mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-09 22:28:51 +02:00
Merge bitcoin/bitcoin#32631: refactor: Convert GenTxid to std::variant
a60f863d3escripted-diff: Replace GenTxidVariant with GenTxid (marcofleon)c8ba199598Remove old GenTxid class (marcofleon)072a198ea4Convert remaining instances of GenTxid to GenTxidVariant (marcofleon)1b528391c7Convert `txrequest` to GenTxidVariant (marcofleon)bde4579b07Convert `txdownloadman_impl` to GenTxidVariant (marcofleon)c876a892ecReplace GenTxid with Txid/Wtxid overloads in `txmempool` (marcofleon)de858ce2bemove-only: make GetInfo a private CTxMemPool member (stickies-v)eee473d9f3Convert `CompareInvMempoolOrder` to GenTxidVariant (marcofleon)243553d590refactor: replace get_iter_from_wtxid with GetIter(const Wtxid&) (stickies-v)fcf92fd640refactor: make CTxMemPool::GetIter strongly typed (marcofleon)11d28f21bbImplement GenTxid as a variant (marcofleon) Pull request description: Part of the [type safety refactor](https://github.com/bitcoin/bitcoin/pull/32189). This PR changes the GenTxid class to a variant, which holds both Txids and Wtxids. This provides compile-time type safety and eliminates the manual type check (bool m_is_wtxid). Variables that can be either a Txid or a Wtxid are now using the new GenTxid variant, instead of uint256. ACKs for top commit: w0xlt: ACKa60f863d3edergoegge: Code review ACKa60f863d3emaflcko: review ACKa60f863d3e🎽 theStack: Code-review ACKa60f863d3eTree-SHA512: da9b73b7bdffee2eb9281a409205519ac330d3336094d17681896703fbca8099608782c9c85801e388e4d90af5af8abf1f34931f57bbbe6e9674d802d6066047
This commit is contained in:
@@ -173,7 +173,7 @@ FUZZ_TARGET(mini_miner_selection, .init = initialize_miner)
|
||||
if (!pool.GetConflictTx(coin)) outpoints.push_back(coin);
|
||||
}
|
||||
for (const auto& tx : transactions) {
|
||||
assert(pool.exists(GenTxid::Txid(tx->GetHash())));
|
||||
assert(pool.exists(tx->GetHash()));
|
||||
for (uint32_t n{0}; n < tx->vout.size(); ++n) {
|
||||
COutPoint coin{tx->GetHash(), n};
|
||||
if (!pool.GetConflictTx(coin)) outpoints.push_back(coin);
|
||||
|
||||
@@ -311,8 +311,8 @@ FUZZ_TARGET(ephemeral_package_eval, .init = initialize_tx_pool)
|
||||
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
|
||||
// We only prioritise out of mempool transactions since PrioritiseTransaction doesn't
|
||||
// filter for ephemeral dust
|
||||
if (tx_pool.exists(GenTxid::Txid(txid))) {
|
||||
const auto tx_info{tx_pool.info(GenTxid::Txid(txid))};
|
||||
if (tx_pool.exists(txid)) {
|
||||
const auto tx_info{tx_pool.info(txid)};
|
||||
if (GetDust(*tx_info.tx, tx_pool.m_opts.dust_relay_feerate).empty()) {
|
||||
tx_pool.PrioritiseTransaction(txid.ToUint256(), delta);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb)
|
||||
available.insert(i);
|
||||
}
|
||||
|
||||
if (add_to_mempool && !pool.exists(GenTxid::Txid(tx->GetHash()))) {
|
||||
if (add_to_mempool && !pool.exists(tx->GetHash())) {
|
||||
LOCK2(cs_main, pool.cs);
|
||||
AddToMempool(pool, ConsumeTxMemPoolEntry(fuzzed_data_provider, *tx));
|
||||
available.insert(i);
|
||||
|
||||
@@ -316,8 +316,8 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
|
||||
node.validation_signals->SyncWithValidationInterfaceQueue();
|
||||
node.validation_signals->UnregisterSharedValidationInterface(txr);
|
||||
|
||||
bool txid_in_mempool = tx_pool.exists(GenTxid::Txid(tx->GetHash()));
|
||||
bool wtxid_in_mempool = tx_pool.exists(GenTxid::Wtxid(tx->GetWitnessHash()));
|
||||
bool txid_in_mempool = tx_pool.exists(tx->GetHash());
|
||||
bool wtxid_in_mempool = tx_pool.exists(tx->GetWitnessHash());
|
||||
CheckATMPInvariants(res, txid_in_mempool, wtxid_in_mempool);
|
||||
|
||||
Assert(accepted != added.empty());
|
||||
|
||||
@@ -227,9 +227,9 @@ FUZZ_TARGET(txdownloadman, .init = initialize)
|
||||
Assert(first_time_failure || !todo.m_should_add_extra_compact_tx);
|
||||
},
|
||||
[&] {
|
||||
GenTxid gtxid = fuzzed_data_provider.ConsumeBool() ?
|
||||
GenTxid::Txid(rand_tx->GetHash()) :
|
||||
GenTxid::Wtxid(rand_tx->GetWitnessHash());
|
||||
auto gtxid = fuzzed_data_provider.ConsumeBool() ?
|
||||
GenTxid{rand_tx->GetHash()} :
|
||||
GenTxid{rand_tx->GetWitnessHash()};
|
||||
txdownloadman.AddTxAnnouncement(rand_peer, gtxid, time);
|
||||
},
|
||||
[&] {
|
||||
@@ -260,8 +260,7 @@ FUZZ_TARGET(txdownloadman, .init = initialize)
|
||||
// returned true.
|
||||
Assert(expect_work);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
// Jump forwards or backwards
|
||||
auto time_skip = fuzzed_data_provider.PickValueInArray(TIME_SKIPS);
|
||||
if (fuzzed_data_provider.ConsumeBool()) time_skip *= -1;
|
||||
@@ -373,9 +372,9 @@ FUZZ_TARGET(txdownloadman_impl, .init = initialize)
|
||||
if (!reject_contains_wtxid) Assert(todo.m_unique_parents.size() <= rand_tx->vin.size());
|
||||
},
|
||||
[&] {
|
||||
GenTxid gtxid = fuzzed_data_provider.ConsumeBool() ?
|
||||
GenTxid::Txid(rand_tx->GetHash()) :
|
||||
GenTxid::Wtxid(rand_tx->GetWitnessHash());
|
||||
auto gtxid = fuzzed_data_provider.ConsumeBool() ?
|
||||
GenTxid{rand_tx->GetHash()} :
|
||||
GenTxid{rand_tx->GetWitnessHash()};
|
||||
txdownload_impl.AddTxAnnouncement(rand_peer, gtxid, time);
|
||||
},
|
||||
[&] {
|
||||
@@ -395,7 +394,7 @@ FUZZ_TARGET(txdownloadman_impl, .init = initialize)
|
||||
// The only combination that doesn't make sense is validate both tx and package.
|
||||
Assert(!(should_validate && maybe_package.has_value()));
|
||||
if (should_validate) {
|
||||
Assert(!txdownload_impl.AlreadyHaveTx(GenTxid::Wtxid(rand_tx->GetWitnessHash()), /*include_reconsiderable=*/true));
|
||||
Assert(!txdownload_impl.AlreadyHaveTx(rand_tx->GetWitnessHash(), /*include_reconsiderable=*/true));
|
||||
}
|
||||
if (maybe_package.has_value()) {
|
||||
CheckPackageToValidate(*maybe_package, rand_peer);
|
||||
@@ -424,7 +423,7 @@ FUZZ_TARGET(txdownloadman_impl, .init = initialize)
|
||||
// However, if there was a non-null tx in the workset, HaveMoreWork should have
|
||||
// returned true.
|
||||
Assert(expect_work);
|
||||
Assert(txdownload_impl.AlreadyHaveTx(GenTxid::Wtxid(ptx->GetWitnessHash()), /*include_reconsiderable=*/false));
|
||||
Assert(txdownload_impl.AlreadyHaveTx(ptx->GetWitnessHash(), /*include_reconsiderable=*/false));
|
||||
// Presumably we have validated this tx. Use "missing inputs" to keep it in the
|
||||
// orphanage longer. Later iterations might call MempoolAcceptedTx or
|
||||
// MempoolRejectedTx with a different error.
|
||||
@@ -432,8 +431,7 @@ FUZZ_TARGET(txdownloadman_impl, .init = initialize)
|
||||
state_missing_inputs.Invalid(TxValidationResult::TX_MISSING_INPUTS, "");
|
||||
txdownload_impl.MempoolRejectedTx(ptx, state_missing_inputs, rand_peer, fuzzed_data_provider.ConsumeBool());
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
auto time_skip = fuzzed_data_provider.PickValueInArray(TIME_SKIPS);
|
||||
if (fuzzed_data_provider.ConsumeBool()) time_skip *= -1;
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace {
|
||||
constexpr int MAX_TXHASHES = 16;
|
||||
constexpr int MAX_PEERS = 16;
|
||||
|
||||
//! Randomly generated GenTxids used in this test (length is MAX_TXHASHES).
|
||||
//! Randomly generated txhashes used in this test (length is MAX_TXHASHES).
|
||||
uint256 TXHASHES[MAX_TXHASHES];
|
||||
|
||||
//! Precomputed random durations (positive and negative, each ~exponentially distributed).
|
||||
@@ -204,7 +204,8 @@ public:
|
||||
}
|
||||
|
||||
// Call TxRequestTracker's implementation.
|
||||
m_tracker.ReceivedInv(peer, is_wtxid ? GenTxid::Wtxid(TXHASHES[txhash]) : GenTxid::Txid(TXHASHES[txhash]), preferred, reqtime);
|
||||
auto gtxid = is_wtxid ? GenTxid{Wtxid::FromUint256(TXHASHES[txhash])} : GenTxid{Txid::FromUint256(TXHASHES[txhash])};
|
||||
m_tracker.ReceivedInv(peer, gtxid, preferred, reqtime);
|
||||
}
|
||||
|
||||
void RequestedTx(int peer, int txhash, std::chrono::microseconds exptime)
|
||||
@@ -252,7 +253,8 @@ public:
|
||||
for (int peer2 = 0; peer2 < MAX_PEERS; ++peer2) {
|
||||
Announcement& ann2 = m_announcements[txhash][peer2];
|
||||
if (ann2.m_state == State::REQUESTED && ann2.m_time <= m_now) {
|
||||
expected_expired.emplace_back(peer2, ann2.m_is_wtxid ? GenTxid::Wtxid(TXHASHES[txhash]) : GenTxid::Txid(TXHASHES[txhash]));
|
||||
auto gtxid = ann2.m_is_wtxid ? GenTxid{Wtxid::FromUint256(TXHASHES[txhash])} : GenTxid{Txid::FromUint256(TXHASHES[txhash])};
|
||||
expected_expired.emplace_back(peer2, gtxid);
|
||||
ann2.m_state = State::COMPLETED;
|
||||
break;
|
||||
}
|
||||
@@ -278,7 +280,7 @@ public:
|
||||
m_tracker.PostGetRequestableSanityCheck(m_now);
|
||||
assert(result.size() == actual.size());
|
||||
for (size_t pos = 0; pos < actual.size(); ++pos) {
|
||||
assert(TXHASHES[std::get<1>(result[pos])] == actual[pos].GetHash());
|
||||
assert(TXHASHES[std::get<1>(result[pos])] == actual[pos].ToUint256());
|
||||
assert(std::get<2>(result[pos]) == actual[pos].IsWtxid());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,12 +454,12 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
AddToMempool(pool, entry.Fee(5000LL).FromTx(tx2));
|
||||
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
|
||||
BOOST_CHECK(pool.exists(GenTxid::Txid(tx1.GetHash())));
|
||||
BOOST_CHECK(pool.exists(GenTxid::Txid(tx2.GetHash())));
|
||||
BOOST_CHECK(pool.exists(tx1.GetHash()));
|
||||
BOOST_CHECK(pool.exists(tx2.GetHash()));
|
||||
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction
|
||||
BOOST_CHECK(pool.exists(GenTxid::Txid(tx1.GetHash())));
|
||||
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx2.GetHash())));
|
||||
BOOST_CHECK(pool.exists(tx1.GetHash()));
|
||||
BOOST_CHECK(!pool.exists(tx2.GetHash()));
|
||||
|
||||
AddToMempool(pool, entry.FromTx(tx2));
|
||||
CMutableTransaction tx3 = CMutableTransaction();
|
||||
@@ -472,14 +472,14 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
AddToMempool(pool, entry.Fee(20000LL).FromTx(tx3));
|
||||
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
|
||||
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx1.GetHash())));
|
||||
BOOST_CHECK(pool.exists(GenTxid::Txid(tx2.GetHash())));
|
||||
BOOST_CHECK(pool.exists(GenTxid::Txid(tx3.GetHash())));
|
||||
BOOST_CHECK(!pool.exists(tx1.GetHash()));
|
||||
BOOST_CHECK(pool.exists(tx2.GetHash()));
|
||||
BOOST_CHECK(pool.exists(tx3.GetHash()));
|
||||
|
||||
pool.TrimToSize(GetVirtualTransactionSize(CTransaction(tx1))); // mempool is limited to tx1's size in memory usage, so nothing fits
|
||||
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx1.GetHash())));
|
||||
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx2.GetHash())));
|
||||
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx3.GetHash())));
|
||||
BOOST_CHECK(!pool.exists(tx1.GetHash()));
|
||||
BOOST_CHECK(!pool.exists(tx2.GetHash()));
|
||||
BOOST_CHECK(!pool.exists(tx3.GetHash()));
|
||||
|
||||
CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2)));
|
||||
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
|
||||
@@ -539,19 +539,19 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
|
||||
// we only require this to remove, at max, 2 txn, because it's not clear what we're really optimizing for aside from that
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
|
||||
BOOST_CHECK(pool.exists(GenTxid::Txid(tx4.GetHash())));
|
||||
BOOST_CHECK(pool.exists(GenTxid::Txid(tx6.GetHash())));
|
||||
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx7.GetHash())));
|
||||
BOOST_CHECK(pool.exists(tx4.GetHash()));
|
||||
BOOST_CHECK(pool.exists(tx6.GetHash()));
|
||||
BOOST_CHECK(!pool.exists(tx7.GetHash()));
|
||||
|
||||
if (!pool.exists(GenTxid::Txid(tx5.GetHash())))
|
||||
if (!pool.exists(tx5.GetHash()))
|
||||
AddToMempool(pool, entry.Fee(1000LL).FromTx(tx5));
|
||||
AddToMempool(pool, entry.Fee(9000LL).FromTx(tx7));
|
||||
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
|
||||
BOOST_CHECK(pool.exists(GenTxid::Txid(tx4.GetHash())));
|
||||
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx5.GetHash())));
|
||||
BOOST_CHECK(pool.exists(GenTxid::Txid(tx6.GetHash())));
|
||||
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx7.GetHash())));
|
||||
BOOST_CHECK(pool.exists(tx4.GetHash()));
|
||||
BOOST_CHECK(!pool.exists(tx5.GetHash()));
|
||||
BOOST_CHECK(pool.exists(tx6.GetHash()));
|
||||
BOOST_CHECK(!pool.exists(tx7.GetHash()));
|
||||
|
||||
AddToMempool(pool, entry.Fee(1000LL).FromTx(tx5));
|
||||
AddToMempool(pool, entry.Fee(9000LL).FromTx(tx7));
|
||||
|
||||
@@ -293,7 +293,7 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
|
||||
const auto spends_unconfirmed = make_tx({tx1}, {36 * CENT});
|
||||
for (const auto& input : spends_unconfirmed->vin) {
|
||||
// Spends unconfirmed inputs.
|
||||
BOOST_CHECK(pool.exists(GenTxid::Txid(input.prevout.hash)));
|
||||
BOOST_CHECK(pool.exists(input.prevout.hash));
|
||||
}
|
||||
BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),
|
||||
/*pool=*/ pool,
|
||||
|
||||
@@ -126,10 +126,10 @@ BOOST_FIXTURE_TEST_CASE(tx_rejection_types, TestChain100Setup)
|
||||
for (const auto segwit_child : {true, false}) {
|
||||
const auto ptx_parent = CreatePlaceholderTx(segwit_parent);
|
||||
const auto ptx_child = CreatePlaceholderTx(segwit_child);
|
||||
const auto& parent_txid = ptx_parent->GetHash().ToUint256();
|
||||
const auto& parent_wtxid = ptx_parent->GetWitnessHash().ToUint256();
|
||||
const auto& child_txid = ptx_child->GetHash().ToUint256();
|
||||
const auto& child_wtxid = ptx_child->GetWitnessHash().ToUint256();
|
||||
const auto& parent_txid = ptx_parent->GetHash();
|
||||
const auto& parent_wtxid = ptx_parent->GetWitnessHash();
|
||||
const auto& child_txid = ptx_child->GetHash();
|
||||
const auto& child_wtxid = ptx_child->GetWitnessHash();
|
||||
|
||||
for (const auto& [result, expected_behavior] : expected_behaviors) {
|
||||
node::TxDownloadManagerImpl txdownload_impl{DEFAULT_OPTS};
|
||||
@@ -141,13 +141,13 @@ BOOST_FIXTURE_TEST_CASE(tx_rejection_types, TestChain100Setup)
|
||||
// No distinction between txid and wtxid caching for nonsegwit transactions, so only test these specific
|
||||
// behaviors for segwit transactions.
|
||||
Behaviors actual_behavior{
|
||||
/*txid_rejects=*/txdownload_impl.RecentRejectsFilter().contains(parent_txid),
|
||||
/*wtxid_rejects=*/txdownload_impl.RecentRejectsFilter().contains(parent_wtxid),
|
||||
/*txid_recon=*/txdownload_impl.RecentRejectsReconsiderableFilter().contains(parent_txid),
|
||||
/*wtxid_recon=*/txdownload_impl.RecentRejectsReconsiderableFilter().contains(parent_wtxid),
|
||||
/*txid_rejects=*/txdownload_impl.RecentRejectsFilter().contains(parent_txid.ToUint256()),
|
||||
/*wtxid_rejects=*/txdownload_impl.RecentRejectsFilter().contains(parent_wtxid.ToUint256()),
|
||||
/*txid_recon=*/txdownload_impl.RecentRejectsReconsiderableFilter().contains(parent_txid.ToUint256()),
|
||||
/*wtxid_recon=*/txdownload_impl.RecentRejectsReconsiderableFilter().contains(parent_wtxid.ToUint256()),
|
||||
/*keep=*/keep,
|
||||
/*txid_inv=*/txdownload_impl.AddTxAnnouncement(nodeid, GenTxid::Txid(parent_txid), now),
|
||||
/*wtxid_inv=*/txdownload_impl.AddTxAnnouncement(nodeid, GenTxid::Wtxid(parent_wtxid), now),
|
||||
/*txid_inv=*/txdownload_impl.AddTxAnnouncement(nodeid, parent_txid, now),
|
||||
/*wtxid_inv=*/txdownload_impl.AddTxAnnouncement(nodeid, parent_wtxid, now),
|
||||
};
|
||||
BOOST_TEST_MESSAGE("Testing behavior for " << result << (segwit_parent ? " segwit " : " nonsegwit"));
|
||||
actual_behavior.CheckEqual(expected_behavior, /*segwit=*/segwit_parent);
|
||||
@@ -158,8 +158,8 @@ BOOST_FIXTURE_TEST_CASE(tx_rejection_types, TestChain100Setup)
|
||||
|
||||
// If parent (by txid) was rejected, child is too.
|
||||
const bool parent_txid_rejected{segwit_parent ? expected_behavior.m_txid_in_rejects : expected_behavior.m_wtxid_in_rejects};
|
||||
BOOST_CHECK_EQUAL(parent_txid_rejected, txdownload_impl.RecentRejectsFilter().contains(child_txid));
|
||||
BOOST_CHECK_EQUAL(parent_txid_rejected, txdownload_impl.RecentRejectsFilter().contains(child_wtxid));
|
||||
BOOST_CHECK_EQUAL(parent_txid_rejected, txdownload_impl.RecentRejectsFilter().contains(child_txid.ToUint256()));
|
||||
BOOST_CHECK_EQUAL(parent_txid_rejected, txdownload_impl.RecentRejectsFilter().contains(child_wtxid.ToUint256()));
|
||||
|
||||
// Unless rejected, the child should be in orphanage.
|
||||
BOOST_CHECK_EQUAL(!parent_txid_rejected, txdownload_impl.m_orphanage.HaveTx(ptx_child->GetWitnessHash()));
|
||||
|
||||
@@ -1090,7 +1090,7 @@ BOOST_AUTO_TEST_CASE(package_rbf_tests)
|
||||
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
|
||||
|
||||
// child1 has been replaced
|
||||
BOOST_CHECK(!m_node.mempool->exists(GenTxid::Txid(tx_child_1->GetHash())));
|
||||
BOOST_CHECK(!m_node.mempool->exists(tx_child_1->GetHash()));
|
||||
}
|
||||
|
||||
// Test package rbf.
|
||||
|
||||
@@ -103,7 +103,7 @@ public:
|
||||
void ForgetTxHash(const uint256& txhash)
|
||||
{
|
||||
auto& runner = m_runner;
|
||||
runner.actions.emplace_back(m_now, [=,&runner]() {
|
||||
runner.actions.emplace_back(m_now, [=, &runner]() {
|
||||
runner.txrequest.ForgetTxHash(txhash);
|
||||
runner.txrequest.SanityCheck();
|
||||
});
|
||||
@@ -113,7 +113,7 @@ public:
|
||||
void ReceivedInv(NodeId peer, const GenTxid& gtxid, bool pref, std::chrono::microseconds reqtime)
|
||||
{
|
||||
auto& runner = m_runner;
|
||||
runner.actions.emplace_back(m_now, [=,&runner]() {
|
||||
runner.actions.emplace_back(m_now, [=, &runner]() {
|
||||
runner.txrequest.ReceivedInv(peer, gtxid, pref, reqtime);
|
||||
runner.txrequest.SanityCheck();
|
||||
});
|
||||
@@ -123,7 +123,7 @@ public:
|
||||
void DisconnectedPeer(NodeId peer)
|
||||
{
|
||||
auto& runner = m_runner;
|
||||
runner.actions.emplace_back(m_now, [=,&runner]() {
|
||||
runner.actions.emplace_back(m_now, [=, &runner]() {
|
||||
runner.txrequest.DisconnectedPeer(peer);
|
||||
runner.txrequest.SanityCheck();
|
||||
});
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
void RequestedTx(NodeId peer, const uint256& txhash, std::chrono::microseconds exptime)
|
||||
{
|
||||
auto& runner = m_runner;
|
||||
runner.actions.emplace_back(m_now, [=,&runner]() {
|
||||
runner.actions.emplace_back(m_now, [=, &runner]() {
|
||||
runner.txrequest.RequestedTx(peer, txhash, exptime);
|
||||
runner.txrequest.SanityCheck();
|
||||
});
|
||||
@@ -143,7 +143,7 @@ public:
|
||||
void ReceivedResponse(NodeId peer, const uint256& txhash)
|
||||
{
|
||||
auto& runner = m_runner;
|
||||
runner.actions.emplace_back(m_now, [=,&runner]() {
|
||||
runner.actions.emplace_back(m_now, [=, &runner]() {
|
||||
runner.txrequest.ReceivedResponse(peer, txhash);
|
||||
runner.txrequest.SanityCheck();
|
||||
});
|
||||
@@ -161,17 +161,19 @@ public:
|
||||
* backwards (but note that the ordering of this event only follows the scenario's m_now.
|
||||
*/
|
||||
void Check(NodeId peer, const std::vector<GenTxid>& expected, size_t candidates, size_t inflight,
|
||||
size_t completed, const std::string& checkname,
|
||||
std::chrono::microseconds offset = std::chrono::microseconds{0})
|
||||
size_t completed, const std::string& checkname,
|
||||
std::chrono::microseconds offset = std::chrono::microseconds{0})
|
||||
{
|
||||
const auto comment = m_testname + " " + checkname;
|
||||
auto& runner = m_runner;
|
||||
const auto now = m_now;
|
||||
assert(offset.count() <= 0);
|
||||
runner.actions.emplace_back(m_now, [=,&runner]() {
|
||||
runner.actions.emplace_back(m_now, [=, &runner]() {
|
||||
std::vector<std::pair<NodeId, GenTxid>> expired_now;
|
||||
auto ret = runner.txrequest.GetRequestable(peer, now + offset, &expired_now);
|
||||
for (const auto& entry : expired_now) runner.expired.insert(entry);
|
||||
for (const auto& entry : expired_now) {
|
||||
runner.expired.insert(entry);
|
||||
}
|
||||
runner.txrequest.SanityCheck();
|
||||
runner.txrequest.PostGetRequestableSanityCheck(now + offset);
|
||||
size_t total = candidates + inflight + completed;
|
||||
@@ -193,7 +195,7 @@ public:
|
||||
{
|
||||
const auto& testname = m_testname;
|
||||
auto& runner = m_runner;
|
||||
runner.actions.emplace_back(m_now, [=,&runner]() {
|
||||
runner.actions.emplace_back(m_now, [=, &runner]() {
|
||||
auto it = runner.expired.find(std::pair<NodeId, GenTxid>{peer, gtxid});
|
||||
BOOST_CHECK_MESSAGE(it != runner.expired.end(), "[" + testname + "] missing expiration");
|
||||
if (it != runner.expired.end()) runner.expired.erase(it);
|
||||
@@ -233,10 +235,11 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Generate a random GenTxid; the txhash follows NewTxHash; the is_wtxid flag is random. */
|
||||
/** Generate a random GenTxid; the txhash follows NewTxHash; the transaction identifier is random. */
|
||||
GenTxid NewGTxid(const std::vector<std::vector<NodeId>>& orders = {})
|
||||
{
|
||||
return m_rng.randbool() ? GenTxid::Wtxid(NewTxHash(orders)) : GenTxid::Txid(NewTxHash(orders));
|
||||
const uint256 txhash{NewTxHash(orders)};
|
||||
return m_rng.randbool() ? GenTxid{Wtxid::FromUint256(txhash)} : GenTxid{Txid::FromUint256(txhash)};
|
||||
}
|
||||
|
||||
/** Generate a new random NodeId to use as peer. The same NodeId is never returned twice
|
||||
@@ -285,7 +288,7 @@ void TxRequestTest::BuildSingleTest(Scenario& scenario, int config)
|
||||
scenario.AdvanceTime(RandomTime8s());
|
||||
auto expiry = RandomTime8s();
|
||||
scenario.Check(peer, {gtxid}, 1, 0, 0, "s5");
|
||||
scenario.RequestedTx(peer, gtxid.GetHash(), scenario.Now() + expiry);
|
||||
scenario.RequestedTx(peer, gtxid.ToUint256(), scenario.Now() + expiry);
|
||||
scenario.Check(peer, {}, 0, 1, 0, "s6");
|
||||
|
||||
if ((config >> 3) == 1) { // The request will time out
|
||||
@@ -299,7 +302,7 @@ void TxRequestTest::BuildSingleTest(Scenario& scenario, int config)
|
||||
scenario.AdvanceTime(std::chrono::microseconds{m_rng.randrange(expiry.count())});
|
||||
scenario.Check(peer, {}, 0, 1, 0, "s9");
|
||||
if ((config >> 3) == 3) { // A response will arrive for the transaction
|
||||
scenario.ReceivedResponse(peer, gtxid.GetHash());
|
||||
scenario.ReceivedResponse(peer, gtxid.ToUint256());
|
||||
scenario.Check(peer, {}, 0, 0, 0, "s10");
|
||||
return;
|
||||
}
|
||||
@@ -309,7 +312,7 @@ void TxRequestTest::BuildSingleTest(Scenario& scenario, int config)
|
||||
if (config & 4) { // The peer will go offline
|
||||
scenario.DisconnectedPeer(peer);
|
||||
} else { // The transaction is no longer needed
|
||||
scenario.ForgetTxHash(gtxid.GetHash());
|
||||
scenario.ForgetTxHash(gtxid.ToUint256());
|
||||
}
|
||||
scenario.Check(peer, {}, 0, 0, 0, "s11");
|
||||
}
|
||||
@@ -355,7 +358,7 @@ void TxRequestTest::BuildPriorityTest(Scenario& scenario, int config)
|
||||
|
||||
// We possibly request from the selected peer.
|
||||
if (config & 8) {
|
||||
scenario.RequestedTx(priopeer, gtxid.GetHash(), MAX_TIME);
|
||||
scenario.RequestedTx(priopeer, gtxid.ToUint256(), MAX_TIME);
|
||||
scenario.Check(priopeer, {}, 0, 1, 0, "p7");
|
||||
scenario.Check(otherpeer, {}, 1, 0, 0, "p8");
|
||||
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
|
||||
@@ -365,7 +368,7 @@ void TxRequestTest::BuildPriorityTest(Scenario& scenario, int config)
|
||||
if (config & 16) {
|
||||
scenario.DisconnectedPeer(priopeer);
|
||||
} else {
|
||||
scenario.ReceivedResponse(priopeer, gtxid.GetHash());
|
||||
scenario.ReceivedResponse(priopeer, gtxid.ToUint256());
|
||||
}
|
||||
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
|
||||
scenario.Check(priopeer, {}, 0, 0, !(config & 16), "p8");
|
||||
@@ -449,7 +452,7 @@ void TxRequestTest::BuildBigPriorityTest(Scenario& scenario, int peers)
|
||||
scenario.DisconnectedPeer(peer);
|
||||
scenario.Check(peer, {}, 0, 0, 0, "b4");
|
||||
} else {
|
||||
scenario.ReceivedResponse(peer, gtxid.GetHash());
|
||||
scenario.ReceivedResponse(peer, gtxid.ToUint256());
|
||||
scenario.Check(peer, {}, 0, 0, request_order.size() > 0, "b5");
|
||||
}
|
||||
if (request_order.size()) {
|
||||
@@ -510,8 +513,8 @@ void TxRequestTest::BuildWtxidTest(Scenario& scenario, int config)
|
||||
auto peerT = scenario.NewPeer();
|
||||
auto peerW = scenario.NewPeer();
|
||||
auto txhash = scenario.NewTxHash();
|
||||
auto txid{GenTxid::Txid(txhash)};
|
||||
auto wtxid{GenTxid::Wtxid(txhash)};
|
||||
auto txid{Txid::FromUint256(txhash)};
|
||||
auto wtxid{Wtxid::FromUint256(txhash)};
|
||||
|
||||
auto reqtimeT = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s();
|
||||
auto reqtimeW = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s();
|
||||
@@ -542,11 +545,11 @@ void TxRequestTest::BuildWtxidTest(Scenario& scenario, int config)
|
||||
// Let the preferred announcement be requested. It's not going to be delivered.
|
||||
auto expiry = RandomTime8s();
|
||||
if (config & 2) {
|
||||
scenario.RequestedTx(peerT, txid.GetHash(), scenario.Now() + expiry);
|
||||
scenario.RequestedTx(peerT, txid.ToUint256(), scenario.Now() + expiry);
|
||||
scenario.Check(peerT, {}, 0, 1, 0, "w5");
|
||||
scenario.Check(peerW, {}, 1, 0, 0, "w6");
|
||||
} else {
|
||||
scenario.RequestedTx(peerW, wtxid.GetHash(), scenario.Now() + expiry);
|
||||
scenario.RequestedTx(peerW, wtxid.ToUint256(), scenario.Now() + expiry);
|
||||
scenario.Check(peerT, {}, 1, 0, 0, "w7");
|
||||
scenario.Check(peerW, {}, 0, 1, 0, "w8");
|
||||
}
|
||||
@@ -599,7 +602,7 @@ void TxRequestTest::BuildTimeBackwardsTest(Scenario& scenario)
|
||||
// Request from peer1.
|
||||
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
|
||||
auto expiry = scenario.Now() + RandomTime8s();
|
||||
scenario.RequestedTx(peer1, gtxid.GetHash(), expiry);
|
||||
scenario.RequestedTx(peer1, gtxid.ToUint256(), expiry);
|
||||
scenario.Check(peer1, {}, 0, 1, 0, "r7");
|
||||
scenario.Check(peer2, {}, 1, 0, 0, "r8");
|
||||
|
||||
@@ -638,20 +641,20 @@ void TxRequestTest::BuildWeirdRequestsTest(Scenario& scenario)
|
||||
|
||||
// We request gtxid2 from *peer1* - no effect.
|
||||
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
|
||||
scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME);
|
||||
scenario.RequestedTx(peer1, gtxid2.ToUint256(), MAX_TIME);
|
||||
scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q4");
|
||||
scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q5");
|
||||
|
||||
// Now request gtxid1 from peer1 - marks it as REQUESTED.
|
||||
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
|
||||
auto expiryA = scenario.Now() + RandomTime8s();
|
||||
scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryA);
|
||||
scenario.RequestedTx(peer1, gtxid1.ToUint256(), expiryA);
|
||||
scenario.Check(peer1, {}, 0, 1, 0, "q6");
|
||||
scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q7");
|
||||
|
||||
// Request it a second time - nothing happens, as it's already REQUESTED.
|
||||
auto expiryB = expiryA + RandomTime8s();
|
||||
scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryB);
|
||||
scenario.RequestedTx(peer1, gtxid1.ToUint256(), expiryB);
|
||||
scenario.Check(peer1, {}, 0, 1, 0, "q8");
|
||||
scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q9");
|
||||
|
||||
@@ -668,7 +671,7 @@ void TxRequestTest::BuildWeirdRequestsTest(Scenario& scenario)
|
||||
|
||||
// Requesting it yet again from peer1 doesn't do anything, as it's already COMPLETED.
|
||||
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
|
||||
scenario.RequestedTx(peer1, gtxid1.GetHash(), MAX_TIME);
|
||||
scenario.RequestedTx(peer1, gtxid1.ToUint256(), MAX_TIME);
|
||||
scenario.Check(peer1, {}, 0, 0, 1, "q14");
|
||||
scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q15");
|
||||
|
||||
@@ -680,13 +683,13 @@ void TxRequestTest::BuildWeirdRequestsTest(Scenario& scenario)
|
||||
|
||||
// And request it from peer1 (weird as peer2 has the preference).
|
||||
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
|
||||
scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME);
|
||||
scenario.RequestedTx(peer1, gtxid2.ToUint256(), MAX_TIME);
|
||||
scenario.Check(peer1, {}, 0, 1, 1, "q18");
|
||||
scenario.Check(peer2, {gtxid1}, 2, 0, 0, "q19");
|
||||
|
||||
// If peer2 now (normally) requests gtxid2, the existing request by peer1 becomes COMPLETED.
|
||||
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
|
||||
scenario.RequestedTx(peer2, gtxid2.GetHash(), MAX_TIME);
|
||||
scenario.RequestedTx(peer2, gtxid2.ToUint256(), MAX_TIME);
|
||||
scenario.Check(peer1, {}, 0, 0, 2, "q20");
|
||||
scenario.Check(peer2, {gtxid1}, 1, 1, 0, "q21");
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
|
||||
Package package_v3_v2{mempool_tx_v3, tx_v2_from_v3};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), package_v3_v2, empty_ancestors), expected_error_str);
|
||||
CTxMemPool::setEntries entries_mempool_v3{pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value()};
|
||||
CTxMemPool::setEntries entries_mempool_v3{pool.GetIter(mempool_tx_v3->GetHash()).value()};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), {tx_v2_from_v3}, entries_mempool_v3), expected_error_str);
|
||||
|
||||
// mempool_tx_v3 mempool_tx_v2
|
||||
@@ -339,7 +339,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
|
||||
Package package_v2_v3{mempool_tx_v2, tx_v3_from_v2};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), package_v2_v3, empty_ancestors), expected_error_str);
|
||||
CTxMemPool::setEntries entries_mempool_v2{pool.GetIter(mempool_tx_v2->GetHash().ToUint256()).value()};
|
||||
CTxMemPool::setEntries entries_mempool_v2{pool.GetIter(mempool_tx_v2->GetHash()).value()};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), {tx_v3_from_v2}, entries_mempool_v2), expected_error_str);
|
||||
|
||||
// mempool_tx_v3 mempool_tx_v2
|
||||
@@ -536,7 +536,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
// Configuration where parent already has 2 other children in mempool (no sibling eviction allowed). This may happen as the result of a reorg.
|
||||
AddToMempool(pool, entry.FromTx(tx_v3_child2));
|
||||
auto tx_v3_child3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 24}}, /*version=*/3);
|
||||
auto entry_mempool_parent = pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value();
|
||||
auto entry_mempool_parent = pool.GetIter(mempool_tx_v3->GetHash()).value();
|
||||
BOOST_CHECK_EQUAL(entry_mempool_parent->GetCountWithDescendants(), 3);
|
||||
auto ancestors_2siblings{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child3), m_limits)};
|
||||
|
||||
|
||||
@@ -122,17 +122,17 @@ std::optional<std::string> CheckPackageMempoolAcceptResult(const Package& txns,
|
||||
if (mempool) {
|
||||
// The tx by txid should be in the mempool iff the result was not INVALID.
|
||||
const bool txid_in_mempool{atmp_result.m_result_type != MempoolAcceptResult::ResultType::INVALID};
|
||||
if (mempool->exists(GenTxid::Txid(tx->GetHash())) != txid_in_mempool) {
|
||||
if (mempool->exists(tx->GetHash()) != txid_in_mempool) {
|
||||
return strprintf("tx %s should %sbe in mempool", wtxid.ToString(), txid_in_mempool ? "" : "not ");
|
||||
}
|
||||
// Additionally, if the result was DIFFERENT_WITNESS, we shouldn't be able to find the tx in mempool by wtxid.
|
||||
if (tx->HasWitness() && atmp_result.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS) {
|
||||
if (mempool->exists(GenTxid::Wtxid(wtxid))) {
|
||||
if (mempool->exists(wtxid)) {
|
||||
return strprintf("wtxid %s should not be in mempool", wtxid.ToString());
|
||||
}
|
||||
}
|
||||
for (const auto& tx_ref : atmp_result.m_replaced_transactions) {
|
||||
if (mempool->exists(GenTxid::Txid(tx_ref->GetHash()))) {
|
||||
if (mempool->exists(tx_ref->GetHash())) {
|
||||
return strprintf("tx %s should not be in mempool as it was replaced", tx_ref->GetWitnessHash().ToString());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user