Skip to content

Commit

Permalink
merge bitcoin#21754: Run feature_cltv with MiniWallet
Browse files Browse the repository at this point in the history
Co-authored-by: UdjinM6 <[email protected]>
  • Loading branch information
kwvg and UdjinM6 committed Jul 23, 2024
1 parent bd75014 commit 8b7ea28
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 31 deletions.
35 changes: 10 additions & 25 deletions test/functional/feature_cltv.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from test_framework.blocktools import (
create_block,
create_coinbase,
create_transaction,
)
from test_framework.messages import (
CTransaction,
Expand All @@ -29,10 +28,8 @@
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
hex_str_to_bytes,
)

from io import BytesIO
from test_framework.wallet import MiniWallet

CLTV_HEIGHT = 1351

Expand All @@ -41,19 +38,14 @@
# 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
def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None):
assert_equal(len(tx.vin), 1)
if nsequence is not None:
tx.vin[0].nSequence = nsequence
tx.nLockTime = nlocktime

# Need to re-sign, since nSequence and nLockTime changed
signed_result = node.signrawtransactionwithwallet(tx.serialize().hex())
new_tx = CTransaction()
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
tx.vin[0].scriptSig = CScript(prepend_scriptsig + list(CScript(tx.vin[0].scriptSig)))
tx.rehash()
return tx


def cltv_invalidate(node, tx, failure_reason):
Expand Down Expand Up @@ -108,27 +100,23 @@ def test_cltv_info(self, *, is_active):
},
)

def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

def run_test(self):
peer = self.nodes[0].add_p2p_connection(P2PInterface())
wallet = MiniWallet(self.nodes[0], raw_script=True)

self.test_cltv_info(is_active=False)

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)]
self.nodeaddress = self.nodes[0].getnewaddress()
wallet.generate(10)
self.nodes[0].generate(CLTV_HEIGHT - 2 - 10)

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
invalid_ctlv_txs = []
for i in range(5):
spendtx = create_transaction(self.nodes[0], self.coinbase_txids[i],
self.nodeaddress, amount=1.0)
spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
spendtx = cltv_invalidate(self.nodes[0], spendtx, i)
spendtx.rehash()
invalid_ctlv_txs.append(spendtx)

tip = self.nodes[0].getbestblockhash()
Expand Down Expand Up @@ -162,10 +150,8 @@ def run_test(self):

# create and test one invalid tx per CLTV failure reason (5 in total)
for i in range(5):
spendtx = create_transaction(self.nodes[0], self.coinbase_txids[10+i],
self.nodeaddress, amount=1.0)
spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
spendtx = cltv_invalidate(self.nodes[0], spendtx, i)
spendtx.rehash()

expected_cltv_reject_reason = [
"non-mandatory-script-verify-flag (Operation not valid with the current stack size)",
Expand All @@ -191,7 +177,6 @@ def run_test(self):

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.rehash()

block.vtx.pop(1)
block.vtx.append(spendtx)
Expand Down
21 changes: 15 additions & 6 deletions test/functional/test_framework/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from test_framework.script import (
CScript,
OP_TRUE,
OP_NOP,
)
from test_framework.util import (
assert_equal,
Expand All @@ -26,11 +27,15 @@


class MiniWallet:
def __init__(self, test_node):
def __init__(self, test_node, *, raw_script=False):
self._test_node = test_node
self._utxos = []
self._address = ADDRESS_BCRT1_P2SH_OP_TRUE
self._scriptPubKey = hex_str_to_bytes(self._test_node.validateaddress(self._address)['scriptPubKey'])
if raw_script:
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):
"""Scan the blocks for self._address outputs and add them to self._utxos"""
Expand All @@ -47,7 +52,7 @@ def scan_tx(self, tx):

def generate(self, num_blocks):
"""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:
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']})
Expand Down Expand Up @@ -89,15 +94,19 @@ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_
tx = CTransaction()
tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']))]
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_info = from_node.testmempoolaccept([tx_hex])[0]
assert_equal(mempool_valid, tx_info['allowed'])
if mempool_valid:
assert_equal(len(tx_hex) // 2, vsize)
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):
from_node.sendrawtransaction(tx_hex)
Expand Down

0 comments on commit 8b7ea28

Please sign in to comment.