19 #include <boost/test/unit_test.hpp> 22 BOOST_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) {
66 static 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(),
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())};
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
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...
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::vector< CTxMemPoolEntry::CTxMemPoolEntryRef > GetParents(const CTxMemPoolEntry &entry) const
TryAddToMempool(pool, CTxMemPoolEntry(tx, fee, 0, 1, 0, false, 4, lp))
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.
std::optional< txiter > GetIter(const Txid &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given hash, if found.
static constexpr auto EPHEMERAL_DUST_INDEX
static const int MAX_PUBKEYS_PER_MULTISIG
static int32_t GetTransactionWeight(const CTransaction &tx)
int64_t GetDescendantCount(txiter it) const
std::unique_ptr< CTxMemPool > mempool
static std::vector< CPubKey > random_keys(size_t num_keys)
static decltype(CTransaction::version) constexpr TRUC_VERSION
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.
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.
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)
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::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.
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac...
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).