diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index 54b42667bba95..020d0017ea89b 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -789,9 +789,9 @@ def test_option_feerate(self): # With no arguments passed, expect fee of 141 satoshis. assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001) - # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified. - result = node.fundrawtransaction(rawtx, {"fee_rate": 10000}) - assert_approx(result["fee"], vexp=0.0141, vspan=0.0001) + # Expect fee to be 10x higher when an explicit fee rate 10x greater is specified. + result = node.fundrawtransaction(rawtx, {"fee_rate": 10}) + assert_approx(result["fee"], vexp=0.0000141, vspan=0.0000001) self.log.info("Test fundrawtxn with invalid estimate_mode settings") for k, v in {"number": 42, "object": {"foo": "bar"}}.items(): @@ -1280,7 +1280,7 @@ def test_22670(self): # Make sure the default wallet will not be loaded when restarted with a high minrelaytxfee self.nodes[0].unloadwallet(self.default_wallet_name, False) feerate = Decimal("0.1") - self.restart_node(0, [f"-minrelaytxfee={feerate}", "-discardfee=0"]) # Set high minrelayfee, set discardfee to 0 for easier calculation + self.restart_node(0, [f"-minrelaytxfee={feerate}", "-maxtxfee=0.1", "-discardfee=0"]) # Set high minrelayfee and maxtxfee, set discardfee to 0 for easier calculation self.nodes[0].loadwallet(self.default_wallet_name, True) funds = self.nodes[0].get_wallet_rpc(self.default_wallet_name) @@ -1310,7 +1310,7 @@ def do_fund_send(target): assert signed_tx["complete"] decoded_tx = tester.decoderawtransaction(signed_tx["hex"]) assert_equal(len(decoded_tx["vin"]), 3) - assert tester.testmempoolaccept([signed_tx["hex"]])[0]["allowed"] + assert tester.testmempoolaccept(rawtxs=[signed_tx["hex"]], maxfeerate='0.1')[0]["allowed"] # Must override default maxfeerate to pass # We want to choose more value than is available in 2 inputs when considering the fee, # but not enough to need 3 inputs when not considering the fee. diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 930aaaa89744e..8191db63715a3 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -269,33 +269,44 @@ def sendrawtransaction_testmempoolaccept_tests(self): self.log.info("Test sendrawtransaction/testmempoolaccept with maxfeerate") fee_exceeds_max = "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)" - # Test a transaction with a small fee. - # Fee rate is 0.00100000 BTC/kvB - tx = self.wallet.create_self_transfer(fee_rate=Decimal('0.00100000')) - # Thus, testmempoolaccept should reject - testres = self.nodes[2].testmempoolaccept([tx['hex']], 0.00001000)[0] + # Test a transaction above the maxfeerate default + # TODO: Make maxfeerate retrievable from rpc rather than hard-coding here. + max_fee_rate = Decimal("0.00500000") # Current maxfeerate is 0.00500000 BTC/kvB + test_fee_rate = max_fee_rate + Decimal("0.00000001") + tx = self.wallet.create_self_transfer(fee_rate=test_fee_rate) + # We're above maxfeerate so testmempoolaccept should reject + testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']])[0] assert_equal(testres['allowed'], False) - assert_equal(testres['reject-reason'], 'max-fee-exceeded') - # and sendrawtransaction should throw - assert_raises_rpc_error(-25, fee_exceeds_max, self.nodes[2].sendrawtransaction, tx['hex'], 0.00001000) - # and the following calls should both succeed + + # Test a transaction exactly at the maxfeerate default + test_fee_rate = max_fee_rate + tx = self.wallet.create_self_transfer(fee_rate=test_fee_rate) + # We're at maxfeerate so testmempoolaccept should accept testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']])[0] assert_equal(testres['allowed'], True) - self.nodes[2].sendrawtransaction(hexstring=tx['hex']) - # Test a transaction with a large fee. - # Fee rate is 0.20000000 BTC/kvB - tx = self.wallet.create_self_transfer(fee_rate=Decimal("0.20000000")) - # Thus, testmempoolaccept should reject - testres = self.nodes[2].testmempoolaccept([tx['hex']])[0] + # Test a transaction below the maxfeerate default + test_fee_rate = max_fee_rate - Decimal("0.00000001") + tx = self.wallet.create_self_transfer(fee_rate=test_fee_rate) + # We're below maxfeerate so testmempoolaccept should accept + testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']])[0] + assert_equal(testres['allowed'], True) + + # Test a transaction with maxfeerate manually decreased + test_max_fee_rate = test_fee_rate - Decimal("0.00000010") # Must be at least a 10 sat diff to create a noticeable effect + # Our previous tx should now be rejected + testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']], maxfeerate=test_max_fee_rate)[0] assert_equal(testres['allowed'], False) - assert_equal(testres['reject-reason'], 'max-fee-exceeded') # and sendrawtransaction should throw - assert_raises_rpc_error(-25, fee_exceeds_max, self.nodes[2].sendrawtransaction, tx['hex']) - # and the following calls should both succeed - testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']], maxfeerate='0.20000000')[0] + assert_raises_rpc_error(-25, fee_exceeds_max, self.nodes[2].sendrawtransaction, tx['hex'], test_max_fee_rate) + + # Test a transaction with maxfeerate manually increased + test_fee_rate = 2*max_fee_rate + tx = self.wallet.create_self_transfer(fee_rate=test_fee_rate) + # high-fee tx should now be accepted + testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']], maxfeerate=test_fee_rate)[0] assert_equal(testres['allowed'], True) - self.nodes[2].sendrawtransaction(hexstring=tx['hex'], maxfeerate='0.20000000') + self.nodes[2].sendrawtransaction(hexstring=tx['hex'], maxfeerate=test_fee_rate) self.log.info("Test sendrawtransaction/testmempoolaccept with tx already in the chain") self.generate(self.nodes[2], 1) @@ -369,11 +380,12 @@ def raw_multisig_transaction_legacy_tests(self): bal = self.nodes[2].getbalance() # send 1.2 BTC to msig adr - txId = self.nodes[0].sendtoaddress(mSigObj, 1.2) + test_amount = Decimal('1.20000000') + txId = self.nodes[0].sendtoaddress(mSigObj, test_amount) self.sync_all() self.generate(self.nodes[0], 1) # node2 has both keys of the 2of2 ms addr, tx should affect the balance - assert_equal(self.nodes[2].getbalance(), bal + Decimal('1.20000000')) + assert_equal(self.nodes[2].getbalance(), bal + test_amount) # 2of3 test from different nodes @@ -388,7 +400,8 @@ def raw_multisig_transaction_legacy_tests(self): mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']])['address'] - txId = self.nodes[0].sendtoaddress(mSigObj, 2.2) + test_amount = Decimal('2.20000000') + txId = self.nodes[0].sendtoaddress(mSigObj, test_amount) decTx = self.nodes[0].gettransaction(txId) rawTx = self.nodes[0].decoderawtransaction(decTx['hex']) self.sync_all() @@ -400,11 +413,12 @@ def raw_multisig_transaction_legacy_tests(self): txDetails = self.nodes[0].gettransaction(txId, True) rawTx = self.nodes[0].decoderawtransaction(txDetails['hex']) - vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('2.20000000')) + vout = next(o for o in rawTx['vout'] if o['value'] == test_amount) bal = self.nodes[0].getbalance() - inputs = [{"txid": txId, "vout": vout['n'], "scriptPubKey": vout['scriptPubKey']['hex'], "amount": vout['value']}] - outputs = {self.nodes[0].getnewaddress(): 2.19} + inputs = [{"txid": txId, "vout": vout['n'], "scriptPubKey": vout['scriptPubKey']['hex'], "amount": test_amount}] + output_amount = test_amount - Decimal("0.00000500") # Keep the fee modest to stay under maxtxfee + outputs = {self.nodes[0].getnewaddress(): output_amount} rawTx = self.nodes[2].createrawtransaction(inputs, outputs) rawTxPartialSigned = self.nodes[1].signrawtransactionwithwallet(rawTx, inputs) assert_equal(rawTxPartialSigned['complete'], False) # node1 only has one key, can't comp. sign the tx @@ -415,7 +429,7 @@ def raw_multisig_transaction_legacy_tests(self): rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex']) self.sync_all() self.generate(self.nodes[0], 1) - assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') + Decimal('2.19000000')) # block reward + tx + assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') + output_amount) # block reward + tx # 2of2 test for combining transactions bal = self.nodes[2].getbalance() @@ -429,7 +443,7 @@ def raw_multisig_transaction_legacy_tests(self): mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address'] mSigObjValid = self.nodes[2].getaddressinfo(mSigObj) - txId = self.nodes[0].sendtoaddress(mSigObj, 2.2) + txId = self.nodes[0].sendtoaddress(mSigObj, test_amount) decTx = self.nodes[0].gettransaction(txId) rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex']) self.sync_all() @@ -439,11 +453,11 @@ def raw_multisig_transaction_legacy_tests(self): txDetails = self.nodes[0].gettransaction(txId, True) rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex']) - vout = next(o for o in rawTx2['vout'] if o['value'] == Decimal('2.20000000')) + vout = next(o for o in rawTx2['vout'] if o['value'] == test_amount) bal = self.nodes[0].getbalance() inputs = [{"txid": txId, "vout": vout['n'], "scriptPubKey": vout['scriptPubKey']['hex'], "redeemScript": mSigObjValid['hex'], "amount": vout['value']}] - outputs = {self.nodes[0].getnewaddress(): 2.19} + outputs = {self.nodes[0].getnewaddress(): output_amount} rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs) rawTxPartialSigned1 = self.nodes[1].signrawtransactionwithwallet(rawTx2, inputs) self.log.debug(rawTxPartialSigned1) @@ -458,7 +472,7 @@ def raw_multisig_transaction_legacy_tests(self): rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb) self.sync_all() self.generate(self.nodes[0], 1) - assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') + Decimal('2.19000000')) # block reward + tx + assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') + output_amount) # block reward + tx if __name__ == '__main__': diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 20c577ceb3085..1f5c10f1548c2 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -333,9 +333,11 @@ def run_test(self): # 4. check if recipient (node0) can list the zero value tx usp = self.nodes[1].listunspent(query_options={'minimumAmount': '49.998'})[0] inputs = [{"txid": usp['txid'], "vout": usp['vout']}] - outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11} + test_amount = Decimal("0.00001000") # this output amount will be zeroed and thereby added to the fee + fee = Decimal("0.00000400") # start with a modest fee so our final fee won't exceed default maxtxfee + outputs = {self.nodes[1].getnewaddress(): usp['amount'] - test_amount - fee, self.nodes[0].getnewaddress(): test_amount} - raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") # replace 11.11 with 0.0 (int32) + raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace("e8030000", "00000000") # replace test_amount with 0.0 (int32) signed_raw_tx = self.nodes[1].signrawtransactionwithwallet(raw_tx) decoded_raw_tx = self.nodes[1].decoderawtransaction(signed_raw_tx['hex']) zero_value_txid = decoded_raw_tx['txid'] diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 158ef66110ee6..1eea4cb0ca9a1 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -38,11 +38,12 @@ WALLET_PASSPHRASE_TIMEOUT = 3600 # Fee rates (sat/vB) -INSUFFICIENT = 1 -ECONOMICAL = 50 -NORMAL = 100 -HIGH = 500 -TOO_HIGH = 100000 +# TODO: Make maxfeerate retrievable from rpc and set these rates accordingly. +INSUFFICIENT = 1 +ECONOMICAL = 50 +NORMAL = 100 +HIGH = 450 # stay below the maxfeerate (500) +TOO_HIGH = 10*HIGH class BumpFeeTest(BitcoinTestFramework): @@ -110,6 +111,7 @@ def test_invalid_parameters(self, rbf_node, peer_node, dest_address): self.sync_mempools((rbf_node, peer_node)) assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool() + # Test incorrect json key names for key in ["totalFee", "feeRate"]: assert_raises_rpc_error(-3, "Unexpected key {}".format(key), rbf_node.bumpfee, rbfid, {key: NORMAL}) @@ -117,7 +119,7 @@ def test_invalid_parameters(self, rbf_node, peer_node, dest_address): assert_raises_rpc_error(-8, "Insufficient total fee 0.00000141", rbf_node.bumpfee, rbfid, {"fee_rate": INSUFFICIENT}) self.log.info("Test invalid fee rate settings") - assert_raises_rpc_error(-4, "Specified or calculated fee 0.141 is too high (cannot be higher than -maxtxfee 0.10", + assert_raises_rpc_error(-4, "is too high (cannot be higher than -maxtxfee", rbf_node.bumpfee, rbfid, {"fee_rate": TOO_HIGH}) # Test fee_rate with zero values. msg = "Insufficient total fee 0.00" @@ -239,7 +241,7 @@ def test_notmine_bumpfee(self, rbf_node, peer_node, dest_address): # here, the rbftx has a peer_node coin and then adds a rbf_node input # Note that this test depends upon the RPC code checking input ownership prior to change outputs # (since it can't use fundrawtransaction, it lacks a proper change output) - fee = Decimal("0.001") + fee = Decimal("0.00001") # Must stay below maxtxfee utxos = [node.listunspent(query_options={'minimumAmount': fee})[-1] for node in (rbf_node, peer_node)] inputs = [{ "txid": utxo["txid"], @@ -459,12 +461,13 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address): funding_address1 = watcher.getnewaddress(address_type='bech32') funding_address2 = watcher.getnewaddress(address_type='bech32') - peer_node.sendmany("", {funding_address1: 0.001, funding_address2: 0.001}) + funding_amount = Decimal("0.001") + peer_node.sendmany("", {funding_address1: funding_amount, funding_address2: funding_amount}) self.generate(peer_node, 1) # Create single-input PSBT for transaction to be bumped - # Ensure the payment amount + change can be fully funded using one of the 0.001BTC inputs. - psbt = watcher.walletcreatefundedpsbt([watcher.listunspent()[0]], {dest_address: 0.0005}, 0, + # Ensure the payment amount can be fully funded using one of the 0.001BTC inputs but won't be enough for additional bump further below. + psbt = watcher.walletcreatefundedpsbt([watcher.listunspent()[0]], {dest_address: funding_amount - Decimal("0.00005000")}, 0, {"fee_rate": 1, "add_inputs": False}, True)['psbt'] psbt_signed = signer.walletprocesspsbt(psbt=psbt, sign=True, sighashtype="ALL", bip32derivs=True) psbt_final = watcher.finalizepsbt(psbt_signed["psbt"]) diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py index a213a261ef717..8207be7aaa93f 100755 --- a/test/functional/wallet_create_tx.py +++ b/test/functional/wallet_create_tx.py @@ -48,7 +48,8 @@ def test_tx_size_too_large(self): outputs = {self.nodes[0].getnewaddress(address_type='bech32'): 0.000025 for _ in range(400)} raw_tx = self.nodes[0].createrawtransaction(inputs=[], outputs=outputs) - for fee_setting in ['-minrelaytxfee=0.01', '-mintxfee=0.01', '-paytxfee=0.01']: + # default maxtxfee is 0.005 + for fee_setting in ['-minrelaytxfee=0.001', '-mintxfee=0.001', '-paytxfee=0.001']: self.log.info('Check maxtxfee in combination with {}'.format(fee_setting)) self.restart_node(0, extra_args=[fee_setting]) assert_raises_rpc_error( @@ -64,7 +65,7 @@ def test_tx_size_too_large(self): self.log.info('Check maxtxfee in combination with settxfee') self.restart_node(0) - self.nodes[0].settxfee(0.01) + self.nodes[0].settxfee(0.001) assert_raises_rpc_error( -6, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)", diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py index e5e4cf03bf7ed..fd9b94478d488 100755 --- a/test/functional/wallet_groups.py +++ b/test/functional/wallet_groups.py @@ -4,6 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test wallet group functionality.""" +from decimal import Decimal from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.messages import ( @@ -160,21 +161,22 @@ def run_test(self): self.generate(self.nodes[0], 1) self.log.info("Fill a wallet with 10,000 outputs corresponding to the same scriptPubKey") + output_amount = Decimal("0.05") for _ in range(5): - raw_tx = self.nodes[0].createrawtransaction([{"txid":"0"*64, "vout":0}], [{addr2[0]: 0.05}]) + raw_tx = self.nodes[0].createrawtransaction([{"txid":"0"*64, "vout":0}], [{addr2[0]: output_amount}]) tx = tx_from_hex(raw_tx) tx.vin = [] tx.vout = [tx.vout[0]] * 2000 - funded_tx = self.nodes[0].fundrawtransaction(tx.serialize().hex()) + funded_tx = self.nodes[0].fundrawtransaction(hexstring=tx.serialize().hex(), options={"fee_rate": 5.0}) # Specify fee_rate so we get change instead of exceeding maxfeerate signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex']) self.nodes[0].sendrawtransaction(signed_tx['hex']) self.generate(self.nodes[0], 1) - # Check that we can create a transaction that only requires ~100 of our + # Check that we can create a transaction that only requires 100 of our # utxos, without pulling in all outputs and creating a transaction that # is way too big. - self.log.info("Test creating txn that only requires ~100 of our UTXOs without pulling in all outputs") - assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5) + self.log.info("Test creating txn that only requires 100 of our UTXOs without pulling in all outputs") + assert self.nodes[2].sendtoaddress(address=addr2[0], amount=100*output_amount) if __name__ == '__main__':