7 #include <chainparams.h> 15 #include <util/time.h> 27 .signals =
node.validation_signals.get(),
50 if (
result.m_state.IsInvalid()) {
51 return strprintf(
"Package validation unexpectedly failed: %s",
result.m_state.ToString());
54 if (
result.m_state.IsValid()) {
55 return strprintf(
"Package validation unexpectedly succeeded. %s",
result.m_state.ToString());
59 return strprintf(
"txns size %u does not match tx results size %u", txns.size(),
result.m_tx_results.size());
61 for (
const auto& tx : txns) {
62 const auto& wtxid = tx->GetWitnessHash();
63 if (!
result.m_tx_results.contains(wtxid)) {
64 return strprintf(
"result not found for tx %s", wtxid.ToString());
67 const auto& atmp_result =
result.m_tx_results.at(wtxid);
69 if (expect_valid && atmp_result.m_state.IsInvalid()) {
70 return strprintf(
"tx %s unexpectedly failed: %s", wtxid.ToString(), atmp_result.m_state.ToString());
75 return strprintf(
"tx %s result replaced too many transactions",
80 if (!atmp_result.m_replaced_transactions.empty() &&
81 atmp_result.m_wtxids_fee_calculations.has_value() && atmp_result.m_wtxids_fee_calculations.value().size() > 2) {
82 return strprintf(
"tx %s was part of a too-large package RBF subpackage",
86 if (!atmp_result.m_replaced_transactions.empty() && mempool) {
89 if (atmp_result.m_wtxids_fee_calculations.has_value() && atmp_result.m_wtxids_fee_calculations.value().size() == 2) {
91 if (cluster.size() != 2)
return strprintf(
"tx %s has too many ancestors or descendants for a package rbf", wtxid.ToString());
97 if (atmp_result.m_base_fees.has_value() != (valid || mempool_entry)) {
98 return strprintf(
"tx %s result should %shave m_base_fees", wtxid.ToString(), valid || mempool_entry ?
"" :
"not ");
100 if (atmp_result.m_vsize.has_value() != (valid || mempool_entry)) {
101 return strprintf(
"tx %s result should %shave m_vsize", wtxid.ToString(), valid || mempool_entry ?
"" :
"not ");
106 if (atmp_result.m_other_wtxid.has_value() != diff_witness) {
107 return strprintf(
"tx %s result should %shave m_other_wtxid", wtxid.ToString(), diff_witness ?
"" :
"not ");
114 if (atmp_result.m_effective_feerate.has_value() != valid_or_reconsiderable) {
115 return strprintf(
"tx %s result should %shave m_effective_feerate",
116 wtxid.ToString(), valid ?
"" :
"not ");
118 if (atmp_result.m_wtxids_fee_calculations.has_value() != valid_or_reconsiderable) {
119 return strprintf(
"tx %s result should %shave m_effective_feerate",
120 wtxid.ToString(), valid ?
"" :
"not ");
126 if (mempool->
exists(tx->GetHash()) != txid_in_mempool) {
127 return strprintf(
"tx %s should %sbe in mempool", wtxid.ToString(), txid_in_mempool ?
"" :
"not ");
131 if (mempool->
exists(wtxid)) {
132 return strprintf(
"wtxid %s should not be in mempool", wtxid.ToString());
135 for (
const auto& tx_ref : atmp_result.m_replaced_transactions) {
136 if (mempool->
exists(tx_ref->GetHash())) {
137 return strprintf(
"tx %s should not be in mempool as it was replaced", tx_ref->GetWitnessHash().ToString());
148 for (
const auto& tx_info : tx_pool.
infoAll()) {
149 const auto& entry = *
Assert(tx_pool.
GetEntry(tx_info.tx->GetHash()));
153 Assert(dust_indexes.size() < 2);
155 if (dust_indexes.empty())
continue;
158 Assert(entry.GetFee() == 0 && entry.GetModifiedFee() == 0);
165 Assert(children.size() < 2);
167 if (children.empty()) {
174 const auto& only_child = children.begin()->get().GetTx();
175 COutPoint dust_outpoint{tx_info.tx->GetHash(), dust_indexes[0]};
176 Assert(std::any_of(only_child.vin.begin(), only_child.vin.end(), [&dust_outpoint](
const CTxIn& txin) {
177 return txin.prevout == dust_outpoint;
185 for (
const auto& tx_info : tx_pool.
infoAll()) {
186 const auto& entry = *
Assert(tx_pool.
GetEntry(tx_info.tx->GetHash()));
203 const auto& parents = tx_pool.
GetParents(entry);
206 }
else if (anc_count > 1) {
208 for (
const auto& parent : tx_pool.
GetParents(entry)) {
222 if (changeset->CheckMemPoolPolicyLimits()) changeset->Apply();
251 changeset->StageAddition(tx, tx_fee,
std::shared_ptr< const CTransaction > CTransactionRef
void MockMempoolMinFee(const CFeeRate &target_feerate, CTxMemPool &mempool)
Mock the mempool minimum feerate by adding a transaction and calling TrimToSize(0), simulating the mempool "reaching capacity" and evicting by descendant feerate.
static constexpr int64_t TRUC_CHILD_MAX_VSIZE
Maximum sigop-adjusted virtual size of a tx which spends from an unconfirmed TRUC transaction...
std::vector< TxMempoolInfo > infoAll() const
static constexpr uint32_t MAX_REPLACEMENT_CANDIDATES
Maximum number of unique clusters that can be affected by an RBF (Rule #5); see GetEntriesForConflict...
The package itself is invalid (e.g. too many transactions).
Valid, transaction was already in the mempool.
std::vector< txiter > GatherClusters(const std::vector< Txid > &txids) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Collect the entire cluster of connected transactions for each transaction in txids.
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
static constexpr int64_t TRUC_MAX_VSIZE
Maximum sigop-adjusted virtual size of all v3 transactions.
unsigned long size() const
std::unique_ptr< ChangeSet > GetChangeSet() EXCLUSIVE_LOCKS_REQUIRED(cs)
std::vector< CTxMemPoolEntry::CTxMemPoolEntryRef > GetParents(const CTxMemPoolEntry &entry) const
bool GetSpendsCoinbase() const
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
Compute the virtual transaction size (weight reinterpreted as bytes).
CTxMemPoolEntry FromTx(const CMutableTransaction &tx) const
util::Result< void > ApplyArgsManOptions(const ArgsManager &args, BlockManager::Options &opts)
void BulkTransaction(CMutableTransaction &tx, int32_t target_weight)
std::tuple< size_t, size_t, CAmount > CalculateAncestorData(const CTxMemPoolEntry &entry) const EXCLUSIVE_LOCKS_REQUIRED(cs)
CTxMemPoolEntry stores data about the corresponding transaction, as well as data about all in-mempool...
NodeContext struct containing references to chain state and connection state.
static decltype(CTransaction::version) constexpr TRUC_VERSION
unsigned int GetHeight() const
Validation result for package mempool acceptance.
An input of a transaction.
const CAmount & GetFee() const
static constexpr unsigned int TRUC_ANCESTOR_LIMIT
Maximum number of transactions including a TRUC tx and all its mempool ancestors. ...
CTransactionRef GetSharedTx() const
CFeeRate min_relay_feerate
A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) ...
std::optional< std::string > CheckPackageMempoolAcceptResult(const Package &txns, const PackageMempoolAcceptResult &result, bool expect_valid, const CTxMemPool *mempool)
Check expected properties for every PackageMempoolAcceptResult, regardless of value.
std::chrono::seconds GetTime() const
An outpoint - a combination of a transaction hash and an index n into its vout.
CFeeRate GetMinFee(size_t sizelimit) const
fails some policy, but might be acceptable if submitted in a (different) package
uint64_t GetSequence() const
bool exists(const Txid &txid) const
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::vector< uint32_t > GetDust(const CTransaction &tx, CFeeRate dust_relay_rate)
Get the vout index numbers of all dust outputs.
const CTxMemPoolEntry * GetEntry(const Txid &txid) const LIFETIMEBOUND EXCLUSIVE_LOCKS_REQUIRED(cs)
void CheckMempoolTRUCInvariants(const CTxMemPool &tx_pool)
For every transaction in tx_pool, check TRUC invariants:
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
const CChainParams & Params()
Return the currently selected parameters.
std::tuple< size_t, size_t, CAmount > CalculateDescendantData(const CTxMemPoolEntry &entry) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Serialized script, used inside transaction inputs and outputs.
static transaction_identifier FromUint256(const uint256 &id)
std::vector< CTxMemPoolEntry::CTxMemPoolEntryRef > GetChildren(const CTxMemPoolEntry &entry) const
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac...
int64_t GetSigOpCost() const
A mutable version of CTransaction.
void TrimToSize(size_t sizelimit, std::vector< COutPoint > *pvNoSpendsRemaining=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Remove transactions from the mempool until its dynamic size is <= sizelimit.
Options struct containing options for constructing a CTxMemPool.
void CheckMempoolEphemeralInvariants(const CTxMemPool &tx_pool)
Check that we never get into a state where an ephemeral dust transaction would be mined without the s...
static constexpr unsigned int TRUC_DESCENDANT_LIMIT
Maximum number of transactions including an unconfirmed tx and its descendants.
const LockPoints & GetLockPoints() const
CAmount GetFee(int32_t virtual_bytes) const
Return the fee in satoshis for the given vsize in vbytes.
void TryAddToMempool(CTxMemPool &tx_pool, const CTxMemPoolEntry &entry)
One-line wrapper for creating a mempool changeset with a single transaction and applying it if the po...
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it...
#define Assert(val)
Identity function.
CFeeRate incremental_relay_feerate
CFeeRate dust_relay_feerate
CTxMemPool::Options MemPoolOptionsForTest(const NodeContext &node)
static constexpr CAmount COIN
The amount of satoshis in one BTC.