aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chow <achow101-github@achow101.com>2021-10-08 13:57:48 -0400
committerfanquake <fanquake@gmail.com>2022-02-15 09:22:06 +0000
commitc768bfa08af034c744402d4294cc323d653b97b8 (patch)
tree835d2376b673f10f78ab8c12a9297774424a0810
parentf66bc42957ad2e86982c8c487f821683d3009b43 (diff)
downloadbitcoin-c768bfa08af034c744402d4294cc323d653b97b8.tar.xz
tests: Calculate fees more similarly to CFeeRate::GetFee
Because of floating point precision issues, not all of the rounding done is always correct. To fix this, the fee calculation for assert_fee_amount is changed to better reflect how CFeeRate::GetFee does it. First the feerate is converted to an int representing sat/kvb. Then this is multiplied by the transaction size, divivided by 1000, and rounded up to the nearest sat. The result is then converted back to BTC (divided by 1e8) and then rounded down to the nearest sat to avoid precision errors. Github-Pull: #22949 Rebased-From: 80dc829be7f8c3914074b85bb4c125baba18cb2c
-rw-r--r--test/functional/test_framework/util.py21
1 files changed, 17 insertions, 4 deletions
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 35dbfbba8d..72fd83e3f7 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -35,13 +35,14 @@ def assert_approx(v, vexp, vspan=0.00001):
raise AssertionError("%s > [%s..%s]" % (str(v), str(vexp - vspan), str(vexp + vspan)))
-def assert_fee_amount(fee, tx_size, fee_per_kB):
- """Assert the fee was in range"""
- target_fee = round(tx_size * fee_per_kB / 1000, 8)
+def assert_fee_amount(fee, tx_size, feerate_BTC_kvB):
+ """Assert the fee is in range."""
+ target_fee = get_fee(tx_size, feerate_BTC_kvB)
if fee < target_fee:
raise AssertionError("Fee of %s BTC too low! (Should be %s BTC)" % (str(fee), str(target_fee)))
# allow the wallet's estimation to be at most 2 bytes off
- if fee > (tx_size + 2) * fee_per_kB / 1000:
+ high_fee = get_fee(tx_size + 2, feerate_BTC_kvB)
+ if fee > high_fee:
raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)" % (str(fee), str(target_fee)))
@@ -222,6 +223,18 @@ def str_to_b64str(string):
return b64encode(string.encode('utf-8')).decode('ascii')
+def ceildiv(a, b):
+ """Divide 2 ints and round up to next int rather than round down"""
+ return -(-a // b)
+
+
+def get_fee(tx_size, feerate_btc_kvb):
+ """Calculate the fee in BTC given a feerate is BTC/kvB. Reflects CFeeRate::GetFee"""
+ feerate_sat_kvb = int(feerate_btc_kvb * Decimal(1e8)) # Fee in sat/kvb as an int to avoid float precision errors
+ target_fee_sat = ceildiv(feerate_sat_kvb * tx_size, 1000) # Round calculated fee up to nearest sat
+ return satoshi_round(target_fee_sat / Decimal(1e8)) # Truncate BTC result to nearest sat
+
+
def satoshi_round(amount):
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)