diff options
author | fanquake <fanquake@gmail.com> | 2022-03-01 09:56:42 +0000 |
---|---|---|
committer | fanquake <fanquake@gmail.com> | 2022-03-01 13:40:11 +0000 |
commit | 9b5f674abb0e90280436fbacb8711250cde11773 (patch) | |
tree | 0f173c70b5ff3a3cf60cb3eb4a1bc30a01c07c75 /test/functional | |
parent | eff97097239fa42764aaa14a7ae57ac9e73b9bd9 (diff) | |
parent | 269553fe73b17f8acda3071a48836c66092d31d0 (diff) | |
download | bitcoin-9b5f674abb0e90280436fbacb8711250cde11773.tar.xz |
Merge bitcoin/bitcoin#23276: [22.x] Backports for 22.x
269553fe73b17f8acda3071a48836c66092d31d0 test: Call ceildiv helper with integer (Martin Zumsande)
2f60fc6d8c6b1d8e74c340fed495b76deac4a048 ci: Replace soon EOL hirsute with jammy (MarcoFalke)
801b0f05aaf974ab9b0e3f7b59948564638d593f build: patch qt to explicitly define previously implicit header include (Kittywhiskers Van Gogh)
c768bfa08af034c744402d4294cc323d653b97b8 tests: Calculate fees more similarly to CFeeRate::GetFee (Andrew Chow)
f66bc42957ad2e86982c8c487f821683d3009b43 tests: Test for assertion when feerate is rounded down (Andrew Chow)
bd7e08e36bf2e1238ddf8cc01433f8db82f848c9 fees: Always round up fee calculated from a feerate (Andrew Chow)
227ae652542451834faddbaffb54fc384e9156e6 wallet: fix segfault by avoiding invalid default-ctored `external_spk_managers` entry (Sebastian Falbesoner)
282863a7e9ddfb14ef02182945ca1978699dbe52 refactor: include a missing <limits> header in fs.cpp (Joan Karadimov)
7febe4f3c7f482390c4aa6fc528e2ee3fb34b142 consensus: don't call GetBlockPos in ReadBlockFromDisk without lock (Jon Atack)
c671c6f4706d17cccfe5c35950235f8777a7975f the result of CWallet::IsHDEnabled() was initialized with true. (Saibato)
a5a153882609c8d77118a88a9a440d4966c8d0ef build, qt: Fix typo in QtInputSupport check (Hennadii Stepanov)
c95b188fc08387d0a89668e56bce3a4fad1ee611 system: skip trying to set the locale on NetBSD (fanquake)
c1cdeddd905b5444eac330d565b297b3d4941c5d guix: Fix powerpc64(le) dynamic linker name (Carl Dong)
92d44ff36cc12e34f93bfcc4ec31ffae8787100c doc: Add 23061 release notes (MarcoFalke)
db76db7329f6357c5226cd08611fe0f669c002af Fix (inverse) meaning of -persistmempool (MarcoFalke)
85c78e08ec857e51a9748d1a2492d1d3794b221a build: Restrict check for CRC32C intrinsic to aarch64 (W. J. van der Laan)
Pull request description:
Collecting backports for the 22.1 release. Currently:
* https://github.com/bitcoin/bitcoin/pull/23045
* https://github.com/bitcoin/bitcoin/pull/23061
* https://github.com/bitcoin/bitcoin/pull/23148
* https://github.com/bitcoin/bitcoin/pull/22390
* https://github.com/bitcoin/bitcoin/pull/22820
* https://github.com/bitcoin/bitcoin/pull/22781
* https://github.com/bitcoin/bitcoin/pull/22895
* https://github.com/bitcoin/bitcoin/pull/23335
* https://github.com/bitcoin/bitcoin/pull/23333
* https://github.com/bitcoin/bitcoin/pull/22949
* https://github.com/bitcoin/bitcoin/pull/23580
* https://github.com/bitcoin/bitcoin/pull/23504
* https://github.com/bitcoin/bitcoin/pull/24239
ACKs for top commit:
achow101:
ACK 269553fe73b17f8acda3071a48836c66092d31d0
Tree-SHA512: b3a57ea241be7a83488eeb032276f4cf82a0987aada906a82f94a20c4acf9f2397708249dcecbe1c7575e70d09c60b835233d4718af4013c7bc58896c618274c
Diffstat (limited to 'test/functional')
-rwxr-xr-x | test/functional/mempool_persist.py | 2 | ||||
-rwxr-xr-x | test/functional/rpc_fundrawtransaction.py | 28 | ||||
-rw-r--r-- | test/functional/test_framework/util.py | 28 | ||||
-rwxr-xr-x | test/functional/wallet_keypool.py | 2 | ||||
-rwxr-xr-x | test/functional/wallet_send.py | 9 |
5 files changed, 59 insertions, 10 deletions
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index 752b925b92..1ae95fced3 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -141,7 +141,7 @@ class MempoolPersistTest(BitcoinTestFramework): self.log.debug("Stop nodes, make node1 use mempool.dat from node0. Verify it has 6 transactions") os.rename(mempooldat0, mempooldat1) self.stop_nodes() - self.start_node(1, extra_args=[]) + self.start_node(1, extra_args=["-persistmempool"]) assert self.nodes[1].getmempoolinfo()["loaded"] assert_equal(len(self.nodes[1].getrawmempool()), 6) diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index fcc310394a..bbd3dbb10c 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -100,6 +100,7 @@ class RawTransactionsTest(BitcoinTestFramework): self.test_transaction_too_large() self.test_include_unsafe() self.test_22670() + self.test_feerate_rounding() def test_change_position(self): """Ensure setting changePosition in fundraw with an exact match is handled properly.""" @@ -1026,6 +1027,33 @@ class RawTransactionsTest(BitcoinTestFramework): do_fund_send(upper_bound) self.restart_node(0) + self.connect_nodes(0, 1) + self.connect_nodes(0, 2) + self.connect_nodes(0, 3) + + def test_feerate_rounding(self): + self.log.info("Test that rounding of GetFee does not result in an assertion") + + self.nodes[1].createwallet("roundtest") + w = self.nodes[1].get_wallet_rpc("roundtest") + + addr = w.getnewaddress(address_type="bech32") + self.nodes[0].sendtoaddress(addr, 1) + self.nodes[0].generate(1) + self.sync_all() + + # A P2WPKH input costs 68 vbytes; With a single P2WPKH output, the rest of the tx is 42 vbytes for a total of 110 vbytes. + # At a feerate of 1.85 sat/vb, the input will need a fee of 125.8 sats and the rest 77.7 sats + # The entire tx fee should be 203.5 sats. + # Coin selection rounds the fee individually instead of at the end (due to how CFeeRate::GetFee works). + # If rounding down (which is the incorrect behavior), then the calculated fee will be 125 + 77 = 202. + # If rounding up, then the calculated fee will be 126 + 78 = 204. + # In the former case, the calculated needed fee is higher than the actual fee being paid, so an assertion is reached + # To test this does not happen, we subtract 202 sats from the input value. If working correctly, this should + # fail with insufficient funds rather than bitcoind asserting. + rawtx = w.createrawtransaction(inputs=[], outputs=[{self.nodes[0].getnewaddress(address_type="bech32"): 1 - 0.00000202}]) + assert_raises_rpc_error(-4, "Insufficient funds", w.fundrawtransaction, rawtx, {"fee_rate": 1.85}) + if __name__ == '__main__': RawTransactionsTest().main() diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 35dbfbba8d..8a41ec4370 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -35,13 +35,15 @@ 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.""" + assert isinstance(tx_size, int) + 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 +224,24 @@ 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 + Implementation requires python integers, which have a // operator that does floor division. + Other types like decimal.Decimal whose // operator truncates towards 0 will not work. + """ + assert isinstance(a, int) + assert isinstance(b, int) + 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 target_fee_sat / Decimal(1e8) # Return result in BTC + + def satoshi_round(amount): return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py index 28bfc9116f..9286387f96 100755 --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -179,7 +179,7 @@ class KeyPoolTest(BitcoinTestFramework): assert_equal("psbt" in res, True) # create a transaction without change at the maximum fee rate, such that the output is still spendable: - res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.0008824}) + res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.0008823}) assert_equal("psbt" in res, True) assert_equal(res["fee"], Decimal("0.00009706")) diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py index d24d1693af..d469af600e 100755 --- a/test/functional/wallet_send.py +++ b/test/functional/wallet_send.py @@ -15,6 +15,7 @@ from test_framework.util import ( assert_fee_amount, assert_greater_than, assert_raises_rpc_error, + count_bytes, ) class WalletSendTest(BitcoinTestFramework): @@ -318,20 +319,20 @@ class WalletSendTest(BitcoinTestFramework): res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate=7, add_to_wallet=False) fee = self.nodes[1].decodepsbt(res["psbt"])["fee"] - assert_fee_amount(fee, Decimal(len(res["hex"]) / 2), Decimal("0.00007")) + assert_fee_amount(fee, count_bytes(res["hex"]), Decimal("0.00007")) # "unset" and None are treated the same for estimate_mode res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate=2, estimate_mode="unset", add_to_wallet=False) fee = self.nodes[1].decodepsbt(res["psbt"])["fee"] - assert_fee_amount(fee, Decimal(len(res["hex"]) / 2), Decimal("0.00002")) + assert_fee_amount(fee, count_bytes(res["hex"]), Decimal("0.00002")) res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate=4.531, add_to_wallet=False) fee = self.nodes[1].decodepsbt(res["psbt"])["fee"] - assert_fee_amount(fee, Decimal(len(res["hex"]) / 2), Decimal("0.00004531")) + assert_fee_amount(fee, count_bytes(res["hex"]), Decimal("0.00004531")) res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate=3, add_to_wallet=False) fee = self.nodes[1].decodepsbt(res["psbt"])["fee"] - assert_fee_amount(fee, Decimal(len(res["hex"]) / 2), Decimal("0.00003")) + assert_fee_amount(fee, count_bytes(res["hex"]), Decimal("0.00003")) # Test that passing fee_rate as both an argument and an option raises. self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate=1, fee_rate=1, add_to_wallet=False, |