mempool_accept.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2017-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 mempool acceptance of raw transactions.""" 6 7 from copy import deepcopy 8 from decimal import Decimal 9 import math 10 11 from test_framework.test_framework import BitcoinTestFramework 12 from test_framework.blocktools import MAX_STANDARD_TX_WEIGHT 13 from test_framework.mempool_util import ( 14 DEFAULT_MIN_RELAY_TX_FEE, 15 DEFAULT_INCREMENTAL_RELAY_FEE, 16 ) 17 from test_framework.messages import ( 18 MAX_BIP125_RBF_SEQUENCE, 19 COIN, 20 COutPoint, 21 CTransaction, 22 CTxIn, 23 CTxInWitness, 24 CTxOut, 25 MAX_BLOCK_WEIGHT, 26 WITNESS_SCALE_FACTOR, 27 MAX_MONEY, 28 SEQUENCE_FINAL, 29 tx_from_hex, 30 ) 31 from test_framework.script import ( 32 CScript, 33 OP_0, 34 OP_HASH160, 35 OP_RETURN, 36 OP_TRUE, 37 SIGHASH_ALL, 38 sign_input_legacy, 39 ) 40 from test_framework.script_util import ( 41 DUMMY_MIN_OP_RETURN_SCRIPT, 42 keys_to_multisig_script, 43 MIN_PADDING, 44 MIN_STANDARD_TX_NONWITNESS_SIZE, 45 PAY_TO_ANCHOR, 46 script_to_p2sh_script, 47 script_to_p2wsh_script, 48 ) 49 from test_framework.util import ( 50 assert_equal, 51 assert_greater_than, 52 assert_raises_rpc_error, 53 sync_txindex, 54 ) 55 from test_framework.wallet import MiniWallet 56 from test_framework.wallet_util import generate_keypair 57 58 59 class MempoolAcceptanceTest(BitcoinTestFramework): 60 def set_test_params(self): 61 self.num_nodes = 1 62 self.extra_args = [[ 63 '-txindex','-permitbaremultisig=0', 64 ]] * self.num_nodes 65 self.supports_cli = False 66 67 def check_mempool_result(self, result_expected, *args, **kwargs): 68 """Wrapper to check result of testmempoolaccept on node_0's mempool""" 69 result_test = self.nodes[0].testmempoolaccept(*args, **kwargs) 70 for r in result_test: 71 # Skip these checks for now 72 r.pop('wtxid') 73 if "fees" in r: 74 r["fees"].pop("effective-feerate") 75 r["fees"].pop("effective-includes") 76 if "reject-details" in r: 77 r.pop("reject-details") 78 assert_equal(result_expected, result_test) 79 assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size) # Must not change mempool state 80 81 def run_test(self): 82 node = self.nodes[0] 83 self.wallet = MiniWallet(node) 84 85 assert_equal(node.getmempoolinfo()['permitbaremultisig'], False) 86 87 self.log.info('Start with empty mempool, and 200 blocks') 88 self.mempool_size = 0 89 assert_equal(node.getblockcount(), 200) 90 assert_equal(node.getmempoolinfo()['size'], self.mempool_size) 91 92 self.log.info("Check default settings") 93 # Settings are listed in BTC/kvB 94 assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN) 95 assert_equal(node.getmempoolinfo()['incrementalrelayfee'], Decimal(DEFAULT_INCREMENTAL_RELAY_FEE) / COIN) 96 97 self.log.info('Should not accept garbage to testmempoolaccept') 98 assert_raises_rpc_error(-3, 'JSON value of type string is not of expected type array', lambda: node.testmempoolaccept(rawtxs='ff00baar')) 99 assert_raises_rpc_error(-8, 'Array must contain between 1 and 25 transactions.', lambda: node.testmempoolaccept(rawtxs=['ff22']*26)) 100 assert_raises_rpc_error(-8, 'Array must contain between 1 and 25 transactions.', lambda: node.testmempoolaccept(rawtxs=[])) 101 assert_raises_rpc_error(-22, 'TX decode failed', lambda: node.testmempoolaccept(rawtxs=['ff00baar'])) 102 103 self.log.info('A transaction already in the blockchain') 104 tx = self.wallet.create_self_transfer()['tx'] # Pick a random coin(base) to spend 105 tx.vout.append(deepcopy(tx.vout[0])) 106 tx.vout[0].nValue = int(0.3 * COIN) 107 tx.vout[1].nValue = int(49 * COIN) 108 raw_tx_in_block = tx.serialize().hex() 109 txid_in_block = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_in_block) 110 self.generate(node, 1) 111 self.mempool_size = 0 112 # Also check feerate. 1BTC/kvB fails 113 assert_raises_rpc_error(-8, "Fee rates larger than or equal to 1BTC/kvB are not accepted", lambda: self.check_mempool_result( 114 result_expected=None, 115 rawtxs=[raw_tx_in_block], 116 maxfeerate=1, 117 )) 118 # Check negative feerate 119 assert_raises_rpc_error(-3, "Amount out of range", lambda: self.check_mempool_result( 120 result_expected=None, 121 rawtxs=[raw_tx_in_block], 122 maxfeerate=-0.01, 123 )) 124 # ... 0.99 passes 125 self.check_mempool_result( 126 result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': 'txn-already-known'}], 127 rawtxs=[raw_tx_in_block], 128 maxfeerate=0.99, 129 ) 130 131 self.log.info('A transaction not in the mempool') 132 fee = Decimal('0.000007') 133 utxo_to_spend = self.wallet.get_utxo(txid=txid_in_block) # use 0.3 BTC UTXO 134 tx = self.wallet.create_self_transfer(utxo_to_spend=utxo_to_spend, sequence=MAX_BIP125_RBF_SEQUENCE)['tx'] 135 tx.vout[0].nValue = int((Decimal('0.3') - fee) * COIN) 136 raw_tx_0 = tx.serialize().hex() 137 txid_0 = tx.txid_hex 138 self.check_mempool_result( 139 result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': fee}}], 140 rawtxs=[raw_tx_0], 141 ) 142 143 self.log.info('A final transaction not in the mempool') 144 output_amount = Decimal('0.025') 145 tx = self.wallet.create_self_transfer( 146 sequence=SEQUENCE_FINAL, 147 locktime=node.getblockcount() + 2000, # Can be anything 148 )['tx'] 149 tx.vout[0].nValue = int(output_amount * COIN) 150 raw_tx_final = tx.serialize().hex() 151 tx = tx_from_hex(raw_tx_final) 152 fee_expected = Decimal('50.0') - output_amount 153 self.check_mempool_result( 154 result_expected=[{'txid': tx.txid_hex, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': fee_expected}}], 155 rawtxs=[tx.serialize().hex()], 156 maxfeerate=0, 157 ) 158 node.sendrawtransaction(hexstring=raw_tx_final, maxfeerate=0) 159 self.mempool_size += 1 160 161 self.log.info('A transaction in the mempool') 162 node.sendrawtransaction(hexstring=raw_tx_0) 163 self.mempool_size += 1 164 self.check_mempool_result( 165 result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'txn-already-in-mempool'}], 166 rawtxs=[raw_tx_0], 167 ) 168 169 self.log.info('A transaction that replaces a mempool transaction') 170 tx = tx_from_hex(raw_tx_0) 171 tx.vout[0].nValue -= int(fee * COIN) # Double the fee 172 raw_tx_0 = tx.serialize().hex() 173 txid_0 = tx.txid_hex 174 self.check_mempool_result( 175 result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': (2 * fee)}}], 176 rawtxs=[raw_tx_0], 177 ) 178 node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0) 179 180 self.log.info('A transaction with missing inputs, that never existed') 181 tx = tx_from_hex(raw_tx_0) 182 tx.vin[0].prevout = COutPoint(hash=int('ff' * 32, 16), n=14) 183 self.check_mempool_result( 184 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'missing-inputs'}], 185 rawtxs=[tx.serialize().hex()], 186 ) 187 188 self.log.info('A transaction with missing inputs, that existed once in the past') 189 tx = tx_from_hex(raw_tx_0) 190 tx.vin[0].prevout.n = 1 # Set vout to 1, to spend the other outpoint (49 coins) of the in-chain-tx we want to double spend 191 raw_tx_1 = tx.serialize().hex() 192 txid_1 = node.sendrawtransaction(hexstring=raw_tx_1, maxfeerate=0) 193 # Now spend both to "clearly hide" the outputs, ie. remove the coins from the utxo set by spending them 194 tx = self.wallet.create_self_transfer()['tx'] 195 tx.vin.append(deepcopy(tx.vin[0])) 196 tx.wit.vtxinwit.append(deepcopy(tx.wit.vtxinwit[0])) 197 tx.vin[0].prevout = COutPoint(hash=int(txid_0, 16), n=0) 198 tx.vin[1].prevout = COutPoint(hash=int(txid_1, 16), n=0) 199 tx.vout[0].nValue = int(0.1 * COIN) 200 raw_tx_spend_both = tx.serialize().hex() 201 txid_spend_both = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_spend_both) 202 self.generate(node, 1) 203 self.mempool_size = 0 204 # Now see if we can add the coins back to the utxo set by sending the exact txs again 205 self.check_mempool_result( 206 result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'missing-inputs'}], 207 rawtxs=[raw_tx_0], 208 ) 209 self.check_mempool_result( 210 result_expected=[{'txid': txid_1, 'allowed': False, 'reject-reason': 'missing-inputs'}], 211 rawtxs=[raw_tx_1], 212 ) 213 214 self.log.info('Create a "reference" tx for later use') 215 utxo_to_spend = self.wallet.get_utxo(txid=txid_spend_both) 216 tx = self.wallet.create_self_transfer(utxo_to_spend=utxo_to_spend, sequence=SEQUENCE_FINAL)['tx'] 217 tx.vout[0].nValue = int(0.05 * COIN) 218 raw_tx_reference = tx.serialize().hex() 219 # Reference tx should be valid on itself 220 self.check_mempool_result( 221 result_expected=[{'txid': tx.txid_hex, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal('0.1') - Decimal('0.05')}}], 222 rawtxs=[tx.serialize().hex()], 223 maxfeerate=0, 224 ) 225 226 self.log.info('A transaction with no outputs') 227 tx = tx_from_hex(raw_tx_reference) 228 tx.vout = [] 229 self.check_mempool_result( 230 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-vout-empty'}], 231 rawtxs=[tx.serialize().hex()], 232 ) 233 234 self.log.info('A really large transaction') 235 tx = tx_from_hex(raw_tx_reference) 236 tx.vin = [tx.vin[0]] * math.ceil((MAX_BLOCK_WEIGHT // WITNESS_SCALE_FACTOR) / len(tx.vin[0].serialize())) 237 self.check_mempool_result( 238 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-oversize'}], 239 rawtxs=[tx.serialize().hex()], 240 ) 241 242 self.log.info('A transaction with negative output value') 243 tx = tx_from_hex(raw_tx_reference) 244 tx.vout[0].nValue *= -1 245 self.check_mempool_result( 246 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-vout-negative'}], 247 rawtxs=[tx.serialize().hex()], 248 ) 249 250 # The following two validations prevent overflow of the output amounts (see CVE-2010-5139). 251 self.log.info('A transaction with too large output value') 252 tx = tx_from_hex(raw_tx_reference) 253 tx.vout[0].nValue = MAX_MONEY + 1 254 self.check_mempool_result( 255 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-vout-toolarge'}], 256 rawtxs=[tx.serialize().hex()], 257 ) 258 259 self.log.info('A transaction with too large sum of output values') 260 tx = tx_from_hex(raw_tx_reference) 261 tx.vout = [tx.vout[0]] * 2 262 tx.vout[0].nValue = MAX_MONEY 263 self.check_mempool_result( 264 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-txouttotal-toolarge'}], 265 rawtxs=[tx.serialize().hex()], 266 ) 267 268 self.log.info('A transaction with duplicate inputs') 269 tx = tx_from_hex(raw_tx_reference) 270 tx.vin = [tx.vin[0]] * 2 271 self.check_mempool_result( 272 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-inputs-duplicate'}], 273 rawtxs=[tx.serialize().hex()], 274 ) 275 276 self.log.info('A non-coinbase transaction with coinbase-like outpoint') 277 tx = tx_from_hex(raw_tx_reference) 278 tx.vin.append(CTxIn(COutPoint(hash=0, n=0xffffffff))) 279 self.check_mempool_result( 280 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bad-txns-prevout-null'}], 281 rawtxs=[tx.serialize().hex()], 282 ) 283 284 self.log.info('A coinbase transaction') 285 # Pick the input of the first tx we created, so it has to be a coinbase tx 286 sync_txindex(self, node) 287 raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid']) 288 tx = tx_from_hex(raw_tx_coinbase_spent) 289 self.check_mempool_result( 290 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'coinbase'}], 291 rawtxs=[tx.serialize().hex()], 292 ) 293 294 self.log.info('Some nonstandard transactions') 295 tx = tx_from_hex(raw_tx_reference) 296 tx.version = 4 # A version currently non-standard 297 self.check_mempool_result( 298 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'version'}], 299 rawtxs=[tx.serialize().hex()], 300 ) 301 tx = tx_from_hex(raw_tx_reference) 302 tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script 303 self.check_mempool_result( 304 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'scriptpubkey'}], 305 rawtxs=[tx.serialize().hex()], 306 ) 307 tx = tx_from_hex(raw_tx_reference) 308 _, pubkey = generate_keypair() 309 tx.vout[0].scriptPubKey = keys_to_multisig_script([pubkey] * 3, k=2) # Some bare multisig script (2-of-3) 310 self.check_mempool_result( 311 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'bare-multisig'}], 312 rawtxs=[tx.serialize().hex()], 313 ) 314 tx = tx_from_hex(raw_tx_reference) 315 tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig 316 self.check_mempool_result( 317 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'scriptsig-not-pushonly'}], 318 rawtxs=[tx.serialize().hex()], 319 ) 320 tx = tx_from_hex(raw_tx_reference) 321 tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes) 322 self.check_mempool_result( 323 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'scriptsig-size'}], 324 rawtxs=[tx.serialize().hex()], 325 ) 326 tx = tx_from_hex(raw_tx_reference) 327 output_p2sh_burn = CTxOut(nValue=540, scriptPubKey=script_to_p2sh_script(b'burn')) 328 num_scripts = 100000 // len(output_p2sh_burn.serialize()) # Use enough outputs to make the tx too large for our policy 329 tx.vout = [output_p2sh_burn] * num_scripts 330 self.check_mempool_result( 331 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'tx-size'}], 332 rawtxs=[tx.serialize().hex()], 333 ) 334 tx = tx_from_hex(raw_tx_reference) 335 tx.vout[0] = output_p2sh_burn 336 tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy 337 self.check_mempool_result( 338 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'dust'}], 339 rawtxs=[tx.serialize().hex()], 340 ) 341 342 # OP_RETURN followed by non-push 343 tx = tx_from_hex(raw_tx_reference) 344 tx.vout[0].scriptPubKey = CScript([OP_RETURN, OP_HASH160]) 345 self.check_mempool_result( 346 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'scriptpubkey'}], 347 rawtxs=[tx.serialize().hex()], 348 ) 349 350 # Multiple OP_RETURN and more than 83 bytes, even if over MAX_SCRIPT_ELEMENT_SIZE 351 # are standard since v30 352 tx = tx_from_hex(raw_tx_reference) 353 tx.vout.append(CTxOut(0, CScript([OP_RETURN, b'\xff']))) 354 tx.vout.append(CTxOut(0, CScript([OP_RETURN, b'\xff' * 50000]))) 355 356 self.check_mempool_result( 357 result_expected=[{'txid': tx.txid_hex, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': Decimal('0.05')}}], 358 rawtxs=[tx.serialize().hex()], 359 maxfeerate=0 360 ) 361 362 self.log.info("A transaction with several OP_RETURN outputs.") 363 tx = tx_from_hex(raw_tx_reference) 364 op_return_count = 42 365 tx.vout[0].nValue = int(tx.vout[0].nValue / op_return_count) 366 tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff']) 367 tx.vout = [tx.vout[0]] * op_return_count 368 self.check_mempool_result( 369 result_expected=[{"txid": tx.txid_hex, "allowed": True, "vsize": tx.get_vsize(), "fees": {"base": Decimal("0.05000026")}}], 370 rawtxs=[tx.serialize().hex()], 371 ) 372 373 self.log.info("A transaction with an OP_RETURN output that bumps into the max standardness tx size.") 374 tx = tx_from_hex(raw_tx_reference) 375 tx.vout[0].scriptPubKey = CScript([OP_RETURN]) 376 data_len = int(MAX_STANDARD_TX_WEIGHT / 4) - tx.get_vsize() - 5 - 4 # -5 for PUSHDATA4 and -4 for script size 377 tx.vout[0].scriptPubKey = CScript([OP_RETURN, b"\xff" * (data_len)]) 378 assert_equal(tx.get_vsize(), int(MAX_STANDARD_TX_WEIGHT / 4)) 379 self.check_mempool_result( 380 result_expected=[{"txid": tx.txid_hex, "allowed": True, "vsize": tx.get_vsize(), "fees": {"base": Decimal("0.1") - Decimal("0.05")}}], 381 rawtxs=[tx.serialize().hex()], 382 ) 383 tx.vout[0].scriptPubKey = CScript([OP_RETURN, b"\xff" * (data_len + 1)]) 384 assert_greater_than(tx.get_vsize(), int(MAX_STANDARD_TX_WEIGHT / 4)) 385 self.check_mempool_result( 386 result_expected=[{"txid": tx.txid_hex, "allowed": False, "reject-reason": "tx-size"}], 387 rawtxs=[tx.serialize().hex()], 388 ) 389 390 self.log.info('A timelocked transaction') 391 tx = tx_from_hex(raw_tx_reference) 392 tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored 393 tx.nLockTime = node.getblockcount() + 1 394 self.check_mempool_result( 395 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'non-final'}], 396 rawtxs=[tx.serialize().hex()], 397 ) 398 399 self.log.info('A transaction that is locked by BIP68 sequence logic') 400 tx = tx_from_hex(raw_tx_reference) 401 tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one 402 self.check_mempool_result( 403 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'non-BIP68-final'}], 404 rawtxs=[tx.serialize().hex()], 405 maxfeerate=0, 406 ) 407 408 # Prep for tiny-tx tests with wsh(OP_TRUE) output 409 seed_tx = self.wallet.send_to(from_node=node, scriptPubKey=script_to_p2wsh_script(CScript([OP_TRUE])), amount=COIN) 410 self.generate(node, 1) 411 412 self.log.info('A tiny transaction(in non-witness bytes) that is disallowed') 413 tx = CTransaction() 414 tx.vin.append(CTxIn(COutPoint(int(seed_tx["txid"], 16), seed_tx["sent_vout"]), b"", SEQUENCE_FINAL)) 415 tx.wit.vtxinwit = [CTxInWitness()] 416 tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] 417 tx.vout.append(CTxOut(0, CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 2))))) 418 # Note it's only non-witness size that matters! 419 assert_equal(len(tx.serialize_without_witness()), 64) 420 assert_equal(MIN_STANDARD_TX_NONWITNESS_SIZE - 1, 64) 421 assert_greater_than(len(tx.serialize()), 64) 422 423 self.check_mempool_result( 424 result_expected=[{'txid': tx.txid_hex, 'allowed': False, 'reject-reason': 'tx-size-small'}], 425 rawtxs=[tx.serialize().hex()], 426 maxfeerate=0, 427 ) 428 429 self.log.info('Minimally-small transaction(in non-witness bytes) that is allowed') 430 tx.vout[0] = CTxOut(COIN - 1000, DUMMY_MIN_OP_RETURN_SCRIPT) 431 assert_equal(len(tx.serialize_without_witness()), MIN_STANDARD_TX_NONWITNESS_SIZE) 432 self.check_mempool_result( 433 result_expected=[{'txid': tx.txid_hex, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal('0.00001000')}}], 434 rawtxs=[tx.serialize().hex()], 435 maxfeerate=0, 436 ) 437 438 self.log.info('OP_1 <0x4e73> is able to be created and spent') 439 anchor_value = 10000 440 create_anchor_tx = self.wallet.send_to(from_node=node, scriptPubKey=PAY_TO_ANCHOR, amount=anchor_value) 441 self.generate(node, 1) 442 443 # First spend has non-empty witness, will be rejected to prevent third party wtxid malleability 444 anchor_nonempty_wit_spend = CTransaction() 445 anchor_nonempty_wit_spend.vin.append(CTxIn(COutPoint(int(create_anchor_tx["txid"], 16), create_anchor_tx["sent_vout"]), b"")) 446 anchor_nonempty_wit_spend.vout.append(CTxOut(anchor_value - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE])))) 447 anchor_nonempty_wit_spend.wit.vtxinwit.append(CTxInWitness()) 448 anchor_nonempty_wit_spend.wit.vtxinwit[0].scriptWitness.stack.append(b"f") 449 450 self.check_mempool_result( 451 result_expected=[{'txid': anchor_nonempty_wit_spend.txid_hex, 'allowed': False, 'reject-reason': 'bad-witness-nonstandard'}], 452 rawtxs=[anchor_nonempty_wit_spend.serialize().hex()], 453 maxfeerate=0, 454 ) 455 456 # but is consensus-legal 457 self.generateblock(node, self.wallet.get_address(), [anchor_nonempty_wit_spend.serialize().hex()]) 458 459 # Without witness elements it is standard 460 create_anchor_tx = self.wallet.send_to(from_node=node, scriptPubKey=PAY_TO_ANCHOR, amount=anchor_value) 461 self.generate(node, 1) 462 463 anchor_spend = CTransaction() 464 anchor_spend.vin.append(CTxIn(COutPoint(int(create_anchor_tx["txid"], 16), create_anchor_tx["sent_vout"]), b"")) 465 anchor_spend.vout.append(CTxOut(anchor_value - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE])))) 466 anchor_spend.wit.vtxinwit.append(CTxInWitness()) 467 # It's "segwit" but txid == wtxid since there is no witness data 468 assert_equal(anchor_spend.txid_hex, anchor_spend.wtxid_hex) 469 470 self.check_mempool_result( 471 result_expected=[{'txid': anchor_spend.txid_hex, 'allowed': True, 'vsize': anchor_spend.get_vsize(), 'fees': { 'base': Decimal('0.00000700')}}], 472 rawtxs=[anchor_spend.serialize().hex()], 473 maxfeerate=0, 474 ) 475 476 self.log.info('But cannot be spent if nested sh()') 477 nested_anchor_tx = self.wallet.create_self_transfer(sequence=SEQUENCE_FINAL)['tx'] 478 nested_anchor_tx.vout[0].scriptPubKey = script_to_p2sh_script(PAY_TO_ANCHOR) 479 self.generateblock(node, self.wallet.get_address(), [nested_anchor_tx.serialize().hex()]) 480 481 nested_anchor_spend = CTransaction() 482 nested_anchor_spend.vin.append(CTxIn(COutPoint(nested_anchor_tx.txid_int, 0), b"")) 483 nested_anchor_spend.vin[0].scriptSig = CScript([bytes(PAY_TO_ANCHOR)]) 484 nested_anchor_spend.vout.append(CTxOut(nested_anchor_tx.vout[0].nValue - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE])))) 485 486 self.check_mempool_result( 487 result_expected=[{'txid': nested_anchor_spend.txid_hex, 'allowed': False, 'reject-reason': 'mempool-script-verify-flag-failed (Witness version reserved for soft-fork upgrades)'}], 488 rawtxs=[nested_anchor_spend.serialize().hex()], 489 maxfeerate=0, 490 ) 491 # but is consensus-legal 492 self.generateblock(node, self.wallet.get_address(), [nested_anchor_spend.serialize().hex()]) 493 494 self.log.info('Spending a confirmed bare multisig is okay') 495 address = self.wallet.get_address() 496 tx = tx_from_hex(raw_tx_reference) 497 privkey, pubkey = generate_keypair() 498 tx.vout[0].scriptPubKey = keys_to_multisig_script([pubkey] * 3, k=1) # Some bare multisig script (1-of-3) 499 self.generateblock(node, address, [tx.serialize().hex()]) 500 tx_spend = CTransaction() 501 tx_spend.vin.append(CTxIn(COutPoint(tx.txid_int, 0), b"")) 502 tx_spend.vout.append(CTxOut(tx.vout[0].nValue - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE])))) 503 sign_input_legacy(tx_spend, 0, tx.vout[0].scriptPubKey, privkey, sighash_type=SIGHASH_ALL) 504 tx_spend.vin[0].scriptSig = bytes(CScript([OP_0])) + tx_spend.vin[0].scriptSig 505 self.check_mempool_result( 506 result_expected=[{'txid': tx_spend.txid_hex, 'allowed': True, 'vsize': tx_spend.get_vsize(), 'fees': { 'base': Decimal('0.00000700')}}], 507 rawtxs=[tx_spend.serialize().hex()], 508 maxfeerate=0, 509 ) 510 511 if __name__ == '__main__': 512 MempoolAcceptanceTest(__file__).main()