Compare commits

...

4 commits

Author SHA1 Message Date
Peter Todd
47e713ea5a
Remove old comment to datacarriersize argument 2025-04-28 20:26:20 +00:00
Peter Todd
8fd09d622d
Add more OP_RETURN mempool acceptance functional tests
Credit: Sjors Provoost and Antoine Poinsot
2025-04-28 20:22:59 +00:00
Peter Todd
47f9565c15
Move node restart in test to better place.
Needed because the previous test used -persistmempool=0 and we need to
forget about the transaction it created.

Credit: Sjors Provoost
2025-04-28 20:16:50 +00:00
Peter Todd
b420376aef
Add comment to test noting when OP_RETURN limit was removed 2025-04-28 20:15:08 +00:00
4 changed files with 55 additions and 4 deletions

View file

@ -859,6 +859,9 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
CheckIsNotStandard(t, "scriptpubkey");
// TxoutType::NULL_DATA
//
// Until v30 OP_RETURN was limited to 83 bytes (80 bytes of data, +1 for
// OP_RETURN, +2 for the pushdata opcodes). Here we test with 84 bytes.
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"_hex;
BOOST_CHECK_EQUAL(84, t.vout[0].scriptPubKey.size());
CheckIsStandard(t);

View file

@ -9,6 +9,7 @@ from decimal import Decimal
import math
from test_framework.test_framework import BitcoinTestFramework
from test_framework.blocktools import MAX_STANDARD_TX_WEIGHT
from test_framework.messages import (
MAX_BIP125_RBF_SEQUENCE,
COIN,
@ -327,6 +328,52 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
rawtxs=[tx.serialize().hex()],
)
# OP_RETURN followed by non-push
tx = tx_from_hex(raw_tx_reference)
tx.vout[0].scriptPubKey = CScript([OP_RETURN, OP_HASH160])
tx.vout = [tx.vout[0]] * 2
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptpubkey'}],
rawtxs=[tx.serialize().hex()],
)
# Multiple OP_RETURN and more than 83 bytes are standard since v30
tx = tx_from_hex(raw_tx_reference)
tx.vout.append(CTxOut(0, CScript([OP_RETURN, b'\xff'])))
tx.vout.append(CTxOut(0, CScript([OP_RETURN, b'\xff' * 90])))
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': Decimal('0.05')}}],
rawtxs=[tx.serialize().hex()],
maxfeerate=0
)
self.log.info("A transaction with several OP_RETURN outputs.")
tx = tx_from_hex(raw_tx_reference)
op_return_count = 42
tx.vout[0].nValue = int(tx.vout[0].nValue / op_return_count)
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
tx.vout = [tx.vout[0]] * op_return_count
self.check_mempool_result(
result_expected=[{"txid": tx.rehash(), "allowed": True, "vsize": tx.get_vsize(), "fees": {"base": Decimal("0.05000026")}}],
rawtxs=[tx.serialize().hex()],
)
self.log.info("A transaction with an OP_RETUN output that bumps into the max standardness tx size.")
tx = tx_from_hex(raw_tx_reference)
tx.vout[0].scriptPubKey = CScript([OP_RETURN])
data_len = int(MAX_STANDARD_TX_WEIGHT / 4) - tx.get_vsize() - 5 - 4 # -5 for PUSHDATA4 and -4 for script size
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b"\xff" * (data_len)])
self.check_mempool_result(
result_expected=[{"txid": tx.rehash(), "allowed": True, "vsize": tx.get_vsize(), "fees": {"base": Decimal("0.1") - Decimal("0.05")}}],
rawtxs=[tx.serialize().hex()],
)
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b"\xff" * (data_len + 1)])
self.check_mempool_result(
result_expected=[{"txid": tx.rehash(), "allowed": False, "reject-reason": "tx-size"}],
rawtxs=[tx.serialize().hex()],
)
self.log.info('A timelocked transaction')
tx = tx_from_hex(raw_tx_reference)
tx.vin[0].nSequence -= 1 # Should be non-max, so locktime is not ignored

View file

@ -186,6 +186,9 @@ class MiningTest(BitcoinTestFramework):
assert tx_below_min_feerate['txid'] not in block_template_txids
assert tx_below_min_feerate['txid'] not in block_txids
# Restart node to clear mempool for the next test
self.restart_node(0)
def test_timewarp(self):
self.log.info("Test timewarp attack mitigation (BIP94)")
node = self.nodes[0]
@ -279,11 +282,9 @@ class MiningTest(BitcoinTestFramework):
def test_block_max_weight(self):
self.log.info("Testing default and custom -blockmaxweight startup options.")
# Restart the node
LARGE_TXS_COUNT = 10
LARGE_VSIZE = int(((MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT) / WITNESS_SCALE_FACTOR) / LARGE_TXS_COUNT)
HIGH_FEERATE = Decimal("0.0003")
self.restart_node(0)
# Ensure the mempool is empty
assert_equal(len(self.nodes[0].getrawmempool()), 0)

View file

@ -41,8 +41,8 @@ def fill_mempool(test_framework, node, *, tx_sync_fun=None):
"""Fill mempool until eviction.
Allows for simpler testing of scenarios with floating mempoolminfee > minrelay
Requires -datacarriersize=100000 and -maxmempool=5 and assumes -minrelaytxfee
is 1 sat/vbyte.
Requires -maxmempool=5 and assumes -minrelaytxfee is 1 sat/vbyte.
To avoid unintentional tx dependencies, the mempool filling txs are created with a
tagged ephemeral miniwallet instance.
"""