diff options
Diffstat (limited to 'test')
32 files changed, 292 insertions, 109 deletions
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py index 8a8a0c7614..8f522aee66 100755 --- a/test/functional/feature_fee_estimation.py +++ b/test/functional/feature_fee_estimation.py @@ -13,6 +13,7 @@ from test_framework.util import ( assert_equal, assert_greater_than, assert_greater_than_or_equal, + assert_raises_rpc_error, satoshi_round, ) @@ -262,6 +263,11 @@ class EstimateFeeTest(BitcoinTestFramework): self.log.info("Final estimates after emptying mempools") check_estimates(self.nodes[1], self.fees_per_kb) + self.log.info("Testing that fee estimation is disabled in blocksonly.") + self.restart_node(0, ["-blocksonly"]) + assert_raises_rpc_error(-32603, "Fee estimation disabled", + self.nodes[0].estimatesmartfee, 2) + if __name__ == '__main__': EstimateFeeTest().main() diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py index 0f0fe8a34a..6ee2b72c11 100755 --- a/test/functional/feature_taproot.py +++ b/test/functional/feature_taproot.py @@ -444,6 +444,8 @@ def make_spender(comment, *, tap=None, witv0=False, script=None, pkh=None, p2sh= * standard: whether the (valid version of) spending is expected to be standard * err_msg: a string with an expected error message for failure (or None, if not cared about) * sigops_weight: the pre-taproot sigops weight consumed by a successful spend + * need_vin_vout_mismatch: whether this test requires being tested in a transaction input that has no corresponding + transaction output. """ conf = dict() @@ -1442,6 +1444,10 @@ class TaprootTest(BitcoinTestFramework): self.nodes[1].generate(101) self.test_spenders(self.nodes[1], spenders_taproot_active(), input_counts=[1, 2, 2, 2, 2, 3]) + # Re-connect nodes in case they have been disconnected + self.disconnect_nodes(0, 1) + self.connect_nodes(0, 1) + # Transfer value of the largest 500 coins to pre-taproot node. addr = self.nodes[0].getnewaddress() diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index 80f262d0d3..91fbd722cf 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -19,8 +19,11 @@ from test_framework.util import ( ) import time +# Keep this with length <= 10. Addresses from larger messages are not relayed. ADDRS = [] -for i in range(10): +num_ipv4_addrs = 10 + +for i in range(num_ipv4_addrs): addr = CAddress() addr.time = int(time.time()) + i addr.nServices = NODE_NETWORK | NODE_WITNESS @@ -30,11 +33,15 @@ for i in range(10): class AddrReceiver(P2PInterface): + num_ipv4_received = 0 + def on_addr(self, message): for addr in message.addrs: assert_equal(addr.nServices, 9) + if not 8333 <= addr.port < 8343: + raise AssertionError("Invalid addr.port of {} (8333-8342 expected)".format(addr.port)) assert addr.ip.startswith('123.123.123.') - assert (8333 <= addr.port < 8343) + self.num_ipv4_received += 1 class AddrTest(BitcoinTestFramework): @@ -48,21 +55,33 @@ class AddrTest(BitcoinTestFramework): msg = msg_addr() self.log.info('Send too-large addr message') - msg.addrs = ADDRS * 101 + msg.addrs = ADDRS * 101 # more than 1000 addresses in one message with self.nodes[0].assert_debug_log(['addr message size = 1010']): addr_source.send_and_ping(msg) self.log.info('Check that addr message content is relayed and added to addrman') - addr_receiver = self.nodes[0].add_p2p_connection(AddrReceiver()) + num_receivers = 7 + receivers = [] + for _ in range(num_receivers): + receivers.append(self.nodes[0].add_p2p_connection(AddrReceiver())) msg.addrs = ADDRS - with self.nodes[0].assert_debug_log([ - 'Added 10 addresses from 127.0.0.1: 0 tried', + with self.nodes[0].assert_debug_log( + [ + 'Added {} addresses from 127.0.0.1: 0 tried'.format(num_ipv4_addrs), 'received: addr (301 bytes) peer=0', - 'sending addr (301 bytes) peer=1', - ]): + ] + ): addr_source.send_and_ping(msg) self.nodes[0].setmocktime(int(time.time()) + 30 * 60) - addr_receiver.sync_with_ping() + for receiver in receivers: + receiver.sync_with_ping() + + total_ipv4_received = sum(r.num_ipv4_received for r in receivers) + + # Every IPv4 address must be relayed to two peers, other than the + # originating node (addr_source). + ipv4_branching_factor = 2 + assert_equal(total_ipv4_received, num_ipv4_addrs * ipv4_branching_factor) if __name__ == '__main__': diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index 611bffb25f..9a9df73049 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -764,6 +764,34 @@ class CompactBlocksTest(BitcoinTestFramework): stalling_peer.send_and_ping(msg) assert_equal(int(node.getbestblockhash(), 16), block.sha256) + def test_highbandwidth_mode_states_via_getpeerinfo(self): + # create new p2p connection for a fresh state w/o any prior sendcmpct messages sent + hb_test_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=2)) + + # assert the RPC getpeerinfo boolean fields `bip152_hb_{to, from}` + # match the given parameters for the last peer of a given node + def assert_highbandwidth_states(node, hb_to, hb_from): + peerinfo = node.getpeerinfo()[-1] + assert_equal(peerinfo['bip152_hb_to'], hb_to) + assert_equal(peerinfo['bip152_hb_from'], hb_from) + + # initially, neither node has selected the other peer as high-bandwidth yet + assert_highbandwidth_states(self.nodes[0], hb_to=False, hb_from=False) + + # peer requests high-bandwidth mode by sending sendcmpct(1) + hb_test_node.send_and_ping(msg_sendcmpct(announce=True, version=2)) + assert_highbandwidth_states(self.nodes[0], hb_to=False, hb_from=True) + + # peer generates a block and sends it to node, which should + # select the peer as high-bandwidth (up to 3 peers according to BIP 152) + block = self.build_block_on_tip(self.nodes[0]) + hb_test_node.send_and_ping(msg_block(block)) + assert_highbandwidth_states(self.nodes[0], hb_to=True, hb_from=True) + + # peer requests low-bandwidth mode by sending sendcmpct(0) + hb_test_node.send_and_ping(msg_sendcmpct(announce=False, version=2)) + assert_highbandwidth_states(self.nodes[0], hb_to=True, hb_from=False) + def run_test(self): # Get the nodes out of IBD self.nodes[0].generate(1) @@ -822,6 +850,9 @@ class CompactBlocksTest(BitcoinTestFramework): self.log.info("Testing invalid index in cmpctblock message...") self.test_invalid_cmpctblock_message() + self.log.info("Testing high-bandwidth mode states via getpeerinfo...") + self.test_highbandwidth_mode_states_via_getpeerinfo() + if __name__ == '__main__': CompactBlocksTest().main() diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py index f60eba2dbf..9614ab6872 100755 --- a/test/functional/p2p_fingerprint.py +++ b/test/functional/p2p_fingerprint.py @@ -98,9 +98,9 @@ class P2PFingerprintTest(BitcoinTestFramework): # Longest chain is extended so stale is much older than chain tip self.nodes[0].setmocktime(0) - self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address) + block_hash = int(self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[-1], 16) assert_equal(self.nodes[0].getblockcount(), 14) - node0.sync_with_ping() + node0.wait_for_block(block_hash, timeout=3) # Request for very old stale block should now fail with p2p_lock: @@ -128,5 +128,6 @@ class P2PFingerprintTest(BitcoinTestFramework): self.send_header_request(block_hash, node0) node0.wait_for_header(hex(block_hash), timeout=3) + if __name__ == '__main__': P2PFingerprintTest().main() diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py index db72a361d9..c0b3c2cb12 100755 --- a/test/functional/p2p_invalid_messages.py +++ b/test/functional/p2p_invalid_messages.py @@ -18,6 +18,7 @@ from test_framework.messages import ( msg_inv, msg_ping, MSG_TX, + msg_version, ser_string, ) from test_framework.p2p import ( @@ -60,6 +61,7 @@ class InvalidMessagesTest(BitcoinTestFramework): def run_test(self): self.test_buffer() + self.test_duplicate_version_msg() self.test_magic_bytes() self.test_checksum() self.test_size() @@ -92,6 +94,13 @@ class InvalidMessagesTest(BitcoinTestFramework): conn.sync_with_ping(timeout=1) self.nodes[0].disconnect_p2ps() + def test_duplicate_version_msg(self): + self.log.info("Test duplicate version message is ignored") + conn = self.nodes[0].add_p2p_connection(P2PDataStore()) + with self.nodes[0].assert_debug_log(['redundant version message from peer']): + conn.send_and_ping(msg_version()) + self.nodes[0].disconnect_p2ps() + def test_magic_bytes(self): self.log.info("Test message with invalid magic bytes disconnects peer") conn = self.nodes[0].add_p2p_connection(P2PDataStore()) diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index 4b32d60db0..ca8bf908a9 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -24,8 +24,6 @@ from test_framework.util import ( assert_greater_than_or_equal, ) -DISCOURAGEMENT_THRESHOLD = 100 - class LazyPeer(P2PInterface): def __init__(self): @@ -93,27 +91,16 @@ class P2PLeakTest(BitcoinTestFramework): self.num_nodes = 1 def run_test(self): - # Peer that never sends a version. We will send a bunch of messages - # from this peer anyway and verify eventual disconnection. - no_version_disconnect_peer = self.nodes[0].add_p2p_connection( - LazyPeer(), send_version=False, wait_for_verack=False) - # Another peer that never sends a version, nor any other messages. It shouldn't receive anything from the node. no_version_idle_peer = self.nodes[0].add_p2p_connection(LazyPeer(), send_version=False, wait_for_verack=False) # Peer that sends a version but not a verack. no_verack_idle_peer = self.nodes[0].add_p2p_connection(NoVerackIdlePeer(), wait_for_verack=False) - # Send enough ping messages (any non-version message will do) prior to sending - # version to reach the peer discouragement threshold. This should get us disconnected. - for _ in range(DISCOURAGEMENT_THRESHOLD): - no_version_disconnect_peer.send_message(msg_ping()) - # Wait until we got the verack in response to the version. Though, don't wait for the node to receive the # verack, since we never sent one no_verack_idle_peer.wait_for_verack() - no_version_disconnect_peer.wait_until(lambda: no_version_disconnect_peer.ever_connected, check_connected=False) no_version_idle_peer.wait_until(lambda: no_version_idle_peer.ever_connected) no_verack_idle_peer.wait_until(lambda: no_verack_idle_peer.version_received) @@ -123,13 +110,9 @@ class P2PLeakTest(BitcoinTestFramework): #Give the node enough time to possibly leak out a message time.sleep(5) - # Expect this peer to be disconnected for misbehavior - assert not no_version_disconnect_peer.is_connected - self.nodes[0].disconnect_p2ps() # Make sure no unexpected messages came in - assert no_version_disconnect_peer.unexpected_msg == False assert no_version_idle_peer.unexpected_msg == False assert no_verack_idle_peer.unexpected_msg == False @@ -148,7 +131,7 @@ class P2PLeakTest(BitcoinTestFramework): p2p_old_peer = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False) old_version_msg = msg_version() old_version_msg.nVersion = 31799 - with self.nodes[0].assert_debug_log(['peer=4 using obsolete version 31799; disconnecting']): + with self.nodes[0].assert_debug_log(['peer=3 using obsolete version 31799; disconnecting']): p2p_old_peer.send_message(old_version_msg) p2p_old_peer.wait_for_disconnect() diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py index ce12ce26ce..47832b04bf 100755 --- a/test/functional/p2p_timeouts.py +++ b/test/functional/p2p_timeouts.py @@ -57,8 +57,10 @@ class TimeoutsTest(BitcoinTestFramework): assert no_version_node.is_connected assert no_send_node.is_connected - no_verack_node.send_message(msg_ping()) - no_version_node.send_message(msg_ping()) + with self.nodes[0].assert_debug_log(['Unsupported message "ping" prior to verack from peer=0']): + no_verack_node.send_message(msg_ping()) + with self.nodes[0].assert_debug_log(['non-version message before version handshake. Message "ping" from peer=1']): + no_version_node.send_message(msg_ping()) sleep(1) diff --git a/test/functional/rpc_estimatefee.py b/test/functional/rpc_estimatefee.py index 3b76c7dd1e..81862ac69e 100755 --- a/test/functional/rpc_estimatefee.py +++ b/test/functional/rpc_estimatefee.py @@ -41,6 +41,8 @@ class EstimateFeeTest(BitcoinTestFramework): self.nodes[0].estimatesmartfee(1) # self.nodes[0].estimatesmartfee(1, None) self.nodes[0].estimatesmartfee(1, 'ECONOMICAL') + self.nodes[0].estimatesmartfee(1, 'unset') + self.nodes[0].estimatesmartfee(1, 'conservative') self.nodes[0].estimaterawfee(1) self.nodes[0].estimaterawfee(1, None) diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index 8ee0ecab0a..569471dc87 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -717,10 +717,10 @@ class RawTransactionsTest(BitcoinTestFramework): result = node.fundrawtransaction(rawtx) # uses self.min_relay_tx_fee (set by settxfee) btc_kvb_to_sat_vb = 100000 # (1e5) - result1 = node.fundrawtransaction(rawtx, {"fee_rate": 2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee}) + result1 = node.fundrawtransaction(rawtx, {"fee_rate": str(2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee)}) result2 = node.fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee}) result3 = node.fundrawtransaction(rawtx, {"fee_rate": 10 * btc_kvb_to_sat_vb * self.min_relay_tx_fee}) - result4 = node.fundrawtransaction(rawtx, {"feeRate": 10 * self.min_relay_tx_fee}) + result4 = node.fundrawtransaction(rawtx, {"feeRate": str(10 * self.min_relay_tx_fee)}) # Test that funding non-standard "zero-fee" transactions is valid. result5 = self.nodes[3].fundrawtransaction(rawtx, {"fee_rate": 0}) result6 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 0}) diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 5840801b00..b364077a9a 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -190,11 +190,11 @@ class PSBTTest(BitcoinTestFramework): self.log.info("Test walletcreatefundedpsbt fee rate of 10000 sat/vB and 0.1 BTC/kvB produces a total fee at or slightly below -maxtxfee (~0.05290000)") res1 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"fee_rate": 10000, "add_inputs": True}) assert_approx(res1["fee"], 0.055, 0.005) - res2 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": 0.1, "add_inputs": True}) + res2 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": "0.1", "add_inputs": True}) assert_approx(res2["fee"], 0.055, 0.005) self.log.info("Test min fee rate checks with walletcreatefundedpsbt are bypassed, e.g. a fee_rate under 1 sat/vB is allowed") - res3 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"fee_rate": 0.99999999, "add_inputs": True}) + res3 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"fee_rate": "0.99999999", "add_inputs": True}) assert_approx(res3["fee"], 0.00000381, 0.0000001) res4 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": 0.00000999, "add_inputs": True}) assert_approx(res4["fee"], 0.00000381, 0.0000001) diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 554c30c0d2..60e66a27c9 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -372,6 +372,13 @@ class RawTransactionsTest(BitcoinTestFramework): encrawtx = "01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000" decrawtx = self.nodes[0].decoderawtransaction(encrawtx, False) # decode as non-witness transaction assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000')) + # known ambiguous transaction in the chain (see https://github.com/bitcoin/bitcoin/issues/20579) + encrawtx = "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4b03c68708046ff8415c622f4254432e434f4d2ffabe6d6de1965d02c68f928e5b244ab1965115a36f56eb997633c7f690124bbf43644e23080000000ca3d3af6d005a65ff0200fd00000000ffffffff03f4c1fb4b0000000016001497cfc76442fe717f2a3f0cc9c175f7561b6619970000000000000000266a24aa21a9ed957d1036a80343e0d1b659497e1b48a38ebe876a056d45965fac4a85cda84e1900000000000000002952534b424c4f434b3a8e092581ab01986cbadc84f4b43f4fa4bb9e7a2e2a0caf9b7cf64d939028e22c0120000000000000000000000000000000000000000000000000000000000000000000000000" + decrawtx = self.nodes[0].decoderawtransaction(encrawtx) + decrawtx_wit = self.nodes[0].decoderawtransaction(encrawtx, True) + assert_raises_rpc_error(-22, 'TX decode failed', self.nodes[0].decoderawtransaction, encrawtx, False) # fails to decode as non-witness transaction + assert_equal(decrawtx, decrawtx_wit) # the witness interpretation should be chosen + assert_equal(decrawtx['vin'][0]['coinbase'], "03c68708046ff8415c622f4254432e434f4d2ffabe6d6de1965d02c68f928e5b244ab1965115a36f56eb997633c7f690124bbf43644e23080000000ca3d3af6d005a65ff0200fd00000000") # Basic signrawtransaction test addr = self.nodes[1].getnewaddress() diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index b962e1c3a5..2fbbdbbdf0 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -151,6 +151,19 @@ class SignRawTransactionsTest(BitcoinTestFramework): assert_equal(rawTxSigned['errors'][1]['witness'], ["304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01", "025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357"]) assert not rawTxSigned['errors'][0]['witness'] + def test_fully_signed_tx(self): + self.log.info("Test signing a fully signed transaction does nothing") + self.nodes[0].walletpassphrase("password", 9999) + self.nodes[0].generate(101) + rawtx = self.nodes[0].createrawtransaction([], [{self.nodes[0].getnewaddress(): 10}]) + fundedtx = self.nodes[0].fundrawtransaction(rawtx) + signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx["hex"]) + assert_equal(signedtx["complete"], True) + signedtx2 = self.nodes[0].signrawtransactionwithwallet(signedtx["hex"]) + assert_equal(signedtx2["complete"], True) + assert_equal(signedtx["hex"], signedtx2["hex"]) + self.nodes[0].walletlock() + def witness_script_test(self): self.log.info("Test signing transaction to P2SH-P2WSH addresses without wallet") # Create a new P2SH-P2WSH 1-of-1 multisig address: @@ -231,6 +244,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): self.witness_script_test() self.OP_1NEGATE_test() self.test_with_lock_outputs() + self.test_fully_signed_tx() if __name__ == '__main__': diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py index 93fb62c5d6..2d6ce77613 100755 --- a/test/functional/rpc_txoutproof.py +++ b/test/functional/rpc_txoutproof.py @@ -78,7 +78,7 @@ class MerkleBlockTest(BitcoinTestFramework): # We can't get a proof if we specify transactions from different blocks assert_raises_rpc_error(-5, "Not all transactions found in specified or retrieved block", self.nodes[0].gettxoutproof, [txid1, txid3]) # Test empty list - assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[0].gettxoutproof, []) + assert_raises_rpc_error(-8, "Parameter 'txids' cannot be empty", self.nodes[0].gettxoutproof, []) # Test duplicate txid assert_raises_rpc_error(-8, 'Invalid parameter, duplicated txid', self.nodes[0].gettxoutproof, [txid1, txid1]) diff --git a/test/functional/rpc_users.py b/test/functional/rpc_users.py index daf02fc4f3..108af2cac8 100755 --- a/test/functional/rpc_users.py +++ b/test/functional/rpc_users.py @@ -99,11 +99,18 @@ class HTTPBasicsTest(BitcoinTestFramework): self.test_auth(self.nodes[1], self.rpcuser, self.rpcpassword) - self.log.info('Check that failure to write cookie file will abort the node gracefully') + init_error = 'Error: Unable to start HTTP server. See debug log for details.' + + self.log.info('Check -rpcauth are validated') + # Empty -rpcauth= are ignored + self.restart_node(0, extra_args=['-rpcauth=']) self.stop_node(0) + self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth=foo']) + self.nodes[0].assert_start_raises_init_error(expected_msg=init_error, extra_args=['-rpcauth=foo:bar']) + + self.log.info('Check that failure to write cookie file will abort the node gracefully') cookie_file = os.path.join(get_datadir_path(self.options.tmpdir, 0), self.chain, '.cookie.tmp') os.mkdir(cookie_file) - init_error = 'Error: Unable to start HTTP server. See debug log for details.' self.nodes[0].assert_start_raises_init_error(expected_msg=init_error) diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index ff7f73bdf4..bab4ad0008 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -51,7 +51,6 @@ MAX_HEADERS_RESULTS = 2000 # Number of headers sent in one getheaders result MAX_INV_SIZE = 50000 # Maximum number of entries in an 'inv' protocol message NODE_NETWORK = (1 << 0) -NODE_GETUTXO = (1 << 1) NODE_BLOOM = (1 << 2) NODE_WITNESS = (1 << 3) NODE_COMPACT_FILTERS = (1 << 6) diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py index 6846d31221..8b79a4dc2f 100755 --- a/test/functional/test_framework/p2p.py +++ b/test/functional/test_framework/p2p.py @@ -396,9 +396,9 @@ class P2PInterface(P2PConnection): assert message.nVersion >= MIN_VERSION_SUPPORTED, "Version {} received. Test framework only supports versions greater than {}".format(message.nVersion, MIN_VERSION_SUPPORTED) if message.nVersion >= 70016: self.send_message(msg_wtxidrelay()) - self.send_message(msg_verack()) if self.support_addrv2: self.send_message(msg_sendaddrv2()) + self.send_message(msg_verack()) self.nServices = message.nServices # Connection helper methods diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index 8e5848d493..26ccab3039 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -824,21 +824,33 @@ def taproot_tree_helper(scripts): h = TaggedHash("TapBranch", left_h + right_h) return (left + right, h) +# A TaprootInfo object has the following fields: +# - scriptPubKey: the scriptPubKey (witness v1 CScript) +# - inner_pubkey: the inner pubkey (32 bytes) +# - negflag: whether the pubkey in the scriptPubKey was negated from inner_pubkey+tweak*G (bool). +# - tweak: the tweak (32 bytes) +# - leaves: a dict of name -> TaprootLeafInfo objects for all known leaves TaprootInfo = namedtuple("TaprootInfo", "scriptPubKey,inner_pubkey,negflag,tweak,leaves") + +# A TaprootLeafInfo object has the following fields: +# - script: the leaf script (CScript or bytes) +# - version: the leaf version (0xc0 for BIP342 tapscript) +# - merklebranch: the merkle branch to use for this leaf (32*N bytes) TaprootLeafInfo = namedtuple("TaprootLeafInfo", "script,version,merklebranch") def taproot_construct(pubkey, scripts=None): """Construct a tree of Taproot spending conditions - pubkey: an ECPubKey object for the internal pubkey + pubkey: a 32-byte xonly pubkey for the internal pubkey (bytes) scripts: a list of items; each item is either: - - a (name, CScript) tuple - - a (name, CScript, leaf version) tuple + - a (name, CScript or bytes, leaf version) tuple + - a (name, CScript or bytes) tuple (defaulting to leaf version 0xc0) - another list of items (with the same structure) - - a function, which specifies how to compute the hashing partner - in function of the hash of whatever it is combined with + - a list of two items; the first of which is an item itself, and the + second is a function. The function takes as input the Merkle root of the + first item, and produces a (fictitious) partner to hash with. - Returns: script (sPK or redeemScript), tweak, {name:(script, leaf version, negation flag, innerkey, merklepath), ...} + Returns: a TaprootInfo object """ if scripts is None: scripts = [] diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 046efe730e..a618706a77 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -482,11 +482,8 @@ class TestNode(): tempfile.NamedTemporaryFile(dir=self.stdout_dir, delete=False) as log_stdout: try: self.start(extra_args, stdout=log_stdout, stderr=log_stderr, *args, **kwargs) - self.wait_for_rpc_connection() - self.stop_node() - self.wait_until_stopped() - except FailedToStartError as e: - self.log.debug('bitcoind failed to start: %s', e) + ret = self.process.wait(timeout=self.rpc_timeout) + self.log.debug(self._node_msg(f'bitcoind exited with status {ret} during initialization')) self.running = False self.process = None # Check stderr for expected message @@ -505,11 +502,15 @@ class TestNode(): if expected_msg != stderr: self._raise_assertion_error( 'Expected message "{}" does not fully match stderr:\n"{}"'.format(expected_msg, stderr)) - else: + except subprocess.TimeoutExpired: + self.process.kill() + self.running = False + self.process = None + assert_msg = f'bitcoind should have exited within {self.rpc_timeout}s ' if expected_msg is None: - assert_msg = "bitcoind should have exited with an error" + assert_msg += "with an error" else: - assert_msg = "bitcoind should have exited with expected error " + expected_msg + assert_msg += "with expected error " + expected_msg self._raise_assertion_error(assert_msg) def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, **kwargs): @@ -544,7 +545,7 @@ class TestNode(): def num_test_p2p_connections(self): """Return number of test framework p2p connections to the node.""" - return len([peer for peer in self.getpeerinfo() if peer['subver'] == MY_SUBVERSION]) + return len([peer for peer in self.getpeerinfo() if peer['subver'] == MY_SUBVERSION.decode("utf-8")]) def disconnect_p2ps(self): """Close all p2p connections to the node.""" diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py index 0e786ca595..433b40faee 100755 --- a/test/functional/wallet_balance.py +++ b/test/functional/wallet_balance.py @@ -263,8 +263,6 @@ class WalletTest(BitcoinTestFramework): self.log.info('Put txs back into mempool of node 1 (not node 0)') self.nodes[0].invalidateblock(block_reorg) self.nodes[1].invalidateblock(block_reorg) - self.sync_blocks() - self.nodes[0].syncwithvalidationinterfacequeue() assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted self.nodes[0].generatetoaddress(1, ADDRESS_WATCHONLY) assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index ac4a6e4948..3cbddaf6da 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -235,7 +235,8 @@ class WalletTest(BitcoinTestFramework): fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8 explicit_fee_rate_btc_kvb = Decimal(fee_rate_btc_kvb) / 1000 - txid = self.nodes[2].sendmany(amounts={address: 10}, fee_rate=fee_rate_sat_vb) + # Test passing fee_rate as a string + txid = self.nodes[2].sendmany(amounts={address: 10}, fee_rate=str(fee_rate_sat_vb)) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) balance = self.nodes[2].getbalance() @@ -244,6 +245,17 @@ class WalletTest(BitcoinTestFramework): node_0_bal += Decimal('10') assert_equal(self.nodes[0].getbalance(), node_0_bal) + # Test passing fee_rate as an integer + amount = Decimal("0.0001") + txid = self.nodes[2].sendmany(amounts={address: amount}, fee_rate=fee_rate_sat_vb) + self.nodes[2].generate(1) + self.sync_all(self.nodes[0:3]) + balance = self.nodes[2].getbalance() + node_2_bal = self.check_fee_amount(balance, node_2_bal - amount, explicit_fee_rate_btc_kvb, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) + assert_equal(balance, node_2_bal) + node_0_bal += amount + assert_equal(self.nodes[0].getbalance(), node_0_bal) + for key in ["totalFee", "feeRate"]: assert_raises_rpc_error(-8, "Unknown named parameter key", self.nodes[2].sendtoaddress, address=address, amount=1, fee_rate=1, key=1) @@ -405,7 +417,7 @@ class WalletTest(BitcoinTestFramework): amount = 3 fee_rate_sat_vb = 2 fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8 - + # Test passing fee_rate as an integer txid = self.nodes[2].sendtoaddress(address=address, amount=amount, fee_rate=fee_rate_sat_vb) tx_size = self.get_vsize(self.nodes[2].gettransaction(txid)['hex']) self.nodes[0].generate(1) @@ -414,6 +426,19 @@ class WalletTest(BitcoinTestFramework): fee = prebalance - postbalance - Decimal(amount) assert_fee_amount(fee, tx_size, Decimal(fee_rate_btc_kvb)) + prebalance = self.nodes[2].getbalance() + amount = Decimal("0.001") + fee_rate_sat_vb = 1.23 + fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8 + # Test passing fee_rate as a string + txid = self.nodes[2].sendtoaddress(address=address, amount=amount, fee_rate=str(fee_rate_sat_vb)) + tx_size = self.get_vsize(self.nodes[2].gettransaction(txid)['hex']) + self.nodes[0].generate(1) + self.sync_all(self.nodes[0:3]) + postbalance = self.nodes[2].getbalance() + fee = prebalance - postbalance - amount + assert_fee_amount(fee, tx_size, Decimal(fee_rate_btc_kvb)) + for key in ["totalFee", "feeRate"]: assert_raises_rpc_error(-8, "Unknown named parameter key", self.nodes[2].sendtoaddress, address=address, amount=1, fee_rate=1, key=1) diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 99c9737258..c8c1f2e374 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -149,7 +149,7 @@ def test_simple_bumpfee_succeeds(self, mode, 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() if mode == "fee_rate": - bumped_psbt = rbf_node.psbtbumpfee(rbfid, {"fee_rate": NORMAL}) + bumped_psbt = rbf_node.psbtbumpfee(rbfid, {"fee_rate": str(NORMAL)}) bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": NORMAL}) else: bumped_psbt = rbf_node.psbtbumpfee(rbfid) diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index f7fdd6e908..30206349ae 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -64,7 +64,7 @@ class ImportMultiTest(BitcoinTestFramework): self.nodes[0].generate(1) self.nodes[1].generate(1) timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime'] - self.nodes[1].syncwithvalidationinterfacequeue() + self.nodes[1].syncwithvalidationinterfacequeue() # Sync the timestamp to the wallet, so that importmulti works node0_address1 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress()) diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index eeaa607db7..fb4532bcf6 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -127,7 +127,7 @@ class MultiWalletTest(BitcoinTestFramework): os.mkdir(wallet_dir('no_access')) os.chmod(wallet_dir('no_access'), 0) try: - with self.nodes[0].assert_debug_log(expected_msgs=['Too many levels of symbolic links', 'Error scanning']): + with self.nodes[0].assert_debug_log(expected_msgs=['Error scanning']): walletlist = self.nodes[0].listwalletdir()['wallets'] finally: # Need to ensure access is restored for cleanup diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py index 353deefcc1..78d88f8aa5 100755 --- a/test/functional/wallet_resendwallettransactions.py +++ b/test/functional/wallet_resendwallettransactions.py @@ -50,6 +50,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): block.solve() node.submitblock(ToHex(block)) + # Set correct m_best_block_time, which is used in ResendWalletTransactions node.syncwithvalidationinterfacequeue() now = int(time.time()) diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py index 192e9065e6..9835c5a2af 100755 --- a/test/functional/wallet_send.py +++ b/test/functional/wallet_send.py @@ -256,8 +256,8 @@ class WalletSendTest(BitcoinTestFramework): assert res["complete"] self.log.info("Test setting explicit fee rate") - res1 = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate=1, add_to_wallet=False) - res2 = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate=1, add_to_wallet=False) + res1 = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate="1", add_to_wallet=False) + res2 = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate="1", add_to_wallet=False) assert_equal(self.nodes[1].decodepsbt(res1["psbt"])["fee"], self.nodes[1].decodepsbt(res2["psbt"])["fee"]) res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate=7, add_to_wallet=False) diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index c7895edbcc..3a2cefbe2b 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -83,7 +83,7 @@ def main(): sys.exit(1) # Build list of tests - test_list_all = parse_test_list(makefile=os.path.join(config["environment"]["SRCDIR"], 'src', 'Makefile.test.include')) + test_list_all = parse_test_list(fuzz_bin=os.path.join(config["environment"]["BUILDDIR"], 'src', 'test', 'fuzz', 'fuzz')) if not test_list_all: logging.error("No fuzz targets found") @@ -126,9 +126,12 @@ def main(): try: help_output = subprocess.run( args=[ - os.path.join(config["environment"]["BUILDDIR"], 'src', 'test', 'fuzz', test_list_selection[0]), + os.path.join(config["environment"]["BUILDDIR"], 'src', 'test', 'fuzz', 'fuzz'), '-help=1', ], + env={ + 'FUZZ': test_list_selection[0] + }, timeout=20, check=True, stderr=subprocess.PIPE, @@ -177,24 +180,30 @@ def generate_corpus_seeds(*, fuzz_pool, build_dir, seed_dir, targets): """ logging.info("Generating corpus seeds to {}".format(seed_dir)) - def job(command): + def job(command, t): logging.debug("Running '{}'\n".format(" ".join(command))) logging.debug("Command '{}' output:\n'{}'\n".format( ' '.join(command), - subprocess.run(command, check=True, stderr=subprocess.PIPE, - universal_newlines=True).stderr - )) + subprocess.run( + command, + env={ + 'FUZZ': t + }, + check=True, + stderr=subprocess.PIPE, + universal_newlines=True, + ).stderr)) futures = [] for target in targets: target_seed_dir = os.path.join(seed_dir, target) os.makedirs(target_seed_dir, exist_ok=True) command = [ - os.path.join(build_dir, "src", "test", "fuzz", target), + os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'), "-runs=100000", target_seed_dir, ] - futures.append(fuzz_pool.submit(job, command)) + futures.append(fuzz_pool.submit(job, command, target)) for future in as_completed(futures): future.result() @@ -205,7 +214,7 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, build_dir, merge_dir): jobs = [] for t in test_list: args = [ - os.path.join(build_dir, 'src', 'test', 'fuzz', t), + os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'), '-merge=1', '-use_value_profile=1', # Also done by oss-fuzz https://github.com/google/oss-fuzz/issues/1406#issuecomment-387790487 os.path.join(corpus, t), @@ -216,7 +225,15 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, build_dir, merge_dir): def job(t, args): output = 'Run {} with args {}\n'.format(t, " ".join(args)) - output += subprocess.run(args, check=True, stderr=subprocess.PIPE, universal_newlines=True).stderr + output += subprocess.run( + args, + env={ + 'FUZZ': t + }, + check=True, + stderr=subprocess.PIPE, + universal_newlines=True, + ).stderr logging.debug(output) jobs.append(fuzz_pool.submit(job, t, args)) @@ -231,7 +248,7 @@ def run_once(*, fuzz_pool, corpus, test_list, build_dir, use_valgrind): corpus_path = os.path.join(corpus, t) os.makedirs(corpus_path, exist_ok=True) args = [ - os.path.join(build_dir, 'src', 'test', 'fuzz', t), + os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'), '-runs=1', corpus_path, ] @@ -240,7 +257,7 @@ def run_once(*, fuzz_pool, corpus, test_list, build_dir, use_valgrind): def job(t, args): output = 'Run {} with args {}'.format(t, args) - result = subprocess.run(args, stderr=subprocess.PIPE, universal_newlines=True) + result = subprocess.run(args, env={'FUZZ': t}, stderr=subprocess.PIPE, universal_newlines=True) output += result.stderr return output, result @@ -260,20 +277,16 @@ def run_once(*, fuzz_pool, corpus, test_list, build_dir, use_valgrind): sys.exit(1) -def parse_test_list(makefile): - with open(makefile, encoding='utf-8') as makefile_test: - test_list_all = [] - read_targets = False - for line in makefile_test.readlines(): - line = line.strip().replace('test/fuzz/', '').replace(' \\', '') - if read_targets: - if not line: - break - test_list_all.append(line) - continue - - if line == 'FUZZ_TARGETS =': - read_targets = True +def parse_test_list(*, fuzz_bin): + test_list_all = subprocess.run( + fuzz_bin, + env={ + 'PRINT_ALL_FUZZ_TARGETS_AND_ABORT': '' + }, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + universal_newlines=True, + ).stdout.splitlines() return test_list_all diff --git a/test/lint/README.md b/test/lint/README.md index d15c061288..7e06308347 100644 --- a/test/lint/README.md +++ b/test/lint/README.md @@ -15,7 +15,16 @@ git-subtree-check.sh Run this script from the root of the repository to verify that a subtree matches the contents of the commit it claims to have been updated to. -To use, make sure that you have fetched the upstream repository branch in which the subtree is +``` +Usage: test/lint/git-subtree-check.sh [-r] DIR [COMMIT] + test/lint/git-subtree-check.sh -? +``` + +- `DIR` is the prefix within the repository to check. +- `COMMIT` is the commit to check, if it is not provided, HEAD will be used. +- `-r` checks that subtree commit is present in repository. + +To do a full check with `-r`, make sure that you have fetched the upstream repository branch in which the subtree is maintained: * for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master) * for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork) @@ -29,10 +38,6 @@ To do so, add the upstream repository as remote: git remote add --fetch secp256k1 https://github.com/bitcoin-core/secp256k1.git ``` -Usage: `git-subtree-check.sh DIR (COMMIT)` - -`COMMIT` may be omitted, in which case `HEAD` is used. - lint-all.sh =========== Calls other scripts with the `lint-` prefix. diff --git a/test/lint/extended-lint-cppcheck.sh b/test/lint/extended-lint-cppcheck.sh index dfa49977de..b2ed811cda 100755 --- a/test/lint/extended-lint-cppcheck.sh +++ b/test/lint/extended-lint-cppcheck.sh @@ -30,6 +30,7 @@ IGNORED_WARNINGS=( "src/protocol.h:.* Class 'CMessageHeader' has a constructor with 1 argument that is not explicit." "src/qt/guiutil.h:.* Class 'ItemDelegate' has a constructor with 1 argument that is not explicit." "src/rpc/util.h:.* Struct 'RPCResults' has a constructor with 1 argument that is not explicit." + "src/rpc/util.h:.* Struct 'UniValueType' has a constructor with 1 argument that is not explicit." "src/rpc/util.h:.* style: Struct 'UniValueType' has a constructor with 1 argument that is not explicit." "src/script/descriptor.cpp:.* Class 'AddressDescriptor' has a constructor with 1 argument that is not explicit." "src/script/descriptor.cpp:.* Class 'ComboDescriptor' has a constructor with 1 argument that is not explicit." @@ -42,6 +43,11 @@ IGNORED_WARNINGS=( "src/script/descriptor.cpp:.* Class 'WSHDescriptor' has a constructor with 1 argument that is not explicit." "src/script/script.h:.* Class 'CScript' has a constructor with 1 argument that is not explicit." "src/script/standard.h:.* Class 'CScriptID' has a constructor with 1 argument that is not explicit." + "src/span.h:.* Class 'Span < const CRPCCommand >' has a constructor with 1 argument that is not explicit." + "src/span.h:.* Class 'Span < const char >' has a constructor with 1 argument that is not explicit." + "src/span.h:.* Class 'Span < const std :: vector <unsigned char > >' has a constructor with 1 argument that is not explicit." + "src/span.h:.* Class 'Span < const uint8_t >' has a constructor with 1 argument that is not explicit." + "src/span.h:.* Class 'Span' has a constructor with 1 argument that is not explicit." "src/support/allocators/secure.h:.* Struct 'secure_allocator < char >' has a constructor with 1 argument that is not explicit." "src/support/allocators/secure.h:.* Struct 'secure_allocator < RNGState >' has a constructor with 1 argument that is not explicit." "src/support/allocators/secure.h:.* Struct 'secure_allocator < unsigned char >' has a constructor with 1 argument that is not explicit." @@ -49,6 +55,9 @@ IGNORED_WARNINGS=( "src/test/checkqueue_tests.cpp:.* Struct 'FailingCheck' has a constructor with 1 argument that is not explicit." "src/test/checkqueue_tests.cpp:.* Struct 'MemoryCheck' has a constructor with 1 argument that is not explicit." "src/test/checkqueue_tests.cpp:.* Struct 'UniqueCheck' has a constructor with 1 argument that is not explicit." + "src/test/fuzz/util.h:.* Class 'FuzzedFileProvider' has a constructor with 1 argument that is not explicit." + "src/test/fuzz/util.h:.* Class 'FuzzedAutoFileProvider' has a constructor with 1 argument that is not explicit." + "src/util/ref.h:.* Class 'Ref' has a constructor with 1 argument that is not explicit." "src/wallet/db.h:.* Class 'BerkeleyEnvironment' has a constructor with 1 argument that is not explicit." ) @@ -66,7 +75,7 @@ function join_array { ENABLED_CHECKS_REGEXP=$(join_array "|" "${ENABLED_CHECKS[@]}") IGNORED_WARNINGS_REGEXP=$(join_array "|" "${IGNORED_WARNINGS[@]}") WARNINGS=$(git ls-files -- "*.cpp" "*.h" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" | \ - xargs cppcheck --enable=all -j "$(getconf _NPROCESSORS_ONLN)" --language=c++ --std=c++11 --template=gcc -D__cplusplus -DCLIENT_VERSION_BUILD -DCLIENT_VERSION_IS_RELEASE -DCLIENT_VERSION_MAJOR -DCLIENT_VERSION_MINOR -DCOPYRIGHT_YEAR -DDEBUG -I src/ -q 2>&1 | sort -u | \ + xargs cppcheck --enable=all -j "$(getconf _NPROCESSORS_ONLN)" --language=c++ --std=c++17 --template=gcc -D__cplusplus -DCLIENT_VERSION_BUILD -DCLIENT_VERSION_IS_RELEASE -DCLIENT_VERSION_MAJOR -DCLIENT_VERSION_MINOR -DCOPYRIGHT_YEAR -DDEBUG -I src/ -q 2>&1 | sort -u | \ grep -E "${ENABLED_CHECKS_REGEXP}" | \ grep -vE "${IGNORED_WARNINGS_REGEXP}") if [[ ${WARNINGS} != "" ]]; then diff --git a/test/lint/git-subtree-check.sh b/test/lint/git-subtree-check.sh index 5a0500df25..46aa6e7157 100755 --- a/test/lint/git-subtree-check.sh +++ b/test/lint/git-subtree-check.sh @@ -4,6 +4,39 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. export LC_ALL=C + +check_remote=0 +while getopts "?hr" opt; do + case $opt in + '?' | h) + echo "Usage: $0 [-r] DIR [COMMIT]" + echo " $0 -?" + echo "" + echo "Checks that a certain prefix is pure subtree, and optionally whether the" + echo "referenced commit is present in any fetched remote." + echo "" + echo "DIR is the prefix within the repository to check." + echo "COMMIT is the commit to check, if it is not provided, HEAD will be used." + echo "" + echo "-r Check that subtree commit is present in repository." + echo " To do this check, fetch the subtreed remote first. Example:" + echo "" + echo " git fetch https://github.com/bitcoin-core/secp256k1.git" + echo " test/lint/git-subtree-check.sh -r src/secp256k1" + exit 1 + ;; + r) + check_remote=1 + ;; + esac +done +shift $((OPTIND-1)) + +if [ -z "$1" ]; then + echo "Need to provide a DIR, see $0 -?" + exit 1 +fi + # Strip trailing / from directory path (in case it was added by autocomplete) DIR="${1%/}" COMMIT="$2" @@ -79,18 +112,20 @@ if [ "$tree_actual_tree" != "$tree_commit" ]; then exit 1 fi -# get the tree in the subtree commit referred to -if [ "d$(git cat-file -t $rev 2>/dev/null)" != dcommit ]; then - echo "subtree commit $rev unavailable: cannot compare. Did you add and fetch the remote?" >&2 - exit -fi -tree_subtree=$(git show -s --format="%T" $rev) -echo "$DIR in $COMMIT was last updated to upstream commit $rev (tree $tree_subtree)" +if [ "$check_remote" != "0" ]; then + # get the tree in the subtree commit referred to + if [ "d$(git cat-file -t $rev 2>/dev/null)" != dcommit ]; then + echo "subtree commit $rev unavailable: cannot compare. Did you add and fetch the remote?" >&2 + exit 1 + fi + tree_subtree=$(git show -s --format="%T" $rev) + echo "$DIR in $COMMIT was last updated to upstream commit $rev (tree $tree_subtree)" -# ... and compare the actual tree with it -if [ "$tree_actual_tree" != "$tree_subtree" ]; then - echo "FAIL: subtree update commit differs from upstream tree!" >&2 - exit 1 + # ... and compare the actual tree with it + if [ "$tree_actual_tree" != "$tree_subtree" ]; then + echo "FAIL: subtree update commit differs from upstream tree!" >&2 + exit 1 + fi fi echo "GOOD" diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh index 6bd02d45ac..c4ad00e954 100755 --- a/test/lint/lint-circular-dependencies.sh +++ b/test/lint/lint-circular-dependencies.sh @@ -20,7 +20,6 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( "txmempool -> validation -> txmempool" "wallet/fees -> wallet/wallet -> wallet/fees" "wallet/wallet -> wallet/walletdb -> wallet/wallet" - "policy/fees -> txmempool -> validation -> policy/fees" ) EXIT_CODE=0 diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan index 48f81f3dbf..986e096056 100644 --- a/test/sanitizer_suppressions/tsan +++ b/test/sanitizer_suppressions/tsan @@ -32,7 +32,6 @@ deadlock:CConnman::ForNode deadlock:CConnman::GetNodeStats deadlock:CChainState::ConnectTip deadlock:UpdateTip -deadlock:wallet_tests::CreateWallet # WalletBatch (unidentified deadlock) deadlock:WalletBatch |