31constexpr size_t NUM_COINS{50};
51std::vector<CTransactionRef> TRANSACTIONS;
54constexpr int NUM_PEERS = 16;
57std::chrono::microseconds TIME_SKIPS[128];
59static CTransactionRef MakeTransactionSpending(
const std::vector<COutPoint>& outpoints,
size_t num_outputs,
bool add_witness)
63 for (
const auto& outpoint : outpoints) {
64 tx.
vin.emplace_back(outpoint);
67 tx.
vin[0].scriptWitness.stack.push_back({1});
69 for (
size_t o = 0; o < num_outputs; ++o) tx.
vout.emplace_back(
CENT, P2WSH_OP_TRUE);
70 return MakeTransactionRef(tx);
74 std::vector<COutPoint>
ret;
86 for (uint32_t i = 0; i < uint32_t{NUM_COINS}; ++i) {
89 size_t outpoints_index = 0;
92 auto tx1{MakeTransactionSpending({COINS[outpoints_index]}, 5,
false)};
93 auto tx2{MakeTransactionSpending({COINS[outpoints_index]}, 5,
true)};
94 Assert(tx1->GetHash() == tx2->GetHash());
95 TRANSACTIONS.emplace_back(tx1);
96 TRANSACTIONS.emplace_back(tx2);
101 auto tx_parent_1{MakeTransactionSpending({COINS[outpoints_index++]}, 1,
true)};
102 TRANSACTIONS.emplace_back(tx_parent_1);
103 auto tx_parent_2{MakeTransactionSpending({COINS[outpoints_index++]}, 1,
false)};
104 TRANSACTIONS.emplace_back(tx_parent_2);
105 TRANSACTIONS.emplace_back(MakeTransactionSpending({
COutPoint{tx_parent_1->GetHash(), 0},
COutPoint{tx_parent_2->GetHash(), 0}},
110 auto tx_parent{MakeTransactionSpending({COINS[outpoints_index++]}, 2,
true)};
111 TRANSACTIONS.emplace_back(tx_parent);
112 TRANSACTIONS.emplace_back(MakeTransactionSpending({
COutPoint{tx_parent->GetHash(), 0}},
114 TRANSACTIONS.emplace_back(MakeTransactionSpending({
COutPoint{tx_parent->GetHash(), 1}},
119 COutPoint& last_outpoint = COINS[outpoints_index++];
120 for (
auto i{0}; i < 5; ++i) {
121 auto tx{MakeTransactionSpending({last_outpoint}, 1,
true)};
122 TRANSACTIONS.emplace_back(tx);
128 COutPoint& last_outpoint = COINS[outpoints_index++];
129 for (
auto i{0}; i < 5; ++i) {
130 auto tx{MakeTransactionSpending({last_outpoint}, 1,
false)};
131 TRANSACTIONS.emplace_back(tx);
137 for (
const auto& outpoint : COINS) {
138 TRANSACTIONS.emplace_back(MakeTransactionSpending({outpoint}, 1,
true));
144 for (; i < 16; ++i) {
145 TIME_SKIPS[i] = std::chrono::microseconds{i};
149 for (; i < 128; ++i) {
150 int diff_bits = ((i - 10) * 2) / 9;
151 uint64_t diff = 1 + (
CSipHasher(0, 0).Write(i).Finalize() >> (64 - diff_bits));
152 TIME_SKIPS[i] = TIME_SKIPS[i - 1] + std::chrono::microseconds{diff};
163 const auto&
package = package_to_validate.m_txns;
165 Assert(package.size() == 2);
179 std::chrono::microseconds time{244466666};
185 auto rand_tx = fuzzed_data_provider.
ConsumeBool() ?
186 MakeTransactionSpending(PickCoins(fuzzed_data_provider),
189 TRANSACTIONS.at(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, TRANSACTIONS.size() - 1));
192 fuzzed_data_provider,
196 .m_relay_permissions = fuzzed_data_provider.
ConsumeBool(),
197 .m_wtxid_relay = fuzzed_data_provider.
ConsumeBool()
210 block.
vtx.push_back(rand_tx);
222 bool first_time_failure{fuzzed_data_provider.
ConsumeBool()};
230 GenTxid{rand_tx->GetWitnessHash()};
238 const auto& [should_validate, maybe_package] = txdownloadman.
ReceivedTx(rand_peer, rand_tx);
244 Assert(!(should_validate && maybe_package.has_value()));
245 if (maybe_package.has_value()) CheckPackageToValidate(*maybe_package, rand_peer);
251 const bool expect_work{txdownloadman.
HaveMoreWork(rand_peer)};
264 if (fuzzed_data_provider.
ConsumeBool()) time_skip *= -1;
268 for (
NodeId nodeid = 0; nodeid < NUM_PEERS; ++nodeid) {
277static bool HasRelayPermissions(
NodeId peer) {
return peer == 0; }
283 for (
NodeId peer = 0; peer < NUM_PEERS; ++peer) {
284 if (!HasRelayPermissions(peer)) {
302 std::chrono::microseconds time{244466666};
308 auto rand_tx = fuzzed_data_provider.
ConsumeBool() ?
309 MakeTransactionSpending(PickCoins(fuzzed_data_provider),
312 TRANSACTIONS.at(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, TRANSACTIONS.size() - 1));
315 fuzzed_data_provider,
319 .m_relay_permissions = HasRelayPermissions(rand_peer),
320 .m_wtxid_relay = fuzzed_data_provider.
ConsumeBool()
331 for (
const auto& tx : TRANSACTIONS) {
340 block.
vtx.push_back(rand_tx);
356 bool first_time_failure{fuzzed_data_provider.
ConsumeBool()};
367 GenTxid{rand_tx->GetWitnessHash()};
371 const auto getdata_requests = txdownload_impl.
GetRequestsToSend(rand_peer, time);
374 for (
const auto& gtxid : getdata_requests) {
379 const auto& [should_validate, maybe_package] = txdownload_impl.
ReceivedTx(rand_peer, rand_tx);
385 Assert(!(should_validate && maybe_package.has_value()));
386 if (should_validate) {
389 if (maybe_package.has_value()) {
390 CheckPackageToValidate(*maybe_package, rand_peer);
392 const auto&
package = maybe_package->m_txns;
395 Assert(txdownload_impl.
m_orphanage->HaveTx(maybe_package->m_txns.back()->GetWitnessHash()));
407 const bool expect_work{txdownload_impl.
HaveMoreWork(rand_peer)};
427 if (fuzzed_data_provider.
ConsumeBool()) time_skip *= -1;
430 CheckInvariants(txdownload_impl);
432 for (
NodeId nodeid = 0; nodeid < NUM_PEERS; ++nodeid) {
const TestingSetup * g_setup
#define Assert(val)
Identity function.
std::vector< CTransactionRef > vtx
An outpoint - a combination of a transaction hash and an index n into its vout.
bool contains(std::span< const unsigned char > vKey) const
CSipHasher(uint64_t k0, uint64_t k1)
Construct a SipHash calculator initialized with 128-bit key (k0, k1).
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Helper to initialize the global NodeClock, let a duration elapse, and reset it after use in a test.
T ConsumeIntegralInRange(T min, T max)
T PickValueInArray(const T(&array)[size])
A writer stream (for serialization) that computes a 256-bit hash.
void SanityCheck() const
Run internal consistency check (testing only).
size_t Count(NodeId peer) const
Count how many announcements a peer has (REQUESTED, CANDIDATE, and COMPLETED combined).
bool Invalid(Result result, const std::string &reject_reason="", const std::string &debug_message="")
Class responsible for deciding what transactions to request and, once downloaded, whether and how to ...
std::vector< GenTxid > GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
Get getdata requests to send.
void ReceivedNotFound(NodeId nodeid, const std::vector< GenTxid > >xids)
Should be called when a notfound for a tx has been received.
std::pair< bool, std::optional< PackageToValidate > > ReceivedTx(NodeId nodeid, const CTransactionRef &ptx)
Marks a tx as ReceivedResponse in txrequest and checks whether AlreadyHaveTx.
bool AddTxAnnouncement(NodeId peer, const GenTxid >xid, std::chrono::microseconds now)
Consider adding this tx hash to txrequest.
void BlockConnected(const std::shared_ptr< const CBlock > &pblock)
CTransactionRef GetTxToReconsider(NodeId nodeid)
Returns next orphan tx to consider, or nullptr if none exist.
void CheckIsEmpty() const
Check that all data structures are empty.
void MempoolAcceptedTx(const CTransactionRef &tx)
Respond to successful transaction submission to mempool.
void ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo &info)
Creates a new PeerInfo.
void DisconnectedPeer(NodeId nodeid)
Deletes all txrequest announcements and orphans for a given peer.
RejectedTxTodo MempoolRejectedTx(const CTransactionRef &ptx, const TxValidationState &state, NodeId nodeid, bool first_time_failure)
Respond to transaction rejected from mempool.
bool HaveMoreWork(NodeId nodeid) const
Whether there are any orphans to reconsider for this peer.
bool AddTxAnnouncement(NodeId peer, const GenTxid >xid, std::chrono::microseconds now)
Consider adding this tx hash to txrequest.
CRollingBloomFilter & RecentConfirmedTransactionsFilter()
std::unique_ptr< TxOrphanage > m_orphanage
Manages unvalidated tx data (orphan transactions for which we are downloading ancestors).
void DisconnectedPeer(NodeId nodeid)
void ReceivedNotFound(NodeId nodeid, const std::vector< GenTxid > >xids)
Marks a tx as ReceivedResponse in txrequest.
bool HaveMoreWork(NodeId nodeid)
TxRequestTracker m_txrequest
Tracks candidates for requesting and downloading transaction data.
std::pair< bool, std::optional< PackageToValidate > > ReceivedTx(NodeId nodeid, const CTransactionRef &ptx)
void MempoolAcceptedTx(const CTransactionRef &tx)
CRollingBloomFilter & RecentRejectsReconsiderableFilter()
RejectedTxTodo MempoolRejectedTx(const CTransactionRef &ptx, const TxValidationState &state, NodeId nodeid, bool first_time_failure)
void ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo &info)
bool AlreadyHaveTx(const GenTxid >xid, bool include_reconsiderable)
Check whether we already have this gtxid in:
std::vector< GenTxid > GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
Get getdata requests to send.
void BlockConnected(const std::shared_ptr< const CBlock > &pblock)
CTransactionRef GetTxToReconsider(NodeId nodeid)
CRollingBloomFilter & RecentRejectsFilter()
const uint256 & ToUint256() const LIFETIMEBOUND
static transaction_identifier FromUint256(const uint256 &id)
TxValidationResult
A "reason" why a transaction was invalid, suitable for determining whether the provider of the transa...
@ TX_MISSING_INPUTS
transaction was missing some of its inputs
@ TX_MEMPOOL_POLICY
violated mempool's fee/size/descendant/RBF/etc limits
@ TX_UNKNOWN
transaction was not validated because package failed
@ TX_PREMATURE_SPEND
transaction spends a coinbase too early, or violates locktime/sequence locks
@ TX_INPUTS_NOT_STANDARD
inputs (covered by txid) failed policy rules
@ TX_WITNESS_STRIPPED
Transaction is missing a witness.
@ TX_CONFLICT
Tx already in mempool or conflicts with a tx in the chain (if it conflicts with another tx in mempool...
@ TX_NOT_STANDARD
otherwise didn't meet our local policy rules
@ TX_WITNESS_MUTATED
Transaction might have a witness prior to SegWit activation, or witness may have been malleated (whic...
@ TX_CONSENSUS
invalid by consensus rules
@ TX_RECONSIDERABLE
fails some policy, but might be acceptable if submitted in a (different) package
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS
Maximum number of transactions to consider for requesting, per peer.
bool IsChildWithParents(const Package &package)
Context-free check that a package is exactly one child and its parents; not all parents need to be pr...
uint256 GetPackageHash(const std::vector< CTransactionRef > &transactions)
Get the hash of the concatenated wtxids of transactions, with wtxids treated as a little-endian numbe...
std::shared_ptr< const CTransaction > CTransactionRef
std::unique_ptr< T > MakeNoLogFileContext(const ChainType chain_type=ChainType::REGTEST, TestOpts opts={})
Make a test setup that has disk access to the debug.log file disabled.
A mutable version of CTransaction.
std::vector< CTxOut > vout
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Testing setup that configures a complete environment.
std::vector< NodeId > m_senders
bool m_should_add_extra_compact_tx
std::vector< Txid > m_unique_parents
SeedRandomStateForTest(SeedRand::ZEROS)
NodeSeconds ConsumeTime(FuzzedDataProvider &fuzzed_data_provider, const std::optional< int64_t > &min, const std::optional< int64_t > &max) noexcept
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
@ ZEROS
Seed with a compile time constant of zeros.
CTxMemPool::Options MemPoolOptionsForTest(const NodeContext &node)