@ -20,6 +20,7 @@
# include <script/signingprovider.h>
# include <script/standard.h>
# include <streams.h>
# include <test/util/script.h>
# include <test/util/transaction_utils.h>
# include <util/strencodings.h>
# include <util/string.h>
@ -59,6 +60,9 @@ static std::map<std::string, unsigned int> mapFlagNames = {
{ std : : string ( " WITNESS_PUBKEYTYPE " ) , ( unsigned int ) SCRIPT_VERIFY_WITNESS_PUBKEYTYPE } ,
{ std : : string ( " CONST_SCRIPTCODE " ) , ( unsigned int ) SCRIPT_VERIFY_CONST_SCRIPTCODE } ,
{ std : : string ( " TAPROOT " ) , ( unsigned int ) SCRIPT_VERIFY_TAPROOT } ,
{ std : : string ( " DISCOURAGE_UPGRADABLE_PUBKEYTYPE " ) , ( unsigned int ) SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE } ,
{ std : : string ( " DISCOURAGE_OP_SUCCESS " ) , ( unsigned int ) SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS } ,
{ std : : string ( " DISCOURAGE_UPGRADABLE_TAPROOT_VERSION " ) , ( unsigned int ) SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION } ,
} ;
unsigned int ParseScriptFlags ( std : : string strFlags )
@ -139,6 +143,7 @@ unsigned int TrimFlags(unsigned int flags)
// CLEANSTACK requires WITNESS (and transitively CLEANSTACK requires P2SH)
if ( ! ( flags & SCRIPT_VERIFY_WITNESS ) ) flags & = ~ ( unsigned int ) SCRIPT_VERIFY_CLEANSTACK ;
Assert ( IsValidFlagCombination ( flags ) ) ;
return flags ;
}
@ -149,6 +154,7 @@ unsigned int FillFlags(unsigned int flags)
// WITNESS implies P2SH (and transitively CLEANSTACK implies P2SH)
if ( flags & SCRIPT_VERIFY_WITNESS ) flags | = SCRIPT_VERIFY_P2SH ;
Assert ( IsValidFlagCombination ( flags ) ) ;
return flags ;
}
@ -231,16 +237,15 @@ BOOST_AUTO_TEST_CASE(tx_valid)
BOOST_ERROR ( " Bad test flags: " < < strTest ) ;
}
if ( ! CheckTxScripts ( tx , mapprevOutScriptPubKeys , mapprevOutValues , ~ verify_flags , txdata , strTest , /* expect_valid */ true ) ) {
BOOST_ERROR ( " Tx unexpectedly failed: " < < strTest ) ;
}
BOOST_CHECK_MESSAGE ( CheckTxScripts ( tx , mapprevOutScriptPubKeys , mapprevOutValues , ~ verify_flags , txdata , strTest , /* expect_valid */ true ) ,
" Tx unexpectedly failed: " < < strTest ) ;
// Backwards compatibility of script verification flags: Removing any flag(s) should not invalidate a valid transaction
for ( size_t i = 0 ; i < mapFlagNames . size ( ) ; + + i ) {
for ( const auto & [ name , flag ] : mapFlagNames ) {
// Removing individual flags
unsigned int flags = TrimFlags ( ~ ( verify_flags | ( 1U < < i ) ) ) ;
unsigned int flags = TrimFlags ( ~ ( verify_flags | flag ) ) ;
if ( ! CheckTxScripts ( tx , mapprevOutScriptPubKeys , mapprevOutValues , flags , txdata , strTest , /* expect_valid */ true ) ) {
BOOST_ERROR ( " Tx unexpectedly failed with flag " < < ToString( i ) < < " unset: " < < strTest ) ;
BOOST_ERROR ( " Tx unexpectedly failed with flag " < < name < < " unset: " < < strTest ) ;
}
// Removing random combinations of flags
flags = TrimFlags ( ~ ( verify_flags | ( unsigned int ) InsecureRandBits ( mapFlagNames . size ( ) ) ) ) ;
@ -250,7 +255,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
}
// Check that flags are maximal: transaction should fail if any unset flags are set.
for ( auto flags_excluding_one : ExcludeIndividualFlags ( verify_flags ) ) {
for ( auto flags_excluding_one : ExcludeIndividualFlags ( verify_flags ) ) {
if ( ! CheckTxScripts ( tx , mapprevOutScriptPubKeys , mapprevOutValues , ~ flags_excluding_one , txdata , strTest , /* expect_valid */ false ) ) {
BOOST_ERROR ( " Too many flags unset: " < < strTest ) ;
}
@ -317,27 +322,31 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
PrecomputedTransactionData txdata ( tx ) ;
unsigned int verify_flags = ParseScriptFlags ( test [ 2 ] . get_str ( ) ) ;
// Not using FillFlags() in the main test, in order to detect invalid verifyFlags combination
if ( ! CheckTxScripts ( tx , mapprevOutScriptPubKeys , mapprevOutValues , verify_flags , txdata , strTest , /* expect_valid */ false ) ) {
BOOST_ERROR ( " Tx unexpectedly passed : " < < strTest ) ;
// Check that the test gives a valid combination of flags (otherwise VerifyScript will throw). Don't edit the flags.
if ( verify_flags ! = FillFlags ( verify_flags ) ) {
BOOST_ERROR ( " Bad test flags : " < < strTest ) ;
}
// Not using FillFlags() in the main test, in order to detect invalid verifyFlags combination
BOOST_CHECK_MESSAGE ( CheckTxScripts ( tx , mapprevOutScriptPubKeys , mapprevOutValues , verify_flags , txdata , strTest , /* expect_valid */ false ) ,
" Tx unexpectedly passed: " < < strTest ) ;
// Backwards compatibility of script verification flags: Adding any flag(s) should not validate an invalid transaction
for ( size_t i = 0 ; i < mapFlagNames . size ( ) ; i + + ) {
unsigned int flags = FillFlags ( verify_flags | ( 1U < < i ) ) ;
for ( const auto & [ name , flag ] : mapFlagNames ) {
unsigned int flags = FillFlags ( verify_flags | flag ) ;
// Adding individual flags
if ( ! CheckTxScripts ( tx , mapprevOutScriptPubKeys , mapprevOutValues , flags , txdata , strTest , /* expect_valid */ false ) ) {
BOOST_ERROR ( " Tx unexpectedly passed with flag " < < ToString( i ) < < " set: " < < strTest ) ;
BOOST_ERROR ( " Tx unexpectedly passed with flag " < < name < < " set: " < < strTest ) ;
}
// Adding random combinations of flags
flags = FillFlags ( verify_flags | ( unsigned int ) InsecureRandBits ( mapFlagNames . size ( ) ) ) ;
if ( ! CheckTxScripts ( tx , mapprevOutScriptPubKeys , mapprevOutValues , flags , txdata , strTest , /* expect_valid */ false ) ) {
BOOST_ERROR ( " Tx unexpectedly passed with random flags " < < ToString( flags ) < < " : " < < strTest ) ;
BOOST_ERROR ( " Tx unexpectedly passed with random flags " < < name < < " : " < < strTest ) ;
}
}
// Check that flags are minimal: transaction should succeed if any set flags are unset.
for ( auto flags_excluding_one : ExcludeIndividualFlags ( verify_flags ) ) {
for ( auto flags_excluding_one : ExcludeIndividualFlags ( verify_flags ) ) {
if ( ! CheckTxScripts ( tx , mapprevOutScriptPubKeys , mapprevOutValues , flags_excluding_one , txdata , strTest , /* expect_valid */ true ) ) {
BOOST_ERROR ( " Too many flags set: " < < strTest ) ;
}