30constexpr size_t NUM_COINS{50};
50std::vector<CTransactionRef> TRANSACTIONS;
53constexpr int NUM_PEERS = 16;
56std::chrono::microseconds TIME_SKIPS[128];
62 for (
const auto& outpoint : outpoints) {
63 tx.
vin.emplace_back(outpoint);
66 tx.
vin[0].scriptWitness.stack.push_back({1});
73 std::vector<COutPoint>
ret;
83 static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
84 g_setup = testing_setup.get();
85 for (uint32_t i = 0; i < uint32_t{NUM_COINS}; ++i) {
88 size_t outpoints_index = 0;
93 Assert(tx1->GetHash() == tx2->GetHash());
94 TRANSACTIONS.emplace_back(tx1);
95 TRANSACTIONS.emplace_back(tx2);
101 TRANSACTIONS.emplace_back(tx_parent_1);
103 TRANSACTIONS.emplace_back(tx_parent_2);
110 TRANSACTIONS.emplace_back(tx_parent);
118 COutPoint& last_outpoint = COINS[outpoints_index++];
119 for (
auto i{0}; i < 5; ++i) {
121 TRANSACTIONS.emplace_back(tx);
127 COutPoint& last_outpoint = COINS[outpoints_index++];
128 for (
auto i{0}; i < 5; ++i) {
130 TRANSACTIONS.emplace_back(tx);
136 for (
const auto& outpoint : COINS) {
143 for (; i < 16; ++i) {
144 TIME_SKIPS[i] = std::chrono::microseconds{i};
148 for (; i < 128; ++i) {
149 int diff_bits = ((i - 10) * 2) / 9;
151 TIME_SKIPS[i] = TIME_SKIPS[i - 1] + std::chrono::microseconds{diff};
162 const auto&
package = package_to_validate.m_txns;
164 Assert(package.size() == 2);
179 std::chrono::microseconds time{244466666};
186 auto rand_tx = fuzzed_data_provider.
ConsumeBool() ?
190 TRANSACTIONS.at(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, TRANSACTIONS.size() - 1));
193 fuzzed_data_provider,
197 .m_relay_permissions = fuzzed_data_provider.
ConsumeBool(),
198 .m_wtxid_relay = fuzzed_data_provider.
ConsumeBool()
200 txdownloadman.ConnectedPeer(rand_peer, info);
203 txdownloadman.DisconnectedPeer(rand_peer);
204 txdownloadman.CheckIsEmpty(rand_peer);
207 txdownloadman.ActiveTipChange();
211 block.
vtx.push_back(rand_tx);
212 txdownloadman.BlockConnected(std::make_shared<CBlock>(block));
215 txdownloadman.BlockDisconnected();
218 txdownloadman.MempoolAcceptedTx(rand_tx);
223 bool first_time_failure{fuzzed_data_provider.ConsumeBool()};
225 node::RejectedTxTodo todo = txdownloadman.MempoolRejectedTx(rand_tx, state, rand_peer, first_time_failure);
226 Assert(first_time_failure || !todo.m_should_add_extra_compact_tx);
231 GenTxid{rand_tx->GetWitnessHash()};
232 txdownloadman.AddTxAnnouncement(rand_peer, gtxid, time);
235 txdownloadman.GetRequestsToSend(rand_peer, time);
238 txdownloadman.ReceivedTx(rand_peer, rand_tx);
239 const auto& [should_validate, maybe_package] = txdownloadman.ReceivedTx(rand_peer, rand_tx);
245 Assert(!(should_validate && maybe_package.has_value()));
246 if (maybe_package.has_value()) CheckPackageToValidate(*maybe_package, rand_peer);
249 txdownloadman.ReceivedNotFound(rand_peer, {rand_tx->GetWitnessHash()});
252 const bool expect_work{txdownloadman.HaveMoreWork(rand_peer)};
253 const auto ptx = txdownloadman.GetTxToReconsider(rand_peer);
265 if (fuzzed_data_provider.
ConsumeBool()) time_skip *= -1;
269 for (
NodeId nodeid = 0; nodeid < NUM_PEERS; ++nodeid) {
270 txdownloadman.DisconnectedPeer(nodeid);
271 txdownloadman.CheckIsEmpty(nodeid);
273 txdownloadman.CheckIsEmpty();
278static bool HasRelayPermissions(
NodeId peer) {
return peer == 0; }
284 for (
NodeId peer = 0; peer < NUM_PEERS; ++peer) {
285 if (!HasRelayPermissions(peer)) {
304 std::chrono::microseconds time{244466666};
311 auto rand_tx = fuzzed_data_provider.
ConsumeBool() ?
315 TRANSACTIONS.at(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, TRANSACTIONS.size() - 1));
318 fuzzed_data_provider,
322 .m_relay_permissions = HasRelayPermissions(rand_peer),
323 .m_wtxid_relay = fuzzed_data_provider.
ConsumeBool()
334 for (
const auto& tx : TRANSACTIONS) {
343 block.
vtx.push_back(rand_tx);
359 bool first_time_failure{fuzzed_data_provider.
ConsumeBool()};
370 GenTxid{rand_tx->GetWitnessHash()};
374 const auto getdata_requests = txdownload_impl.
GetRequestsToSend(rand_peer, time);
377 for (
const auto& gtxid : getdata_requests) {
382 const auto& [should_validate, maybe_package] = txdownload_impl.
ReceivedTx(rand_peer, rand_tx);
388 Assert(!(should_validate && maybe_package.has_value()));
389 if (should_validate) {
392 if (maybe_package.has_value()) {
393 CheckPackageToValidate(*maybe_package, rand_peer);
395 const auto&
package = maybe_package->m_txns;
398 Assert(txdownload_impl.
m_orphanage->HaveTx(maybe_package->m_txns.back()->GetWitnessHash()));
410 const bool expect_work{txdownload_impl.
HaveMoreWork(rand_peer)};
430 if (fuzzed_data_provider.
ConsumeBool()) time_skip *= -1;
433 CheckInvariants(txdownload_impl);
435 for (
NodeId nodeid = 0; nodeid < NUM_PEERS; ++nodeid) {
#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
uint64_t Finalize() const
Compute the 64-bit SipHash-2-4 of the data written so far.
CSipHasher & Write(uint64_t data)
Hash a 64-bit integer worth of data It is treated as if this was the little-endian interpretation of ...
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
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 ...
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.
static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS
Maximum number of transactions to consider for requesting, per peer.
static CTransactionRef MakeTransactionSpending(const std::vector< COutPoint > &outpoints, FastRandomContext &det_rand)
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...
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::shared_ptr< const CTransaction > CTransactionRef
static constexpr CAmount CENT
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
const bool m_preferred
Whether this peer is preferred for transaction download.
int64_t 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)
void SeedRandomStateForTest(SeedRand seedtype)
Seed the global RNG state for testing and log the seed value.
@ ZEROS
Seed with a compile time constant of zeros.
static const CScript P2WSH_OP_TRUE
CTxMemPool::Options MemPoolOptionsForTest(const NodeContext &node)
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.