test: index, improve txospenderindex_initial_sync() test code
What changed, and why it matters
This is a routine improvement to a Bitcoin Core unit test. It reorganizes when an index is started during the test and adds an extra check that the index fully catches up to the latest block. There is no change to production code, no security fix, and no vulnerability.
No security action needed. Treat as normal test-quality maintenance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors src/test/txospenderindex_tests.cpp only. It moves TxoSpenderIndex construction/Init() to after the test chain setup, adds a best_block_hash assertion after Sync() to confirm the index reached the tip, and removes a now-unnecessary SyncWithValidationInterfaceQueue() call. No consensus, networking, wallet, or index implementation code is modified.
Changed components
src/test/txospenderindex_tests.cppInspect captured patch +29 / −31
diff --git a/src/test/txospenderindex_tests.cpp b/src/test/txospenderindex_tests.cpp
index 889ef7ff..c54370a5 100644
--- a/src/test/txospenderindex_tests.cpp
+++ b/src/test/txospenderindex_tests.cpp
@@ -2,10 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <chainparams.h>
#include <index/txospenderindex.h>
#include <test/util/setup_common.h>
-#include <util/time.h>
#include <validation.h>
#include <boost/test/unit_test.hpp>
@@ -14,63 +12,63 @@ BOOST_AUTO_TEST_SUITE(txospenderindex_tests)
BOOST_FIXTURE_TEST_CASE(txospenderindex_initial_sync, TestChain100Setup)
{
- TxoSpenderIndex txospenderindex(interfaces::MakeChain(m_node), 1 << 20, true);
- BOOST_REQUIRE(txospenderindex.Init());
-
+ // Setup phase:
// Mine blocks for coinbase maturity, so we can spend some coinbase outputs in the test.
- for (int i = 0; i < 50; i++) {
- std::vector<CMutableTransaction> no_txns;
- CreateAndProcessBlock(no_txns, this->m_coinbase_txns[i]->vout[0].scriptPubKey);
- }
+ const CScript& coinbase_script = m_coinbase_txns[0]->vout[0].scriptPubKey;
+ for (int i = 0; i < 10; i++) CreateAndProcessBlock({}, coinbase_script);
+
+ // Spend 10 outputs
std::vector<COutPoint> spent(10);
std::vector<CMutableTransaction> spender(spent.size());
-
for (size_t i = 0; i < spent.size(); i++) {
- spent[i] = COutPoint(this->m_coinbase_txns[i]->GetHash(), 0);
+ // Outpoint
+ auto coinbase_tx = m_coinbase_txns[i];
+ spent[i] = COutPoint(coinbase_tx->GetHash(), 0);
+
+ // Spending tx
spender[i].version = 1;
spender[i].vin.resize(1);
spender[i].vin[0].prevout.hash = spent[i].hash;
spender[i].vin[0].prevout.n = spent[i].n;
spender[i].vout.resize(1);
- spender[i].vout[0].nValue = this->m_coinbase_txns[i]->GetValueOut();
- spender[i].vout[0].scriptPubKey = this->m_coinbase_txns[i]->vout[0].scriptPubKey;
+ spender[i].vout[0].nValue = coinbase_tx->GetValueOut();
+ spender[i].vout[0].scriptPubKey = coinbase_script;
- // Sign:
+ // Sign
std::vector<unsigned char> vchSig;
- const uint256 hash = SignatureHash(this->m_coinbase_txns[i]->vout[0].scriptPubKey, spender[i], 0, SIGHASH_ALL, 0, SigVersion::BASE);
- coinbaseKey.Sign(hash, vchSig);
+ const uint256 hash = SignatureHash(coinbase_script, spender[i], 0, SIGHASH_ALL, 0, SigVersion::BASE);
+ BOOST_REQUIRE(coinbaseKey.Sign(hash, vchSig));
vchSig.push_back((unsigned char)SIGHASH_ALL);
spender[i].vin[0].scriptSig << vchSig;
}
- CBlock block = CreateAndProcessBlock(spender, this->m_coinbase_txns[0]->vout[0].scriptPubKey);
+ // Generate and ensure block has been fully processed
+ const uint256 tip_hash = CreateAndProcessBlock(spender, coinbase_script).GetHash();
+ m_node.validation_signals->SyncWithValidationInterfaceQueue();
+ BOOST_CHECK_EQUAL(WITH_LOCK(::cs_main, return m_node.chainman->ActiveTip()->GetBlockHash()), tip_hash);
- // Transaction should not be found in the index before it is started.
+ // Now we concluded the setup phase, run index
+ TxoSpenderIndex txospenderindex(interfaces::MakeChain(m_node), 1 << 20, true);
+ BOOST_REQUIRE(txospenderindex.Init());
+ BOOST_CHECK(!txospenderindex.BlockUntilSyncedToCurrentChain()); // false when not synced
+ BOOST_CHECK_NE(txospenderindex.GetSummary().best_block_hash, tip_hash);
+
+ // Transaction should not be found in the index before it is synced.
for (const auto& outpoint : spent) {
BOOST_CHECK(!txospenderindex.FindSpender(outpoint).value());
}
- // BlockUntilSyncedToCurrentChain should return false before txospenderindex is started.
- BOOST_CHECK(!txospenderindex.BlockUntilSyncedToCurrentChain());
-
txospenderindex.Sync();
+ BOOST_CHECK_EQUAL(txospenderindex.GetSummary().best_block_hash, tip_hash);
+
for (size_t i = 0; i < spent.size(); i++) {
const auto tx_spender{txospenderindex.FindSpender(spent[i])};
BOOST_REQUIRE(tx_spender.has_value());
BOOST_REQUIRE(tx_spender->has_value());
BOOST_CHECK_EQUAL((*tx_spender)->tx->GetHash(), spender[i].GetHash());
- BOOST_CHECK_EQUAL((*tx_spender)->block_hash, block.GetHash());
+ BOOST_CHECK_EQUAL((*tx_spender)->block_hash, tip_hash);
}
- // It is not safe to stop and destroy the index until it finishes handling
- // the last BlockConnected notification. The BlockUntilSyncedToCurrentChain()
- // call above is sufficient to ensure this, but the
- // SyncWithValidationInterfaceQueue() call below is also needed to ensure
- // TSAN always sees the test thread waiting for the notification thread, and
- // avoid potential false positive reports.
- m_node.validation_signals->SyncWithValidationInterfaceQueue();
-
- // shutdown sequence (c.f. Shutdown() in init.cpp)
txospenderindex.Stop();
}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.