2016-08-31 08:38:23 -03:00
#!/usr/bin/env python3
2020-04-16 13:14:08 -04:00
# Copyright (c) 2016-2020 The Bitcoin Core developers
2016-08-31 08:38:23 -03:00
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-01-17 20:34:40 -03:00
""" Test NULLDUMMY softfork.
Connect to a single node .
Generate 2 blocks ( save the coinbases for later ) .
2021-03-05 12:42:25 -03:00
Generate COINBASE_MATURITY ( CB ) more blocks to ensure the coinbases are mature .
[ Policy / Consensus ] Check that NULLDUMMY compliant transactions are accepted in block CB + 3.
2017-01-17 20:34:40 -03:00
[ Policy ] Check that non - NULLDUMMY transactions are rejected before activation .
2021-03-05 12:42:25 -03:00
[ Consensus ] Check that the new NULLDUMMY rules are not enforced on block CB + 4.
[ Policy / Consensus ] Check that the new NULLDUMMY rules are enforced on block CB + 5.
2017-01-17 20:34:40 -03:00
"""
2018-09-23 09:50:47 -03:00
import time
2016-08-31 08:38:23 -03:00
2021-05-17 10:38:02 -04:00
from test_framework . blocktools import (
COINBASE_MATURITY ,
NORMAL_GBT_REQUEST_PARAMS ,
add_witness_commitment ,
create_block ,
create_transaction ,
)
2018-07-06 18:10:35 -04:00
from test_framework . messages import CTransaction
2016-08-31 08:38:23 -03:00
from test_framework . script import CScript
2018-07-06 18:10:35 -04:00
from test_framework . test_framework import BitcoinTestFramework
2019-02-18 12:35:48 -03:00
from test_framework . util import assert_equal , assert_raises_rpc_error
2018-07-06 18:10:35 -04:00
2019-10-10 12:19:42 -03:00
NULLDUMMY_ERROR = " non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero) "
2016-08-31 08:38:23 -03:00
2021-06-04 09:48:07 -04:00
2016-08-31 08:38:23 -03:00
def trueDummy ( tx ) :
scriptSig = CScript ( tx . vin [ 0 ] . scriptSig )
newscript = [ ]
for i in scriptSig :
2021-03-06 08:01:45 -03:00
if len ( newscript ) == 0 :
2019-02-19 19:43:44 -03:00
assert len ( i ) == 0
2016-08-31 08:38:23 -03:00
newscript . append ( b ' \x51 ' )
else :
newscript . append ( i )
tx . vin [ 0 ] . scriptSig = CScript ( newscript )
tx . rehash ( )
2021-06-04 09:48:07 -04:00
class NULLDUMMYTest ( BitcoinTestFramework ) :
2017-06-09 18:21:21 -04:00
def set_test_params ( self ) :
2021-06-04 09:48:07 -04:00
self . num_nodes = 1
2016-09-29 10:34:04 -03:00
self . setup_clean_chain = True
2017-10-12 00:25:18 -03:00
# This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through
# normal segwit activation here (and don't use the default always-on behaviour).
2020-02-25 13:38:56 -03:00
self . extra_args = [ [
2021-03-05 12:42:25 -03:00
f ' -segwitheight= { COINBASE_MATURITY + 5 } ' ,
2020-02-25 13:38:56 -03:00
' -addresstype=legacy ' ,
2021-06-04 09:48:07 -04:00
] ]
2016-08-31 08:38:23 -03:00
2018-09-09 14:32:37 -03:00
def skip_test_if_missing_module ( self ) :
self . skip_if_no_wallet ( )
2016-08-31 08:38:23 -03:00
def run_test ( self ) :
2020-04-06 18:13:46 -04:00
self . nodes [ 0 ] . createwallet ( wallet_name = ' wmulti ' , disable_private_keys = True )
wmulti = self . nodes [ 0 ] . get_wallet_rpc ( ' wmulti ' )
w0 = self . nodes [ 0 ] . get_wallet_rpc ( self . default_wallet_name )
self . address = w0 . getnewaddress ( )
self . pubkey = w0 . getaddressinfo ( self . address ) [ ' pubkey ' ]
self . ms_address = wmulti . addmultisigaddress ( 1 , [ self . pubkey ] ) [ ' address ' ]
self . wit_address = w0 . getnewaddress ( address_type = ' p2sh-segwit ' )
self . wit_ms_address = wmulti . addmultisigaddress ( 1 , [ self . pubkey ] , ' ' , ' p2sh-segwit ' ) [ ' address ' ]
if not self . options . descriptors :
2020-12-24 10:37:17 -03:00
# Legacy wallets need to import these so that they are watched by the wallet. This is unnecessary (and does not need to be tested) for descriptor wallets
2020-04-06 18:13:46 -04:00
wmulti . importaddress ( self . ms_address )
wmulti . importaddress ( self . wit_ms_address )
2016-08-31 08:38:23 -03:00
2021-03-05 12:42:25 -03:00
self . coinbase_blocks = self . nodes [ 0 ] . generate ( 2 ) # block height = 2
2016-08-31 08:38:23 -03:00
coinbase_txid = [ ]
for i in self . coinbase_blocks :
coinbase_txid . append ( self . nodes [ 0 ] . getblock ( i ) [ ' tx ' ] [ 0 ] )
2021-03-05 12:42:25 -03:00
self . nodes [ 0 ] . generate ( COINBASE_MATURITY ) # block height = COINBASE_MATURITY + 2
2016-08-31 08:38:23 -03:00
self . lastblockhash = self . nodes [ 0 ] . getbestblockhash ( )
2021-03-05 12:42:25 -03:00
self . lastblockheight = COINBASE_MATURITY + 2
self . lastblocktime = int ( time . time ( ) ) + self . lastblockheight
2016-08-31 08:38:23 -03:00
2021-03-05 12:42:25 -03:00
self . log . info ( f " Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [ { COINBASE_MATURITY + 3 } ] " )
2018-08-09 13:27:45 -04:00
test1txs = [ create_transaction ( self . nodes [ 0 ] , coinbase_txid [ 0 ] , self . ms_address , amount = 49 ) ]
2018-06-27 04:21:07 -04:00
txid1 = self . nodes [ 0 ] . sendrawtransaction ( test1txs [ 0 ] . serialize_with_witness ( ) . hex ( ) , 0 )
2018-08-09 13:27:45 -04:00
test1txs . append ( create_transaction ( self . nodes [ 0 ] , txid1 , self . ms_address , amount = 48 ) )
2018-06-27 04:21:07 -04:00
txid2 = self . nodes [ 0 ] . sendrawtransaction ( test1txs [ 1 ] . serialize_with_witness ( ) . hex ( ) , 0 )
2018-08-09 13:27:45 -04:00
test1txs . append ( create_transaction ( self . nodes [ 0 ] , coinbase_txid [ 1 ] , self . wit_ms_address , amount = 49 ) )
2018-06-27 04:21:07 -04:00
txid3 = self . nodes [ 0 ] . sendrawtransaction ( test1txs [ 2 ] . serialize_with_witness ( ) . hex ( ) , 0 )
2016-08-31 08:38:23 -03:00
self . block_submit ( self . nodes [ 0 ] , test1txs , False , True )
2017-03-07 20:46:17 -03:00
self . log . info ( " Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation " )
2018-08-09 13:27:45 -04:00
test2tx = create_transaction ( self . nodes [ 0 ] , txid2 , self . ms_address , amount = 47 )
2016-08-31 08:38:23 -03:00
trueDummy ( test2tx )
2018-06-27 04:21:07 -04:00
assert_raises_rpc_error ( - 26 , NULLDUMMY_ERROR , self . nodes [ 0 ] . sendrawtransaction , test2tx . serialize_with_witness ( ) . hex ( ) , 0 )
2016-08-31 08:38:23 -03:00
2021-03-05 12:42:25 -03:00
self . log . info ( f " Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [ { COINBASE_MATURITY + 4 } ] " )
2016-08-31 08:38:23 -03:00
self . block_submit ( self . nodes [ 0 ] , [ test2tx ] , False , True )
2017-03-17 19:36:39 -03:00
self . log . info ( " Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation " )
2018-08-09 13:27:45 -04:00
test4tx = create_transaction ( self . nodes [ 0 ] , test2tx . hash , self . address , amount = 46 )
2018-09-23 09:50:47 -03:00
test6txs = [ CTransaction ( test4tx ) ]
2016-08-31 08:38:23 -03:00
trueDummy ( test4tx )
2018-06-27 04:21:07 -04:00
assert_raises_rpc_error ( - 26 , NULLDUMMY_ERROR , self . nodes [ 0 ] . sendrawtransaction , test4tx . serialize_with_witness ( ) . hex ( ) , 0 )
2016-08-31 08:38:23 -03:00
self . block_submit ( self . nodes [ 0 ] , [ test4tx ] )
2017-03-17 19:36:39 -03:00
self . log . info ( " Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation " )
2018-08-09 13:27:45 -04:00
test5tx = create_transaction ( self . nodes [ 0 ] , txid3 , self . wit_address , amount = 48 )
2016-08-31 08:38:23 -03:00
test6txs . append ( CTransaction ( test5tx ) )
test5tx . wit . vtxinwit [ 0 ] . scriptWitness . stack [ 0 ] = b ' \x01 '
2018-06-27 04:21:07 -04:00
assert_raises_rpc_error ( - 26 , NULLDUMMY_ERROR , self . nodes [ 0 ] . sendrawtransaction , test5tx . serialize_with_witness ( ) . hex ( ) , 0 )
2016-08-31 08:38:23 -03:00
self . block_submit ( self . nodes [ 0 ] , [ test5tx ] , True )
2021-03-05 12:42:25 -03:00
self . log . info ( f " Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [ { COINBASE_MATURITY + 5 } ] " )
2016-08-31 08:38:23 -03:00
for i in test6txs :
2018-06-27 04:21:07 -04:00
self . nodes [ 0 ] . sendrawtransaction ( i . serialize_with_witness ( ) . hex ( ) , 0 )
2016-08-31 08:38:23 -03:00
self . block_submit ( self . nodes [ 0 ] , test6txs , True , True )
2018-09-23 09:50:47 -03:00
def block_submit ( self , node , txs , witness = False , accept = False ) :
2020-06-26 20:24:13 -04:00
tmpl = node . getblocktemplate ( NORMAL_GBT_REQUEST_PARAMS )
assert_equal ( tmpl [ ' previousblockhash ' ] , self . lastblockhash )
assert_equal ( tmpl [ ' height ' ] , self . lastblockheight + 1 )
block = create_block ( tmpl = tmpl , ntime = self . lastblocktime + 1 )
2016-08-31 08:38:23 -03:00
for tx in txs :
tx . rehash ( )
block . vtx . append ( tx )
block . hashMerkleRoot = block . calc_merkle_root ( )
witness and add_witness_commitment ( block )
block . rehash ( )
block . solve ( )
2020-04-22 16:57:19 -04:00
assert_equal ( None if accept else ' block-validation-failed ' , node . submitblock ( block . serialize ( ) . hex ( ) ) )
2016-08-31 08:38:23 -03:00
if ( accept ) :
assert_equal ( node . getbestblockhash ( ) , block . hash )
self . lastblockhash = block . hash
self . lastblocktime + = 1
self . lastblockheight + = 1
else :
assert_equal ( node . getbestblockhash ( ) , self . lastblockhash )
2021-03-05 12:42:25 -03:00
2016-08-31 08:38:23 -03:00
if __name__ == ' __main__ ' :
2016-09-29 10:34:04 -03:00
NULLDUMMYTest ( ) . main ( )