diff --git a/.arclint b/.arclint --- a/.arclint +++ b/.arclint @@ -23,7 +23,7 @@ "exclude": [ "(^contrib/gitian-builder/)", "(^contrib/apple-sdk-tools/)", - "(^test/functional/[a-fmt].*\\.py$)" + "(^test/functional/[a-mt].*\\.py$)" ], "flags": [ "--aggressive", @@ -35,7 +35,7 @@ "type": "black", "version": ">=23.0.0", "include": [ - "(^test/functional/[a-fmt].*\\.py$)" + "(^test/functional/[a-mt].*\\.py$)" ], "flags": [ "--preview" diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -20,11 +20,14 @@ BLOCKS = 101 BALANCE = (BLOCKS - 100) * 50000000 -JSON_PARSING_ERROR = 'error: Error parsing JSON: foo' -BLOCKS_VALUE_OF_ZERO = 'error: the first argument (number of blocks to generate, default: 1) must be an integer value greater than zero' -TOO_MANY_ARGS = 'error: too many arguments (maximum 2 for nblocks and maxtries)' -WALLET_NOT_LOADED = 'Requested wallet does not exist or is not loaded' -WALLET_NOT_SPECIFIED = 'Wallet file not specified' +JSON_PARSING_ERROR = "error: Error parsing JSON: foo" +BLOCKS_VALUE_OF_ZERO = ( + "error: the first argument (number of blocks to generate, default: 1) must be an" + " integer value greater than zero" +) +TOO_MANY_ARGS = "error: too many arguments (maximum 2 for nblocks and maxtries)" +WALLET_NOT_LOADED = "Requested wallet does not exist or is not loaded" +WALLET_NOT_SPECIFIED = "Wallet file not specified" class TestBitcoinCli(BitcoinTestFramework): @@ -40,7 +43,9 @@ self.generate(self.nodes[0], BLOCKS) self.log.info( - "Compare responses from getblockchaininfo RPC and `bitcoin-cli getblockchaininfo`") + "Compare responses from getblockchaininfo RPC and `bitcoin-cli" + " getblockchaininfo`" + ) cli_response = self.nodes[0].cli.getblockchaininfo() rpc_response = self.nodes[0].getblockchaininfo() assert_equal(cli_response, rpc_response) @@ -48,83 +53,108 @@ user, password = get_auth_cookie(self.nodes[0].datadir, self.chain) self.log.info("Test -stdinrpcpass option") - assert_equal(BLOCKS, self.nodes[0].cli( - f'-rpcuser={user}', '-stdinrpcpass', cli_input=password).getblockcount()) - assert_raises_process_error(1, "Incorrect rpcuser or rpcpassword", self.nodes[0].cli( - f'-rpcuser={user}', '-stdinrpcpass', cli_input="foo").echo) + assert_equal( + BLOCKS, + self.nodes[0] + .cli(f"-rpcuser={user}", "-stdinrpcpass", cli_input=password) + .getblockcount(), + ) + assert_raises_process_error( + 1, + "Incorrect rpcuser or rpcpassword", + self.nodes[0] + .cli(f"-rpcuser={user}", "-stdinrpcpass", cli_input="foo") + .echo, + ) self.log.info("Test -stdin and -stdinrpcpass") - assert_equal(["foo", "bar"], self.nodes[0].cli(f'-rpcuser={user}', - '-stdin', '-stdinrpcpass', cli_input=f"{password}\nfoo\nbar").echo()) - assert_raises_process_error(1, "Incorrect rpcuser or rpcpassword", self.nodes[0].cli( - f'-rpcuser={user}', '-stdin', '-stdinrpcpass', cli_input="foo").echo) + assert_equal( + ["foo", "bar"], + self.nodes[0] + .cli( + f"-rpcuser={user}", + "-stdin", + "-stdinrpcpass", + cli_input=f"{password}\nfoo\nbar", + ) + .echo(), + ) + assert_raises_process_error( + 1, + "Incorrect rpcuser or rpcpassword", + self.nodes[0] + .cli(f"-rpcuser={user}", "-stdin", "-stdinrpcpass", cli_input="foo") + .echo, + ) self.log.info("Test connecting to a non-existing server") assert_raises_process_error( - 1, "Could not connect to the server", self.nodes[0].cli('-rpcport=1').echo) + 1, "Could not connect to the server", self.nodes[0].cli("-rpcport=1").echo + ) self.log.info("Test connecting with non-existing RPC cookie file") - assert_raises_process_error(1, "Could not locate RPC credentials", self.nodes[0].cli( - '-rpccookiefile=does-not-exist', '-rpcpassword=').echo) + assert_raises_process_error( + 1, + "Could not locate RPC credentials", + self.nodes[0].cli("-rpccookiefile=does-not-exist", "-rpcpassword=").echo, + ) self.log.info("Test -getinfo with arguments fails") assert_raises_process_error( - 1, "-getinfo takes no arguments", self.nodes[0].cli('-getinfo').help) + 1, "-getinfo takes no arguments", self.nodes[0].cli("-getinfo").help + ) - self.log.info( - "Test -getinfo returns expected network and blockchain info") + self.log.info("Test -getinfo returns expected network and blockchain info") if self.is_wallet_compiled(): self.nodes[0].encryptwallet(password) - cli_get_info = self.nodes[0].cli().send_cli('-getinfo') + cli_get_info = self.nodes[0].cli().send_cli("-getinfo") network_info = self.nodes[0].getnetworkinfo() blockchain_info = self.nodes[0].getblockchaininfo() - assert_equal(cli_get_info['version'], network_info['version']) - assert_equal(cli_get_info['blocks'], blockchain_info['blocks']) - assert_equal(cli_get_info['headers'], blockchain_info['headers']) - assert_equal(cli_get_info['timeoffset'], network_info['timeoffset']) + assert_equal(cli_get_info["version"], network_info["version"]) + assert_equal(cli_get_info["blocks"], blockchain_info["blocks"]) + assert_equal(cli_get_info["headers"], blockchain_info["headers"]) + assert_equal(cli_get_info["timeoffset"], network_info["timeoffset"]) assert_equal( - cli_get_info['connections'], + cli_get_info["connections"], { - 'in': network_info['connections_in'], - 'out': network_info['connections_out'], - 'total': network_info['connections'] - } + "in": network_info["connections_in"], + "out": network_info["connections_out"], + "total": network_info["connections"], + }, ) - assert_equal(cli_get_info['proxy'], - network_info['networks'][0]['proxy']) - assert_equal(cli_get_info['difficulty'], blockchain_info['difficulty']) - assert_equal(cli_get_info['chain'], blockchain_info['chain']) + assert_equal(cli_get_info["proxy"], network_info["networks"][0]["proxy"]) + assert_equal(cli_get_info["difficulty"], blockchain_info["difficulty"]) + assert_equal(cli_get_info["chain"], blockchain_info["chain"]) if self.is_wallet_compiled(): self.log.info( - "Test -getinfo and bitcoin-cli getwalletinfo return expected wallet info") - assert_equal(cli_get_info['balance'], BALANCE) - assert 'balances' not in cli_get_info.keys() + "Test -getinfo and bitcoin-cli getwalletinfo return expected wallet" + " info" + ) + assert_equal(cli_get_info["balance"], BALANCE) + assert "balances" not in cli_get_info.keys() wallet_info = self.nodes[0].getwalletinfo() - assert_equal( - cli_get_info['keypoolsize'], - wallet_info['keypoolsize']) - assert_equal( - cli_get_info['unlocked_until'], - wallet_info['unlocked_until']) - assert_equal(cli_get_info['paytxfee'], wallet_info['paytxfee']) - assert_equal(cli_get_info['relayfee'], network_info['relayfee']) + assert_equal(cli_get_info["keypoolsize"], wallet_info["keypoolsize"]) + assert_equal(cli_get_info["unlocked_until"], wallet_info["unlocked_until"]) + assert_equal(cli_get_info["paytxfee"], wallet_info["paytxfee"]) + assert_equal(cli_get_info["relayfee"], network_info["relayfee"]) assert_equal(self.nodes[0].cli.getwalletinfo(), wallet_info) # Setup to test -getinfo, -generate, and -rpcwallet= with multiple # wallets. - wallets = [self.default_wallet_name, 'Encrypted', 'secret'] + wallets = [self.default_wallet_name, "Encrypted", "secret"] amounts = [ - BALANCE + Decimal('9999995.50'), + BALANCE + Decimal("9999995.50"), Decimal(9000000), - Decimal(31000000)] + Decimal(31000000), + ] self.nodes[0].createwallet(wallet_name=wallets[1]) self.nodes[0].createwallet(wallet_name=wallets[2]) w1 = self.nodes[0].get_wallet_rpc(wallets[0]) w2 = self.nodes[0].get_wallet_rpc(wallets[1]) w3 = self.nodes[0].get_wallet_rpc(wallets[2]) - rpcwallet2 = f'-rpcwallet={wallets[1]}' - rpcwallet3 = f'-rpcwallet={wallets[2]}' + rpcwallet2 = f"-rpcwallet={wallets[1]}" + rpcwallet3 = f"-rpcwallet={wallets[2]}" w1.walletpassphrase(password, self.rpc_timeout) w2.encryptwallet(password) w1.sendtoaddress(w2.getnewaddress(), amounts[1]) @@ -135,61 +165,72 @@ self.generate(self.nodes[0], 1) self.log.info( - "Test -getinfo with multiple wallets and -rpcwallet returns specified wallet balance") + "Test -getinfo with multiple wallets and -rpcwallet returns specified" + " wallet balance" + ) for i in range(len(wallets)): - cli_get_info = self.nodes[0].cli( - '-getinfo', f'-rpcwallet={wallets[i]}').send_cli() - assert 'balances' not in cli_get_info.keys() - assert_equal(cli_get_info['balance'], amounts[i]) + cli_get_info = ( + self.nodes[0].cli("-getinfo", f"-rpcwallet={wallets[i]}").send_cli() + ) + assert "balances" not in cli_get_info.keys() + assert_equal(cli_get_info["balance"], amounts[i]) self.log.info( "Test -getinfo with multiple wallets and " - "-rpcwallet=non-existing-wallet returns no balances") - cli_get_info_keys = self.nodes[0].cli( - '-getinfo', '-rpcwallet=does-not-exist').send_cli().keys() - assert 'balance' not in cli_get_info_keys - assert 'balances' not in cli_get_info_keys + "-rpcwallet=non-existing-wallet returns no balances" + ) + cli_get_info_keys = ( + self.nodes[0] + .cli("-getinfo", "-rpcwallet=does-not-exist") + .send_cli() + .keys() + ) + assert "balance" not in cli_get_info_keys + assert "balances" not in cli_get_info_keys self.log.info( "Test -getinfo with multiple wallets returns all loaded " - "wallet names and balances") + "wallet names and balances" + ) assert_equal(set(self.nodes[0].listwallets()), set(wallets)) - cli_get_info = self.nodes[0].cli('-getinfo').send_cli() - assert 'balance' not in cli_get_info.keys() - assert_equal(cli_get_info['balances'], dict(zip(wallets, amounts))) + cli_get_info = self.nodes[0].cli("-getinfo").send_cli() + assert "balance" not in cli_get_info.keys() + assert_equal(cli_get_info["balances"], dict(zip(wallets, amounts))) # Unload the default wallet and re-verify. self.nodes[0].unloadwallet(wallets[0]) assert wallets[0] not in self.nodes[0].listwallets() - cli_get_info = self.nodes[0].cli('-getinfo').send_cli() - assert 'balance' not in cli_get_info.keys() - assert_equal(cli_get_info['balances'], - dict(zip(wallets[1:], amounts[1:]))) + cli_get_info = self.nodes[0].cli("-getinfo").send_cli() + assert "balance" not in cli_get_info.keys() + assert_equal(cli_get_info["balances"], dict(zip(wallets[1:], amounts[1:]))) self.log.info( "Test -getinfo after unloading all wallets except a " - "non-default one returns its balance") + "non-default one returns its balance" + ) self.nodes[0].unloadwallet(wallets[2]) assert_equal(self.nodes[0].listwallets(), [wallets[1]]) - cli_get_info = self.nodes[0].cli('-getinfo').send_cli() - assert 'balances' not in cli_get_info.keys() - assert_equal(cli_get_info['balance'], amounts[1]) + cli_get_info = self.nodes[0].cli("-getinfo").send_cli() + assert "balances" not in cli_get_info.keys() + assert_equal(cli_get_info["balance"], amounts[1]) self.log.info( "Test -getinfo with -rpcwallet=remaining-non-default-wallet" - " returns only its balance") - cli_get_info = self.nodes[0].cli('-getinfo', rpcwallet2).send_cli() - assert 'balances' not in cli_get_info.keys() - assert_equal(cli_get_info['balance'], amounts[1]) + " returns only its balance" + ) + cli_get_info = self.nodes[0].cli("-getinfo", rpcwallet2).send_cli() + assert "balances" not in cli_get_info.keys() + assert_equal(cli_get_info["balance"], amounts[1]) self.log.info( - "Test -getinfo with -rpcwallet=unloaded wallet returns" - " no balances") - cli_get_info_keys = self.nodes[0].cli( - '-getinfo', rpcwallet3).send_cli().keys() - assert 'balance' not in cli_get_info_keys - assert 'balances' not in cli_get_info_keys + "Test -getinfo with -rpcwallet=unloaded wallet returns no balances" + ) + cli_get_info_keys = ( + self.nodes[0].cli("-getinfo", rpcwallet3).send_cli().keys() + ) + assert "balance" not in cli_get_info_keys + assert "balances" not in cli_get_info_keys # Test bitcoin-cli -generate. n1 = 3 @@ -197,64 +238,60 @@ w2.walletpassphrase(password, self.rpc_timeout) blocks = self.nodes[0].getblockcount() - self.log.info('Test -generate with no args') - generate = self.nodes[0].cli('-generate').send_cli() - assert_equal(set(generate.keys()), {'address', 'blocks'}) + self.log.info("Test -generate with no args") + generate = self.nodes[0].cli("-generate").send_cli() + assert_equal(set(generate.keys()), {"address", "blocks"}) assert_equal(len(generate["blocks"]), 1) assert_equal(self.nodes[0].getblockcount(), blocks + 1) - self.log.info('Test -generate with bad args') + self.log.info("Test -generate with bad args") assert_raises_process_error( - 1, JSON_PARSING_ERROR, self.nodes[0].cli( - '-generate', 'foo').echo) + 1, JSON_PARSING_ERROR, self.nodes[0].cli("-generate", "foo").echo + ) assert_raises_process_error( - 1, BLOCKS_VALUE_OF_ZERO, self.nodes[0].cli( - '-generate', 0).echo) + 1, BLOCKS_VALUE_OF_ZERO, self.nodes[0].cli("-generate", 0).echo + ) assert_raises_process_error( - 1, TOO_MANY_ARGS, self.nodes[0].cli( - '-generate', 1, 2, 3).echo) + 1, TOO_MANY_ARGS, self.nodes[0].cli("-generate", 1, 2, 3).echo + ) - self.log.info('Test -generate with nblocks') - generate = self.nodes[0].cli('-generate', n1).send_cli() - assert_equal(set(generate.keys()), {'address', 'blocks'}) + self.log.info("Test -generate with nblocks") + generate = self.nodes[0].cli("-generate", n1).send_cli() + assert_equal(set(generate.keys()), {"address", "blocks"}) assert_equal(len(generate["blocks"]), n1) assert_equal(self.nodes[0].getblockcount(), blocks + 1 + n1) - self.log.info('Test -generate with nblocks and maxtries') - generate = self.nodes[0].cli('-generate', n2, 1000000).send_cli() - assert_equal(set(generate.keys()), {'address', 'blocks'}) + self.log.info("Test -generate with nblocks and maxtries") + generate = self.nodes[0].cli("-generate", n2, 1000000).send_cli() + assert_equal(set(generate.keys()), {"address", "blocks"}) assert_equal(len(generate["blocks"]), n2) assert_equal(self.nodes[0].getblockcount(), blocks + 1 + n1 + n2) - self.log.info('Test -generate -rpcwallet in single-wallet mode') - generate = self.nodes[0].cli(rpcwallet2, '-generate').send_cli() - assert_equal(set(generate.keys()), {'address', 'blocks'}) + self.log.info("Test -generate -rpcwallet in single-wallet mode") + generate = self.nodes[0].cli(rpcwallet2, "-generate").send_cli() + assert_equal(set(generate.keys()), {"address", "blocks"}) assert_equal(len(generate["blocks"]), 1) assert_equal(self.nodes[0].getblockcount(), blocks + 2 + n1 + n2) - self.log.info( - 'Test -generate -rpcwallet=unloaded wallet raises RPC error') - assert_raises_rpc_error(-18, - WALLET_NOT_LOADED, - self.nodes[0].cli(rpcwallet3, - '-generate').echo) - assert_raises_rpc_error(-18, - WALLET_NOT_LOADED, - self.nodes[0].cli(rpcwallet3, - '-generate', - 'foo').echo) - assert_raises_rpc_error(-18, - WALLET_NOT_LOADED, - self.nodes[0].cli(rpcwallet3, - '-generate', - 0).echo) - assert_raises_rpc_error(-18, - WALLET_NOT_LOADED, - self.nodes[0].cli(rpcwallet3, - '-generate', - 1, - 2, - 3).echo) + self.log.info("Test -generate -rpcwallet=unloaded wallet raises RPC error") + assert_raises_rpc_error( + -18, WALLET_NOT_LOADED, self.nodes[0].cli(rpcwallet3, "-generate").echo + ) + assert_raises_rpc_error( + -18, + WALLET_NOT_LOADED, + self.nodes[0].cli(rpcwallet3, "-generate", "foo").echo, + ) + assert_raises_rpc_error( + -18, + WALLET_NOT_LOADED, + self.nodes[0].cli(rpcwallet3, "-generate", 0).echo, + ) + assert_raises_rpc_error( + -18, + WALLET_NOT_LOADED, + self.nodes[0].cli(rpcwallet3, "-generate", 1, 2, 3).echo, + ) # Test bitcoin-cli -generate with -rpcwallet in multiwallet mode. self.nodes[0].loadwallet(wallets[2]) @@ -262,75 +299,83 @@ n4 = 10 blocks = self.nodes[0].getblockcount() - self.log.info('Test -generate -rpcwallet with no args') - generate = self.nodes[0].cli(rpcwallet2, '-generate').send_cli() - assert_equal(set(generate.keys()), {'address', 'blocks'}) + self.log.info("Test -generate -rpcwallet with no args") + generate = self.nodes[0].cli(rpcwallet2, "-generate").send_cli() + assert_equal(set(generate.keys()), {"address", "blocks"}) assert_equal(len(generate["blocks"]), 1) assert_equal(self.nodes[0].getblockcount(), blocks + 1) - self.log.info('Test -generate -rpcwallet with bad args') + self.log.info("Test -generate -rpcwallet with bad args") assert_raises_process_error( - 1, JSON_PARSING_ERROR, self.nodes[0].cli( - rpcwallet2, '-generate', 'foo').echo) + 1, + JSON_PARSING_ERROR, + self.nodes[0].cli(rpcwallet2, "-generate", "foo").echo, + ) assert_raises_process_error( - 1, BLOCKS_VALUE_OF_ZERO, self.nodes[0].cli( - rpcwallet2, '-generate', 0).echo) + 1, + BLOCKS_VALUE_OF_ZERO, + self.nodes[0].cli(rpcwallet2, "-generate", 0).echo, + ) assert_raises_process_error( - 1, TOO_MANY_ARGS, self.nodes[0].cli( - rpcwallet2, '-generate', 1, 2, 3).echo) - - self.log.info('Test -generate -rpcwallet with nblocks') - generate = self.nodes[0].cli( - rpcwallet2, '-generate', n3).send_cli() - assert_equal(set(generate.keys()), {'address', 'blocks'}) + 1, + TOO_MANY_ARGS, + self.nodes[0].cli(rpcwallet2, "-generate", 1, 2, 3).echo, + ) + + self.log.info("Test -generate -rpcwallet with nblocks") + generate = self.nodes[0].cli(rpcwallet2, "-generate", n3).send_cli() + assert_equal(set(generate.keys()), {"address", "blocks"}) assert_equal(len(generate["blocks"]), n3) assert_equal(self.nodes[0].getblockcount(), blocks + 1 + n3) - self.log.info( - 'Test -generate -rpcwallet with nblocks and maxtries') - generate = self.nodes[0].cli( - rpcwallet2, '-generate', n4, 1000000).send_cli() - assert_equal(set(generate.keys()), {'address', 'blocks'}) + self.log.info("Test -generate -rpcwallet with nblocks and maxtries") + generate = ( + self.nodes[0].cli(rpcwallet2, "-generate", n4, 1000000).send_cli() + ) + assert_equal(set(generate.keys()), {"address", "blocks"}) assert_equal(len(generate["blocks"]), n4) assert_equal(self.nodes[0].getblockcount(), blocks + 1 + n3 + n4) self.log.info( - 'Test -generate without -rpcwallet in multiwallet mode raises RPC error') - assert_raises_rpc_error(-19, - WALLET_NOT_SPECIFIED, - self.nodes[0].cli('-generate').echo) - assert_raises_rpc_error(-19, - WALLET_NOT_SPECIFIED, - self.nodes[0].cli('-generate', - 'foo').echo) - assert_raises_rpc_error(-19, WALLET_NOT_SPECIFIED, - self.nodes[0].cli('-generate', 0).echo) - assert_raises_rpc_error(-19, WALLET_NOT_SPECIFIED, - self.nodes[0].cli('-generate', 1, 2, 3).echo) + "Test -generate without -rpcwallet in multiwallet mode raises RPC error" + ) + assert_raises_rpc_error( + -19, WALLET_NOT_SPECIFIED, self.nodes[0].cli("-generate").echo + ) + assert_raises_rpc_error( + -19, WALLET_NOT_SPECIFIED, self.nodes[0].cli("-generate", "foo").echo + ) + assert_raises_rpc_error( + -19, WALLET_NOT_SPECIFIED, self.nodes[0].cli("-generate", 0).echo + ) + assert_raises_rpc_error( + -19, WALLET_NOT_SPECIFIED, self.nodes[0].cli("-generate", 1, 2, 3).echo + ) else: self.log.info( - "*** Wallet not compiled; cli getwalletinfo and -getinfo wallet tests skipped") + "*** Wallet not compiled; cli getwalletinfo and -getinfo wallet tests" + " skipped" + ) # maintain block parity with the wallet_compiled conditional branch self.generate(self.nodes[0], 25) self.log.info("Test -version with node stopped") self.stop_node(0) - cli_response = self.nodes[0].cli().send_cli('-version') + cli_response = self.nodes[0].cli().send_cli("-version") assert ( f"{self.config['environment']['PACKAGE_NAME']} RPC client version" in cli_response ) - self.log.info( - "Test -rpcwait option successfully waits for RPC connection") + self.log.info("Test -rpcwait option successfully waits for RPC connection") # Start node without RPC connection. self.nodes[0].start() # ensure cookie file is available to avoid race condition self.nodes[0].wait_for_cookie_credentials() - blocks = self.nodes[0].cli('-rpcwait').send_cli('getblockcount') + blocks = self.nodes[0].cli("-rpcwait").send_cli("getblockcount") self.nodes[0].wait_for_rpc_connection() assert_equal(blocks, BLOCKS + 25) -if __name__ == '__main__': +if __name__ == "__main__": TestBitcoinCli().main() diff --git a/test/functional/interface_http.py b/test/functional/interface_http.py --- a/test/functional/interface_http.py +++ b/test/functional/interface_http.py @@ -11,7 +11,7 @@ from test_framework.util import assert_equal, str_to_b64str -class HTTPBasicsTest (BitcoinTestFramework): +class HTTPBasicsTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 3 self.supports_cli = False @@ -21,7 +21,6 @@ self.setup_nodes() def run_test(self): - # # lowlevel check for http persistent connection # # @@ -31,14 +30,14 @@ conn = http.client.HTTPConnection(url.hostname, url.port) conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + conn.request("POST", "/", '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() assert b'"error":null' in out1 assert conn.sock is not None # according to http/1.1 connection must still be open! # send 2nd request without closing connection - conn.request('POST', '/', '{"method": "getchaintips"}', headers) + conn.request("POST", "/", '{"method": "getchaintips"}', headers) out1 = conn.getresponse().read() assert b'"error":null' in out1 # must also response with a correct json-rpc message @@ -48,19 +47,21 @@ # same should be if we add keep-alive because this should be the std. # behaviour - headers = {"Authorization": "Basic " + - str_to_b64str(authpair), "Connection": "keep-alive"} + headers = { + "Authorization": "Basic " + str_to_b64str(authpair), + "Connection": "keep-alive", + } conn = http.client.HTTPConnection(url.hostname, url.port) conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + conn.request("POST", "/", '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() assert b'"error":null' in out1 assert conn.sock is not None # according to http/1.1 connection must still be open! # send 2nd request without closing connection - conn.request('POST', '/', '{"method": "getchaintips"}', headers) + conn.request("POST", "/", '{"method": "getchaintips"}', headers) out1 = conn.getresponse().read() assert b'"error":null' in out1 # must also response with a correct json-rpc message @@ -69,12 +70,14 @@ conn.close() # now do the same with "Connection: close" - headers = {"Authorization": "Basic " + - str_to_b64str(authpair), "Connection": "close"} + headers = { + "Authorization": "Basic " + str_to_b64str(authpair), + "Connection": "close", + } conn = http.client.HTTPConnection(url.hostname, url.port) conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + conn.request("POST", "/", '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() assert b'"error":null' in out1 assert conn.sock is None @@ -87,7 +90,7 @@ conn = http.client.HTTPConnection(urlNode1.hostname, urlNode1.port) conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + conn.request("POST", "/", '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() assert b'"error":null' in out1 @@ -99,7 +102,7 @@ conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port) conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + conn.request("POST", "/", '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() assert b'"error":null' in out1 assert conn.sock is not None @@ -109,13 +112,13 @@ # Check excessive request size conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port) conn.connect() - conn.request('GET', f"/{'x' * 1000}", '', headers) + conn.request("GET", f"/{'x' * 1000}", "", headers) out1 = conn.getresponse() assert_equal(out1.status, http.client.NOT_FOUND) conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port) conn.connect() - conn.request('GET', f"/{'x' * 10000}", '', headers) + conn.request("GET", f"/{'x' * 10000}", "", headers) out1 = conn.getresponse() assert_equal(out1.status, http.client.BAD_REQUEST) @@ -125,49 +128,51 @@ conn = http.client.HTTPConnection(url.hostname, url.port) conn.connect() authpair = f"{url.username}:{url.password}" - headers = {"Authorization": f"Basic {str_to_b64str(authpair)}", - "Origin": origin} - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + headers = { + "Authorization": f"Basic {str_to_b64str(authpair)}", + "Origin": origin, + } + conn.request("POST", "/", '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse() assert_equal(out1.status, http.client.OK) assert_equal(out1.headers["Access-Control-Allow-Origin"], origin) assert_equal(out1.headers["Access-Control-Allow-Credentials"], "true") - assert_equal(out1.headers["Access-Control-Expose-Headers"], - "WWW-Authenticate") + assert_equal(out1.headers["Access-Control-Expose-Headers"], "WWW-Authenticate") assert b'"error":null' in out1.read() # Check Pre-flight CORS request - corsheaders = {"Origin": origin, - "Access-Control-Request-Method": "POST"} - conn.request('OPTIONS', '/', None, corsheaders) + corsheaders = {"Origin": origin, "Access-Control-Request-Method": "POST"} + conn.request("OPTIONS", "/", None, corsheaders) out1 = conn.getresponse() assert_equal(out1.status, http.client.OK) assert_equal(out1.headers["Access-Control-Allow-Origin"], origin) assert_equal(out1.headers["Access-Control-Allow-Credentials"], "true") assert_equal(out1.headers["Access-Control-Allow-Methods"], "POST") - assert_equal(out1.headers["Access-Control-Allow-Headers"], - "authorization,content-type") - assert_equal(b'', out1.read()) + assert_equal( + out1.headers["Access-Control-Allow-Headers"], "authorization,content-type" + ) + assert_equal(b"", out1.read()) # Check Standard CORS request to node without CORS, expected failure conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port) conn.connect() authpair = f"{url.username}:{url.password}" - headers = {"Authorization": f"Basic {str_to_b64str(authpair)}", - "Origin": origin} - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + headers = { + "Authorization": f"Basic {str_to_b64str(authpair)}", + "Origin": origin, + } + conn.request("POST", "/", '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse() assert_equal(out1.status, http.client.UNAUTHORIZED) - assert_equal(b'', out1.read()) + assert_equal(b"", out1.read()) # Check Pre-flight CORS request to node without CORS, expected failure - corsheaders = {"Origin": origin, - "Access-Control-Request-Method": "POST"} - conn.request('OPTIONS', '/', None, corsheaders) + corsheaders = {"Origin": origin, "Access-Control-Request-Method": "POST"} + conn.request("OPTIONS", "/", None, corsheaders) out1 = conn.getresponse() assert_equal(out1.status, http.client.METHOD_NOT_ALLOWED) - assert_equal(b'JSONRPC server handles only POST requests', out1.read()) + assert_equal(b"JSONRPC server handles only POST requests", out1.read()) -if __name__ == '__main__': +if __name__ == "__main__": HTTPBasicsTest().main() diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -35,11 +35,11 @@ def filter_output_indices_by_value(vouts, value): for vout in vouts: - if vout['value'] == value: - yield vout['n'] + if vout["value"] == value: + yield vout["n"] -class RESTTest (BitcoinTestFramework): +class RESTTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 @@ -49,22 +49,29 @@ def skip_test_if_missing_module(self): self.skip_if_no_wallet() - def test_rest_request(self, uri, http_method='GET', req_type=ReqType.JSON, - body='', status=200, ret_type=RetType.JSON): + def test_rest_request( + self, + uri, + http_method="GET", + req_type=ReqType.JSON, + body="", + status=200, + ret_type=RetType.JSON, + ): rest_uri = f"/rest{uri}" if req_type == ReqType.JSON: - rest_uri += '.json' + rest_uri += ".json" elif req_type == ReqType.BIN: - rest_uri += '.bin' + rest_uri += ".bin" elif req_type == ReqType.HEX: - rest_uri += '.hex' + rest_uri += ".hex" conn = http.client.HTTPConnection(self.url.hostname, self.url.port) - self.log.debug(f'{http_method} {rest_uri} {body}') - if http_method == 'GET': - conn.request('GET', rest_uri) - elif http_method == 'POST': - conn.request('POST', rest_uri, body) + self.log.debug(f"{http_method} {rest_uri} {body}") + if http_method == "GET": + conn.request("GET", rest_uri) + elif http_method == "POST": + conn.request("POST", rest_uri, body) resp = conn.getresponse() assert_equal(resp.status, status) @@ -74,7 +81,7 @@ elif ret_type == RetType.BYTES: return resp.read() elif ret_type == RetType.JSON: - return json.loads(resp.read().decode('utf-8'), parse_float=Decimal) + return json.loads(resp.read().decode("utf-8"), parse_float=Decimal) def run_test(self): self.url = urllib.parse.urlparse(self.nodes[0].url) @@ -88,25 +95,26 @@ assert_equal(self.nodes[0].getbalance(), 50000000) - txid = self.nodes[0].sendtoaddress( - self.nodes[1].getnewaddress(), 100000) + txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 100000) self.sync_all() self.log.info("Test the /tx URI") json_obj = self.test_rest_request(f"/tx/{txid}") - assert_equal(json_obj['txid'], txid) + assert_equal(json_obj["txid"], txid) # Check hex format response hex_response = self.test_rest_request( - f"/tx/{txid}", req_type=ReqType.HEX, ret_type=RetType.OBJ) - assert_greater_than_or_equal(int(hex_response.getheader('content-length')), - json_obj['size'] * 2) + f"/tx/{txid}", req_type=ReqType.HEX, ret_type=RetType.OBJ + ) + assert_greater_than_or_equal( + int(hex_response.getheader("content-length")), json_obj["size"] * 2 + ) # Get the vin to later check for utxo (should be spent by then) - spent = (json_obj['vin'][0]['txid'], json_obj['vin'][0]['vout']) + spent = (json_obj["vin"][0]["txid"], json_obj["vin"][0]["vout"]) # Get n of 100_000 XEC outpoint - n, = filter_output_indices_by_value(json_obj['vout'], Decimal('100000')) + (n,) = filter_output_indices_by_value(json_obj["vout"], Decimal("100000")) spending = (txid, n) self.log.info("Query an unspent TXO using the /getutxos URI") @@ -118,46 +126,49 @@ # Check chainTip response json_obj = self.test_rest_request(f"/getutxos/{txid}-{n}") - assert_equal(json_obj['chaintipHash'], bb_hash) + assert_equal(json_obj["chaintipHash"], bb_hash) # Make sure there is one utxo - assert_equal(len(json_obj['utxos']), 1) - assert_equal(json_obj['utxos'][0]['value'], Decimal('100000')) + assert_equal(len(json_obj["utxos"]), 1) + assert_equal(json_obj["utxos"][0]["value"], Decimal("100000")) self.log.info("Query a spent TXO using the /getutxos URI") json_obj = self.test_rest_request(f"/getutxos/{spent[0]}-{spent[1]}") # Check chainTip response - assert_equal(json_obj['chaintipHash'], bb_hash) + assert_equal(json_obj["chaintipHash"], bb_hash) # Make sure there is no utxo in the response because this outpoint has # been spent - assert_equal(len(json_obj['utxos']), 0) + assert_equal(len(json_obj["utxos"]), 0) # Check bitmap - assert_equal(json_obj['bitmap'], "0") + assert_equal(json_obj["bitmap"], "0") self.log.info("Query two TXOs using the /getutxos URI") - json_obj = self.test_rest_request( - f"/getutxos/{txid}-{n}/{spent[0]}-{spent[1]}") + json_obj = self.test_rest_request(f"/getutxos/{txid}-{n}/{spent[0]}-{spent[1]}") - assert_equal(len(json_obj['utxos']), 1) - assert_equal(json_obj['bitmap'], "10") + assert_equal(len(json_obj["utxos"]), 1) + assert_equal(json_obj["bitmap"], "10") - self.log.info( - "Query the TXOs using the /getutxos URI with a binary response") + self.log.info("Query the TXOs using the /getutxos URI with a binary response") - bin_request = b'\x01\x02' + bin_request = b"\x01\x02" for txid, n in [spending, spent]: bin_request += bytes.fromhex(txid) bin_request += pack("i", n) bin_response = self.test_rest_request( - "/getutxos", http_method='POST', req_type=ReqType.BIN, body=bin_request, ret_type=RetType.BYTES) + "/getutxos", + http_method="POST", + req_type=ReqType.BIN, + body=bin_request, + ret_type=RetType.BYTES, + ) output = BytesIO(bin_response) - chain_height, = unpack(" 0 assert event.duration > 0 @@ -380,9 +394,9 @@ # UTXOs and one that flushes 0 UTXOs. Normally the 0-UTXO-flush is the # second flush, however it can happen that the order changes. expected_flushes.append( - {"mode": "ALWAYS", "for_prune": False, "size": UTXOS_IN_CACHE}) - expected_flushes.append( - {"mode": "ALWAYS", "for_prune": False, "size": 0}) + {"mode": "ALWAYS", "for_prune": False, "size": UTXOS_IN_CACHE} + ) + expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": 0}) self.stop_node(0) bpf.perf_buffer_poll(timeout=200) @@ -401,8 +415,7 @@ self.log.info("test the utxocache:flush tracepoint API with pruning") self.log.info("hook into the utxocache:flush tracepoint") ctx = USDT(pid=self.nodes[0].process.pid) - ctx.enable_probe(probe="utxocache:flush", - fn_name="trace_utxocache_flush") + ctx.enable_probe(probe="utxocache:flush", fn_name="trace_utxocache_flush") bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0) bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush) @@ -414,10 +427,12 @@ bpf.cleanup() self.log.info( - "check that we don't expect additional flushes and that the handle_* function succeeded") + "check that we don't expect additional flushes and that the handle_*" + " function succeeded" + ) assert_equal(0, len(expected_flushes)) assert_equal(EXPECTED_HANDLE_FLUSH_SUCCESS, handle_flush_succeeds) -if __name__ == '__main__': +if __name__ == "__main__": UTXOCacheTracepointTest().main() diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py --- a/test/functional/interface_usdt_validation.py +++ b/test/functional/interface_usdt_validation.py @@ -94,10 +94,10 @@ self.log.info("hook into the validation:block_connected tracepoint") ctx = USDT(pid=self.nodes[0].process.pid) - ctx.enable_probe(probe="validation:block_connected", - fn_name="trace_block_connected") - bpf = BPF(text=validation_blockconnected_program, - usdt_contexts=[ctx], debug=0) + ctx.enable_probe( + probe="validation:block_connected", fn_name="trace_block_connected" + ) + bpf = BPF(text=validation_blockconnected_program, usdt_contexts=[ctx], debug=0) def handle_blockconnected(_, data, __): nonlocal expected_blocks, blocks_checked @@ -115,12 +115,12 @@ blocks_checked += 1 - bpf["block_connected"].open_perf_buffer( - handle_blockconnected) + bpf["block_connected"].open_perf_buffer(handle_blockconnected) self.log.info(f"mine {BLOCKS_EXPECTED} blocks") block_hashes = self.generatetoaddress( - self.nodes[0], BLOCKS_EXPECTED, ADDRESS_ECREG_UNSPENDABLE) + self.nodes[0], BLOCKS_EXPECTED, ADDRESS_ECREG_UNSPENDABLE + ) for block_hash in block_hashes: expected_blocks.append(self.nodes[0].getblock(block_hash, 2)) @@ -132,5 +132,5 @@ assert_equal(0, len(expected_blocks)) -if __name__ == '__main__': +if __name__ == "__main__": ValidationTracepointTest().main() diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -43,7 +43,7 @@ # Topic should match the subscriber topic. assert_equal(topic, self.topic) # Sequence should be incremental. - received_seq = struct.unpack(' seq_num + assert ( + self.nodes[0].getrawmempool(mempool_sequence=True)["mempool_sequence"] + > seq_num + ) - assert_equal((payment_txid_2, "R", seq_num), - seq.receive_sequence()) + assert_equal((payment_txid_2, "R", seq_num), seq.receive_sequence()) seq_num += 1 assert_equal((best_hash, "D", None), seq.receive_sequence()) assert_equal((payment_txid, "A", seq_num), seq.receive_sequence()) @@ -487,33 +500,35 @@ self.log.info("Evict mempool transaction by block conflict") orig_txid = self.nodes[0].sendtoaddress( - address=self.nodes[0].getnewaddress(), amount=1_000_000) + address=self.nodes[0].getnewaddress(), amount=1_000_000 + ) # More to be simply mined more_tx = [] for _ in range(5): - more_tx.append(self.nodes[0].sendtoaddress( - self.nodes[0].getnewaddress(), 100_000)) + more_tx.append( + self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 100_000) + ) raw_tx = self.nodes[0].getrawtransaction(orig_txid) block = create_block( int(self.nodes[0].getbestblockhash(), 16), - create_coinbase(self.nodes[0].getblockcount() + 1)) + create_coinbase(self.nodes[0].getblockcount() + 1), + ) tx = FromHex(CTransaction(), raw_tx) block.vtx.append(tx) for txid in more_tx: - tx = FromHex(CTransaction(), - self.nodes[0].getrawtransaction(txid)) + tx = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid)) block.vtx.append(tx) make_conform_to_ctor(block) block.hashMerkleRoot = block.calc_merkle_root() block.solve() - assert_equal(self.nodes[0].submitblock(block.serialize().hex()), - None) + assert_equal(self.nodes[0].submitblock(block.serialize().hex()), None) tip = self.nodes[0].getbestblockhash() assert_equal(int(tip, 16), block.sha256) orig_txid_2 = self.nodes[0].sendtoaddress( - address=self.nodes[0].getnewaddress(), amount=1_000_000) + address=self.nodes[0].getnewaddress(), amount=1_000_000 + ) # Flush old notifications until evicted tx original entry (hash_str, label, mempool_seq) = seq.receive_sequence() @@ -525,8 +540,7 @@ assert_equal(label, "A") # More transactions to be simply mined for i in range(len(more_tx)): - assert_equal((more_tx[i], "A", mempool_seq), - seq.receive_sequence()) + assert_equal((more_tx[i], "A", mempool_seq), seq.receive_sequence()) mempool_seq += 1 # Removed RBF tests @@ -535,8 +549,7 @@ assert_equal((tip, "C", None), seq.receive_sequence()) mempool_seq += len(more_tx) # Last tx - assert_equal((orig_txid_2, "A", mempool_seq), - seq.receive_sequence()) + assert_equal((orig_txid_2, "A", mempool_seq), seq.receive_sequence()) mempool_seq += 1 self.generatetoaddress(self.nodes[0], 1, ADDRESS_ECREG_UNSPENDABLE) # want to make sure we didn't break "consensus" for other tests @@ -555,8 +568,9 @@ [seq] = self.setup_zmq_test([("sequence", "tcp://127.0.0.1:28333")]) # In-memory counter, should always start at 1 - next_mempool_seq = self.nodes[0].getrawmempool( - mempool_sequence=True)["mempool_sequence"] + next_mempool_seq = self.nodes[0].getrawmempool(mempool_sequence=True)[ + "mempool_sequence" + ] assert_equal(next_mempool_seq, 1) # Some transactions have been happening but we aren't consuming @@ -565,8 +579,11 @@ txids = [] num_txs = 5 for _ in range(num_txs): - txids.append(self.nodes[1].sendtoaddress( - address=self.nodes[0].getnewaddress(), amount=1_000_000)) + txids.append( + self.nodes[1].sendtoaddress( + address=self.nodes[0].getnewaddress(), amount=1_000_000 + ) + ) self.sync_all() # 1) Consume backlog until we get a mempool sequence number @@ -585,21 +602,24 @@ # Snapshot may be too old compared to zmq message we read off latest while zmq_mem_seq >= get_raw_seq: sleep(2) - mempool_snapshot = self.nodes[0].getrawmempool( - mempool_sequence=True) + mempool_snapshot = self.nodes[0].getrawmempool(mempool_sequence=True) mempool_view = set(mempool_snapshot["txids"]) get_raw_seq = mempool_snapshot["mempool_sequence"] # Things continue to happen in the "interim" while waiting for # snapshot results for _ in range(num_txs): - txids.append(self.nodes[0].sendtoaddress( - address=self.nodes[0].getnewaddress(), amount=1_000_000)) + txids.append( + self.nodes[0].sendtoaddress( + address=self.nodes[0].getnewaddress(), amount=1_000_000 + ) + ) self.sync_all() self.create_conflicting_tx() self.generatetoaddress(self.nodes[0], 1, ADDRESS_ECREG_UNSPENDABLE) final_txid = self.nodes[0].sendtoaddress( - address=self.nodes[0].getnewaddress(), amount=100_000) + address=self.nodes[0].getnewaddress(), amount=100_000 + ) # 3) Consume ZMQ backlog until we get to "now" for the mempool snapshot while True: @@ -610,9 +630,10 @@ zmq_mem_seq = mempool_sequence if zmq_mem_seq > get_raw_seq: raise Exception( - f"We somehow jumped mempool sequence numbers! " + "We somehow jumped mempool sequence numbers! " f"zmq_mem_seq: {zmq_mem_seq} > " - f"get_raw_seq: {get_raw_seq}") + f"get_raw_seq: {get_raw_seq}" + ) # 4) Moving forward, we apply the delta to our local view # remaining txs + conflict (A, R, C) + 1 block connect + 1 final tx @@ -642,9 +663,9 @@ assert_equal(self.nodes[0].getrawmempool(), [final_txid]) assert_equal( - self.nodes[0].getrawmempool( - mempool_sequence=True)["mempool_sequence"], - expected_sequence) + self.nodes[0].getrawmempool(mempool_sequence=True)["mempool_sequence"], + expected_sequence, + ) # 5) If you miss a zmq/mempool sequence number, go back to step (2) @@ -655,24 +676,23 @@ # (note that after the reorg test, syncing would fail due to different # chain lengths on node0 and node1; for this test we only need node0, so # we can disable syncing blocks on the setup) - subscribers = self.setup_zmq_test([ - ("hashblock", "tcp://127.0.0.1:28334"), - ("hashblock", "tcp://127.0.0.1:28335"), - ], sync_blocks=False) + subscribers = self.setup_zmq_test( + [ + ("hashblock", "tcp://127.0.0.1:28334"), + ("hashblock", "tcp://127.0.0.1:28335"), + ], + sync_blocks=False, + ) # Generate 1 block in nodes[0] and receive all notifications self.generatetoaddress( - self.nodes[0], - 1, - ADDRESS_ECREG_UNSPENDABLE, - sync_fun=self.no_op) + self.nodes[0], 1, ADDRESS_ECREG_UNSPENDABLE, sync_fun=self.no_op + ) # Should receive the same block hash on both subscribers - assert_equal(self.nodes[0].getbestblockhash(), - subscribers[0].receive().hex()) - assert_equal(self.nodes[0].getbestblockhash(), - subscribers[1].receive().hex()) + assert_equal(self.nodes[0].getbestblockhash(), subscribers[0].receive().hex()) + assert_equal(self.nodes[0].getbestblockhash(), subscribers[1].receive().hex()) -if __name__ == '__main__': +if __name__ == "__main__": ZMQTest().main()