19#include <boost/test/unit_test.hpp>
22BOOST_AUTO_TEST_SUITE(txvalidation_tests)
33 coinbaseTx.
vin.resize(1);
34 coinbaseTx.
vout.resize(1);
36 coinbaseTx.
vout[0].nValue = 1 *
CENT;
37 coinbaseTx.
vout[0].scriptPubKey = scriptPubKey;
59 std::vector<COutPoint> outpoints;
60 for (
size_t i{0}; i < num_outpoints; ++i) {
66static inline std::vector<CPubKey>
random_keys(
size_t num_keys) {
67 std::vector<CPubKey> keys;
68 keys.reserve(num_keys);
69 for (
size_t i{0}; i < num_keys; ++i) {
82 mtx.
vin.resize(inputs.size());
84 for (
size_t i{0}; i < inputs.size(); ++i) {
85 mtx.
vin[i].prevout = inputs[i];
87 for (
auto i{0}; i < 25; ++i) {
89 mtx.
vout[i].nValue = 10000;
102 mtx.
vin.resize(inputs.size());
103 for (
size_t i{0}; i < inputs.size(); ++i) {
104 mtx.
vin[i].prevout = inputs[i];
128 const auto dust_txid = grandparent_tx_1->GetHash();
156 const auto dust_non_spend_wtxid{dust_non_spend->GetWitnessHash()};
161 child_wtxid =
Wtxid();
167 child_wtxid =
Wtxid();
173 child_wtxid =
Wtxid();
176 const auto dust_txid_2 = grandparent_tx_2->GetHash();
189 child_wtxid =
Wtxid();
199 auto dust_spend_all_outpoints =
make_tx(all_outpoints, 2);
259 child_wtxid =
Wtxid();
281 std::set<Txid> empty_conflicts_set;
282 std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> empty_parents;
296 const auto expected_error_str{
strprintf(
"non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
297 tx_v2_from_v3->GetHash().ToString(), tx_v2_from_v3->GetWitnessHash().ToString(),
298 mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
303 Package package_v3_v2{mempool_tx_v3, tx_v2_from_v3};
310 auto tx_v2_from_v2_and_v3 =
make_tx({
COutPoint{mempool_tx_v3->GetHash(), 0},
COutPoint{mempool_tx_v2->GetHash(), 0}}, 2);
311 auto parents_2_from_both{pool.
GetParents(entry.
FromTx(tx_v2_from_v2_and_v3))};
312 const auto expected_error_str_2{
strprintf(
"non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
313 tx_v2_from_v2_and_v3->GetHash().ToString(), tx_v2_from_v2_and_v3->GetWitnessHash().ToString(),
314 mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
319 Package package_v3_v2_v2{mempool_tx_v3, mempool_tx_v2, tx_v2_from_v2_and_v3};
330 const auto expected_error_str{
strprintf(
"version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
331 tx_v3_from_v2->GetHash().ToString(), tx_v3_from_v2->GetWitnessHash().ToString(),
332 mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
337 Package package_v2_v3{mempool_tx_v2, tx_v3_from_v2};
344 auto tx_v3_from_v2_and_v3 =
make_tx({
COutPoint{mempool_tx_v3->GetHash(), 0},
COutPoint{mempool_tx_v2->GetHash(), 0}}, 3);
345 auto parents_v3_from_both{pool.
GetParents(entry.
FromTx(tx_v3_from_v2_and_v3))};
346 const auto expected_error_str_2{
strprintf(
"version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
347 tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString(),
348 mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
354 const auto expected_error_str_3{
strprintf(
"tx %s (wtxid=%s) would have too many ancestors",
355 tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString())};
356 Package package_v3_v2_v3{mempool_tx_v3, mempool_tx_v2, tx_v3_from_v2_and_v3};
369 Package package_v3_v3{mempool_tx_v3, tx_v3_from_v3};
380 Package package_v2_v2{mempool_tx_v2, tx_v2_from_v2};
388 std::vector<COutPoint> mempool_outpoints;
389 mempool_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0);
390 package_multi_parents.emplace_back(mempool_tx_v3);
391 for (
size_t i{0}; i < 2; ++i) {
394 mempool_outpoints.emplace_back(mempool_tx->GetHash(), 0);
395 package_multi_parents.emplace_back(mempool_tx);
397 auto tx_v3_multi_parent =
make_tx(mempool_outpoints, 3);
398 package_multi_parents.emplace_back(tx_v3_multi_parent);
401 const auto expected_error_str{
strprintf(
"tx %s (wtxid=%s) would have too many ancestors",
402 tx_v3_multi_parent->GetHash().ToString(), tx_v3_multi_parent->GetWitnessHash().ToString())};
416 for (
size_t i{0}; i < 2; ++i) {
417 auto mempool_tx =
make_tx({last_outpoint}, 3);
419 last_outpoint =
COutPoint{mempool_tx->GetHash(), 0};
420 package_multi_gen.emplace_back(mempool_tx);
421 if (i == 1) middle_tx = mempool_tx;
423 auto tx_v3_multi_gen =
make_tx({last_outpoint}, 3);
424 package_multi_gen.emplace_back(tx_v3_multi_gen);
426 const auto expected_error_str{
strprintf(
"tx %s (wtxid=%s) would have too many ancestors",
427 tx_v3_multi_gen->GetHash().ToString(), tx_v3_multi_gen->GetWitnessHash().ToString())};
439 many_inputs.emplace_back(mempool_tx_v3->GetHash(), 0);
441 auto tx_v3_child_big =
make_tx(many_inputs, 3);
444 const auto expected_error_str{
strprintf(
"version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
445 tx_v3_child_big->GetHash().ToString(), tx_v3_child_big->GetWitnessHash().ToString(), vsize,
TRUC_CHILD_MAX_VSIZE)};
450 Package package_child_big{mempool_tx_v3, tx_v3_child_big};
458 multisig_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0);
461 script_multisig <<
OP_1;
462 for (
const auto& key : keys) {
469 for (
const auto& outpoint : multisig_outpoints) {
470 mtx_many_sigops.
vin.emplace_back(outpoint);
471 mtx_many_sigops.
vin.back().scriptWitness.stack.emplace_back(script_multisig.
begin(), script_multisig.
end());
473 mtx_many_sigops.
vout.resize(1);
475 mtx_many_sigops.
vout.back().nValue = 10000;
480 const int64_t total_sigops{
static_cast<int64_t
>(tx_many_sigops->vin.size()) *
static_cast<int64_t
>(script_multisig.
GetSigOpCount(
false))};
486 const auto expected_error_str{
strprintf(
"version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
487 tx_many_sigops->GetHash().ToString(), tx_many_sigops->GetWitnessHash().ToString(),
489 auto result{
SingleTRUCChecks(pool, tx_many_sigops, parents, empty_conflicts_set,
494 Package package_child_sigops{mempool_tx_v3, tx_many_sigops};
500 auto tx_mempool_v3_child =
make_tx({
COutPoint{mempool_tx_v3->GetHash(), 0}}, 3);
507 Package package_v3_1p1c{mempool_tx_v3, tx_mempool_v3_child};
516 const auto expected_error_str{
strprintf(
"tx %s (wtxid=%s) would exceed descendant count limit",
517 mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
527 Package package_v3_1p2c{mempool_tx_v3, tx_mempool_v3_child, tx_v3_child2};
534 auto entry_mempool_parent = pool.
GetIter(mempool_tx_v3->GetHash()).value();
547 auto tx_mempool_sibling =
make_tx({
COutPoint{tx_mempool_grandparent->GetHash(), 0}}, 3);
548 auto tx_mempool_nibling =
make_tx({
COutPoint{tx_mempool_sibling->GetHash(), 0}}, 3);
549 auto tx_to_submit =
make_tx({
COutPoint{tx_mempool_grandparent->GetHash(), 1}}, 3);
556 const auto expected_error_str{
strprintf(
"tx %s (wtxid=%s) would exceed descendant count limit",
557 tx_mempool_grandparent->GetHash().ToString(), tx_mempool_grandparent->GetWitnessHash().ToString())};
TryAddToMempool(pool, CTxMemPoolEntry(tx, fee, 0, 1, 0, false, 4, lp))
#define Assert(val)
Identity function.
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
An encapsulated private key.
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
CPubKey GetPubKey() const
Compute the public key from a private key.
An outpoint - a combination of a transaction hash and an index n into its vout.
Serialized script, used inside transaction inputs and outputs.
unsigned int GetSigOpCount(bool fAccurate) const
Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs as 20 sigops.
The basic transaction that is broadcasted on the network and contained in blocks.
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
std::optional< txiter > GetIter(const Txid &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given hash, if found.
int64_t GetDescendantCount(txiter it) const
std::vector< CTxMemPoolEntry::CTxMemPoolEntryRef > GetParents(const CTxMemPoolEntry &entry) const
std::string GetRejectReason() const
transaction_identifier represents the two canonical transaction identifier types (txid,...
static transaction_identifier FromUint256(const uint256 &id)
static int32_t GetTransactionWeight(const CTransaction &tx)
@ TX_CONSENSUS
invalid by consensus rules
static const int WITNESS_SCALE_FACTOR
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
BOOST_AUTO_TEST_SUITE_END()
bool CheckEphemeralSpends(const Package &package, CFeeRate dust_relay_rate, const CTxMemPool &tx_pool, TxValidationState &out_child_state, Wtxid &out_child_wtxid)
Called for each transaction(package) if any dust is in the package.
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
Compute the virtual transaction size (weight reinterpreted as bytes).
static constexpr unsigned int DUST_RELAY_TX_FEE
Min feerate for defining dust.
static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP
Default for -bytespersigop.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::shared_ptr< const CTransaction > CTransactionRef
uint256 GetRandHash() noexcept
Generate a random uint256.
static const int MAX_PUBKEYS_PER_MULTISIG
std::vector< unsigned char > ToByteVector(const T &in)
static constexpr CAmount CENT
A mutable version of CTransaction.
std::vector< CTxOut > vout
Validation result for a transaction evaluated by MemPoolAccept (single or package).
const ResultType m_result_type
Result type.
const TxValidationState m_state
Contains information about why the transaction failed.
@ INVALID
‍Fully validated, valid.
Identical to TestingSetup, but chain set to regtest.
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
CTxMemPoolEntry FromTx(const CMutableTransaction &tx) const
std::unique_ptr< CTxMemPool > mempool
std::unique_ptr< ChainstateManager > chainman
transaction_identifier< true > Wtxid
Wtxid commits to all transaction fields including the witness.
std::optional< std::pair< std::string, CTransactionRef > > SingleTRUCChecks(const CTxMemPool &pool, const CTransactionRef &ptx, const std::vector< CTxMemPoolEntry::CTxMemPoolEntryRef > &mempool_parents, const std::set< Txid > &direct_conflicts, int64_t vsize)
Must be called for every transaction, even if not TRUC.
std::optional< std::string > PackageTRUCChecks(const CTxMemPool &pool, const CTransactionRef &ptx, int64_t vsize, const Package &package, const std::vector< CTxMemPoolEntry::CTxMemPoolEntryRef > &mempool_parents)
Must be called for every transaction that is submitted within a package, even if not TRUC.
static constexpr int64_t TRUC_CHILD_MAX_VSIZE
Maximum sigop-adjusted virtual size of a tx which spends from an unconfirmed TRUC transaction.
static constexpr decltype(CTransaction::version) TRUC_VERSION
static CTransactionRef make_ephemeral_tx(const std::vector< COutPoint > &inputs, int32_t version)
static CTransactionRef make_tx(const std::vector< COutPoint > &inputs, int32_t version)
static std::vector< COutPoint > random_outpoints(size_t num_outpoints)
static constexpr auto NUM_EPHEMERAL_TX_OUTPUTS
BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
Ensure that the mempool won't accept coinbase transactions.
static std::vector< CPubKey > random_keys(size_t num_keys)
static constexpr auto EPHEMERAL_DUST_INDEX