Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
251BOOST_REQUIRE(!bucket.empty());252for (const auto& pos : bucket) db.Erase(txindex::DBKey{prefix, pos});254LookupTx(txindex, legacy_txid);256txindex.Stop();257}259BOOST_FIXTURE_TEST_CASE(txindex_locator_upgrade, TestChain100Setup)260{261uint256 legacy_hash, new_hash;262{263LOCK(cs_main);264legacy_hash = Assert(m_node.chainman->ActiveChain()[1])->GetBlockHash();265new_hash = Assert(m_node.chainman->ActiveChain().Tip())->GetBlockHash();266}267CBlockLocator legacy_locator{{legacy_hash}}, new_locator{{new_hash}};268{ CDBWrapper{DBParams{.path = gArgs.GetDataDirNet() / "indexes" / "txindex", .cache_bytes = 1_MiB}}.Write(uint8_t{'B'}, legacy_locator); }270TxIndex txindex(interfaces::MakeChain(m_node), /*n_cache_size=*/1_MiB, /*f_memory=*/false);271BOOST_CHECK(TxIndexTest::ReadBestBlock(txindex).vHave == legacy_locator.vHave);273TxIndexTest::WriteBestBlock(txindex, new_locator);274BOOST_CHECK(TxIndexTest::ReadBestBlock(txindex).vHave == new_locator.vHave);276CBlockLocator stored_legacy_locator;277BOOST_REQUIRE(TxIndexTest::GetDB(txindex).Read(uint8_t{'B'}, stored_legacy_locator));278BOOST_CHECK(stored_legacy_locator.vHave == legacy_locator.vHave);279}281BOOST_FIXTURE_TEST_CASE(txindex_reorg_keeps_stale_entries, TestChain100Setup)282{283TxIndex txindex(interfaces::MakeChain(m_node), /*n_cache_size=*/1_MiB, /*f_memory=*/true);284BOOST_REQUIRE(txindex.Init());285txindex.Sync();287const CScript coinbase_script{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG};289// Mine a unique (non-coinbase) transaction into a new block at height 101.290CMutableTransaction unique_mtx{CreateValidMempoolTransaction(291/*input_transaction=*/m_coinbase_txns[0],292/*input_vout=*/0,293/*input_height=*/1,294/*input_signing_key=*/coinbaseKey,295/*output_destination=*/CScript() << OP_TRUE,296/*output_amount=*/CAmount{1 * COIN},297/*submit=*/false)};298const Txid unique_txid{MakeTransactionRef(unique_mtx)->GetHash()};299const uint256 stale_block_hash{CreateAndProcessBlock({unique_mtx}, coinbase_script).GetHash()};300BOOST_REQUIRE(txindex.BlockUntilSyncedToCurrentChain());302BOOST_CHECK(LookupTx(txindex, unique_txid) == stale_block_hash);304CDBWrapper& db{TxIndexTest::GetDB(txindex)};305const auto prefix{txindex::CreateKeyPrefix(ReadHasher(db), unique_txid)};306const auto original_bucket{BucketPositions(db, prefix)};307BOOST_REQUIRE_EQUAL(original_bucket.size(), 1U);309ChainstateManager& chainman{*m_node.chainman};311// Invalidate the block holding the unique transaction.312InvalidateBlock(chainman, stale_block_hash);313BOOST_REQUIRE(txindex.BlockUntilSyncedToCurrentChain());315// The disconnected transaction is still found, in the now-stale block.316BOOST_CHECK(LookupTx(txindex, unique_txid) == stale_block_hash);317{318LOCK(cs_main);319const CBlockIndex* stale_index{chainman.m_blockman.LookupBlockIndex(stale_block_hash)};320BOOST_REQUIRE(stale_index);321BOOST_CHECK(!chainman.ActiveChain().Contains(*stale_index));322}324// Mine the same transaction into a replacement branch, which gets a later325// sequence number. The lookup must now return the branch block in the active chain.326const uint256 branch_block_hash{CreateAndProcessBlock({unique_mtx}, CScript() << OP_TRUE).GetHash()};327CreateAndProcessBlock({}, coinbase_script);328BOOST_REQUIRE(txindex.BlockUntilSyncedToCurrentChain());329BOOST_CHECK(LookupTx(txindex, unique_txid) == branch_block_hash);331// Reorg back to the original branch. The original branch block must be332// now be preferred even though the replacement branch has a later sequence.333{334LOCK(cs_main);335chainman.ActiveChainstate().ResetBlockFailureFlags(chainman.m_blockman.LookupBlockIndex(stale_block_hash));336}337InvalidateBlock(chainman, branch_block_hash);338{339BlockValidationState state;340BOOST_REQUIRE(chainman.ActiveChainstate().ActivateBestChain(state));341}342BOOST_REQUIRE(txindex.BlockUntilSyncedToCurrentChain());343BOOST_CHECK(WITH_LOCK(cs_main, return chainman.ActiveChain().Tip()->GetBlockHash()) == stale_block_hash);345BOOST_CHECK(LookupTx(txindex, unique_txid) == stale_block_hash);347// Reconnecting the original block must not create duplicate entries.348const auto reorg_bucket{BucketPositions(db, prefix)};349BOOST_REQUIRE_EQUAL(reorg_bucket.size(), 2U);350BOOST_CHECK(reorg_bucket.front() == original_bucket.front());352txindex.Stop();353}355BOOST_AUTO_TEST_SUITE_END()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.