Skip to content

Commit 97d53ff

Browse files
committed
Add functional test to catch too large vsize packages
1 parent 83621b8 commit 97d53ff

File tree

1 file changed

+48
-1
lines changed

1 file changed

+48
-1
lines changed

test/functional/mempool_sigoplimit.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test sigop limit mempool policy (`-bytespersigop` parameter)"""
6+
from decimal import Decimal
67
from math import ceil
78

89
from test_framework.messages import (
@@ -25,16 +26,18 @@
2526
OP_TRUE,
2627
)
2728
from test_framework.script_util import (
29+
keys_to_multisig_script,
2830
script_to_p2wsh_script,
2931
)
3032
from test_framework.test_framework import BitcoinTestFramework
3133
from test_framework.util import (
3234
assert_equal,
3335
assert_greater_than,
3436
assert_greater_than_or_equal,
37+
assert_raises_rpc_error,
3538
)
3639
from test_framework.wallet import MiniWallet
37-
40+
from test_framework.wallet_util import generate_keypair
3841

3942
DEFAULT_BYTES_PER_SIGOP = 20 # default setting
4043

@@ -133,6 +136,48 @@ def test_sigops_limit(self, bytes_per_sigop, num_sigops):
133136
assert_equal(entry_parent['descendantcount'], 2)
134137
assert_equal(entry_parent['descendantsize'], parent_tx.get_vsize() + sigop_equivalent_vsize)
135138

139+
def test_sigops_package(self):
140+
# Make a 2-transaction package which fails vbyte checks even though
141+
# separately they would work.
142+
self.restart_node(0, extra_args=["-bytespersigop=5000"] + self.extra_args[0])
143+
144+
_, pubkey = generate_keypair()
145+
amount_for_bare = 50000
146+
tx_parent_dict = self.wallet.create_self_transfer(fee=Decimal("3"))
147+
tx_parent_utxo = tx_parent_dict["new_utxo"]
148+
tx_parent = tx_parent_dict["tx"]
149+
tx_parent.vout.append(CTxOut(amount_for_bare, keys_to_multisig_script([pubkey], k=1)))
150+
tx_parent.vout[0].nValue -= amount_for_bare
151+
tx_parent.calc_sha256()
152+
tx_parent_utxo["txid"] = tx_parent.hash
153+
tx_parent_utxo["value"] -= Decimal("0.00005000")
154+
155+
tx_child_dict = self.wallet.create_self_transfer(utxo_to_spend=tx_parent_utxo, fee=Decimal("3"))
156+
tx_child_utxo = tx_child_dict["new_utxo"]
157+
tx_child = tx_child_dict["tx"]
158+
tx_child.vout.append(CTxOut(amount_for_bare, keys_to_multisig_script([pubkey], k=1)))
159+
tx_child.vout[0].nValue -= amount_for_bare
160+
tx_child.calc_sha256()
161+
tx_child_utxo["txid"] = tx_child.hash
162+
tx_child_utxo["value"] -= Decimal("0.00005000")
163+
164+
# Separately, the parent tx is ok
165+
parent_individual_testres = self.nodes[0].testmempoolaccept([tx_parent.serialize().hex()])[0]
166+
assert parent_individual_testres["allowed"]
167+
# Multisig is counted as MAX_PUBKEYS_PER_MULTISIG = 20 sigops
168+
assert_equal(parent_individual_testres["vsize"], 5000 * 20)
169+
170+
# But together, it's exceeding limits
171+
packet_test = self.nodes[0].testmempoolaccept([tx_parent.serialize().hex(), tx_child.serialize().hex()])
172+
assert_equal([x["package-error"] for x in packet_test], ["package-mempool-limits", "package-mempool-limits"])
173+
174+
# When we actually try to submit, the parent makes it into the mempool, but the child would exceed ancestor vsize limits
175+
assert_raises_rpc_error(-26, "too-long-mempool-chain", self.nodes[0].submitpackage, [tx_parent.serialize().hex(), tx_child.serialize().hex()])
176+
assert tx_parent.rehash() in self.nodes[0].getrawmempool()
177+
178+
# Transactions are tiny in weight
179+
assert_greater_than(2000, tx_parent.get_weight() + tx_child.get_weight())
180+
136181
def run_test(self):
137182
self.wallet = MiniWallet(self.nodes[0])
138183

@@ -149,6 +194,8 @@ def run_test(self):
149194

150195
self.generate(self.wallet, 1)
151196

197+
self.test_sigops_package()
198+
152199

153200
if __name__ == '__main__':
154201
BytesPerSigOpTest().main()

0 commit comments

Comments
 (0)