aboutsummaryrefslogtreecommitdiff
path: root/test/functional/test_framework
diff options
context:
space:
mode:
authorglozow <gloriajzhao@gmail.com>2024-06-11 11:49:48 +0100
committerglozow <gloriajzhao@gmail.com>2024-06-11 13:02:03 +0100
commite6e4c18a9be21c6bad78778ed919299617d40f7a (patch)
treedd19e4103a2b5c29ede6933e1d1d1252e48d49ab /test/functional/test_framework
parentba5dd96298559d1f078c397048ce6703b90c067c (diff)
parent39d135e79f3f0c40dfd8fad2c53723d533cd19b4 (diff)
Merge bitcoin/bitcoin#30162: test: MiniWallet: respect passed feerate for padded txs (using `target_weight`)
39d135e79f3f0c40dfd8fad2c53723d533cd19b4 test: MiniWallet: respect fee_rate for target_weight, use in mempool_limit.py (Sebastian Falbesoner) b2f0a9f8b0776d49ef1639310311ca50435a2a0a test: add framework functional test for MiniWallet's tx padding (Sebastian Falbesoner) c17550bc3a68faa1eb82d1bdb767b41d8cd85a6b 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, commit 1d6b438ef0ccd05e1522ac38b44f847c1d93e72f), 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](https://github.com/bitcoin/bitcoin/pull/30162/commits/39d135e79f3f0c40dfd8fad2c53723d533cd19b4) ismaelsadeeq: Code Review ACK 39d135e79f3f0c40dfd8fad2c53723d533cd19b4 🚀 glozow: light review ACK 39d135e79f3f0c40dfd8fad2c53723d533cd19b4 Tree-SHA512: 6bf8e853a921576d463291d619cdfd6a7e74cf92f61933a563800ac0b3c023a06569b581243166906f56b3c5e8858fec2d8a6910d55899e904221f847eb0953d
Diffstat (limited to 'test/functional/test_framework')
-rw-r--r--test/functional/test_framework/wallet.py22
1 files changed, 17 insertions, 5 deletions
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 4433cbcc55..7d4f4a3392 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -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