diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -4,14 +4,15 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test mempool acceptance of raw transactions.""" -from io import BytesIO from test_framework.test_framework import BitcoinTestFramework from test_framework.messages import ( COIN, COutPoint, CTransaction, CTxOut, + FromHex, MAX_BLOCK_BASE_SIZE, + ToHex, ) from test_framework.script import ( hash160, @@ -24,7 +25,6 @@ from test_framework.util import ( assert_equal, assert_raises_rpc_error, - hex_str_to_bytes, wait_until, ) @@ -86,8 +86,7 @@ "sequence": 0xfffffffd}], outputs=[{node.getnewaddress(): 0.3 - fee}], ))['hex'] - tx = CTransaction() - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0))) + tx = FromHex(CTransaction(), raw_tx_0) txid_0 = tx.rehash() self.check_mempool_result( result_expected=[{'txid': txid_0, 'allowed': True}], @@ -103,10 +102,10 @@ outputs=[{node.getnewaddress(): 0.025}], locktime=node.getblockcount() + 2000, # Can be anything ))['hex'] - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_final))) + tx = FromHex(CTransaction(), raw_tx_final) self.check_mempool_result( result_expected=[{'txid': tx.rehash(), 'allowed': True}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], allowhighfees=True, ) node.sendrawtransaction(hexstring=raw_tx_final, allowhighfees=True) @@ -126,37 +125,37 @@ # ... self.log.info('A transaction that conflicts with an unconfirmed tx') - # Send the transaction that replaces the mempool transaction and opts out of replaceability + # Send the transaction that conflicts with the mempool transaction node.sendrawtransaction( - hexstring=tx.serialize().hex(), allowhighfees=True) + hexstring=ToHex(tx), allowhighfees=True) # take original raw_tx_0 - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0))) + tx = FromHex(CTransaction(), raw_tx_0) tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee # skip re-signing the tx self.check_mempool_result( result_expected=[{'txid': tx.rehash( ), 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], allowhighfees=True, ) self.log.info('A transaction with missing inputs, that never existed') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0))) + tx = FromHex(CTransaction(), raw_tx_0) tx.vin[0].prevout = COutPoint(hash=int('ff' * 32, 16), n=14) # skip re-signing the tx self.check_mempool_result( result_expected=[ {'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'missing-inputs'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info( 'A transaction with missing inputs, that existed once in the past') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0))) + tx = FromHex(CTransaction(), raw_tx_0) # Set vout to 1, to spend the other outpoint (49 coins) of the in-chain-tx we want to double spend tx.vin[0].prevout.n = 1 raw_tx_1 = node.signrawtransactionwithwallet( - tx.serialize().hex())['hex'] + ToHex(tx))['hex'] txid_1 = node.sendrawtransaction( hexstring=raw_tx_1, allowhighfees=True) # Now spend both to "clearly hide" the outputs, ie. remove the coins from the utxo set by spending them @@ -188,106 +187,106 @@ inputs=[{'txid': txid_spend_both, 'vout': 0}], outputs=[{node.getnewaddress(): 0.05}], ))['hex'] - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) # Reference tx should be valid on itself self.check_mempool_result( result_expected=[{'txid': tx.rehash(), 'allowed': True}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info('A transaction with no outputs') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) tx.vout = [] # Skip re-signing the transaction for context independent checks from now on - # tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex']))) + # FromHex(tx, node.signrawtransactionwithwallet(ToHex(tx))['hex']) self.check_mempool_result( result_expected=[{'txid': tx.rehash( ), 'allowed': False, 'reject-reason': '16: bad-txns-vout-empty'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info('A really large transaction') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) tx.vin = [tx.vin[0]] * (1 + MAX_BLOCK_BASE_SIZE // len(tx.vin[0].serialize())) self.check_mempool_result( result_expected=[ {'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-oversize'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info('A transaction with negative output value') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) tx.vout[0].nValue *= -1 self.check_mempool_result( result_expected=[{'txid': tx.rehash( ), 'allowed': False, 'reject-reason': '16: bad-txns-vout-negative'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info('A transaction with too large output value') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) tx.vout[0].nValue = 21000000 * COIN + 1 self.check_mempool_result( result_expected=[{'txid': tx.rehash( ), 'allowed': False, 'reject-reason': '16: bad-txns-vout-toolarge'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info('A transaction with too large sum of output values') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) tx.vout = [tx.vout[0]] * 2 tx.vout[0].nValue = 21000000 * COIN self.check_mempool_result( result_expected=[{'txid': tx.rehash( ), 'allowed': False, 'reject-reason': '16: bad-txns-txouttotal-toolarge'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info('A transaction with duplicate inputs') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) tx.vin = [tx.vin[0]] * 2 self.check_mempool_result( result_expected=[{'txid': tx.rehash( ), 'allowed': False, 'reject-reason': '16: bad-txns-inputs-duplicate'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info('A coinbase transaction') # Pick the input of the first tx we signed, so it has to be a coinbase tx raw_tx_coinbase_spent = node.getrawtransaction( txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid']) - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent))) + tx = FromHex(CTransaction(), raw_tx_coinbase_spent) self.check_mempool_result( result_expected=[ {'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-tx-coinbase'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info('Some nonstandard transactions') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) tx.nVersion = 3 # A version currently non-standard self.check_mempool_result( result_expected=[ {'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: version'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script self.check_mempool_result( result_expected=[ {'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptpubkey'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) # Some not-pushonly scriptSig tx.vin[0].scriptSig = CScript([OP_HASH160]) self.check_mempool_result( result_expected=[{'txid': tx.rehash( ), 'allowed': False, 'reject-reason': '64: scriptsig-not-pushonly'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) output_p2sh_burn = CTxOut(nValue=540, scriptPubKey=CScript( [OP_HASH160, hash160(b'burn'), OP_EQUAL])) # Use enough outputs to make the tx too large for our policy @@ -296,46 +295,46 @@ self.check_mempool_result( result_expected=[ {'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: tx-size'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) tx.vout[0] = output_p2sh_burn # Make output smaller, such that it is dust for our policy tx.vout[0].nValue -= 1 self.check_mempool_result( result_expected=[ {'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: dust'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff']) tx.vout = [tx.vout[0]] * 2 self.check_mempool_result( result_expected=[ {'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: multi-op-return'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info('A timelocked transaction') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) # Should be non-max, so locktime is not ignored tx.vin[0].nSequence -= 1 tx.nLockTime = node.getblockcount() + 1 self.check_mempool_result( result_expected=[ {'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: bad-txns-nonfinal'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], ) self.log.info('A transaction that is locked by BIP68 sequence logic') - tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) + tx = FromHex(CTransaction(), raw_tx_reference) # We could include it in the second block mined from now, but not the very next one tx.vin[0].nSequence = 2 # Can skip re-signing the tx because of early rejection self.check_mempool_result( result_expected=[ {'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-BIP68-final'}], - rawtxs=[tx.serialize().hex()], + rawtxs=[ToHex(tx)], allowhighfees=True, )