feature_segwit.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2016-present The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Test the SegWit changeover logic.""" 6 7 from decimal import Decimal 8 9 from test_framework.address import ( 10 script_to_p2sh_p2wsh, 11 script_to_p2wsh, 12 ) 13 from test_framework.blocktools import ( 14 send_to_witness, 15 witness_script, 16 ) 17 from test_framework.descriptors import descsum_create 18 from test_framework.messages import ( 19 COIN, 20 COutPoint, 21 CTransaction, 22 CTxIn, 23 CTxOut, 24 tx_from_hex, 25 ) 26 from test_framework.script import ( 27 CScript, 28 OP_DROP, 29 OP_TRUE, 30 ) 31 from test_framework.script_util import ( 32 key_to_p2pk_script, 33 key_to_p2wpkh_script, 34 keys_to_multisig_script, 35 script_to_p2sh_script, 36 script_to_p2wsh_script, 37 ) 38 from test_framework.test_framework import BitcoinTestFramework 39 from test_framework.util import ( 40 assert_equal, 41 assert_greater_than_or_equal, 42 assert_is_hex_string, 43 assert_raises_rpc_error, 44 ) 45 from test_framework.wallet_util import ( 46 get_generate_key, 47 ) 48 49 NODE_0 = 0 50 NODE_2 = 2 51 P2WPKH = 0 52 P2WSH = 1 53 54 55 def getutxo(txid): 56 utxo = {} 57 utxo["vout"] = 0 58 utxo["txid"] = txid 59 return utxo 60 61 62 def find_spendable_utxo(node, min_value): 63 for utxo in node.listunspent(query_options={'minimumAmount': min_value}): 64 if utxo['spendable']: 65 return utxo 66 67 raise AssertionError(f"Unspent output equal or higher than {min_value} not found") 68 69 70 txs_mined = {} # txindex from txid to blockhash 71 72 73 class SegWitTest(BitcoinTestFramework): 74 def set_test_params(self): 75 self.setup_clean_chain = True 76 self.num_nodes = 3 77 # This test tests SegWit both pre and post-activation, so use the normal BIP9 activation. 78 self.extra_args = [ 79 [ 80 "-acceptnonstdtxn=1", 81 "-testactivationheight=segwit@165", 82 "-addresstype=legacy", 83 ], 84 [ 85 "-acceptnonstdtxn=1", 86 "-testactivationheight=segwit@165", 87 "-addresstype=legacy", 88 ], 89 [ 90 "-acceptnonstdtxn=1", 91 "-testactivationheight=segwit@165", 92 "-addresstype=legacy", 93 ], 94 ] 95 self.rpc_timeout = 120 96 97 def skip_test_if_missing_module(self): 98 self.skip_if_no_wallet() 99 100 def setup_network(self): 101 super().setup_network() 102 self.connect_nodes(0, 2) 103 self.sync_all() 104 105 def success_mine(self, node, txid, sign, redeem_script=""): 106 send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) 107 block = self.generate(node, 1) 108 assert_equal(len(node.getblock(block[0])["tx"]), 2) 109 self.sync_blocks() 110 111 def fail_accept(self, node, error_msg, txid, sign, redeem_script=""): 112 assert_raises_rpc_error(-26, error_msg, send_to_witness, use_p2wsh=1, node=node, utxo=getutxo(txid), pubkey=self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=sign, insert_redeem_script=redeem_script) 113 114 def run_test(self): 115 self.generate(self.nodes[0], 161) # block 161 116 117 self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork") 118 txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) 119 tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']}) 120 assert_equal(tmpl['sizelimit'], 1000000) 121 assert 'weightlimit' not in tmpl 122 assert_equal(tmpl['sigoplimit'], 20000) 123 assert_equal(tmpl['transactions'][0]['hash'], txid) 124 assert_equal(tmpl['transactions'][0]['sigops'], 2) 125 assert '!segwit' not in tmpl['rules'] 126 self.generate(self.nodes[0], 1) # block 162 127 128 balance_presetup = self.nodes[0].getbalance() 129 self.pubkey = [] 130 p2sh_ids = [] # p2sh_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE embedded in p2sh 131 wit_ids = [] # wit_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE via bare witness 132 for i in range(3): 133 key = get_generate_key() 134 self.pubkey.append(key.pubkey) 135 136 multiscript = keys_to_multisig_script([self.pubkey[-1]]) 137 p2sh_ms_addr = self.nodes[i].createmultisig(1, [self.pubkey[-1]], 'p2sh-segwit')['address'] 138 bip173_ms_addr = self.nodes[i].createmultisig(1, [self.pubkey[-1]], 'bech32')['address'] 139 assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript)) 140 assert_equal(bip173_ms_addr, script_to_p2wsh(multiscript)) 141 142 p2sh_ms_desc = descsum_create(f"sh(wsh(multi(1,{key.privkey})))") 143 bip173_ms_desc = descsum_create(f"wsh(multi(1,{key.privkey}))") 144 assert_equal(self.nodes[i].deriveaddresses(p2sh_ms_desc)[0], p2sh_ms_addr) 145 assert_equal(self.nodes[i].deriveaddresses(bip173_ms_desc)[0], bip173_ms_addr) 146 147 sh_wpkh_desc = descsum_create(f"sh(wpkh({key.privkey}))") 148 wpkh_desc = descsum_create(f"wpkh({key.privkey})") 149 assert_equal(self.nodes[i].deriveaddresses(sh_wpkh_desc)[0], key.p2sh_p2wpkh_addr) 150 assert_equal(self.nodes[i].deriveaddresses(wpkh_desc)[0], key.p2wpkh_addr) 151 152 res = self.nodes[i].importdescriptors([ 153 {"desc": p2sh_ms_desc, "timestamp": "now"}, 154 {"desc": bip173_ms_desc, "timestamp": "now"}, 155 {"desc": sh_wpkh_desc, "timestamp": "now"}, 156 {"desc": wpkh_desc, "timestamp": "now"}, 157 ]) 158 assert all([r["success"] for r in res]) 159 160 p2sh_ids.append([]) 161 wit_ids.append([]) 162 for _ in range(2): 163 p2sh_ids[i].append([]) 164 wit_ids[i].append([]) 165 166 for _ in range(5): 167 for n in range(3): 168 for v in range(2): 169 wit_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], False, Decimal("49.999"))) 170 p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], True, Decimal("49.999"))) 171 172 self.generate(self.nodes[0], 1) # block 163 173 174 # Make sure all nodes recognize the transactions as theirs 175 assert_equal(self.nodes[0].getbalance(), balance_presetup - 60 * 50 + 20 * Decimal("49.999") + 50) 176 assert_equal(self.nodes[1].getbalance(), 20 * Decimal("49.999")) 177 assert_equal(self.nodes[2].getbalance(), 20 * Decimal("49.999")) 178 179 self.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid") 180 self.fail_accept(self.nodes[2], "mempool-script-verify-flag-failed (Operation not valid with the current stack size)", p2sh_ids[NODE_2][P2WPKH][1], sign=False) 181 self.fail_accept(self.nodes[2], "mempool-script-verify-flag-failed (Operation not valid with the current stack size)", p2sh_ids[NODE_2][P2WSH][1], sign=False) 182 183 self.generate(self.nodes[0], 1) # block 164 184 185 self.log.info("Verify witness txs are mined as soon as segwit activates") 186 187 send_to_witness(1, self.nodes[2], getutxo(wit_ids[NODE_2][P2WPKH][0]), self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=True) 188 send_to_witness(1, self.nodes[2], getutxo(wit_ids[NODE_2][P2WSH][0]), self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=True) 189 send_to_witness(1, self.nodes[2], getutxo(p2sh_ids[NODE_2][P2WPKH][0]), self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=True) 190 send_to_witness(1, self.nodes[2], getutxo(p2sh_ids[NODE_2][P2WSH][0]), self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=True) 191 192 assert_equal(len(self.nodes[2].getrawmempool()), 4) 193 blockhash = self.generate(self.nodes[2], 1)[0] # block 165 (first block with new rules) 194 assert_equal(len(self.nodes[2].getrawmempool()), 0) 195 segwit_tx_list = self.nodes[2].getblock(blockhash)["tx"] 196 assert_equal(len(segwit_tx_list), 5) 197 198 self.log.info("Verify default node can't accept txs with missing witness") 199 # unsigned, no scriptsig 200 self.fail_accept(self.nodes[0], "mempool-script-verify-flag-failed (Witness program hash mismatch)", wit_ids[NODE_0][P2WPKH][0], sign=False) 201 self.fail_accept(self.nodes[0], "mempool-script-verify-flag-failed (Witness program was passed an empty witness)", wit_ids[NODE_0][P2WSH][0], sign=False) 202 self.fail_accept(self.nodes[0], "mempool-script-verify-flag-failed (Operation not valid with the current stack size)", p2sh_ids[NODE_0][P2WPKH][0], sign=False) 203 self.fail_accept(self.nodes[0], "mempool-script-verify-flag-failed (Operation not valid with the current stack size)", p2sh_ids[NODE_0][P2WSH][0], sign=False) 204 # unsigned with redeem script 205 self.fail_accept(self.nodes[0], "mempool-script-verify-flag-failed (Witness program hash mismatch)", p2sh_ids[NODE_0][P2WPKH][0], sign=False, redeem_script=witness_script(False, self.pubkey[0])) 206 self.fail_accept(self.nodes[0], "mempool-script-verify-flag-failed (Witness program was passed an empty witness)", p2sh_ids[NODE_0][P2WSH][0], sign=False, redeem_script=witness_script(True, self.pubkey[0])) 207 208 # Coinbase contains the witness commitment nonce, check that RPC shows us 209 coinbase_txid = self.nodes[2].getblock(blockhash)['tx'][0] 210 coinbase_tx = self.nodes[2].gettransaction(txid=coinbase_txid, verbose=True) 211 witnesses = coinbase_tx["decoded"]["vin"][0]["txinwitness"] 212 assert_equal(len(witnesses), 1) 213 assert_is_hex_string(witnesses[0]) 214 assert_equal(witnesses[0], '00' * 32) 215 216 self.log.info("Verify witness txs without witness data are invalid after the fork") 217 self.fail_accept(self.nodes[2], 'mempool-script-verify-flag-failed (Witness program hash mismatch)', wit_ids[NODE_2][P2WPKH][2], sign=False) 218 self.fail_accept(self.nodes[2], 'mempool-script-verify-flag-failed (Witness program was passed an empty witness)', wit_ids[NODE_2][P2WSH][2], sign=False) 219 self.fail_accept(self.nodes[2], 'mempool-script-verify-flag-failed (Witness program hash mismatch)', p2sh_ids[NODE_2][P2WPKH][2], sign=False, redeem_script=witness_script(False, self.pubkey[2])) 220 self.fail_accept(self.nodes[2], 'mempool-script-verify-flag-failed (Witness program was passed an empty witness)', p2sh_ids[NODE_2][P2WSH][2], sign=False, redeem_script=witness_script(True, self.pubkey[2])) 221 222 self.log.info("Verify default node can now use witness txs") 223 self.success_mine(self.nodes[0], wit_ids[NODE_0][P2WPKH][0], True) 224 self.success_mine(self.nodes[0], wit_ids[NODE_0][P2WSH][0], True) 225 self.success_mine(self.nodes[0], p2sh_ids[NODE_0][P2WPKH][0], True) 226 self.success_mine(self.nodes[0], p2sh_ids[NODE_0][P2WSH][0], True) 227 228 self.log.info("Verify sigops are counted in GBT with BIP141 rules after the fork") 229 txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) 230 raw_tx = self.nodes[0].getrawtransaction(txid, True) 231 tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']}) 232 assert_greater_than_or_equal(tmpl['sizelimit'], 3999577) # actual maximum size is lower due to minimum mandatory non-witness data 233 assert_equal(tmpl['weightlimit'], 4000000) 234 assert_equal(tmpl['sigoplimit'], 80000) 235 assert_equal(tmpl['transactions'][0]['txid'], txid) 236 expected_sigops = 9 if 'txinwitness' in raw_tx["vin"][0] else 8 237 assert_equal(tmpl['transactions'][0]['sigops'], expected_sigops) 238 assert '!segwit' in tmpl['rules'] 239 240 self.generate(self.nodes[0], 1) # Mine a block to clear the gbt cache 241 242 self.log.info("Non-segwit miners are able to use GBT response after activation.") 243 # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) -> 244 # tx2 (segwit input, paying to a non-segwit output) -> 245 # tx3 (non-segwit input, paying to a non-segwit output). 246 # tx1 is allowed to appear in the block, but no others. 247 txid1 = send_to_witness(1, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.996")) 248 assert txid1 in self.nodes[0].getrawmempool() 249 250 tx1_hex = self.nodes[0].gettransaction(txid1)['hex'] 251 tx1 = tx_from_hex(tx1_hex) 252 253 # Check that wtxid is properly reported in mempool entry (txid1) 254 assert_equal(self.nodes[0].getmempoolentry(txid1)["wtxid"], tx1.wtxid_hex) 255 256 # Check that weight and vsize are properly reported in mempool entry (txid1) 257 assert_equal(self.nodes[0].getmempoolentry(txid1)["vsize"], tx1.get_vsize()) 258 assert_equal(self.nodes[0].getmempoolentry(txid1)["weight"], tx1.get_weight()) 259 260 # Now create tx2, which will spend from txid1. 261 tx = CTransaction() 262 tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b'')) 263 tx.vout.append(CTxOut(int(49.99 * COIN), CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))) 264 tx2_hex = self.nodes[0].signrawtransactionwithwallet(tx.serialize().hex())['hex'] 265 txid2 = self.nodes[0].sendrawtransaction(tx2_hex) 266 tx = tx_from_hex(tx2_hex) 267 assert not tx.wit.is_null() 268 269 # Check that wtxid is properly reported in mempool entry (txid2) 270 assert_equal(self.nodes[0].getmempoolentry(txid2)["wtxid"], tx.wtxid_hex) 271 272 # Check that weight and vsize are properly reported in mempool entry (txid2) 273 assert_equal(self.nodes[0].getmempoolentry(txid2)["vsize"], tx.get_vsize()) 274 assert_equal(self.nodes[0].getmempoolentry(txid2)["weight"], tx.get_weight()) 275 276 # Now create tx3, which will spend from txid2 277 tx = CTransaction() 278 tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b"")) 279 tx.vout.append(CTxOut(int(49.95 * COIN), CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))) # Huge fee 280 txid3 = self.nodes[0].sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0) 281 assert tx.wit.is_null() 282 assert txid3 in self.nodes[0].getrawmempool() 283 284 # Check that getblocktemplate includes all transactions. 285 template = self.nodes[0].getblocktemplate({"rules": ["segwit"]}) 286 template_txids = [t['txid'] for t in template['transactions']] 287 assert txid1 in template_txids 288 assert txid2 in template_txids 289 assert txid3 in template_txids 290 291 # Check that wtxid is properly reported in mempool entry (txid3) 292 assert_equal(self.nodes[0].getmempoolentry(txid3)["wtxid"], tx.wtxid_hex) 293 294 # Check that weight and vsize are properly reported in mempool entry (txid3) 295 assert_equal(self.nodes[0].getmempoolentry(txid3)["vsize"], tx.get_vsize()) 296 assert_equal(self.nodes[0].getmempoolentry(txid3)["weight"], tx.get_weight()) 297 298 # Mine a block to clear the gbt cache again. 299 self.generate(self.nodes[0], 1) 300 301 def mine_and_test_listunspent(self, script_list, ismine): 302 utxo = find_spendable_utxo(self.nodes[0], 50) 303 tx = CTransaction() 304 tx.vin.append(CTxIn(COutPoint(int('0x' + utxo['txid'], 0), utxo['vout']))) 305 for i in script_list: 306 tx.vout.append(CTxOut(10000000, i)) 307 signresults = self.nodes[0].signrawtransactionwithwallet(tx.serialize_without_witness().hex())['hex'] 308 txid = self.nodes[0].sendrawtransaction(hexstring=signresults, maxfeerate=0) 309 txs_mined[txid] = self.generate(self.nodes[0], 1)[0] 310 watchcount = 0 311 spendcount = 0 312 for i in self.nodes[0].listunspent(): 313 if i['txid'] == txid: 314 watchcount += 1 315 if i['spendable']: 316 spendcount += 1 317 if ismine == 2: 318 assert_equal(spendcount, len(script_list)) 319 elif ismine == 1: 320 assert_equal(watchcount, len(script_list)) 321 assert_equal(spendcount, 0) 322 else: 323 assert_equal(watchcount, 0) 324 return txid 325 326 def p2sh_address_to_script(self, v): 327 bare = CScript(bytes.fromhex(v['hex'])) 328 p2sh = CScript(bytes.fromhex(v['scriptPubKey'])) 329 p2wsh = script_to_p2wsh_script(bare) 330 p2sh_p2wsh = script_to_p2sh_script(p2wsh) 331 return [bare, p2sh, p2wsh, p2sh_p2wsh] 332 333 def p2pkh_address_to_script(self, v): 334 pubkey = bytes.fromhex(v['pubkey']) 335 p2wpkh = key_to_p2wpkh_script(pubkey) 336 p2sh_p2wpkh = script_to_p2sh_script(p2wpkh) 337 p2pk = key_to_p2pk_script(pubkey) 338 p2pkh = CScript(bytes.fromhex(v['scriptPubKey'])) 339 p2sh_p2pk = script_to_p2sh_script(p2pk) 340 p2sh_p2pkh = script_to_p2sh_script(p2pkh) 341 p2wsh_p2pk = script_to_p2wsh_script(p2pk) 342 p2wsh_p2pkh = script_to_p2wsh_script(p2pkh) 343 p2sh_p2wsh_p2pk = script_to_p2sh_script(p2wsh_p2pk) 344 p2sh_p2wsh_p2pkh = script_to_p2sh_script(p2wsh_p2pkh) 345 return [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] 346 347 def create_and_mine_tx_from_txids(self, txids, success=True): 348 tx = CTransaction() 349 for i in txids: 350 txraw = self.nodes[0].getrawtransaction(i, 0, txs_mined[i]) 351 txtmp = tx_from_hex(txraw) 352 for j in range(len(txtmp.vout)): 353 tx.vin.append(CTxIn(COutPoint(int('0x' + i, 0), j))) 354 tx.vout.append(CTxOut(0, CScript())) 355 signresults = self.nodes[0].signrawtransactionwithwallet(tx.serialize_without_witness().hex())['hex'] 356 self.nodes[0].sendrawtransaction(hexstring=signresults, maxfeerate=0) 357 self.generate(self.nodes[0], 1) 358 359 360 if __name__ == '__main__': 361 SegWitTest(__file__).main()