Merge bitcoin/bitcoin#21754: test: Run feature_cltv with MiniWallet

fa066f1b66 test: Run feature_cltv with MiniWallet (MarcoFalke)
fa5591d38c test: Hide tx rehash in helper (MarcoFalke)
fa5f938cfe test: Remove new_tx reference (MarcoFalke)

Pull request description:

  Allows to run the test even with no wallet compiled in

ACKs for top commit:
  theStack:
    ACK fa066f1b66 💽

Tree-SHA512: 3f659a178ba3ee0baffd70fddf8b8a68e5551d85626c7f254b234d7f75e6a16430a32a7952037db358b579f045b4d296b46156f72e5d226f3e80334dc635ca10
This commit is contained in:
MarcoFalke 2021-05-05 08:45:01 +02:00
commit 779aaa7f03
No known key found for this signature in database
GPG Key ID: CE2B75697E69A548
2 changed files with 27 additions and 36 deletions

View File

@ -11,11 +11,9 @@ 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,
ToHex,
msg_block, msg_block,
) )
from test_framework.p2p import P2PInterface from test_framework.p2p import P2PInterface
@ -27,12 +25,8 @@ from test_framework.script import (
OP_DROP, OP_DROP,
) )
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import ( from test_framework.util import assert_equal
assert_equal, from test_framework.wallet import MiniWallet
hex_str_to_bytes,
)
from io import BytesIO
CLTV_HEIGHT = 1351 CLTV_HEIGHT = 1351
@ -41,19 +35,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(ToHex(tx)) 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):
@ -98,9 +87,6 @@ class BIP65Test(BitcoinTestFramework):
self.setup_clean_chain = True self.setup_clean_chain = True
self.rpc_timeout = 480 self.rpc_timeout = 480
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def test_cltv_info(self, *, is_active): def test_cltv_info(self, *, is_active):
assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip65'], { assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip65'], {
"active": is_active, "active": is_active,
@ -111,22 +97,21 @@ class BIP65Test(BitcoinTestFramework):
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()
@ -160,10 +145,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)",
@ -197,7 +180,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_P2WSH_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_P2WSH_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,8 +94,12 @@ 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.wit.vtxinwit = [CTxInWitness()] if not self._address:
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])] # raw script
tx.vin[0].scriptSig = CScript([OP_NOP] * 35) # pad to identical size
else:
tx.wit.vtxinwit = [CTxInWitness()]
tx.wit.vtxinwit[0].scriptWitness.stack = [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]
@ -98,7 +107,7 @@ class MiniWallet:
if mempool_valid: if mempool_valid:
assert_equal(tx_info['vsize'], vsize) assert_equal(tx_info['vsize'], vsize)
assert_equal(tx_info['fees']['base'], fee) assert_equal(tx_info['fees']['base'], fee)
return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], 'hex': tx_hex} return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], '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)