diff options
Diffstat (limited to 'test')
-rwxr-xr-x | test/functional/feature_minchainwork.py | 29 | ||||
-rwxr-xr-x | test/functional/mempool_packages.py | 6 | ||||
-rwxr-xr-x | test/functional/p2p_blockfilters.py | 5 | ||||
-rwxr-xr-x | test/functional/rpc_mempool_entry_fee_fields_deprecation.py | 67 | ||||
-rwxr-xr-x | test/functional/rpc_mempool_info.py | 102 | ||||
-rwxr-xr-x | test/functional/rpc_rawtransaction.py | 160 | ||||
-rwxr-xr-x | test/functional/rpc_signrawtransaction.py | 51 | ||||
-rwxr-xr-x | test/functional/test_runner.py | 3 | ||||
-rwxr-xr-x | test/lint/lint-logs.py | 4 |
9 files changed, 238 insertions, 189 deletions
diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py index 489a729cfc..fa10855a98 100755 --- a/test/functional/feature_minchainwork.py +++ b/test/functional/feature_minchainwork.py @@ -17,6 +17,7 @@ only succeeds past a given node once its nMinimumChainWork has been exceeded. import time +from test_framework.p2p import P2PInterface, msg_getheaders from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal @@ -41,6 +42,9 @@ class MinimumChainWorkTest(BitcoinTestFramework): for i in range(self.num_nodes-1): self.connect_nodes(i+1, i) + # Set clock of node2 2 days ahead, to keep it in IBD during this test. + self.nodes[2].setmocktime(int(time.time()) + 48*60*60) + def run_test(self): # Start building a chain on node0. node2 shouldn't be able to sync until node1's # minchainwork is exceeded @@ -71,6 +75,15 @@ class MinimumChainWorkTest(BitcoinTestFramework): assert self.nodes[1].getbestblockhash() != self.nodes[0].getbestblockhash() assert_equal(self.nodes[2].getblockcount(), starting_blockcount) + self.log.info("Check that getheaders requests to node2 are ignored") + peer = self.nodes[2].add_p2p_connection(P2PInterface()) + msg = msg_getheaders() + msg.locator.vHave = [int(self.nodes[2].getbestblockhash(), 16)] + msg.hashstop = 0 + peer.send_and_ping(msg) + time.sleep(5) + assert "headers" not in peer.last_message + self.log.info("Generating one more block") self.generate(self.nodes[0], 1) @@ -85,5 +98,21 @@ class MinimumChainWorkTest(BitcoinTestFramework): self.sync_all() self.log.info(f"Blockcounts: {[n.getblockcount() for n in self.nodes]}") + self.log.info("Test that getheaders requests to node2 are not ignored") + peer.send_and_ping(msg) + assert "headers" in peer.last_message + + # Verify that node2 is in fact still in IBD (otherwise this test may + # not be exercising the logic we want!) + assert_equal(self.nodes[2].getblockchaininfo()['initialblockdownload'], True) + + self.log.info("Test -minimumchainwork with a non-hex value") + self.stop_node(0) + self.nodes[0].assert_start_raises_init_error( + ["-minimumchainwork=test"], + expected_msg='Error: Invalid non-hex (test) minimum chain work value specified', + ) + + if __name__ == '__main__': MinimumChainWorkTest().main() diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index 068fdc0b65..a2a2caf324 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -100,6 +100,12 @@ class MempoolPackagesTest(BitcoinTestFramework): entry = self.nodes[0].getmempoolentry(x) assert_equal(entry, mempool[x]) + # Check that gettxspendingprevout is consistent with getrawmempool + witnesstx = self.nodes[0].gettransaction(txid=x, verbose=True)['decoded'] + for tx_in in witnesstx["vin"]: + spending_result = self.nodes[0].gettxspendingprevout([ {'txid' : tx_in["txid"], 'vout' : tx_in["vout"]} ]) + assert_equal(spending_result, [ {'txid' : tx_in["txid"], 'vout' : tx_in["vout"], 'spendingtxid' : x} ]) + # Check that the descendant calculations are correct assert_equal(entry['descendantcount'], descendant_count) descendant_fees += entry['fees']['base'] diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py index 2ffc825acd..ef12b5f6b7 100755 --- a/test/functional/p2p_blockfilters.py +++ b/test/functional/p2p_blockfilters.py @@ -250,6 +250,11 @@ class CompactFiltersTest(BitcoinTestFramework): msg = "Error: Cannot set -peerblockfilters without -blockfilterindex." self.nodes[0].assert_start_raises_init_error(expected_msg=msg) + self.log.info("Test unknown value to -blockfilterindex raises an error") + self.nodes[0].extra_args = ["-blockfilterindex=abc"] + msg = "Error: Unknown -blockfilterindex value abc." + self.nodes[0].assert_start_raises_init_error(expected_msg=msg) + self.log.info("Test -blockfilterindex with -reindex-chainstate raises an error") self.nodes[0].assert_start_raises_init_error( expected_msg='Error: -reindex-chainstate option is not compatible with -blockfilterindex. ' diff --git a/test/functional/rpc_mempool_entry_fee_fields_deprecation.py b/test/functional/rpc_mempool_entry_fee_fields_deprecation.py deleted file mode 100755 index 82761ff7c8..0000000000 --- a/test/functional/rpc_mempool_entry_fee_fields_deprecation.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2021 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Test deprecation of fee fields from top level mempool entry object""" - -from test_framework.blocktools import COIN -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal -from test_framework.wallet import MiniWallet - - -def assertions_helper(new_object, deprecated_object, deprecated_fields): - for field in deprecated_fields: - assert field in deprecated_object - assert field not in new_object - - -class MempoolFeeFieldsDeprecationTest(BitcoinTestFramework): - def set_test_params(self): - self.num_nodes = 2 - self.extra_args = [[], ["-deprecatedrpc=fees"]] - - def run_test(self): - # we get spendable outputs from the premined chain starting - # at block 76. see BitcoinTestFramework._initialize_chain() for details - self.wallet = MiniWallet(self.nodes[0]) - self.wallet.rescan_utxos() - - # we create the tx on the first node and wait until it syncs to node_deprecated - # thus, any differences must be coming from getmempoolentry or getrawmempool - tx = self.wallet.send_self_transfer(from_node=self.nodes[0]) - self.nodes[1].sendrawtransaction(tx["hex"]) - - deprecated_fields = ["ancestorfees", "descendantfees", "modifiedfee", "fee"] - self.test_getmempoolentry(tx["txid"], deprecated_fields) - self.test_getrawmempool(tx["txid"], deprecated_fields) - self.test_deprecated_fields_match(tx["txid"]) - - def test_getmempoolentry(self, txid, deprecated_fields): - - self.log.info("Test getmempoolentry rpc") - entry = self.nodes[0].getmempoolentry(txid) - deprecated_entry = self.nodes[1].getmempoolentry(txid) - assertions_helper(entry, deprecated_entry, deprecated_fields) - - def test_getrawmempool(self, txid, deprecated_fields): - - self.log.info("Test getrawmempool rpc") - entry = self.nodes[0].getrawmempool(verbose=True)[txid] - deprecated_entry = self.nodes[1].getrawmempool(verbose=True)[txid] - assertions_helper(entry, deprecated_entry, deprecated_fields) - - def test_deprecated_fields_match(self, txid): - - self.log.info("Test deprecated fee fields match new fees object") - entry = self.nodes[0].getmempoolentry(txid) - deprecated_entry = self.nodes[1].getmempoolentry(txid) - - assert_equal(deprecated_entry["fee"], entry["fees"]["base"]) - assert_equal(deprecated_entry["modifiedfee"], entry["fees"]["modified"]) - assert_equal(deprecated_entry["descendantfees"], entry["fees"]["descendant"] * COIN) - assert_equal(deprecated_entry["ancestorfees"], entry["fees"]["ancestor"] * COIN) - - -if __name__ == "__main__": - MempoolFeeFieldsDeprecationTest().main() diff --git a/test/functional/rpc_mempool_info.py b/test/functional/rpc_mempool_info.py new file mode 100755 index 0000000000..cd7a48d387 --- /dev/null +++ b/test/functional/rpc_mempool_info.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2022 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test RPCs that retrieve information from the mempool.""" + +from test_framework.blocktools import COINBASE_MATURITY +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + assert_raises_rpc_error, +) +from test_framework.wallet import MiniWallet + + +class RPCMempoolInfoTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + + def run_test(self): + self.wallet = MiniWallet(self.nodes[0]) + self.generate(self.wallet, COINBASE_MATURITY + 1) + self.wallet.rescan_utxos() + confirmed_utxo = self.wallet.get_utxo() + + # Create a tree of unconfirmed transactions in the mempool: + # txA + # / \ + # / \ + # / \ + # / \ + # / \ + # txB txC + # / \ / \ + # / \ / \ + # txD txE txF txG + # \ / + # \ / + # txH + + def create_tx(**kwargs): + return self.wallet.send_self_transfer_multi( + from_node=self.nodes[0], + **kwargs, + ) + + txA = create_tx(utxos_to_spend=[confirmed_utxo], num_outputs=2) + txB = create_tx(utxos_to_spend=[txA["new_utxos"][0]], num_outputs=2) + txC = create_tx(utxos_to_spend=[txA["new_utxos"][1]], num_outputs=2) + txD = create_tx(utxos_to_spend=[txB["new_utxos"][0]], num_outputs=1) + txE = create_tx(utxos_to_spend=[txB["new_utxos"][1]], num_outputs=1) + txF = create_tx(utxos_to_spend=[txC["new_utxos"][0]], num_outputs=2) + txG = create_tx(utxos_to_spend=[txC["new_utxos"][1]], num_outputs=1) + txH = create_tx(utxos_to_spend=[txE["new_utxos"][0],txF["new_utxos"][0]], num_outputs=1) + txidA, txidB, txidC, txidD, txidE, txidF, txidG, txidH = [ + tx["txid"] for tx in [txA, txB, txC, txD, txE, txF, txG, txH] + ] + + mempool = self.nodes[0].getrawmempool() + assert_equal(len(mempool), 8) + for txid in [txidA, txidB, txidC, txidD, txidE, txidF, txidG, txidH]: + assert_equal(txid in mempool, True) + + self.log.info("Find transactions spending outputs") + result = self.nodes[0].gettxspendingprevout([ {'txid' : confirmed_utxo['txid'], 'vout' : 0}, {'txid' : txidA, 'vout' : 1} ]) + assert_equal(result, [ {'txid' : confirmed_utxo['txid'], 'vout' : 0, 'spendingtxid' : txidA}, {'txid' : txidA, 'vout' : 1, 'spendingtxid' : txidC} ]) + + self.log.info("Find transaction spending multiple outputs") + result = self.nodes[0].gettxspendingprevout([ {'txid' : txidE, 'vout' : 0}, {'txid' : txidF, 'vout' : 0} ]) + assert_equal(result, [ {'txid' : txidE, 'vout' : 0, 'spendingtxid' : txidH}, {'txid' : txidF, 'vout' : 0, 'spendingtxid' : txidH} ]) + + self.log.info("Find no transaction when output is unspent") + result = self.nodes[0].gettxspendingprevout([ {'txid' : txidH, 'vout' : 0} ]) + assert_equal(result, [ {'txid' : txidH, 'vout' : 0} ]) + result = self.nodes[0].gettxspendingprevout([ {'txid' : txidA, 'vout' : 5} ]) + assert_equal(result, [ {'txid' : txidA, 'vout' : 5} ]) + + self.log.info("Mixed spent and unspent outputs") + result = self.nodes[0].gettxspendingprevout([ {'txid' : txidB, 'vout' : 0}, {'txid' : txidG, 'vout' : 3} ]) + assert_equal(result, [ {'txid' : txidB, 'vout' : 0, 'spendingtxid' : txidD}, {'txid' : txidG, 'vout' : 3} ]) + + self.log.info("Unknown input fields") + assert_raises_rpc_error(-3, "Unexpected key unknown", self.nodes[0].gettxspendingprevout, [{'txid' : txidC, 'vout' : 1, 'unknown' : 42}]) + + self.log.info("Invalid vout provided") + assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", self.nodes[0].gettxspendingprevout, [{'txid' : txidA, 'vout' : -1}]) + + self.log.info("Invalid txid provided") + assert_raises_rpc_error(-3, "Expected type string for txid, got number", self.nodes[0].gettxspendingprevout, [{'txid' : 42, 'vout' : 0}]) + + self.log.info("Missing outputs") + assert_raises_rpc_error(-8, "Invalid parameter, outputs are missing", self.nodes[0].gettxspendingprevout, []) + + self.log.info("Missing vout") + assert_raises_rpc_error(-3, "Missing vout", self.nodes[0].gettxspendingprevout, [{'txid' : txidA}]) + + self.log.info("Missing txid") + assert_raises_rpc_error(-3, "Missing txid", self.nodes[0].gettxspendingprevout, [{'vout' : 3}]) + + +if __name__ == '__main__': + RPCMempoolInfoTest().main() diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index a839af0288..fecb8310b9 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -24,7 +24,10 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_rpc_error, - find_vout_for_address, +) +from test_framework.wallet import ( + getnewdestination, + MiniWallet, ) @@ -52,79 +55,67 @@ class multidict(dict): class RawTransactionsTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 + self.num_nodes = 3 self.extra_args = [ ["-txindex"], ["-txindex"], - ["-txindex"], [], ] # whitelist all peers to speed up tx relay / mempool sync for args in self.extra_args: args.append("-whitelist=noban@127.0.0.1") + self.requires_wallet = self.is_specified_wallet_compiled() self.supports_cli = False - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def setup_network(self): super().setup_network() self.connect_nodes(0, 2) def run_test(self): + self.wallet = MiniWallet(self.nodes[0]) self.log.info("Prepare some coins for multiple *rawtransaction commands") - self.generate(self.nodes[2], 1) + self.generate(self.wallet, 10) self.generate(self.nodes[0], COINBASE_MATURITY + 1) - for amount in [1.5, 1.0, 5.0]: - self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), amount) - self.sync_all() - self.generate(self.nodes[0], 5) self.getrawtransaction_tests() self.createrawtransaction_tests() - self.signrawtransactionwithwallet_tests() self.sendrawtransaction_tests() self.sendrawtransaction_testmempoolaccept_tests() self.decoderawtransaction_tests() self.transaction_version_number_tests() - if not self.options.descriptors: + if self.requires_wallet and not self.options.descriptors: self.raw_multisig_transaction_legacy_tests() def getrawtransaction_tests(self): - addr = self.nodes[1].getnewaddress() - txid = self.nodes[0].sendtoaddress(addr, 10) + tx = self.wallet.send_self_transfer(from_node=self.nodes[0]) self.generate(self.nodes[0], 1) - vout = find_vout_for_address(self.nodes[1], txid, addr) - rawTx = self.nodes[1].createrawtransaction([{'txid': txid, 'vout': vout}], {self.nodes[1].getnewaddress(): 9.999}) - rawTxSigned = self.nodes[1].signrawtransactionwithwallet(rawTx) - txId = self.nodes[1].sendrawtransaction(rawTxSigned['hex']) - self.generateblock(self.nodes[0], output=self.nodes[0].getnewaddress(), transactions=[rawTxSigned['hex']]) + txId = tx['txid'] err_msg = ( "No such mempool transaction. Use -txindex or provide a block hash to enable" " blockchain transaction queries. Use gettransaction for wallet transactions." ) - for n in [0, 3]: + for n in [0, 2]: self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex") if n == 0: # With -txindex. # 1. valid parameters - only supply txid - assert_equal(self.nodes[n].getrawtransaction(txId), rawTxSigned['hex']) + assert_equal(self.nodes[n].getrawtransaction(txId), tx['hex']) # 2. valid parameters - supply txid and 0 for non-verbose - assert_equal(self.nodes[n].getrawtransaction(txId, 0), rawTxSigned['hex']) + assert_equal(self.nodes[n].getrawtransaction(txId, 0), tx['hex']) # 3. valid parameters - supply txid and False for non-verbose - assert_equal(self.nodes[n].getrawtransaction(txId, False), rawTxSigned['hex']) + assert_equal(self.nodes[n].getrawtransaction(txId, False), tx['hex']) # 4. valid parameters - supply txid and 1 for verbose. # We only check the "hex" field of the output so we don't need to update this test every time the output format changes. - assert_equal(self.nodes[n].getrawtransaction(txId, 1)["hex"], rawTxSigned['hex']) + assert_equal(self.nodes[n].getrawtransaction(txId, 1)["hex"], tx['hex']) # 5. valid parameters - supply txid and True for non-verbose - assert_equal(self.nodes[n].getrawtransaction(txId, True)["hex"], rawTxSigned['hex']) + assert_equal(self.nodes[n].getrawtransaction(txId, True)["hex"], tx['hex']) else: # Without -txindex, expect to raise. for verbose in [None, 0, False, 1, True]: @@ -141,9 +132,9 @@ class RawTransactionsTest(BitcoinTestFramework): assert_raises_rpc_error(-1, "not a boolean", self.nodes[n].getrawtransaction, txId, {}) # Make a tx by sending, then generate 2 blocks; block1 has the tx in it - tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1) + tx = self.wallet.send_self_transfer(from_node=self.nodes[2])['txid'] block1, block2 = self.generate(self.nodes[2], 2) - for n in [0, 3]: + for n in [0, 2]: self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex, with blockhash") # We should be able to get the raw transaction by providing the correct block gottx = self.nodes[n].getrawtransaction(txid=tx, verbose=True, blockhash=block1) @@ -200,20 +191,21 @@ class RawTransactionsTest(BitcoinTestFramework): # sequence number out of range for invalid_seq in [-1, 4294967296]: inputs = [{'txid': TXID, 'vout': 1, 'sequence': invalid_seq}] - outputs = {self.nodes[0].getnewaddress(): 1} + address = getnewdestination()[2] + outputs = {address: 1} assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) # with valid sequence number for valid_seq in [1000, 4294967294]: inputs = [{'txid': TXID, 'vout': 1, 'sequence': valid_seq}] - outputs = {self.nodes[0].getnewaddress(): 1} + address = getnewdestination()[2] + outputs = {address: 1} rawtx = self.nodes[0].createrawtransaction(inputs, outputs) decrawtx = self.nodes[0].decoderawtransaction(rawtx) assert_equal(decrawtx['vin'][0]['sequence'], valid_seq) # Test `createrawtransaction` invalid `outputs` - address = self.nodes[0].getnewaddress() - address2 = self.nodes[0].getnewaddress() + address = getnewdestination()[2] assert_raises_rpc_error(-1, "JSON value is not an array as expected", self.nodes[0].createrawtransaction, [], 'foo') self.nodes[0].createrawtransaction(inputs=[], outputs={}) # Should not throw for backwards compatibility self.nodes[0].createrawtransaction(inputs=[], outputs=[]) @@ -245,6 +237,7 @@ class RawTransactionsTest(BitcoinTestFramework): self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=[{address: 99}]), ) # Two outputs + address2 = getnewdestination()[2] tx = tx_from_hex(self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=OrderedDict([(address, 99), (address2, 99)]))) assert_equal(len(tx.vout), 2) assert_equal( @@ -259,122 +252,53 @@ class RawTransactionsTest(BitcoinTestFramework): self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=[{address: 99}, {address2: 99}, {'data': '99'}]), ) - def signrawtransactionwithwallet_tests(self): - for type in ["bech32", "p2sh-segwit", "legacy"]: - self.log.info(f"Test signrawtransactionwithwallet with missing prevtx info ({type})") - addr = self.nodes[0].getnewaddress("", type) - addrinfo = self.nodes[0].getaddressinfo(addr) - pubkey = addrinfo["scriptPubKey"] - inputs = [{'txid': TXID, 'vout': 3, 'sequence': 1000}] - outputs = {self.nodes[0].getnewaddress(): 1} - rawtx = self.nodes[0].createrawtransaction(inputs, outputs) - - prevtx = dict(txid=TXID, scriptPubKey=pubkey, vout=3, amount=1) - succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx]) - assert succ["complete"] - - if type == "legacy": - del prevtx["amount"] - succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx]) - assert succ["complete"] - else: - assert_raises_rpc_error(-3, "Missing amount", self.nodes[0].signrawtransactionwithwallet, rawtx, [ - { - "txid": TXID, - "scriptPubKey": pubkey, - "vout": 3, - } - ]) - - assert_raises_rpc_error(-3, "Missing vout", self.nodes[0].signrawtransactionwithwallet, rawtx, [ - { - "txid": TXID, - "scriptPubKey": pubkey, - "amount": 1, - } - ]) - assert_raises_rpc_error(-3, "Missing txid", self.nodes[0].signrawtransactionwithwallet, rawtx, [ - { - "scriptPubKey": pubkey, - "vout": 3, - "amount": 1, - } - ]) - assert_raises_rpc_error(-3, "Missing scriptPubKey", self.nodes[0].signrawtransactionwithwallet, rawtx, [ - { - "txid": TXID, - "vout": 3, - "amount": 1 - } - ]) - def sendrawtransaction_tests(self): self.log.info("Test sendrawtransaction with missing input") inputs = [{'txid': TXID, 'vout': 1}] # won't exist - outputs = {self.nodes[0].getnewaddress(): 4.998} + address = getnewdestination()[2] + outputs = {address: 4.998} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) - rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx) - assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[2].sendrawtransaction, rawtx['hex']) + assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[2].sendrawtransaction, rawtx) 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. - txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0) - rawTx = self.nodes[0].getrawtransaction(txId, True) - vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('1.00000000')) - - self.sync_all() - inputs = [{"txid": txId, "vout": vout['n']}] - # Fee 10,000 satoshis, (1 - (10000 sat * 0.00000001 BTC/sat)) = 0.9999 - outputs = {self.nodes[0].getnewaddress(): Decimal("0.99990000")} - rawTx = self.nodes[2].createrawtransaction(inputs, outputs) - rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx) - assert_equal(rawTxSigned['complete'], True) - # Fee 10,000 satoshis, ~100 b transaction, fee rate should land around 100 sat/byte = 0.00100000 BTC/kB + # 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([rawTxSigned['hex']], 0.00001000)[0] + testres = self.nodes[2].testmempoolaccept([tx['hex']], 0.00001000)[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, rawTxSigned['hex'], 0.00001000) + assert_raises_rpc_error(-25, fee_exceeds_max, self.nodes[2].sendrawtransaction, tx['hex'], 0.00001000) # and the following calls should both succeed - testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']])[0] + testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']])[0] assert_equal(testres['allowed'], True) - self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex']) + self.nodes[2].sendrawtransaction(hexstring=tx['hex']) # Test a transaction with a large fee. - txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0) - rawTx = self.nodes[0].getrawtransaction(txId, True) - vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('1.00000000')) - - self.sync_all() - inputs = [{"txid": txId, "vout": vout['n']}] - # Fee 2,000,000 satoshis, (1 - (2000000 sat * 0.00000001 BTC/sat)) = 0.98 - outputs = {self.nodes[0].getnewaddress() : Decimal("0.98000000")} - rawTx = self.nodes[2].createrawtransaction(inputs, outputs) - rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx) - assert_equal(rawTxSigned['complete'], True) - # Fee 2,000,000 satoshis, ~100 b transaction, fee rate should land around 20,000 sat/byte = 0.20000000 BTC/kB + # Fee rate is 0.20000000 BTC/kvB + tx = self.wallet.create_self_transfer(mempool_valid=False, from_node=self.nodes[0], fee_rate=Decimal('0.20000000')) # Thus, testmempoolaccept should reject - testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0] + testres = self.nodes[2].testmempoolaccept([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, rawTxSigned['hex']) + 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=[rawTxSigned['hex']], maxfeerate='0.20000000')[0] + testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']], maxfeerate='0.20000000')[0] assert_equal(testres['allowed'], True) - self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'], maxfeerate='0.20000000') + self.nodes[2].sendrawtransaction(hexstring=tx['hex'], maxfeerate='0.20000000') self.log.info("Test sendrawtransaction/testmempoolaccept with tx already in the chain") self.generate(self.nodes[2], 1) for node in self.nodes: - testres = node.testmempoolaccept([rawTxSigned['hex']])[0] + testres = node.testmempoolaccept([tx['hex']])[0] assert_equal(testres['allowed'], False) assert_equal(testres['reject-reason'], 'txn-already-known') - assert_raises_rpc_error(-27, 'Transaction already in block chain', node.sendrawtransaction, rawTxSigned['hex']) + assert_raises_rpc_error(-27, 'Transaction already in block chain', node.sendrawtransaction, tx['hex']) def decoderawtransaction_tests(self): self.log.info("Test decoderawtransaction") diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index a2091b4ece..8da2cfa72b 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -334,6 +334,56 @@ class SignRawTransactionsTest(BitcoinTestFramework): assert_equal(signed["complete"], True) self.nodes[0].sendrawtransaction(signed["hex"]) + def test_signing_with_missing_prevtx_info(self): + txid = "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000" + for type in ["bech32", "p2sh-segwit", "legacy"]: + self.log.info(f"Test signing with missing prevtx info ({type})") + addr = self.nodes[0].getnewaddress("", type) + addrinfo = self.nodes[0].getaddressinfo(addr) + pubkey = addrinfo["scriptPubKey"] + inputs = [{'txid': txid, 'vout': 3, 'sequence': 1000}] + outputs = {self.nodes[0].getnewaddress(): 1} + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + + prevtx = dict(txid=txid, scriptPubKey=pubkey, vout=3, amount=1) + succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx]) + assert succ["complete"] + + if type == "legacy": + del prevtx["amount"] + succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx]) + assert succ["complete"] + else: + assert_raises_rpc_error(-3, "Missing amount", self.nodes[0].signrawtransactionwithwallet, rawtx, [ + { + "txid": txid, + "scriptPubKey": pubkey, + "vout": 3, + } + ]) + + assert_raises_rpc_error(-3, "Missing vout", self.nodes[0].signrawtransactionwithwallet, rawtx, [ + { + "txid": txid, + "scriptPubKey": pubkey, + "amount": 1, + } + ]) + assert_raises_rpc_error(-3, "Missing txid", self.nodes[0].signrawtransactionwithwallet, rawtx, [ + { + "scriptPubKey": pubkey, + "vout": 3, + "amount": 1, + } + ]) + assert_raises_rpc_error(-3, "Missing scriptPubKey", self.nodes[0].signrawtransactionwithwallet, rawtx, [ + { + "txid": txid, + "vout": 3, + "amount": 1 + } + ]) + def run_test(self): self.successful_signing_test() self.script_verification_error_test() @@ -343,6 +393,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): self.test_fully_signed_tx() self.test_signing_with_csv() self.test_signing_with_cltv() + self.test_signing_with_missing_prevtx_info() if __name__ == '__main__': diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 8416a5881d..40e08c3f1f 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -183,7 +183,6 @@ BASE_SCRIPTS = [ 'rpc_signrawtransaction.py --legacy-wallet', 'rpc_signrawtransaction.py --descriptors', 'rpc_rawtransaction.py --legacy-wallet', - 'rpc_rawtransaction.py --descriptors', 'wallet_groups.py --legacy-wallet', 'wallet_transactiontime_rescan.py --descriptors', 'wallet_transactiontime_rescan.py --legacy-wallet', @@ -328,7 +327,7 @@ BASE_SCRIPTS = [ 'feature_presegwit_node_upgrade.py', 'feature_settings.py', 'rpc_getdescriptorinfo.py', - 'rpc_mempool_entry_fee_fields_deprecation.py', + 'rpc_mempool_info.py', 'rpc_help.py', 'feature_dirsymlinks.py', 'feature_help.py', diff --git a/test/lint/lint-logs.py b/test/lint/lint-logs.py index e6c4c068fb..de53729b4e 100755 --- a/test/lint/lint-logs.py +++ b/test/lint/lint-logs.py @@ -16,12 +16,12 @@ from subprocess import check_output def main(): - logs_list = check_output(["git", "grep", "--extended-regexp", r"LogPrintf?\(", "--", "*.cpp"], universal_newlines=True, encoding="utf8").splitlines() + logs_list = check_output(["git", "grep", "--extended-regexp", r"(LogPrintLevel|LogPrintf?)\(", "--", "*.cpp"], universal_newlines=True, encoding="utf8").splitlines() unterminated_logs = [line for line in logs_list if not re.search(r'(\\n"|/\* Continued \*/)', line)] if unterminated_logs != []: - print("All calls to LogPrintf() and LogPrint() should be terminated with \\n") + print("All calls to LogPrintf(), LogPrint(), LogPrintLevel(), and WalletLogPrintf() should be terminated with \"\\n\".") print("") for line in unterminated_logs: |