mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-07-12 19:52:34 +02:00
Merge bitcoin/bitcoin#30162: test: MiniWallet: respect passed feerate for padded txs (using target_weight
)
39d135e79f
test: MiniWallet: respect fee_rate for target_weight, use in mempool_limit.py (Sebastian Falbesoner)b2f0a9f8b0
test: add framework functional test for MiniWallet's tx padding (Sebastian Falbesoner)c17550bc3a
test: MiniWallet: fix tx padding (`target_weight`) for large sizes, improve accuracy (Sebastian Falbesoner) Pull request description: MiniWallet allows to create padded transactions that are equal or slightly above a certain `target_weight` (first introduced in PR #25379, commit1d6b438ef0
), which can be useful especially for mempool-related tests, e.g. for policy limit checks or scenarios to trigger mempool eviction. Currently the `target_weight` parameter doesn't play together with `fee_rate` though, as the fee calculation is incorrectly based on the tx vsize before the padding output is added, so the fee-rate is consequently far off. This means users are forced to pass an absolute fee, which can be quite inconvenient and leads to lots of duplicated "calculate absolute fee from fee-rate and vsize" code with the pattern `fee = (feerate / 1000) * (weight // 4)` on the call-sites. This PR first improves the tx padding itself to be more accurate, adds a functional test for it, and fixes the `fee_rate` treatment for the `{create,send}_self_transfer` methods. (Next step would be to enable this also for the `_self_transfer_multi` methods, but those currently don't even offer a `fee_rate` parameter). Finally, the ability to pass both `target_weight` and `fee_rate` is used in the `mempool_limit.py` functional test. There might be more use-cases in other tests, that could be done in a follow-up. ACKs for top commit: rkrux: tACK [39d135e
](39d135e79f
) ismaelsadeeq: Code Review ACK39d135e79f
🚀 glozow: light review ACK39d135e79f
Tree-SHA512: 6bf8e853a921576d463291d619cdfd6a7e74cf92f61933a563800ac0b3c023a06569b581243166906f56b3c5e8858fec2d8a6910d55899e904221f847eb0953d
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
from copy import deepcopy
|
||||
from decimal import Decimal
|
||||
from enum import Enum
|
||||
import math
|
||||
from typing import (
|
||||
Any,
|
||||
Optional,
|
||||
@ -33,10 +34,13 @@ from test_framework.messages import (
|
||||
CTxInWitness,
|
||||
CTxOut,
|
||||
hash256,
|
||||
ser_compact_size,
|
||||
WITNESS_SCALE_FACTOR,
|
||||
)
|
||||
from test_framework.script import (
|
||||
CScript,
|
||||
LEAF_VERSION_TAPSCRIPT,
|
||||
OP_1,
|
||||
OP_NOP,
|
||||
OP_RETURN,
|
||||
OP_TRUE,
|
||||
@ -52,6 +56,7 @@ from test_framework.script_util import (
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_greater_than_or_equal,
|
||||
get_fee,
|
||||
)
|
||||
from test_framework.wallet_util import generate_keypair
|
||||
|
||||
@ -119,13 +124,16 @@ class MiniWallet:
|
||||
"""Pad a transaction with extra outputs until it reaches a target weight (or higher).
|
||||
returns the tx
|
||||
"""
|
||||
tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN, b'a'])))
|
||||
tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN])))
|
||||
# determine number of needed padding bytes by converting weight difference to vbytes
|
||||
dummy_vbytes = (target_weight - tx.get_weight() + 3) // 4
|
||||
tx.vout[-1].scriptPubKey = CScript([OP_RETURN, b'a' * dummy_vbytes])
|
||||
# Lower bound should always be off by at most 3
|
||||
# compensate for the increase of the compact-size encoded script length
|
||||
# (note that the length encoding of the unpadded output script needs one byte)
|
||||
dummy_vbytes -= len(ser_compact_size(dummy_vbytes)) - 1
|
||||
tx.vout[-1].scriptPubKey = CScript([OP_RETURN] + [OP_1] * dummy_vbytes)
|
||||
# Actual weight should be at most 3 higher than target weight
|
||||
assert_greater_than_or_equal(tx.get_weight(), target_weight)
|
||||
# Higher bound should always be off by at most 3 + 12 weight (for encoding the length)
|
||||
assert_greater_than_or_equal(target_weight + 15, tx.get_weight())
|
||||
assert_greater_than_or_equal(target_weight + 3, tx.get_weight())
|
||||
|
||||
def get_balance(self):
|
||||
return sum(u['value'] for u in self._utxos)
|
||||
@ -367,6 +375,10 @@ class MiniWallet:
|
||||
vsize = Decimal(168) # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other)
|
||||
else:
|
||||
assert False
|
||||
if target_weight and not fee: # respect fee_rate if target weight is passed
|
||||
# the actual weight might be off by 3 WUs, so calculate based on that (see self._bulk_tx)
|
||||
max_actual_weight = target_weight + 3
|
||||
fee = get_fee(math.ceil(max_actual_weight / WITNESS_SCALE_FACTOR), fee_rate)
|
||||
send_value = utxo_to_spend["value"] - (fee or (fee_rate * vsize / 1000))
|
||||
|
||||
# create tx
|
||||
|
Reference in New Issue
Block a user