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-v].*\\.py$)" + "(^test/functional/.*\\.py$)" ], "flags": [ "--aggressive", @@ -35,7 +35,7 @@ "type": "black", "version": ">=23.0.0", "include": [ - "(^test/functional/[a-v].*\\.py$)" + "(^test/functional/.*\\.py$)" ], "flags": [ "--preview" diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -32,27 +32,36 @@ total = 0 for txid in txids: # '-=' is because gettransaction(txid)['fee'] returns a negative - total -= self.nodes[0].gettransaction(txid)['fee'] + total -= self.nodes[0].gettransaction(txid)["fee"] return satoshi_round(total) self.generate(self.nodes[1], 100) balance = self.nodes[0].getbalance() txA = self.nodes[0].sendtoaddress( - self.nodes[0].getnewaddress(), Decimal("10000000")) + self.nodes[0].getnewaddress(), Decimal("10000000") + ) txB = self.nodes[0].sendtoaddress( - self.nodes[0].getnewaddress(), Decimal("10000000")) + self.nodes[0].getnewaddress(), Decimal("10000000") + ) txC = self.nodes[0].sendtoaddress( - self.nodes[0].getnewaddress(), Decimal("10000000")) + self.nodes[0].getnewaddress(), Decimal("10000000") + ) self.sync_mempools() self.generate(self.nodes[1], 1) # Can not abandon non-wallet transaction - assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', - lambda: self.nodes[0].abandontransaction(txid='ff' * 32)) + assert_raises_rpc_error( + -5, + "Invalid or non-wallet transaction id", + lambda: self.nodes[0].abandontransaction(txid="ff" * 32), + ) # Can not abandon confirmed transaction - assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', - lambda: self.nodes[0].abandontransaction(txid=txA)) + assert_raises_rpc_error( + -5, + "Transaction not eligible for abandonment", + lambda: self.nodes[0].abandontransaction(txid=txA), + ) newbalance = self.nodes[0].getbalance() @@ -65,12 +74,21 @@ self.disconnect_nodes(0, 1) # Identify the 10btc outputs - nA = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction( - txA)["details"] if tx_out["amount"] == Decimal("10000000")) - nB = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction( - txB)["details"] if tx_out["amount"] == Decimal("10000000")) - nC = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction( - txC)["details"] if tx_out["amount"] == Decimal("10000000")) + nA = next( + tx_out["vout"] + for tx_out in self.nodes[0].gettransaction(txA)["details"] + if tx_out["amount"] == Decimal("10000000") + ) + nB = next( + tx_out["vout"] + for tx_out in self.nodes[0].gettransaction(txB)["details"] + if tx_out["amount"] == Decimal("10000000") + ) + nC = next( + tx_out["vout"] + for tx_out in self.nodes[0].gettransaction(txC)["details"] + if tx_out["amount"] == Decimal("10000000") + ) inputs = [] # spend 10btc outputs from txA and txB @@ -81,12 +99,16 @@ outputs[self.nodes[0].getnewaddress()] = Decimal("14999980") outputs[self.nodes[1].getnewaddress()] = Decimal("5000000") signed = self.nodes[0].signrawtransactionwithwallet( - self.nodes[0].createrawtransaction(inputs, outputs)) + self.nodes[0].createrawtransaction(inputs, outputs) + ) txAB1 = self.nodes[0].sendrawtransaction(signed["hex"]) # Identify the 14,999,980 XEC output - nAB = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction( - txAB1)["details"] if tx_out["amount"] == Decimal("14999980")) + nAB = next( + tx_out["vout"] + for tx_out in self.nodes[0].gettransaction(txAB1)["details"] + if tx_out["amount"] == Decimal("14999980") + ) # Create a child tx spending AB1 and C inputs = [] @@ -97,7 +119,8 @@ outputs = {} outputs[self.nodes[0].getnewaddress()] = Decimal("24999600") signed2 = self.nodes[0].signrawtransactionwithwallet( - self.nodes[0].createrawtransaction(inputs, outputs)) + self.nodes[0].createrawtransaction(inputs, outputs) + ) txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"]) # Create a child tx spending ABC2 @@ -105,24 +128,21 @@ inputs = [{"txid": txABC2, "vout": 0}] outputs = {self.nodes[0].getnewaddress(): signed3_change} signed3 = self.nodes[0].signrawtransactionwithwallet( - self.nodes[0].createrawtransaction(inputs, outputs)) + self.nodes[0].createrawtransaction(inputs, outputs) + ) # note tx is never directly referenced, only abandoned as a child of # the above self.nodes[0].sendrawtransaction(signed3["hex"]) # In mempool txs from self should increase balance from change newbalance = self.nodes[0].getbalance() - assert_equal( - newbalance, - balance - - Decimal("30000000") + - signed3_change) + assert_equal(newbalance, balance - Decimal("30000000") + signed3_change) balance = newbalance # Restart the node with a higher min relay fee so the parent tx is no longer in mempool # TODO: redo with eviction self.restart_node(0, extra_args=["-minrelaytxfee=100"]) - assert self.nodes[0].getmempoolinfo()['loaded'] + assert self.nodes[0].getmempoolinfo()["loaded"] # Verify txs no longer in either node's mempool assert_equal(len(self.nodes[0].getrawmempool()), 0) @@ -136,15 +156,11 @@ # Unconfirmed received funds that are not in mempool also shouldn't show # up in unconfirmed balance. Note that the transactions stored in the wallet # are not necessarily in the node's mempool. - balances = self.nodes[0].getbalances()['mine'] - assert_equal( - balances['untrusted_pending'] + - balances['trusted'], - newbalance) + balances = self.nodes[0].getbalances()["mine"] + assert_equal(balances["untrusted_pending"] + balances["trusted"], newbalance) # Unconfirmed transactions which are not in the mempool should also # not be in listunspent - assert txABC2 not in [utxo["txid"] - for utxo in self.nodes[0].listunspent(0)] + assert txABC2 not in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)] balance = newbalance # Abandon original transaction and verify inputs are available again @@ -156,17 +172,20 @@ self.log.info("Check abandoned transactions in listsinceblock") listsinceblock = self.nodes[0].listsinceblock() - txAB1_listsinceblock = [d for d in listsinceblock['transactions'] - if d['txid'] == txAB1 and d['category'] == 'send'] + txAB1_listsinceblock = [ + d + for d in listsinceblock["transactions"] + if d["txid"] == txAB1 and d["category"] == "send" + ] for tx in txAB1_listsinceblock: - assert_equal(tx['abandoned'], True) - assert_equal(tx['confirmations'], 0) - assert_equal(tx['trusted'], False) + assert_equal(tx["abandoned"], True) + assert_equal(tx["confirmations"], 0) + assert_equal(tx["trusted"], False) # Verify that even with a low min relay fee, the tx is not re-accepted # from wallet on startup once abandoned. self.restart_node(0, extra_args=["-minrelaytxfee=10"]) - assert self.nodes[0].getmempoolinfo()['loaded'] + assert self.nodes[0].getmempoolinfo()["loaded"] assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(self.nodes[0].getbalance(), balance) @@ -178,23 +197,21 @@ # separately from other indices. self.nodes[0].sendrawtransaction(signed["hex"]) newbalance = self.nodes[0].getbalance() - assert_equal( - newbalance, - balance - - Decimal("20000000") + - Decimal("14999980")) + assert_equal(newbalance, balance - Decimal("20000000") + Decimal("14999980")) balance = newbalance # Send child tx again so it is no longer abandoned. self.nodes[0].sendrawtransaction(signed2["hex"]) newbalance = self.nodes[0].getbalance() - assert_equal(newbalance, balance - Decimal("10000000") - - Decimal("14999980") + Decimal("24999600")) + assert_equal( + newbalance, + balance - Decimal("10000000") - Decimal("14999980") + Decimal("24999600"), + ) balance = newbalance # Reset to a higher relay fee so that we abandon a transaction self.restart_node(0, extra_args=["-minrelaytxfee=100"]) - assert self.nodes[0].getmempoolinfo()['loaded'] + assert self.nodes[0].getmempoolinfo()["loaded"] assert_equal(len(self.nodes[0].getrawmempool()), 0) newbalance = self.nodes[0].getbalance() assert_equal(newbalance, balance - Decimal("24999600")) @@ -228,11 +245,15 @@ newbalance = self.nodes[0].getbalance() # assert_equal(newbalance, balance - Decimal("10000000")) self.log.info( - "If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer") + "If balance has not declined after invalidateblock then out of mempool" + " wallet tx which is no longer" + ) self.log.info( - "conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315") + "conflicted has not resumed causing its inputs to be seen as spent. See" + " Issue #7315" + ) self.log.info(f"{str(balance)} -> {str(newbalance)} ?") -if __name__ == '__main__': +if __name__ == "__main__": AbandonConflictTest().main() diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py --- a/test/functional/wallet_address_types.py +++ b/test/functional/wallet_address_types.py @@ -58,26 +58,26 @@ self.connect_nodes(i, j) self.sync_all() - def get_balances(self, key='trusted'): + def get_balances(self, key="trusted"): """Return a list of balances.""" - return [self.nodes[i].getbalances()['mine'][key] for i in range(4)] + return [self.nodes[i].getbalances()["mine"][key] for i in range(4)] def test_address(self, node, address, multisig, typ): """Run sanity checks on an address.""" self.log.info(address) info = self.nodes[node].getaddressinfo(address) - assert self.nodes[node].validateaddress(address)['isvalid'] - assert_equal(info.get('solvable'), True) + assert self.nodes[node].validateaddress(address)["isvalid"] + assert_equal(info.get("solvable"), True) - if not multisig and typ == 'legacy': + if not multisig and typ == "legacy": # P2PKH - assert not info['isscript'] - assert 'pubkey' in info - elif typ == 'legacy': + assert not info["isscript"] + assert "pubkey" in info + elif typ == "legacy": # P2SH-multisig - assert info['isscript'] - assert_equal(info['script'], 'multisig') - assert 'pubkeys' in info + assert info["isscript"] + assert_equal(info["script"], "multisig") + assert "pubkeys" in info else: # Unknown type assert False @@ -85,82 +85,93 @@ def test_desc(self, node, address, multisig, typ, utxo): """Run sanity checks on a descriptor reported by getaddressinfo.""" info = self.nodes[node].getaddressinfo(address) - assert 'desc' in info + assert "desc" in info - assert_equal(info['desc'], utxo['desc']) - assert self.nodes[node].validateaddress(address)['isvalid'] + assert_equal(info["desc"], utxo["desc"]) + assert self.nodes[node].validateaddress(address)["isvalid"] # Use a ridiculously roundabout way to find the key origin info through # the PSBT logic. However, this does test consistency between the PSBT reported # fingerprints/paths and the descriptor logic. psbt = self.nodes[node].createpsbt( - [{'txid': utxo['txid'], 'vout':utxo['vout']}], [{address: 100.00}]) - psbt = self.nodes[node].walletprocesspsbt( - psbt, False, "ALL|FORKID", True) - decode = self.nodes[node].decodepsbt(psbt['psbt']) + [{"txid": utxo["txid"], "vout": utxo["vout"]}], [{address: 100.00}] + ) + psbt = self.nodes[node].walletprocesspsbt(psbt, False, "ALL|FORKID", True) + decode = self.nodes[node].decodepsbt(psbt["psbt"]) key_descs = {} - for deriv in decode['inputs'][0]['bip32_derivs']: - assert_equal(len(deriv['master_fingerprint']), 8) - assert_equal(deriv['path'][0], 'm') - key_descs[deriv['pubkey']] = '[' + deriv['master_fingerprint'] + \ - deriv['path'][1:] + ']' + deriv['pubkey'] + for deriv in decode["inputs"][0]["bip32_derivs"]: + assert_equal(len(deriv["master_fingerprint"]), 8) + assert_equal(deriv["path"][0], "m") + key_descs[deriv["pubkey"]] = ( + "[" + + deriv["master_fingerprint"] + + deriv["path"][1:] + + "]" + + deriv["pubkey"] + ) # Verify the descriptor checksum against the Python implementation - assert descsum_check(info['desc']) + assert descsum_check(info["desc"]) # Verify that stripping the checksum and recreating it using Python # roundtrips - assert info['desc'] == descsum_create(info['desc'][:-9]) + assert info["desc"] == descsum_create(info["desc"][:-9]) # Verify that stripping the checksum and feeding it to # getdescriptorinfo roundtrips - assert info['desc'] == self.nodes[0].getdescriptorinfo( - info['desc'][:-9])['descriptor'] + assert ( + info["desc"] + == self.nodes[0].getdescriptorinfo(info["desc"][:-9])["descriptor"] + ) assert_equal( - info['desc'][-8:], self.nodes[0].getdescriptorinfo(info['desc'][:-9])['checksum']) + info["desc"][-8:], + self.nodes[0].getdescriptorinfo(info["desc"][:-9])["checksum"], + ) # Verify that keeping the checksum and feeding it to getdescriptorinfo # roundtrips - assert info['desc'] == self.nodes[0].getdescriptorinfo(info['desc'])[ - 'descriptor'] - assert_equal(info['desc'][-8:], - self.nodes[0].getdescriptorinfo(info['desc'])['checksum']) + assert ( + info["desc"] == self.nodes[0].getdescriptorinfo(info["desc"])["descriptor"] + ) + assert_equal( + info["desc"][-8:], self.nodes[0].getdescriptorinfo(info["desc"])["checksum"] + ) - if not multisig and typ == 'legacy': + if not multisig and typ == "legacy": # P2PKH - assert_equal(info['desc'], - descsum_create(f"pkh({key_descs[info['pubkey']]})")) - elif typ == 'legacy': + assert_equal( + info["desc"], descsum_create(f"pkh({key_descs[info['pubkey']]})") + ) + elif typ == "legacy": # P2SH-multisig - assert_equal(info['desc'], - descsum_create(f"sh(multi(2,{key_descs[info['pubkeys'][0]]}," - f"{key_descs[info['pubkeys'][1]]}))")) + assert_equal( + info["desc"], + descsum_create( + f"sh(multi(2,{key_descs[info['pubkeys'][0]]}," + f"{key_descs[info['pubkeys'][1]]}))" + ), + ) else: # Unknown type assert False - def test_change_output_type( - self, node_sender, destinations, expected_type): + def test_change_output_type(self, node_sender, destinations, expected_type): txid = self.nodes[node_sender].sendmany( - dummy="", amounts=dict.fromkeys( - destinations, 1000.00)) - tx = self.nodes[node_sender].gettransaction( - txid=txid, verbose=True)['decoded'] + dummy="", amounts=dict.fromkeys(destinations, 1000.00) + ) + tx = self.nodes[node_sender].gettransaction(txid=txid, verbose=True)["decoded"] # Make sure the transaction has change: assert_equal(len(tx["vout"]), len(destinations) + 1) # Make sure the destinations are included, and remove them: - output_addresses = [vout['scriptPubKey']['addresses'][0] - for vout in tx["vout"]] - change_addresses = [ - d for d in output_addresses if d not in destinations] + output_addresses = [vout["scriptPubKey"]["addresses"][0] for vout in tx["vout"]] + change_addresses = [d for d in output_addresses if d not in destinations] assert_equal(len(change_addresses), 1) self.log.debug( - f"Check if change address {change_addresses[0]} is {expected_type}") + f"Check if change address {change_addresses[0]} is {expected_type}" + ) self.test_address( - node_sender, - change_addresses[0], - multisig=False, - typ=expected_type) + node_sender, change_addresses[0], multisig=False, typ=expected_type + ) def run_test(self): # Mine 101 blocks on node4 to bring nodes out of IBD and make sure that @@ -169,8 +180,12 @@ uncompressed_1 = "0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee" uncompressed_2 = "047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77" - compressed_1 = "0296b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52" - compressed_2 = "037211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073" + compressed_1 = ( + "0296b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52" + ) + compressed_2 = ( + "037211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073" + ) if not self.options.descriptors: # Tests for addmultisigaddress's address type behavior is only for @@ -182,29 +197,37 @@ self.test_address( node, self.nodes[node].addmultisigaddress( - 2, [uncompressed_1, uncompressed_2])['address'], + 2, [uncompressed_1, uncompressed_2] + )["address"], True, - 'legacy') + "legacy", + ) self.test_address( node, self.nodes[node].addmultisigaddress( - 2, [compressed_1, uncompressed_2])['address'], + 2, [compressed_1, uncompressed_2] + )["address"], True, - 'legacy') + "legacy", + ) self.test_address( node, self.nodes[node].addmultisigaddress( - 2, [uncompressed_1, compressed_2])['address'], + 2, [uncompressed_1, compressed_2] + )["address"], True, - 'legacy') + "legacy", + ) # addmultisigaddress with all compressed keys should return the # appropriate address type (even when the keys are not ours). self.test_address( 0, - self.nodes[0].addmultisigaddress( - 2, [compressed_1, compressed_2])['address'], + self.nodes[0].addmultisigaddress(2, [compressed_1, compressed_2])[ + "address" + ], True, - 'legacy') + "legacy", + ) do_multisigs = [False] if not self.options.descriptors: @@ -212,13 +235,12 @@ for multisig, from_node in itertools.product(do_multisigs, range(4)): self.log.info( - f"Sending from node {from_node} with{'' if multisig else 'out'} multisig") + "Sending from node" + f" {from_node} with{'' if multisig else 'out'} multisig" + ) old_balances = self.get_balances() self.log.debug(f"Old balances are {old_balances}") - to_send = ( - old_balances[from_node] / - 101).quantize( - Decimal("0.01")) + to_send = (old_balances[from_node] / 101).quantize(Decimal("0.01")) sends = {} addresses = {} @@ -236,10 +258,11 @@ addr1 = self.nodes[to_node].getnewaddress() addr2 = self.nodes[to_node].getnewaddress() address = self.nodes[to_node].addmultisigaddress(2, [addr1, addr2])[ - 'address'] + "address" + ] # Do some sanity checking on the created address - typ = 'legacy' + typ = "legacy" self.test_address(to_node, address, multisig, typ) # Output entry @@ -250,9 +273,8 @@ self.nodes[from_node].sendmany("", sends) self.sync_mempools() - unconf_balances = self.get_balances('untrusted_pending') - self.log.debug( - f"Check unconfirmed balances: {unconf_balances}") + unconf_balances = self.get_balances("untrusted_pending") + self.log.debug(f"Check unconfirmed balances: {unconf_balances}") assert_equal(unconf_balances[from_node], 0) for n, to_node in enumerate(range(from_node + 1, from_node + 4)): to_node %= 4 @@ -267,14 +289,15 @@ to_node %= 4 found = False for utxo in self.nodes[to_node].listunspent(): - if utxo['address'] == addresses[to_node][0]: + if utxo["address"] == addresses[to_node][0]: found = True self.test_desc( to_node, addresses[to_node][0], multisig, addresses[to_node][1], - utxo) + utxo, + ) break assert found @@ -287,7 +310,9 @@ for n, to_node in enumerate(range(from_node + 1, from_node + 4)): to_node %= 4 assert_equal( - new_balances[to_node], old_balances[to_node] + to_send * 10 * (2 + n)) + new_balances[to_node], + old_balances[to_node] + to_send * 10 * (2 + n), + ) # Get addresses from node2 and node3: to_address_2 = self.nodes[2].getnewaddress() @@ -295,22 +320,18 @@ to_address_3_2 = self.nodes[3].getnewaddress() self.log.info("Various change output tests") - self.test_change_output_type(0, [to_address_3_1], 'legacy') - self.test_change_output_type(1, [to_address_2], 'legacy') - self.test_change_output_type(1, [to_address_3_1], 'legacy') - self.test_change_output_type( - 1, [to_address_2, to_address_3_1], 'legacy') - self.test_change_output_type( - 1, [to_address_3_1, to_address_3_2], 'legacy') - self.test_change_output_type(2, [to_address_3_1], 'legacy') - - self.log.info('Test getrawchangeaddress') + self.test_change_output_type(0, [to_address_3_1], "legacy") + self.test_change_output_type(1, [to_address_2], "legacy") + self.test_change_output_type(1, [to_address_3_1], "legacy") + self.test_change_output_type(1, [to_address_2, to_address_3_1], "legacy") + self.test_change_output_type(1, [to_address_3_1, to_address_3_2], "legacy") + self.test_change_output_type(2, [to_address_3_1], "legacy") + + self.log.info("Test getrawchangeaddress") self.test_address( - 3, - self.nodes[3].getrawchangeaddress(), - multisig=False, - typ='legacy') + 3, self.nodes[3].getrawchangeaddress(), multisig=False, typ="legacy" + ) -if __name__ == '__main__': +if __name__ == "__main__": AddressTypeTest().main() diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py --- a/test/functional/wallet_avoidreuse.py +++ b/test/functional/wallet_avoidreuse.py @@ -9,18 +9,19 @@ def reset_balance(node, discardaddr): - '''Throw away all owned coins by the node so it gets a balance of 0.''' + """Throw away all owned coins by the node so it gets a balance of 0.""" balance = node.getbalance(avoid_reuse=False) if balance > 500000: node.sendtoaddress( address=discardaddr, amount=balance, subtractfeefromamount=True, - avoid_reuse=False) + avoid_reuse=False, + ) def count_unspent(node): - '''Count the unspent outputs for the given node and return various statistics''' + """Count the unspent outputs for the given node and return various statistics""" r = { "total": { "count": 0, @@ -45,9 +46,15 @@ return r -def assert_unspent(node, total_count=None, total_sum=None, - reused_supported=None, reused_count=None, reused_sum=None): - '''Make assertions about a node's unspent output statistics''' +def assert_unspent( + node, + total_count=None, + total_sum=None, + reused_supported=None, + reused_count=None, + reused_sum=None, +): + """Make assertions about a node's unspent output statistics""" stats = count_unspent(node) if total_count is not None: assert_equal(stats["total"]["count"], total_count) @@ -62,14 +69,13 @@ def assert_balances(node, mine): - '''Make assertions about a node's getbalances output''' + """Make assertions about a node's getbalances output""" got = node.getbalances()["mine"] for k, v in mine.items(): assert_approx(got[k], v, 1000) class AvoidReuseTest(BitcoinTestFramework): - def set_test_params(self): self.num_nodes = 2 # This test isn't testing txn relay/timing, so set whitelist on the @@ -80,7 +86,7 @@ self.skip_if_no_wallet() def run_test(self): - '''Set up initial chain and run tests defined below''' + """Set up initial chain and run tests defined below""" self.test_persistence() self.test_immutable() @@ -99,11 +105,11 @@ self.test_all_destination_groups_are_used() def test_persistence(self): - '''Test that wallet files persist the avoid_reuse flag.''' + """Test that wallet files persist the avoid_reuse flag.""" self.log.info("Test wallet files persist avoid_reuse flag") # Configure node 1 to use avoid_reuse - self.nodes[1].setwalletflag('avoid_reuse') + self.nodes[1].setwalletflag("avoid_reuse") # Flags should be node1.avoid_reuse=false, node2.avoid_reuse=true assert_equal(self.nodes[0].getwalletinfo()["avoid_reuse"], False) @@ -118,80 +124,83 @@ assert_equal(self.nodes[1].getwalletinfo()["avoid_reuse"], True) # Attempting to set flag to its current state should throw - assert_raises_rpc_error(-8, - "Wallet flag is already set to false", - self.nodes[0].setwalletflag, - 'avoid_reuse', - False) - assert_raises_rpc_error(-8, - "Wallet flag is already set to true", - self.nodes[1].setwalletflag, - 'avoid_reuse', - True) + assert_raises_rpc_error( + -8, + "Wallet flag is already set to false", + self.nodes[0].setwalletflag, + "avoid_reuse", + False, + ) + assert_raises_rpc_error( + -8, + "Wallet flag is already set to true", + self.nodes[1].setwalletflag, + "avoid_reuse", + True, + ) def test_immutable(self): - '''Test immutable wallet flags''' + """Test immutable wallet flags""" self.log.info("Test immutable wallet flags") # Attempt to set the disable_private_keys flag; this should not work - assert_raises_rpc_error(-8, - "Wallet flag is immutable", - self.nodes[1].setwalletflag, - 'disable_private_keys') + assert_raises_rpc_error( + -8, + "Wallet flag is immutable", + self.nodes[1].setwalletflag, + "disable_private_keys", + ) tempwallet = ".wallet_avoidreuse.py_test_immutable_wallet.dat" # Create a wallet with disable_private_keys set; this should work - self.nodes[1].createwallet(wallet_name=tempwallet, - disable_private_keys=True) + self.nodes[1].createwallet(wallet_name=tempwallet, disable_private_keys=True) w = self.nodes[1].get_wallet_rpc(tempwallet) # Attempt to unset the disable_private_keys flag; this should not work - assert_raises_rpc_error(-8, - "Wallet flag is immutable", - w.setwalletflag, - 'disable_private_keys', - False) + assert_raises_rpc_error( + -8, + "Wallet flag is immutable", + w.setwalletflag, + "disable_private_keys", + False, + ) # Unload temp wallet self.nodes[1].unloadwallet(tempwallet) def test_change_remains_change(self, node): - self.log.info( - "Test that change doesn't turn into non-change when spent") + self.log.info("Test that change doesn't turn into non-change when spent") reset_balance(node, node.getnewaddress()) addr = node.getnewaddress() txid = node.sendtoaddress(addr, 1000000) - out = node.listunspent( - minconf=0, query_options={ - 'minimumAmount': 2000000}) + out = node.listunspent(minconf=0, query_options={"minimumAmount": 2000000}) assert_equal(len(out), 1) - assert_equal(out[0]['txid'], txid) - changeaddr = out[0]['address'] + assert_equal(out[0]["txid"], txid) + changeaddr = out[0]["address"] # Make sure it's starting out as change as expected - assert node.getaddressinfo(changeaddr)['ischange'] + assert node.getaddressinfo(changeaddr)["ischange"] for logical_tx in node.listtransactions(): - assert logical_tx.get('address') != changeaddr + assert logical_tx.get("address") != changeaddr # Spend it reset_balance(node, node.getnewaddress()) # It should still be change - assert node.getaddressinfo(changeaddr)['ischange'] + assert node.getaddressinfo(changeaddr)["ischange"] for logical_tx in node.listtransactions(): - assert logical_tx.get('address') != changeaddr + assert logical_tx.get("address") != changeaddr def test_sending_from_reused_address_without_avoid_reuse(self): - ''' + """ Test the same as test_sending_from_reused_address_fails, except send the 10MM XEC with the avoid_reuse flag set to false. This means the 10MM XEC send should succeed, where it fails in test_sending_from_reused_address_fails. - ''' - self.log.info( - "Test sending from reused address with avoid_reuse=false") + """ + self.log.info("Test sending from reused address with avoid_reuse=false") fundaddr = self.nodes[1].getnewaddress() retaddr = self.nodes[0].getnewaddress() @@ -205,7 +214,8 @@ total_count=1, total_sum=10000000, reused_supported=True, - reused_count=0) + reused_count=0, + ) # getbalances should show no used, 10MM XEC trusted assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10000000}) # node 0 should not show a used entry, as it does not enable @@ -221,7 +231,8 @@ total_count=1, total_sum=5000000, reused_supported=True, - reused_count=0) + reused_count=0, + ) # getbalances should show no used, 5MM XEC trusted assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5000000}) @@ -235,43 +246,31 @@ total_count=2, total_sum=15000000, reused_count=1, - reused_sum=10000000) + reused_sum=10000000, + ) # getbalances should show 10MM used, 5MM XEC trusted - assert_balances( - self.nodes[1], - mine={ - "used": 10000000, - "trusted": 5000000}) + assert_balances(self.nodes[1], mine={"used": 10000000, "trusted": 5000000}) - self.nodes[1].sendtoaddress( - address=retaddr, amount=10000000, avoid_reuse=False) + self.nodes[1].sendtoaddress(address=retaddr, amount=10000000, avoid_reuse=False) # listunspent should show 1 total outputs (5MM XEC), unused - assert_unspent( - self.nodes[1], - total_count=1, - total_sum=5000000, - reused_count=0) + assert_unspent(self.nodes[1], total_count=1, total_sum=5000000, reused_count=0) # getbalances should show no used, 5MM XEC trusted assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5000000}) # node 1 should now have about 5MM XEC left (for both cases) assert_approx(self.nodes[1].getbalance(), 5000000, 1000) - assert_approx( - self.nodes[1].getbalance( - avoid_reuse=False), - 5000000, - 1000) + assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 5000000, 1000) def test_sending_from_reused_address_fails(self): - ''' + """ Test the simple case where [1] generates a new address A, then [0] sends 10MM XEC to A. [1] spends 5MM XEC from A. (leaving roughly 5MM XEC useable) [0] sends 10MM XEC to A again. [1] tries to spend 10MM XEC (fails; dirty). [1] tries to spend 4MM XEC (succeeds; change address sufficient) - ''' + """ self.log.info("Test sending from reused address fails") fundaddr = self.nodes[1].getnewaddress(label="", address_type="legacy") @@ -286,7 +285,8 @@ total_count=1, total_sum=10000000, reused_supported=True, - reused_count=0) + reused_count=0, + ) # getbalances should show no used, 10MM XEC trusted assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10000000}) @@ -299,7 +299,8 @@ total_count=1, total_sum=5000000, reused_supported=True, - reused_count=0) + reused_count=0, + ) # getbalances should show no used, 5MM XEC trusted assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5000000}) @@ -320,25 +321,19 @@ total_count=2, total_sum=15000000, reused_count=1, - reused_sum=10000000) + reused_sum=10000000, + ) # getbalances should show 10MM used, 5MM XEC trusted - assert_balances( - self.nodes[1], - mine={ - "used": 10000000, - "trusted": 5000000}) + assert_balances(self.nodes[1], mine={"used": 10000000, "trusted": 5000000}) # node 1 should now have a balance of 5MM (no dirty) or 15MM # (including dirty) assert_approx(self.nodes[1].getbalance(), 5000000, 1000) - assert_approx( - self.nodes[1].getbalance( - avoid_reuse=False), - 15000000, - 1000) + assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 15000000, 1000) - assert_raises_rpc_error(-6, "Insufficient funds", - self.nodes[1].sendtoaddress, retaddr, 10000000) + assert_raises_rpc_error( + -6, "Insufficient funds", self.nodes[1].sendtoaddress, retaddr, 10000000 + ) self.nodes[1].sendtoaddress(retaddr, 4000000) @@ -349,29 +344,22 @@ total_count=2, total_sum=11000000, reused_count=1, - reused_sum=10000000) + reused_sum=10000000, + ) # getbalances should show 10MM used, 1MM XEC trusted - assert_balances( - self.nodes[1], - mine={ - "used": 10000000, - "trusted": 1000000}) + assert_balances(self.nodes[1], mine={"used": 10000000, "trusted": 1000000}) # node 1 should now have about 1MM XEC left (no dirty) and 11MM # (including dirty) assert_approx(self.nodes[1].getbalance(), 1000000, 1000) - assert_approx( - self.nodes[1].getbalance( - avoid_reuse=False), - 11000000, - 1000) + assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11000000, 1000) def test_getbalances_used(self): - ''' + """ getbalances and listunspent should pick up on reused addresses immediately, even for address reusing outputs created before the first transaction was spending from that address - ''' + """ self.log.info("Test getbalances used category") # node under test should be completely empty @@ -397,23 +385,21 @@ total_count=2, total_sum=6000000, reused_count=1, - reused_sum=1000000) - assert_balances( - self.nodes[1], - mine={ - "used": 1000000, - "trusted": 5000000}) + reused_sum=1000000, + ) + assert_balances(self.nodes[1], mine={"used": 1000000, "trusted": 5000000}) def test_full_destination_group_is_preferred(self): - ''' + """ Test the case where [1] only has 11 outputs of 1MM XEC in the same reused address and tries to send a small payment of 500,000 XEC. The wallet should use 10 outputs from the reused address as inputs and not a single 1MM XEC input, in order to join several outputs from the reused address. - ''' + """ self.log.info( - "Test that full destination groups are preferred in coin selection") + "Test that full destination groups are preferred in coin selection" + ) # Node under test should be empty assert_equal(self.nodes[1].getbalance(avoid_reuse=False), 0) @@ -436,11 +422,11 @@ assert_equal(len(inputs), 10) def test_all_destination_groups_are_used(self): - ''' + """ Test the case where [1] only has 22 outputs of 1MM XEC in the same reused address and tries to send a payment of 20,5MM XEC. The wallet should use all 22 outputs from the reused address as inputs. - ''' + """ self.log.info("Test that all destination groups are used") # Node under test should be empty @@ -464,5 +450,5 @@ assert_equal(len(inputs), 22) -if __name__ == '__main__': +if __name__ == "__main__": AvoidReuseTest().main() diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py --- a/test/functional/wallet_backup.py +++ b/test/functional/wallet_backup.py @@ -65,7 +65,7 @@ self.sync_all() def one_send(self, from_node, to_address): - if (randint(1, 2) == 1): + if randint(1, 2) == 1: amount = Decimal(randint(1, 10)) * Decimal(100000) self.nodes[from_node].sendtoaddress(to_address, amount) @@ -103,35 +103,58 @@ def erase_three(self): os.remove( - os.path.join(self.nodes[0].datadir, self.chain, 'wallets', - self.default_wallet_name, self.wallet_data_filename)) + os.path.join( + self.nodes[0].datadir, + self.chain, + "wallets", + self.default_wallet_name, + self.wallet_data_filename, + ) + ) os.remove( - os.path.join(self.nodes[1].datadir, self.chain, 'wallets', - self.default_wallet_name, self.wallet_data_filename)) + os.path.join( + self.nodes[1].datadir, + self.chain, + "wallets", + self.default_wallet_name, + self.wallet_data_filename, + ) + ) os.remove( - os.path.join(self.nodes[2].datadir, self.chain, 'wallets', - self.default_wallet_name, self.wallet_data_filename)) + os.path.join( + self.nodes[2].datadir, + self.chain, + "wallets", + self.default_wallet_name, + self.wallet_data_filename, + ) + ) def restore_nonexistent_wallet(self): node = self.nodes[3] nonexistent_wallet_file = os.path.join( - self.nodes[0].datadir, 'nonexistent_wallet.bak') + self.nodes[0].datadir, "nonexistent_wallet.bak" + ) wallet_name = "res0" - assert_raises_rpc_error(-8, - "Backup file does not exist", - node.restorewallet, - wallet_name, - nonexistent_wallet_file) + assert_raises_rpc_error( + -8, + "Backup file does not exist", + node.restorewallet, + wallet_name, + nonexistent_wallet_file, + ) def restore_wallet_existent_name(self): node = self.nodes[3] - wallet_file = os.path.join(self.nodes[0].datadir, 'wallet.bak') + wallet_file = os.path.join(self.nodes[0].datadir, "wallet.bak") wallet_name = "res0" - assert_raises_rpc_error(-8, - "Wallet name already exists.", - node.restorewallet, - wallet_name, - wallet_file) + assert_raises_rpc_error( + -8, + "Wallet name already exists.", + node.restorewallet, + wallet_name, + wallet_file, + ) def run_test(self): self.log.info("Generating initial blockchain") @@ -151,18 +174,12 @@ self.do_one_round() self.log.info("Backing up") - self.nodes[0].backupwallet(os.path.join( - self.nodes[0].datadir, 'wallet.bak')) - self.nodes[0].dumpwallet(os.path.join( - self.nodes[0].datadir, 'wallet.dump')) - self.nodes[1].backupwallet(os.path.join( - self.nodes[1].datadir, 'wallet.bak')) - self.nodes[1].dumpwallet(os.path.join( - self.nodes[1].datadir, 'wallet.dump')) - self.nodes[2].backupwallet(os.path.join( - self.nodes[2].datadir, 'wallet.bak')) - self.nodes[2].dumpwallet(os.path.join( - self.nodes[2].datadir, 'wallet.dump')) + self.nodes[0].backupwallet(os.path.join(self.nodes[0].datadir, "wallet.bak")) + self.nodes[0].dumpwallet(os.path.join(self.nodes[0].datadir, "wallet.dump")) + self.nodes[1].backupwallet(os.path.join(self.nodes[1].datadir, "wallet.bak")) + self.nodes[1].dumpwallet(os.path.join(self.nodes[1].datadir, "wallet.dump")) + self.nodes[2].backupwallet(os.path.join(self.nodes[2].datadir, "wallet.bak")) + self.nodes[2].dumpwallet(os.path.join(self.nodes[2].datadir, "wallet.dump")) self.log.info("More transactions") for _ in range(5): @@ -188,9 +205,9 @@ self.restore_nonexistent_wallet() - backup_file_0 = os.path.join(self.nodes[0].datadir, 'wallet.bak') - backup_file_1 = os.path.join(self.nodes[1].datadir, 'wallet.bak') - backup_file_2 = os.path.join(self.nodes[2].datadir, 'wallet.bak') + backup_file_0 = os.path.join(self.nodes[0].datadir, "wallet.bak") + backup_file_1 = os.path.join(self.nodes[1].datadir, "wallet.bak") + backup_file_2 = os.path.join(self.nodes[2].datadir, "wallet.bak") self.nodes[3].restorewallet("res0", backup_file_0) self.nodes[3].restorewallet("res1", backup_file_1) @@ -211,13 +228,8 @@ self.erase_three() # start node2 with no chain - shutil.rmtree( - os.path.join( - self.nodes[2].datadir, - self.chain, - 'blocks')) - shutil.rmtree(os.path.join( - self.nodes[2].datadir, self.chain, 'chainstate')) + shutil.rmtree(os.path.join(self.nodes[2].datadir, self.chain, "blocks")) + shutil.rmtree(os.path.join(self.nodes[2].datadir, self.chain, "chainstate")) self.start_three() @@ -225,12 +237,9 @@ assert_equal(self.nodes[1].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 0) - self.nodes[0].importwallet(os.path.join( - self.nodes[0].datadir, 'wallet.dump')) - self.nodes[1].importwallet(os.path.join( - self.nodes[1].datadir, 'wallet.dump')) - self.nodes[2].importwallet(os.path.join( - self.nodes[2].datadir, 'wallet.dump')) + self.nodes[0].importwallet(os.path.join(self.nodes[0].datadir, "wallet.dump")) + self.nodes[1].importwallet(os.path.join(self.nodes[1].datadir, "wallet.dump")) + self.nodes[2].importwallet(os.path.join(self.nodes[2].datadir, "wallet.dump")) self.sync_blocks() @@ -240,18 +249,32 @@ # Backup to source wallet file must fail sourcePaths = [ - os.path.join(self.nodes[0].datadir, self.chain, 'wallets', - self.default_wallet_name, self.wallet_data_filename), - os.path.join(self.nodes[0].datadir, self.chain, '.', 'wallets', - self.default_wallet_name, self.wallet_data_filename), - os.path.join(self.nodes[0].datadir, self.chain, 'wallets', - self.default_wallet_name), - os.path.join(self.nodes[0].datadir, self.chain, 'wallets')] + os.path.join( + self.nodes[0].datadir, + self.chain, + "wallets", + self.default_wallet_name, + self.wallet_data_filename, + ), + os.path.join( + self.nodes[0].datadir, + self.chain, + ".", + "wallets", + self.default_wallet_name, + self.wallet_data_filename, + ), + os.path.join( + self.nodes[0].datadir, self.chain, "wallets", self.default_wallet_name + ), + os.path.join(self.nodes[0].datadir, self.chain, "wallets"), + ] for sourcePath in sourcePaths: - assert_raises_rpc_error(-4, "backup failed", - self.nodes[0].backupwallet, sourcePath) + assert_raises_rpc_error( + -4, "backup failed", self.nodes[0].backupwallet, sourcePath + ) -if __name__ == '__main__': +if __name__ == "__main__": WalletBackupTest().main() diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py --- a/test/functional/wallet_balance.py +++ b/test/functional/wallet_balance.py @@ -17,14 +17,14 @@ # Create and sign raw transactions from node to address for amt. # Creates a transaction for each fee and returns an array # of the raw transactions. - utxos = [u for u in node.listunspent(0) if u['spendable']] + utxos = [u for u in node.listunspent(0) if u["spendable"]] # Create transactions inputs = [] ins_total = 0 for utxo in utxos: inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) - ins_total += utxo['amount'] + ins_total += utxo["amount"] if ins_total >= amt + max(fees): break # make sure there was enough utxos @@ -38,7 +38,7 @@ outputs[node.getrawchangeaddress()] = ins_total - amt - fee raw_tx = node.createrawtransaction(inputs, outputs, 0) raw_tx = node.signrawtransactionwithwallet(raw_tx) - assert_equal(raw_tx['complete'], True) + assert_equal(raw_tx["complete"], True) txs.append(raw_tx) return txs @@ -52,9 +52,10 @@ # Limit mempool descendants as a hack to have wallet txs rejected # from the mempool. This will no longer work after wellington, so # move the activation in the future for this test. - ['-limitdescendantcount=3', - f'-wellingtonactivationtime={FAR_IN_THE_FUTURE}', - ], + [ + "-limitdescendantcount=3", + f"-wellingtonactivationtime={FAR_IN_THE_FUTURE}", + ], [], ] # whitelist peers to speed up tx relay / mempool sync @@ -74,8 +75,8 @@ assert_equal(len(self.nodes[1].listunspent()), 0) self.log.info("Check that only node 0 is watching an address") - assert 'watchonly' in self.nodes[0].getbalances() - assert 'watchonly' not in self.nodes[1].getbalances() + assert "watchonly" in self.nodes[0].getbalances() + assert "watchonly" not in self.nodes[1].getbalances() self.log.info("Mining blocks ...") self.generate(self.nodes[0], 1) @@ -85,15 +86,14 @@ if not self.options.descriptors: # Tests legacy watchonly behavior which is not present (and does not # need to be tested) in descriptor wallets - assert_equal(self.nodes[0].getbalances()['mine']['trusted'], - 50000000) - assert_equal(self.nodes[0].getwalletinfo()['balance'], 50000000) - assert_equal(self.nodes[1].getbalances()['mine']['trusted'], - 50000000) + assert_equal(self.nodes[0].getbalances()["mine"]["trusted"], 50000000) + assert_equal(self.nodes[0].getwalletinfo()["balance"], 50000000) + assert_equal(self.nodes[1].getbalances()["mine"]["trusted"], 50000000) - assert_equal(self.nodes[0].getbalances()['watchonly']['immature'], - 5000000000) - assert 'watchonly' not in self.nodes[1].getbalances() + assert_equal( + self.nodes[0].getbalances()["watchonly"]["immature"], 5000000000 + ) + assert "watchonly" not in self.nodes[1].getbalances() assert_equal(self.nodes[0].getbalance(), 50000000) assert_equal(self.nodes[1].getbalance(), 50000000) @@ -104,40 +104,47 @@ assert_equal(self.nodes[0].getbalance(minconf=1), 50000000) if not self.options.descriptors: - assert_equal(self.nodes[0].getbalance(minconf=0, - include_watchonly=True), - 100_000_000) + assert_equal( + self.nodes[0].getbalance(minconf=0, include_watchonly=True), 100_000_000 + ) assert_equal(self.nodes[0].getbalance("*", 1, True), 100_000_000) else: - assert_equal(self.nodes[0].getbalance(minconf=0, - include_watchonly=True), - 50_000_000) + assert_equal( + self.nodes[0].getbalance(minconf=0, include_watchonly=True), 50_000_000 + ) assert_equal(self.nodes[0].getbalance("*", 1, True), 50_000_000) assert_equal( - self.nodes[1].getbalance( - minconf=0, - include_watchonly=True), - 50000000) + self.nodes[1].getbalance(minconf=0, include_watchonly=True), 50000000 + ) # Send 40 BTC from 0 to 1 and 60 BTC from 1 to 0. txs = create_transactions( - self.nodes[0], self.nodes[1].getnewaddress(), 40000000, [Decimal('10000')]) - self.nodes[0].sendrawtransaction(txs[0]['hex']) + self.nodes[0], self.nodes[1].getnewaddress(), 40000000, [Decimal("10000")] + ) + self.nodes[0].sendrawtransaction(txs[0]["hex"]) # sending on both nodes is faster than waiting for propagation - self.nodes[1].sendrawtransaction(txs[0]['hex']) + self.nodes[1].sendrawtransaction(txs[0]["hex"]) self.sync_all() - txs = create_transactions(self.nodes[1], self.nodes[0].getnewaddress(), 60000000, [ - Decimal('10000'), Decimal('20000')]) - self.nodes[1].sendrawtransaction(txs[0]['hex']) + txs = create_transactions( + self.nodes[1], + self.nodes[0].getnewaddress(), + 60000000, + [Decimal("10000"), Decimal("20000")], + ) + self.nodes[1].sendrawtransaction(txs[0]["hex"]) # sending on both nodes is faster than waiting for propagation - self.nodes[0].sendrawtransaction(txs[0]['hex']) + self.nodes[0].sendrawtransaction(txs[0]["hex"]) self.sync_all() # First argument of getbalance must be set to "*" - assert_raises_rpc_error(-32, "dummy first argument must be excluded or set to \"*\"", - self.nodes[1].getbalance, "") + assert_raises_rpc_error( + -32, + 'dummy first argument must be excluded or set to "*"', + self.nodes[1].getbalance, + "", + ) self.log.info("Test balances with unconfirmed inputs") @@ -180,56 +187,64 @@ def test_balances(*, fee_node_1=0): # getbalances - expected_balances_0 = {'mine': {'immature': Decimal('0E-2'), - # change from node 0's send - 'trusted': Decimal('9990000'), - 'untrusted_pending': Decimal('60000000.0')}, - 'watchonly': {'immature': Decimal('5000000000'), - 'trusted': Decimal('50000000.0'), - 'untrusted_pending': Decimal('0E-2')}} - expected_balances_1 = {'mine': {'immature': Decimal('0E-2'), - # node 1's send had an unsafe input - 'trusted': Decimal('0E-2'), - # Doesn't include output of node - # 0's send since it was spent - 'untrusted_pending': Decimal('30000000.0') - fee_node_1}} + expected_balances_0 = { + "mine": { + "immature": Decimal("0E-2"), + # change from node 0's send + "trusted": Decimal("9990000"), + "untrusted_pending": Decimal("60000000.0"), + }, + "watchonly": { + "immature": Decimal("5000000000"), + "trusted": Decimal("50000000.0"), + "untrusted_pending": Decimal("0E-2"), + }, + } + expected_balances_1 = { + "mine": { + "immature": Decimal("0E-2"), + # node 1's send had an unsafe input + "trusted": Decimal("0E-2"), + # Doesn't include output of node + # 0's send since it was spent + "untrusted_pending": Decimal("30000000.0") - fee_node_1, + } + } if self.options.descriptors: del expected_balances_0["watchonly"] assert_equal(self.nodes[0].getbalances(), expected_balances_0) assert_equal(self.nodes[1].getbalances(), expected_balances_1) # getbalance without any arguments includes unconfirmed transactions, but not untrusted transactions # change from node 0's send - assert_equal(self.nodes[0].getbalance(), Decimal('9990000')) + assert_equal(self.nodes[0].getbalance(), Decimal("9990000")) # node 1's send had an unsafe input - assert_equal(self.nodes[1].getbalance(), Decimal('0')) + assert_equal(self.nodes[1].getbalance(), Decimal("0")) # Same with minconf=0 - assert_equal( - self.nodes[0].getbalance( - minconf=0), - Decimal('9990000')) - assert_equal(self.nodes[1].getbalance(minconf=0), Decimal('0')) + assert_equal(self.nodes[0].getbalance(minconf=0), Decimal("9990000")) + assert_equal(self.nodes[1].getbalance(minconf=0), Decimal("0")) # getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago # TODO: fix getbalance tracking of coin spentness depth - assert_equal(self.nodes[0].getbalance(minconf=1), Decimal('0')) - assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0')) + assert_equal(self.nodes[0].getbalance(minconf=1), Decimal("0")) + assert_equal(self.nodes[1].getbalance(minconf=1), Decimal("0")) # getunconfirmedbalance # output of node 1's spend - assert_equal( - self.nodes[0].getunconfirmedbalance(), - Decimal('60000000')) + assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal("60000000")) # Doesn't include output of node 0's send since it was spent assert_equal( - self.nodes[1].getunconfirmedbalance(), - Decimal('30000000') - fee_node_1) + self.nodes[1].getunconfirmedbalance(), Decimal("30000000") - fee_node_1 + ) # getwalletinfo.unconfirmed_balance - assert_equal(self.nodes[0].getwalletinfo()[ - "unconfirmed_balance"], Decimal('60000000')) + assert_equal( + self.nodes[0].getwalletinfo()["unconfirmed_balance"], + Decimal("60000000"), + ) assert_equal( self.nodes[1].getwalletinfo()["unconfirmed_balance"], - Decimal('30000000') - fee_node_1) + Decimal("30000000") - fee_node_1, + ) - test_balances(fee_node_1=Decimal('10000')) + test_balances(fee_node_1=Decimal("10000")) # In the original Core version of this test, Node 1 would've bumped # the fee by 0.01 here to resend, but this is XEC, so it has 10000 XEC @@ -237,106 +252,100 @@ self.sync_all() self.log.info( - "Test getbalance and getbalances.mine.untrusted_pending with conflicted unconfirmed inputs") - test_balances(fee_node_1=Decimal('10000')) + "Test getbalance and getbalances.mine.untrusted_pending with conflicted" + " unconfirmed inputs" + ) + test_balances(fee_node_1=Decimal("10000")) self.generatetoaddress(self.nodes[1], 1, ADDRESS_WATCHONLY) # balances are correct after the transactions are confirmed # node 1's send plus change from node 0's send - balance_node0 = Decimal('69990000') + balance_node0 = Decimal("69990000") # change from node 0's send - balance_node1 = Decimal('29990000') - assert_equal(self.nodes[0].getbalances()[ - 'mine']['trusted'], balance_node0) - assert_equal(self.nodes[1].getbalances()[ - 'mine']['trusted'], balance_node1) + balance_node1 = Decimal("29990000") + assert_equal(self.nodes[0].getbalances()["mine"]["trusted"], balance_node0) + assert_equal(self.nodes[1].getbalances()["mine"]["trusted"], balance_node1) assert_equal(self.nodes[0].getbalance(), balance_node0) assert_equal(self.nodes[1].getbalance(), balance_node1) # Send total balance away from node 1 - txs = create_transactions(self.nodes[1], self.nodes[0].getnewaddress( - ), Decimal('29970000'), [Decimal('10000')]) - self.nodes[1].sendrawtransaction(txs[0]['hex']) + txs = create_transactions( + self.nodes[1], + self.nodes[0].getnewaddress(), + Decimal("29970000"), + [Decimal("10000")], + ) + self.nodes[1].sendrawtransaction(txs[0]["hex"]) self.generatetoaddress(self.nodes[1], 2, ADDRESS_WATCHONLY) # getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago # TODO: fix getbalance tracking of coin spentness depth # getbalance with minconf=3 should still show the old balance - assert_equal(self.nodes[1].getbalance(minconf=3), Decimal('0')) + assert_equal(self.nodes[1].getbalance(minconf=3), Decimal("0")) # getbalance with minconf=2 will show the new balance. - assert_equal(self.nodes[1].getbalance(minconf=2), Decimal('10000')) + assert_equal(self.nodes[1].getbalance(minconf=2), Decimal("10000")) # check mempool transactions count for wallet unconfirmed balance after # dynamically loading the wallet. - before = self.nodes[1].getbalances()['mine']['untrusted_pending'] + before = self.nodes[1].getbalances()["mine"]["untrusted_pending"] dst = self.nodes[1].getnewaddress() self.nodes[1].unloadwallet(self.default_wallet_name) self.nodes[0].sendtoaddress(dst, 100000) self.sync_all() self.nodes[1].loadwallet(self.default_wallet_name) - after = self.nodes[1].getbalances()['mine']['untrusted_pending'] - assert_equal(before + Decimal('100000'), after) + after = self.nodes[1].getbalances()["mine"]["untrusted_pending"] + assert_equal(before + Decimal("100000"), after) # Create 3 more wallet txs, where the last is not accepted to the # mempool because it is the third descendant of the tx above for _ in range(3): # Set amount high enough such that all coins are spent by each tx - txid = self.nodes[0].sendtoaddress( - self.nodes[0].getnewaddress(), 99000000) + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 99000000) - self.log.info('Check that wallet txs not in the mempool are untrusted') + self.log.info("Check that wallet txs not in the mempool are untrusted") assert txid not in self.nodes[0].getrawmempool() - assert_equal(self.nodes[0].gettransaction(txid)['trusted'], False) + assert_equal(self.nodes[0].gettransaction(txid)["trusted"], False) assert_equal(self.nodes[0].getbalance(minconf=0), 0) self.log.info("Test replacement and reorg of non-mempool tx") - tx_orig = self.nodes[0].gettransaction(txid)['hex'] + tx_orig = self.nodes[0].gettransaction(txid)["hex"] # Increase fee by 1 coin tx_replace = tx_orig.replace( struct.pack(" 1 for address in output_addresses: - ischange = self.nodes[0].getaddressinfo(address)['ischange'] + ischange = self.nodes[0].getaddressinfo(address)["ischange"] assert_equal(ischange, address != destination) if ischange: change = address - self.nodes[0].setlabel(change, 'foobar') - assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False) + self.nodes[0].setlabel(change, "foobar") + assert_equal(self.nodes[0].getaddressinfo(change)["ischange"], False) # Test gettransaction response with different arguments. - self.log.info( - "Testing gettransaction response with different arguments...") - self.nodes[0].setlabel(change, 'baz') + self.log.info("Testing gettransaction response with different arguments...") + self.nodes[0].setlabel(change, "baz") baz = self.nodes[0].listtransactions(label="baz", count=1)[0] - expected_receive_vout = {"label": "baz", - "address": baz["address"], - "amount": baz["amount"], - "category": baz["category"], - "vout": baz["vout"]} - expected_fields = frozenset({'amount', - 'confirmations', - 'details', - 'fee', - 'hex', - 'time', - 'timereceived', - 'trusted', - 'txid', - 'walletconflicts'}) + expected_receive_vout = { + "label": "baz", + "address": baz["address"], + "amount": baz["amount"], + "category": baz["category"], + "vout": baz["vout"], + } + expected_fields = frozenset( + { + "amount", + "confirmations", + "details", + "fee", + "hex", + "time", + "timereceived", + "trusted", + "txid", + "walletconflicts", + } + ) verbose_field = "decoded" expected_verbose_fields = expected_fields | {verbose_field} @@ -655,29 +756,24 @@ tx = self.nodes[0].gettransaction(txid=txid) assert_equal(set(tx), expected_fields) assert_array_result( - tx["details"], { - "category": "receive"}, expected_receive_vout) + tx["details"], {"category": "receive"}, expected_receive_vout + ) - self.log.debug( - "Testing gettransaction response with verbose set to False") + self.log.debug("Testing gettransaction response with verbose set to False") tx = self.nodes[0].gettransaction(txid=txid, verbose=False) assert_equal(set(tx), expected_fields) assert_array_result( - tx["details"], { - "category": "receive"}, expected_receive_vout) + tx["details"], {"category": "receive"}, expected_receive_vout + ) - self.log.debug( - "Testing gettransaction response with verbose set to True") + self.log.debug("Testing gettransaction response with verbose set to True") tx = self.nodes[0].gettransaction(txid=txid, verbose=True) assert_equal(set(tx), expected_verbose_fields) assert_array_result( - tx["details"], { - "category": "receive"}, expected_receive_vout) - assert_equal( - tx[verbose_field], - self.nodes[0].decoderawtransaction( - tx["hex"])) + tx["details"], {"category": "receive"}, expected_receive_vout + ) + assert_equal(tx[verbose_field], self.nodes[0].decoderawtransaction(tx["hex"])) -if __name__ == '__main__': +if __name__ == "__main__": WalletTest().main() diff --git a/test/functional/wallet_coinbase_category.py b/test/functional/wallet_coinbase_category.py --- a/test/functional/wallet_coinbase_category.py +++ b/test/functional/wallet_coinbase_category.py @@ -19,15 +19,21 @@ self.skip_if_no_wallet() def assert_category(self, category, address, txid, skip): - assert_array_result(self.nodes[0].listtransactions(skip=skip), - {"address": address}, - {"category": category}) - assert_array_result(self.nodes[0].listsinceblock()["transactions"], - {"address": address}, - {"category": category}) - assert_array_result(self.nodes[0].gettransaction(txid)["details"], - {"address": address}, - {"category": category}) + assert_array_result( + self.nodes[0].listtransactions(skip=skip), + {"address": address}, + {"category": category}, + ) + assert_array_result( + self.nodes[0].listsinceblock()["transactions"], + {"address": address}, + {"category": category}, + ) + assert_array_result( + self.nodes[0].gettransaction(txid)["details"], + {"address": address}, + {"category": category}, + ) def run_test(self): # Generate one block to an address @@ -55,5 +61,5 @@ self.assert_category("orphan", address, txid, 100) -if __name__ == '__main__': +if __name__ == "__main__": CoinbaseCategoryTest().main() diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py --- a/test/functional/wallet_create_tx.py +++ b/test/functional/wallet_create_tx.py @@ -17,7 +17,7 @@ self.skip_if_no_wallet() def run_test(self): - self.log.info('Create some old blocks') + self.log.info("Create some old blocks") self.nodes[0].setmocktime(TIME_GENESIS_BLOCK) self.generate(self.nodes[0], 200) self.nodes[0].setmocktime(0) @@ -30,20 +30,20 @@ # to prevent fee-sniping. This feature is now disabled because it hurts # privacy and fee-sniping is now mitigated by avalanche post-consensus. self.log.info( - 'Check that we have some (old) blocks and that anti-fee-sniping is disabled') - assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200) - txid = self.nodes[0].sendtoaddress( - self.nodes[0].getnewaddress(), 1000000) - tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded'] - assert_equal(tx['locktime'], 0) + "Check that we have some (old) blocks and that anti-fee-sniping is disabled" + ) + assert_equal(self.nodes[0].getblockchaininfo()["blocks"], 200) + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1000000) + tx = self.nodes[0].gettransaction(txid=txid, verbose=True)["decoded"] + assert_equal(tx["locktime"], 0) self.log.info( - 'Check that anti-fee-sniping is still disabled when we mine a recent block') + "Check that anti-fee-sniping is still disabled when we mine a recent block" + ) self.generate(self.nodes[0], 1) - txid = self.nodes[0].sendtoaddress( - self.nodes[0].getnewaddress(), 1000000) - tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded'] - assert_equal(tx['locktime'], 0) + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1000000) + tx = self.nodes[0].gettransaction(txid=txid, verbose=True)["decoded"] + assert_equal(tx["locktime"], 0) def test_tx_size_too_large(self): # More than 10kB of outputs, so that we hit -maxtxfee with a high @@ -51,10 +51,12 @@ outputs = {self.nodes[0].getnewaddress(): 25 for _ in range(400)} raw_tx = self.nodes[0].createrawtransaction(inputs=[], outputs=outputs) - for fee_setting in ['-minrelaytxfee=10000', - '-mintxfee=10000', '-paytxfee=10000']: - self.log.info( - f'Check maxtxfee in combination with {fee_setting}') + for fee_setting in [ + "-minrelaytxfee=10000", + "-mintxfee=10000", + "-paytxfee=10000", + ]: + self.log.info(f"Check maxtxfee in combination with {fee_setting}") self.restart_node(0, extra_args=[fee_setting]) assert_raises_rpc_error( -6, @@ -67,7 +69,7 @@ lambda: self.nodes[0].fundrawtransaction(hexstring=raw_tx), ) - self.log.info('Check maxtxfee in combination with settxfee') + self.log.info("Check maxtxfee in combination with settxfee") self.restart_node(0) self.nodes[0].settxfee(10000) assert_raises_rpc_error( @@ -83,5 +85,5 @@ self.nodes[0].settxfee(0) -if __name__ == '__main__': +if __name__ == "__main__": CreateTxWalletTest().main() diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py --- a/test/functional/wallet_createwallet.py +++ b/test/functional/wallet_createwallet.py @@ -25,226 +25,285 @@ # Leave IBD for sethdseed self.generate(node, 1) - self.nodes[0].createwallet(wallet_name='w0') - w0 = node.get_wallet_rpc('w0') + self.nodes[0].createwallet(wallet_name="w0") + w0 = node.get_wallet_rpc("w0") address1 = w0.getnewaddress() self.log.info("Test disableprivatekeys creation.") - self.nodes[0].createwallet(wallet_name='w1', disable_private_keys=True) - w1 = node.get_wallet_rpc('w1') - assert_raises_rpc_error(-4, - "Error: This wallet has no available keys", w1.getnewaddress) - assert_raises_rpc_error(-4, "Error: This wallet has no available keys", - w1.getrawchangeaddress) - w1.importpubkey(w0.getaddressinfo(address1)['pubkey']) - - self.log.info('Test that private keys cannot be imported') + self.nodes[0].createwallet(wallet_name="w1", disable_private_keys=True) + w1 = node.get_wallet_rpc("w1") + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w1.getnewaddress + ) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w1.getrawchangeaddress + ) + w1.importpubkey(w0.getaddressinfo(address1)["pubkey"]) + + self.log.info("Test that private keys cannot be imported") eckey = ECKey() eckey.generate() privkey = bytes_to_wif(eckey.get_bytes()) assert_raises_rpc_error( - -4, 'Cannot import private keys to a wallet with private keys disabled', w1.importprivkey, privkey) + -4, + "Cannot import private keys to a wallet with private keys disabled", + w1.importprivkey, + privkey, + ) if self.options.descriptors: result = w1.importdescriptors( - [{'desc': descsum_create(f"pkh({privkey})"), - 'timestamp': 'now'}]) + [{"desc": descsum_create(f"pkh({privkey})"), "timestamp": "now"}] + ) else: result = w1.importmulti( - [{'scriptPubKey': { - 'address': key_to_p2pkh(eckey.get_pubkey().get_bytes())}, - 'timestamp': 'now', 'keys': [privkey]}]) - assert not result[0]['success'] - assert 'warning' not in result[0] - assert_equal(result[0]['error']['code'], -4) - assert_equal(result[0]['error']['message'], - 'Cannot import private keys to a wallet with private keys disabled') + [ + { + "scriptPubKey": { + "address": key_to_p2pkh(eckey.get_pubkey().get_bytes()) + }, + "timestamp": "now", + "keys": [privkey], + } + ] + ) + assert not result[0]["success"] + assert "warning" not in result[0] + assert_equal(result[0]["error"]["code"], -4) + assert_equal( + result[0]["error"]["message"], + "Cannot import private keys to a wallet with private keys disabled", + ) self.log.info("Test blank creation with private keys disabled.") self.nodes[0].createwallet( - wallet_name='w2', disable_private_keys=True, blank=True) - w2 = node.get_wallet_rpc('w2') - assert_raises_rpc_error(-4, - "Error: This wallet has no available keys", w2.getnewaddress) - assert_raises_rpc_error(-4, "Error: This wallet has no available keys", - w2.getrawchangeaddress) - w2.importpubkey(w0.getaddressinfo(address1)['pubkey']) + wallet_name="w2", disable_private_keys=True, blank=True + ) + w2 = node.get_wallet_rpc("w2") + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w2.getnewaddress + ) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w2.getrawchangeaddress + ) + w2.importpubkey(w0.getaddressinfo(address1)["pubkey"]) self.log.info("Test blank creation with private keys enabled.") self.nodes[0].createwallet( - wallet_name='w3', disable_private_keys=False, blank=True) - w3 = node.get_wallet_rpc('w3') - assert_equal(w3.getwalletinfo()['keypoolsize'], 0) - assert_raises_rpc_error(-4, - "Error: This wallet has no available keys", w3.getnewaddress) - assert_raises_rpc_error(-4, "Error: This wallet has no available keys", - w3.getrawchangeaddress) + wallet_name="w3", disable_private_keys=False, blank=True + ) + w3 = node.get_wallet_rpc("w3") + assert_equal(w3.getwalletinfo()["keypoolsize"], 0) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w3.getnewaddress + ) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w3.getrawchangeaddress + ) # Import private key w3.importprivkey(generate_wif_key()) # Imported private keys are currently ignored by the keypool - assert_equal(w3.getwalletinfo()['keypoolsize'], 0) - assert_raises_rpc_error(-4, - "Error: This wallet has no available keys", w3.getnewaddress) + assert_equal(w3.getwalletinfo()["keypoolsize"], 0) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w3.getnewaddress + ) # Set the seed if self.options.descriptors: - w3.importdescriptors([{ - 'desc': descsum_create( - 'pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)'), - 'timestamp': 'now', - 'active': True - }, - { - 'desc': descsum_create( - 'pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)'), - 'timestamp': 'now', - 'active': True, - 'internal': True - }]) + w3.importdescriptors( + [ + { + "desc": descsum_create( + "pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)" + ), + "timestamp": "now", + "active": True, + }, + { + "desc": descsum_create( + "pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)" + ), + "timestamp": "now", + "active": True, + "internal": True, + }, + ] + ) else: w3.sethdseed() - assert_equal(w3.getwalletinfo()['keypoolsize'], 1) + assert_equal(w3.getwalletinfo()["keypoolsize"], 1) w3.getnewaddress() w3.getrawchangeaddress() - self.log.info( - "Test blank creation with privkeys enabled and then encryption") + self.log.info("Test blank creation with privkeys enabled and then encryption") self.nodes[0].createwallet( - wallet_name='w4', disable_private_keys=False, blank=True) - w4 = node.get_wallet_rpc('w4') - assert_equal(w4.getwalletinfo()['keypoolsize'], 0) - assert_raises_rpc_error(-4, - "Error: This wallet has no available keys", w4.getnewaddress) - assert_raises_rpc_error(-4, "Error: This wallet has no available keys", - w4.getrawchangeaddress) + wallet_name="w4", disable_private_keys=False, blank=True + ) + w4 = node.get_wallet_rpc("w4") + assert_equal(w4.getwalletinfo()["keypoolsize"], 0) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w4.getnewaddress + ) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w4.getrawchangeaddress + ) # Encrypt the wallet. Nothing should change about the keypool - w4.encryptwallet('pass') - assert_raises_rpc_error(-4, - "Error: This wallet has no available keys", w4.getnewaddress) - assert_raises_rpc_error(-4, "Error: This wallet has no available keys", - w4.getrawchangeaddress) + w4.encryptwallet("pass") + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w4.getnewaddress + ) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w4.getrawchangeaddress + ) # Now set a seed and it should work. Wallet should also be encrypted - w4.walletpassphrase('pass', 2) + w4.walletpassphrase("pass", 2) if self.options.descriptors: - w4.importdescriptors([{ - 'desc': descsum_create( - 'pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)'), - 'timestamp': 'now', - 'active': True - }, - { - 'desc': descsum_create( - 'pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)'), - 'timestamp': 'now', - 'active': True, - 'internal': True - }]) + w4.importdescriptors( + [ + { + "desc": descsum_create( + "pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)" + ), + "timestamp": "now", + "active": True, + }, + { + "desc": descsum_create( + "pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)" + ), + "timestamp": "now", + "active": True, + "internal": True, + }, + ] + ) else: w4.sethdseed() w4.getnewaddress() w4.getrawchangeaddress() - self.log.info( - "Test blank creation with privkeys disabled and then encryption") + self.log.info("Test blank creation with privkeys disabled and then encryption") self.nodes[0].createwallet( - wallet_name='w5', disable_private_keys=True, blank=True) - - w5 = node.get_wallet_rpc('w5') - assert_equal(w5.getwalletinfo()['keypoolsize'], 0) - assert_raises_rpc_error(-4, - "Error: This wallet has no available keys", w5.getnewaddress) - assert_raises_rpc_error(-4, "Error: This wallet has no available keys", - w5.getrawchangeaddress) + wallet_name="w5", disable_private_keys=True, blank=True + ) + + w5 = node.get_wallet_rpc("w5") + assert_equal(w5.getwalletinfo()["keypoolsize"], 0) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w5.getnewaddress + ) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w5.getrawchangeaddress + ) # Encrypt the wallet - assert_raises_rpc_error(-16, - "Error: wallet does not contain private keys, nothing to encrypt.", - w5.encryptwallet, - 'pass') - assert_raises_rpc_error(-4, - "Error: This wallet has no available keys", w5.getnewaddress) - assert_raises_rpc_error(-4, "Error: This wallet has no available keys", - w5.getrawchangeaddress) - - self.log.info('New blank and encrypted wallets can be created') + assert_raises_rpc_error( + -16, + "Error: wallet does not contain private keys, nothing to encrypt.", + w5.encryptwallet, + "pass", + ) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w5.getnewaddress + ) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", w5.getrawchangeaddress + ) + + self.log.info("New blank and encrypted wallets can be created") self.nodes[0].createwallet( - wallet_name='wblank', + wallet_name="wblank", disable_private_keys=False, blank=True, - passphrase='thisisapassphrase') - wblank = node.get_wallet_rpc('wblank') + passphrase="thisisapassphrase", + ) + wblank = node.get_wallet_rpc("wblank") assert_raises_rpc_error( -13, "Error: Please enter the wallet passphrase with walletpassphrase first.", wblank.signmessage, "needanargument", - "test") - wblank.walletpassphrase('thisisapassphrase', 10) - assert_raises_rpc_error(-4, - "Error: This wallet has no available keys", - wblank.getnewaddress) - assert_raises_rpc_error(-4, - "Error: This wallet has no available keys", - wblank.getrawchangeaddress) - - self.log.info('Test creating a new encrypted wallet.') + "test", + ) + wblank.walletpassphrase("thisisapassphrase", 10) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", wblank.getnewaddress + ) + assert_raises_rpc_error( + -4, "Error: This wallet has no available keys", wblank.getrawchangeaddress + ) + + self.log.info("Test creating a new encrypted wallet.") # Born encrypted wallet is created (has keys) self.nodes[0].createwallet( - wallet_name='w6', + wallet_name="w6", disable_private_keys=False, blank=False, - passphrase='thisisapassphrase') - w6 = node.get_wallet_rpc('w6') + passphrase="thisisapassphrase", + ) + w6 = node.get_wallet_rpc("w6") assert_raises_rpc_error( -13, "Error: Please enter the wallet passphrase with walletpassphrase first.", w6.signmessage, "needanargument", - "test") - w6.walletpassphrase('thisisapassphrase', 10) - w6.signmessage(w6.getnewaddress('', 'legacy'), "test") + "test", + ) + w6.walletpassphrase("thisisapassphrase", 10) + w6.signmessage(w6.getnewaddress("", "legacy"), "test") w6.keypoolrefill(1) # There should only be 1 key for legacy and for descriptors walletinfo = w6.getwalletinfo() - assert_equal(walletinfo['keypoolsize'], 1) - assert_equal(walletinfo['keypoolsize_hd_internal'], 1) + assert_equal(walletinfo["keypoolsize"], 1) + assert_equal(walletinfo["keypoolsize_hd_internal"], 1) # Allow empty passphrase, but there should be a warning resp = self.nodes[0].createwallet( - wallet_name='w7', - disable_private_keys=False, - blank=False, - passphrase='') + wallet_name="w7", disable_private_keys=False, blank=False, passphrase="" + ) assert ( - 'Empty string given as passphrase, wallet will not be encrypted.' - in resp['warning']) - w7 = node.get_wallet_rpc('w7') + "Empty string given as passphrase, wallet will not be encrypted." + in resp["warning"] + ) + w7 = node.get_wallet_rpc("w7") assert_raises_rpc_error( -15, - 'Error: running with an unencrypted wallet, but walletpassphrase was called.', + ( + "Error: running with an unencrypted wallet, but walletpassphrase was" + " called." + ), w7.walletpassphrase, - '', - 10) + "", + 10, + ) - self.log.info('Test making a wallet with avoid reuse flag') + self.log.info("Test making a wallet with avoid reuse flag") # Use positional arguments to check for bug where avoid_reuse could not # be set for wallets without needing them to be encrypted - self.nodes[0].createwallet('w8', False, False, '', True) - w8 = node.get_wallet_rpc('w8') + self.nodes[0].createwallet("w8", False, False, "", True) + w8 = node.get_wallet_rpc("w8") assert_raises_rpc_error( -15, - 'Error: running with an unencrypted wallet, but walletpassphrase was called.', + ( + "Error: running with an unencrypted wallet, but walletpassphrase was" + " called." + ), w7.walletpassphrase, - '', - 10) + "", + 10, + ) assert_equal(w8.getwalletinfo()["avoid_reuse"], True) - self.log.info( - 'Using a passphrase with private keys disabled returns error') + self.log.info("Using a passphrase with private keys disabled returns error") assert_raises_rpc_error( -4, - 'Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.', + ( + "Passphrase provided but private keys are disabled. A passphrase is" + " only used to encrypt private keys, so cannot be used for wallets with" + " private keys disabled." + ), self.nodes[0].createwallet, - wallet_name='w9', + wallet_name="w9", disable_private_keys=True, - passphrase='thisisapassphrase') + passphrase="thisisapassphrase", + ) -if __name__ == '__main__': +if __name__ == "__main__": CreateWalletTest().main() diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py --- a/test/functional/wallet_descriptor.py +++ b/test/functional/wallet_descriptor.py @@ -12,7 +12,7 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - self.extra_args = [['-keypool=100']] + self.extra_args = [["-keypool=100"]] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -26,22 +26,22 @@ # A descriptor wallet should have 100 addresses = 100 keys self.log.info("Checking wallet info") wallet_info = self.nodes[0].getwalletinfo() - assert_equal(wallet_info['keypoolsize'], 100) - assert_equal(wallet_info['keypoolsize_hd_internal'], 100) - assert 'keypoololdest' not in wallet_info + assert_equal(wallet_info["keypoolsize"], 100) + assert_equal(wallet_info["keypoolsize_hd_internal"], 100) + assert "keypoololdest" not in wallet_info # Check that getnewaddress works self.log.info("Test that getnewaddress and getrawchangeaddress work") addr = self.nodes[0].getnewaddress("", "legacy") addr_info = self.nodes[0].getaddressinfo(addr) - assert addr_info['desc'].startswith('pkh(') - assert_equal(addr_info['hdkeypath'], 'm/44\'/1\'/0\'/0/0') + assert addr_info["desc"].startswith("pkh(") + assert_equal(addr_info["hdkeypath"], "m/44'/1'/0'/0/0") # Check that getrawchangeaddress works addr = self.nodes[0].getrawchangeaddress() addr_info = self.nodes[0].getaddressinfo(addr) - assert addr_info['desc'].startswith('pkh(') - assert_equal(addr_info['hdkeypath'], 'm/44\'/1\'/0\'/1/0') + assert addr_info["desc"].startswith("pkh(") + assert_equal(addr_info["hdkeypath"], "m/44'/1'/0'/1/0") # Make a wallet to receive coins at self.nodes[0].createwallet(wallet_name="desc2", descriptors=True) @@ -58,110 +58,136 @@ # Make sure things are disabled self.log.info("Test disabled RPCs") - assert_raises_rpc_error(-4, - "This type of wallet does not support this command", - recv_wrpc.rpc.importprivkey, - "cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW") - assert_raises_rpc_error(-4, - "This type of wallet does not support this command", - recv_wrpc.rpc.importpubkey, - send_wrpc.getaddressinfo(send_wrpc.getnewaddress())) - assert_raises_rpc_error(-4, - "This type of wallet does not support this command", - recv_wrpc.rpc.importaddress, - recv_wrpc.getnewaddress()) - assert_raises_rpc_error(-4, - "This type of wallet does not support this command", - recv_wrpc.rpc.importmulti, - []) - assert_raises_rpc_error(-4, - "This type of wallet does not support this command", - recv_wrpc.rpc.addmultisigaddress, - 1, - [recv_wrpc.getnewaddress()]) - assert_raises_rpc_error(-4, - "This type of wallet does not support this command", - recv_wrpc.rpc.dumpprivkey, - recv_wrpc.getnewaddress()) - assert_raises_rpc_error(-4, - "This type of wallet does not support this command", - recv_wrpc.rpc.dumpwallet, - 'wallet.dump') - assert_raises_rpc_error(-4, - "This type of wallet does not support this command", - recv_wrpc.rpc.importwallet, - 'wallet.dump') - assert_raises_rpc_error(-4, - "This type of wallet does not support this command", - recv_wrpc.rpc.sethdseed) + assert_raises_rpc_error( + -4, + "This type of wallet does not support this command", + recv_wrpc.rpc.importprivkey, + "cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW", + ) + assert_raises_rpc_error( + -4, + "This type of wallet does not support this command", + recv_wrpc.rpc.importpubkey, + send_wrpc.getaddressinfo(send_wrpc.getnewaddress()), + ) + assert_raises_rpc_error( + -4, + "This type of wallet does not support this command", + recv_wrpc.rpc.importaddress, + recv_wrpc.getnewaddress(), + ) + assert_raises_rpc_error( + -4, + "This type of wallet does not support this command", + recv_wrpc.rpc.importmulti, + [], + ) + assert_raises_rpc_error( + -4, + "This type of wallet does not support this command", + recv_wrpc.rpc.addmultisigaddress, + 1, + [recv_wrpc.getnewaddress()], + ) + assert_raises_rpc_error( + -4, + "This type of wallet does not support this command", + recv_wrpc.rpc.dumpprivkey, + recv_wrpc.getnewaddress(), + ) + assert_raises_rpc_error( + -4, + "This type of wallet does not support this command", + recv_wrpc.rpc.dumpwallet, + "wallet.dump", + ) + assert_raises_rpc_error( + -4, + "This type of wallet does not support this command", + recv_wrpc.rpc.importwallet, + "wallet.dump", + ) + assert_raises_rpc_error( + -4, + "This type of wallet does not support this command", + recv_wrpc.rpc.sethdseed, + ) self.log.info("Test encryption") # Get the master fingerprint before encrypt info1 = send_wrpc.getaddressinfo(send_wrpc.getnewaddress()) # Encrypt wallet 0 - send_wrpc.encryptwallet('pass') - send_wrpc.walletpassphrase('pass', 10) + send_wrpc.encryptwallet("pass") + send_wrpc.walletpassphrase("pass", 10) addr = send_wrpc.getnewaddress() info2 = send_wrpc.getaddressinfo(addr) - assert info1['hdmasterfingerprint'] != info2['hdmasterfingerprint'] + assert info1["hdmasterfingerprint"] != info2["hdmasterfingerprint"] send_wrpc.walletlock() - assert 'hdmasterfingerprint' in send_wrpc.getaddressinfo( - send_wrpc.getnewaddress()) + assert "hdmasterfingerprint" in send_wrpc.getaddressinfo( + send_wrpc.getnewaddress() + ) info3 = send_wrpc.getaddressinfo(addr) - assert_equal(info2['desc'], info3['desc']) + assert_equal(info2["desc"], info3["desc"]) self.log.info( - "Test that getnewaddress still works after keypool is exhausted in an encrypted wallet") + "Test that getnewaddress still works after keypool is exhausted in an" + " encrypted wallet" + ) for _ in range(500): send_wrpc.getnewaddress() self.log.info( - "Test that unlock is needed when deriving only hardened keys in an encrypted wallet") - send_wrpc.walletpassphrase('pass', 10) - send_wrpc.importdescriptors([{ - "desc": "sh(pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/*h))#45ls09gz", - "timestamp": "now", - "range": [0, 10], - "active": True - }]) + "Test that unlock is needed when deriving only hardened keys in an" + " encrypted wallet" + ) + send_wrpc.walletpassphrase("pass", 10) + send_wrpc.importdescriptors( + [ + { + "desc": "sh(pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/*h))#45ls09gz", + "timestamp": "now", + "range": [0, 10], + "active": True, + } + ] + ) send_wrpc.walletlock() # Exhaust keypool of 100 for _ in range(100): send_wrpc.getnewaddress() # This should now error - assert_raises_rpc_error(-12, - "Keypool ran out, please call keypoolrefill first", - send_wrpc.getnewaddress, - '') + assert_raises_rpc_error( + -12, + "Keypool ran out, please call keypoolrefill first", + send_wrpc.getnewaddress, + "", + ) self.log.info("Test born encrypted wallets") - self.nodes[0].createwallet( - 'desc_enc', False, False, 'pass', False, True) - enc_rpc = self.nodes[0].get_wallet_rpc('desc_enc') + self.nodes[0].createwallet("desc_enc", False, False, "pass", False, True) + enc_rpc = self.nodes[0].get_wallet_rpc("desc_enc") # Makes sure that we can get a new address from a born encrypted wallet enc_rpc.getnewaddress() self.log.info("Test blank descriptor wallets") self.nodes[0].createwallet( - wallet_name='desc_blank', - blank=True, - descriptors=True) - blank_rpc = self.nodes[0].get_wallet_rpc('desc_blank') - assert_raises_rpc_error(-4, - 'This wallet has no available keys', - blank_rpc.getnewaddress) + wallet_name="desc_blank", blank=True, descriptors=True + ) + blank_rpc = self.nodes[0].get_wallet_rpc("desc_blank") + assert_raises_rpc_error( + -4, "This wallet has no available keys", blank_rpc.getnewaddress + ) self.log.info("Test descriptor wallet with disabled private keys") self.nodes[0].createwallet( - wallet_name='desc_no_priv', - disable_private_keys=True, - descriptors=True) - nopriv_rpc = self.nodes[0].get_wallet_rpc('desc_no_priv') - assert_raises_rpc_error(-4, - 'This wallet has no available keys', - nopriv_rpc.getnewaddress) + wallet_name="desc_no_priv", disable_private_keys=True, descriptors=True + ) + nopriv_rpc = self.nodes[0].get_wallet_rpc("desc_no_priv") + assert_raises_rpc_error( + -4, "This wallet has no available keys", nopriv_rpc.getnewaddress + ) -if __name__ == '__main__': +if __name__ == "__main__": WalletDescriptorTest().main() diff --git a/test/functional/wallet_disable.py b/test/functional/wallet_disable.py --- a/test/functional/wallet_disable.py +++ b/test/functional/wallet_disable.py @@ -12,7 +12,7 @@ from test_framework.util import assert_raises_rpc_error -class DisableWalletTest (BitcoinTestFramework): +class DisableWalletTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 @@ -21,20 +21,24 @@ def run_test(self): # Make sure wallet is really disabled - assert_raises_rpc_error(-32601, 'Method not found', - self.nodes[0].getwalletinfo) - x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') - assert x['isvalid'] is False - x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') - assert x['isvalid'] is True + assert_raises_rpc_error(-32601, "Method not found", self.nodes[0].getwalletinfo) + x = self.nodes[0].validateaddress("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") + assert x["isvalid"] is False + x = self.nodes[0].validateaddress("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") + assert x["isvalid"] is True # Checking mining to an address without a wallet. Generating to a valid address should succeed # but generating to an invalid address will fail. - self.generatetoaddress(self.nodes[0], - 1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') - assert_raises_rpc_error(-5, "Invalid address", - self.generatetoaddress, self.nodes[0], 1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') - - -if __name__ == '__main__': + self.generatetoaddress(self.nodes[0], 1, "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") + assert_raises_rpc_error( + -5, + "Invalid address", + self.generatetoaddress, + self.nodes[0], + 1, + "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy", + ) + + +if __name__ == "__main__": DisableWalletTest().main() diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -17,7 +17,7 @@ Read the given dump, count the addrs that match, count change and reserve. Also check that the old hd_master is inactive """ - with open(file_name, encoding='utf8') as inputfile: + with open(file_name, encoding="utf8") as inputfile: found_addr = 0 found_comments = [] found_script_addr = 0 @@ -28,7 +28,7 @@ line = line.strip() if not line: continue - if line[0] == '#': + if line[0] == "#": found_comments.append(line) else: # split out some data @@ -38,7 +38,7 @@ date = key_date_label[1] keytype = key_date_label[2] - imported_key = date == '1970-01-01T00:00:01Z' + imported_key = date == "1970-01-01T00:00:01Z" if imported_key: # Imported keys have multiple addresses, no label (keypath) and timestamp # Skip them @@ -62,7 +62,11 @@ # count key types for addrObj in addrs: - if addrObj['address'] == addr and addrObj['hdkeypath'] == keypath and keytype == "label=": + if ( + addrObj["address"] == addr + and addrObj["hdkeypath"] == keypath + and keytype == "label=" + ): found_addr += 1 break elif keytype == "change=1": @@ -78,7 +82,14 @@ found_script_addr += 1 break - return found_comments, found_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret + return ( + found_comments, + found_addr, + found_script_addr, + found_addr_chg, + found_addr_rsv, + hd_master_addr_ret, + ) class WalletDumpTest(BitcoinTestFramework): @@ -96,64 +107,78 @@ def run_test(self): wallet_unenc_dump = os.path.join( - self.nodes[0].datadir, "wallet.unencrypted.dump") - wallet_enc_dump = os.path.join( - self.nodes[0].datadir, "wallet.encrypted.dump") + self.nodes[0].datadir, "wallet.unencrypted.dump" + ) + wallet_enc_dump = os.path.join(self.nodes[0].datadir, "wallet.encrypted.dump") # generate 20 addresses to compare against the dump test_addr_count = 20 addrs = [] for _ in range(test_addr_count): addr = self.nodes[0].getnewaddress() - vaddr = self.nodes[0].getaddressinfo( - addr) # required to get hd keypath + vaddr = self.nodes[0].getaddressinfo(addr) # required to get hd keypath addrs.append(vaddr) # Should be a no-op: self.nodes[0].keypoolrefill() # Test scripts dump by adding a 1-of-1 multisig address - multisig_addr = self.nodes[0].addmultisigaddress( - 1, [addrs[0]["address"]])["address"] + multisig_addr = self.nodes[0].addmultisigaddress(1, [addrs[0]["address"]])[ + "address" + ] - self.log.info('Mine a block one second before the wallet is dumped') + self.log.info("Mine a block one second before the wallet is dumped") dump_time = int(time.time()) self.nodes[0].setmocktime(dump_time - 1) self.generate(self.nodes[0], 1) self.nodes[0].setmocktime(dump_time) - dump_time_str = '# * Created on {}Z'.format( + dump_time_str = "# * Created on {}Z".format( datetime.datetime.fromtimestamp( dump_time, tz=datetime.timezone.utc, - ).replace(tzinfo=None).isoformat()) + ) + .replace(tzinfo=None) + .isoformat() + ) dump_best_block_1 = ( - f'# * Best block at time of backup was {self.nodes[0].getblockcount()} ' - f'({self.nodes[0].getbestblockhash()}),' + f"# * Best block at time of backup was {self.nodes[0].getblockcount()} " + f"({self.nodes[0].getbestblockhash()})," ) - dump_best_block_2 = '# mined on {}Z'.format( + dump_best_block_2 = "# mined on {}Z".format( datetime.datetime.fromtimestamp( dump_time - 1, tz=datetime.timezone.utc, - ).replace(tzinfo=None).isoformat()) + ) + .replace(tzinfo=None) + .isoformat() + ) - self.log.info('Dump unencrypted wallet') + self.log.info("Dump unencrypted wallet") result = self.nodes[0].dumpwallet(wallet_unenc_dump) - assert_equal(result['filename'], wallet_unenc_dump) + assert_equal(result["filename"], wallet_unenc_dump) - found_comments, found_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc = \ - read_dump(wallet_unenc_dump, addrs, [multisig_addr], None) + ( + found_comments, + found_addr, + found_script_addr, + found_addr_chg, + found_addr_rsv, + hd_master_addr_unenc, + ) = read_dump(wallet_unenc_dump, addrs, [multisig_addr], None) # Check that file is not corrupt - assert '# End of dump' in found_comments - assert found_comments[0].startswith( - "# Wallet dump created by Bitcoin ABC") + assert "# End of dump" in found_comments + assert found_comments[0].startswith("# Wallet dump created by Bitcoin ABC") assert_equal( - dump_time_str, next( - c for c in found_comments if c.startswith('# * Created on'))) + dump_time_str, + next(c for c in found_comments if c.startswith("# * Created on")), + ) assert_equal( - dump_best_block_1, next( - c for c in found_comments if c.startswith('# * Best block'))) + dump_best_block_1, + next(c for c in found_comments if c.startswith("# * Best block")), + ) assert_equal( - dump_best_block_2, next( - c for c in found_comments if c.startswith('# mined on'))) + dump_best_block_2, + next(c for c in found_comments if c.startswith("# mined on")), + ) # all keys must be in the dump assert_equal(found_addr, test_addr_count) # all scripts must be in the dump @@ -164,55 +189,60 @@ assert_equal(found_addr_rsv, 90 * 2) # encrypt wallet, restart, unlock and dump - self.nodes[0].encryptwallet('test') - self.nodes[0].walletpassphrase('test', 10) + self.nodes[0].encryptwallet("test") + self.nodes[0].walletpassphrase("test", 10) # Should be a no-op: self.nodes[0].keypoolrefill() self.nodes[0].dumpwallet(wallet_enc_dump) - found_comments, found_addr, found_script_addr, found_addr_chg, found_addr_rsv, _ = \ - read_dump( - wallet_enc_dump, - addrs, - [multisig_addr], - hd_master_addr_unenc) + ( + found_comments, + found_addr, + found_script_addr, + found_addr_chg, + found_addr_rsv, + _, + ) = read_dump(wallet_enc_dump, addrs, [multisig_addr], hd_master_addr_unenc) # Check that file is not corrupt - assert '# End of dump' in found_comments + assert "# End of dump" in found_comments assert_equal(found_addr, test_addr_count) assert_equal( - dump_time_str, next( - c for c in found_comments if c.startswith('# * Created on'))) + dump_time_str, + next(c for c in found_comments if c.startswith("# * Created on")), + ) assert_equal( - dump_best_block_1, next( - c for c in found_comments if c.startswith('# * Best block'))) + dump_best_block_1, + next(c for c in found_comments if c.startswith("# * Best block")), + ) assert_equal( - dump_best_block_2, next( - c for c in found_comments if c.startswith('# mined on'))) + dump_best_block_2, + next(c for c in found_comments if c.startswith("# mined on")), + ) assert_equal(found_script_addr, 1) # old reserve keys are marked as change now assert_equal(found_addr_chg, 90 * 2) assert_equal(found_addr_rsv, 90 * 2) # Overwriting should fail - assert_raises_rpc_error(-8, - "already exists", - lambda: self.nodes[0].dumpwallet(wallet_enc_dump)) + assert_raises_rpc_error( + -8, "already exists", lambda: self.nodes[0].dumpwallet(wallet_enc_dump) + ) # Restart node with new wallet, and test importwallet - self.restart_node(0, ['-wallet=w2']) + self.restart_node(0, ["-wallet=w2"]) # Make sure the address is not IsMine before import result = self.nodes[0].getaddressinfo(multisig_addr) - assert result['ismine'] is False + assert result["ismine"] is False self.nodes[0].importwallet(wallet_unenc_dump) # Now check IsMine is true result = self.nodes[0].getaddressinfo(multisig_addr) - assert result['ismine'] is True + assert result["ismine"] is True - self.log.info('Check that wallet is flushed') - with self.nodes[0].assert_debug_log(['Flushing wallet.dat'], timeout=20): + self.log.info("Check that wallet is flushed") + with self.nodes[0].assert_debug_log(["Flushing wallet.dat"], timeout=20): self.nodes[0].getnewaddress() # Make sure that dumpwallet doesn't have a lock order issue when there is an unconfirmed tx and it is reloaded @@ -221,12 +251,13 @@ w3 = self.nodes[0].get_wallet_rpc("w3") w3.importprivkey( privkey=self.nodes[0].get_deterministic_priv_key().key, - label="coinbase_import") + label="coinbase_import", + ) w3.sendtoaddress(w3.getnewaddress(), 10) w3.unloadwallet() self.nodes[0].loadwallet("w3") w3.dumpwallet(os.path.join(self.nodes[0].datadir, "w3.dump")) -if __name__ == '__main__': +if __name__ == "__main__": WalletDumpTest().main() diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -16,7 +16,6 @@ class WalletEncryptionTest(BitcoinTestFramework): - def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 @@ -34,35 +33,59 @@ sig = self.nodes[0].signmessage(address, msg) assert self.nodes[0].verifymessage(address, sig, msg) assert_raises_rpc_error( - -15, "Error: running with an unencrypted wallet, but walletpassphrase was called", - self.nodes[0].walletpassphrase, 'ff', 1) + -15, + ( + "Error: running with an unencrypted wallet, but walletpassphrase was" + " called" + ), + self.nodes[0].walletpassphrase, + "ff", + 1, + ) assert_raises_rpc_error( -15, - "Error: running with an unencrypted wallet, but walletpassphrasechange was called.", - self.nodes[0].walletpassphrasechange, 'ff', 'ff') + ( + "Error: running with an unencrypted wallet, but walletpassphrasechange" + " was called." + ), + self.nodes[0].walletpassphrasechange, + "ff", + "ff", + ) # Encrypt the wallet assert_raises_rpc_error( - -8, "passphrase can not be empty", - self.nodes[0].encryptwallet, '') + -8, "passphrase can not be empty", self.nodes[0].encryptwallet, "" + ) self.nodes[0].encryptwallet(passphrase) # Check the encrypted wallet is marked as locked on initialization - assert_equal(self.nodes[0].getwalletinfo()['unlocked_until'], 0) + assert_equal(self.nodes[0].getwalletinfo()["unlocked_until"], 0) # Test that the wallet is encrypted assert_raises_rpc_error( - -13, "Please enter the wallet passphrase with walletpassphrase first", - self.nodes[0].signmessage, address, msg) + -13, + "Please enter the wallet passphrase with walletpassphrase first", + self.nodes[0].signmessage, + address, + msg, + ) assert_raises_rpc_error( - -15, "Error: running with an encrypted wallet, but encryptwallet was called.", - self.nodes[0].encryptwallet, 'ff') + -15, + "Error: running with an encrypted wallet, but encryptwallet was called.", + self.nodes[0].encryptwallet, + "ff", + ) assert_raises_rpc_error( - -8, "passphrase can not be empty", - self.nodes[0].walletpassphrase, '', 1) + -8, "passphrase can not be empty", self.nodes[0].walletpassphrase, "", 1 + ) assert_raises_rpc_error( - -8, "passphrase can not be empty", - self.nodes[0].walletpassphrasechange, '', 'ff') + -8, + "passphrase can not be empty", + self.nodes[0].walletpassphrasechange, + "", + "ff", + ) # Check that walletpassphrase works self.nodes[0].walletpassphrase(passphrase, 2) @@ -72,12 +95,21 @@ # Check that the timeout is right time.sleep(3) assert_raises_rpc_error( - -13, "Please enter the wallet passphrase with walletpassphrase first", - self.nodes[0].signmessage, address, msg) + -13, + "Please enter the wallet passphrase with walletpassphrase first", + self.nodes[0].signmessage, + address, + msg, + ) # Test wrong passphrase - assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", - self.nodes[0].walletpassphrase, f"{passphrase}wrong", 10) + assert_raises_rpc_error( + -14, + "wallet passphrase entered was incorrect", + self.nodes[0].walletpassphrase, + f"{passphrase}wrong", + 10, + ) # Test walletlock and unlocked_until values self.mocktime = 1 @@ -85,43 +117,56 @@ self.nodes[0].walletpassphrase(passphrase, 84600) sig = self.nodes[0].signmessage(address, msg) assert self.nodes[0].verifymessage(address, sig, msg) - assert_equal( - self.nodes[0].getwalletinfo()['unlocked_until'], 1 + 84600) + assert_equal(self.nodes[0].getwalletinfo()["unlocked_until"], 1 + 84600) self.nodes[0].walletlock() assert_raises_rpc_error( - -13, "Please enter the wallet passphrase with walletpassphrase first", - self.nodes[0].signmessage, address, msg) - assert_equal(self.nodes[0].getwalletinfo()['unlocked_until'], 0) + -13, + "Please enter the wallet passphrase with walletpassphrase first", + self.nodes[0].signmessage, + address, + msg, + ) + assert_equal(self.nodes[0].getwalletinfo()["unlocked_until"], 0) # Test passphrase changes self.nodes[0].walletpassphrasechange(passphrase, passphrase2) - assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", - self.nodes[0].walletpassphrase, passphrase, 10) + assert_raises_rpc_error( + -14, + "wallet passphrase entered was incorrect", + self.nodes[0].walletpassphrase, + passphrase, + 10, + ) self.nodes[0].walletpassphrase(passphrase2, 10) sig = self.nodes[0].signmessage(address, msg) assert self.nodes[0].verifymessage(address, sig, msg) self.nodes[0].walletlock() # Test timeout bounds - assert_raises_rpc_error(-8, "Timeout cannot be negative.", - self.nodes[0].walletpassphrase, passphrase2, -10) + assert_raises_rpc_error( + -8, + "Timeout cannot be negative.", + self.nodes[0].walletpassphrase, + passphrase2, + -10, + ) # Check the timeout # Check a time less than the limit MAX_VALUE = 100000000 expected_time = self.mocktime + MAX_VALUE - 600 self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE - 600) - actual_time = self.nodes[0].getwalletinfo()['unlocked_until'] + actual_time = self.nodes[0].getwalletinfo()["unlocked_until"] assert_greater_than_or_equal(actual_time, expected_time) # 5 second buffer assert_greater_than(expected_time + 5, actual_time) # Check a time greater than the limit expected_time = self.mocktime + MAX_VALUE - 1 self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE + 1000) - actual_time = self.nodes[0].getwalletinfo()['unlocked_until'] + actual_time = self.nodes[0].getwalletinfo()["unlocked_until"] assert_greater_than_or_equal(actual_time, expected_time) # 5 second buffer assert_greater_than(expected_time + 5, actual_time) -if __name__ == '__main__': +if __name__ == "__main__": WalletEncryptionTest().main() diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py --- a/test/functional/wallet_groups.py +++ b/test/functional/wallet_groups.py @@ -16,13 +16,14 @@ self.extra_args = [ [], [], - ['-avoidpartialspends'], + ["-avoidpartialspends"], # 2.93 XEC is the threshold that causes a node to prefer a # non-grouped tx (3 inputs, 2 outputs) to a grouped tx (5 inputs, # 2 outputs). The fee for the grouped tx is 294 sats higher than # the fee for the non-grouped tx. See tx5 below. ["-maxapsfee=2.93"], - ["-maxapsfee=2.94"]] + ["-maxapsfee=2.94"], + ] # whitelist peers to speed up tx relay / mempool sync for args in self.extra_args: args.append("-whitelist=noban@127.0.0.1") @@ -52,8 +53,7 @@ # - node[1] should pick one 0.5 UTXO and leave the rest # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a # given address, and leave the rest - txid1 = self.nodes[1].sendtoaddress( - self.nodes[0].getnewaddress(), 200000) + txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 200000) tx1 = self.nodes[1].getrawtransaction(txid1, True) # txid1 should have 1 input and 2 outputs assert_equal(1, len(tx1["vin"])) @@ -63,8 +63,7 @@ assert_approx(v[0], vexp=200_000, vspan=100) assert_approx(v[1], vexp=300_000, vspan=100) - txid2 = self.nodes[2].sendtoaddress( - self.nodes[0].getnewaddress(), 200000) + txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 200000) tx2 = self.nodes[2].getrawtransaction(txid2, True) # txid2 should have 2 inputs and 2 outputs assert_equal(2, len(tx2["vin"])) @@ -91,8 +90,7 @@ # this could be (A / B0 / C0) + (B1 / C1 / D). We ensure that it is # B0 + B1 or C0 + C1, because this avoids partial spends while not being # detrimental to transaction cost - txid3 = self.nodes[1].sendtoaddress( - self.nodes[0].getnewaddress(), 1400000) + txid3 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1400000) tx3 = self.nodes[1].getrawtransaction(txid3, True) # tx3 should have 2 inputs and 2 outputs assert_equal(2, len(tx3["vin"])) @@ -104,8 +102,10 @@ assert_approx(values[1], vexp=1_400_000, vspan=100) input_txids = [vin["txid"] for vin in tx3["vin"]] - input_addrs = [self.nodes[1].gettransaction( - txid)['details'][0]['address'] for txid in input_txids] + input_addrs = [ + self.nodes[1].gettransaction(txid)["details"][0]["address"] + for txid in input_txids + ] assert_equal(input_addrs[0], input_addrs[1]) # Node 2 enforces avoidpartialspends so needs no checking here @@ -114,10 +114,10 @@ self.nodes[0].sendtoaddress(addr_aps, 1000000) self.nodes[0].sendtoaddress(addr_aps, 1000000) self.generate(self.nodes[0], 1) - with self.nodes[3].assert_debug_log([ - 'Fee non-grouped = 225, grouped = 372, using grouped']): - txid4 = self.nodes[3].sendtoaddress( - self.nodes[0].getnewaddress(), 100_000) + with self.nodes[3].assert_debug_log( + ["Fee non-grouped = 225, grouped = 372, using grouped"] + ): + txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 100_000) tx4 = self.nodes[3].getrawtransaction(txid4, True) # tx4 should have 2 inputs and 2 outputs although one output would # have been enough and the transaction caused higher fees @@ -127,10 +127,12 @@ addr_aps2 = self.nodes[3].getnewaddress() [self.nodes[0].sendtoaddress(addr_aps2, 1_000_000) for _ in range(5)] self.generate(self.nodes[0], 1) - with self.nodes[3].assert_debug_log([ - 'Fee non-grouped = 519, grouped = 813, using non-grouped']): - txid5 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), - 2_950_000) + with self.nodes[3].assert_debug_log( + ["Fee non-grouped = 519, grouped = 813, using non-grouped"] + ): + txid5 = self.nodes[3].sendtoaddress( + self.nodes[0].getnewaddress(), 2_950_000 + ) tx5 = self.nodes[3].getrawtransaction(txid5, True) # tx5 should have 3 inputs (1.0, 1.0, 1.0) and 2 outputs assert_equal(3, len(tx5["vin"])) @@ -141,18 +143,23 @@ addr_aps3 = self.nodes[4].getnewaddress() [self.nodes[0].sendtoaddress(addr_aps3, 1_000_000) for _ in range(5)] self.generate(self.nodes[0], 1) - with self.nodes[4].assert_debug_log([ - 'Fee non-grouped = 519, grouped = 813, using grouped']): - txid6 = self.nodes[4].sendtoaddress(self.nodes[0].getnewaddress(), - 2_950_000) + with self.nodes[4].assert_debug_log( + ["Fee non-grouped = 519, grouped = 813, using grouped"] + ): + txid6 = self.nodes[4].sendtoaddress( + self.nodes[0].getnewaddress(), 2_950_000 + ) tx6 = self.nodes[4].getrawtransaction(txid6, True) # tx6 should have 5 inputs and 2 outputs assert_equal(5, len(tx6["vin"])) assert_equal(2, len(tx6["vout"])) # Empty out node2's wallet - self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress( - ), amount=self.nodes[2].getbalance(), subtractfeefromamount=True) + self.nodes[2].sendtoaddress( + address=self.nodes[0].getnewaddress(), + amount=self.nodes[2].getbalance(), + subtractfeefromamount=True, + ) self.sync_all() self.generate(self.nodes[0], 1) @@ -160,14 +167,14 @@ # scriptPubKey for _ in range(5): raw_tx = self.nodes[0].createrawtransaction( - [{"txid": "0" * 64, "vout": 0}], [{addr2[0]: 50_000}]) + [{"txid": "0" * 64, "vout": 0}], [{addr2[0]: 50_000}] + ) tx = FromHex(CTransaction(), raw_tx) tx.vin = [] tx.vout = [tx.vout[0]] * 2000 funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx)) - signed_tx = self.nodes[0].signrawtransactionwithwallet( - funded_tx['hex']) - self.nodes[0].sendrawtransaction(signed_tx['hex']) + signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx["hex"]) + self.nodes[0].sendrawtransaction(signed_tx["hex"]) self.generate(self.nodes[0], 1) # Check that we can create a transaction that only requires ~100 of our @@ -176,5 +183,5 @@ assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5000000) -if __name__ == '__main__': +if __name__ == "__main__": WalletGroupTest().main() diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -15,7 +15,7 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - self.extra_args = [[], ['-keypool=0']] + self.extra_args = [[], ["-keypool=0"]] # whitelist peers to speed up tx relay / mempool sync for args in self.extra_args: args.append("-whitelist=noban@127.0.0.1") @@ -27,8 +27,9 @@ def run_test(self): # Make sure we use hd, keep masterkeyid - hd_fingerprint = self.nodes[1].getaddressinfo( - self.nodes[1].getnewaddress())['hdmasterfingerprint'] + hd_fingerprint = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())[ + "hdmasterfingerprint" + ] assert_equal(len(hd_fingerprint), 8) # create an internal key @@ -41,13 +42,12 @@ assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") # Import a non-HD private key in the HD wallet - non_hd_add = 'ecregtest:qr09jgufyeae4s97nqp6mv0tv6eymfunygeyv0llfe' - non_hd_key = 'cS9umN9w6cDMuRVYdbkfE4c7YUFLJRoXMfhQ569uY4odiQbVN8Rt' + non_hd_add = "ecregtest:qr09jgufyeae4s97nqp6mv0tv6eymfunygeyv0llfe" + non_hd_key = "cS9umN9w6cDMuRVYdbkfE4c7YUFLJRoXMfhQ569uY4odiQbVN8Rt" self.nodes[1].importprivkey(non_hd_key) # This should be enough to keep the master key and the non-HD key - self.nodes[1].backupwallet( - os.path.join(self.nodes[1].datadir, "hd.bak")) + self.nodes[1].backupwallet(os.path.join(self.nodes[1].datadir, "hd.bak")) # self.nodes[1].dumpwallet(os.path.join(self.nodes[1].datadir, "hd.dump")) # Derive some HD addresses and remember the last @@ -78,26 +78,25 @@ assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") self.sync_all() - assert_equal( - self.nodes[1].getbalance(), - (NUM_HD_ADDS * 1000000) + 1000000) + assert_equal(self.nodes[1].getbalance(), (NUM_HD_ADDS * 1000000) + 1000000) self.log.info("Restore backup ...") self.stop_node(1) # we need to delete the complete regtest directory # otherwise node1 would auto-recover all funds in flag the keypool keys # as used - shutil.rmtree( + shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "blocks")) + shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "chainstate")) + shutil.copyfile( + os.path.join(self.nodes[1].datadir, "hd.bak"), os.path.join( self.nodes[1].datadir, self.chain, - "blocks")) - shutil.rmtree(os.path.join( - self.nodes[1].datadir, self.chain, "chainstate")) - shutil.copyfile( - os.path.join(self.nodes[1].datadir, "hd.bak"), - os.path.join(self.nodes[1].datadir, self.chain, 'wallets', - self.default_wallet_name, self.wallet_data_filename)) + "wallets", + self.default_wallet_name, + self.wallet_data_filename, + ), + ) self.start_node(1) # Assert that derivation is deterministic @@ -115,58 +114,52 @@ self.sync_all() # Needs rescan - self.restart_node(1, extra_args=self.extra_args[1] + ['-rescan']) - assert_equal( - self.nodes[1].getbalance(), - (NUM_HD_ADDS * 1000000) + 1000000) + self.restart_node(1, extra_args=self.extra_args[1] + ["-rescan"]) + assert_equal(self.nodes[1].getbalance(), (NUM_HD_ADDS * 1000000) + 1000000) # Try a RPC based rescan self.stop_node(1) - shutil.rmtree( + shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "blocks")) + shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "chainstate")) + shutil.copyfile( + os.path.join(self.nodes[1].datadir, "hd.bak"), os.path.join( self.nodes[1].datadir, self.chain, - "blocks")) - shutil.rmtree(os.path.join( - self.nodes[1].datadir, self.chain, "chainstate")) - shutil.copyfile( - os.path.join(self.nodes[1].datadir, "hd.bak"), - os.path.join(self.nodes[1].datadir, self.chain, "wallets", - self.default_wallet_name, self.wallet_data_filename)) + "wallets", + self.default_wallet_name, + self.wallet_data_filename, + ), + ) self.start_node(1, extra_args=self.extra_args[1]) self.connect_nodes(0, 1) self.sync_all() # Wallet automatically scans blocks older than key on startup - assert_equal( - self.nodes[1].getbalance(), - (NUM_HD_ADDS * 1000000) + 1000000) + assert_equal(self.nodes[1].getbalance(), (NUM_HD_ADDS * 1000000) + 1000000) out = self.nodes[1].rescanblockchain(0, 1) - assert_equal(out['start_height'], 0) - assert_equal(out['stop_height'], 1) + assert_equal(out["start_height"], 0) + assert_equal(out["stop_height"], 1) out = self.nodes[1].rescanblockchain(2, 4) - assert_equal(out['start_height'], 2) - assert_equal(out['stop_height'], 4) + assert_equal(out["start_height"], 2) + assert_equal(out["stop_height"], 4) out = self.nodes[1].rescanblockchain(3) - assert_equal(out['start_height'], 3) - assert_equal(out['stop_height'], self.nodes[1].getblockcount()) + assert_equal(out["start_height"], 3) + assert_equal(out["stop_height"], self.nodes[1].getblockcount()) out = self.nodes[1].rescanblockchain() - assert_equal(out['start_height'], 0) - assert_equal(out['stop_height'], self.nodes[1].getblockcount()) - assert_equal( - self.nodes[1].getbalance(), - (NUM_HD_ADDS * 1000000) + 1000000) + assert_equal(out["start_height"], 0) + assert_equal(out["stop_height"], self.nodes[1].getblockcount()) + assert_equal(self.nodes[1].getbalance(), (NUM_HD_ADDS * 1000000) + 1000000) # send a tx and make sure its using the internal chain for the # changeoutput - txid = self.nodes[1].sendtoaddress( - self.nodes[0].getnewaddress(), 1000000) - outs = self.nodes[1].gettransaction( - txid=txid, verbose=True)['decoded']['vout'] + txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1000000) + outs = self.nodes[1].gettransaction(txid=txid, verbose=True)["decoded"]["vout"] keypath = "" for out in outs: - if out['value'] != 1000000: + if out["value"] != 1000000: keypath = self.nodes[1].getaddressinfo( - out['scriptPubKey']['addresses'][0])['hdkeypath'] + out["scriptPubKey"]["addresses"][0] + )["hdkeypath"] if self.options.descriptors: assert_equal(keypath[0:14], "m/44'/1'/0'/1/") @@ -175,14 +168,13 @@ if not self.options.descriptors: # Generate a new HD seed on node 1 and make sure it is set - orig_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] + orig_masterkeyid = self.nodes[1].getwalletinfo()["hdseedid"] self.nodes[1].sethdseed() - new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] + new_masterkeyid = self.nodes[1].getwalletinfo()["hdseedid"] assert orig_masterkeyid != new_masterkeyid addr = self.nodes[1].getnewaddress() # Make sure the new address is the first from the keypool - assert_equal(self.nodes[1].getaddressinfo( - addr)['hdkeypath'], 'm/0\'/0\'/0\'') + assert_equal(self.nodes[1].getaddressinfo(addr)["hdkeypath"], "m/0'/0'/0'") # Fill keypool with 1 key self.nodes[1].keypoolrefill(1) @@ -190,66 +182,82 @@ new_seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress()) orig_masterkeyid = new_masterkeyid self.nodes[1].sethdseed(False, new_seed) - new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] + new_masterkeyid = self.nodes[1].getwalletinfo()["hdseedid"] assert orig_masterkeyid != new_masterkeyid addr = self.nodes[1].getnewaddress() - assert_equal(orig_masterkeyid, self.nodes[1].getaddressinfo( - addr)['hdseedid']) + assert_equal( + orig_masterkeyid, self.nodes[1].getaddressinfo(addr)["hdseedid"] + ) # Make sure the new address continues previous keypool - assert_equal(self.nodes[1].getaddressinfo( - addr)['hdkeypath'], 'm/0\'/0\'/1\'') + assert_equal(self.nodes[1].getaddressinfo(addr)["hdkeypath"], "m/0'/0'/1'") # Check that the next address is from the new seed self.nodes[1].keypoolrefill(1) next_addr = self.nodes[1].getnewaddress() - assert_equal(new_masterkeyid, self.nodes[1].getaddressinfo( - next_addr)['hdseedid']) + assert_equal( + new_masterkeyid, self.nodes[1].getaddressinfo(next_addr)["hdseedid"] + ) # Make sure the new address is not from previous keypool - assert_equal(self.nodes[1].getaddressinfo( - next_addr)['hdkeypath'], 'm/0\'/0\'/0\'') + assert_equal( + self.nodes[1].getaddressinfo(next_addr)["hdkeypath"], "m/0'/0'/0'" + ) assert next_addr != addr # Sethdseed parameter validity - assert_raises_rpc_error(-1, 'sethdseed', self.nodes[0].sethdseed, - False, new_seed, 0) - assert_raises_rpc_error(-5, "Invalid private key", - self.nodes[1].sethdseed, False, "not_wif") assert_raises_rpc_error( - -1, "JSON value is not a boolean as expected", - self.nodes[1].sethdseed, "Not_bool") + -1, "sethdseed", self.nodes[0].sethdseed, False, new_seed, 0 + ) + assert_raises_rpc_error( + -5, "Invalid private key", self.nodes[1].sethdseed, False, "not_wif" + ) + assert_raises_rpc_error( + -1, + "JSON value is not a boolean as expected", + self.nodes[1].sethdseed, + "Not_bool", + ) assert_raises_rpc_error( - -1, "JSON value is not a string as expected", - self.nodes[1].sethdseed, False, True) + -1, + "JSON value is not a string as expected", + self.nodes[1].sethdseed, + False, + True, + ) assert_raises_rpc_error( - -5, "Already have this key", self.nodes[1].sethdseed, False, - new_seed) + -5, "Already have this key", self.nodes[1].sethdseed, False, new_seed + ) assert_raises_rpc_error( - -5, "Already have this key", self.nodes[1].sethdseed, False, - self.nodes[1].dumpprivkey(self.nodes[1].getnewaddress())) + -5, + "Already have this key", + self.nodes[1].sethdseed, + False, + self.nodes[1].dumpprivkey(self.nodes[1].getnewaddress()), + ) self.log.info( - 'Test sethdseed restoring with keys outside of the initial keypool') + "Test sethdseed restoring with keys outside of the initial keypool" + ) self.generate(self.nodes[0], 10) # Restart node 1 with keypool of 3 and a different wallet - self.nodes[1].createwallet(wallet_name='origin', blank=True) - self.restart_node(1, extra_args=['-keypool=3', '-wallet=origin']) + self.nodes[1].createwallet(wallet_name="origin", blank=True) + self.restart_node(1, extra_args=["-keypool=3", "-wallet=origin"]) self.connect_nodes(0, 1) # sethdseed restoring and seeing txs to addresses out of the # keypool - origin_rpc = self.nodes[1].get_wallet_rpc('origin') + origin_rpc = self.nodes[1].get_wallet_rpc("origin") seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress()) origin_rpc.sethdseed(True, seed) - self.nodes[1].createwallet(wallet_name='restore', blank=True) - restore_rpc = self.nodes[1].get_wallet_rpc('restore') + self.nodes[1].createwallet(wallet_name="restore", blank=True) + restore_rpc = self.nodes[1].get_wallet_rpc("restore") # Set to be the same seed as origin_rpc restore_rpc.sethdseed(True, seed) # Rotate to a new seed, making original `seed` inactive restore_rpc.sethdseed(True) - self.nodes[1].createwallet(wallet_name='restore2', blank=True) - restore2_rpc = self.nodes[1].get_wallet_rpc('restore2') + self.nodes[1].createwallet(wallet_name="restore2", blank=True) + restore2_rpc = self.nodes[1].get_wallet_rpc("restore2") # Set to be the same seed as origin_rpc restore2_rpc.sethdseed(True, seed) # Rotate to a new seed, making original `seed` inactive @@ -258,8 +266,8 @@ # Check persistence of inactive seed by reloading restore. restore2 # is still loaded to test the case where the wallet is not reloaded restore_rpc.unloadwallet() - self.nodes[1].loadwallet('restore') - restore_rpc = self.nodes[1].get_wallet_rpc('restore') + self.nodes[1].loadwallet("restore") + restore_rpc = self.nodes[1].get_wallet_rpc("restore") # Empty origin keypool and get an address that is beyond the # initial keypool @@ -272,29 +280,30 @@ # Check that the restored seed has last_addr but does not have addr info = restore_rpc.getaddressinfo(last_addr) - assert_equal(info['ismine'], True) + assert_equal(info["ismine"], True) info = restore_rpc.getaddressinfo(addr) - assert_equal(info['ismine'], False) + assert_equal(info["ismine"], False) info = restore2_rpc.getaddressinfo(last_addr) - assert_equal(info['ismine'], True) + assert_equal(info["ismine"], True) info = restore2_rpc.getaddressinfo(addr) - assert_equal(info['ismine'], False) + assert_equal(info["ismine"], False) # Check that the origin seed has addr info = origin_rpc.getaddressinfo(addr) - assert_equal(info['ismine'], True) + assert_equal(info["ismine"], True) # Send a transaction to addr, which is out of the initial keypool. # The wallet that has set a new seed (restore_rpc) should not # detect this transaction. txid = self.nodes[0].sendtoaddress(addr, 1000000) - origin_rpc.sendrawtransaction( - self.nodes[0].gettransaction(txid)['hex']) + origin_rpc.sendrawtransaction(self.nodes[0].gettransaction(txid)["hex"]) self.generate(self.nodes[0], 1) origin_rpc.gettransaction(txid) - assert_raises_rpc_error(-5, - 'Invalid or non-wallet transaction id', - restore_rpc.gettransaction, - txid) + assert_raises_rpc_error( + -5, + "Invalid or non-wallet transaction id", + restore_rpc.gettransaction, + txid, + ) out_of_kp_txid = txid # Send a transaction to last_addr, which is in the initial keypool. @@ -303,20 +312,23 @@ # The previous transaction (out_of_kp_txid) should still not be # detected as a rescan is required. txid = self.nodes[0].sendtoaddress(last_addr, 1000000) - origin_rpc.sendrawtransaction( - self.nodes[0].gettransaction(txid)['hex']) + origin_rpc.sendrawtransaction(self.nodes[0].gettransaction(txid)["hex"]) self.generate(self.nodes[0], 1) origin_rpc.gettransaction(txid) restore_rpc.gettransaction(txid) - assert_raises_rpc_error(-5, - 'Invalid or non-wallet transaction id', - restore_rpc.gettransaction, - out_of_kp_txid) + assert_raises_rpc_error( + -5, + "Invalid or non-wallet transaction id", + restore_rpc.gettransaction, + out_of_kp_txid, + ) restore2_rpc.gettransaction(txid) - assert_raises_rpc_error(-5, - 'Invalid or non-wallet transaction id', - restore2_rpc.gettransaction, - out_of_kp_txid) + assert_raises_rpc_error( + -5, + "Invalid or non-wallet transaction id", + restore2_rpc.gettransaction, + out_of_kp_txid, + ) # After rescanning, restore_rpc should now see out_of_kp_txid and # generate an additional key. @@ -324,11 +336,11 @@ restore_rpc.rescanblockchain() restore_rpc.gettransaction(out_of_kp_txid) info = restore_rpc.getaddressinfo(addr) - assert_equal(info['ismine'], True) + assert_equal(info["ismine"], True) restore2_rpc.rescanblockchain() restore2_rpc.gettransaction(out_of_kp_txid) info = restore2_rpc.getaddressinfo(addr) - assert_equal(info['ismine'], True) + assert_equal(info["ismine"], True) # Check again that 3 keys were derived. # Empty keypool and get an address that is beyond the initial @@ -340,14 +352,14 @@ # Check that the restored seed has last_addr but does not have addr info = restore_rpc.getaddressinfo(last_addr) - assert_equal(info['ismine'], True) + assert_equal(info["ismine"], True) info = restore_rpc.getaddressinfo(addr) - assert_equal(info['ismine'], False) + assert_equal(info["ismine"], False) info = restore2_rpc.getaddressinfo(last_addr) - assert_equal(info['ismine'], True) + assert_equal(info["ismine"], True) info = restore2_rpc.getaddressinfo(addr) - assert_equal(info['ismine'], False) + assert_equal(info["ismine"], False) -if __name__ == '__main__': +if __name__ == "__main__": WalletHDTest().main() diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -45,33 +45,38 @@ if self.call == Call.single: if self.data == Data.address: response = self.node.importaddress( - address=self.address["address"], label=self.label, rescan=rescan) + address=self.address["address"], label=self.label, rescan=rescan + ) elif self.data == Data.pub: response = self.node.importpubkey( - pubkey=self.address["pubkey"], label=self.label, rescan=rescan) + pubkey=self.address["pubkey"], label=self.label, rescan=rescan + ) elif self.data == Data.priv: response = self.node.importprivkey( - privkey=self.key, label=self.label, rescan=rescan) + privkey=self.key, label=self.label, rescan=rescan + ) assert_equal(response, None) elif self.call in (Call.multiaddress, Call.multiscript): request = { - "scriptPubKey": { - "address": self.address["address"] - } if self.call == Call.multiaddress else self.address["scriptPubKey"], - "timestamp": timestamp + TIMESTAMP_WINDOW + ( - 1 if self.rescan == Rescan.late_timestamp else 0), + "scriptPubKey": ( + {"address": self.address["address"]} + if self.call == Call.multiaddress + else self.address["scriptPubKey"] + ), + "timestamp": ( + timestamp + + TIMESTAMP_WINDOW + + (1 if self.rescan == Rescan.late_timestamp else 0) + ), "pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [], "keys": [self.key] if self.data == Data.priv else [], "label": self.label, - "watchonly": self.data != Data.priv + "watchonly": self.data != Data.priv, } response = self.node.importmulti( requests=[request], - options={ - "rescan": self.rescan in ( - Rescan.yes, - Rescan.late_timestamp)}, + options={"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)}, ) assert_equal(response, [{"success": True}]) @@ -79,32 +84,34 @@ """Verify that listtransactions/listreceivedbyaddress return expected values.""" txs = self.node.listtransactions( - label=self.label, count=10000, include_watchonly=True) + label=self.label, count=10000, include_watchonly=True + ) current_height = self.node.getblockcount() assert_equal(len(txs), self.expected_txs) addresses = self.node.listreceivedbyaddress( - minconf=0, include_watchonly=True, address_filter=self.address['address']) + minconf=0, include_watchonly=True, address_filter=self.address["address"] + ) if self.expected_txs: assert_equal(len(addresses[0]["txids"]), self.expected_txs) if txid is not None: - tx, = [tx for tx in txs if tx["txid"] == txid] + (tx,) = [tx for tx in txs if tx["txid"] == txid] assert_equal(tx["label"], self.label) assert_equal(tx["address"], self.address["address"]) assert_equal(tx["amount"], amount) assert_equal(tx["category"], "receive") assert_equal(tx["label"], self.label) assert_equal(tx["txid"], txid) - assert_equal(tx["confirmations"], - 1 + current_height - confirmation_height) + assert_equal(tx["confirmations"], 1 + current_height - confirmation_height) assert_equal("trusted" not in tx, True) - address, = [ad for ad in addresses if txid in ad["txids"]] + (address,) = [ad for ad in addresses if txid in ad["txids"]] assert_equal(address["address"], self.address["address"]) assert_equal(address["amount"], self.expected_balance) - assert_equal(address["confirmations"], - 1 + current_height - confirmation_height) + assert_equal( + address["confirmations"], 1 + current_height - confirmation_height + ) # Verify the transaction is correctly marked watchonly depending on # whether the transaction pays to an imported public key or # imported private key. The test setup ensures that transaction @@ -118,8 +125,10 @@ # List of Variants for each way a key or address could be imported. -IMPORT_VARIANTS = [Variant(*variants) - for variants in itertools.product(Call, Data, Rescan, (False, True))] +IMPORT_VARIANTS = [ + Variant(*variants) + for variants in itertools.product(Call, Data, Rescan, (False, True)) +] # List of nodes to import keys to. Half the nodes will have pruning disabled, # half will have it enabled. Different nodes will be used for imports that are @@ -128,8 +137,9 @@ # transactions associated with earlier imports. This makes it easier to keep # track of expected balances and transactions. ImportNode = collections.namedtuple("ImportNode", "prune rescan") -IMPORT_NODES = [ImportNode(*fields) - for fields in itertools.product((False, True), repeat=2)] +IMPORT_NODES = [ + ImportNode(*fields) for fields in itertools.product((False, True), repeat=2) +] # Rescans start at the earliest block up to 2 hours before the key timestamp. TIMESTAMP_WINDOW = 2 * 60 * 60 @@ -174,36 +184,47 @@ for i, variant in enumerate(IMPORT_VARIANTS): variant.label = f"label {i} {variant}" variant.address = self.nodes[1].getaddressinfo( - self.nodes[1].getnewaddress(label=variant.label)) + self.nodes[1].getnewaddress(label=variant.label) + ) variant.key = self.nodes[1].dumpprivkey(variant.address["address"]) variant.initial_amount = get_rand_amount() variant.initial_txid = self.nodes[0].sendtoaddress( - variant.address["address"], variant.initial_amount) + variant.address["address"], variant.initial_amount + ) # Generate one block for each send self.generate(self.nodes[0], 1) variant.confirmation_height = self.nodes[0].getblockcount() variant.timestamp = self.nodes[0].getblockheader( - self.nodes[0].getbestblockhash())["time"] + self.nodes[0].getbestblockhash() + )["time"] # Generate a block further in the future (past the rescan window). assert_equal(self.nodes[0].getrawmempool(), []) - set_node_times(self.nodes, self.nodes[0].getblockheader( - self.nodes[0].getbestblockhash())["time"] + TIMESTAMP_WINDOW + 1) + set_node_times( + self.nodes, + self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"] + + TIMESTAMP_WINDOW + + 1, + ) self.generate(self.nodes[0], 1) # For each variation of wallet key import, invoke the import RPC and # check the results from getbalance and listtransactions. for variant in IMPORT_VARIANTS: - self.log.info(f'Run import for variant {variant}') + self.log.info(f"Run import for variant {variant}") expect_rescan = variant.rescan == Rescan.yes - variant.node = self.nodes[2 + IMPORT_NODES.index( - ImportNode(variant.prune, expect_rescan))] + variant.node = self.nodes[ + 2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan)) + ] variant.do_import(variant.timestamp) if expect_rescan: variant.expected_balance = variant.initial_amount variant.expected_txs = 1 - variant.check(variant.initial_txid, variant.initial_amount, - variant.confirmation_height) + variant.check( + variant.initial_txid, + variant.initial_amount, + variant.confirmation_height, + ) else: variant.expected_balance = 0 variant.expected_txs = 0 @@ -213,7 +234,8 @@ for i, variant in enumerate(IMPORT_VARIANTS): variant.sent_amount = get_rand_amount() variant.sent_txid = self.nodes[0].sendtoaddress( - variant.address["address"], variant.sent_amount) + variant.address["address"], variant.sent_amount + ) # Generate one block for each send self.generate(self.nodes[0], 1) variant.confirmation_height = self.nodes[0].getblockcount() @@ -223,11 +245,12 @@ # Check the latest results from getbalance and listtransactions. for variant in IMPORT_VARIANTS: - self.log.info(f'Run check for variant {variant}') + self.log.info(f"Run check for variant {variant}") variant.expected_balance += variant.sent_amount variant.expected_txs += 1 - variant.check(variant.sent_txid, variant.sent_amount, - variant.confirmation_height) + variant.check( + variant.sent_txid, variant.sent_amount, variant.confirmation_height + ) if __name__ == "__main__": diff --git a/test/functional/wallet_import_with_label.py b/test/functional/wallet_import_with_label.py --- a/test/functional/wallet_import_with_label.py +++ b/test/functional/wallet_import_with_label.py @@ -34,18 +34,14 @@ def run_test(self): """Main test logic""" - self.log.info( - "Test importaddress with label and importprivkey without label." - ) + self.log.info("Test importaddress with label and importprivkey without label.") self.log.info("Import a watch-only address with a label.") address = self.nodes[0].getnewaddress() label = "Test Label" self.nodes[1].importaddress(address, label) - test_address(self.nodes[1], - address, - iswatchonly=True, - ismine=False, - labels=[label]) + test_address( + self.nodes[1], address, iswatchonly=True, ismine=False, labels=[label] + ) self.log.info( "Import the watch-only address's private key without a " @@ -55,17 +51,13 @@ self.nodes[1].importprivkey(priv_key) test_address(self.nodes[1], address, labels=[label]) - self.log.info( - "Test importaddress without label and importprivkey with label." - ) + self.log.info("Test importaddress without label and importprivkey with label.") self.log.info("Import a watch-only address without a label.") address2 = self.nodes[0].getnewaddress() self.nodes[1].importaddress(address2) - test_address(self.nodes[1], - address2, - iswatchonly=True, - ismine=False, - labels=[""]) + test_address( + self.nodes[1], address2, iswatchonly=True, ismine=False, labels=[""] + ) self.log.info( "Import the watch-only address's private key with a " @@ -77,17 +69,18 @@ test_address(self.nodes[1], address2, labels=[label2]) - self.log.info( - "Test importaddress with label and importprivkey with label.") + self.log.info("Test importaddress with label and importprivkey with label.") self.log.info("Import a watch-only address with a label.") address3 = self.nodes[0].getnewaddress() label3_addr = "Test Label 3 for importaddress" self.nodes[1].importaddress(address3, label3_addr) - test_address(self.nodes[1], - address3, - iswatchonly=True, - ismine=False, - labels=[label3_addr]) + test_address( + self.nodes[1], + address3, + iswatchonly=True, + ismine=False, + labels=[label3_addr], + ) self.log.info( "Import the watch-only address's private key with a " @@ -97,10 +90,7 @@ label3_priv = "Test Label 3 for importprivkey" self.nodes[1].importprivkey(priv_key3, label3_priv) - test_address( - self.nodes[1], - address3, - labels=[label3_priv]) + test_address(self.nodes[1], address3, labels=[label3_priv]) self.log.info( "Test importprivkey won't label new dests with the same " @@ -110,12 +100,14 @@ address4 = self.nodes[0].getnewaddress() label4_addr = "Test Label 4 for importaddress" self.nodes[1].importaddress(address4, label4_addr) - test_address(self.nodes[1], - address4, - iswatchonly=True, - ismine=False, - labels=[label4_addr], - embedded=None) + test_address( + self.nodes[1], + address4, + iswatchonly=True, + ismine=False, + labels=[label4_addr], + embedded=None, + ) self.log.info( "Import the watch-only address's private key without a " @@ -126,28 +118,26 @@ # Build a P2SH manually for this test. priv_key4 = self.nodes[0].dumpprivkey(address4) - pubkey4 = self.nodes[0].getaddressinfo(address4)['pubkey'] + pubkey4 = self.nodes[0].getaddressinfo(address4)["pubkey"] pkh4 = hash160(bytes.fromhex(pubkey4)) - script4 = CScript( - [OP_DUP, OP_HASH160, pkh4, OP_EQUALVERIFY, OP_CHECKSIG]) + script4 = CScript([OP_DUP, OP_HASH160, pkh4, OP_EQUALVERIFY, OP_CHECKSIG]) p2shaddr4 = script_to_p2sh(script4) - self.nodes[1].importmulti([{ - "scriptPubKey": {"address": p2shaddr4}, - "timestamp": "now", - "redeemscript": script4.hex(), - "keys": [priv_key4], - }]) - - test_address(self.nodes[1], - p2shaddr4, - labels=[""]) - - embedded_addr = self.nodes[1].getaddressinfo( - p2shaddr4)['embedded']['address'] - test_address(self.nodes[1], - embedded_addr, - labels=[label4_addr]) + self.nodes[1].importmulti( + [ + { + "scriptPubKey": {"address": p2shaddr4}, + "timestamp": "now", + "redeemscript": script4.hex(), + "keys": [priv_key4], + } + ] + ) + + test_address(self.nodes[1], p2shaddr4, labels=[""]) + + embedded_addr = self.nodes[1].getaddressinfo(p2shaddr4)["embedded"]["address"] + test_address(self.nodes[1], embedded_addr, labels=[label4_addr]) self.stop_nodes() diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py --- a/test/functional/wallet_importdescriptors.py +++ b/test/functional/wallet_importdescriptors.py @@ -38,52 +38,53 @@ def skip_test_if_missing_module(self): self.skip_if_no_wallet() - def test_importdesc(self, req, success, error_code=None, - error_message=None, warnings=None, wallet=None): + def test_importdesc( + self, + req, + success, + error_code=None, + error_message=None, + warnings=None, + wallet=None, + ): """Run importdescriptors and assert success""" if warnings is None: warnings = [] - wrpc = self.nodes[1].get_wallet_rpc('w1') + wrpc = self.nodes[1].get_wallet_rpc("w1") if wallet is not None: wrpc = wallet result = wrpc.importdescriptors([req]) observed_warnings = [] - if 'warnings' in result[0]: - observed_warnings = result[0]['warnings'] - assert_equal( - "\n".join( - sorted(warnings)), "\n".join( - sorted(observed_warnings))) - assert_equal(result[0]['success'], success) + if "warnings" in result[0]: + observed_warnings = result[0]["warnings"] + assert_equal("\n".join(sorted(warnings)), "\n".join(sorted(observed_warnings))) + assert_equal(result[0]["success"], success) if error_code is not None: - assert_equal(result[0]['error']['code'], error_code) - assert_equal(result[0]['error']['message'], error_message) + assert_equal(result[0]["error"]["code"], error_code) + assert_equal(result[0]["error"]["message"], error_message) def run_test(self): - self.log.info('Setting up wallets') - self.nodes[0].createwallet( - wallet_name='w0', - disable_private_keys=False) - w0 = self.nodes[0].get_wallet_rpc('w0') + self.log.info("Setting up wallets") + self.nodes[0].createwallet(wallet_name="w0", disable_private_keys=False) + w0 = self.nodes[0].get_wallet_rpc("w0") self.nodes[1].createwallet( - wallet_name='w1', - disable_private_keys=True, - blank=True, - descriptors=True) - w1 = self.nodes[1].get_wallet_rpc('w1') - assert_equal(w1.getwalletinfo()['keypoolsize'], 0) + wallet_name="w1", disable_private_keys=True, blank=True, descriptors=True + ) + w1 = self.nodes[1].get_wallet_rpc("w1") + assert_equal(w1.getwalletinfo()["keypoolsize"], 0) self.nodes[1].createwallet( wallet_name="wpriv", disable_private_keys=False, blank=True, - descriptors=True) + descriptors=True, + ) wpriv = self.nodes[1].get_wallet_rpc("wpriv") - assert_equal(wpriv.getwalletinfo()['keypoolsize'], 0) + assert_equal(wpriv.getwalletinfo()["keypoolsize"], 0) - self.log.info('Mining coins') + self.log.info("Mining coins") self.generatetoaddress(self.nodes[0], 101, w0.getnewaddress()) # RPC importdescriptors ----------------------------------------------- @@ -91,266 +92,340 @@ # # Test import fails if no descriptor present key = get_generate_key() self.log.info("Import should fail if a descriptor is not provided") - self.test_importdesc({"timestamp": "now"}, - success=False, - error_code=-8, - error_message='Descriptor not found.') + self.test_importdesc( + {"timestamp": "now"}, + success=False, + error_code=-8, + error_message="Descriptor not found.", + ) # # Test importing of a P2PKH descriptor key = get_generate_key() self.log.info("Should import a p2pkh descriptor") - self.test_importdesc({"desc": descsum_create(f"pkh({key.pubkey})"), - "timestamp": "now", - "label": "Descriptor import test"}, - success=True) - test_address(w1, - key.p2pkh_addr, - solvable=True, - ismine=True, - labels=["Descriptor import test"]) - assert_equal(w1.getwalletinfo()['keypoolsize'], 0) + self.test_importdesc( + { + "desc": descsum_create(f"pkh({key.pubkey})"), + "timestamp": "now", + "label": "Descriptor import test", + }, + success=True, + ) + test_address( + w1, + key.p2pkh_addr, + solvable=True, + ismine=True, + labels=["Descriptor import test"], + ) + assert_equal(w1.getwalletinfo()["keypoolsize"], 0) self.log.info("Internal addresses cannot have labels") - self.test_importdesc({"desc": descsum_create(f"pkh({key.pubkey})"), - "timestamp": "now", - "internal": True, - "label": "Descriptor import test"}, - success=False, - error_code=-8, - error_message="Internal addresses should not have a label") + self.test_importdesc( + { + "desc": descsum_create(f"pkh({key.pubkey})"), + "timestamp": "now", + "internal": True, + "label": "Descriptor import test", + }, + success=False, + error_code=-8, + error_message="Internal addresses should not have a label", + ) self.log.info("Internal addresses should be detected as such") key = get_generate_key() addr = key_to_p2pkh(key.pubkey) - self.test_importdesc({"desc": descsum_create(f"pkh({key.pubkey})"), - "timestamp": "now", - "internal": True}, - success=True) + self.test_importdesc( + { + "desc": descsum_create(f"pkh({key.pubkey})"), + "timestamp": "now", + "internal": True, + }, + success=True, + ) info = w1.getaddressinfo(addr) assert_equal(info["ismine"], True) assert_equal(info["ischange"], True) - assert_equal(w1.getwalletinfo()['keypoolsize'], 0) + assert_equal(w1.getwalletinfo()["keypoolsize"], 0) - test_address(w1, - key.p2pkh_addr, - ismine=True, - solvable=True) + test_address(w1, key.p2pkh_addr, ismine=True, solvable=True) # Check persistence of data and that loading works correctly w1.unloadwallet() - self.nodes[1].loadwallet('w1') - test_address(w1, - key.p2pkh_addr, - ismine=True, - solvable=True) + self.nodes[1].loadwallet("w1") + test_address(w1, key.p2pkh_addr, ismine=True, solvable=True) # # Test importing of a multisig descriptor key1 = get_generate_key() key2 = get_generate_key() self.log.info("Should import a 1-of-2 bare multisig from descriptor") - self.test_importdesc({"desc": descsum_create(f"multi(1,{key1.pubkey},{key2.pubkey})"), - "timestamp": "now"}, - success=True) + self.test_importdesc( + { + "desc": descsum_create(f"multi(1,{key1.pubkey},{key2.pubkey})"), + "timestamp": "now", + }, + success=True, + ) self.log.info( - "Should not treat individual keys from the imported bare multisig as watchonly") - test_address(w1, - key1.p2pkh_addr, - ismine=False) + "Should not treat individual keys from the imported bare multisig as" + " watchonly" + ) + test_address(w1, key1.p2pkh_addr, ismine=False) # # Test ranged descriptors xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg" xpub = "tpubD6NzVbkrYhZ4YNXVQbNhMK1WqguFsUXceaVJKbmno2aZ3B6QfbMeraaYvnBSGpV3vxLyTTK9DYT1yoEck4XUScMzXoQ2U2oSmE2JyMedq3H" addresses = [ "2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf", - "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA"] # hdkeypath=m/0'/0'/0' and 1' + "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA", + ] # hdkeypath=m/0'/0'/0' and 1' # wpkh subscripts corresponding to the above addresses - addresses += ["ecregtest:prvn9ycvgr5atuyh49sua3mapskh2mnnzg7t9yp6dt", - "ecregtest:pp3n087yx0njv2e5wcvltahfxqst7l66rutz8ceeat"] + addresses += [ + "ecregtest:prvn9ycvgr5atuyh49sua3mapskh2mnnzg7t9yp6dt", + "ecregtest:pp3n087yx0njv2e5wcvltahfxqst7l66rutz8ceeat", + ] desc = f"sh(pkh({xpub}/0/0/*))" self.log.info("Ranged descriptors cannot have labels") - self.test_importdesc({"desc": descsum_create(desc), - "timestamp": "now", - "range": [0, 100], - "label": "test"}, - success=False, - error_code=-8, - error_message='Ranged descriptors should not have a label') + self.test_importdesc( + { + "desc": descsum_create(desc), + "timestamp": "now", + "range": [0, 100], + "label": "test", + }, + success=False, + error_code=-8, + error_message="Ranged descriptors should not have a label", + ) self.log.info("Private keys required for private keys enabled wallet") - self.test_importdesc({"desc": descsum_create(desc), - "timestamp": "now", - "range": [0, 100]}, - success=False, - error_code=-4, - error_message='Cannot import descriptor without private keys to a wallet with private keys enabled', - wallet=wpriv) - - self.log.info( - "Ranged descriptor import should warn without a specified range") - self.test_importdesc({"desc": descsum_create(desc), - "timestamp": "now"}, - success=True, - warnings=['Range not given, using default keypool range']) - assert_equal(w1.getwalletinfo()['keypoolsize'], 0) + self.test_importdesc( + {"desc": descsum_create(desc), "timestamp": "now", "range": [0, 100]}, + success=False, + error_code=-4, + error_message=( + "Cannot import descriptor without private keys to a wallet with private" + " keys enabled" + ), + wallet=wpriv, + ) + + self.log.info("Ranged descriptor import should warn without a specified range") + self.test_importdesc( + {"desc": descsum_create(desc), "timestamp": "now"}, + success=True, + warnings=["Range not given, using default keypool range"], + ) + assert_equal(w1.getwalletinfo()["keypoolsize"], 0) # # Test importing of a ranged descriptor with xpriv self.log.info( - "Should not import a ranged descriptor that includes xpriv into a watch-only wallet") + "Should not import a ranged descriptor that includes xpriv into a" + " watch-only wallet" + ) desc = f"sh(pkh({xpriv}/0'/0'/*'))" - self.test_importdesc({"desc": descsum_create(desc), - "timestamp": "now", - "range": 1}, - success=False, - error_code=-4, - error_message='Cannot import private keys to a wallet with private keys disabled') - - self.log.info("Should not import a descriptor with hardened " - "derivations when private keys are disabled") - self.test_importdesc({"desc": descsum_create(f"pkh({xpub}/1h/*)"), - "timestamp": "now", - "range": 1}, - success=False, - error_code=-4, - error_message='Cannot expand descriptor. Probably because of hardened derivations without private keys provided') + self.test_importdesc( + {"desc": descsum_create(desc), "timestamp": "now", "range": 1}, + success=False, + error_code=-4, + error_message=( + "Cannot import private keys to a wallet with private keys disabled" + ), + ) - for address in addresses: - test_address(w1, - address, - ismine=False, - solvable=False) - - self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": -1}, - success=False, error_code=-8, error_message='End of range is too high') - - self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]}, - success=False, error_code=-8, error_message='Range should be greater or equal than 0') - - self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]}, - success=False, error_code=-8, error_message='End of range is too high') - - self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]}, - success=False, error_code=-8, error_message='Range specified as [begin,end] must not have begin after end') + self.log.info( + "Should not import a descriptor with hardened " + "derivations when private keys are disabled" + ) + self.test_importdesc( + { + "desc": descsum_create(f"pkh({xpub}/1h/*)"), + "timestamp": "now", + "range": 1, + }, + success=False, + error_code=-4, + error_message=( + "Cannot expand descriptor. Probably because of hardened derivations" + " without private keys provided" + ), + ) - self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]}, - success=False, error_code=-8, error_message='Range is too large') + for address in addresses: + test_address(w1, address, ismine=False, solvable=False) + + self.test_importdesc( + {"desc": descsum_create(desc), "timestamp": "now", "range": -1}, + success=False, + error_code=-8, + error_message="End of range is too high", + ) + + self.test_importdesc( + {"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]}, + success=False, + error_code=-8, + error_message="Range should be greater or equal than 0", + ) + + self.test_importdesc( + { + "desc": descsum_create(desc), + "timestamp": "now", + "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)], + }, + success=False, + error_code=-8, + error_message="End of range is too high", + ) + + self.test_importdesc( + {"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]}, + success=False, + error_code=-8, + error_message=( + "Range specified as [begin,end] must not have begin after end" + ), + ) + + self.test_importdesc( + {"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]}, + success=False, + error_code=-8, + error_message="Range is too large", + ) # Make sure ranged imports import keys in order - w1 = self.nodes[1].get_wallet_rpc('w1') - self.log.info('Key ranges should be imported in order') + w1 = self.nodes[1].get_wallet_rpc("w1") + self.log.info("Key ranges should be imported in order") xpub = "tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY" addresses = [ - 'ecregtest:qp0v86h53rc92hjrlpwzpjtdlgzsxu25svv6g40fpl', # m/0'/0'/0 - 'ecregtest:qqasy0zlkdleqt4pkn8fs4ehm5gnnz6qpgdcpt90fq', # m/0'/0'/1 - 'ecregtest:qp0sp4wlhctvprqvdt2dgvqcfdjssu04xgey0l3syw', # m/0'/0'/2 - 'ecregtest:qrhn24tegn04cptfv4ldhtkduxq55zcwrycjfdj9vr', # m/0'/0'/3 - 'ecregtest:qzpqhett2uwltq803vrxv7zkqhft5vsnmcjeh50v0p', # m/0'/0'/4 + "ecregtest:qp0v86h53rc92hjrlpwzpjtdlgzsxu25svv6g40fpl", # m/0'/0'/0 + "ecregtest:qqasy0zlkdleqt4pkn8fs4ehm5gnnz6qpgdcpt90fq", # m/0'/0'/1 + "ecregtest:qp0sp4wlhctvprqvdt2dgvqcfdjssu04xgey0l3syw", # m/0'/0'/2 + "ecregtest:qrhn24tegn04cptfv4ldhtkduxq55zcwrycjfdj9vr", # m/0'/0'/3 + "ecregtest:qzpqhett2uwltq803vrxv7zkqhft5vsnmcjeh50v0p", # m/0'/0'/4 ] - self.test_importdesc({'desc': descsum_create(f"sh(pkh([abcdef12/0h/0h]{xpub}/*))"), - 'active': True, - 'range': [0, 2], - 'timestamp': 'now' - }, - success=True) - self.test_importdesc({'desc': descsum_create(f"pkh([12345678/0h/0h]{xpub}/*)"), - 'active': True, - 'range': [0, 2], - 'timestamp': 'now' - }, - success=True) - - assert_equal(w1.getwalletinfo()['keypoolsize'], 5) + self.test_importdesc( + { + "desc": descsum_create(f"sh(pkh([abcdef12/0h/0h]{xpub}/*))"), + "active": True, + "range": [0, 2], + "timestamp": "now", + }, + success=True, + ) + self.test_importdesc( + { + "desc": descsum_create(f"pkh([12345678/0h/0h]{xpub}/*)"), + "active": True, + "range": [0, 2], + "timestamp": "now", + }, + success=True, + ) + + assert_equal(w1.getwalletinfo()["keypoolsize"], 5) for i, expected_addr in enumerate(addresses): - pkh_addr = w1.getnewaddress('') - assert_raises_rpc_error(-4, - 'This wallet has no available keys', - w1.getrawchangeaddress) + pkh_addr = w1.getnewaddress("") + assert_raises_rpc_error( + -4, "This wallet has no available keys", w1.getrawchangeaddress + ) assert_equal(pkh_addr, expected_addr) pkh_addr_info = w1.getaddressinfo(pkh_addr) - assert_equal(pkh_addr_info['desc'][:22], - f'pkh([12345678/0\'/0\'/{i}]') + assert_equal(pkh_addr_info["desc"][:22], f"pkh([12345678/0'/0'/{i}]") # After retrieving a key, we don't refill the keypool again, so # it's one less for each address type - assert_equal(w1.getwalletinfo()['keypoolsize'], 4) + assert_equal(w1.getwalletinfo()["keypoolsize"], 4) w1.keypoolrefill() - assert_equal(w1.getwalletinfo()['keypoolsize'], 5) + assert_equal(w1.getwalletinfo()["keypoolsize"], 5) # Check active=False default - self.log.info('Check imported descriptors are not active by default') - self.test_importdesc({'desc': descsum_create(f"pkh([12345678/0h/0h]{xpub}/*)"), - 'range': [0, 2], - 'timestamp': 'now', - 'internal': True - }, - success=True) - assert_raises_rpc_error(-4, - 'This wallet has no available keys', - w1.getrawchangeaddress) + self.log.info("Check imported descriptors are not active by default") + self.test_importdesc( + { + "desc": descsum_create(f"pkh([12345678/0h/0h]{xpub}/*)"), + "range": [0, 2], + "timestamp": "now", + "internal": True, + }, + success=True, + ) + assert_raises_rpc_error( + -4, "This wallet has no available keys", w1.getrawchangeaddress + ) # # Test importing a descriptor containing a WIF private key wif_priv = "cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh" address = "ecregtest:ppn85zpvym8cdccmgw8km6e48jfhnpa435h3hkyfd6" desc = f"sh(pkh({wif_priv}))" - self.log.info( - "Should import a descriptor with a WIF private key as spendable") - self.test_importdesc({"desc": descsum_create(desc), - "timestamp": "now"}, - success=True, - wallet=wpriv) - test_address(wpriv, - address, - solvable=True, - ismine=True) + self.log.info("Should import a descriptor with a WIF private key as spendable") + self.test_importdesc( + {"desc": descsum_create(desc), "timestamp": "now"}, + success=True, + wallet=wpriv, + ) + test_address(wpriv, address, solvable=True, ismine=True) txid = w0.sendtoaddress(address, 49999996.00) self.generatetoaddress(self.nodes[0], 6, w0.getnewaddress()) - tx = wpriv.createrawtransaction([{"txid": txid, "vout": 0}], { - w0.getnewaddress(): 49999000}) + tx = wpriv.createrawtransaction( + [{"txid": txid, "vout": 0}], {w0.getnewaddress(): 49999000} + ) signed_tx = wpriv.signrawtransactionwithwallet(tx) - w1.sendrawtransaction(signed_tx['hex']) + w1.sendrawtransaction(signed_tx["hex"]) # Make sure that we can use import and use multisig as addresses self.log.info( - 'Test that multisigs can be imported, signed for, and getnewaddress\'d') + "Test that multisigs can be imported, signed for, and getnewaddress'd" + ) self.nodes[1].createwallet( wallet_name="wmulti_priv", disable_private_keys=False, blank=True, - descriptors=True) + descriptors=True, + ) wmulti_priv = self.nodes[1].get_wallet_rpc("wmulti_priv") - assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 0) - - self.test_importdesc({"desc": "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/0h/0h/*))#f5nqn4ax", - "active": True, - "range": 1000, - "next_index": 0, - "timestamp": "now"}, - success=True, - wallet=wmulti_priv) - self.test_importdesc({"desc": "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/1h/0h/*))#m4e4s5de", - "active": True, - "internal": True, - "range": 1000, - "next_index": 0, - "timestamp": "now"}, - success=True, - wallet=wmulti_priv) + assert_equal(wmulti_priv.getwalletinfo()["keypoolsize"], 0) + + self.test_importdesc( + { + "desc": "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/0h/0h/*))#f5nqn4ax", + "active": True, + "range": 1000, + "next_index": 0, + "timestamp": "now", + }, + success=True, + wallet=wmulti_priv, + ) + self.test_importdesc( + { + "desc": "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/1h/0h/*))#m4e4s5de", + "active": True, + "internal": True, + "range": 1000, + "next_index": 0, + "timestamp": "now", + }, + success=True, + wallet=wmulti_priv, + ) # Range end (1000) is inclusive, so 1001 addresses generated - assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1001) - addr = wmulti_priv.getnewaddress('') + assert_equal(wmulti_priv.getwalletinfo()["keypoolsize"], 1001) + addr = wmulti_priv.getnewaddress("") # Derived at m/84'/0'/0'/0 - assert_equal( - addr, - 'ecregtest:pzkcf26dw7np58jcspnpxaupgz9csnc3wsf5wdh2a3') + assert_equal(addr, "ecregtest:pzkcf26dw7np58jcspnpxaupgz9csnc3wsf5wdh2a3") change_addr = wmulti_priv.getrawchangeaddress() assert_equal( - change_addr, - 'ecregtest:prnkfg7pxe3kpyv3l4v00ft6q3sfseag7vnva0k49n') + change_addr, "ecregtest:prnkfg7pxe3kpyv3l4v00ft6q3sfseag7vnva0k49n" + ) - assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1000) + assert_equal(wmulti_priv.getwalletinfo()["keypoolsize"], 1000) txid = w0.sendtoaddress(addr, 10000000) self.generate(self.nodes[0], 6) @@ -358,40 +433,47 @@ wallet_name="wmulti_pub", disable_private_keys=True, blank=True, - descriptors=True) + descriptors=True, + ) wmulti_pub = self.nodes[1].get_wallet_rpc("wmulti_pub") - assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 0) - - self.test_importdesc({"desc": "sh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))#x75vpsak", - "active": True, - "range": 1000, - "next_index": 0, - "timestamp": "now"}, - success=True, - wallet=wmulti_pub) - self.test_importdesc({"desc": "sh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))#v0t48ucu", - "active": True, - "internal": True, - "range": 1000, - "next_index": 0, - "timestamp": "now"}, - success=True, - wallet=wmulti_pub) + assert_equal(wmulti_pub.getwalletinfo()["keypoolsize"], 0) + + self.test_importdesc( + { + "desc": "sh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))#x75vpsak", + "active": True, + "range": 1000, + "next_index": 0, + "timestamp": "now", + }, + success=True, + wallet=wmulti_pub, + ) + self.test_importdesc( + { + "desc": "sh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))#v0t48ucu", + "active": True, + "internal": True, + "range": 1000, + "next_index": 0, + "timestamp": "now", + }, + success=True, + wallet=wmulti_pub, + ) # The first one was already consumed by previous import and is detected # as used - assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 1000) - addr = wmulti_pub.getnewaddress('') + assert_equal(wmulti_pub.getwalletinfo()["keypoolsize"], 1000) + addr = wmulti_pub.getnewaddress("") # Derived at m/84'/0'/0'/1 - assert_equal( - addr, - 'ecregtest:pr5xql8r03jp5dvrep22dns59vf7hhykr5nmaucy2h') + assert_equal(addr, "ecregtest:pr5xql8r03jp5dvrep22dns59vf7hhykr5nmaucy2h") change_addr = wmulti_pub.getrawchangeaddress() assert_equal( - change_addr, - 'ecregtest:prnkfg7pxe3kpyv3l4v00ft6q3sfseag7vnva0k49n') + change_addr, "ecregtest:prnkfg7pxe3kpyv3l4v00ft6q3sfseag7vnva0k49n" + ) - assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 999) + assert_equal(wmulti_pub.getwalletinfo()["keypoolsize"], 999) txid = w0.sendtoaddress(addr, 10000000) vout = find_vout_for_address(self.nodes[0], txid, addr) self.generate(self.nodes[0], 6) @@ -400,94 +482,133 @@ # Make sure that descriptor wallets containing multiple xpubs in a # single descriptor load correctly wmulti_pub.unloadwallet() - self.nodes[1].loadwallet('wmulti_pub') + self.nodes[1].loadwallet("wmulti_pub") self.log.info("Multisig with distributed keys") - self.nodes[1].createwallet( - wallet_name="wmulti_priv1", - descriptors=True) + self.nodes[1].createwallet(wallet_name="wmulti_priv1", descriptors=True) wmulti_priv1 = self.nodes[1].get_wallet_rpc("wmulti_priv1") - res = wmulti_priv1.importdescriptors([ - { - "desc": descsum_create("sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))"), - "active": True, - "range": 1000, - "next_index": 0, - "timestamp": "now" - }, - { - "desc": descsum_create("sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))"), - "active": True, - "internal": True, - "range": 1000, - "next_index": 0, - "timestamp": "now" - }]) - assert_equal(res[0]['success'], True) + res = wmulti_priv1.importdescriptors( + [ + { + "desc": descsum_create( + "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))" + ), + "active": True, + "range": 1000, + "next_index": 0, + "timestamp": "now", + }, + { + "desc": descsum_create( + "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))" + ), + "active": True, + "internal": True, + "range": 1000, + "next_index": 0, + "timestamp": "now", + }, + ] + ) + assert_equal(res[0]["success"], True) assert_equal( - res[0]['warnings'][0], - 'Not all private keys provided. Some wallet functionality may return unexpected errors') - assert_equal(res[1]['success'], True) + res[0]["warnings"][0], + ( + "Not all private keys provided. Some wallet functionality may return" + " unexpected errors" + ), + ) + assert_equal(res[1]["success"], True) assert_equal( - res[1]['warnings'][0], - 'Not all private keys provided. Some wallet functionality may return unexpected errors') + res[1]["warnings"][0], + ( + "Not all private keys provided. Some wallet functionality may return" + " unexpected errors" + ), + ) self.nodes[1].createwallet( - wallet_name='wmulti_priv2', - blank=True, - descriptors=True) - wmulti_priv2 = self.nodes[1].get_wallet_rpc('wmulti_priv2') - res = wmulti_priv2.importdescriptors([ - { - "desc": descsum_create("sh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))"), - "active": True, - "range": 1000, - "next_index": 0, - "timestamp": "now" - }, - { - "desc": descsum_create("sh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))"), - "active": True, - "internal": True, - "range": 1000, - "next_index": 0, - "timestamp": "now" - }]) - assert_equal(res[0]['success'], True) + wallet_name="wmulti_priv2", blank=True, descriptors=True + ) + wmulti_priv2 = self.nodes[1].get_wallet_rpc("wmulti_priv2") + res = wmulti_priv2.importdescriptors( + [ + { + "desc": descsum_create( + "sh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))" + ), + "active": True, + "range": 1000, + "next_index": 0, + "timestamp": "now", + }, + { + "desc": descsum_create( + "sh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))" + ), + "active": True, + "internal": True, + "range": 1000, + "next_index": 0, + "timestamp": "now", + }, + ] + ) + assert_equal(res[0]["success"], True) assert_equal( - res[0]['warnings'][0], - 'Not all private keys provided. Some wallet functionality may return unexpected errors') - assert_equal(res[1]['success'], True) + res[0]["warnings"][0], + ( + "Not all private keys provided. Some wallet functionality may return" + " unexpected errors" + ), + ) + assert_equal(res[1]["success"], True) assert_equal( - res[1]['warnings'][0], - 'Not all private keys provided. Some wallet functionality may return unexpected errors') + res[1]["warnings"][0], + ( + "Not all private keys provided. Some wallet functionality may return" + " unexpected errors" + ), + ) rawtx = self.nodes[1].createrawtransaction( - [{'txid': txid, 'vout': vout}], {w0.getnewaddress(): 9999000}) + [{"txid": txid, "vout": vout}], {w0.getnewaddress(): 9999000} + ) tx_signed_1 = wmulti_priv1.signrawtransactionwithwallet(rawtx) - assert_equal(tx_signed_1['complete'], False) - tx_signed_2 = wmulti_priv2.signrawtransactionwithwallet( - tx_signed_1['hex']) - assert_equal(tx_signed_2['complete'], True) - self.nodes[1].sendrawtransaction(tx_signed_2['hex']) + assert_equal(tx_signed_1["complete"], False) + tx_signed_2 = wmulti_priv2.signrawtransactionwithwallet(tx_signed_1["hex"]) + assert_equal(tx_signed_2["complete"], True) + self.nodes[1].sendrawtransaction(tx_signed_2["hex"]) self.log.info("Combo descriptors cannot be active") - self.test_importdesc({"desc": descsum_create("combo(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"), - "active": True, - "range": 1, - "timestamp": "now"}, - success=False, - error_code=-4, - error_message="Combo descriptors cannot be set to active") + self.test_importdesc( + { + "desc": descsum_create( + "combo(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)" + ), + "active": True, + "range": 1, + "timestamp": "now", + }, + success=False, + error_code=-4, + error_message="Combo descriptors cannot be set to active", + ) self.log.info("Descriptors with no type cannot be active") - self.test_importdesc({"desc": descsum_create("pk(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"), - "active": True, - "range": 1, - "timestamp": "now"}, - success=True, - warnings=["Unknown output type, cannot set descriptor to active."]) + self.test_importdesc( + { + "desc": descsum_create( + "pk(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)" + ), + "active": True, + "range": 1, + "timestamp": "now", + }, + success=True, + warnings=["Unknown output type, cannot set descriptor to active."], + ) -if __name__ == '__main__': +if __name__ == "__main__": ImportDescriptorsTest().main() diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -37,493 +37,707 @@ def setup_network(self, split=False): self.setup_nodes() - def test_importmulti(self, req, success, error_code=None, - error_message=None, warnings=None): + def test_importmulti( + self, req, success, error_code=None, error_message=None, warnings=None + ): """Run importmulti and assert success""" if warnings is None: warnings = [] result = self.nodes[1].importmulti([req]) observed_warnings = [] - if 'warnings' in result[0]: - observed_warnings = result[0]['warnings'] - assert_equal( - "\n".join( - sorted(warnings)), "\n".join( - sorted(observed_warnings))) - assert_equal(result[0]['success'], success) + if "warnings" in result[0]: + observed_warnings = result[0]["warnings"] + assert_equal("\n".join(sorted(warnings)), "\n".join(sorted(observed_warnings))) + assert_equal(result[0]["success"], success) if error_code is not None: - assert_equal(result[0]['error']['code'], error_code) - assert_equal(result[0]['error']['message'], error_message) + assert_equal(result[0]["error"]["code"], error_code) + assert_equal(result[0]["error"]["message"], error_message) def run_test(self): self.log.info("Mining blocks...") self.generate(self.nodes[0], 1, sync_fun=self.no_op) self.generate(self.nodes[1], 1, sync_fun=self.no_op) - timestamp = self.nodes[1].getblock( - self.nodes[1].getbestblockhash())['mediantime'] + timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())[ + "mediantime" + ] # Sync the timestamp to the wallet, so that importmulti works self.nodes[1].syncwithvalidationinterfacequeue() - node0_address1 = self.nodes[0].getaddressinfo( - self.nodes[0].getnewaddress()) + node0_address1 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress()) # Check only one address - assert_equal(node0_address1['ismine'], True) + assert_equal(node0_address1["ismine"], True) # Node 1 sync test assert_equal(self.nodes[1].getblockcount(), 1) # Address Test - before import - address_info = self.nodes[1].getaddressinfo(node0_address1['address']) - assert_equal(address_info['iswatchonly'], False) - assert_equal(address_info['ismine'], False) + address_info = self.nodes[1].getaddressinfo(node0_address1["address"]) + assert_equal(address_info["iswatchonly"], False) + assert_equal(address_info["ismine"], False) # RPC importmulti ----------------------------------------------- # Bitcoin Address (implicit non-internal) self.log.info("Should import an address") key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, - "timestamp": "now"}, - success=True) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=True, - ismine=False, - timestamp=timestamp, - ischange=False) + self.test_importmulti( + {"scriptPubKey": {"address": key.p2pkh_addr}, "timestamp": "now"}, + success=True, + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + timestamp=timestamp, + ischange=False, + ) watchonly_address = key.p2pkh_addr watchonly_timestamp = timestamp self.log.info("Should not import an invalid address") - self.test_importmulti({"scriptPubKey": {"address": "not valid address"}, - "timestamp": "now"}, - success=False, - error_code=-5, - error_message='Invalid address \"not valid address\"') + self.test_importmulti( + {"scriptPubKey": {"address": "not valid address"}, "timestamp": "now"}, + success=False, + error_code=-5, + error_message='Invalid address "not valid address"', + ) # ScriptPubKey + internal self.log.info("Should import a scriptPubKey with internal flag") key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": key.p2pkh_script, - "timestamp": "now", - "internal": True}, - success=True) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=True, - ismine=False, - timestamp=timestamp, - ischange=True) + self.test_importmulti( + {"scriptPubKey": key.p2pkh_script, "timestamp": "now", "internal": True}, + success=True, + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + timestamp=timestamp, + ischange=True, + ) # ScriptPubKey + internal + label - self.log.info( - "Should not allow a label to be specified when internal is true") + self.log.info("Should not allow a label to be specified when internal is true") key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": key.p2pkh_script, - "timestamp": "now", - "internal": True, - "label": "Unsuccessful labelling for internal addresses"}, - success=False, - error_code=-8, - error_message='Internal addresses should not have a label') + self.test_importmulti( + { + "scriptPubKey": key.p2pkh_script, + "timestamp": "now", + "internal": True, + "label": "Unsuccessful labelling for internal addresses", + }, + success=False, + error_code=-8, + error_message="Internal addresses should not have a label", + ) # Nonstandard scriptPubKey + !internal self.log.info( - "Should not import a nonstandard scriptPubKey without internal flag") + "Should not import a nonstandard scriptPubKey without internal flag" + ) nonstandardScriptPubKey = key.p2pkh_script + CScript([OP_NOP]).hex() key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": nonstandardScriptPubKey, - "timestamp": "now"}, - success=False, - error_code=-8, - error_message='Internal must be set to true for nonstandard scriptPubKey imports.') - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=False, - ismine=False, - timestamp=None) + self.test_importmulti( + {"scriptPubKey": nonstandardScriptPubKey, "timestamp": "now"}, + success=False, + error_code=-8, + error_message=( + "Internal must be set to true for nonstandard scriptPubKey imports." + ), + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=False, + timestamp=None, + ) # Address + Public key + !Internal(explicit) self.log.info("Should import an address with public key") key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, - "timestamp": "now", - "pubkeys": [key.pubkey], - "internal": False}, - success=True, - warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=True, - ismine=False, - timestamp=timestamp) + self.test_importmulti( + { + "scriptPubKey": {"address": key.p2pkh_addr}, + "timestamp": "now", + "pubkeys": [key.pubkey], + "internal": False, + }, + success=True, + warnings=[ + "Some private keys are missing, outputs will be considered watchonly." + " If this is intentional, specify the watchonly flag." + ], + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + timestamp=timestamp, + ) # ScriptPubKey + Public key + internal - self.log.info( - "Should import a scriptPubKey with internal and with public key") + self.log.info("Should import a scriptPubKey with internal and with public key") key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": key.p2pkh_script, - "timestamp": "now", - "pubkeys": [key.pubkey], - "internal": True}, - success=True, - warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=True, - ismine=False, - timestamp=timestamp) + self.test_importmulti( + { + "scriptPubKey": key.p2pkh_script, + "timestamp": "now", + "pubkeys": [key.pubkey], + "internal": True, + }, + success=True, + warnings=[ + "Some private keys are missing, outputs will be considered watchonly." + " If this is intentional, specify the watchonly flag." + ], + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + timestamp=timestamp, + ) # Nonstandard scriptPubKey + Public key + !internal self.log.info( - "Should not import a nonstandard scriptPubKey without internal and with public key") + "Should not import a nonstandard scriptPubKey without internal and with" + " public key" + ) key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": nonstandardScriptPubKey, - "timestamp": "now", - "pubkeys": [key.pubkey]}, - success=False, - error_code=-8, - error_message='Internal must be set to true for nonstandard scriptPubKey imports.') - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=False, - ismine=False, - timestamp=None) + self.test_importmulti( + { + "scriptPubKey": nonstandardScriptPubKey, + "timestamp": "now", + "pubkeys": [key.pubkey], + }, + success=False, + error_code=-8, + error_message=( + "Internal must be set to true for nonstandard scriptPubKey imports." + ), + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=False, + timestamp=None, + ) # Address + Private key + !watchonly self.log.info("Should import an address with private key") key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, - "timestamp": "now", - "keys": [key.privkey]}, - success=True) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=False, - ismine=True, - timestamp=timestamp) + self.test_importmulti( + { + "scriptPubKey": {"address": key.p2pkh_addr}, + "timestamp": "now", + "keys": [key.privkey], + }, + success=True, + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=True, + timestamp=timestamp, + ) self.log.info( - "Should not import an address with private key if is already imported") - self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, - "timestamp": "now", - "keys": [key.privkey]}, - success=False, - error_code=-4, - error_message=f"The wallet already contains the private key for this address or script (\"{key.p2pkh_script}\")") + "Should not import an address with private key if is already imported" + ) + self.test_importmulti( + { + "scriptPubKey": {"address": key.p2pkh_addr}, + "timestamp": "now", + "keys": [key.privkey], + }, + success=False, + error_code=-4, + error_message=( + "The wallet already contains the private key for this address or" + f' script ("{key.p2pkh_script}")' + ), + ) # Address + Private key + watchonly - self.log.info( - "Should import an address with private key and with watchonly") + self.log.info("Should import an address with private key and with watchonly") key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, - "timestamp": "now", - "keys": [key.privkey], - "watchonly": True}, - success=True, - warnings=["All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag."]) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=False, - ismine=True, - timestamp=timestamp) + self.test_importmulti( + { + "scriptPubKey": {"address": key.p2pkh_addr}, + "timestamp": "now", + "keys": [key.privkey], + "watchonly": True, + }, + success=True, + warnings=[ + "All private keys are provided, outputs will be considered spendable." + " If this is intentional, do not specify the watchonly flag." + ], + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=True, + timestamp=timestamp, + ) # ScriptPubKey + Private key + internal - self.log.info( - "Should import a scriptPubKey with internal and with private key") + self.log.info("Should import a scriptPubKey with internal and with private key") key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": key.p2pkh_script, - "timestamp": "now", - "keys": [key.privkey], - "internal": True}, - success=True) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=False, - ismine=True, - timestamp=timestamp) + self.test_importmulti( + { + "scriptPubKey": key.p2pkh_script, + "timestamp": "now", + "keys": [key.privkey], + "internal": True, + }, + success=True, + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=True, + timestamp=timestamp, + ) # Nonstandard scriptPubKey + Private key + !internal self.log.info( - "Should not import a nonstandard scriptPubKey without internal and with private key") + "Should not import a nonstandard scriptPubKey without internal and with" + " private key" + ) key = get_key(self.nodes[0]) - self.test_importmulti({"scriptPubKey": nonstandardScriptPubKey, - "timestamp": "now", - "keys": [key.privkey]}, - success=False, - error_code=-8, - error_message='Internal must be set to true for nonstandard scriptPubKey imports.') - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=False, - ismine=False, - timestamp=None) + self.test_importmulti( + { + "scriptPubKey": nonstandardScriptPubKey, + "timestamp": "now", + "keys": [key.privkey], + }, + success=False, + error_code=-8, + error_message=( + "Internal must be set to true for nonstandard scriptPubKey imports." + ), + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=False, + ismine=False, + timestamp=None, + ) # P2SH address multisig = get_multisig(self.nodes[0]) self.generate(self.nodes[1], 100, sync_fun=self.no_op) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.generate(self.nodes[1], 1, sync_fun=self.no_op) - timestamp = self.nodes[1].getblock( - self.nodes[1].getbestblockhash())['mediantime'] + timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())[ + "mediantime" + ] self.nodes[1].syncwithvalidationinterfacequeue() self.log.info("Should import a p2sh") - self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr}, - "timestamp": "now"}, - success=True) - test_address(self.nodes[1], - multisig.p2sh_addr, - isscript=True, - iswatchonly=True, - timestamp=timestamp) - p2shunspent = self.nodes[1].listunspent( - 0, 999999, [multisig.p2sh_addr])[0] - assert_equal(p2shunspent['spendable'], False) - assert_equal(p2shunspent['solvable'], False) + self.test_importmulti( + {"scriptPubKey": {"address": multisig.p2sh_addr}, "timestamp": "now"}, + success=True, + ) + test_address( + self.nodes[1], + multisig.p2sh_addr, + isscript=True, + iswatchonly=True, + timestamp=timestamp, + ) + p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0] + assert_equal(p2shunspent["spendable"], False) + assert_equal(p2shunspent["solvable"], False) # P2SH + Redeem script multisig = get_multisig(self.nodes[0]) self.generate(self.nodes[1], 100, sync_fun=self.no_op) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.generate(self.nodes[1], 1, sync_fun=self.no_op) - timestamp = self.nodes[1].getblock( - self.nodes[1].getbestblockhash())['mediantime'] + timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())[ + "mediantime" + ] self.nodes[1].syncwithvalidationinterfacequeue() self.log.info("Should import a p2sh with respective redeem script") - self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr}, - "timestamp": "now", - "redeemscript": multisig.redeem_script}, - success=True, - warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) + self.test_importmulti( + { + "scriptPubKey": {"address": multisig.p2sh_addr}, + "timestamp": "now", + "redeemscript": multisig.redeem_script, + }, + success=True, + warnings=[ + "Some private keys are missing, outputs will be considered watchonly." + " If this is intentional, specify the watchonly flag." + ], + ) test_address( self.nodes[1], multisig.p2sh_addr, timestamp=timestamp, iswatchonly=True, ismine=False, - solvable=True) + solvable=True, + ) - p2shunspent = self.nodes[1].listunspent( - 0, 999999, [multisig.p2sh_addr])[0] - assert_equal(p2shunspent['spendable'], False) - assert_equal(p2shunspent['solvable'], True) + p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0] + assert_equal(p2shunspent["spendable"], False) + assert_equal(p2shunspent["solvable"], True) # P2SH + Redeem script + Private Keys + !Watchonly multisig = get_multisig(self.nodes[0]) self.generate(self.nodes[1], 100, sync_fun=self.no_op) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.generate(self.nodes[1], 1, sync_fun=self.no_op) - timestamp = self.nodes[1].getblock( - self.nodes[1].getbestblockhash())['mediantime'] + timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())[ + "mediantime" + ] self.nodes[1].syncwithvalidationinterfacequeue() self.log.info( - "Should import a p2sh with respective redeem script and private keys") - self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr}, - "timestamp": "now", - "redeemscript": multisig.redeem_script, - "keys": multisig.privkeys[0:2]}, - success=True, - warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - test_address(self.nodes[1], - multisig.p2sh_addr, - timestamp=timestamp, - ismine=False, - iswatchonly=True, - solvable=True) - - p2shunspent = self.nodes[1].listunspent( - 0, 999999, [multisig.p2sh_addr])[0] - assert_equal(p2shunspent['spendable'], False) - assert_equal(p2shunspent['solvable'], True) + "Should import a p2sh with respective redeem script and private keys" + ) + self.test_importmulti( + { + "scriptPubKey": {"address": multisig.p2sh_addr}, + "timestamp": "now", + "redeemscript": multisig.redeem_script, + "keys": multisig.privkeys[0:2], + }, + success=True, + warnings=[ + "Some private keys are missing, outputs will be considered watchonly." + " If this is intentional, specify the watchonly flag." + ], + ) + test_address( + self.nodes[1], + multisig.p2sh_addr, + timestamp=timestamp, + ismine=False, + iswatchonly=True, + solvable=True, + ) + + p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0] + assert_equal(p2shunspent["spendable"], False) + assert_equal(p2shunspent["solvable"], True) # P2SH + Redeem script + Private Keys + Watchonly multisig = get_multisig(self.nodes[0]) self.generate(self.nodes[1], 100, sync_fun=self.no_op) self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00) self.generate(self.nodes[1], 1, sync_fun=self.no_op) - timestamp = self.nodes[1].getblock( - self.nodes[1].getbestblockhash())['mediantime'] + timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())[ + "mediantime" + ] self.nodes[1].syncwithvalidationinterfacequeue() self.log.info( - "Should import a p2sh with respective redeem script and private keys") - self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr}, - "timestamp": "now", - "redeemscript": multisig.redeem_script, - "keys": multisig.privkeys[0:2], - "watchonly": True}, - success=True) - test_address(self.nodes[1], - multisig.p2sh_addr, - iswatchonly=True, - ismine=False, - solvable=True, - timestamp=timestamp) + "Should import a p2sh with respective redeem script and private keys" + ) + self.test_importmulti( + { + "scriptPubKey": {"address": multisig.p2sh_addr}, + "timestamp": "now", + "redeemscript": multisig.redeem_script, + "keys": multisig.privkeys[0:2], + "watchonly": True, + }, + success=True, + ) + test_address( + self.nodes[1], + multisig.p2sh_addr, + iswatchonly=True, + ismine=False, + solvable=True, + timestamp=timestamp, + ) # Address + Public key + !Internal + Wrong pubkey self.log.info( - "Should not import an address with the wrong public key as non-solvable") + "Should not import an address with the wrong public key as non-solvable" + ) key = get_key(self.nodes[0]) wrong_key = get_key(self.nodes[0]).pubkey - self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, - "timestamp": "now", - "pubkeys": [wrong_key]}, - success=True, - warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=True, - ismine=False, - solvable=False, - timestamp=timestamp) + self.test_importmulti( + { + "scriptPubKey": {"address": key.p2pkh_addr}, + "timestamp": "now", + "pubkeys": [wrong_key], + }, + success=True, + warnings=[ + ( + "Importing as non-solvable: some required keys are missing. If this" + " is intentional, don't provide any keys, pubkeys or redeemscript." + ), + ( + "Some private keys are missing, outputs will be considered" + " watchonly. If this is intentional, specify the watchonly flag." + ), + ], + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + solvable=False, + timestamp=timestamp, + ) # ScriptPubKey + Public key + internal + Wrong pubkey self.log.info( - "Should import a scriptPubKey with internal and with a wrong public key as non-solvable") + "Should import a scriptPubKey with internal and with a wrong public key as" + " non-solvable" + ) key = get_key(self.nodes[0]) wrong_key = get_key(self.nodes[0]).pubkey - self.test_importmulti({"scriptPubKey": key.p2pkh_script, - "timestamp": "now", - "pubkeys": [wrong_key], - "internal": True}, - success=True, - warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=True, - ismine=False, - solvable=False, - timestamp=timestamp) + self.test_importmulti( + { + "scriptPubKey": key.p2pkh_script, + "timestamp": "now", + "pubkeys": [wrong_key], + "internal": True, + }, + success=True, + warnings=[ + ( + "Importing as non-solvable: some required keys are missing. If this" + " is intentional, don't provide any keys, pubkeys or redeemscript." + ), + ( + "Some private keys are missing, outputs will be considered" + " watchonly. If this is intentional, specify the watchonly flag." + ), + ], + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + solvable=False, + timestamp=timestamp, + ) # Address + Private key + !watchonly + Wrong private key self.log.info( - "Should import an address with a wrong private key as non-solvable") + "Should import an address with a wrong private key as non-solvable" + ) key = get_key(self.nodes[0]) wrong_privkey = get_key(self.nodes[0]).privkey - self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr}, - "timestamp": "now", - "keys": [wrong_privkey]}, - success=True, - warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=True, - ismine=False, - solvable=False, - timestamp=timestamp) + self.test_importmulti( + { + "scriptPubKey": {"address": key.p2pkh_addr}, + "timestamp": "now", + "keys": [wrong_privkey], + }, + success=True, + warnings=[ + ( + "Importing as non-solvable: some required keys are missing. If this" + " is intentional, don't provide any keys, pubkeys or redeemscript." + ), + ( + "Some private keys are missing, outputs will be considered" + " watchonly. If this is intentional, specify the watchonly flag." + ), + ], + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + solvable=False, + timestamp=timestamp, + ) # ScriptPubKey + Private key + internal + Wrong private key self.log.info( - "Should import a scriptPubKey with internal and with a wrong private key as non-solvable") + "Should import a scriptPubKey with internal and with a wrong private key as" + " non-solvable" + ) key = get_key(self.nodes[0]) wrong_privkey = get_key(self.nodes[0]).privkey - self.test_importmulti({"scriptPubKey": key.p2pkh_script, - "timestamp": "now", - "keys": [wrong_privkey], - "internal": True}, - success=True, - warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - test_address(self.nodes[1], - key.p2pkh_addr, - iswatchonly=True, - ismine=False, - solvable=False, - timestamp=timestamp) + self.test_importmulti( + { + "scriptPubKey": key.p2pkh_script, + "timestamp": "now", + "keys": [wrong_privkey], + "internal": True, + }, + success=True, + warnings=[ + ( + "Importing as non-solvable: some required keys are missing. If this" + " is intentional, don't provide any keys, pubkeys or redeemscript." + ), + ( + "Some private keys are missing, outputs will be considered" + " watchonly. If this is intentional, specify the watchonly flag." + ), + ], + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + iswatchonly=True, + ismine=False, + solvable=False, + timestamp=timestamp, + ) # Importing existing watch only address with new timestamp should # replace saved timestamp. assert_greater_than(timestamp, watchonly_timestamp) self.log.info("Should replace previously saved watch only timestamp.") - self.test_importmulti({"scriptPubKey": {"address": watchonly_address}, - "timestamp": "now"}, - success=True) - test_address(self.nodes[1], - watchonly_address, - iswatchonly=True, - ismine=False, - timestamp=timestamp) + self.test_importmulti( + {"scriptPubKey": {"address": watchonly_address}, "timestamp": "now"}, + success=True, + ) + test_address( + self.nodes[1], + watchonly_address, + iswatchonly=True, + ismine=False, + timestamp=timestamp, + ) watchonly_timestamp = timestamp # restart nodes to check for proper serialization/deserialization of # watch only address self.stop_nodes() self.start_nodes() - test_address(self.nodes[1], - watchonly_address, - iswatchonly=True, - ismine=False, - timestamp=watchonly_timestamp) + test_address( + self.nodes[1], + watchonly_address, + iswatchonly=True, + ismine=False, + timestamp=watchonly_timestamp, + ) # Bad or missing timestamps self.log.info("Should throw on invalid or missing timestamp values") - assert_raises_rpc_error(-3, 'Missing required timestamp field for key', - self.nodes[1].importmulti, [{"scriptPubKey": key.p2pkh_script}]) - assert_raises_rpc_error(-3, 'Expected number or "now" timestamp value for key. got type string', - self.nodes[1].importmulti, [{ - "scriptPubKey": key.p2pkh_script, - "timestamp": "" - }]) + assert_raises_rpc_error( + -3, + "Missing required timestamp field for key", + self.nodes[1].importmulti, + [{"scriptPubKey": key.p2pkh_script}], + ) + assert_raises_rpc_error( + -3, + 'Expected number or "now" timestamp value for key. got type string', + self.nodes[1].importmulti, + [{"scriptPubKey": key.p2pkh_script, "timestamp": ""}], + ) # Test that importing of a P2PKH address via descriptor without # checksum fails key = get_key(self.nodes[0]) self.log.info( - "Should fail to import a p2pkh address from descriptor with no checksum") - self.test_importmulti({"desc": f"pkh({key.pubkey})", - "timestamp": "now", - "label": "Descriptor import test"}, - success=False, - error_code=-5, - error_message='Missing checksum') + "Should fail to import a p2pkh address from descriptor with no checksum" + ) + self.test_importmulti( + { + "desc": f"pkh({key.pubkey})", + "timestamp": "now", + "label": "Descriptor import test", + }, + success=False, + error_code=-5, + error_message="Missing checksum", + ) # Test ranged descriptor fails if range is not specified xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg" # hdkeypath=m/0'/0'/0' and 1' addresses = [ "ecregtest:prvn9ycvgr5atuyh49sua3mapskh2mnnzg7t9yp6dt", - "ecregtest:pp3n087yx0njv2e5wcvltahfxqst7l66rutz8ceeat"] + "ecregtest:pp3n087yx0njv2e5wcvltahfxqst7l66rutz8ceeat", + ] # pkh subscripts corresponding to the above addresses addresses += [ "ecregtest:qqdkxd2xnzftq2p8wr3sqqyw8lntap7tncs546s6pr", "ecregtest:qpyryy83jfaec5u0gpzldk6teadsuq8zlyqh5l30uq", ] desc = f"sh(pkh({xpriv}/0'/0'/*'))" - self.log.info( - "Ranged descriptor import should fail without a specified range") - self.test_importmulti({"desc": descsum_create(desc), - "timestamp": "now"}, - success=False, - error_code=-8, - error_message='Descriptor is ranged, please specify the range') + self.log.info("Ranged descriptor import should fail without a specified range") + self.test_importmulti( + {"desc": descsum_create(desc), "timestamp": "now"}, + success=False, + error_code=-8, + error_message="Descriptor is ranged, please specify the range", + ) # Test importing of a ranged descriptor with xpriv self.log.info( - "Should import the ranged descriptor with specified range as solvable") - self.test_importmulti({"desc": descsum_create(desc), - "timestamp": "now", - "range": 1}, - success=True) + "Should import the ranged descriptor with specified range as solvable" + ) + self.test_importmulti( + {"desc": descsum_create(desc), "timestamp": "now", "range": 1}, success=True + ) for address in addresses: test_address(self.nodes[1], address, solvable=True, ismine=True) - self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": -1}, - success=False, error_code=-8, error_message='End of range is too high') + self.test_importmulti( + {"desc": descsum_create(desc), "timestamp": "now", "range": -1}, + success=False, + error_code=-8, + error_message="End of range is too high", + ) - self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]}, - success=False, error_code=-8, error_message='Range should be greater or equal than 0') + self.test_importmulti( + {"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]}, + success=False, + error_code=-8, + error_message="Range should be greater or equal than 0", + ) - self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]}, - success=False, error_code=-8, error_message='End of range is too high') + self.test_importmulti( + { + "desc": descsum_create(desc), + "timestamp": "now", + "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)], + }, + success=False, + error_code=-8, + error_message="End of range is too high", + ) - self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]}, - success=False, error_code=-8, error_message='Range specified as [begin,end] must not have begin after end') + self.test_importmulti( + {"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]}, + success=False, + error_code=-8, + error_message=( + "Range specified as [begin,end] must not have begin after end" + ), + ) - self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]}, - success=False, error_code=-8, error_message='Range is too large') + self.test_importmulti( + {"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]}, + success=False, + error_code=-8, + error_message="Range is too large", + ) # Test importing a descriptor containing a WIF private key wif_priv = "cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh" @@ -532,15 +746,11 @@ # address instead, which returns the same privkey. address = "ecregtest:qzh6rch6st3wjvp0h2ud87gn7xnxvf6h8yrk8gcg8t" desc = f"sh(pkh({wif_priv}))" - self.log.info( - "Should import a descriptor with a WIF private key as spendable") - self.test_importmulti({"desc": descsum_create(desc), - "timestamp": "now"}, - success=True) - test_address(self.nodes[1], - address, - solvable=True, - ismine=True) + self.log.info("Should import a descriptor with a WIF private key as spendable") + self.test_importmulti( + {"desc": descsum_create(desc), "timestamp": "now"}, success=True + ) + test_address(self.nodes[1], address, solvable=True, ismine=True) # dump the private key to ensure it matches what was imported privkey = self.nodes[1].dumpprivkey(address) @@ -550,143 +760,176 @@ key = get_key(self.nodes[0]) p2pkh_label = "P2PKH descriptor import" self.log.info("Should import a p2pkh address from descriptor") - self.test_importmulti({"desc": descsum_create(f"pkh({key.pubkey})"), - "timestamp": "now", - "label": p2pkh_label}, - success=True, - warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) - test_address(self.nodes[1], - key.p2pkh_addr, - solvable=True, - ismine=False, - labels=[p2pkh_label]) + self.test_importmulti( + { + "desc": descsum_create(f"pkh({key.pubkey})"), + "timestamp": "now", + "label": p2pkh_label, + }, + success=True, + warnings=[ + "Some private keys are missing, outputs will be considered watchonly." + " If this is intentional, specify the watchonly flag." + ], + ) + test_address( + self.nodes[1], + key.p2pkh_addr, + solvable=True, + ismine=False, + labels=[p2pkh_label], + ) # Test import fails if both desc and scriptPubKey are provided key = get_key(self.nodes[0]) - self.log.info( - "Import should fail if both scriptPubKey and desc are provided") - self.test_importmulti({"desc": descsum_create(f"pkh({key.pubkey})"), - "scriptPubKey": {"address": key.p2pkh_addr}, - "timestamp": "now"}, - success=False, - error_code=-8, - error_message='Both a descriptor and a scriptPubKey should not be provided.') + self.log.info("Import should fail if both scriptPubKey and desc are provided") + self.test_importmulti( + { + "desc": descsum_create(f"pkh({key.pubkey})"), + "scriptPubKey": {"address": key.p2pkh_addr}, + "timestamp": "now", + }, + success=False, + error_code=-8, + error_message=( + "Both a descriptor and a scriptPubKey should not be provided." + ), + ) # Test import fails if neither desc nor scriptPubKey are present key = get_key(self.nodes[0]) self.log.info( - "Import should fail if neither a descriptor nor a scriptPubKey are provided") - self.test_importmulti({"timestamp": "now"}, - success=False, - error_code=-8, - error_message='Either a descriptor or scriptPubKey must be provided.') + "Import should fail if neither a descriptor nor a scriptPubKey are provided" + ) + self.test_importmulti( + {"timestamp": "now"}, + success=False, + error_code=-8, + error_message="Either a descriptor or scriptPubKey must be provided.", + ) # Test importing of a multisig via descriptor key1 = get_key(self.nodes[0]) key2 = get_key(self.nodes[0]) self.log.info("Should import a 1-of-2 bare multisig from descriptor") - self.test_importmulti({"desc": descsum_create(f"multi(1,{key1.pubkey},{key2.pubkey})"), - "timestamp": "now"}, - success=True, - warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) + self.test_importmulti( + { + "desc": descsum_create(f"multi(1,{key1.pubkey},{key2.pubkey})"), + "timestamp": "now", + }, + success=True, + warnings=[ + "Some private keys are missing, outputs will be considered watchonly." + " If this is intentional, specify the watchonly flag." + ], + ) self.log.info( - "Should not treat individual keys from the imported bare multisig as watchonly") - test_address(self.nodes[1], - key1.p2pkh_addr, - ismine=False, - iswatchonly=False) + "Should not treat individual keys from the imported bare multisig as" + " watchonly" + ) + test_address(self.nodes[1], key1.p2pkh_addr, ismine=False, iswatchonly=False) # Import pubkeys with key origin info self.log.info( - "Addresses should have hd keypath and master key id after import with key origin") + "Addresses should have hd keypath and master key id after import with key" + " origin" + ) pub_addr = self.nodes[1].getnewaddress() pub_addr = self.nodes[1].getnewaddress() info = self.nodes[1].getaddressinfo(pub_addr) - pub = info['pubkey'] - pub_keypath = info['hdkeypath'] - pub_fpr = info['hdmasterfingerprint'] + pub = info["pubkey"] + pub_keypath = info["hdkeypath"] + pub_fpr = info["hdmasterfingerprint"] result = self.nodes[0].importmulti( - [{ - 'desc': descsum_create(f"pkh([{pub_fpr}{pub_keypath[1:]}]{pub})"), - "timestamp": "now", - }] + [ + { + "desc": descsum_create(f"pkh([{pub_fpr}{pub_keypath[1:]}]{pub})"), + "timestamp": "now", + } + ] ) - assert result[0]['success'] + assert result[0]["success"] pub_import_info = self.nodes[0].getaddressinfo(pub_addr) - assert_equal(pub_import_info['hdmasterfingerprint'], pub_fpr) - assert_equal(pub_import_info['pubkey'], pub) - assert_equal(pub_import_info['hdkeypath'], pub_keypath) + assert_equal(pub_import_info["hdmasterfingerprint"], pub_fpr) + assert_equal(pub_import_info["pubkey"], pub) + assert_equal(pub_import_info["hdkeypath"], pub_keypath) # Import privkeys with key origin info priv_addr = self.nodes[1].getnewaddress() info = self.nodes[1].getaddressinfo(priv_addr) priv = self.nodes[1].dumpprivkey(priv_addr) - priv_keypath = info['hdkeypath'] - priv_fpr = info['hdmasterfingerprint'] + priv_keypath = info["hdkeypath"] + priv_fpr = info["hdmasterfingerprint"] result = self.nodes[0].importmulti( - [{ - 'desc': descsum_create(f"pkh([{priv_fpr}{priv_keypath[1:]}]{priv})"), - "timestamp": "now", - }] + [ + { + "desc": descsum_create( + f"pkh([{priv_fpr}{priv_keypath[1:]}]{priv})" + ), + "timestamp": "now", + } + ] ) - assert result[0]['success'] + assert result[0]["success"] priv_import_info = self.nodes[0].getaddressinfo(priv_addr) - assert_equal(priv_import_info['hdmasterfingerprint'], priv_fpr) - assert_equal(priv_import_info['hdkeypath'], priv_keypath) + assert_equal(priv_import_info["hdmasterfingerprint"], priv_fpr) + assert_equal(priv_import_info["hdkeypath"], priv_keypath) # Make sure the key origin info are still there after a restart self.stop_nodes() self.start_nodes() import_info = self.nodes[0].getaddressinfo(pub_addr) - assert_equal(import_info['hdmasterfingerprint'], pub_fpr) - assert_equal(import_info['hdkeypath'], pub_keypath) + assert_equal(import_info["hdmasterfingerprint"], pub_fpr) + assert_equal(import_info["hdkeypath"], pub_keypath) import_info = self.nodes[0].getaddressinfo(priv_addr) - assert_equal(import_info['hdmasterfingerprint'], priv_fpr) - assert_equal(import_info['hdkeypath'], priv_keypath) + assert_equal(import_info["hdmasterfingerprint"], priv_fpr) + assert_equal(import_info["hdkeypath"], priv_keypath) # Check legacy import does not import key origin info self.log.info("Legacy imports don't have key origin info") pub_addr = self.nodes[1].getnewaddress() info = self.nodes[1].getaddressinfo(pub_addr) - pub = info['pubkey'] + pub = info["pubkey"] result = self.nodes[0].importmulti( - [{ - 'scriptPubKey': {'address': pub_addr}, - 'pubkeys': [pub], - "timestamp": "now", - }] + [ + { + "scriptPubKey": {"address": pub_addr}, + "pubkeys": [pub], + "timestamp": "now", + } + ] ) - assert result[0]['success'] + assert result[0]["success"] pub_import_info = self.nodes[0].getaddressinfo(pub_addr) - assert_equal(pub_import_info['pubkey'], pub) - assert 'hdmasterfingerprint' not in pub_import_info - assert 'hdkeypath' not in pub_import_info + assert_equal(pub_import_info["pubkey"], pub) + assert "hdmasterfingerprint" not in pub_import_info + assert "hdkeypath" not in pub_import_info # Import some public keys to the keypool of a no privkey wallet self.log.info("Adding pubkey to keypool of disableprivkey wallet") - self.nodes[1].createwallet( - wallet_name="noprivkeys", - disable_private_keys=True) + self.nodes[1].createwallet(wallet_name="noprivkeys", disable_private_keys=True) wrpc = self.nodes[1].get_wallet_rpc("noprivkeys") addr1 = self.nodes[0].getnewaddress() addr2 = self.nodes[0].getnewaddress() - pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey'] - pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey'] + pub1 = self.nodes[0].getaddressinfo(addr1)["pubkey"] + pub2 = self.nodes[0].getaddressinfo(addr2)["pubkey"] result = wrpc.importmulti( - [{ - 'desc': descsum_create(f"pkh({pub1})"), - 'keypool': True, - "timestamp": "now", - }, + [ { - 'desc': descsum_create(f"pkh({pub2})"), - 'keypool': True, - "timestamp": "now", - }] + "desc": descsum_create(f"pkh({pub1})"), + "keypool": True, + "timestamp": "now", + }, + { + "desc": descsum_create(f"pkh({pub2})"), + "keypool": True, + "timestamp": "now", + }, + ] ) - assert result[0]['success'] - assert result[1]['success'] + assert result[0]["success"] + assert result[1]["success"] assert_equal(wrpc.getwalletinfo()["keypoolsize"], 2) newaddr1 = wrpc.getnewaddress() assert_equal(addr1, newaddr1) @@ -695,28 +938,29 @@ # Import some public keys to the internal keypool of a no privkey # wallet - self.log.info( - "Adding pubkey to internal keypool of disableprivkey wallet") + self.log.info("Adding pubkey to internal keypool of disableprivkey wallet") addr1 = self.nodes[0].getnewaddress() addr2 = self.nodes[0].getnewaddress() - pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey'] - pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey'] + pub1 = self.nodes[0].getaddressinfo(addr1)["pubkey"] + pub2 = self.nodes[0].getaddressinfo(addr2)["pubkey"] result = wrpc.importmulti( - [{ - 'desc': descsum_create(f"pkh({pub1})"), - 'keypool': True, - 'internal': True, - "timestamp": "now", - }, + [ { - 'desc': descsum_create(f"pkh({pub2})"), - 'keypool': True, - 'internal': True, - "timestamp": "now", - }] + "desc": descsum_create(f"pkh({pub1})"), + "keypool": True, + "internal": True, + "timestamp": "now", + }, + { + "desc": descsum_create(f"pkh({pub2})"), + "keypool": True, + "internal": True, + "timestamp": "now", + }, + ] ) - assert result[0]['success'] - assert result[1]['success'] + assert result[0]["success"] + assert result[1]["success"] assert_equal(wrpc.getwalletinfo()["keypoolsize_hd_internal"], 2) newaddr1 = wrpc.getrawchangeaddress() assert_equal(addr1, newaddr1) @@ -725,64 +969,74 @@ # Import a multisig and make sure the keys don't go into the keypool self.log.info( - 'Imported scripts with pubkeys shoud not have their pubkeys go into the keypool') + "Imported scripts with pubkeys shoud not have their pubkeys go into the" + " keypool" + ) addr1 = self.nodes[0].getnewaddress() addr2 = self.nodes[0].getnewaddress() - pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey'] - pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey'] + pub1 = self.nodes[0].getaddressinfo(addr1)["pubkey"] + pub2 = self.nodes[0].getaddressinfo(addr2)["pubkey"] result = wrpc.importmulti( - [{ - 'desc': descsum_create(f"sh(multi(2,{pub1},{pub2}))"), - 'keypool': True, - "timestamp": "now", - }] + [ + { + "desc": descsum_create(f"sh(multi(2,{pub1},{pub2}))"), + "keypool": True, + "timestamp": "now", + } + ] ) - assert result[0]['success'] + assert result[0]["success"] assert_equal(wrpc.getwalletinfo()["keypoolsize"], 0) # Cannot import those pubkeys to keypool of wallet with privkeys self.log.info( - "Pubkeys cannot be added to the keypool of a wallet with private keys") + "Pubkeys cannot be added to the keypool of a wallet with private keys" + ) wrpc = self.nodes[1].get_wallet_rpc(self.default_wallet_name) - assert wrpc.getwalletinfo()['private_keys_enabled'] + assert wrpc.getwalletinfo()["private_keys_enabled"] result = wrpc.importmulti( - [{ - 'desc': descsum_create(f"pkh({pub1})"), - 'keypool': True, - "timestamp": "now", - }] + [ + { + "desc": descsum_create(f"pkh({pub1})"), + "keypool": True, + "timestamp": "now", + } + ] ) - assert_equal(result[0]['error']['code'], -8) + assert_equal(result[0]["error"]["code"], -8) assert_equal( - result[0]['error']['message'], - "Keys can only be imported to the keypool when private keys are disabled") + result[0]["error"]["message"], + "Keys can only be imported to the keypool when private keys are disabled", + ) # Make sure ranged imports import keys in order - self.log.info('Key ranges should be imported in order') + self.log.info("Key ranges should be imported in order") wrpc = self.nodes[1].get_wallet_rpc("noprivkeys") assert_equal(wrpc.getwalletinfo()["keypoolsize"], 0) assert_equal(wrpc.getwalletinfo()["private_keys_enabled"], False) xpub = "tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY" addresses = [ - 'ecregtest:qp0v86h53rc92hjrlpwzpjtdlgzsxu25svv6g40fpl', # m/0'/0'/0 - 'ecregtest:qqasy0zlkdleqt4pkn8fs4ehm5gnnz6qpgdcpt90fq', # m/0'/0'/1 - 'ecregtest:qp0sp4wlhctvprqvdt2dgvqcfdjssu04xgey0l3syw', # m/0'/0'/2 - 'ecregtest:qrhn24tegn04cptfv4ldhtkduxq55zcwrycjfdj9vr', # m/0'/0'/3 - 'ecregtest:qzpqhett2uwltq803vrxv7zkqhft5vsnmcjeh50v0p', # m/0'/0'/4 + "ecregtest:qp0v86h53rc92hjrlpwzpjtdlgzsxu25svv6g40fpl", # m/0'/0'/0 + "ecregtest:qqasy0zlkdleqt4pkn8fs4ehm5gnnz6qpgdcpt90fq", # m/0'/0'/1 + "ecregtest:qp0sp4wlhctvprqvdt2dgvqcfdjssu04xgey0l3syw", # m/0'/0'/2 + "ecregtest:qrhn24tegn04cptfv4ldhtkduxq55zcwrycjfdj9vr", # m/0'/0'/3 + "ecregtest:qzpqhett2uwltq803vrxv7zkqhft5vsnmcjeh50v0p", # m/0'/0'/4 ] result = wrpc.importmulti( - [{ - 'desc': descsum_create(f"pkh([80002067/0h/0h]{xpub}/*)"), - 'keypool': True, - 'timestamp': 'now', - 'range': [0, 4], - }] + [ + { + "desc": descsum_create(f"pkh([80002067/0h/0h]{xpub}/*)"), + "keypool": True, + "timestamp": "now", + "range": [0, 4], + } + ] ) self.log.info(result) for i in range(0, 5): - addr = wrpc.getnewaddress('') + addr = wrpc.getnewaddress("") assert_equal(addr, addresses[i]) -if __name__ == '__main__': +if __name__ == "__main__": ImportMultiTest().main() diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py --- a/test/functional/wallet_importprunedfunds.py +++ b/test/functional/wallet_importprunedfunds.py @@ -38,7 +38,7 @@ # Check only one address address_info = self.nodes[0].getaddressinfo(address1) - assert_equal(address_info['ismine'], True) + assert_equal(address_info["ismine"], True) self.sync_all() @@ -47,88 +47,102 @@ # Address Test - before import address_info = self.nodes[1].getaddressinfo(address1) - assert_equal(address_info['iswatchonly'], False) - assert_equal(address_info['ismine'], False) + assert_equal(address_info["iswatchonly"], False) + assert_equal(address_info["ismine"], False) address_info = self.nodes[1].getaddressinfo(address2) - assert_equal(address_info['iswatchonly'], False) - assert_equal(address_info['ismine'], False) + assert_equal(address_info["iswatchonly"], False) + assert_equal(address_info["ismine"], False) address_info = self.nodes[1].getaddressinfo(address3) - assert_equal(address_info['iswatchonly'], False) - assert_equal(address_info['ismine'], False) + assert_equal(address_info["iswatchonly"], False) + assert_equal(address_info["ismine"], False) # Send funds to self txnid1 = self.nodes[0].sendtoaddress(address1, 100000) self.generate(self.nodes[0], 1) - rawtxn1 = self.nodes[0].gettransaction(txnid1)['hex'] + rawtxn1 = self.nodes[0].gettransaction(txnid1)["hex"] proof1 = self.nodes[0].gettxoutproof([txnid1]) txnid2 = self.nodes[0].sendtoaddress(address2, 50000) self.generate(self.nodes[0], 1) - rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex'] + rawtxn2 = self.nodes[0].gettransaction(txnid2)["hex"] proof2 = self.nodes[0].gettxoutproof([txnid2]) txnid3 = self.nodes[0].sendtoaddress(address3, 25000) self.generate(self.nodes[0], 1) - rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex'] + rawtxn3 = self.nodes[0].gettransaction(txnid3)["hex"] proof3 = self.nodes[0].gettxoutproof([txnid3]) self.sync_all() # Import with no affiliated address assert_raises_rpc_error( - -5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1) + -5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1 + ) balance1 = self.nodes[1].getbalance() assert_equal(balance1, Decimal(0)) # Import with affiliated address with no rescan - self.nodes[1].createwallet('wwatch', disable_private_keys=True) - wwatch = self.nodes[1].get_wallet_rpc('wwatch') + self.nodes[1].createwallet("wwatch", disable_private_keys=True) + wwatch = self.nodes[1].get_wallet_rpc("wwatch") wwatch.importaddress(address=address2, rescan=False) wwatch.importprunedfunds(rawtransaction=rawtxn2, txoutproof=proof2) - assert [tx for tx in wwatch.listtransactions(include_watchonly=True) - if tx['txid'] == txnid2] + assert [ + tx + for tx in wwatch.listtransactions(include_watchonly=True) + if tx["txid"] == txnid2 + ] # Import with private key with no rescan w1 = self.nodes[1].get_wallet_rpc(self.default_wallet_name) w1.importprivkey(privkey=address3_privkey, rescan=False) w1.importprunedfunds(rawtxn3, proof3) - assert [tx for tx in w1.listtransactions() if tx['txid'] == txnid3] + assert [tx for tx in w1.listtransactions() if tx["txid"] == txnid3] balance3 = w1.getbalance() - assert_equal(balance3, Decimal('25000')) + assert_equal(balance3, Decimal("25000")) # Addresses Test - after import address_info = w1.getaddressinfo(address1) - assert_equal(address_info['iswatchonly'], False) - assert_equal(address_info['ismine'], False) + assert_equal(address_info["iswatchonly"], False) + assert_equal(address_info["ismine"], False) address_info = wwatch.getaddressinfo(address2) if self.options.descriptors: - assert_equal(address_info['iswatchonly'], False) - assert_equal(address_info['ismine'], True) + assert_equal(address_info["iswatchonly"], False) + assert_equal(address_info["ismine"], True) else: - assert_equal(address_info['iswatchonly'], True) - assert_equal(address_info['ismine'], False) + assert_equal(address_info["iswatchonly"], True) + assert_equal(address_info["ismine"], False) address_info = w1.getaddressinfo(address3) - assert_equal(address_info['iswatchonly'], False) - assert_equal(address_info['ismine'], True) + assert_equal(address_info["iswatchonly"], False) + assert_equal(address_info["ismine"], True) # Remove transactions assert_raises_rpc_error( - -8, "Transaction does not exist in wallet.", w1.removeprunedfunds, txnid1) + -8, "Transaction does not exist in wallet.", w1.removeprunedfunds, txnid1 + ) - assert not [tx for tx in w1.listtransactions( - include_watchonly=True) if tx['txid'] == txnid1] + assert not [ + tx + for tx in w1.listtransactions(include_watchonly=True) + if tx["txid"] == txnid1 + ] wwatch.removeprunedfunds(txnid2) - assert not [tx for tx in wwatch.listtransactions( - include_watchonly=True) if tx['txid'] == txnid2] + assert not [ + tx + for tx in wwatch.listtransactions(include_watchonly=True) + if tx["txid"] == txnid2 + ] w1.removeprunedfunds(txnid3) - assert not [tx for tx in w1.listtransactions( - include_watchonly=True) if tx['txid'] == txnid3] + assert not [ + tx + for tx in w1.listtransactions(include_watchonly=True) + if tx["txid"] == txnid3 + ] -if __name__ == '__main__': +if __name__ == "__main__": ImportPrunedFundsTest().main() diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -20,32 +20,32 @@ def run_test(self): nodes = self.nodes addr_before_encrypting = nodes[0].getnewaddress() - addr_before_encrypting_data = nodes[ - 0].getaddressinfo(addr_before_encrypting) + addr_before_encrypting_data = nodes[0].getaddressinfo(addr_before_encrypting) wallet_info_old = nodes[0].getwalletinfo() - assert addr_before_encrypting_data[ - 'hdseedid'] == wallet_info_old['hdseedid'] + assert addr_before_encrypting_data["hdseedid"] == wallet_info_old["hdseedid"] # Encrypt wallet and wait to terminate - nodes[0].encryptwallet('test') + nodes[0].encryptwallet("test") # Keep creating keys addr = nodes[0].getnewaddress() addr_data = nodes[0].getaddressinfo(addr) wallet_info = nodes[0].getwalletinfo() - assert addr_before_encrypting_data[ - 'hdseedid'] != wallet_info['hdseedid'] - assert addr_data['hdseedid'] == wallet_info['hdseedid'] + assert addr_before_encrypting_data["hdseedid"] != wallet_info["hdseedid"] + assert addr_data["hdseedid"] == wallet_info["hdseedid"] assert_raises_rpc_error( - -12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) + -12, + "Error: Keypool ran out, please call keypoolrefill first", + nodes[0].getnewaddress, + ) # put six (plus 2) new keys in the keypool (100% external-, +100% # internal-keys, 1 in min) - nodes[0].walletpassphrase('test', 12000) + nodes[0].walletpassphrase("test", 12000) nodes[0].keypoolrefill(6) nodes[0].walletlock() wi = nodes[0].getwalletinfo() - assert_equal(wi['keypoolsize_hd_internal'], 6) - assert_equal(wi['keypoolsize'], 6) + assert_equal(wi["keypoolsize_hd_internal"], 6) + assert_equal(wi["keypoolsize"], 6) # drain the internal keys nodes[0].getrawchangeaddress() @@ -56,8 +56,7 @@ nodes[0].getrawchangeaddress() addr = set() # the next one should fail - assert_raises_rpc_error(-12, "Keypool ran out", - nodes[0].getrawchangeaddress) + assert_raises_rpc_error(-12, "Keypool ran out", nodes[0].getrawchangeaddress) # drain the external keys addr.add(nodes[0].getnewaddress()) @@ -69,10 +68,13 @@ assert len(addr) == 6 # the next one should fail assert_raises_rpc_error( - -12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) + -12, + "Error: Keypool ran out, please call keypoolrefill first", + nodes[0].getnewaddress, + ) # refill keypool with three new addresses - nodes[0].walletpassphrase('test', 1) + nodes[0].walletpassphrase("test", 1) nodes[0].keypoolrefill(3) # test walletpassphrase timeout @@ -84,15 +86,15 @@ nodes[0].getnewaddress() assert_raises_rpc_error(-12, "Keypool ran out", nodes[0].getnewaddress) - nodes[0].walletpassphrase('test', 100) + nodes[0].walletpassphrase("test", 100) nodes[0].keypoolrefill(100) wi = nodes[0].getwalletinfo() - assert_equal(wi['keypoolsize_hd_internal'], 100) - assert_equal(wi['keypoolsize'], 100) + assert_equal(wi["keypoolsize_hd_internal"], 100) + assert_equal(wi["keypoolsize"], 100) # create a blank wallet - nodes[0].createwallet(wallet_name='w2', blank=True) - w2 = nodes[0].get_wallet_rpc('w2') + nodes[0].createwallet(wallet_name="w2", blank=True) + w2 = nodes[0].get_wallet_rpc("w2") # refer to initial wallet as w1 w1 = nodes[0].get_wallet_rpc(self.default_wallet_name) @@ -101,9 +103,16 @@ address = addr.pop() privkey = w1.dumpprivkey(address) res = w2.importmulti( - [{'scriptPubKey': {'address': address}, 'keys': [privkey], 'timestamp': 'now'}]) - assert_equal(res[0]['success'], True) - w1.walletpassphrase('test', 100) + [ + { + "scriptPubKey": {"address": address}, + "keys": [privkey], + "timestamp": "now", + } + ] + ) + assert_equal(res[0]["success"], True) + w1.walletpassphrase("test", 100) res = w1.sendtoaddress(address=address, amount=100.00) self.generate(nodes[0], 1) @@ -111,20 +120,25 @@ # Using a fee rate (10 sat / byte) well above the minimum relay rate # creating a 5,000 sat transaction with change should not be possible - assert_raises_rpc_error(-4, - "Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.", - w2.walletcreatefundedpsbt, - inputs=[], - outputs=[{addr.pop(): 50.00}], - options={"subtractFeeFromOutputs": [0], - "feeRate": 100}) + assert_raises_rpc_error( + -4, + ( + "Transaction needs a change address, but we can't generate it. Please" + " call keypoolrefill first." + ), + w2.walletcreatefundedpsbt, + inputs=[], + outputs=[{addr.pop(): 50.00}], + options={"subtractFeeFromOutputs": [0], "feeRate": 100}, + ) # creating a 10,000 sat transaction without change, with a manual # input, should still be possible res = w2.walletcreatefundedpsbt( inputs=w2.listunspent(), outputs=[{destination: 100.00}], - options={"subtractFeeFromOutputs": [0], "feeRate": 100}) + options={"subtractFeeFromOutputs": [0], "feeRate": 100}, + ) assert_equal("psbt" in res, True) # creating a 10,000 sat transaction without change should still be @@ -132,19 +146,20 @@ res = w2.walletcreatefundedpsbt( inputs=[], outputs=[{destination: 100.00}], - options={"subtractFeeFromOutputs": [0], "feeRate": 100}) + options={"subtractFeeFromOutputs": [0], "feeRate": 100}, + ) assert_equal("psbt" in res, True) # should work without subtractFeeFromOutputs if the exact fee is # subtracted from the amount - res = w2.walletcreatefundedpsbt(inputs=[], - outputs=[{destination: 80.00}], - options={"feeRate": 100}) + res = w2.walletcreatefundedpsbt( + inputs=[], outputs=[{destination: 80.00}], options={"feeRate": 100} + ) assert_equal("psbt" in res, True) # dust change should be removed - res = w2.walletcreatefundedpsbt(inputs=[], - outputs=[{destination: 79.00}], - options={"feeRate": 100}) + res = w2.walletcreatefundedpsbt( + inputs=[], outputs=[{destination: 79.00}], options={"feeRate": 100} + ) assert_equal("psbt" in res, True) # create a transaction without change at the maximum fee rate, such @@ -152,19 +167,24 @@ res = w2.walletcreatefundedpsbt( inputs=[], outputs=[{destination: 100.00}], - options={"subtractFeeFromOutputs": [0], "feeRate": 494.90}) + options={"subtractFeeFromOutputs": [0], "feeRate": 494.90}, + ) assert_equal("psbt" in res, True) assert_equal(res["fee"], Decimal("94.53")) # creating a 10,000 sat transaction with a manual change address should # be possible - res = w2.walletcreatefundedpsbt(inputs=[], - outputs=[{destination: 100.00}], - options={"subtractFeeFromOutputs": [0], - "feeRate": 100, - "changeAddress": addr.pop()}) + res = w2.walletcreatefundedpsbt( + inputs=[], + outputs=[{destination: 100.00}], + options={ + "subtractFeeFromOutputs": [0], + "feeRate": 100, + "changeAddress": addr.pop(), + }, + ) assert_equal("psbt" in res, True) -if __name__ == '__main__': +if __name__ == "__main__": KeyPoolTest().main() diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py --- a/test/functional/wallet_keypool_topup.py +++ b/test/functional/wallet_keypool_topup.py @@ -21,15 +21,19 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - self.extra_args = [[], ['-keypool=100']] + self.extra_args = [[], ["-keypool=100"]] def skip_test_if_missing_module(self): self.skip_if_no_wallet() def run_test(self): wallet_path = os.path.join( - self.nodes[1].datadir, self.chain, "wallets", - self.default_wallet_name, self.wallet_data_filename) + self.nodes[1].datadir, + self.chain, + "wallets", + self.default_wallet_name, + self.wallet_data_filename, + ) wallet_backup_path = os.path.join(self.nodes[1].datadir, "wallet.bak") self.generate(self.nodes[0], 101) @@ -60,20 +64,23 @@ self.log.info("Verify keypool is restored and balance is correct") assert_equal(self.nodes[1].getbalance(), 15000000) - assert_equal(self.nodes[1].listtransactions() - [0]['category'], "receive") + assert_equal(self.nodes[1].listtransactions()[0]["category"], "receive") # Check that we have marked all keys up to the used keypool key as used if self.options.descriptors: assert_equal( - self.nodes[1].getaddressinfo( - self.nodes[1].getnewaddress())['hdkeypath'], - "m/44'/1'/0'/0/110") + self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())[ + "hdkeypath" + ], + "m/44'/1'/0'/0/110", + ) else: assert_equal( - self.nodes[1].getaddressinfo( - self.nodes[1].getnewaddress())['hdkeypath'], - "m/0'/0'/110'") + self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())[ + "hdkeypath" + ], + "m/0'/0'/110'", + ) -if __name__ == '__main__': +if __name__ == "__main__": KeypoolRestoreTest().main() diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py --- a/test/functional/wallet_labels.py +++ b/test/functional/wallet_labels.py @@ -31,13 +31,12 @@ # Note each time we call generate, all generated coins go into # the same address, so we call twice to get two addresses w/50 each - self.generatetoaddress(node, - nblocks=1, address=node.getnewaddress( - label='coinbase')) - self.generatetoaddress(node, - nblocks=101, - address=node.getnewaddress( - label='coinbase')) + self.generatetoaddress( + node, nblocks=1, address=node.getnewaddress(label="coinbase") + ) + self.generatetoaddress( + node, nblocks=101, address=node.getnewaddress(label="coinbase") + ) assert_equal(node.getbalance(), 100000000) # there should be 2 address groups @@ -51,7 +50,7 @@ assert_equal(len(address_group), 1) assert_equal(len(address_group[0]), 3) assert_equal(address_group[0][1], 50000000) - assert_equal(address_group[0][2], 'coinbase') + assert_equal(address_group[0][2], "coinbase") linked_addresses.add(address_group[0][0]) # send 50 from each address to a third address not in this wallet @@ -78,16 +77,16 @@ # Create labels and make sure subsequent label API calls # recognize the label/address associations. - labels = [Label(name) - for name in ("a", "b", "c", "d", "e")] + labels = [Label(name) for name in ("a", "b", "c", "d", "e")] for label in labels: address = node.getnewaddress(label.name) label.add_receive_address(address) label.verify(node) # Check all labels are returned by listlabels. - assert_equal(node.listlabels(), sorted( - ['coinbase'] + [label.name for label in labels])) + assert_equal( + node.listlabels(), sorted(["coinbase"] + [label.name for label in labels]) + ) # Send a transaction to each label. for label in labels: @@ -97,8 +96,7 @@ # Check the amounts received. self.generate(node, 1) for label in labels: - assert_equal( - node.getreceivedbyaddress(label.addresses[0]), amount_to_send) + assert_equal(node.getreceivedbyaddress(label.addresses[0]), amount_to_send) assert_equal(node.getreceivedbylabel(label.name), amount_to_send) for i, label in enumerate(labels): @@ -119,10 +117,9 @@ node.setlabel(address, label.name) label.add_address(address) label.verify(node) - assert_raises_rpc_error(-11, - "No addresses with label", - node.getaddressesbylabel, - "") + assert_raises_rpc_error( + -11, "No addresses with label", node.getaddressesbylabel, "" + ) # Check that addmultisigaddress can assign labels. if not self.options.descriptors: @@ -130,8 +127,9 @@ addresses = [] for _ in range(10): addresses.append(node.getnewaddress()) - multisig_address = node.addmultisigaddress( - 5, addresses, label.name)['address'] + multisig_address = node.addmultisigaddress(5, addresses, label.name)[ + "address" + ] label.add_address(multisig_address) label.purpose[multisig_address] = "send" label.verify(node) @@ -172,7 +170,8 @@ assert self.name in node.listlabels() assert_equal( node.getaddressesbylabel(self.name), - {address: {"purpose": self.purpose[address]} for address in self.addresses}) + {address: {"purpose": self.purpose[address]} for address in self.addresses}, + ) def change_label(node, address, old_label, new_label): @@ -186,5 +185,5 @@ new_label.verify(node) -if __name__ == '__main__': +if __name__ == "__main__": WalletLabelsTest().main() diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py --- a/test/functional/wallet_listreceivedby.py +++ b/test/functional/wallet_listreceivedby.py @@ -32,9 +32,9 @@ # save the number of coinbase reward addresses so far num_cb_reward_addresses = len( self.nodes[1].listreceivedbyaddress( - minconf=0, - include_empty=True, - include_watchonly=True)) + minconf=0, include_empty=True, include_watchonly=True + ) + ) self.log.info("listreceivedbyaddress Test") @@ -44,36 +44,72 @@ self.sync_all() # Check not listed in listreceivedbyaddress because has 0 confirmations - assert_array_result(self.nodes[1].listreceivedbyaddress(), - {"address": addr}, - {}, - True) + assert_array_result( + self.nodes[1].listreceivedbyaddress(), {"address": addr}, {}, True + ) # Bury Tx under 10 block so it will be returned by # listreceivedbyaddress self.generate(self.nodes[1], 10) - assert_array_result(self.nodes[1].listreceivedbyaddress(), - {"address": addr}, - {"address": addr, "label": "", "amount": Decimal("100000"), "confirmations": 10, "txids": [txid, ]}) + assert_array_result( + self.nodes[1].listreceivedbyaddress(), + {"address": addr}, + { + "address": addr, + "label": "", + "amount": Decimal("100000"), + "confirmations": 10, + "txids": [ + txid, + ], + }, + ) # With min confidence < 10 - assert_array_result(self.nodes[1].listreceivedbyaddress(5), - {"address": addr}, - {"address": addr, "label": "", "amount": Decimal("100000"), "confirmations": 10, "txids": [txid, ]}) + assert_array_result( + self.nodes[1].listreceivedbyaddress(5), + {"address": addr}, + { + "address": addr, + "label": "", + "amount": Decimal("100000"), + "confirmations": 10, + "txids": [ + txid, + ], + }, + ) # With min confidence > 10, should not find Tx - assert_array_result(self.nodes[1].listreceivedbyaddress(11), { - "address": addr}, {}, True) + assert_array_result( + self.nodes[1].listreceivedbyaddress(11), {"address": addr}, {}, True + ) # Empty Tx empty_addr = self.nodes[1].getnewaddress() - assert_array_result(self.nodes[1].listreceivedbyaddress(0, True), - {"address": empty_addr}, - {"address": empty_addr, "label": "", "amount": 0, "confirmations": 0, "txids": []}) + assert_array_result( + self.nodes[1].listreceivedbyaddress(0, True), + {"address": empty_addr}, + { + "address": empty_addr, + "label": "", + "amount": 0, + "confirmations": 0, + "txids": [], + }, + ) # Test Address filtering # Only on addr - expected = {"address": addr, "label": "", "amount": Decimal( - "100000"), "confirmations": 10, "txids": [txid, ]} + expected = { + "address": addr, + "label": "", + "amount": Decimal("100000"), + "confirmations": 10, + "txids": [ + txid, + ], + } res = self.nodes[1].listreceivedbyaddress( - minconf=0, include_empty=True, include_watchonly=True, address_filter=addr) + minconf=0, include_empty=True, include_watchonly=True, address_filter=addr + ) assert_array_result(res, {"address": addr}, expected) assert_equal(len(res), 1) # Test for regression on CLI calls with address string (#14173) @@ -81,8 +117,15 @@ assert_array_result(cli_res, {"address": addr}, expected) assert_equal(len(cli_res), 1) # Error on invalid address - assert_raises_rpc_error(-4, "address_filter parameter was invalid", - self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, include_watchonly=True, address_filter="bamboozling") + assert_raises_rpc_error( + -4, + "address_filter parameter was invalid", + self.nodes[1].listreceivedbyaddress, + minconf=0, + include_empty=True, + include_watchonly=True, + address_filter="bamboozling", + ) # Another address receive money res = self.nodes[1].listreceivedbyaddress(0, True, True) # Right now 2 entries @@ -91,14 +134,28 @@ txid2 = self.nodes[0].sendtoaddress(other_addr, 100000) self.generate(self.nodes[0], 1) # Same test as above should still pass - expected = {"address": addr, "label": "", "amount": Decimal( - "100000"), "confirmations": 11, "txids": [txid, ]} + expected = { + "address": addr, + "label": "", + "amount": Decimal("100000"), + "confirmations": 11, + "txids": [ + txid, + ], + } res = self.nodes[1].listreceivedbyaddress(0, True, True, addr) assert_array_result(res, {"address": addr}, expected) assert_equal(len(res), 1) # Same test as above but with other_addr should still pass - expected = {"address": other_addr, "label": "", "amount": Decimal( - "100000"), "confirmations": 1, "txids": [txid2, ]} + expected = { + "address": other_addr, + "label": "", + "amount": Decimal("100000"), + "confirmations": 1, + "txids": [ + txid2, + ], + } res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr) assert_array_result(res, {"address": other_addr}, expected) assert_equal(len(res), 1) @@ -136,17 +193,19 @@ # Trying to getreceivedby for an address the wallet doesn't own should # return an error - assert_raises_rpc_error(-4, "Address not found in wallet", - self.nodes[0].getreceivedbyaddress, addr) + assert_raises_rpc_error( + -4, "Address not found in wallet", self.nodes[0].getreceivedbyaddress, addr + ) self.log.info("listreceivedbylabel + getreceivedbylabel Test") # set pre-state - label = '' + label = "" address = self.nodes[1].getnewaddress() test_address(self.nodes[1], address, labels=[label]) received_by_label_json = [ - r for r in self.nodes[1].listreceivedbylabel() if r["label"] == label][0] + r for r in self.nodes[1].listreceivedbylabel() if r["label"] == label + ][0] balance_by_label = self.nodes[1].getreceivedbylabel(label) txid = self.nodes[0].sendtoaddress(addr, 100000) @@ -154,9 +213,11 @@ # listreceivedbylabel should return received_by_label_json because of 0 # confirmations - assert_array_result(self.nodes[1].listreceivedbylabel(), - {"label": label}, - received_by_label_json) + assert_array_result( + self.nodes[1].listreceivedbylabel(), + {"label": label}, + received_by_label_json, + ) # getreceivedbyaddress should return same balance because of 0 # confirmations @@ -165,9 +226,14 @@ self.generate(self.nodes[1], 10) # listreceivedbylabel should return updated received list - assert_array_result(self.nodes[1].listreceivedbylabel(), - {"label": label}, - {"label": received_by_label_json["label"], "amount": (received_by_label_json["amount"] + Decimal("100000"))}) + assert_array_result( + self.nodes[1].listreceivedbylabel(), + {"label": label}, + { + "label": received_by_label_json["label"], + "amount": received_by_label_json["amount"] + Decimal("100000"), + }, + ) # getreceivedbylabel should return updated receive total balance = self.nodes[1].getreceivedbylabel(label) @@ -176,8 +242,11 @@ # Create a new label named "mynewlabel" that has a 0 balance address = self.nodes[1].getnewaddress() self.nodes[1].setlabel(address, "mynewlabel") - received_by_label_json = [r for r in self.nodes[1].listreceivedbylabel( - 0, True) if r["label"] == "mynewlabel"][0] + received_by_label_json = [ + r + for r in self.nodes[1].listreceivedbylabel(0, True) + if r["label"] == "mynewlabel" + ][0] # Test includeempty of listreceivedbylabel assert_equal(received_by_label_json["amount"], Decimal("0.0")) @@ -187,5 +256,5 @@ assert_equal(balance, Decimal("0.0")) -if __name__ == '__main__': +if __name__ == "__main__": ReceivedByTest().main() diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py --- a/test/functional/wallet_listsinceblock.py +++ b/test/functional/wallet_listsinceblock.py @@ -43,63 +43,86 @@ def test_no_blockhash(self): self.log.info("Test no blockhash") - txid = self.nodes[2].sendtoaddress( - self.nodes[0].getnewaddress(), 1000000) - blockhash, = self.generate(self.nodes[2], 1) - blockheight = self.nodes[2].getblockheader(blockhash)['height'] + txid = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1000000) + (blockhash,) = self.generate(self.nodes[2], 1) + blockheight = self.nodes[2].getblockheader(blockhash)["height"] txs = self.nodes[0].listtransactions() - assert_array_result(txs, {"txid": txid}, { - "category": "receive", - "amount": 1000000, - "blockhash": blockhash, - "blockheight": blockheight, - "confirmations": 1, - }) + assert_array_result( + txs, + {"txid": txid}, + { + "category": "receive", + "amount": 1000000, + "blockhash": blockhash, + "blockheight": blockheight, + "confirmations": 1, + }, + ) assert_equal( self.nodes[0].listsinceblock(), - {"lastblock": blockhash, - "removed": [], - "transactions": txs}) + {"lastblock": blockhash, "removed": [], "transactions": txs}, + ) assert_equal( self.nodes[0].listsinceblock(""), - {"lastblock": blockhash, - "removed": [], - "transactions": txs}) + {"lastblock": blockhash, "removed": [], "transactions": txs}, + ) def test_invalid_blockhash(self): self.log.info("Test invalid blockhash") - assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, - "42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4") - assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, - "0000000000000000000000000000000000000000000000000000000000000000") - assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 11, for 'invalid-hex')", self.nodes[0].listsinceblock, - "invalid-hex") - assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'Z000000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].listsinceblock, - "Z000000000000000000000000000000000000000000000000000000000000000") + assert_raises_rpc_error( + -5, + "Block not found", + self.nodes[0].listsinceblock, + "42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4", + ) + assert_raises_rpc_error( + -5, + "Block not found", + self.nodes[0].listsinceblock, + "0000000000000000000000000000000000000000000000000000000000000000", + ) + assert_raises_rpc_error( + -8, + "blockhash must be of length 64 (not 11, for 'invalid-hex')", + self.nodes[0].listsinceblock, + "invalid-hex", + ) + assert_raises_rpc_error( + -8, + ( + "blockhash must be hexadecimal string (not" + " 'Z000000000000000000000000000000000000000000000000000000000000000')" + ), + self.nodes[0].listsinceblock, + "Z000000000000000000000000000000000000000000000000000000000000000", + ) def test_targetconfirmations(self): - ''' + """ This tests when the value of target_confirmations exceeds the number of blocks in the main chain. In this case, the genesis block hash should be given for the `lastblock` property. If target_confirmations is < 1, then a -8 invalid parameter error is thrown. - ''' + """ self.log.info("Test target_confirmations") - blockhash, = self.generate(self.nodes[2], 1) - blockheight = self.nodes[2].getblockheader(blockhash)['height'] + (blockhash,) = self.generate(self.nodes[2], 1) + blockheight = self.nodes[2].getblockheader(blockhash)["height"] assert_equal( self.nodes[0].getblockhash(0), - self.nodes[0].listsinceblock(blockhash, blockheight + 1)['lastblock']) + self.nodes[0].listsinceblock(blockhash, blockheight + 1)["lastblock"], + ) assert_equal( self.nodes[0].getblockhash(0), - self.nodes[0].listsinceblock(blockhash, blockheight + 1000)['lastblock']) - assert_raises_rpc_error(-8, "Invalid parameter", - self.nodes[0].listsinceblock, blockhash, 0) + self.nodes[0].listsinceblock(blockhash, blockheight + 1000)["lastblock"], + ) + assert_raises_rpc_error( + -8, "Invalid parameter", self.nodes[0].listsinceblock, blockhash, 0 + ) def test_reorg(self): - ''' + """ `listsinceblock` did not behave correctly when handed a block that was no longer in the main chain: @@ -125,40 +148,41 @@ range bb1-bb4. This test only checks that [tx0] is present. - ''' + """ self.log.info("Test reorg") # Split network into two self.split_network() # send to nodes[0] from nodes[2] - senttx = self.nodes[2].sendtoaddress( - self.nodes[0].getnewaddress(), 1000000) + senttx = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1000000) # generate on both sides nodes1_last_blockhash = self.generate( - self.nodes[1], 6, sync_fun=lambda: self.sync_all(self.nodes[:2]))[-1] + self.nodes[1], 6, sync_fun=lambda: self.sync_all(self.nodes[:2]) + )[-1] nodes2_first_blockhash = self.generate( - self.nodes[2], 7, sync_fun=lambda: self.sync_all(self.nodes[2:]))[0] - self.log.debug( - f"nodes[1] last blockhash = {nodes1_last_blockhash}") - self.log.debug( - f"nodes[2] first blockhash = {nodes2_first_blockhash}") + self.nodes[2], 7, sync_fun=lambda: self.sync_all(self.nodes[2:]) + )[0] + self.log.debug(f"nodes[1] last blockhash = {nodes1_last_blockhash}") + self.log.debug(f"nodes[2] first blockhash = {nodes2_first_blockhash}") self.join_network() # listsinceblock(nodes1_last_blockhash) should now include tx as seen from nodes[0] # and return the block height which listsinceblock now exposes since # rABC6098a1cb2b25. - transactions = self.nodes[0].listsinceblock( - nodes1_last_blockhash)['transactions'] - found = next(tx for tx in transactions if tx['txid'] == senttx) + transactions = self.nodes[0].listsinceblock(nodes1_last_blockhash)[ + "transactions" + ] + found = next(tx for tx in transactions if tx["txid"] == senttx) assert_equal( - found['blockheight'], - self.nodes[0].getblockheader(nodes2_first_blockhash)['height']) + found["blockheight"], + self.nodes[0].getblockheader(nodes2_first_blockhash)["height"], + ) def test_double_spend(self): - ''' + """ This tests the case where the same UTXO is spent twice on two separate blocks as part of a reorg. @@ -185,7 +209,7 @@ asked for in listsinceblock, and to iterate back over existing blocks up until the fork point, and to include all transactions that relate to the node wallet. - ''' + """ self.log.info("Test double spend") self.sync_all() @@ -194,8 +218,9 @@ eckey = ECKey() eckey.generate() privkey = bytes_to_wif(eckey.get_bytes()) - address = cashaddr.encode_full("ecregtest", cashaddr.PUBKEY_TYPE, - hash160(eckey.get_pubkey().get_bytes())) + address = cashaddr.encode_full( + "ecregtest", cashaddr.PUBKEY_TYPE, hash160(eckey.get_pubkey().get_bytes()) + ) self.nodes[2].sendtoaddress(address, 10_000_000) self.generate(self.nodes[2], 6) self.nodes[2].importprivkey(privkey) @@ -212,13 +237,17 @@ self.nodes[0].getnewaddress(): 1000000, self.nodes[1].getnewaddress(): change, } - utxo_dicts = [{ - 'txid': utxo['txid'], - 'vout': utxo['vout'], - }] + utxo_dicts = [ + { + "txid": utxo["txid"], + "vout": utxo["vout"], + } + ] txid1 = self.nodes[1].sendrawtransaction( self.nodes[1].signrawtransactionwithwallet( - self.nodes[1].createrawtransaction(utxo_dicts, recipient_dict))['hex']) + self.nodes[1].createrawtransaction(utxo_dicts, recipient_dict) + )["hex"] + ) # send from nodes[2] using utxo to nodes[3] recipient_dict2 = { @@ -227,7 +256,9 @@ } self.nodes[2].sendrawtransaction( self.nodes[2].signrawtransactionwithwallet( - self.nodes[2].createrawtransaction(utxo_dicts, recipient_dict2))['hex']) + self.nodes[2].createrawtransaction(utxo_dicts, recipient_dict2) + )["hex"] + ) # generate on both sides lastblockhash = self.generate(self.nodes[1], 3, sync_fun=self.no_op)[2] @@ -238,21 +269,23 @@ self.sync_all() # gettransaction should work for txid1 - assert self.nodes[0].gettransaction( - txid1)['txid'] == txid1, "gettransaction failed to find txid1" + assert ( + self.nodes[0].gettransaction(txid1)["txid"] == txid1 + ), "gettransaction failed to find txid1" # listsinceblock(lastblockhash) should now include txid1, as seen from # nodes[0] lsbres = self.nodes[0].listsinceblock(lastblockhash) - assert any(tx['txid'] == txid1 for tx in lsbres['removed']) + assert any(tx["txid"] == txid1 for tx in lsbres["removed"]) # but it should not include 'removed' if include_removed=false lsbres2 = self.nodes[0].listsinceblock( - blockhash=lastblockhash, include_removed=False) - assert 'removed' not in lsbres2 + blockhash=lastblockhash, include_removed=False + ) + assert "removed" not in lsbres2 def test_double_send(self): - ''' + """ This tests the case where the same transaction is submitted twice on two separate blocks as part of a reorg. The former will vanish and the latter will appear as the true transaction (with confirmations dropping @@ -275,7 +308,7 @@ present in a different block. 3. It is listed with a confirmation count of 2 (bb3, bb4), not 3 (aa1, aa2, aa3). - ''' + """ self.log.info("Test double send") self.sync_all() @@ -291,15 +324,18 @@ self.nodes[0].getnewaddress(): 1000000, self.nodes[2].getnewaddress(): change, } - utxo_dicts = [{ - 'txid': utxo['txid'], - 'vout': utxo['vout'], - }] + utxo_dicts = [ + { + "txid": utxo["txid"], + "vout": utxo["vout"], + } + ] signedtxres = self.nodes[2].signrawtransactionwithwallet( - self.nodes[2].createrawtransaction(utxo_dicts, recipient_dict)) - assert signedtxres['complete'] + self.nodes[2].createrawtransaction(utxo_dicts, recipient_dict) + ) + assert signedtxres["complete"] - signedtx = signedtxres['hex'] + signedtx = signedtxres["hex"] # send from nodes[1]; this will end up in aa1 txid1 = self.nodes[1].sendrawtransaction(signedtx) @@ -323,26 +359,25 @@ # gettransaction should work for txid1 tx1 = self.nodes[0].gettransaction(txid1) assert_equal( - tx1['blockheight'], - self.nodes[0].getblockheader( - tx1['blockhash'])['height']) + tx1["blockheight"], self.nodes[0].getblockheader(tx1["blockhash"])["height"] + ) # listsinceblock(lastblockhash) should now include txid1 in transactions # as well as in removed lsbres = self.nodes[0].listsinceblock(lastblockhash) - assert any(tx['txid'] == txid1 for tx in lsbres['transactions']) - assert any(tx['txid'] == txid1 for tx in lsbres['removed']) + assert any(tx["txid"] == txid1 for tx in lsbres["transactions"]) + assert any(tx["txid"] == txid1 for tx in lsbres["removed"]) # find transaction and ensure confirmations is valid - for tx in lsbres['transactions']: - if tx['txid'] == txid1: - assert_equal(tx['confirmations'], 2) + for tx in lsbres["transactions"]: + if tx["txid"] == txid1: + assert_equal(tx["confirmations"], 2) # the same check for the removed array; confirmations should STILL be 2 - for tx in lsbres['removed']: - if tx['txid'] == txid1: - assert_equal(tx['confirmations'], 2) + for tx in lsbres["removed"]: + if tx["txid"] == txid1: + assert_equal(tx["confirmations"], 2) -if __name__ == '__main__': +if __name__ == "__main__": ListSinceBlockTest().main() diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py --- a/test/functional/wallet_listtransactions.py +++ b/test/functional/wallet_listtransactions.py @@ -24,96 +24,151 @@ # Leave IBD self.generate(self.nodes[0], 1) # Simple send, 0 to 1: - txid = self.nodes[0].sendtoaddress( - self.nodes[1].getnewaddress(), 100000) + txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 100000) self.sync_all() - assert_array_result(self.nodes[0].listtransactions(), - {"txid": txid}, - {"category": "send", "amount": Decimal("-100000"), "confirmations": 0}) - assert_array_result(self.nodes[1].listtransactions(), - {"txid": txid}, - {"category": "receive", "amount": Decimal("100000"), "confirmations": 0}) + assert_array_result( + self.nodes[0].listtransactions(), + {"txid": txid}, + {"category": "send", "amount": Decimal("-100000"), "confirmations": 0}, + ) + assert_array_result( + self.nodes[1].listtransactions(), + {"txid": txid}, + {"category": "receive", "amount": Decimal("100000"), "confirmations": 0}, + ) # mine a block, confirmations should change: blockhash = self.generate(self.nodes[0], 1)[0] - blockheight = self.nodes[0].getblockheader(blockhash)['height'] - assert_array_result(self.nodes[0].listtransactions(), - {"txid": txid}, - {"category": "send", "amount": Decimal("-100000"), "confirmations": 1, "blockhash": blockhash, "blockheight": blockheight}) - assert_array_result(self.nodes[1].listtransactions(), - {"txid": txid}, - {"category": "receive", "amount": Decimal("100000"), "confirmations": 1, "blockhash": blockhash, "blockheight": blockheight}) + blockheight = self.nodes[0].getblockheader(blockhash)["height"] + assert_array_result( + self.nodes[0].listtransactions(), + {"txid": txid}, + { + "category": "send", + "amount": Decimal("-100000"), + "confirmations": 1, + "blockhash": blockhash, + "blockheight": blockheight, + }, + ) + assert_array_result( + self.nodes[1].listtransactions(), + {"txid": txid}, + { + "category": "receive", + "amount": Decimal("100000"), + "confirmations": 1, + "blockhash": blockhash, + "blockheight": blockheight, + }, + ) # send-to-self: - txid = self.nodes[0].sendtoaddress( - self.nodes[0].getnewaddress(), 200000) - assert_array_result(self.nodes[0].listtransactions(), - {"txid": txid, "category": "send"}, - {"amount": Decimal("-200000")}) - assert_array_result(self.nodes[0].listtransactions(), - {"txid": txid, "category": "receive"}, - {"amount": Decimal("200000")}) + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 200000) + assert_array_result( + self.nodes[0].listtransactions(), + {"txid": txid, "category": "send"}, + {"amount": Decimal("-200000")}, + ) + assert_array_result( + self.nodes[0].listtransactions(), + {"txid": txid, "category": "receive"}, + {"amount": Decimal("200000")}, + ) # sendmany from node1: twice to self, twice to node2: - send_to = {self.nodes[0].getnewaddress(): 110000, - self.nodes[1].getnewaddress(): 220000, - self.nodes[0].getnewaddress(): 330000, - self.nodes[1].getnewaddress(): 440000} + send_to = { + self.nodes[0].getnewaddress(): 110000, + self.nodes[1].getnewaddress(): 220000, + self.nodes[0].getnewaddress(): 330000, + self.nodes[1].getnewaddress(): 440000, + } txid = self.nodes[1].sendmany("", send_to) self.sync_all() - assert_array_result(self.nodes[1].listtransactions(), - {"category": "send", "amount": Decimal("-110000")}, - {"txid": txid}) - assert_array_result(self.nodes[0].listtransactions(), - {"category": "receive", - "amount": Decimal("110000")}, - {"txid": txid}) - assert_array_result(self.nodes[1].listtransactions(), - {"category": "send", "amount": Decimal("-220000")}, - {"txid": txid}) - assert_array_result(self.nodes[1].listtransactions(), - {"category": "receive", - "amount": Decimal("220000")}, - {"txid": txid}) - assert_array_result(self.nodes[1].listtransactions(), - {"category": "send", "amount": Decimal("-330000")}, - {"txid": txid}) - assert_array_result(self.nodes[0].listtransactions(), - {"category": "receive", - "amount": Decimal("330000")}, - {"txid": txid}) - assert_array_result(self.nodes[1].listtransactions(), - {"category": "send", "amount": Decimal("-440000")}, - {"txid": txid}) - assert_array_result(self.nodes[1].listtransactions(), - {"category": "receive", - "amount": Decimal("440000")}, - {"txid": txid}) + assert_array_result( + self.nodes[1].listtransactions(), + {"category": "send", "amount": Decimal("-110000")}, + {"txid": txid}, + ) + assert_array_result( + self.nodes[0].listtransactions(), + {"category": "receive", "amount": Decimal("110000")}, + {"txid": txid}, + ) + assert_array_result( + self.nodes[1].listtransactions(), + {"category": "send", "amount": Decimal("-220000")}, + {"txid": txid}, + ) + assert_array_result( + self.nodes[1].listtransactions(), + {"category": "receive", "amount": Decimal("220000")}, + {"txid": txid}, + ) + assert_array_result( + self.nodes[1].listtransactions(), + {"category": "send", "amount": Decimal("-330000")}, + {"txid": txid}, + ) + assert_array_result( + self.nodes[0].listtransactions(), + {"category": "receive", "amount": Decimal("330000")}, + {"txid": txid}, + ) + assert_array_result( + self.nodes[1].listtransactions(), + {"category": "send", "amount": Decimal("-440000")}, + {"txid": txid}, + ) + assert_array_result( + self.nodes[1].listtransactions(), + {"category": "receive", "amount": Decimal("440000")}, + {"txid": txid}, + ) if not self.options.descriptors: # include_watchonly is a legacy wallet feature, so don't test it # for descriptor wallets - pubkey = self.nodes[1].getaddressinfo( - self.nodes[1].getnewaddress())['pubkey'] + pubkey = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())[ + "pubkey" + ] multisig = self.nodes[1].createmultisig(1, [pubkey]) self.nodes[0].importaddress( - multisig["redeemScript"], "watchonly", False, True) + multisig["redeemScript"], "watchonly", False, True + ) txid = self.nodes[1].sendtoaddress(multisig["address"], 100000) self.generate(self.nodes[1], 1) - assert_equal(len(self.nodes[0].listtransactions( - label="watchonly", include_watchonly=True)), 1) - assert_equal(len(self.nodes[0].listtransactions( - dummy="watchonly", include_watchonly=True)), 1) - assert len( - self.nodes[0].listtransactions( - label="watchonly", - count=100, - include_watchonly=False)) == 0 + assert_equal( + len( + self.nodes[0].listtransactions( + label="watchonly", include_watchonly=True + ) + ), + 1, + ) + assert_equal( + len( + self.nodes[0].listtransactions( + dummy="watchonly", include_watchonly=True + ) + ), + 1, + ) + assert ( + len( + self.nodes[0].listtransactions( + label="watchonly", count=100, include_watchonly=False + ) + ) + == 0 + ) assert_array_result( - self.nodes[0].listtransactions(label="watchonly", count=100, - include_watchonly=True), + self.nodes[0].listtransactions( + label="watchonly", count=100, include_watchonly=True + ), {"category": "receive", "amount": Decimal("100000")}, - {"txid": txid, "label": "watchonly"}) + {"txid": txid, "label": "watchonly"}, + ) -if __name__ == '__main__': +if __name__ == "__main__": ListTransactionsTest().main() diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -21,7 +21,7 @@ got_loading_error = False -def test_load_unload(node, name, timeout=60.): +def test_load_unload(node, name, timeout=60.0): global got_loading_error t0 = time.time() while time.time() - t0 < timeout and not got_loading_error: @@ -29,8 +29,10 @@ node.loadwallet(name) node.unloadwallet(name) except JSONRPCException as e: - if e.error['code'] == - \ - 4 and 'Wallet already being loading' in e.error['message']: + if ( + e.error["code"] == -4 + and "Wallet already being loading" in e.error["message"] + ): got_loading_error = True return # Add a small sleep to avoid CPU exhaustion in the unlikely case @@ -49,55 +51,65 @@ def add_options(self, parser): parser.add_argument( - '--data_wallets_dir', + "--data_wallets_dir", default=os.path.join( - os.path.dirname( - os.path.realpath(__file__)), - 'data/wallets/'), - help='Test data with wallet directories (default: %(default)s)', + os.path.dirname(os.path.realpath(__file__)), "data/wallets/" + ), + help="Test data with wallet directories (default: %(default)s)", ) def run_test(self): node = self.nodes[0] - def data_dir(*p): return os.path.join(node.datadir, self.chain, *p) + def data_dir(*p): + return os.path.join(node.datadir, self.chain, *p) - def wallet_dir(*p): return data_dir('wallets', *p) + def wallet_dir(*p): + return data_dir("wallets", *p) - def wallet(name): return node.get_wallet_rpc(name) + def wallet(name): + return node.get_wallet_rpc(name) def wallet_file(name): if os.path.isdir(wallet_dir(name)): return wallet_dir(name, self.wallet_data_filename) return wallet_dir(name) - assert_equal(self.nodes[0].listwalletdir(), - {'wallets': [{'name': self.default_wallet_name}]}) + assert_equal( + self.nodes[0].listwalletdir(), + {"wallets": [{"name": self.default_wallet_name}]}, + ) # check wallet.dat is created self.stop_nodes() - assert_equal(os.path.isfile(wallet_dir(self.default_wallet_name, - self.wallet_data_filename)), - True) + assert_equal( + os.path.isfile( + wallet_dir(self.default_wallet_name, self.wallet_data_filename) + ), + True, + ) # create symlink to verify wallet directory path can be referenced # through symlink - if os.name != 'nt': - os.mkdir(wallet_dir('w7')) - os.symlink('w7', wallet_dir('w7_symlink')) + if os.name != "nt": + os.mkdir(wallet_dir("w7")) + os.symlink("w7", wallet_dir("w7_symlink")) # rename wallet.dat to make sure plain wallet file paths (as opposed to # directory paths) can be loaded - os.rename(wallet_dir(self.default_wallet_name, self.wallet_data_filename), - wallet_dir("w8")) + os.rename( + wallet_dir(self.default_wallet_name, self.wallet_data_filename), + wallet_dir("w8"), + ) # create another dummy wallet for use in testing backups later - self.start_node( - 0, ["-nowallet", f"-wallet={self.default_wallet_name}"]) + self.start_node(0, ["-nowallet", f"-wallet={self.default_wallet_name}"]) self.stop_nodes() - empty_wallet = os.path.join(self.options.tmpdir, 'empty.dat') - os.rename(wallet_dir(self.default_wallet_name, self.wallet_data_filename), - empty_wallet) + empty_wallet = os.path.join(self.options.tmpdir, "empty.dat") + os.rename( + wallet_dir(self.default_wallet_name, self.wallet_data_filename), + empty_wallet, + ) # restart node with a mix of wallet names: # w1, w2, w3 - to verify new wallets created when non-existing paths specified @@ -107,18 +119,35 @@ # w7_symlink - to verify symlinked wallet path is initialized correctly # w8 - to verify existing wallet file is loaded correctly # '' - to verify default wallet file is created correctly - wallet_names = ['w1', 'w2', 'w3', 'w', 'sub/w5', - os.path.join(self.options.tmpdir, 'extern/w6'), - 'w7_symlink', 'w8', self.default_wallet_name] - if os.name == 'nt': - wallet_names.remove('w7_symlink') - extra_args = ['-nowallet'] + \ - [f'-wallet={n}' for n in wallet_names] + wallet_names = [ + "w1", + "w2", + "w3", + "w", + "sub/w5", + os.path.join(self.options.tmpdir, "extern/w6"), + "w7_symlink", + "w8", + self.default_wallet_name, + ] + if os.name == "nt": + wallet_names.remove("w7_symlink") + extra_args = ["-nowallet"] + [f"-wallet={n}" for n in wallet_names] self.start_node(0, extra_args) assert_equal( - sorted(w['name'] for w in self.nodes[0].listwalletdir()['wallets']), - [self.default_wallet_name, os.path.join('sub', 'w5'), 'w', 'w1', - 'w2', 'w3', 'w7', 'w7_symlink', 'w8']) + sorted(w["name"] for w in self.nodes[0].listwalletdir()["wallets"]), + [ + self.default_wallet_name, + os.path.join("sub", "w5"), + "w", + "w1", + "w2", + "w3", + "w7", + "w7_symlink", + "w8", + ], + ) assert_equal(set(node.listwallets()), set(wallet_names)) @@ -129,106 +158,150 @@ # should not initialize if wallet path can't be created exp_stderr = ( - "filesystem error:" if sys.platform != 'win32' - else "create_directories:" + "filesystem error:" if sys.platform != "win32" else "create_directories:" ) self.nodes[0].assert_start_raises_init_error( - ['-wallet=w8/bad'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX) + ["-wallet=w8/bad"], exp_stderr, match=ErrorMatch.PARTIAL_REGEX + ) self.nodes[0].assert_start_raises_init_error( - ['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" does not exist') + ["-walletdir=wallets"], + 'Error: Specified -walletdir "wallets" does not exist', + ) self.nodes[0].assert_start_raises_init_error( - ['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" is a relative path', cwd=data_dir()) + ["-walletdir=wallets"], + 'Error: Specified -walletdir "wallets" is a relative path', + cwd=data_dir(), + ) self.nodes[0].assert_start_raises_init_error( - ['-walletdir=debug.log'], 'Error: Specified -walletdir "debug.log" is not a directory', cwd=data_dir()) + ["-walletdir=debug.log"], + 'Error: Specified -walletdir "debug.log" is not a directory', + cwd=data_dir(), + ) - self.start_node(0, ['-wallet=w1', '-wallet=w1']) - self.stop_node(0, 'Warning: Ignoring duplicate -wallet w1.') + self.start_node(0, ["-wallet=w1", "-wallet=w1"]) + self.stop_node(0, "Warning: Ignoring duplicate -wallet w1.") # should not initialize if one wallet is a copy of another - shutil.copyfile(wallet_dir('w8'), wallet_dir('w8_copy')) - exp_stderr = r"BerkeleyDatabase: Can't open database w8_copy \(duplicates fileid \w+ from w8\)" + shutil.copyfile(wallet_dir("w8"), wallet_dir("w8_copy")) + exp_stderr = ( + r"BerkeleyDatabase: Can't open database w8_copy \(duplicates fileid \w+" + r" from w8\)" + ) self.nodes[0].assert_start_raises_init_error( - ['-wallet=w8', '-wallet=w8_copy'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX) + ["-wallet=w8", "-wallet=w8_copy"], + exp_stderr, + match=ErrorMatch.PARTIAL_REGEX, + ) # should not initialize if wallet file is a symlink - if os.name != 'nt': - os.symlink('w8', wallet_dir('w8_symlink')) + if os.name != "nt": + os.symlink("w8", wallet_dir("w8_symlink")) self.nodes[0].assert_start_raises_init_error( - ['-wallet=w8_symlink'], r'Error: Invalid -wallet path \'w8_symlink\'\. .*', match=ErrorMatch.FULL_REGEX) + ["-wallet=w8_symlink"], + r"Error: Invalid -wallet path \'w8_symlink\'\. .*", + match=ErrorMatch.FULL_REGEX, + ) # should not initialize if the specified walletdir does not exist self.nodes[0].assert_start_raises_init_error( - ['-walletdir=bad'], 'Error: Specified -walletdir "bad" does not exist') + ["-walletdir=bad"], 'Error: Specified -walletdir "bad" does not exist' + ) # should not initialize if the specified walletdir is not a directory - not_a_dir = wallet_dir('notadir') - open(not_a_dir, 'a', encoding="utf8").close() + not_a_dir = wallet_dir("notadir") + open(not_a_dir, "a", encoding="utf8").close() self.nodes[0].assert_start_raises_init_error( - [f"-walletdir={not_a_dir}"], f"Error: Specified -walletdir \"{not_a_dir}\" is not a directory") + [f"-walletdir={not_a_dir}"], + f'Error: Specified -walletdir "{not_a_dir}" is not a directory', + ) # if wallets/ doesn't exist, datadir should be the default wallet dir - wallet_dir2 = data_dir('walletdir') + wallet_dir2 = data_dir("walletdir") os.rename(wallet_dir(), wallet_dir2) - self.start_node(0, ['-nowallet', '-wallet=w4', '-wallet=w5']) + self.start_node(0, ["-nowallet", "-wallet=w4", "-wallet=w5"]) assert_equal(set(node.listwallets()), {"w4", "w5"}) w5 = wallet("w5") self.generatetoaddress( - node, - nblocks=1, - address=w5.getnewaddress(), - sync_fun=self.no_op) + node, nblocks=1, address=w5.getnewaddress(), sync_fun=self.no_op + ) # now if wallets/ exists again, but the rootdir is specified as the # walletdir, w4 and w5 should still be loaded os.rename(wallet_dir2, wallet_dir()) - self.restart_node(0, ['-nowallet', '-wallet=w4', '-wallet=w5', - f"-walletdir={data_dir()}"]) + self.restart_node( + 0, ["-nowallet", "-wallet=w4", "-wallet=w5", f"-walletdir={data_dir()}"] + ) assert_equal(set(node.listwallets()), {"w4", "w5"}) w5 = wallet("w5") w5_info = w5.getwalletinfo() - assert_equal(w5_info['immature_balance'], 50000000) + assert_equal(w5_info["immature_balance"], 50000000) - competing_wallet_dir = os.path.join( - self.options.tmpdir, 'competing_walletdir') + competing_wallet_dir = os.path.join(self.options.tmpdir, "competing_walletdir") os.mkdir(competing_wallet_dir) self.restart_node(0, [f"-walletdir={competing_wallet_dir}"]) - exp_stderr = r"Error: Error initializing wallet database environment \"\S+competing_walletdir\"!" + exp_stderr = ( + r"Error: Error initializing wallet database environment" + r" \"\S+competing_walletdir\"!" + ) self.nodes[1].assert_start_raises_init_error( - [f"-walletdir={competing_wallet_dir}"], exp_stderr, match=ErrorMatch.PARTIAL_REGEX) + [f"-walletdir={competing_wallet_dir}"], + exp_stderr, + match=ErrorMatch.PARTIAL_REGEX, + ) self.restart_node(0, extra_args) assert_equal( - sorted(w['name'] for w in self.nodes[0].listwalletdir()['wallets']), - [self.default_wallet_name, os.path.join('sub', 'w5'), 'w', 'w1', 'w2', - 'w3', 'w7', 'w7_symlink', 'w8', 'w8_copy']) + sorted(w["name"] for w in self.nodes[0].listwalletdir()["wallets"]), + [ + self.default_wallet_name, + os.path.join("sub", "w5"), + "w", + "w1", + "w2", + "w3", + "w7", + "w7_symlink", + "w8", + "w8_copy", + ], + ) wallets = [wallet(w) for w in wallet_names] wallet_bad = wallet("bad") # check wallet names and balances self.generatetoaddress( - node, nblocks=1, address=wallets[0].getnewaddress(), sync_fun=self.no_op) + node, nblocks=1, address=wallets[0].getnewaddress(), sync_fun=self.no_op + ) for wallet_name, wallet in zip(wallet_names, wallets): info = wallet.getwalletinfo() - assert_equal(info['immature_balance'], - 50000000 if wallet is wallets[0] else 0) - assert_equal(info['walletname'], wallet_name) + assert_equal( + info["immature_balance"], 50000000 if wallet is wallets[0] else 0 + ) + assert_equal(info["walletname"], wallet_name) # accessing invalid wallet fails - assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", - wallet_bad.getwalletinfo) + assert_raises_rpc_error( + -18, + "Requested wallet does not exist or is not loaded", + wallet_bad.getwalletinfo, + ) # accessing wallet RPC without using wallet endpoint fails - assert_raises_rpc_error(-19, "Wallet file not specified (must request wallet RPC through /wallet/ uri-path).", - node.getwalletinfo) + assert_raises_rpc_error( + -19, + ( + "Wallet file not specified (must request wallet RPC through" + " /wallet/ uri-path)." + ), + node.getwalletinfo, + ) w1, w2, w3, w4, *_ = wallets self.generatetoaddress( - node, - nblocks=101, - address=w1.getnewaddress(), - sync_fun=self.no_op) + node, nblocks=101, address=w1.getnewaddress(), sync_fun=self.no_op + ) assert_equal(w1.getbalance(), 100000000) assert_equal(w2.getbalance(), 0) assert_equal(w3.getbalance(), 0) @@ -238,41 +311,42 @@ w1.sendtoaddress(w3.getnewaddress(), 2000000) w1.sendtoaddress(w4.getnewaddress(), 3000000) self.generatetoaddress( - node, - nblocks=1, - address=w1.getnewaddress(), - sync_fun=self.no_op) + node, nblocks=1, address=w1.getnewaddress(), sync_fun=self.no_op + ) assert_equal(w2.getbalance(), 1000000) assert_equal(w3.getbalance(), 2000000) assert_equal(w4.getbalance(), 3000000) - batch = w1.batch([w1.getblockchaininfo.get_request(), - w1.getwalletinfo.get_request()]) + batch = w1.batch( + [w1.getblockchaininfo.get_request(), w1.getwalletinfo.get_request()] + ) assert_equal(batch[0]["result"]["chain"], self.chain) assert_equal(batch[1]["result"]["walletname"], "w1") - self.log.info('Check for per-wallet settxfee call') - assert_equal(w1.getwalletinfo()['paytxfee'], 0) - assert_equal(w2.getwalletinfo()['paytxfee'], 0) + self.log.info("Check for per-wallet settxfee call") + assert_equal(w1.getwalletinfo()["paytxfee"], 0) + assert_equal(w2.getwalletinfo()["paytxfee"], 0) w2.settxfee(1000) - assert_equal(w1.getwalletinfo()['paytxfee'], 0) - assert_equal(w2.getwalletinfo()['paytxfee'], Decimal('1000.00')) + assert_equal(w1.getwalletinfo()["paytxfee"], 0) + assert_equal(w2.getwalletinfo()["paytxfee"], Decimal("1000.00")) self.log.info("Test dynamic wallet loading") - self.restart_node(0, ['-nowallet']) + self.restart_node(0, ["-nowallet"]) assert_equal(node.listwallets(), []) assert_raises_rpc_error( -18, - "No wallet is loaded. Load a wallet using loadwallet or create a new" - " one with createwallet. (Note: A default wallet is no longer " - "automatically created)", - node.getwalletinfo + ( + "No wallet is loaded. Load a wallet using loadwallet or create a new" + " one with createwallet. (Note: A default wallet is no longer " + "automatically created)" + ), + node.getwalletinfo, ) self.log.info("Load first wallet") loadwallet_name = node.loadwallet(wallet_names[0]) - assert_equal(loadwallet_name['name'], wallet_names[0]) + assert_equal(loadwallet_name["name"], wallet_names[0]) assert_equal(node.listwallets(), wallet_names[0:1]) node.getwalletinfo() w1 = node.get_wallet_rpc(wallet_names[0]) @@ -280,24 +354,26 @@ self.log.info("Load second wallet") loadwallet_name = node.loadwallet(wallet_names[1]) - assert_equal(loadwallet_name['name'], wallet_names[1]) + assert_equal(loadwallet_name["name"], wallet_names[1]) assert_equal(node.listwallets(), wallet_names[0:2]) - assert_raises_rpc_error(-19, - "Wallet file not specified", node.getwalletinfo) + assert_raises_rpc_error(-19, "Wallet file not specified", node.getwalletinfo) w2 = node.get_wallet_rpc(wallet_names[1]) w2.getwalletinfo() self.log.info("Concurrent wallet loading") threads = [] for _ in range(3): - n = node.cli if self.options.usecli else get_rpc_proxy( - node.url, 1, timeout=600, coveragedir=node.coverage_dir) + n = ( + node.cli + if self.options.usecli + else get_rpc_proxy( + node.url, 1, timeout=600, coveragedir=node.coverage_dir + ) + ) t = Thread( target=test_load_unload, - args=( - n, - wallet_names[2], - 20 * self.rpc_timeout)) + args=(n, wallet_names[2], 20 * self.rpc_timeout), + ) t.start() threads.append(t) for t in threads: @@ -308,18 +384,23 @@ self.log.info("Load remaining wallets") for wallet_name in wallet_names[2:]: loadwallet_name = self.nodes[0].loadwallet(wallet_name) - assert_equal(loadwallet_name['name'], wallet_name) + assert_equal(loadwallet_name["name"], wallet_name) assert_equal(set(self.nodes[0].listwallets()), set(wallet_names)) # Fail to load if wallet doesn't exist - path = os.path.join(self.options.tmpdir, "node0", "regtest", - "wallets", "wallets") + path = os.path.join( + self.options.tmpdir, "node0", "regtest", "wallets", "wallets" + ) assert_raises_rpc_error( -18, - f"Wallet file verification failed. Failed to load database path '{path}'. " - "Path does not exist.", - self.nodes[0].loadwallet, 'wallets') + ( + "Wallet file verification failed. Failed to load database path" + f" '{path}'. Path does not exist." + ), + self.nodes[0].loadwallet, + "wallets", + ) # Fail to load duplicate wallets path = os.path.join( @@ -328,13 +409,17 @@ "regtest", "wallets", "w1", - self.wallet_data_filename) + self.wallet_data_filename, + ) assert_raises_rpc_error( -4, - "Wallet file verification failed. Refusing to load database. " - f"Data file '{path}' is already loaded.", + ( + "Wallet file verification failed. Refusing to load database. " + f"Data file '{path}' is already loaded." + ), self.nodes[0].loadwallet, - wallet_names[0]) + wallet_names[0], + ) # Fail to load duplicate wallets by different ways (directory and # filepath) @@ -343,94 +428,122 @@ "node0", "regtest", "wallets", - self.wallet_data_filename) + self.wallet_data_filename, + ) assert_raises_rpc_error( -4, - "Wallet file verification failed. Refusing to load database. " - f"Data file '{path}' is already loaded.", + ( + "Wallet file verification failed. Refusing to load database. " + f"Data file '{path}' is already loaded." + ), self.nodes[0].loadwallet, - self.wallet_data_filename) + self.wallet_data_filename, + ) # Fail to load if one wallet is a copy of another - assert_raises_rpc_error(-4, "BerkeleyDatabase: Can't open database w8_copy (duplicates fileid", - self.nodes[0].loadwallet, 'w8_copy') + assert_raises_rpc_error( + -4, + "BerkeleyDatabase: Can't open database w8_copy (duplicates fileid", + self.nodes[0].loadwallet, + "w8_copy", + ) # Fail to load if one wallet is a copy of another. # Test this twice to make sure that we don't re-introduce # https://github.com/bitcoin/bitcoin/issues/14304 - assert_raises_rpc_error(-4, "BerkeleyDatabase: Can't open database w8_copy (duplicates fileid", - self.nodes[0].loadwallet, 'w8_copy') + assert_raises_rpc_error( + -4, + "BerkeleyDatabase: Can't open database w8_copy (duplicates fileid", + self.nodes[0].loadwallet, + "w8_copy", + ) # Fail to load if wallet file is a symlink - if os.name != 'nt': + if os.name != "nt": assert_raises_rpc_error( -4, "Wallet file verification failed. Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, - 'w8_symlink') + "w8_symlink", + ) # Fail to load if a directory is specified that doesn't contain a # wallet - os.mkdir(wallet_dir('empty_wallet_dir')) - path = os.path.join(self.options.tmpdir, "node0", "regtest", - "wallets", "empty_wallet_dir") + os.mkdir(wallet_dir("empty_wallet_dir")) + path = os.path.join( + self.options.tmpdir, "node0", "regtest", "wallets", "empty_wallet_dir" + ) assert_raises_rpc_error( -18, - f"Wallet file verification failed. Failed to load database path '{path}'. " - "Data is not in recognized format.", - self.nodes[0].loadwallet, 'empty_wallet_dir') + ( + "Wallet file verification failed. Failed to load database path" + f" '{path}'. Data is not in recognized format." + ), + self.nodes[0].loadwallet, + "empty_wallet_dir", + ) self.log.info("Test dynamic wallet creation.") # Fail to create a wallet if it already exists. - path = os.path.join(self.options.tmpdir, "node0", "regtest", - "wallets", "w2") + path = os.path.join(self.options.tmpdir, "node0", "regtest", "wallets", "w2") assert_raises_rpc_error( -4, f"Failed to create database path '{path}'. Database already exists.", - self.nodes[0].createwallet, 'w2') + self.nodes[0].createwallet, + "w2", + ) # Successfully create a wallet with a new name - loadwallet_name = self.nodes[0].createwallet('w9') - assert_equal(loadwallet_name['name'], 'w9') - w9 = node.get_wallet_rpc('w9') - assert_equal(w9.getwalletinfo()['walletname'], 'w9') + loadwallet_name = self.nodes[0].createwallet("w9") + assert_equal(loadwallet_name["name"], "w9") + w9 = node.get_wallet_rpc("w9") + assert_equal(w9.getwalletinfo()["walletname"], "w9") - assert 'w9' in self.nodes[0].listwallets() + assert "w9" in self.nodes[0].listwallets() # Successfully create a wallet using a full path - new_wallet_dir = os.path.join(self.options.tmpdir, 'new_walletdir') - new_wallet_name = os.path.join(new_wallet_dir, 'w10') + new_wallet_dir = os.path.join(self.options.tmpdir, "new_walletdir") + new_wallet_name = os.path.join(new_wallet_dir, "w10") loadwallet_name = self.nodes[0].createwallet(new_wallet_name) - assert_equal(loadwallet_name['name'], new_wallet_name) + assert_equal(loadwallet_name["name"], new_wallet_name) w10 = node.get_wallet_rpc(new_wallet_name) - assert_equal(w10.getwalletinfo()['walletname'], new_wallet_name) + assert_equal(w10.getwalletinfo()["walletname"], new_wallet_name) assert new_wallet_name in self.nodes[0].listwallets() self.log.info("Test dynamic wallet unloading") # Test `unloadwallet` errors - assert_raises_rpc_error(-1, "JSON value is not a string as expected", - self.nodes[0].unloadwallet) - assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", - self.nodes[0].unloadwallet, "dummy") - assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", - node.get_wallet_rpc("dummy").unloadwallet) - assert_raises_rpc_error(-8, "Cannot unload the requested wallet", - w1.unloadwallet, "w2"), + assert_raises_rpc_error( + -1, "JSON value is not a string as expected", self.nodes[0].unloadwallet + ) + assert_raises_rpc_error( + -18, + "Requested wallet does not exist or is not loaded", + self.nodes[0].unloadwallet, + "dummy", + ) + assert_raises_rpc_error( + -18, + "Requested wallet does not exist or is not loaded", + node.get_wallet_rpc("dummy").unloadwallet, + ) + assert_raises_rpc_error( + -8, "Cannot unload the requested wallet", w1.unloadwallet, "w2" + ), # Successfully unload the specified wallet name self.nodes[0].unloadwallet("w1") - assert 'w1' not in self.nodes[0].listwallets() + assert "w1" not in self.nodes[0].listwallets() # Successfully unload the wallet referenced by the request endpoint # Also ensure unload works during walletpassphrase timeout - w2.encryptwallet('test') - w2.walletpassphrase('test', 1) + w2.encryptwallet("test") + w2.walletpassphrase("test", 1) w2.unloadwallet() time.sleep(1.1) - assert 'w2' not in self.nodes[0].listwallets() + assert "w2" not in self.nodes[0].listwallets() # Successfully unload all wallets for wallet_name in self.nodes[0].listwallets(): @@ -438,50 +551,68 @@ assert_equal(self.nodes[0].listwallets(), []) assert_raises_rpc_error( -18, - "No wallet is loaded. Load a wallet using loadwallet or create a new" - " one with createwallet. (Note: A default wallet is no longer " - "automatically created)", - self.nodes[0].getwalletinfo + ( + "No wallet is loaded. Load a wallet using loadwallet or create a new" + " one with createwallet. (Note: A default wallet is no longer " + "automatically created)" + ), + self.nodes[0].getwalletinfo, ) # Successfully load a previously unloaded wallet - self.nodes[0].loadwallet('w1') - assert_equal(self.nodes[0].listwallets(), ['w1']) - assert_equal(w1.getwalletinfo()['walletname'], 'w1') + self.nodes[0].loadwallet("w1") + assert_equal(self.nodes[0].listwallets(), ["w1"]) + assert_equal(w1.getwalletinfo()["walletname"], "w1") assert_equal( - sorted(w['name'] for w in self.nodes[0].listwalletdir()['wallets']), - [self.default_wallet_name, os.path.join('sub', 'w5'), 'w', 'w1', 'w2', - 'w3', 'w7', 'w7_symlink', 'w8', 'w8_copy', 'w9']) + sorted(w["name"] for w in self.nodes[0].listwalletdir()["wallets"]), + [ + self.default_wallet_name, + os.path.join("sub", "w5"), + "w", + "w1", + "w2", + "w3", + "w7", + "w7_symlink", + "w8", + "w8_copy", + "w9", + ], + ) # Test backing up and restoring wallets self.log.info("Test wallet backup") - self.restart_node(0, ['-nowallet']) + self.restart_node(0, ["-nowallet"]) for wallet_name in wallet_names: self.nodes[0].loadwallet(wallet_name) for wallet_name in wallet_names: rpc = self.nodes[0].get_wallet_rpc(wallet_name) addr = rpc.getnewaddress() - backup = os.path.join(self.options.tmpdir, 'backup.dat') + backup = os.path.join(self.options.tmpdir, "backup.dat") rpc.backupwallet(backup) self.nodes[0].unloadwallet(wallet_name) shutil.copyfile(empty_wallet, wallet_file(wallet_name)) self.nodes[0].loadwallet(wallet_name) - assert_equal(rpc.getaddressinfo(addr)['ismine'], False) + assert_equal(rpc.getaddressinfo(addr)["ismine"], False) self.nodes[0].unloadwallet(wallet_name) shutil.copyfile(backup, wallet_file(wallet_name)) self.nodes[0].loadwallet(wallet_name) - assert_equal(rpc.getaddressinfo(addr)['ismine'], True) + assert_equal(rpc.getaddressinfo(addr)["ismine"], True) # Test .walletlock file is closed self.start_node(1) - wallet = os.path.join(self.options.tmpdir, 'my_wallet') + wallet = os.path.join(self.options.tmpdir, "my_wallet") self.nodes[0].createwallet(wallet) - assert_raises_rpc_error(-4, "Error initializing wallet database environment", - self.nodes[1].loadwallet, wallet) + assert_raises_rpc_error( + -4, + "Error initializing wallet database environment", + self.nodes[1].loadwallet, + wallet, + ) self.nodes[0].unloadwallet(wallet) self.nodes[1].loadwallet(wallet) -if __name__ == '__main__': +if __name__ == "__main__": MultiWalletTest().main() diff --git a/test/functional/wallet_reorgsrestore.py b/test/functional/wallet_reorgsrestore.py --- a/test/functional/wallet_reorgsrestore.py +++ b/test/functional/wallet_reorgsrestore.py @@ -32,7 +32,8 @@ def run_test(self): # Send a tx from which to conflict outputs later txid_conflict_from = self.nodes[0].sendtoaddress( - self.nodes[0].getnewaddress(), Decimal("10000000")) + self.nodes[0].getnewaddress(), Decimal("10000000") + ) self.generate(self.nodes[0], 1) # Disconnect node1 from others to reorg its chain later @@ -42,7 +43,8 @@ # Send a tx to be unconfirmed later txid = self.nodes[0].sendtoaddress( - self.nodes[0].getnewaddress(), Decimal("10000000")) + self.nodes[0].getnewaddress(), Decimal("10000000") + ) tx = self.nodes[0].gettransaction(txid) self.generate(self.nodes[0], 4, sync_fun=self.no_op) tx_before_reorg = self.nodes[0].gettransaction(txid) @@ -51,8 +53,11 @@ # Disconnect node0 from node2 to broadcast a conflict on their # respective chains self.disconnect_nodes(0, 2) - nA = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction( - txid_conflict_from)["details"] if tx_out["amount"] == Decimal("10000000")) + nA = next( + tx_out["vout"] + for tx_out in self.nodes[0].gettransaction(txid_conflict_from)["details"] + if tx_out["amount"] == Decimal("10000000") + ) inputs = [] inputs.append({"txid": txid_conflict_from, "vout": nA}) outputs_1 = {} @@ -63,9 +68,11 @@ outputs_1[self.nodes[0].getnewaddress()] = Decimal("9999980") outputs_2[self.nodes[0].getnewaddress()] = Decimal("9999980") conflicted = self.nodes[0].signrawtransactionwithwallet( - self.nodes[0].createrawtransaction(inputs, outputs_1)) + self.nodes[0].createrawtransaction(inputs, outputs_1) + ) conflicting = self.nodes[0].signrawtransactionwithwallet( - self.nodes[0].createrawtransaction(inputs, outputs_2)) + self.nodes[0].createrawtransaction(inputs, outputs_2) + ) conflicted_txid = self.nodes[0].sendrawtransaction(conflicted["hex"]) self.generate(self.nodes[0], 1, sync_fun=self.no_op) @@ -93,19 +100,16 @@ # Node0 wallet file is loaded on longest sync'ed node1 self.stop_node(1) - self.nodes[0].backupwallet( - os.path.join( - self.nodes[0].datadir, - 'wallet.bak')) + self.nodes[0].backupwallet(os.path.join(self.nodes[0].datadir, "wallet.bak")) shutil.copyfile( - os.path.join( - self.nodes[0].datadir, - 'wallet.bak'), + os.path.join(self.nodes[0].datadir, "wallet.bak"), os.path.join( self.nodes[1].datadir, self.chain, self.default_wallet_name, - self.wallet_data_filename)) + self.wallet_data_filename, + ), + ) self.start_node(1) tx_after_reorg = self.nodes[1].gettransaction(txid) # Check that normal confirmed tx is confirmed again but with different @@ -119,5 +123,5 @@ assert conflicting["blockhash"] != conflicted_after_reorg["blockhash"] -if __name__ == '__main__': +if __name__ == "__main__": ReorgsRestoreTest().main() diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py --- a/test/functional/wallet_resendwallettransactions.py +++ b/test/functional/wallet_resendwallettransactions.py @@ -47,8 +47,11 @@ # extra minute to be sure. block_time = int(time.time()) + 6 * 60 node.setmocktime(block_time) - block = create_block(int(node.getbestblockhash(), 16), create_coinbase( - node.getblockcount() + 1), block_time) + block = create_block( + int(node.getbestblockhash(), 16), + create_coinbase(node.getblockcount() + 1), + block_time, + ) block.rehash() block.solve() node.submitblock(ToHex(block)) @@ -70,7 +73,9 @@ self.log.info("Bump time & check that transaction is rebroadcast") # Transaction should be rebroadcast approximately 24 hours in the future, # but can range from 12-36. So bump 36 hours to be sure. - with node.assert_debug_log(['ResendWalletTransactions: resubmit 1 unconfirmed transactions']): + with node.assert_debug_log( + ["ResendWalletTransactions: resubmit 1 unconfirmed transactions"] + ): node.setmocktime(now + 36 * 60 * 60) # Tell scheduler to call MaybeResendWalletTxn now. node.mockscheduler(1) @@ -79,5 +84,5 @@ peer_second.wait_for_broadcast([txid]) -if __name__ == '__main__': +if __name__ == "__main__": ResendWalletTransactionsTest().main() diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py --- a/test/functional/wallet_send.py +++ b/test/functional/wallet_send.py @@ -21,27 +21,45 @@ self.num_nodes = 2 # whitelist all peers to speed up tx relay / mempool sync self.extra_args = [ - ["-whitelist=127.0.0.1", ], - ["-whitelist=127.0.0.1", ], + [ + "-whitelist=127.0.0.1", + ], + [ + "-whitelist=127.0.0.1", + ], ] def skip_test_if_missing_module(self): self.skip_if_no_wallet() - def test_send(self, from_wallet, to_wallet=None, amount=None, data=None, - add_to_wallet=None, psbt=None, inputs=None, add_inputs=None, - change_address=None, change_position=None, - include_watching=None, locktime=None, lock_unspents=None, - subtract_fee_from_outputs=None, fee_rate=None, - expect_error=None): + def test_send( + self, + from_wallet, + to_wallet=None, + amount=None, + data=None, + add_to_wallet=None, + psbt=None, + inputs=None, + add_inputs=None, + change_address=None, + change_position=None, + include_watching=None, + locktime=None, + lock_unspents=None, + subtract_fee_from_outputs=None, + fee_rate=None, + expect_error=None, + ): assert (amount is None) != (data is None) from_balance_before = from_wallet.getbalance() if to_wallet is None: assert amount is None else: - to_untrusted_pending_before = \ - to_wallet.getbalances()["mine"]["untrusted_pending"] + to_untrusted_pending_before = to_wallet.getbalances()["mine"][ + "untrusted_pending" + ] if amount: dest = to_wallet.getnewaddress() @@ -55,8 +73,7 @@ options["add_to_wallet"] = add_to_wallet else: add_to_wallet = ( - False if psbt else - from_wallet.getwalletinfo()["private_keys_enabled"] + False if psbt else from_wallet.getwalletinfo()["private_keys_enabled"] ) if psbt is not None: options["psbt"] = psbt @@ -83,21 +100,21 @@ options = None if expect_error is None: - res = from_wallet.send( - outputs=outputs, - options=options) + res = from_wallet.send(outputs=outputs, options=options) else: try: assert_raises_rpc_error( - expect_error[0], expect_error[1], from_wallet.send, - outputs=outputs, options=options) + expect_error[0], + expect_error[1], + from_wallet.send, + outputs=outputs, + options=options, + ) except AssertionError: # Provide debug info if the test fails self.log.error("Unexpected successful result:") self.log.error(options) - res = from_wallet.send( - outputs=outputs, - options=options) + res = from_wallet.send(outputs=outputs, options=options) self.log.error(res) if "txid" in res and add_to_wallet: self.log.error("Transaction details:") @@ -105,9 +122,9 @@ tx = from_wallet.gettransaction(res["txid"]) self.log.error(tx) self.log.error( - "testmempoolaccept (transaction may already be in mempool):") - self.log.error( - from_wallet.testmempoolaccept([tx["hex"]])) + "testmempoolaccept (transaction may already be in mempool):" + ) + self.log.error(from_wallet.testmempoolaccept([tx["hex"]])) except JSONRPCException as exc: self.log.error(exc) @@ -118,8 +135,7 @@ if locktime: return res - if (from_wallet.getwalletinfo()["private_keys_enabled"] - and not include_watching): + if from_wallet.getwalletinfo()["private_keys_enabled"] and not include_watching: assert_equal(res["complete"], True) assert "txid" in res else: @@ -136,18 +152,20 @@ assert tx if amount: if subtract_fee_from_outputs: - assert_equal( - from_balance_before - - from_wallet.getbalance(), - amount) + assert_equal(from_balance_before - from_wallet.getbalance(), amount) else: assert_greater_than( - from_balance_before - from_wallet.getbalance(), amount) + from_balance_before - from_wallet.getbalance(), amount + ) else: assert next( - (out for out in tx["vout"] if out["scriptPubKey"] - ["asm"] == "OP_RETURN 35"), - None) + ( + out + for out in tx["vout"] + if out["scriptPubKey"]["asm"] == "OP_RETURN 35" + ), + None, + ) else: assert_equal(from_balance_before, from_wallet.getbalance()) @@ -157,13 +175,13 @@ if not subtract_fee_from_outputs: assert_equal( to_wallet.getbalances()["mine"]["untrusted_pending"], - to_untrusted_pending_before + - Decimal( - amount if amount else 0)) + to_untrusted_pending_before + Decimal(amount if amount else 0), + ) else: assert_equal( to_wallet.getbalances()["mine"]["untrusted_pending"], - to_untrusted_pending_before) + to_untrusted_pending_before, + ) return res @@ -184,18 +202,23 @@ a2_receive = w2.getnewaddress() # doesn't actually use change derivation a2_change = w2.getrawchangeaddress() - res = w3.importmulti([{ - "desc": w2.getaddressinfo(a2_receive)["desc"], - "timestamp": "now", - "keypool": True, - "watchonly": True - }, { - "desc": w2.getaddressinfo(a2_change)["desc"], - "timestamp": "now", - "keypool": True, - "internal": True, - "watchonly": True - }]) + res = w3.importmulti( + [ + { + "desc": w2.getaddressinfo(a2_receive)["desc"], + "timestamp": "now", + "keypool": True, + "watchonly": True, + }, + { + "desc": w2.getaddressinfo(a2_change)["desc"], + "timestamp": "now", + "keypool": True, + "internal": True, + "watchonly": True, + }, + ] + ) assert_equal(res, [{"success": True}, {"success": True}]) # fund w3 @@ -204,18 +227,20 @@ # w4 has private keys enabled, but only contains watch-only keys (from # w2) - self.nodes[1].createwallet( - wallet_name="w4", - disable_private_keys=False) + self.nodes[1].createwallet(wallet_name="w4", disable_private_keys=False) w4 = self.nodes[1].get_wallet_rpc("w4") for _ in range(3): a2_receive = w2.getnewaddress() - res = w4.importmulti([{ - "desc": w2.getaddressinfo(a2_receive)["desc"], - "timestamp": "now", - "keypool": False, - "watchonly": True - }]) + res = w4.importmulti( + [ + { + "desc": w2.getaddressinfo(a2_receive)["desc"], + "timestamp": "now", + "keypool": False, + "watchonly": True, + } + ] + ) assert_equal(res, [{"success": True}]) # fund w4 @@ -225,34 +250,25 @@ self.log.info("Send to address...") self.test_send(from_wallet=w0, to_wallet=w1, amount=1_000_000) self.test_send( - from_wallet=w0, - to_wallet=w1, - amount=1_000_000, - add_to_wallet=True) + from_wallet=w0, to_wallet=w1, amount=1_000_000, add_to_wallet=True + ) self.log.info("Don't broadcast...") res = self.test_send( - from_wallet=w0, - to_wallet=w1, - amount=1_000_000, - add_to_wallet=False) + from_wallet=w0, to_wallet=w1, amount=1_000_000, add_to_wallet=False + ) assert res["hex"] self.log.info("Return PSBT...") - res = self.test_send( - from_wallet=w0, - to_wallet=w1, - amount=1_000_000, - psbt=True) + res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1_000_000, psbt=True) assert res["psbt"] self.log.info( - "Create transaction that spends to address, but don't broadcast...") + "Create transaction that spends to address, but don't broadcast..." + ) self.test_send( - from_wallet=w0, - to_wallet=w1, - amount=1_000_000, - add_to_wallet=False) + from_wallet=w0, to_wallet=w1, amount=1_000_000, add_to_wallet=False + ) self.log.info("Create PSBT from watch-only wallet w3, sign with w2...") res = self.test_send(from_wallet=w3, to_wallet=w1, amount=1_000_000) @@ -260,24 +276,31 @@ assert res["complete"] self.log.info( - "Create PSBT from wallet w4 with watch-only keys, sign with w2...") - self.test_send(from_wallet=w4, to_wallet=w1, amount=1_000_000, - expect_error=(-4, "Insufficient funds")) + "Create PSBT from wallet w4 with watch-only keys, sign with w2..." + ) + self.test_send( + from_wallet=w4, + to_wallet=w1, + amount=1_000_000, + expect_error=(-4, "Insufficient funds"), + ) res = self.test_send( from_wallet=w4, to_wallet=w1, amount=1_000_000, include_watching=True, - add_to_wallet=False) + add_to_wallet=False, + ) res = w2.walletprocesspsbt(res["psbt"]) assert res["complete"] self.log.info("Create OP_RETURN...") self.test_send(from_wallet=w0, to_wallet=w1, amount=1_000_000) - self.test_send(from_wallet=w0, - data="Hello World", - expect_error=(-8, - "Data must be hexadecimal string (not 'Hello World')")) + self.test_send( + from_wallet=w0, + data="Hello World", + expect_error=(-8, "Data must be hexadecimal string (not 'Hello World')"), + ) self.test_send(from_wallet=w0, data="23") res = self.test_send(from_wallet=w3, data="23") res = w2.walletprocesspsbt(res["psbt"]) @@ -289,17 +312,31 @@ to_wallet=w1, amount=1_000_000, fee_rate=Decimal("20.00"), - add_to_wallet=False) + add_to_wallet=False, + ) fee = self.nodes[1].decodepsbt(res["psbt"])["fee"] - assert_fee_amount(fee, - len(res["hex"]) // 2, - Decimal("20.00")) - self.test_send(from_wallet=w0, to_wallet=w1, amount=1_000_000, fee_rate=-1, - expect_error=(-3, "Amount out of range")) + assert_fee_amount(fee, len(res["hex"]) // 2, Decimal("20.00")) + self.test_send( + from_wallet=w0, + to_wallet=w1, + amount=1_000_000, + fee_rate=-1, + expect_error=(-3, "Amount out of range"), + ) # Fee rate of 0.1 satoshi per byte should throw an error - self.test_send(from_wallet=w0, to_wallet=w1, amount=1_000_000, - fee_rate=Decimal("1.00"), - expect_error=(-4, "Fee rate (1.00 XEC/kB) is lower than the minimum fee rate setting (10.00 XEC/kB)")) + self.test_send( + from_wallet=w0, + to_wallet=w1, + amount=1_000_000, + fee_rate=Decimal("1.00"), + expect_error=( + -4, + ( + "Fee rate (1.00 XEC/kB) is lower than the minimum fee rate setting" + " (10.00 XEC/kB)" + ), + ), + ) # TODO: Return hex if fee rate is below -maxmempool # res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1_000_000, @@ -311,41 +348,58 @@ # assert_equal(res[0]["reject-reason"], "...") # low fee # assert_fee_amount(fee, Decimal(len(res["hex"]) / 2), Decimal("1.00")) - self.log.info( - "If inputs are specified, do not automatically add more...") + self.log.info("If inputs are specified, do not automatically add more...") res = self.test_send( from_wallet=w0, to_wallet=w1, amount=51_000_000, inputs=[], - add_to_wallet=False) + add_to_wallet=False, + ) assert res["complete"] utxo1 = w0.listunspent()[0] assert_equal(utxo1["amount"], 50_000_000) - self.test_send(from_wallet=w0, to_wallet=w1, amount=51_000_000, - inputs=[utxo1], expect_error=(-4, "Insufficient funds")) - self.test_send(from_wallet=w0, to_wallet=w1, amount=51_000_000, - inputs=[utxo1], add_inputs=False, - expect_error=(-4, "Insufficient funds")) + self.test_send( + from_wallet=w0, + to_wallet=w1, + amount=51_000_000, + inputs=[utxo1], + expect_error=(-4, "Insufficient funds"), + ) + self.test_send( + from_wallet=w0, + to_wallet=w1, + amount=51_000_000, + inputs=[utxo1], + add_inputs=False, + expect_error=(-4, "Insufficient funds"), + ) res = self.test_send( from_wallet=w0, to_wallet=w1, amount=51_000_000, inputs=[utxo1], add_inputs=True, - add_to_wallet=False) + add_to_wallet=False, + ) assert res["complete"] self.log.info("Manual change address and position...") - self.test_send(from_wallet=w0, to_wallet=w1, amount=1_000_000, change_address="not an address", - expect_error=(-5, "Change address must be a valid bitcoin address")) + self.test_send( + from_wallet=w0, + to_wallet=w1, + amount=1_000_000, + change_address="not an address", + expect_error=(-5, "Change address must be a valid bitcoin address"), + ) change_address = w0.getnewaddress() self.test_send( from_wallet=w0, to_wallet=w1, amount=1_000_000, add_to_wallet=False, - change_address=change_address) + change_address=change_address, + ) assert res["complete"] res = self.test_send( from_wallet=w0, @@ -353,20 +407,21 @@ amount=1_000_000, add_to_wallet=False, change_address=change_address, - change_position=0) + change_position=0, + ) assert res["complete"] assert_equal( - self.nodes[0].decodepsbt( - res["psbt"])["tx"]["vout"][0]["scriptPubKey"]["addresses"], - [change_address]) + self.nodes[0].decodepsbt(res["psbt"])["tx"]["vout"][0]["scriptPubKey"][ + "addresses" + ], + [change_address], + ) self.log.info("Set lock time...") height = self.nodes[0].getblockchaininfo()["blocks"] res = self.test_send( - from_wallet=w0, - to_wallet=w1, - amount=1_000_000, - locktime=height + 1) + from_wallet=w0, to_wallet=w1, amount=1_000_000, locktime=height + 1 + ) assert res["complete"] assert res["txid"] txid = res["txid"] @@ -396,7 +451,8 @@ amount=1_000_000, inputs=[utxo1], add_to_wallet=False, - lock_unspents=True) + lock_unspents=True, + ) assert res["complete"] locked_coins = w0.listlockunspent() assert_equal(len(locked_coins), 1) @@ -406,7 +462,8 @@ to_wallet=w1, amount=1_000_000, inputs=[utxo1], - add_to_wallet=False) + add_to_wallet=False, + ) assert res["complete"] self.log.info("Subtract fee from output") @@ -414,8 +471,9 @@ from_wallet=w0, to_wallet=w1, amount=1_000_000, - subtract_fee_from_outputs=[0]) + subtract_fee_from_outputs=[0], + ) -if __name__ == '__main__': +if __name__ == "__main__": WalletSendTest().main() diff --git a/test/functional/wallet_startup.py b/test/functional/wallet_startup.py --- a/test/functional/wallet_startup.py +++ b/test/functional/wallet_startup.py @@ -24,36 +24,36 @@ self.start_nodes() def run_test(self): - self.log.info('Should start without any wallets') + self.log.info("Should start without any wallets") assert_equal(self.nodes[0].listwallets(), []) - assert_equal(self.nodes[0].listwalletdir(), {'wallets': []}) + assert_equal(self.nodes[0].listwalletdir(), {"wallets": []}) self.log.info( - 'New default wallet should load by default when there are no other wallets') - self.nodes[0].createwallet(wallet_name='', load_on_startup=False) + "New default wallet should load by default when there are no other wallets" + ) + self.nodes[0].createwallet(wallet_name="", load_on_startup=False) self.restart_node(0) - assert_equal(self.nodes[0].listwallets(), ['']) - - self.log.info('Test load on startup behavior') - self.nodes[0].createwallet(wallet_name='w0', load_on_startup=True) - self.nodes[0].createwallet(wallet_name='w1', load_on_startup=False) - self.nodes[0].createwallet(wallet_name='w2', load_on_startup=True) - self.nodes[0].createwallet(wallet_name='w3', load_on_startup=False) - self.nodes[0].createwallet(wallet_name='w4', load_on_startup=False) - self.nodes[0].unloadwallet(wallet_name='w0', load_on_startup=False) - self.nodes[0].unloadwallet(wallet_name='w4', load_on_startup=False) - self.nodes[0].loadwallet(filename='w4', load_on_startup=True) - assert_equal(set(self.nodes[0].listwallets()), - {'', 'w1', 'w2', 'w3', 'w4'}) + assert_equal(self.nodes[0].listwallets(), [""]) + + self.log.info("Test load on startup behavior") + self.nodes[0].createwallet(wallet_name="w0", load_on_startup=True) + self.nodes[0].createwallet(wallet_name="w1", load_on_startup=False) + self.nodes[0].createwallet(wallet_name="w2", load_on_startup=True) + self.nodes[0].createwallet(wallet_name="w3", load_on_startup=False) + self.nodes[0].createwallet(wallet_name="w4", load_on_startup=False) + self.nodes[0].unloadwallet(wallet_name="w0", load_on_startup=False) + self.nodes[0].unloadwallet(wallet_name="w4", load_on_startup=False) + self.nodes[0].loadwallet(filename="w4", load_on_startup=True) + assert_equal(set(self.nodes[0].listwallets()), {"", "w1", "w2", "w3", "w4"}) self.restart_node(0) - assert_equal(set(self.nodes[0].listwallets()), {'', 'w2', 'w4'}) - self.nodes[0].unloadwallet(wallet_name='', load_on_startup=False) - self.nodes[0].unloadwallet(wallet_name='w4', load_on_startup=False) - self.nodes[0].loadwallet(filename='w3', load_on_startup=True) - self.nodes[0].loadwallet(filename='') + assert_equal(set(self.nodes[0].listwallets()), {"", "w2", "w4"}) + self.nodes[0].unloadwallet(wallet_name="", load_on_startup=False) + self.nodes[0].unloadwallet(wallet_name="w4", load_on_startup=False) + self.nodes[0].loadwallet(filename="w3", load_on_startup=True) + self.nodes[0].loadwallet(filename="") self.restart_node(0) - assert_equal(set(self.nodes[0].listwallets()), {'w2', 'w3'}) + assert_equal(set(self.nodes[0].listwallets()), {"w2", "w3"}) -if __name__ == '__main__': +if __name__ == "__main__": WalletStartupTest().main() diff --git a/test/functional/wallet_timelock.py b/test/functional/wallet_timelock.py --- a/test/functional/wallet_timelock.py +++ b/test/functional/wallet_timelock.py @@ -30,8 +30,7 @@ ) self.generate(node, 1, sync_fun=self.no_op) - self.log.info( - "Check that clock can not change finality of confirmed txs") + self.log.info("Check that clock can not change finality of confirmed txs") amount_before_ad = node.getreceivedbyaddress(address) amount_before_lb = node.getreceivedbylabel(label) list_before_ad = node.listreceivedbyaddress(address_filter=address) @@ -41,14 +40,8 @@ node.setmocktime(mtp_tip - 1) assert_equal(node.getreceivedbyaddress(address), amount_before_ad) assert_equal(node.getreceivedbylabel(label), amount_before_lb) - assert_equal( - node.listreceivedbyaddress( - address_filter=address), - list_before_ad) - assert_equal( - node.listreceivedbylabel( - include_empty=False), - list_before_lb) + assert_equal(node.listreceivedbyaddress(address_filter=address), list_before_ad) + assert_equal(node.listreceivedbylabel(include_empty=False), list_before_lb) assert_equal(node.getbalances()["mine"]["trusted"], balance_before) assert_equal(node.listunspent(maxconf=1), coin_before) diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py --- a/test/functional/wallet_txn_clone.py +++ b/test/functional/wallet_txn_clone.py @@ -21,8 +21,13 @@ self.skip_if_no_wallet() def add_options(self, parser): - parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true", - help="Test double-spend of 1-confirmed transaction") + parser.add_argument( + "--mineblock", + dest="mine_block", + default=False, + action="store_true", + help="Test double-spend of 1-confirmed transaction", + ) def setup_network(self): # Start with split network: @@ -47,8 +52,10 @@ node0_txid2 = self.nodes[0].sendtoaddress(node0_address2, 29000000) node0_tx2 = self.nodes[0].gettransaction(node0_txid2) - assert_equal(self.nodes[0].getbalance(), - starting_balance + node0_tx1["fee"] + node0_tx2["fee"]) + assert_equal( + self.nodes[0].getbalance(), + starting_balance + node0_tx1["fee"] + node0_tx2["fee"], + ) # Coins are sent to node1_address node1_address = self.nodes[1].getnewaddress() @@ -59,36 +66,50 @@ # Construct a clone of tx1, to be malleated rawtx1 = self.nodes[0].getrawtransaction(txid1, 1) - clone_inputs = [{"txid": rawtx1["vin"][0]["txid"], - "vout": rawtx1["vin"][0]["vout"], - "sequence": rawtx1["vin"][0]["sequence"]}] - clone_outputs = {rawtx1["vout"][0]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][0]["value"], - rawtx1["vout"][1]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][1]["value"]} + clone_inputs = [ + { + "txid": rawtx1["vin"][0]["txid"], + "vout": rawtx1["vin"][0]["vout"], + "sequence": rawtx1["vin"][0]["sequence"], + } + ] + clone_outputs = { + rawtx1["vout"][0]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][0][ + "value" + ], + rawtx1["vout"][1]["scriptPubKey"]["addresses"][0]: rawtx1["vout"][1][ + "value" + ], + } clone_locktime = rawtx1["locktime"] clone_raw = self.nodes[0].createrawtransaction( - clone_inputs, clone_outputs, clone_locktime) + clone_inputs, clone_outputs, clone_locktime + ) # createrawtransaction randomizes the order of its outputs, so swap # them if necessary. clone_tx = CTransaction() clone_tx.deserialize(io.BytesIO(bytes.fromhex(clone_raw))) - if (rawtx1["vout"][0]["value"] == 40000000 and - clone_tx.vout[0].nValue != 40000000 * XEC or - rawtx1["vout"][0]["value"] != 40000000 and - clone_tx.vout[0].nValue == 40000000 * XEC): - (clone_tx.vout[0], clone_tx.vout[1]) = (clone_tx.vout[1], - clone_tx.vout[0]) + if ( + rawtx1["vout"][0]["value"] == 40000000 + and clone_tx.vout[0].nValue != 40000000 * XEC + or rawtx1["vout"][0]["value"] != 40000000 + and clone_tx.vout[0].nValue == 40000000 * XEC + ): + (clone_tx.vout[0], clone_tx.vout[1]) = (clone_tx.vout[1], clone_tx.vout[0]) # Use a different signature hash type to sign. This creates an equivalent but malleated clone. # Don't send the clone anywhere yet tx1_clone = self.nodes[0].signrawtransactionwithwallet( - clone_tx.serialize().hex(), None, "ALL|FORKID|ANYONECANPAY") + clone_tx.serialize().hex(), None, "ALL|FORKID|ANYONECANPAY" + ) assert_equal(tx1_clone["complete"], True) # Have node0 mine a block, if requested: - if (self.options.mine_block): + if self.options.mine_block: self.generate( - self.nodes[0], 1, sync_fun=lambda: self.sync_blocks(self.nodes[0:2])) + self.nodes[0], 1, sync_fun=lambda: self.sync_blocks(self.nodes[0:2]) + ) tx1 = self.nodes[0].gettransaction(txid1) tx2 = self.nodes[0].gettransaction(txid2) @@ -136,10 +157,10 @@ # Check node0's total balance; should be same as before the clone, + # 100,000,000 XEC for 2 matured, less possible orphaned matured subsidy expected += 100000000 - if (self.options.mine_block): + if self.options.mine_block: expected -= 50000000 assert_equal(self.nodes[0].getbalance(), expected) -if __name__ == '__main__': +if __name__ == "__main__": TxnMallTest().main() diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py --- a/test/functional/wallet_txn_doublespend.py +++ b/test/functional/wallet_txn_doublespend.py @@ -19,8 +19,13 @@ self.skip_if_no_wallet() def add_options(self, parser): - parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true", - help="Test double-spend of 1-confirmed transaction") + parser.add_argument( + "--mineblock", + dest="mine_block", + default=False, + action="store_true", + help="Test double-spend of 1-confirmed transaction", + ) def setup_network(self): # Start with split network: @@ -43,32 +48,30 @@ # Assign coins to foo and bar addresses: node0_address_foo = self.nodes[0].getnewaddress() - fund_foo_txid = self.nodes[0].sendtoaddress( - node0_address_foo, 1219000000) + fund_foo_txid = self.nodes[0].sendtoaddress(node0_address_foo, 1219000000) fund_foo_tx = self.nodes[0].gettransaction(fund_foo_txid) node0_address_bar = self.nodes[0].getnewaddress() - fund_bar_txid = self.nodes[0].sendtoaddress( - node0_address_bar, 29000000) + fund_bar_txid = self.nodes[0].sendtoaddress(node0_address_bar, 29000000) fund_bar_tx = self.nodes[0].gettransaction(fund_bar_txid) - assert_equal(self.nodes[0].getbalance(), - starting_balance + fund_foo_tx["fee"] + fund_bar_tx["fee"]) + assert_equal( + self.nodes[0].getbalance(), + starting_balance + fund_foo_tx["fee"] + fund_bar_tx["fee"], + ) # Coins are sent to node1_address node1_address = self.nodes[1].getnewaddress() # First: use raw transaction API to send 1,240,000,000 XEC to # node1_address, but don't broadcast: - doublespend_fee = Decimal('-20000') + doublespend_fee = Decimal("-20000") rawtx_input_0 = {} rawtx_input_0["txid"] = fund_foo_txid - rawtx_input_0["vout"] = find_output( - self.nodes[0], fund_foo_txid, 1219000000) + rawtx_input_0["vout"] = find_output(self.nodes[0], fund_foo_txid, 1219000000) rawtx_input_1 = {} rawtx_input_1["txid"] = fund_bar_txid - rawtx_input_1["vout"] = find_output( - self.nodes[0], fund_bar_txid, 29000000) + rawtx_input_1["vout"] = find_output(self.nodes[0], fund_bar_txid, 29000000) inputs = [rawtx_input_0, rawtx_input_1] change_address = self.nodes[0].getnewaddress() outputs = {} @@ -83,9 +86,10 @@ txid2 = self.nodes[0].sendtoaddress(node1_address, 20000000) # Have node0 mine a block: - if (self.options.mine_block): + if self.options.mine_block: self.generate( - self.nodes[0], 1, sync_fun=lambda: self.sync_blocks(self.nodes[0:2])) + self.nodes[0], 1, sync_fun=lambda: self.sync_blocks(self.nodes[0:2]) + ) tx1 = self.nodes[0].gettransaction(txid1) tx2 = self.nodes[0].gettransaction(txid2) @@ -104,8 +108,10 @@ assert_equal(tx1["confirmations"], 1) assert_equal(tx2["confirmations"], 1) # Node1's balance should be both transaction amounts: - assert_equal(self.nodes[1].getbalance( - ), starting_balance - tx1["amount"] - tx2["amount"]) + assert_equal( + self.nodes[1].getbalance(), + starting_balance - tx1["amount"] - tx2["amount"], + ) else: assert_equal(tx1["confirmations"], 0) assert_equal(tx2["confirmations"], 0) @@ -121,8 +127,7 @@ self.connect_nodes(1, 2) # Mine another block to make sure we sync self.generate(self.nodes[2], 1) - assert_equal(self.nodes[0].gettransaction( - doublespend_txid)["confirmations"], 2) + assert_equal(self.nodes[0].gettransaction(doublespend_txid)["confirmations"], 2) # Re-fetch transaction info: tx1 = self.nodes[0].gettransaction(txid1) @@ -135,8 +140,14 @@ # Node0's total balance should be starting balance, plus 100BTC for # two more matured blocks, minus 1240 for the double-spend, plus fees (which are # negative): - expected = starting_balance + 100000000 - 1240000000 + \ - fund_foo_tx["fee"] + fund_bar_tx["fee"] + doublespend_fee + expected = ( + starting_balance + + 100000000 + - 1240000000 + + fund_foo_tx["fee"] + + fund_bar_tx["fee"] + + doublespend_fee + ) assert_equal(self.nodes[0].getbalance(), expected) # Node1's balance should be its initial balance (1250 for 25 block @@ -144,5 +155,5 @@ assert_equal(self.nodes[1].getbalance(), 1250000000 + 1240000000) -if __name__ == '__main__': +if __name__ == "__main__": TxnMallTest().main() diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py --- a/test/functional/wallet_watchonly.py +++ b/test/functional/wallet_watchonly.py @@ -19,20 +19,18 @@ def run_test(self): node = self.nodes[0] - self.nodes[0].createwallet(wallet_name='default') - def_wallet = node.get_wallet_rpc('default') + self.nodes[0].createwallet(wallet_name="default") + def_wallet = node.get_wallet_rpc("default") a1 = def_wallet.getnewaddress() wo_change = def_wallet.getnewaddress() wo_addr = def_wallet.getnewaddress() - self.nodes[0].createwallet(wallet_name='wo', disable_private_keys=True) - wo_wallet = node.get_wallet_rpc('wo') + self.nodes[0].createwallet(wallet_name="wo", disable_private_keys=True) + wo_wallet = node.get_wallet_rpc("wo") - wo_wallet.importpubkey( - pubkey=def_wallet.getaddressinfo(wo_addr)['pubkey']) - wo_wallet.importpubkey( - pubkey=def_wallet.getaddressinfo(wo_change)['pubkey']) + wo_wallet.importpubkey(pubkey=def_wallet.getaddressinfo(wo_addr)["pubkey"]) + wo_wallet.importpubkey(pubkey=def_wallet.getaddressinfo(wo_change)["pubkey"]) # generate some btc for testing self.generatetoaddress(node, 101, a1) @@ -42,74 +40,74 @@ self.generate(self.nodes[0], 1) # getbalance - self.log.info( - 'include_watchonly should default to true for watch-only wallets') - self.log.info('Testing getbalance watch-only defaults') + self.log.info("include_watchonly should default to true for watch-only wallets") + self.log.info("Testing getbalance watch-only defaults") assert_equal(wo_wallet.getbalance(), 1000000) assert_equal(len(wo_wallet.listtransactions()), 1) assert_equal(wo_wallet.getbalance(include_watchonly=False), 0) - self.log.info('Testing listreceivedbyaddress watch-only defaults') + self.log.info("Testing listreceivedbyaddress watch-only defaults") result = wo_wallet.listreceivedbyaddress() assert_equal(len(result), 1) assert_equal(result[0]["involvesWatchonly"], True) result = wo_wallet.listreceivedbyaddress(include_watchonly=False) assert_equal(len(result), 0) - self.log.info('Testing listreceivedbylabel watch-only defaults') + self.log.info("Testing listreceivedbylabel watch-only defaults") result = wo_wallet.listreceivedbylabel() assert_equal(len(result), 1) assert_equal(result[0]["involvesWatchonly"], True) result = wo_wallet.listreceivedbylabel(include_watchonly=False) assert_equal(len(result), 0) - self.log.info('Testing listtransactions watch-only defaults') + self.log.info("Testing listtransactions watch-only defaults") result = wo_wallet.listtransactions() assert_equal(len(result), 1) assert_equal(result[0]["involvesWatchonly"], True) result = wo_wallet.listtransactions(include_watchonly=False) assert_equal(len(result), 0) - self.log.info('Testing listsinceblock watch-only defaults') + self.log.info("Testing listsinceblock watch-only defaults") result = wo_wallet.listsinceblock() assert_equal(len(result["transactions"]), 1) assert_equal(result["transactions"][0]["involvesWatchonly"], True) result = wo_wallet.listsinceblock(include_watchonly=False) assert_equal(len(result["transactions"]), 0) - self.log.info('Testing gettransaction watch-only defaults') + self.log.info("Testing gettransaction watch-only defaults") result = wo_wallet.gettransaction(txid) assert_equal(result["details"][0]["involvesWatchonly"], True) result = wo_wallet.gettransaction(txid=txid, include_watchonly=False) assert_equal(len(result["details"]), 0) - self.log.info('Testing walletcreatefundedpsbt watch-only defaults') + self.log.info("Testing walletcreatefundedpsbt watch-only defaults") inputs = [] outputs = [{a1: 500000}] - options = {'changeAddress': wo_change} - no_wo_options = {'changeAddress': wo_change, 'includeWatching': False} + options = {"changeAddress": wo_change} + no_wo_options = {"changeAddress": wo_change, "includeWatching": False} result = wo_wallet.walletcreatefundedpsbt( - inputs=inputs, outputs=outputs, options=options) + inputs=inputs, outputs=outputs, options=options + ) assert_equal("psbt" in result, True) - assert_raises_rpc_error(-4, - "Insufficient funds", - wo_wallet.walletcreatefundedpsbt, - inputs, - outputs, - 0, - no_wo_options) - - self.log.info('Testing fundrawtransaction watch-only defaults') + assert_raises_rpc_error( + -4, + "Insufficient funds", + wo_wallet.walletcreatefundedpsbt, + inputs, + outputs, + 0, + no_wo_options, + ) + + self.log.info("Testing fundrawtransaction watch-only defaults") rawtx = wo_wallet.createrawtransaction(inputs=inputs, outputs=outputs) result = wo_wallet.fundrawtransaction(hexstring=rawtx, options=options) assert_equal("hex" in result, True) - assert_raises_rpc_error(-4, - "Insufficient funds", - wo_wallet.fundrawtransaction, - rawtx, - no_wo_options) + assert_raises_rpc_error( + -4, "Insufficient funds", wo_wallet.fundrawtransaction, rawtx, no_wo_options + ) -if __name__ == '__main__': +if __name__ == "__main__": CreateWalletWatchonlyTest().main()