7
7
from copy import deepcopy
8
8
from decimal import Decimal
9
9
from enum import Enum
10
+ import math
10
11
from typing import (
11
12
Any ,
12
13
Optional ,
33
34
CTxInWitness ,
34
35
CTxOut ,
35
36
hash256 ,
37
+ ser_compact_size ,
38
+ WITNESS_SCALE_FACTOR ,
36
39
)
37
40
from test_framework .script import (
38
41
CScript ,
39
42
LEAF_VERSION_TAPSCRIPT ,
43
+ OP_1 ,
40
44
OP_NOP ,
41
45
OP_RETURN ,
42
46
OP_TRUE ,
52
56
from test_framework .util import (
53
57
assert_equal ,
54
58
assert_greater_than_or_equal ,
59
+ get_fee ,
55
60
)
56
- from enum import Enum
57
- from test_framework .blocktools import COINBASE_MATURITY
58
61
from test_framework .wallet_util import generate_keypair
59
62
60
63
DEFAULT_FEE = Decimal ("0.0001" )
@@ -109,7 +112,7 @@ def __init__(self, test_node, *, mode=MiniWalletMode.ADDRESS_OP_TRUE, tag_name=N
109
112
110
113
# When the pre-mined test framework chain is used, it contains coinbase
111
114
# outputs to the MiniWallet's default address in blocks 76-100
112
- # (see method BGLTestFramework ._initialize_chain())
115
+ # (see method BitcoinTestFramework ._initialize_chain())
113
116
# The MiniWallet needs to rescan_utxos() in order to account
114
117
# for those mature UTXOs, so that all txs spend confirmed coins
115
118
self .rescan_utxos ()
@@ -121,13 +124,16 @@ def _bulk_tx(self, tx, target_weight):
121
124
"""Pad a transaction with extra outputs until it reaches a target weight (or higher).
122
125
returns the tx
123
126
"""
124
- tx .vout .append (CTxOut (nValue = 0 , scriptPubKey = CScript ([OP_RETURN , b'a' ])))
127
+ tx .vout .append (CTxOut (nValue = 0 , scriptPubKey = CScript ([OP_RETURN ])))
128
+ # determine number of needed padding bytes by converting weight difference to vbytes
125
129
dummy_vbytes = (target_weight - tx .get_weight () + 3 ) // 4
126
- tx .vout [- 1 ].scriptPubKey = CScript ([OP_RETURN , b'a' * dummy_vbytes ])
127
- # Lower bound should always be off by at most 3
130
+ # compensate for the increase of the compact-size encoded script length
131
+ # (note that the length encoding of the unpadded output script needs one byte)
132
+ dummy_vbytes -= len (ser_compact_size (dummy_vbytes )) - 1
133
+ tx .vout [- 1 ].scriptPubKey = CScript ([OP_RETURN ] + [OP_1 ] * dummy_vbytes )
134
+ # Actual weight should be at most 3 higher than target weight
128
135
assert_greater_than_or_equal (tx .get_weight (), target_weight )
129
- # Higher bound should always be off by at most 3 + 12 weight (for encoding the length)
130
- assert_greater_than_or_equal (target_weight + 15 , tx .get_weight ())
136
+ assert_greater_than_or_equal (target_weight + 3 , tx .get_weight ())
131
137
132
138
def get_balance (self ):
133
139
return sum (u ['value' ] for u in self ._utxos )
@@ -369,6 +375,10 @@ def create_self_transfer(
369
375
vsize = Decimal (168 ) # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other)
370
376
else :
371
377
assert False
378
+ if target_weight and not fee : # respect fee_rate if target weight is passed
379
+ # the actual weight might be off by 3 WUs, so calculate based on that (see self._bulk_tx)
380
+ max_actual_weight = target_weight + 3
381
+ fee = get_fee (math .ceil (max_actual_weight / WITNESS_SCALE_FACTOR ), fee_rate )
372
382
send_value = utxo_to_spend ["value" ] - (fee or (fee_rate * vsize / 1000 ))
373
383
374
384
# create tx
0 commit comments