2021-12-30 19:36:57 +02:00
// Copyright (c) 2017-2021 The Bitcoin Core developers
2017-11-18 00:48:34 -08:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include <consensus/validation.h>
2021-05-03 09:51:13 -07:00
# include <key_io.h>
2021-04-05 11:13:27 -07:00
# include <policy/packages.h>
# include <policy/policy.h>
2024-06-11 13:06:21 +01:00
# include <policy/truc_policy.h>
2017-11-18 00:48:34 -08:00
# include <primitives/transaction.h>
2023-12-15 12:17:23 +00:00
# include <random.h>
2017-11-18 00:48:34 -08:00
# include <script/script.h>
2019-11-05 15:18:59 -05:00
# include <test/util/setup_common.h>
2023-12-15 12:17:23 +00:00
# include <test/util/txmempool.h>
2020-04-16 13:11:54 -04:00
# include <validation.h>
2017-11-18 00:48:34 -08:00
# include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE ( txvalidation_tests )
/**
* Ensure that the mempool won ' t accept coinbase transactions .
*/
BOOST_FIXTURE_TEST_CASE ( tx_mempool_reject_coinbase , TestChain100Setup )
{
CScript scriptPubKey = CScript ( ) < < ToByteVector ( coinbaseKey . GetPubKey ( ) ) < < OP_CHECKSIG ;
CMutableTransaction coinbaseTx ;
2024-01-26 15:27:13 -05:00
coinbaseTx . version = 1 ;
2017-11-18 00:48:34 -08:00
coinbaseTx . vin . resize ( 1 ) ;
coinbaseTx . vout . resize ( 1 ) ;
coinbaseTx . vin [ 0 ] . scriptSig = CScript ( ) < < OP_11 < < OP_EQUAL ;
coinbaseTx . vout [ 0 ] . nValue = 1 * CENT ;
coinbaseTx . vout [ 0 ] . scriptPubKey = scriptPubKey ;
2018-06-26 17:19:31 +02:00
BOOST_CHECK ( CTransaction ( coinbaseTx ) . IsCoinBase ( ) ) ;
2017-11-18 00:48:34 -08:00
LOCK ( cs_main ) ;
2019-11-08 11:10:13 -05:00
unsigned int initialPoolSize = m_node . mempool - > size ( ) ;
2021-09-27 17:47:21 +01:00
const MempoolAcceptResult result = m_node . chainman - > ProcessTransaction ( MakeTransactionRef ( coinbaseTx ) ) ;
2017-11-18 00:48:34 -08:00
2021-01-19 05:29:40 -08:00
BOOST_CHECK ( result . m_result_type = = MempoolAcceptResult : : ResultType : : INVALID ) ;
2017-11-18 00:48:34 -08:00
// Check that the transaction hasn't been added to mempool.
2019-11-08 11:10:13 -05:00
BOOST_CHECK_EQUAL ( m_node . mempool - > size ( ) , initialPoolSize ) ;
2017-11-18 00:48:34 -08:00
2017-11-21 19:14:35 +01:00
// Check that the validation state reflects the unsuccessful attempt.
2021-01-19 05:29:40 -08:00
BOOST_CHECK ( result . m_state . IsInvalid ( ) ) ;
BOOST_CHECK_EQUAL ( result . m_state . GetRejectReason ( ) , " coinbase " ) ;
BOOST_CHECK ( result . m_state . GetResult ( ) = = TxValidationResult : : TX_CONSENSUS ) ;
2017-11-18 00:48:34 -08:00
}
2023-12-15 12:17:23 +00:00
// Generate a number of random, nonexistent outpoints.
static inline std : : vector < COutPoint > random_outpoints ( size_t num_outpoints ) {
std : : vector < COutPoint > outpoints ;
for ( size_t i { 0 } ; i < num_outpoints ; + + i ) {
outpoints . emplace_back ( Txid : : FromUint256 ( GetRandHash ( ) ) , 0 ) ;
}
return outpoints ;
}
static inline std : : vector < CPubKey > random_keys ( size_t num_keys ) {
std : : vector < CPubKey > keys ;
keys . reserve ( num_keys ) ;
for ( size_t i { 0 } ; i < num_keys ; + + i ) {
CKey key ;
key . MakeNewKey ( true ) ;
keys . emplace_back ( key . GetPubKey ( ) ) ;
}
return keys ;
}
2024-01-26 15:27:13 -05:00
// Creates a placeholder tx (not valid) with 25 outputs. Specify the version and the inputs.
2023-12-15 12:17:23 +00:00
static inline CTransactionRef make_tx ( const std : : vector < COutPoint > & inputs , int32_t version )
{
CMutableTransaction mtx = CMutableTransaction { } ;
2024-01-26 15:27:13 -05:00
mtx . version = version ;
2023-12-15 12:17:23 +00:00
mtx . vin . resize ( inputs . size ( ) ) ;
mtx . vout . resize ( 25 ) ;
for ( size_t i { 0 } ; i < inputs . size ( ) ; + + i ) {
mtx . vin [ i ] . prevout = inputs [ i ] ;
}
for ( auto i { 0 } ; i < 25 ; + + i ) {
mtx . vout [ i ] . scriptPubKey = CScript ( ) < < OP_TRUE ;
mtx . vout [ i ] . nValue = 10000 ;
}
return MakeTransactionRef ( mtx ) ;
}
BOOST_FIXTURE_TEST_CASE ( version3_tests , RegTestingSetup )
{
2024-06-11 13:37:05 +01:00
// Test TRUC policy helper functions
2023-12-15 12:17:23 +00:00
CTxMemPool & pool = * Assert ( m_node . mempool ) ;
LOCK2 ( cs_main , pool . cs ) ;
TestMemPoolEntryHelper entry ;
std : : set < Txid > empty_conflicts_set ;
CTxMemPool : : setEntries empty_ancestors ;
auto mempool_tx_v3 = make_tx ( random_outpoints ( 1 ) , /*version=*/ 3 ) ;
pool . addUnchecked ( entry . FromTx ( mempool_tx_v3 ) ) ;
auto mempool_tx_v2 = make_tx ( random_outpoints ( 1 ) , /*version=*/ 2 ) ;
pool . addUnchecked ( entry . FromTx ( mempool_tx_v2 ) ) ;
// Default values.
CTxMemPool : : Limits m_limits { } ;
2024-06-11 13:37:05 +01:00
// Cannot spend from an unconfirmed TRUC transaction unless this tx is also TRUC.
2023-12-15 12:17:23 +00:00
{
// mempool_tx_v3
// ^
// tx_v2_from_v3
auto tx_v2_from_v3 = make_tx ( { COutPoint { mempool_tx_v3 - > GetHash ( ) , 0 } } , /*version=*/ 2 ) ;
auto ancestors_v2_from_v3 { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v2_from_v3 ) , m_limits ) } ;
const auto expected_error_str { strprintf ( " non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s) " ,
tx_v2_from_v3 - > GetHash ( ) . ToString ( ) , tx_v2_from_v3 - > GetWitnessHash ( ) . ToString ( ) ,
mempool_tx_v3 - > GetHash ( ) . ToString ( ) , mempool_tx_v3 - > GetWitnessHash ( ) . ToString ( ) ) } ;
2024-01-23 10:30:39 +00:00
auto result_v2_from_v3 { SingleV3Checks ( tx_v2_from_v3 , * ancestors_v2_from_v3 , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v2_from_v3 ) ) } ;
BOOST_CHECK_EQUAL ( result_v2_from_v3 - > first , expected_error_str ) ;
BOOST_CHECK_EQUAL ( result_v2_from_v3 - > second , nullptr ) ;
2023-12-15 12:17:23 +00:00
Package package_v3_v2 { mempool_tx_v3 , tx_v2_from_v3 } ;
BOOST_CHECK_EQUAL ( * PackageV3Checks ( tx_v2_from_v3 , GetVirtualTransactionSize ( * tx_v2_from_v3 ) , package_v3_v2 , empty_ancestors ) , expected_error_str ) ;
2024-02-12 14:08:57 +00:00
CTxMemPool : : setEntries entries_mempool_v3 { pool . GetIter ( mempool_tx_v3 - > GetHash ( ) . ToUint256 ( ) ) . value ( ) } ;
BOOST_CHECK_EQUAL ( * PackageV3Checks ( tx_v2_from_v3 , GetVirtualTransactionSize ( * tx_v2_from_v3 ) , { tx_v2_from_v3 } , entries_mempool_v3 ) , expected_error_str ) ;
2023-12-15 12:17:23 +00:00
// mempool_tx_v3 mempool_tx_v2
// ^ ^
// tx_v2_from_v2_and_v3
auto tx_v2_from_v2_and_v3 = make_tx ( { COutPoint { mempool_tx_v3 - > GetHash ( ) , 0 } , COutPoint { mempool_tx_v2 - > GetHash ( ) , 0 } } , /*version=*/ 2 ) ;
auto ancestors_v2_from_both { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v2_from_v2_and_v3 ) , m_limits ) } ;
const auto expected_error_str_2 { strprintf ( " non-v3 tx %s (wtxid=%s) cannot spend from v3 tx %s (wtxid=%s) " ,
tx_v2_from_v2_and_v3 - > GetHash ( ) . ToString ( ) , tx_v2_from_v2_and_v3 - > GetWitnessHash ( ) . ToString ( ) ,
mempool_tx_v3 - > GetHash ( ) . ToString ( ) , mempool_tx_v3 - > GetWitnessHash ( ) . ToString ( ) ) } ;
2024-01-23 10:30:39 +00:00
auto result_v2_from_both { SingleV3Checks ( tx_v2_from_v2_and_v3 , * ancestors_v2_from_both , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v2_from_v2_and_v3 ) ) } ;
BOOST_CHECK_EQUAL ( result_v2_from_both - > first , expected_error_str_2 ) ;
BOOST_CHECK_EQUAL ( result_v2_from_both - > second , nullptr ) ;
2023-12-15 12:17:23 +00:00
Package package_v3_v2_v2 { mempool_tx_v3 , mempool_tx_v2 , tx_v2_from_v2_and_v3 } ;
BOOST_CHECK_EQUAL ( * PackageV3Checks ( tx_v2_from_v2_and_v3 , GetVirtualTransactionSize ( * tx_v2_from_v2_and_v3 ) , package_v3_v2_v2 , empty_ancestors ) , expected_error_str_2 ) ;
}
2024-06-11 13:37:05 +01:00
// TRUC cannot spend from an unconfirmed non-TRUC transaction.
2023-12-15 12:17:23 +00:00
{
// mempool_tx_v2
// ^
// tx_v3_from_v2
auto tx_v3_from_v2 = make_tx ( { COutPoint { mempool_tx_v2 - > GetHash ( ) , 0 } } , /*version=*/ 3 ) ;
auto ancestors_v3_from_v2 { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v3_from_v2 ) , m_limits ) } ;
const auto expected_error_str { strprintf ( " v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s) " ,
tx_v3_from_v2 - > GetHash ( ) . ToString ( ) , tx_v3_from_v2 - > GetWitnessHash ( ) . ToString ( ) ,
mempool_tx_v2 - > GetHash ( ) . ToString ( ) , mempool_tx_v2 - > GetWitnessHash ( ) . ToString ( ) ) } ;
2024-01-23 10:30:39 +00:00
auto result_v3_from_v2 { SingleV3Checks ( tx_v3_from_v2 , * ancestors_v3_from_v2 , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v3_from_v2 ) ) } ;
BOOST_CHECK_EQUAL ( result_v3_from_v2 - > first , expected_error_str ) ;
BOOST_CHECK_EQUAL ( result_v3_from_v2 - > second , nullptr ) ;
2023-12-15 12:17:23 +00:00
Package package_v2_v3 { mempool_tx_v2 , tx_v3_from_v2 } ;
BOOST_CHECK_EQUAL ( * PackageV3Checks ( tx_v3_from_v2 , GetVirtualTransactionSize ( * tx_v3_from_v2 ) , package_v2_v3 , empty_ancestors ) , expected_error_str ) ;
2024-02-12 14:08:57 +00:00
CTxMemPool : : setEntries entries_mempool_v2 { pool . GetIter ( mempool_tx_v2 - > GetHash ( ) . ToUint256 ( ) ) . value ( ) } ;
BOOST_CHECK_EQUAL ( * PackageV3Checks ( tx_v3_from_v2 , GetVirtualTransactionSize ( * tx_v3_from_v2 ) , { tx_v3_from_v2 } , entries_mempool_v2 ) , expected_error_str ) ;
2023-12-15 12:17:23 +00:00
// mempool_tx_v3 mempool_tx_v2
// ^ ^
// tx_v3_from_v2_and_v3
auto tx_v3_from_v2_and_v3 = make_tx ( { COutPoint { mempool_tx_v3 - > GetHash ( ) , 0 } , COutPoint { mempool_tx_v2 - > GetHash ( ) , 0 } } , /*version=*/ 3 ) ;
auto ancestors_v3_from_both { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v3_from_v2_and_v3 ) , m_limits ) } ;
const auto expected_error_str_2 { strprintf ( " v3 tx %s (wtxid=%s) cannot spend from non-v3 tx %s (wtxid=%s) " ,
tx_v3_from_v2_and_v3 - > GetHash ( ) . ToString ( ) , tx_v3_from_v2_and_v3 - > GetWitnessHash ( ) . ToString ( ) ,
mempool_tx_v2 - > GetHash ( ) . ToString ( ) , mempool_tx_v2 - > GetWitnessHash ( ) . ToString ( ) ) } ;
2024-01-23 10:30:39 +00:00
auto result_v3_from_both { SingleV3Checks ( tx_v3_from_v2_and_v3 , * ancestors_v3_from_both , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v3_from_v2_and_v3 ) ) } ;
BOOST_CHECK_EQUAL ( result_v3_from_both - > first , expected_error_str_2 ) ;
BOOST_CHECK_EQUAL ( result_v3_from_both - > second , nullptr ) ;
2023-12-15 12:17:23 +00:00
// tx_v3_from_v2_and_v3 also violates V3_ANCESTOR_LIMIT.
const auto expected_error_str_3 { strprintf ( " tx %s (wtxid=%s) would have too many ancestors " ,
tx_v3_from_v2_and_v3 - > GetHash ( ) . ToString ( ) , tx_v3_from_v2_and_v3 - > GetWitnessHash ( ) . ToString ( ) ) } ;
Package package_v3_v2_v3 { mempool_tx_v3 , mempool_tx_v2 , tx_v3_from_v2_and_v3 } ;
BOOST_CHECK_EQUAL ( * PackageV3Checks ( tx_v3_from_v2_and_v3 , GetVirtualTransactionSize ( * tx_v3_from_v2_and_v3 ) , package_v3_v2_v3 , empty_ancestors ) , expected_error_str_3 ) ;
}
// V3 from V3 is ok, and non-V3 from non-V3 is ok.
{
// mempool_tx_v3
// ^
// tx_v3_from_v3
auto tx_v3_from_v3 = make_tx ( { COutPoint { mempool_tx_v3 - > GetHash ( ) , 0 } } , /*version=*/ 3 ) ;
auto ancestors_v3 { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v3_from_v3 ) , m_limits ) } ;
BOOST_CHECK ( SingleV3Checks ( tx_v3_from_v3 , * ancestors_v3 , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v3_from_v3 ) )
= = std : : nullopt ) ;
Package package_v3_v3 { mempool_tx_v3 , tx_v3_from_v3 } ;
BOOST_CHECK ( PackageV3Checks ( tx_v3_from_v3 , GetVirtualTransactionSize ( * tx_v3_from_v3 ) , package_v3_v3 , empty_ancestors ) = = std : : nullopt ) ;
// mempool_tx_v2
// ^
// tx_v2_from_v2
auto tx_v2_from_v2 = make_tx ( { COutPoint { mempool_tx_v2 - > GetHash ( ) , 0 } } , /*version=*/ 2 ) ;
auto ancestors_v2 { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v2_from_v2 ) , m_limits ) } ;
BOOST_CHECK ( SingleV3Checks ( tx_v2_from_v2 , * ancestors_v2 , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v2_from_v2 ) )
= = std : : nullopt ) ;
Package package_v2_v2 { mempool_tx_v2 , tx_v2_from_v2 } ;
BOOST_CHECK ( PackageV3Checks ( tx_v2_from_v2 , GetVirtualTransactionSize ( * tx_v2_from_v2 ) , package_v2_v2 , empty_ancestors ) = = std : : nullopt ) ;
}
2024-06-11 13:37:05 +01:00
// Tx spending TRUC cannot have too many mempool ancestors
2023-12-15 12:17:23 +00:00
// Configuration where the tx has multiple direct parents.
{
Package package_multi_parents ;
std : : vector < COutPoint > mempool_outpoints ;
mempool_outpoints . emplace_back ( mempool_tx_v3 - > GetHash ( ) , 0 ) ;
package_multi_parents . emplace_back ( mempool_tx_v3 ) ;
for ( size_t i { 0 } ; i < 2 ; + + i ) {
auto mempool_tx = make_tx ( random_outpoints ( i + 1 ) , /*version=*/ 3 ) ;
pool . addUnchecked ( entry . FromTx ( mempool_tx ) ) ;
mempool_outpoints . emplace_back ( mempool_tx - > GetHash ( ) , 0 ) ;
package_multi_parents . emplace_back ( mempool_tx ) ;
}
auto tx_v3_multi_parent = make_tx ( mempool_outpoints , /*version=*/ 3 ) ;
package_multi_parents . emplace_back ( tx_v3_multi_parent ) ;
auto ancestors { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v3_multi_parent ) , m_limits ) } ;
BOOST_CHECK_EQUAL ( ancestors - > size ( ) , 3 ) ;
const auto expected_error_str { strprintf ( " tx %s (wtxid=%s) would have too many ancestors " ,
tx_v3_multi_parent - > GetHash ( ) . ToString ( ) , tx_v3_multi_parent - > GetWitnessHash ( ) . ToString ( ) ) } ;
2024-01-23 10:30:39 +00:00
auto result { SingleV3Checks ( tx_v3_multi_parent , * ancestors , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v3_multi_parent ) ) } ;
BOOST_CHECK_EQUAL ( result - > first , expected_error_str ) ;
BOOST_CHECK_EQUAL ( result - > second , nullptr ) ;
2023-12-15 12:17:23 +00:00
BOOST_CHECK_EQUAL ( * PackageV3Checks ( tx_v3_multi_parent , GetVirtualTransactionSize ( * tx_v3_multi_parent ) , package_multi_parents , empty_ancestors ) ,
expected_error_str ) ;
}
// Configuration where the tx is in a multi-generation chain.
{
Package package_multi_gen ;
CTransactionRef middle_tx ;
auto last_outpoint { random_outpoints ( 1 ) [ 0 ] } ;
for ( size_t i { 0 } ; i < 2 ; + + i ) {
auto mempool_tx = make_tx ( { last_outpoint } , /*version=*/ 3 ) ;
pool . addUnchecked ( entry . FromTx ( mempool_tx ) ) ;
last_outpoint = COutPoint { mempool_tx - > GetHash ( ) , 0 } ;
package_multi_gen . emplace_back ( mempool_tx ) ;
if ( i = = 1 ) middle_tx = mempool_tx ;
}
auto tx_v3_multi_gen = make_tx ( { last_outpoint } , /*version=*/ 3 ) ;
package_multi_gen . emplace_back ( tx_v3_multi_gen ) ;
auto ancestors { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v3_multi_gen ) , m_limits ) } ;
const auto expected_error_str { strprintf ( " tx %s (wtxid=%s) would have too many ancestors " ,
tx_v3_multi_gen - > GetHash ( ) . ToString ( ) , tx_v3_multi_gen - > GetWitnessHash ( ) . ToString ( ) ) } ;
2024-01-23 10:30:39 +00:00
auto result { SingleV3Checks ( tx_v3_multi_gen , * ancestors , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v3_multi_gen ) ) } ;
BOOST_CHECK_EQUAL ( result - > first , expected_error_str ) ;
BOOST_CHECK_EQUAL ( result - > second , nullptr ) ;
2023-12-15 12:17:23 +00:00
// Middle tx is what triggers a failure for the grandchild:
BOOST_CHECK_EQUAL ( * PackageV3Checks ( middle_tx , GetVirtualTransactionSize ( * middle_tx ) , package_multi_gen , empty_ancestors ) , expected_error_str ) ;
BOOST_CHECK ( PackageV3Checks ( tx_v3_multi_gen , GetVirtualTransactionSize ( * tx_v3_multi_gen ) , package_multi_gen , empty_ancestors ) = = std : : nullopt ) ;
}
2024-06-11 13:37:05 +01:00
// Tx spending TRUC cannot be too large in virtual size.
2023-12-15 12:17:23 +00:00
auto many_inputs { random_outpoints ( 100 ) } ;
many_inputs . emplace_back ( mempool_tx_v3 - > GetHash ( ) , 0 ) ;
{
auto tx_v3_child_big = make_tx ( many_inputs , /*version=*/ 3 ) ;
const auto vsize { GetVirtualTransactionSize ( * tx_v3_child_big ) } ;
auto ancestors { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v3_child_big ) , m_limits ) } ;
const auto expected_error_str { strprintf ( " v3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes " ,
tx_v3_child_big - > GetHash ( ) . ToString ( ) , tx_v3_child_big - > GetWitnessHash ( ) . ToString ( ) , vsize , V3_CHILD_MAX_VSIZE ) } ;
2024-01-23 10:30:39 +00:00
auto result { SingleV3Checks ( tx_v3_child_big , * ancestors , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v3_child_big ) ) } ;
BOOST_CHECK_EQUAL ( result - > first , expected_error_str ) ;
BOOST_CHECK_EQUAL ( result - > second , nullptr ) ;
2023-12-15 12:17:23 +00:00
Package package_child_big { mempool_tx_v3 , tx_v3_child_big } ;
BOOST_CHECK_EQUAL ( * PackageV3Checks ( tx_v3_child_big , GetVirtualTransactionSize ( * tx_v3_child_big ) , package_child_big , empty_ancestors ) ,
expected_error_str ) ;
}
2024-06-11 13:37:05 +01:00
// Tx spending TRUC cannot have too many sigops.
2023-12-15 12:17:23 +00:00
// This child has 10 P2WSH multisig inputs.
auto multisig_outpoints { random_outpoints ( 10 ) } ;
multisig_outpoints . emplace_back ( mempool_tx_v3 - > GetHash ( ) , 0 ) ;
auto keys { random_keys ( 2 ) } ;
CScript script_multisig ;
script_multisig < < OP_1 ;
for ( const auto & key : keys ) {
script_multisig < < ToByteVector ( key ) ;
}
script_multisig < < OP_2 < < OP_CHECKMULTISIG ;
{
CMutableTransaction mtx_many_sigops = CMutableTransaction { } ;
2024-01-26 15:27:13 -05:00
mtx_many_sigops . version = TRUC_VERSION ;
2023-12-15 12:17:23 +00:00
for ( const auto & outpoint : multisig_outpoints ) {
mtx_many_sigops . vin . emplace_back ( outpoint ) ;
mtx_many_sigops . vin . back ( ) . scriptWitness . stack . emplace_back ( script_multisig . begin ( ) , script_multisig . end ( ) ) ;
}
mtx_many_sigops . vout . resize ( 1 ) ;
mtx_many_sigops . vout . back ( ) . scriptPubKey = CScript ( ) < < OP_TRUE ;
mtx_many_sigops . vout . back ( ) . nValue = 10000 ;
auto tx_many_sigops { MakeTransactionRef ( mtx_many_sigops ) } ;
auto ancestors { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_many_sigops ) , m_limits ) } ;
// legacy uses fAccurate = false, and the maximum number of multisig keys is used
const int64_t total_sigops { static_cast < int64_t > ( tx_many_sigops - > vin . size ( ) ) * static_cast < int64_t > ( script_multisig . GetSigOpCount ( /*fAccurate=*/ false ) ) } ;
BOOST_CHECK_EQUAL ( total_sigops , tx_many_sigops - > vin . size ( ) * MAX_PUBKEYS_PER_MULTISIG ) ;
const int64_t bip141_vsize { GetVirtualTransactionSize ( * tx_many_sigops ) } ;
// Weight limit is not reached...
BOOST_CHECK ( SingleV3Checks ( tx_many_sigops , * ancestors , empty_conflicts_set , bip141_vsize ) = = std : : nullopt ) ;
// ...but sigop limit is.
const auto expected_error_str { strprintf ( " v3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes " ,
tx_many_sigops - > GetHash ( ) . ToString ( ) , tx_many_sigops - > GetWitnessHash ( ) . ToString ( ) ,
total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR , V3_CHILD_MAX_VSIZE ) } ;
2024-01-23 10:30:39 +00:00
auto result { SingleV3Checks ( tx_many_sigops , * ancestors , empty_conflicts_set ,
GetVirtualTransactionSize ( * tx_many_sigops , /*nSigOpCost=*/ total_sigops , /*bytes_per_sigop=*/ DEFAULT_BYTES_PER_SIGOP ) ) } ;
BOOST_CHECK_EQUAL ( result - > first , expected_error_str ) ;
BOOST_CHECK_EQUAL ( result - > second , nullptr ) ;
2023-12-15 12:17:23 +00:00
Package package_child_sigops { mempool_tx_v3 , tx_many_sigops } ;
BOOST_CHECK_EQUAL ( * PackageV3Checks ( tx_many_sigops , total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR , package_child_sigops , empty_ancestors ) ,
expected_error_str ) ;
}
2024-06-11 13:37:05 +01:00
// Parent + child with TRUC in the mempool. Child is allowed as long as it is under V3_CHILD_MAX_VSIZE.
2023-12-15 12:17:23 +00:00
auto tx_mempool_v3_child = make_tx ( { COutPoint { mempool_tx_v3 - > GetHash ( ) , 0 } } , /*version=*/ 3 ) ;
{
BOOST_CHECK ( GetTransactionWeight ( * tx_mempool_v3_child ) < = V3_CHILD_MAX_VSIZE * WITNESS_SCALE_FACTOR ) ;
auto ancestors { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_mempool_v3_child ) , m_limits ) } ;
BOOST_CHECK ( SingleV3Checks ( tx_mempool_v3_child , * ancestors , empty_conflicts_set , GetVirtualTransactionSize ( * tx_mempool_v3_child ) ) = = std : : nullopt ) ;
pool . addUnchecked ( entry . FromTx ( tx_mempool_v3_child ) ) ;
Package package_v3_1p1c { mempool_tx_v3 , tx_mempool_v3_child } ;
BOOST_CHECK ( PackageV3Checks ( tx_mempool_v3_child , GetVirtualTransactionSize ( * tx_mempool_v3_child ) , package_v3_1p1c , empty_ancestors ) = = std : : nullopt ) ;
}
2024-06-11 13:37:05 +01:00
// A TRUC transaction cannot have more than 1 descendant. Sibling is returned when exactly 1 exists.
2023-12-15 12:17:23 +00:00
{
auto tx_v3_child2 = make_tx ( { COutPoint { mempool_tx_v3 - > GetHash ( ) , 1 } } , /*version=*/ 3 ) ;
2024-02-14 14:15:48 +00:00
// Configuration where parent already has 1 other child in mempool
auto ancestors_1sibling { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v3_child2 ) , m_limits ) } ;
2023-12-15 12:17:23 +00:00
const auto expected_error_str { strprintf ( " tx %s (wtxid=%s) would exceed descendant count limit " ,
mempool_tx_v3 - > GetHash ( ) . ToString ( ) , mempool_tx_v3 - > GetWitnessHash ( ) . ToString ( ) ) } ;
2024-02-14 14:15:48 +00:00
auto result_with_sibling_eviction { SingleV3Checks ( tx_v3_child2 , * ancestors_1sibling , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v3_child2 ) ) } ;
BOOST_CHECK_EQUAL ( result_with_sibling_eviction - > first , expected_error_str ) ;
// The other mempool child is returned to allow for sibling eviction.
BOOST_CHECK_EQUAL ( result_with_sibling_eviction - > second , tx_mempool_v3_child ) ;
// If directly replacing the child, make sure there is no double-counting.
BOOST_CHECK ( SingleV3Checks ( tx_v3_child2 , * ancestors_1sibling , { tx_mempool_v3_child - > GetHash ( ) } , GetVirtualTransactionSize ( * tx_v3_child2 ) )
2023-12-15 12:17:23 +00:00
= = std : : nullopt ) ;
Package package_v3_1p2c { mempool_tx_v3 , tx_mempool_v3_child , tx_v3_child2 } ;
BOOST_CHECK_EQUAL ( * PackageV3Checks ( tx_v3_child2 , GetVirtualTransactionSize ( * tx_v3_child2 ) , package_v3_1p2c , empty_ancestors ) ,
expected_error_str ) ;
2024-02-21 16:45:31 +00:00
// Configuration where parent already has 2 other children in mempool (no sibling eviction allowed). This may happen as the result of a reorg.
pool . addUnchecked ( entry . FromTx ( tx_v3_child2 ) ) ;
auto tx_v3_child3 = make_tx ( { COutPoint { mempool_tx_v3 - > GetHash ( ) , 24 } } , /*version=*/ 3 ) ;
auto entry_mempool_parent = pool . GetIter ( mempool_tx_v3 - > GetHash ( ) . ToUint256 ( ) ) . value ( ) ;
BOOST_CHECK_EQUAL ( entry_mempool_parent - > GetCountWithDescendants ( ) , 3 ) ;
auto ancestors_2siblings { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_v3_child3 ) , m_limits ) } ;
auto result_2children { SingleV3Checks ( tx_v3_child3 , * ancestors_2siblings , empty_conflicts_set , GetVirtualTransactionSize ( * tx_v3_child3 ) ) } ;
BOOST_CHECK_EQUAL ( result_2children - > first , expected_error_str ) ;
// The other mempool child is not returned because sibling eviction is not allowed.
BOOST_CHECK_EQUAL ( result_2children - > second , nullptr ) ;
}
// Sibling eviction: parent already has 1 other child, which also has its own child (no sibling eviction allowed). This may happen as the result of a reorg.
{
auto tx_mempool_grandparent = make_tx ( random_outpoints ( 1 ) , /*version=*/ 3 ) ;
auto tx_mempool_sibling = make_tx ( { COutPoint { tx_mempool_grandparent - > GetHash ( ) , 0 } } , /*version=*/ 3 ) ;
auto tx_mempool_nibling = make_tx ( { COutPoint { tx_mempool_sibling - > GetHash ( ) , 0 } } , /*version=*/ 3 ) ;
auto tx_to_submit = make_tx ( { COutPoint { tx_mempool_grandparent - > GetHash ( ) , 1 } } , /*version=*/ 3 ) ;
pool . addUnchecked ( entry . FromTx ( tx_mempool_grandparent ) ) ;
pool . addUnchecked ( entry . FromTx ( tx_mempool_sibling ) ) ;
pool . addUnchecked ( entry . FromTx ( tx_mempool_nibling ) ) ;
auto ancestors_3gen { pool . CalculateMemPoolAncestors ( entry . FromTx ( tx_to_submit ) , m_limits ) } ;
const auto expected_error_str { strprintf ( " tx %s (wtxid=%s) would exceed descendant count limit " ,
tx_mempool_grandparent - > GetHash ( ) . ToString ( ) , tx_mempool_grandparent - > GetWitnessHash ( ) . ToString ( ) ) } ;
auto result_3gen { SingleV3Checks ( tx_to_submit , * ancestors_3gen , empty_conflicts_set , GetVirtualTransactionSize ( * tx_to_submit ) ) } ;
BOOST_CHECK_EQUAL ( result_3gen - > first , expected_error_str ) ;
// The other mempool child is not returned because sibling eviction is not allowed.
BOOST_CHECK_EQUAL ( result_3gen - > second , nullptr ) ;
2023-12-15 12:17:23 +00:00
}
// Configuration where tx has multiple generations of descendants is not tested because that is
// equivalent to the tx with multiple generations of ancestors.
}
2017-11-18 00:48:34 -08:00
BOOST_AUTO_TEST_SUITE_END ( )