merge bitcoin#21754: Run feature_cltv with MiniWallet

Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
Kittywhiskers Van Gogh 2024-07-23 17:39:49 +00:00
parent bd750140be
commit 8b7ea28e80
No known key found for this signature in database
GPG Key ID: 30CD0C065E5C4AAD
2 changed files with 25 additions and 31 deletions

View File

@ -11,7 +11,6 @@ Test that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height
from test_framework.blocktools import ( from test_framework.blocktools import (
create_block, create_block,
create_coinbase, create_coinbase,
create_transaction,
) )
from test_framework.messages import ( from test_framework.messages import (
CTransaction, CTransaction,
@ -29,10 +28,8 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import ( from test_framework.util import (
assert_equal, assert_equal,
assert_raises_rpc_error, assert_raises_rpc_error,
hex_str_to_bytes,
) )
from test_framework.wallet import MiniWallet
from io import BytesIO
CLTV_HEIGHT = 1351 CLTV_HEIGHT = 1351
@ -41,19 +38,14 @@ CLTV_HEIGHT = 1351
# 1) prepending a given script to the scriptSig of vin 0 and # 1) prepending a given script to the scriptSig of vin 0 and
# 2) (optionally) modify the nSequence of vin 0 and the tx's nLockTime # 2) (optionally) modify the nSequence of vin 0 and the tx's nLockTime
def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None): def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None):
assert_equal(len(tx.vin), 1)
if nsequence is not None: if nsequence is not None:
tx.vin[0].nSequence = nsequence tx.vin[0].nSequence = nsequence
tx.nLockTime = nlocktime tx.nLockTime = nlocktime
# Need to re-sign, since nSequence and nLockTime changed tx.vin[0].scriptSig = CScript(prepend_scriptsig + list(CScript(tx.vin[0].scriptSig)))
signed_result = node.signrawtransactionwithwallet(tx.serialize().hex()) tx.rehash()
new_tx = CTransaction() return tx
new_tx.deserialize(BytesIO(hex_str_to_bytes(signed_result['hex'])))
else:
new_tx = tx
new_tx.vin[0].scriptSig = CScript(prepend_scriptsig + list(CScript(new_tx.vin[0].scriptSig)))
return new_tx
def cltv_invalidate(node, tx, failure_reason): def cltv_invalidate(node, tx, failure_reason):
@ -108,27 +100,23 @@ class BIP65Test(BitcoinTestFramework):
}, },
) )
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def run_test(self): def run_test(self):
peer = self.nodes[0].add_p2p_connection(P2PInterface()) peer = self.nodes[0].add_p2p_connection(P2PInterface())
wallet = MiniWallet(self.nodes[0], raw_script=True)
self.test_cltv_info(is_active=False) self.test_cltv_info(is_active=False)
self.log.info("Mining %d blocks", CLTV_HEIGHT - 2) self.log.info("Mining %d blocks", CLTV_HEIGHT - 2)
self.coinbase_txids = [self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(CLTV_HEIGHT - 2)] wallet.generate(10)
self.nodeaddress = self.nodes[0].getnewaddress() self.nodes[0].generate(CLTV_HEIGHT - 2 - 10)
self.log.info("Test that invalid-according-to-CLTV transactions can still appear in a block") self.log.info("Test that invalid-according-to-CLTV transactions can still appear in a block")
# create one invalid tx per CLTV failure reason (5 in total) and collect them # create one invalid tx per CLTV failure reason (5 in total) and collect them
invalid_ctlv_txs = [] invalid_ctlv_txs = []
for i in range(5): for i in range(5):
spendtx = create_transaction(self.nodes[0], self.coinbase_txids[i], spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
self.nodeaddress, amount=1.0)
spendtx = cltv_invalidate(self.nodes[0], spendtx, i) spendtx = cltv_invalidate(self.nodes[0], spendtx, i)
spendtx.rehash()
invalid_ctlv_txs.append(spendtx) invalid_ctlv_txs.append(spendtx)
tip = self.nodes[0].getbestblockhash() tip = self.nodes[0].getbestblockhash()
@ -162,10 +150,8 @@ class BIP65Test(BitcoinTestFramework):
# create and test one invalid tx per CLTV failure reason (5 in total) # create and test one invalid tx per CLTV failure reason (5 in total)
for i in range(5): for i in range(5):
spendtx = create_transaction(self.nodes[0], self.coinbase_txids[10+i], spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
self.nodeaddress, amount=1.0)
spendtx = cltv_invalidate(self.nodes[0], spendtx, i) spendtx = cltv_invalidate(self.nodes[0], spendtx, i)
spendtx.rehash()
expected_cltv_reject_reason = [ expected_cltv_reject_reason = [
"non-mandatory-script-verify-flag (Operation not valid with the current stack size)", "non-mandatory-script-verify-flag (Operation not valid with the current stack size)",
@ -191,7 +177,6 @@ class BIP65Test(BitcoinTestFramework):
self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted") self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted")
spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1) spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1)
spendtx.rehash()
block.vtx.pop(1) block.vtx.pop(1)
block.vtx.append(spendtx) block.vtx.append(spendtx)

View File

@ -17,6 +17,7 @@ from test_framework.messages import (
from test_framework.script import ( from test_framework.script import (
CScript, CScript,
OP_TRUE, OP_TRUE,
OP_NOP,
) )
from test_framework.util import ( from test_framework.util import (
assert_equal, assert_equal,
@ -26,11 +27,15 @@ from test_framework.util import (
class MiniWallet: class MiniWallet:
def __init__(self, test_node): def __init__(self, test_node, *, raw_script=False):
self._test_node = test_node self._test_node = test_node
self._utxos = [] self._utxos = []
self._address = ADDRESS_BCRT1_P2SH_OP_TRUE if raw_script:
self._scriptPubKey = hex_str_to_bytes(self._test_node.validateaddress(self._address)['scriptPubKey']) self._address = None
self._scriptPubKey = bytes(CScript([OP_TRUE]))
else:
self._address = ADDRESS_BCRT1_P2SH_OP_TRUE
self._scriptPubKey = hex_str_to_bytes(self._test_node.validateaddress(self._address)['scriptPubKey'])
def scan_blocks(self, *, start=1, num): def scan_blocks(self, *, start=1, num):
"""Scan the blocks for self._address outputs and add them to self._utxos""" """Scan the blocks for self._address outputs and add them to self._utxos"""
@ -47,7 +52,7 @@ class MiniWallet:
def generate(self, num_blocks): def generate(self, num_blocks):
"""Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list""" """Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list"""
blocks = self._test_node.generatetoaddress(num_blocks, self._address) blocks = self._test_node.generatetodescriptor(num_blocks, f'raw({self._scriptPubKey.hex()})')
for b in blocks: for b in blocks:
cb_tx = self._test_node.getblock(blockhash=b, verbosity=2)['tx'][0] cb_tx = self._test_node.getblock(blockhash=b, verbosity=2)['tx'][0]
self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']}) self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']})
@ -89,7 +94,11 @@ class MiniWallet:
tx = CTransaction() tx = CTransaction()
tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']))] tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']))]
tx.vout = [CTxOut(int(send_value * COIN), self._scriptPubKey)] tx.vout = [CTxOut(int(send_value * COIN), self._scriptPubKey)]
tx.vin[0].scriptSig = CScript([CScript([OP_TRUE])]) if not self._address:
# raw script
tx.vin[0].scriptSig = CScript([OP_NOP] * 24) # pad to identical size
else:
tx.vin[0].scriptSig = CScript([CScript([OP_TRUE])])
tx_hex = tx.serialize().hex() tx_hex = tx.serialize().hex()
tx_info = from_node.testmempoolaccept([tx_hex])[0] tx_info = from_node.testmempoolaccept([tx_hex])[0]
@ -97,7 +106,7 @@ class MiniWallet:
if mempool_valid: if mempool_valid:
assert_equal(len(tx_hex) // 2, vsize) assert_equal(len(tx_hex) // 2, vsize)
assert_equal(tx_info['fees']['base'], fee) assert_equal(tx_info['fees']['base'], fee)
return {'txid': tx_info['txid'], 'hex': tx_hex} return {'txid': tx_info['txid'], 'hex': tx_hex, 'tx': tx}
def sendrawtransaction(self, *, from_node, tx_hex): def sendrawtransaction(self, *, from_node, tx_hex):
from_node.sendrawtransaction(tx_hex) from_node.sendrawtransaction(tx_hex)