diff --git a/doc/files.md b/doc/files.md index a74cbd28e3..8e15fccec9 100644 --- a/doc/files.md +++ b/doc/files.md @@ -1,33 +1,34 @@ * banlist.dat: stores the IPs/Subnets of banned nodes * bitcoin.conf: contains configuration settings for bitcoind or bitcoin-qt * bitcoind.pid: stores the process id of bitcoind while running * blocks/blk000??.dat: block data (custom, 128 MiB per file); since 0.8.0 * blocks/rev000??.dat; block undo data (custom); since 0.8.0 (format changed since pre-0.8) * blocks/index/*; block index (LevelDB); since 0.8.0 * chainstate/*; block chain state database (LevelDB); since 0.8.0 * database/*: BDB database environment; only used for wallet since 0.8.0; moved to wallets/ directory on new installs since 0.18.7 * db.log: wallet database log file; moved to wallets/ directory on new installs since 0.18.7 * debug.log: contains debug information and general logging generated by bitcoind or bitcoin-qt +* indexes/txindex/*: optional transaction index database (LevelDB); since 0.19.7 * mempool.dat: dump of the mempool's transactions; since 0.14.0. * peers.dat: peer IP address database (custom format); since 0.7.0 * wallet.dat: personal wallet (BDB) with keys and transactions; moved to wallets/ directory on new installs since 0.18.7 * wallets/database/*: BDB database environment; used for wallets since 0.18.7 * wallets/db.log: wallet database log file; since 0.18.7 * wallets/wallet.dat: personal wallet (BDB) with keys and transactions; since 0.18.7 * .cookie: session RPC authentication cookie (written at start when cookie authentication is used, deleted on shutdown): since 0.12.0 * onion_private_key: cached Tor hidden service private key for `-listenonion`: since 0.12.0 Only used in pre-0.8.0 --------------------- * blktree/*; block chain index (LevelDB); since pre-0.8, replaced by blocks/index/* in 0.8.0 * coins/*; unspent transaction output database (LevelDB); since pre-0.8, replaced by chainstate/* in 0.8.0 Only used before 0.8.0 --------------------- * blkindex.dat: block chain index database (BDB); replaced by {chainstate/*,blocks/index/*,blocks/rev000??.dat} in 0.8.0 * blk000?.dat: block data (custom, 2 GiB per file); replaced by blocks/blk000??.dat in 0.8.0 Only used before 0.7.0 --------------------- * addr.dat: peer IP address database (BDB); replaced by peers.dat in 0.7.0 diff --git a/doc/release-notes.md b/doc/release-notes.md index 8e8ff46bab..b3de6650b4 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,16 +1,28 @@ Bitcoin ABC version 0.19.7 is now available from: This release includes the following features and fixes: - `-includeconf=` can be used to include additional configuration files. Only works inside the `bitcoin.conf` file, not inside included files or from command-line. Multiple files may be included. Can be disabled from command- line via `-noincludeconf`. Note that multi-argument commands like `-includeconf` will override preceding `-noincludeconf`, i.e. noincludeconf=1 includeconf=relative.conf as bitcoin.conf will still include `relative.conf`. - The `createrawtransaction` RPC will now accept an array or dictionary (kept for compatibility) for the `outputs` parameter. This means the order of transaction outputs can be specified by the client. - The new RPC `testmempoolaccept` can be used to test acceptance of a transaction to the mempool without adding it. - An `initialblockdownload` boolean has been added to the `getblockchaininfo` RPC to indicate whether the node is currently in IBD or not. + +Transaction index changes +------------------------- + +The transaction index is now built separately from the main node procedure, +meaning the `-txindex` flag can be toggled without a full reindex. If bitcoind +is run with `-txindex` on a node that is already partially or fully synced +without one, the transaction index will be built in the background and become +available once caught up. When switching from running `-txindex` to running +without the flag, the transaction index database will *not* be deleted +automatically, meaning it could be turned back on at a later time without a full +resync. diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 7d23b34a7f..0ebd3c9cd8 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -1,206 +1,207 @@ # Copyright (c) 2013-2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. TESTS += test/test_bitcoin LOG_DRIVER = $(srcdir)/test/test-bitcoin-driver EXTRA_DIST += test/test-bitcoin-driver bin_PROGRAMS += test/test_bitcoin noinst_PROGRAMS += test/test_bitcoin_fuzzy TEST_SRCDIR = test TEST_BINARY=test/test_bitcoin$(EXEEXT) JSON_TEST_FILES = \ test/data/script_tests.json \ test/data/base58_keys_valid.json \ test/data/base58_encode_decode.json \ test/data/base58_keys_invalid.json \ test/data/blockfilters.json \ test/data/tx_invalid.json \ test/data/tx_valid.json \ test/data/sighash.json RAW_TEST_FILES = GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) # test_bitcoin binary # BITCOIN_TESTS =\ test/scriptnum10.h \ test/activation_tests.cpp \ test/addrman_tests.cpp \ test/allocator_tests.cpp \ test/amount_tests.cpp \ test/arith_uint256_tests.cpp \ test/avalanche_tests.cpp \ test/base32_tests.cpp \ test/base58_tests.cpp \ test/base64_tests.cpp \ test/bip32_tests.cpp \ test/blockcheck_tests.cpp \ test/blockencodings_tests.cpp \ test/blockfilter_tests.cpp \ test/blockindex_tests.cpp \ test/blockstatus_tests.cpp \ test/bloom_tests.cpp \ test/bswap_tests.cpp \ test/cashaddr_tests.cpp \ test/cashaddrenc_tests.cpp \ test/checkdatasig_tests.cpp \ test/checkpoints_tests.cpp \ test/checkqueue_tests.cpp \ test/coins_tests.cpp \ test/compress_tests.cpp \ test/config_tests.cpp \ test/core_io_tests.cpp \ test/crypto_tests.cpp \ test/cuckoocache_tests.cpp \ test/dbwrapper_tests.cpp \ test/DoS_tests.cpp \ test/dstencode_tests.cpp \ test/excessiveblock_tests.cpp \ test/feerate_tests.cpp \ test/finalization_tests.cpp \ test/getarg_tests.cpp \ test/hash_tests.cpp \ test/inv_tests.cpp \ test/jsonutil.cpp \ test/jsonutil.h \ test/key_tests.cpp \ test/lcg_tests.cpp \ test/lcg.h \ test/limitedmap_tests.cpp \ test/main_tests.cpp \ test/mempool_tests.cpp \ test/merkle_tests.cpp \ test/miner_tests.cpp \ test/monolith_opcodes_tests.cpp \ test/multisig_tests.cpp \ test/net_tests.cpp \ test/netbase_tests.cpp \ test/pmt_tests.cpp \ test/policyestimator_tests.cpp \ test/pow_tests.cpp \ test/prevector_tests.cpp \ test/radix_tests.cpp \ test/raii_event_tests.cpp \ test/random_tests.cpp \ test/rcu_tests.cpp \ test/reverselock_tests.cpp \ test/rpc_tests.cpp \ test/rpc_server_tests.cpp \ test/rwcollection_tests.cpp \ test/sanity_tests.cpp \ test/scheduler_tests.cpp \ test/schnorr_tests.cpp \ test/script_commitment_tests.cpp \ test/script_P2SH_tests.cpp \ test/script_tests.cpp \ test/scriptflags.cpp \ test/scriptflags.h \ test/scriptnum_tests.cpp \ test/serialize_tests.cpp \ test/sigcache_tests.cpp \ test/sigencoding_tests.cpp \ test/sighash_tests.cpp \ test/sighashtype_tests.cpp \ test/sigopcount_tests.cpp \ test/sigutil.cpp \ test/sigutil.h \ test/skiplist_tests.cpp \ test/streams_tests.cpp \ test/sync_tests.cpp \ test/test_bitcoin.cpp \ test/test_bitcoin.h \ test/test_bitcoin_main.cpp \ test/timedata_tests.cpp \ test/transaction_tests.cpp \ + test/txindex_tests.cpp \ test/txvalidationcache_tests.cpp \ test/uint256_tests.cpp \ test/undo_tests.cpp \ test/univalue_tests.cpp \ test/util_tests.cpp \ test/validation_tests.cpp \ test/work_comparator_tests.cpp \ rpc/test/server_tests.cpp if ENABLE_WALLET BITCOIN_TESTS += \ wallet/test/wallet_test_fixture.cpp \ wallet/test/wallet_test_fixture.h \ wallet/test/accounting_tests.cpp \ wallet/test/wallet_tests.cpp \ wallet/test/walletdb_tests.cpp \ wallet/test/wallet_crypto_tests.cpp endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(EVENT_CFLAGS) test_test_bitcoin_LDADD = if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \ $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static if ENABLE_ZMQ test_test_bitcoin_LDADD += $(ZMQ_LIBS) endif # # test_bitcoin_fuzzy binary # test_test_bitcoin_fuzzy_SOURCES = test/test_bitcoin_fuzzy.cpp test_test_bitcoin_fuzzy_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_test_bitcoin_fuzzy_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_bitcoin_fuzzy_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) test_test_bitcoin_fuzzy_LDADD = \ $(LIBUNIVALUE) \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) test_test_bitcoin_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) $(BITCOIN_TESTS): $(GENERATED_TEST_FILES) CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) CLEANFILES += $(CLEAN_BITCOIN_TEST) bitcoin_test: $(TEST_BINARY) bitcoin_test_check: $(TEST_BINARY) FORCE $(MAKE) check-TESTS TESTS=$^ bitcoin_test_clean : FORCE rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) check-local: @echo "Running test/util/bitcoin-util-test.py..." $(top_builddir)/test/util/bitcoin-util-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check if EMBEDDED_UNIVALUE $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check endif %.json.h: %.json @$(MKDIR_P) $(@D) @{ \ echo "namespace json_tests{" && \ echo "static unsigned const char $(*F)[] = {" && \ $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ echo "};};"; \ } > "$@.new" && mv -f "$@.new" "$@" @echo "Generated $@" diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index 356de099e5..844412465c 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -1,281 +1,305 @@ // Copyright (c) 2017-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include constexpr int64_t SYNC_LOG_INTERVAL = 30; // seconds constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL = 30; // seconds +std::unique_ptr g_txindex; + template static void FatalError(const char *fmt, const Args &... args) { std::string strMessage = tfm::format(fmt, args...); SetMiscWarning(strMessage); LogPrintf("*** %s\n", strMessage); uiInterface.ThreadSafeMessageBox( "Error: A fatal internal error occurred, see debug.log for details", "", CClientUIInterface::MSG_ERROR); StartShutdown(); } TxIndex::TxIndex(std::unique_ptr db) : m_db(std::move(db)), m_synced(false), m_best_block_index(nullptr) {} TxIndex::~TxIndex() { Interrupt(); Stop(); } bool TxIndex::Init() { LOCK(cs_main); // Attempt to migrate txindex from the old database to the new one. Even if // chain_tip is null, the node could be reindexing and we still want to // delete txindex records in the old database. if (!m_db->MigrateData(*pblocktree, chainActive.GetLocator())) { return false; } CBlockLocator locator; if (!m_db->ReadBestBlock(locator)) { locator.SetNull(); } m_best_block_index = FindForkInGlobalIndex(chainActive, locator); m_synced = m_best_block_index.load() == chainActive.Tip(); return true; } static const CBlockIndex *NextSyncBlock(const CBlockIndex *pindex_prev) { AssertLockHeld(cs_main); if (!pindex_prev) { return chainActive.Genesis(); } const CBlockIndex *pindex = chainActive.Next(pindex_prev); if (pindex) { return pindex; } return chainActive.Next(chainActive.FindFork(pindex_prev)); } void TxIndex::ThreadSync() { const CBlockIndex *pindex = m_best_block_index.load(); if (!m_synced) { auto &config = GetConfig(); int64_t last_log_time = 0; int64_t last_locator_write_time = 0; while (true) { if (m_interrupt) { WriteBestBlock(pindex); return; } { LOCK(cs_main); const CBlockIndex *pindex_next = NextSyncBlock(pindex); if (!pindex_next) { WriteBestBlock(pindex); m_best_block_index = pindex; m_synced = true; break; } pindex = pindex_next; } int64_t current_time = GetTime(); if (last_log_time + SYNC_LOG_INTERVAL < current_time) { LogPrintf("Syncing txindex with block chain from height %d\n", pindex->nHeight); last_log_time = current_time; } if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) { WriteBestBlock(pindex); last_locator_write_time = current_time; } CBlock block; if (!ReadBlockFromDisk(block, pindex, config)) { FatalError("%s: Failed to read block %s from disk", __func__, pindex->GetBlockHash().ToString()); return; } if (!WriteBlock(block, pindex)) { FatalError("%s: Failed to write block %s to tx index database", __func__, pindex->GetBlockHash().ToString()); return; } } } if (pindex) { LogPrintf("txindex is enabled at height %d\n", pindex->nHeight); } else { LogPrintf("txindex is enabled\n"); } } bool TxIndex::WriteBlock(const CBlock &block, const CBlockIndex *pindex) { CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); std::vector> vPos; vPos.reserve(block.vtx.size()); for (const auto &tx : block.vtx) { vPos.emplace_back(tx->GetHash(), pos); pos.nTxOffset += ::GetSerializeSize(*tx, SER_DISK, CLIENT_VERSION); } return m_db->WriteTxs(vPos); } bool TxIndex::WriteBestBlock(const CBlockIndex *block_index) { LOCK(cs_main); if (!m_db->WriteBestBlock(chainActive.GetLocator(block_index))) { return error("%s: Failed to write locator to disk", __func__); } return true; } void TxIndex::BlockConnected( const std::shared_ptr &block, const CBlockIndex *pindex, const std::vector &txn_conflicted) { if (!m_synced) { return; } const CBlockIndex *best_block_index = m_best_block_index.load(); if (!best_block_index) { if (pindex->nHeight != 0) { FatalError("%s: First block connected is not the genesis block " "(height=%d)", __func__, pindex->nHeight); return; } } else { // Ensure block connects to an ancestor of the current best block. This // should be the case most of the time, but may not be immediately after // the the sync thread catches up and sets m_synced. Consider the case // where there is a reorg and the blocks on the stale branch are in the // ValidationInterface queue backlog even after the sync thread has // caught up to the new chain tip. In this unlikely event, log a warning // and let the queue clear. if (best_block_index->GetAncestor(pindex->nHeight - 1) != pindex->pprev) { LogPrintf("%s: WARNING: Block %s does not connect to an ancestor " "of known best chain (tip=%s); not updating txindex\n", __func__, pindex->GetBlockHash().ToString(), best_block_index->GetBlockHash().ToString()); return; } } if (WriteBlock(*block, pindex)) { m_best_block_index = pindex; } else { FatalError("%s: Failed to write block %s to txindex", __func__, pindex->GetBlockHash().ToString()); return; } } void TxIndex::ChainStateFlushed(const CBlockLocator &locator) { if (!m_synced) { return; } const uint256 &locator_tip_hash = locator.vHave.front(); const CBlockIndex *locator_tip_index; { LOCK(cs_main); locator_tip_index = LookupBlockIndex(locator_tip_hash); } if (!locator_tip_index) { FatalError("%s: First block (hash=%s) in locator was not found", __func__, locator_tip_hash.ToString()); return; } // This checks that ChainStateFlushed callbacks are received after // BlockConnected. The check may fail immediately after the the sync thread // catches up and sets m_synced. Consider the case where there is a reorg // and the blocks on the stale branch are in the ValidationInterface queue // backlog even after the sync thread has caught up to the new chain tip. In // this unlikely event, log a warning and let the queue clear. const CBlockIndex *best_block_index = m_best_block_index.load(); if (best_block_index->GetAncestor(locator_tip_index->nHeight) != locator_tip_index) { LogPrintf("%s: WARNING: Locator contains block (hash=%s) not on known " "best chain (tip=%s); not writing txindex locator\n", __func__, locator_tip_hash.ToString(), best_block_index->GetBlockHash().ToString()); return; } if (!m_db->WriteBestBlock(locator)) { error("%s: Failed to write locator to disk", __func__); } } bool TxIndex::BlockUntilSyncedToCurrentChain() { AssertLockNotHeld(cs_main); if (!m_synced) { return false; } { // Skip the queue-draining stuff if we know we're caught up with // chainActive.Tip(). LOCK(cs_main); const CBlockIndex *chain_tip = chainActive.Tip(); const CBlockIndex *best_block_index = m_best_block_index.load(); if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) { return true; } } LogPrintf("%s: txindex is catching up on block notifications\n", __func__); SyncWithValidationInterfaceQueue(); return true; } -bool TxIndex::FindTx(const uint256 &txid, CDiskTxPos &pos) const { - return m_db->ReadTxPos(txid, pos); +bool TxIndex::FindTx(const uint256 &tx_hash, uint256 &block_hash, + CTransactionRef &tx) const { + CDiskTxPos postx; + if (!m_db->ReadTxPos(tx_hash, postx)) { + return false; + } + + CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); + if (file.IsNull()) { + return error("%s: OpenBlockFile failed", __func__); + } + CBlockHeader header; + try { + file >> header; + fseek(file.Get(), postx.nTxOffset, SEEK_CUR); + file >> tx; + } catch (const std::exception &e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + if (tx->GetHash() != tx_hash) { + return error("%s: txid mismatch", __func__); + } + block_hash = header.GetHash(); + return true; } void TxIndex::Interrupt() { m_interrupt(); } void TxIndex::Start() { // Need to register this ValidationInterface before running Init(), so that // callbacks are not missed if Init sets m_synced to true. RegisterValidationInterface(this); if (!Init()) { FatalError("%s: txindex failed to initialize", __func__); return; } m_thread_sync = std::thread(&TraceThread>, "txindex", std::bind(&TxIndex::ThreadSync, this)); } void TxIndex::Stop() { UnregisterValidationInterface(this); if (m_thread_sync.joinable()) { m_thread_sync.join(); } } diff --git a/src/index/txindex.h b/src/index/txindex.h index 43db34e5ce..22db753a20 100644 --- a/src/index/txindex.h +++ b/src/index/txindex.h @@ -1,87 +1,98 @@ // Copyright (c) 2017-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_INDEX_TXINDEX_H #define BITCOIN_INDEX_TXINDEX_H #include +#include #include #include #include #include class CBlockIndex; /** * TxIndex is used to look up transactions included in the blockchain by hash. * The index is written to a LevelDB database and records the filesystem * location of each transaction by transaction hash. */ class TxIndex final : public CValidationInterface { private: const std::unique_ptr m_db; /// Whether the index is in sync with the main chain. The flag is flipped /// from false to true once, after which point this starts processing /// ValidationInterface notifications to stay in sync. std::atomic m_synced; /// The last block in the chain that the TxIndex is in sync with. std::atomic m_best_block_index; std::thread m_thread_sync; CThreadInterrupt m_interrupt; /// Initialize internal state from the database and block index. bool Init(); /// Sync the tx index with the block index starting from the current best /// block. Intended to be run in its own thread, m_thread_sync, and can be /// interrupted with m_interrupt. Once the txindex gets in sync, the /// m_synced flag is set and the BlockConnected ValidationInterface callback /// takes over and the sync thread exits. void ThreadSync(); /// Write update index entries for a newly connected block. bool WriteBlock(const CBlock &block, const CBlockIndex *pindex); /// Write the current chain block locator to the DB. bool WriteBestBlock(const CBlockIndex *block_index); protected: void BlockConnected(const std::shared_ptr &block, const CBlockIndex *pindex, const std::vector &txn_conflicted) override; void ChainStateFlushed(const CBlockLocator &locator) override; public: /// Constructs the TxIndex, which becomes available to be queried. explicit TxIndex(std::unique_ptr db); /// Destructor interrupts sync thread if running and blocks until it exits. ~TxIndex(); /// Blocks the current thread until the transaction index is caught up to /// the current state of the block chain. This only blocks if the index has /// gotten in sync once and only needs to process blocks in the /// ValidationInterface queue. If the index is catching up from far behind, /// this method does not block and immediately returns false. bool BlockUntilSyncedToCurrentChain(); - /// Look up the on-disk location of a transaction by hash. - bool FindTx(const uint256 &txid, CDiskTxPos &pos) const; + /// Look up a transaction by hash. + /// + /// @param[in] tx_hash The hash of the transaction to be returned. + /// @param[out] block_hash The hash of the block the transaction is found + /// in. + /// @param[out] tx The transaction itself. + /// @return true if transaction is found, false otherwise + bool FindTx(const uint256 &tx_hash, uint256 &block_hash, + CTransactionRef &tx) const; void Interrupt(); /// Start initializes the sync state and registers the instance as a /// ValidationInterface so that it stays in sync with blockchain updates. void Start(); /// Stops the instance from staying in sync with blockchain updates. void Stop(); }; +/// The global transaction index, used in GetTransaction. May be null. +extern std::unique_ptr g_txindex; + #endif // BITCOIN_INDEX_TXINDEX_H diff --git a/src/init.cpp b/src/init.cpp index 4ebb4c1449..13d59edbd9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,2455 +1,2467 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include