18 #include <boost/test/unit_test.hpp> 21 BOOST_AUTO_TEST_SUITE(txvalidation_tests)
32 coinbaseTx.vin.resize(1);
33 coinbaseTx.vout.resize(1);
35 coinbaseTx.vout[0].nValue = 1 *
CENT;
36 coinbaseTx.vout[0].scriptPubKey = scriptPubKey;
58 std::vector<COutPoint> outpoints;
59 for (
size_t i{0}; i < num_outpoints; ++i) {
65 static inline std::vector<CPubKey>
random_keys(
size_t num_keys) {
66 std::vector<CPubKey> keys;
67 keys.reserve(num_keys);
68 for (
size_t i{0}; i < num_keys; ++i) {
81 mtx.
vin.resize(inputs.size());
83 for (
size_t i{0}; i < inputs.size(); ++i) {
84 mtx.
vin[i].prevout = inputs[i];
86 for (
auto i{0}; i < 25; ++i) {
88 mtx.
vout[i].nValue = 10000;
101 mtx.
vin.resize(inputs.size());
102 for (
size_t i{0}; i < inputs.size(); ++i) {
103 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;
298 const auto expected_error_str{
strprintf(
"non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
299 tx_v2_from_v3->GetHash().ToString(), tx_v2_from_v3->GetWitnessHash().ToString(),
300 mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
305 Package package_v3_v2{mempool_tx_v3, tx_v2_from_v3};
313 auto tx_v2_from_v2_and_v3 =
make_tx({
COutPoint{mempool_tx_v3->GetHash(), 0},
COutPoint{mempool_tx_v2->GetHash(), 0}}, 2);
315 const auto expected_error_str_2{
strprintf(
"non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
316 tx_v2_from_v2_and_v3->GetHash().ToString(), tx_v2_from_v2_and_v3->GetWitnessHash().ToString(),
317 mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
322 Package package_v3_v2_v2{mempool_tx_v3, mempool_tx_v2, tx_v2_from_v2_and_v3};
333 const auto expected_error_str{
strprintf(
"version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
334 tx_v3_from_v2->GetHash().ToString(), tx_v3_from_v2->GetWitnessHash().ToString(),
335 mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
340 Package package_v2_v3{mempool_tx_v2, tx_v3_from_v2};
348 auto tx_v3_from_v2_and_v3 =
make_tx({
COutPoint{mempool_tx_v3->GetHash(), 0},
COutPoint{mempool_tx_v2->GetHash(), 0}}, 3);
350 const auto expected_error_str_2{
strprintf(
"version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
351 tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString(),
352 mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
358 const auto expected_error_str_3{
strprintf(
"tx %s (wtxid=%s) would have too many ancestors",
359 tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString())};
360 Package package_v3_v2_v3{mempool_tx_v3, mempool_tx_v2, tx_v3_from_v2_and_v3};
373 Package package_v3_v3{mempool_tx_v3, tx_v3_from_v3};
384 Package package_v2_v2{mempool_tx_v2, tx_v2_from_v2};
392 std::vector<COutPoint> mempool_outpoints;
393 mempool_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0);
394 package_multi_parents.emplace_back(mempool_tx_v3);
395 for (
size_t i{0}; i < 2; ++i) {
398 mempool_outpoints.emplace_back(mempool_tx->GetHash(), 0);
399 package_multi_parents.emplace_back(mempool_tx);
401 auto tx_v3_multi_parent =
make_tx(mempool_outpoints, 3);
402 package_multi_parents.emplace_back(tx_v3_multi_parent);
405 const auto expected_error_str{
strprintf(
"tx %s (wtxid=%s) would have too many ancestors",
406 tx_v3_multi_parent->GetHash().ToString(), tx_v3_multi_parent->GetWitnessHash().ToString())};
420 for (
size_t i{0}; i < 2; ++i) {
421 auto mempool_tx =
make_tx({last_outpoint}, 3);
423 last_outpoint =
COutPoint{mempool_tx->GetHash(), 0};
424 package_multi_gen.emplace_back(mempool_tx);
425 if (i == 1) middle_tx = mempool_tx;
427 auto tx_v3_multi_gen =
make_tx({last_outpoint}, 3);
428 package_multi_gen.emplace_back(tx_v3_multi_gen);
430 const auto expected_error_str{
strprintf(
"tx %s (wtxid=%s) would have too many ancestors",
431 tx_v3_multi_gen->GetHash().ToString(), tx_v3_multi_gen->GetWitnessHash().ToString())};
443 many_inputs.emplace_back(mempool_tx_v3->GetHash(), 0);
445 auto tx_v3_child_big =
make_tx(many_inputs, 3);
448 const auto expected_error_str{
strprintf(
"version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
449 tx_v3_child_big->GetHash().ToString(), tx_v3_child_big->GetWitnessHash().ToString(), vsize,
TRUC_CHILD_MAX_VSIZE)};
454 Package package_child_big{mempool_tx_v3, tx_v3_child_big};
462 multisig_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0);
465 script_multisig <<
OP_1;
466 for (
const auto& key : keys) {
473 for (
const auto& outpoint : multisig_outpoints) {
474 mtx_many_sigops.
vin.emplace_back(outpoint);
475 mtx_many_sigops.
vin.back().scriptWitness.stack.emplace_back(script_multisig.
begin(), script_multisig.
end());
477 mtx_many_sigops.
vout.resize(1);
479 mtx_many_sigops.
vout.back().nValue = 10000;
484 const int64_t total_sigops{
static_cast<int64_t
>(tx_many_sigops->vin.size()) * static_cast<int64_t>(script_multisig.
GetSigOpCount(
false))};
490 const auto expected_error_str{
strprintf(
"version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
491 tx_many_sigops->GetHash().ToString(), tx_many_sigops->GetWitnessHash().ToString(),
498 Package package_child_sigops{mempool_tx_v3, tx_many_sigops};
504 auto tx_mempool_v3_child =
make_tx({
COutPoint{mempool_tx_v3->GetHash(), 0}}, 3);
511 Package package_v3_1p1c{mempool_tx_v3, tx_mempool_v3_child};
521 const auto expected_error_str{
strprintf(
"tx %s (wtxid=%s) would exceed descendant count limit",
522 mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
532 Package package_v3_1p2c{mempool_tx_v3, tx_mempool_v3_child, tx_v3_child2};
539 auto entry_mempool_parent = pool.
GetIter(mempool_tx_v3->GetHash().ToUint256()).value();
552 auto tx_mempool_sibling =
make_tx({
COutPoint{tx_mempool_grandparent->GetHash(), 0}}, 3);
553 auto tx_mempool_nibling =
make_tx({
COutPoint{tx_mempool_sibling->GetHash(), 0}}, 3);
554 auto tx_to_submit =
make_tx({
COutPoint{tx_mempool_grandparent->GetHash(), 1}}, 3);
561 const auto expected_error_str{
strprintf(
"tx %s (wtxid=%s) would exceed descendant count limit",
562 tx_mempool_grandparent->GetHash().ToString(), tx_mempool_grandparent->GetWitnessHash().ToString())};
std::shared_ptr< const CTransaction > CTransactionRef
unsigned int GetSigOpCount(bool fAccurate) const
Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs as 20 sigops.
invalid by consensus rules
static constexpr int64_t TRUC_CHILD_MAX_VSIZE
Maximum sigop-adjusted virtual size of a tx which spends from an unconfirmed TRUC transaction...
static const int WITNESS_SCALE_FACTOR
Options struct containing limit options for a CTxMemPool.
CPubKey GetPubKey() const
Compute the public key from a private key.
static CTransactionRef make_ephemeral_tx(const std::vector< COutPoint > &inputs, int32_t version)
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
std::set< txiter, CompareIteratorByHash > setEntries
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
static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP
Default for -bytespersigop.
static constexpr auto EPHEMERAL_DUST_INDEX
static const int MAX_PUBKEYS_PER_MULTISIG
static int32_t GetTransactionWeight(const CTransaction &tx)
std::optional< std::pair< std::string, CTransactionRef > > SingleTRUCChecks(const CTransactionRef &ptx, const CTxMemPool::setEntries &mempool_ancestors, const std::set< Txid > &direct_conflicts, int64_t vsize)
Must be called for every transaction, even if not TRUC.
util::Result< setEntries > CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, const Limits &limits, bool fSearchForParents=true) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Try to calculate all in-mempool ancestors of entry.
std::unique_ptr< CTxMemPool > mempool
static std::vector< CPubKey > random_keys(size_t num_keys)
static decltype(CTransaction::version) constexpr TRUC_VERSION
static constexpr auto NUM_EPHEMERAL_TX_OUTPUTS
static CTransactionRef make_tx(const std::vector< COutPoint > &inputs, int32_t version)
BOOST_AUTO_TEST_SUITE_END()
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
AddToMempool(pool, CTxMemPoolEntry(tx, fee, nTime, nHeight, sequence, spendsCoinbase, sigOpCost, lp))
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
An outpoint - a combination of a transaction hash and an index n into its vout.
std::vector< CTxOut > vout
Validation result for a transaction evaluated by MemPoolAccept (single or package).
bool CheckEphemeralSpends(const Package &package, CFeeRate dust_relay_rate, const CTxMemPool &tx_pool, TxValidationState &out_child_state, Wtxid &out_child_wtxid)
Must be called for each transaction(package) if any dust is in the package.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
Ensure that the mempool won't accept coinbase transactions.
static constexpr unsigned int DUST_RELAY_TX_FEE
Min feerate for defining dust.
std::optional< txiter > GetIter(const uint256 &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given hash, if found.
std::vector< unsigned char > ToByteVector(const T &in)
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
#define BOOST_CHECK_EQUAL(v1, v2)
Serialized script, used inside transaction inputs and outputs.
transaction_identifier< true > Wtxid
Wtxid commits to all transaction fields including the witness.
static transaction_identifier FromUint256(const uint256 &id)
uint256 GetRandHash() noexcept
Generate a random uint256.
std::optional< std::string > PackageTRUCChecks(const CTransactionRef &ptx, int64_t vsize, const Package &package, const CTxMemPool::setEntries &mempool_ancestors)
Must be called for every transaction that is submitted within a package, even if not TRUC...
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
A mutable version of CTransaction.
static std::vector< COutPoint > random_outpoints(size_t num_outpoints)
static constexpr CAmount CENT
An encapsulated private key.
The basic transaction that is broadcasted on the network and contained in blocks. ...
Identical to TestingSetup, but chain set to regtest.
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
std::unique_ptr< ChainstateManager > chainman
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it...
#define Assert(val)
Identity function.
#define BOOST_CHECK(expr)
transaction_identifier represents the two canonical transaction identifier types (txid, wtxid).