mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-05 14:06:27 -05:00
Merge bitcoin/bitcoin#24035: test: use MiniWallet for mempool_accept.py
aa8a65e4a8
test: use MiniWallet for mempool_accept.py (Sebastian Falbesoner)b24f6c6855
test: MiniWallet: support default `from_node` for creating txs (Sebastian Falbesoner)f30041c914
test: create txs with current `nVersion` (2) by default (Sebastian Falbesoner)2f79786822
test: refactor: add constant for sequence number `SEQUENCE_FINAL` (Sebastian Falbesoner) Pull request description: This PR enables one more of the non-wallet functional tests (mempool_accept.py) to be run even with the Bitcoin Core wallet disabled by using the MiniWallet instead, as proposed in #20078. It also includes some other minor changes that came up while working on the replacement: * [commit 1/4] replace magic number 0xffffffff for a tx's nSequence with a new constant `SEQUENCE_FINAL` * [commit 2/4] create `CTransaction` instances with the current nVersion=2 by default, in order to use BIP68 for tests * [commit 3/4] support default `from_node` parameter for creating txs (this is a stripped down version of PR #24025) ACKs for top commit: MarcoFalke: re-ACKaa8a65e4a8
📊 Tree-SHA512: 34cd085ea4147ad5bd3f3321c84204064ceb95f382664c7fe29062c1bbc79d9d9465c5e46d35e11c416f2f3cd46030c90a09b518c829c73ae40d060be5e4c9cb
This commit is contained in:
commit
807169e10b
16 changed files with 88 additions and 86 deletions
|
@ -28,6 +28,7 @@ from test_framework.messages import (
|
|||
CTxIn,
|
||||
CTxOut,
|
||||
MAX_MONEY,
|
||||
SEQUENCE_FINAL,
|
||||
)
|
||||
from test_framework.blocktools import create_tx_with_script, MAX_BLOCK_SIGOPS
|
||||
from test_framework.script import (
|
||||
|
@ -77,7 +78,7 @@ class BadTxTemplate:
|
|||
def __init__(self, *, spend_tx=None, spend_block=None):
|
||||
self.spend_tx = spend_block.vtx[0] if spend_block else spend_tx
|
||||
self.spend_avail = sum(o.nValue for o in self.spend_tx.vout)
|
||||
self.valid_txin = CTxIn(COutPoint(self.spend_tx.sha256, 0), b"", 0xffffffff)
|
||||
self.valid_txin = CTxIn(COutPoint(self.spend_tx.sha256, 0), b"", SEQUENCE_FINAL)
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_tx(self, *args, **kwargs):
|
||||
|
@ -137,7 +138,7 @@ class BadInputOutpointIndex(BadTxTemplate):
|
|||
bad_idx = num_indices + 100
|
||||
|
||||
tx = CTransaction()
|
||||
tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256, bad_idx), b"", 0xffffffff))
|
||||
tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256, bad_idx), b"", SEQUENCE_FINAL))
|
||||
tx.vout.append(CTxOut(0, basic_p2sh))
|
||||
tx.calc_sha256()
|
||||
return tx
|
||||
|
@ -175,7 +176,7 @@ class NonexistentInput(BadTxTemplate):
|
|||
|
||||
def get_tx(self):
|
||||
tx = CTransaction()
|
||||
tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256 + 1, 0), b"", 0xffffffff))
|
||||
tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256 + 1, 0), b"", SEQUENCE_FINAL))
|
||||
tx.vin.append(self.valid_txin)
|
||||
tx.vout.append(CTxOut(1, basic_p2sh))
|
||||
tx.calc_sha256()
|
||||
|
|
|
@ -23,6 +23,7 @@ from test_framework.messages import (
|
|||
CTxIn,
|
||||
CTxOut,
|
||||
MAX_BLOCK_WEIGHT,
|
||||
SEQUENCE_FINAL,
|
||||
uint256_from_compact,
|
||||
uint256_from_str,
|
||||
)
|
||||
|
@ -50,9 +51,13 @@ from test_framework.script_util import (
|
|||
script_to_p2sh_script,
|
||||
)
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_greater_than,
|
||||
)
|
||||
from data import invalid_txs
|
||||
|
||||
|
||||
# Use this class for tests that require behavior other than normal p2p behavior.
|
||||
# For now, it is used to serialize a bloated varint (b64).
|
||||
class CBrokenBlock(CBlock):
|
||||
|
@ -801,7 +806,7 @@ class FullBlockTest(BitcoinTestFramework):
|
|||
b58 = self.next_block(58, spend=out[17])
|
||||
tx = CTransaction()
|
||||
assert len(out[17].vout) < 42
|
||||
tx.vin.append(CTxIn(COutPoint(out[17].sha256, 42), CScript([OP_TRUE]), 0xffffffff))
|
||||
tx.vin.append(CTxIn(COutPoint(out[17].sha256, 42), CScript([OP_TRUE]), SEQUENCE_FINAL))
|
||||
tx.vout.append(CTxOut(0, b""))
|
||||
tx.calc_sha256()
|
||||
b58 = self.update_block(58, [tx])
|
||||
|
@ -876,7 +881,7 @@ class FullBlockTest(BitcoinTestFramework):
|
|||
tx.nLockTime = 0xffffffff # this locktime is non-final
|
||||
tx.vin.append(CTxIn(COutPoint(out[18].sha256, 0))) # don't set nSequence
|
||||
tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
|
||||
assert tx.vin[0].nSequence < 0xffffffff
|
||||
assert_greater_than(SEQUENCE_FINAL, tx.vin[0].nSequence)
|
||||
tx.calc_sha256()
|
||||
b62 = self.update_block(62, [tx])
|
||||
self.send_blocks([b62], success=False, reject_reason='bad-txns-nonfinal', reconnect=True)
|
||||
|
@ -1024,7 +1029,7 @@ class FullBlockTest(BitcoinTestFramework):
|
|||
bogus_tx = CTransaction()
|
||||
bogus_tx.sha256 = uint256_from_str(b"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c")
|
||||
tx = CTransaction()
|
||||
tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", 0xffffffff))
|
||||
tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", SEQUENCE_FINAL))
|
||||
tx.vout.append(CTxOut(1, b""))
|
||||
b70 = self.update_block(70, [tx])
|
||||
self.send_blocks([b70], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
|
||||
|
|
|
@ -13,6 +13,7 @@ from test_framework.blocktools import (
|
|||
)
|
||||
from test_framework.messages import (
|
||||
CTransaction,
|
||||
SEQUENCE_FINAL,
|
||||
msg_block,
|
||||
)
|
||||
from test_framework.p2p import P2PInterface
|
||||
|
@ -53,7 +54,7 @@ def cltv_invalidate(tx, failure_reason):
|
|||
# 3) the lock-time type (height vs. timestamp) of the top stack item and the
|
||||
# nLockTime field are not the same
|
||||
# 4) the top stack item is greater than the transaction's nLockTime field
|
||||
# 5) the nSequence field of the txin is 0xffffffff
|
||||
# 5) the nSequence field of the txin is 0xffffffff (SEQUENCE_FINAL)
|
||||
assert failure_reason in range(5)
|
||||
scheme = [
|
||||
# | Script to prepend to scriptSig | nSequence | nLockTime |
|
||||
|
@ -62,7 +63,7 @@ def cltv_invalidate(tx, failure_reason):
|
|||
[[OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP], None, None],
|
||||
[[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 1296688602], # timestamp of genesis block
|
||||
[[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 50],
|
||||
[[CScriptNum(50), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0xffffffff, 50],
|
||||
[[CScriptNum(50), OP_CHECKLOCKTIMEVERIFY, OP_DROP], SEQUENCE_FINAL, 50],
|
||||
][failure_reason]
|
||||
|
||||
cltv_modify_tx(tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
|
||||
|
@ -114,7 +115,7 @@ class BIP65Test(BitcoinTestFramework):
|
|||
# create one invalid tx per CLTV failure reason (5 in total) and collect them
|
||||
invalid_cltv_txs = []
|
||||
for i in range(5):
|
||||
spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
|
||||
spendtx = wallet.create_self_transfer()['tx']
|
||||
cltv_invalidate(spendtx, i)
|
||||
invalid_cltv_txs.append(spendtx)
|
||||
|
||||
|
@ -145,7 +146,7 @@ class BIP65Test(BitcoinTestFramework):
|
|||
|
||||
# create and test one invalid tx per CLTV failure reason (5 in total)
|
||||
for i in range(5):
|
||||
spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
|
||||
spendtx = wallet.create_self_transfer()['tx']
|
||||
cltv_invalidate(spendtx, i)
|
||||
|
||||
expected_cltv_reject_reason = [
|
||||
|
|
|
@ -104,7 +104,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
|
|||
|
||||
def create_self_transfer_from_utxo(self, input_tx):
|
||||
utxo = self.miniwallet.get_utxo(txid=input_tx.rehash(), mark_as_spent=False)
|
||||
tx = self.miniwallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo)['tx']
|
||||
tx = self.miniwallet.create_self_transfer(utxo_to_spend=utxo)['tx']
|
||||
return tx
|
||||
|
||||
def create_bip112special(self, input, txversion):
|
||||
|
|
|
@ -57,7 +57,7 @@ class BIP66Test(BitcoinTestFramework):
|
|||
|
||||
def create_tx(self, input_txid):
|
||||
utxo_to_spend = self.miniwallet.get_utxo(txid=input_txid, mark_as_spent=False)
|
||||
return self.miniwallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_to_spend)['tx']
|
||||
return self.miniwallet.create_self_transfer(utxo_to_spend=utxo_to_spend)['tx']
|
||||
|
||||
def test_dersig_info(self, *, is_active):
|
||||
assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip66'],
|
||||
|
|
|
@ -14,6 +14,7 @@ from test_framework.messages import (
|
|||
CTransaction,
|
||||
CTxIn,
|
||||
CTxOut,
|
||||
SEQUENCE_FINAL,
|
||||
)
|
||||
from test_framework.script import CScript, OP_DROP
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
|
@ -114,7 +115,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
|||
"""Simple doublespend"""
|
||||
# we use MiniWallet to create a transaction template with inputs correctly set,
|
||||
# and modify the output (amount, scriptPubKey) according to our needs
|
||||
tx_template = self.wallet.create_self_transfer(from_node=self.nodes[0])['tx']
|
||||
tx_template = self.wallet.create_self_transfer()['tx']
|
||||
|
||||
tx1a = deepcopy(tx_template)
|
||||
tx1a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
|
||||
|
@ -402,7 +403,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
|||
|
||||
# Create a non-opting in transaction
|
||||
tx1a = CTransaction()
|
||||
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0xffffffff)]
|
||||
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=SEQUENCE_FINAL)]
|
||||
tx1a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
|
||||
tx1a_hex = tx1a.serialize().hex()
|
||||
tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)
|
||||
|
@ -445,7 +446,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
|||
tx2a_txid = int(tx2a_txid, 16)
|
||||
|
||||
tx3a = CTransaction()
|
||||
tx3a.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0xffffffff),
|
||||
tx3a.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=SEQUENCE_FINAL),
|
||||
CTxIn(COutPoint(tx2a_txid, 0), nSequence=0xfffffffd)]
|
||||
tx3a.vout = [CTxOut(int(0.9 * COIN), CScript([b'c'])), CTxOut(int(0.9 * COIN), CScript([b'd']))]
|
||||
tx3a_hex = tx3a.serialize().hex()
|
||||
|
@ -562,7 +563,6 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
|||
assert_equal(True, self.nodes[0].getmempoolentry(optin_parent_tx['txid'])['bip125-replaceable'])
|
||||
|
||||
replacement_parent_tx = self.wallet.create_self_transfer(
|
||||
from_node=self.nodes[0],
|
||||
utxo_to_spend=confirmed_utxo,
|
||||
sequence=BIP125_SEQUENCE_NUMBER,
|
||||
fee_rate=Decimal('0.02'),
|
||||
|
@ -579,7 +579,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
|||
optout_child_tx = self.wallet.send_self_transfer(
|
||||
from_node=self.nodes[0],
|
||||
utxo_to_spend=parent_utxo,
|
||||
sequence=0xffffffff,
|
||||
sequence=SEQUENCE_FINAL,
|
||||
fee_rate=Decimal('0.01'),
|
||||
)
|
||||
|
||||
|
@ -587,9 +587,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
|||
assert_equal(True, self.nodes[0].getmempoolentry(optout_child_tx['txid'])['bip125-replaceable'])
|
||||
|
||||
replacement_child_tx = self.wallet.create_self_transfer(
|
||||
from_node=self.nodes[0],
|
||||
utxo_to_spend=parent_utxo,
|
||||
sequence=0xffffffff,
|
||||
sequence=SEQUENCE_FINAL,
|
||||
fee_rate=Decimal('0.02'),
|
||||
mempool_valid=False,
|
||||
)
|
||||
|
@ -608,7 +607,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
|||
replacement_parent_tx = self.wallet.send_self_transfer(
|
||||
from_node=self.nodes[0],
|
||||
utxo_to_spend=confirmed_utxo,
|
||||
sequence=0xffffffff,
|
||||
sequence=SEQUENCE_FINAL,
|
||||
fee_rate=Decimal('0.03'),
|
||||
)
|
||||
# Check that child is removed and update wallet utxo state
|
||||
|
|
|
@ -19,6 +19,7 @@ from test_framework.messages import (
|
|||
CTxIn,
|
||||
CTxInWitness,
|
||||
CTxOut,
|
||||
SEQUENCE_FINAL,
|
||||
)
|
||||
from test_framework.script import (
|
||||
ANNEX_TAG,
|
||||
|
@ -1516,7 +1517,7 @@ class TaprootTest(BitcoinTestFramework):
|
|||
assert self.nodes[1].getblockcount() == 0
|
||||
coinbase = CTransaction()
|
||||
coinbase.nVersion = 1
|
||||
coinbase.vin = [CTxIn(COutPoint(0, 0xffffffff), CScript([OP_1, OP_1]), 0xffffffff)]
|
||||
coinbase.vin = [CTxIn(COutPoint(0, 0xffffffff), CScript([OP_1, OP_1]), SEQUENCE_FINAL)]
|
||||
coinbase.vout = [CTxOut(5000000000, CScript([OP_1]))]
|
||||
coinbase.nLockTime = 0
|
||||
coinbase.rehash()
|
||||
|
@ -1604,7 +1605,7 @@ class TaprootTest(BitcoinTestFramework):
|
|||
val = 42000000 * (i + 7)
|
||||
tx = CTransaction()
|
||||
tx.nVersion = 1
|
||||
tx.vin = [CTxIn(COutPoint(lasttxid, i & 1), CScript([]), 0xffffffff)]
|
||||
tx.vin = [CTxIn(COutPoint(lasttxid, i & 1), CScript([]), SEQUENCE_FINAL)]
|
||||
tx.vout = [CTxOut(val, spk), CTxOut(amount - val, CScript([OP_1]))]
|
||||
if i & 1:
|
||||
tx.vout = list(reversed(tx.vout))
|
||||
|
@ -1664,7 +1665,7 @@ class TaprootTest(BitcoinTestFramework):
|
|||
tx.vin = []
|
||||
inputs = []
|
||||
input_spks = [tap_spks[0], tap_spks[1], old_spks[0], tap_spks[2], tap_spks[5], old_spks[2], tap_spks[6], tap_spks[3], tap_spks[4]]
|
||||
sequences = [0, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffffe, 0, 0, 0xffffffff, 0xffffffff]
|
||||
sequences = [0, SEQUENCE_FINAL, SEQUENCE_FINAL, 0xfffffffe, 0xfffffffe, 0, 0, SEQUENCE_FINAL, SEQUENCE_FINAL]
|
||||
hashtypes = [SIGHASH_SINGLE, SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, SIGHASH_ALL, SIGHASH_ALL, SIGHASH_DEFAULT, SIGHASH_ALL, SIGHASH_NONE, SIGHASH_NONE|SIGHASH_ANYONECANPAY, SIGHASH_ALL|SIGHASH_ANYONECANPAY]
|
||||
for i, spk in enumerate(input_spks):
|
||||
tx.vin.append(CTxIn(spend_info[spk]['prevout'], CScript(), sequences[i]))
|
||||
|
|
|
@ -69,8 +69,8 @@ class UTXOSetHashTest(BitcoinTestFramework):
|
|||
assert_equal(finalized[::-1].hex(), node_muhash)
|
||||
|
||||
self.log.info("Test deterministic UTXO set hash results")
|
||||
assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "221f245cf4c9010eeb7f5183d342c002ae6c1c27e98aa357dccb788c21d98049")
|
||||
assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "7c0890c68501f7630d36aeb3999dc924e63af084ae1bbfba11dd462144637635")
|
||||
assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "3a570529b4c32e77268de1f81b903c75cc2da53c48df0d125c1e697ba7c8c7b7")
|
||||
assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "a13e0e70eb8acc786549596e3bc154623f1a5a622ba2f70715f6773ec745f435")
|
||||
|
||||
def run_test(self):
|
||||
self.test_muhash_implementation()
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test mempool acceptance of raw transactions."""
|
||||
|
||||
from copy import deepcopy
|
||||
from decimal import Decimal
|
||||
import math
|
||||
|
||||
|
@ -17,6 +18,7 @@ from test_framework.messages import (
|
|||
CTxOut,
|
||||
MAX_BLOCK_WEIGHT,
|
||||
MAX_MONEY,
|
||||
SEQUENCE_FINAL,
|
||||
tx_from_hex,
|
||||
)
|
||||
from test_framework.script import (
|
||||
|
@ -33,6 +35,7 @@ from test_framework.util import (
|
|||
assert_equal,
|
||||
assert_raises_rpc_error,
|
||||
)
|
||||
from test_framework.wallet import MiniWallet
|
||||
|
||||
|
||||
class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
|
@ -43,9 +46,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
]] * self.num_nodes
|
||||
self.supports_cli = False
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def check_mempool_result(self, result_expected, *args, **kwargs):
|
||||
"""Wrapper to check result of testmempoolaccept on node_0's mempool"""
|
||||
result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)
|
||||
|
@ -56,12 +56,13 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
|
||||
def run_test(self):
|
||||
node = self.nodes[0]
|
||||
self.wallet = MiniWallet(node)
|
||||
self.wallet.rescan_utxos()
|
||||
|
||||
self.log.info('Start with empty mempool, and 200 blocks')
|
||||
self.mempool_size = 0
|
||||
assert_equal(node.getblockcount(), 200)
|
||||
assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
|
||||
coins = node.listunspent()
|
||||
|
||||
self.log.info('Should not accept garbage to testmempoolaccept')
|
||||
assert_raises_rpc_error(-3, 'Expected type array, got string', lambda: node.testmempoolaccept(rawtxs='ff00baar'))
|
||||
|
@ -70,12 +71,12 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
assert_raises_rpc_error(-22, 'TX decode failed', lambda: node.testmempoolaccept(rawtxs=['ff00baar']))
|
||||
|
||||
self.log.info('A transaction already in the blockchain')
|
||||
coin = coins.pop() # Pick a random coin(base) to spend
|
||||
raw_tx_in_block = node.signrawtransactionwithwallet(node.createrawtransaction(
|
||||
inputs=[{'txid': coin['txid'], 'vout': coin['vout']}],
|
||||
outputs=[{node.getnewaddress(): 0.3}, {node.getnewaddress(): 49}],
|
||||
))['hex']
|
||||
txid_in_block = node.sendrawtransaction(hexstring=raw_tx_in_block, maxfeerate=0)
|
||||
tx = self.wallet.create_self_transfer()['tx'] # Pick a random coin(base) to spend
|
||||
tx.vout.append(deepcopy(tx.vout[0]))
|
||||
tx.vout[0].nValue = int(0.3 * COIN)
|
||||
tx.vout[1].nValue = int(49 * COIN)
|
||||
raw_tx_in_block = tx.serialize().hex()
|
||||
txid_in_block = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_in_block, maxfeerate=0)
|
||||
self.generate(node, 1)
|
||||
self.mempool_size = 0
|
||||
self.check_mempool_result(
|
||||
|
@ -85,11 +86,10 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
|
||||
self.log.info('A transaction not in the mempool')
|
||||
fee = Decimal('0.000007')
|
||||
raw_tx_0 = node.signrawtransactionwithwallet(node.createrawtransaction(
|
||||
inputs=[{"txid": txid_in_block, "vout": 0, "sequence": BIP125_SEQUENCE_NUMBER}], # RBF is used later
|
||||
outputs=[{node.getnewaddress(): Decimal('0.3') - fee}],
|
||||
))['hex']
|
||||
tx = tx_from_hex(raw_tx_0)
|
||||
utxo_to_spend = self.wallet.get_utxo(txid=txid_in_block) # use 0.3 BTC UTXO
|
||||
tx = self.wallet.create_self_transfer(utxo_to_spend=utxo_to_spend, sequence=BIP125_SEQUENCE_NUMBER)['tx']
|
||||
tx.vout[0].nValue = int((Decimal('0.3') - fee) * COIN)
|
||||
raw_tx_0 = tx.serialize().hex()
|
||||
txid_0 = tx.rehash()
|
||||
self.check_mempool_result(
|
||||
result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': fee}}],
|
||||
|
@ -97,15 +97,15 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
)
|
||||
|
||||
self.log.info('A final transaction not in the mempool')
|
||||
coin = coins.pop() # Pick a random coin(base) to spend
|
||||
output_amount = Decimal('0.025')
|
||||
raw_tx_final = node.signrawtransactionwithwallet(node.createrawtransaction(
|
||||
inputs=[{'txid': coin['txid'], 'vout': coin['vout'], "sequence": 0xffffffff}], # SEQUENCE_FINAL
|
||||
outputs=[{node.getnewaddress(): output_amount}],
|
||||
tx = self.wallet.create_self_transfer(
|
||||
sequence=SEQUENCE_FINAL,
|
||||
locktime=node.getblockcount() + 2000, # Can be anything
|
||||
))['hex']
|
||||
)['tx']
|
||||
tx.vout[0].nValue = int(output_amount * COIN)
|
||||
raw_tx_final = tx.serialize().hex()
|
||||
tx = tx_from_hex(raw_tx_final)
|
||||
fee_expected = coin['amount'] - output_amount
|
||||
fee_expected = Decimal('50.0') - output_amount
|
||||
self.check_mempool_result(
|
||||
result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': fee_expected}}],
|
||||
rawtxs=[tx.serialize().hex()],
|
||||
|
@ -126,8 +126,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
tx = tx_from_hex(raw_tx_0)
|
||||
tx.vout[0].nValue -= int(fee * COIN) # Double the fee
|
||||
tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER + 1 # Now, opt out of RBF
|
||||
raw_tx_0 = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
|
||||
tx = tx_from_hex(raw_tx_0)
|
||||
raw_tx_0 = tx.serialize().hex()
|
||||
txid_0 = tx.rehash()
|
||||
self.check_mempool_result(
|
||||
result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': (2 * fee)}}],
|
||||
|
@ -140,7 +139,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
# take original raw_tx_0
|
||||
tx = tx_from_hex(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': 'txn-mempool-conflict'}],
|
||||
rawtxs=[tx.serialize().hex()],
|
||||
|
@ -150,7 +148,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
self.log.info('A transaction with missing inputs, that never existed')
|
||||
tx = tx_from_hex(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()],
|
||||
|
@ -159,17 +156,17 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
self.log.info('A transaction with missing inputs, that existed once in the past')
|
||||
tx = tx_from_hex(raw_tx_0)
|
||||
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
|
||||
raw_tx_1 = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
|
||||
raw_tx_1 = tx.serialize().hex()
|
||||
txid_1 = node.sendrawtransaction(hexstring=raw_tx_1, maxfeerate=0)
|
||||
# Now spend both to "clearly hide" the outputs, ie. remove the coins from the utxo set by spending them
|
||||
raw_tx_spend_both = node.signrawtransactionwithwallet(node.createrawtransaction(
|
||||
inputs=[
|
||||
{'txid': txid_0, 'vout': 0},
|
||||
{'txid': txid_1, 'vout': 0},
|
||||
],
|
||||
outputs=[{node.getnewaddress(): 0.1}]
|
||||
))['hex']
|
||||
txid_spend_both = node.sendrawtransaction(hexstring=raw_tx_spend_both, maxfeerate=0)
|
||||
tx = self.wallet.create_self_transfer()['tx']
|
||||
tx.vin.append(deepcopy(tx.vin[0]))
|
||||
tx.wit.vtxinwit.append(deepcopy(tx.wit.vtxinwit[0]))
|
||||
tx.vin[0].prevout = COutPoint(hash=int(txid_0, 16), n=0)
|
||||
tx.vin[1].prevout = COutPoint(hash=int(txid_1, 16), n=0)
|
||||
tx.vout[0].nValue = int(0.1 * COIN)
|
||||
raw_tx_spend_both = tx.serialize().hex()
|
||||
txid_spend_both = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_spend_both, maxfeerate=0)
|
||||
self.generate(node, 1)
|
||||
self.mempool_size = 0
|
||||
# Now see if we can add the coins back to the utxo set by sending the exact txs again
|
||||
|
@ -182,12 +179,11 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
rawtxs=[raw_tx_1],
|
||||
)
|
||||
|
||||
self.log.info('Create a signed "reference" tx for later use')
|
||||
raw_tx_reference = node.signrawtransactionwithwallet(node.createrawtransaction(
|
||||
inputs=[{'txid': txid_spend_both, 'vout': 0}],
|
||||
outputs=[{node.getnewaddress(): 0.05}],
|
||||
))['hex']
|
||||
tx = tx_from_hex(raw_tx_reference)
|
||||
self.log.info('Create a "reference" tx for later use')
|
||||
utxo_to_spend = self.wallet.get_utxo(txid=txid_spend_both)
|
||||
tx = self.wallet.create_self_transfer(utxo_to_spend=utxo_to_spend, sequence=SEQUENCE_FINAL)['tx']
|
||||
tx.vout[0].nValue = int(0.05 * COIN)
|
||||
raw_tx_reference = tx.serialize().hex()
|
||||
# Reference tx should be valid on itself
|
||||
self.check_mempool_result(
|
||||
result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal('0.1') - Decimal('0.05')}}],
|
||||
|
@ -198,8 +194,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
self.log.info('A transaction with no outputs')
|
||||
tx = tx_from_hex(raw_tx_reference)
|
||||
tx.vout = []
|
||||
# Skip re-signing the transaction for context independent checks from now on
|
||||
# tx = tx_from_hex(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])
|
||||
self.check_mempool_result(
|
||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-empty'}],
|
||||
rawtxs=[tx.serialize().hex()],
|
||||
|
@ -256,7 +250,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
)
|
||||
|
||||
self.log.info('A coinbase transaction')
|
||||
# Pick the input of the first tx we signed, so it has to be a coinbase tx
|
||||
# Pick the input of the first tx we created, 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 = tx_from_hex(raw_tx_coinbase_spent)
|
||||
self.check_mempool_result(
|
||||
|
@ -333,7 +327,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
|||
self.log.info('A transaction that is locked by BIP68 sequence logic')
|
||||
tx = tx_from_hex(raw_tx_reference)
|
||||
tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one
|
||||
# Can skip re-signing the tx because of early rejection
|
||||
self.check_mempool_result(
|
||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-BIP68-final'}],
|
||||
rawtxs=[tx.serialize().hex()],
|
||||
|
|
|
@ -45,14 +45,13 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
|
|||
utxo_2 = wallet.get_utxo(txid=coinbase_txids[2])
|
||||
utxo_3 = wallet.get_utxo(txid=coinbase_txids[3])
|
||||
self.log.info("Create three transactions spending from coinbase utxos: spend_1, spend_2, spend_3")
|
||||
spend_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_1)
|
||||
spend_2 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_2)
|
||||
spend_3 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_3)
|
||||
spend_1 = wallet.create_self_transfer(utxo_to_spend=utxo_1)
|
||||
spend_2 = wallet.create_self_transfer(utxo_to_spend=utxo_2)
|
||||
spend_3 = wallet.create_self_transfer(utxo_to_spend=utxo_3)
|
||||
|
||||
self.log.info("Create another transaction which is time-locked to two blocks in the future")
|
||||
utxo = wallet.get_utxo(txid=coinbase_txids[0])
|
||||
timelock_tx = wallet.create_self_transfer(
|
||||
from_node=self.nodes[0],
|
||||
utxo_to_spend=utxo,
|
||||
mempool_valid=False,
|
||||
locktime=self.nodes[0].getblockcount() + 2
|
||||
|
@ -71,9 +70,9 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
|
|||
|
||||
self.log.info("Create spend_2_1 and spend_3_1")
|
||||
spend_2_utxo = wallet.get_utxo(txid=spend_2['txid'])
|
||||
spend_2_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=spend_2_utxo)
|
||||
spend_2_1 = wallet.create_self_transfer(utxo_to_spend=spend_2_utxo)
|
||||
spend_3_utxo = wallet.get_utxo(txid=spend_3['txid'])
|
||||
spend_3_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=spend_3_utxo)
|
||||
spend_3_1 = wallet.create_self_transfer(utxo_to_spend=spend_3_utxo)
|
||||
|
||||
self.log.info("Broadcast and mine spend_3_1")
|
||||
spend_3_1_id = self.nodes[0].sendrawtransaction(spend_3_1['hex'])
|
||||
|
|
|
@ -40,7 +40,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
|
|||
spend_mature_id = wallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_mature)["txid"]
|
||||
|
||||
# other coinbase should be too immature to spend
|
||||
immature_tx = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_immature, mempool_valid=False)
|
||||
immature_tx = wallet.create_self_transfer(utxo_to_spend=utxo_immature, mempool_valid=False)
|
||||
assert_raises_rpc_error(-26,
|
||||
"bad-txns-premature-spend-of-coinbase",
|
||||
lambda: self.nodes[0].sendrawtransaction(immature_tx['hex']))
|
||||
|
|
|
@ -102,7 +102,7 @@ class P2PBlocksOnly(BitcoinTestFramework):
|
|||
|
||||
def check_p2p_tx_violation(self):
|
||||
self.log.info('Check that txs from P2P are rejected and result in disconnect')
|
||||
spendtx = self.miniwallet.create_self_transfer(from_node=self.nodes[0])
|
||||
spendtx = self.miniwallet.create_self_transfer()
|
||||
|
||||
with self.nodes[0].assert_debug_log(['transaction sent in violation of protocol peer=0']):
|
||||
self.nodes[0].p2ps[0].send_message(msg_tx(spendtx['tx']))
|
||||
|
|
|
@ -63,7 +63,7 @@ class GenerateBlockTest(BitcoinTestFramework):
|
|||
assert_equal(block['tx'][1], txid)
|
||||
|
||||
self.log.info('Generate block with raw tx')
|
||||
rawtx = miniwallet.create_self_transfer(from_node=node)['hex']
|
||||
rawtx = miniwallet.create_self_transfer()['hex']
|
||||
hash = self.generateblock(node, address, [rawtx])['hash']
|
||||
|
||||
block = node.getblock(hash, 1)
|
||||
|
@ -74,7 +74,7 @@ class GenerateBlockTest(BitcoinTestFramework):
|
|||
self.log.info('Fail to generate block with out of order txs')
|
||||
txid1 = miniwallet.send_self_transfer(from_node=node)['txid']
|
||||
utxo1 = miniwallet.get_utxo(txid=txid1)
|
||||
rawtx2 = miniwallet.create_self_transfer(from_node=node, utxo_to_spend=utxo1)['hex']
|
||||
rawtx2 = miniwallet.create_self_transfer(utxo_to_spend=utxo1)['hex']
|
||||
assert_raises_rpc_error(-25, 'TestBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [rawtx2, txid1])
|
||||
|
||||
self.log.info('Fail to generate block with txid not in mempool')
|
||||
|
|
|
@ -22,6 +22,7 @@ from .messages import (
|
|||
CTxIn,
|
||||
CTxInWitness,
|
||||
CTxOut,
|
||||
SEQUENCE_FINAL,
|
||||
hash256,
|
||||
ser_uint256,
|
||||
tx_from_hex,
|
||||
|
@ -128,7 +129,7 @@ def create_coinbase(height, pubkey=None, extra_output_script=None, fees=0, nValu
|
|||
If extra_output_script is given, make a 0-value output to that
|
||||
script. This is useful to pad block weight/sigops as needed. """
|
||||
coinbase = CTransaction()
|
||||
coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), 0xffffffff))
|
||||
coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), SEQUENCE_FINAL))
|
||||
coinbaseoutput = CTxOut()
|
||||
coinbaseoutput.nValue = nValue * COIN
|
||||
if nValue == 50:
|
||||
|
@ -156,7 +157,7 @@ def create_tx_with_script(prevtx, n, script_sig=b"", *, amount, script_pub_key=C
|
|||
"""
|
||||
tx = CTransaction()
|
||||
assert n < len(prevtx.vout)
|
||||
tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), script_sig, 0xffffffff))
|
||||
tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), script_sig, SEQUENCE_FINAL))
|
||||
tx.vout.append(CTxOut(amount, script_pub_key))
|
||||
tx.calc_sha256()
|
||||
return tx
|
||||
|
|
|
@ -40,6 +40,7 @@ COIN = 100000000 # 1 btc in satoshis
|
|||
MAX_MONEY = 21000000 * COIN
|
||||
|
||||
BIP125_SEQUENCE_NUMBER = 0xfffffffd # Sequence number that is rbf-opt-in (BIP 125) and csv-opt-out (BIP 68)
|
||||
SEQUENCE_FINAL = 0xffffffff # Sequence number that disables nLockTime if set for every input of a tx
|
||||
|
||||
MAX_PROTOCOL_MESSAGE_LENGTH = 4000000 # Maximum length of incoming protocol messages
|
||||
MAX_HEADERS_RESULTS = 2000 # Number of headers sent in one getheaders result
|
||||
|
@ -508,7 +509,7 @@ class CTransaction:
|
|||
|
||||
def __init__(self, tx=None):
|
||||
if tx is None:
|
||||
self.nVersion = 1
|
||||
self.nVersion = 2
|
||||
self.vin = []
|
||||
self.vout = []
|
||||
self.wit = CTxWitness()
|
||||
|
|
|
@ -179,8 +179,9 @@ class MiniWallet:
|
|||
txid = self.sendrawtransaction(from_node=from_node, tx_hex=tx.serialize().hex())
|
||||
return txid, 1
|
||||
|
||||
def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True, locktime=0, sequence=0):
|
||||
def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node=None, utxo_to_spend=None, mempool_valid=True, locktime=0, sequence=0):
|
||||
"""Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
|
||||
from_node = from_node or self._test_node
|
||||
utxo_to_spend = utxo_to_spend or self.get_utxo()
|
||||
if self._priv_key is None:
|
||||
vsize = Decimal(104) # anyone-can-spend
|
||||
|
@ -213,8 +214,8 @@ class MiniWallet:
|
|||
assert_equal(tx_info['fees']['base'], utxo_to_spend['value'] - Decimal(send_value) / COIN)
|
||||
return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], 'hex': tx_hex, 'tx': tx}
|
||||
|
||||
def sendrawtransaction(self, *, from_node, tx_hex):
|
||||
txid = from_node.sendrawtransaction(tx_hex)
|
||||
def sendrawtransaction(self, *, from_node, tx_hex, **kwargs):
|
||||
txid = from_node.sendrawtransaction(hexstring=tx_hex, **kwargs)
|
||||
self.scan_tx(from_node.decoderawtransaction(tx_hex))
|
||||
return txid
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue