Changeset View
Changeset View
Standalone View
Standalone View
test/functional/wallet_keypool.py
Show All 17 Lines | def skip_test_if_missing_module(self): | ||||
self.skip_if_no_wallet() | self.skip_if_no_wallet() | ||||
def run_test(self): | def run_test(self): | ||||
nodes = self.nodes | nodes = self.nodes | ||||
addr_before_encrypting = nodes[0].getnewaddress() | addr_before_encrypting = nodes[0].getnewaddress() | ||||
addr_before_encrypting_data = nodes[ | addr_before_encrypting_data = nodes[ | ||||
0].getaddressinfo(addr_before_encrypting) | 0].getaddressinfo(addr_before_encrypting) | ||||
wallet_info_old = nodes[0].getwalletinfo() | wallet_info_old = nodes[0].getwalletinfo() | ||||
assert addr_before_encrypting_data[ | if not self.options.descriptors: | ||||
'hdseedid'] == wallet_info_old['hdseedid'] | assert addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid'] | ||||
# Encrypt wallet and wait to terminate | # Encrypt wallet and wait to terminate | ||||
nodes[0].encryptwallet('test') | nodes[0].encryptwallet('test') | ||||
if self.options.descriptors: | |||||
# Import hardened derivation only descriptors | |||||
nodes[0].walletpassphrase('test', 10) | |||||
nodes[0].importdescriptors([ | |||||
{ | |||||
"desc": "pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/*h)#dfe4u060", | |||||
"timestamp": "now", | |||||
"range": [0, 0], | |||||
"active": True | |||||
}, | |||||
{ | |||||
"desc": "pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1h/*h)#a0nyvl0k", | |||||
"timestamp": "now", | |||||
"range": [0, 0], | |||||
"active": True | |||||
}, | |||||
{ | |||||
"desc": "sh(pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/2h/*h))#ptcuwey3", | |||||
"timestamp": "now", | |||||
"range": [0, 0], | |||||
"active": True | |||||
}, | |||||
{ | |||||
"desc": "pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/4h/*h)#l3crwaus", | |||||
"timestamp": "now", | |||||
"range": [0, 0], | |||||
"active": True, | |||||
"internal": True | |||||
}, | |||||
{ | |||||
"desc": "sh(pkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/5h/*h))#7cxwe6ks", | |||||
"timestamp": "now", | |||||
"range": [0, 0], | |||||
"active": True, | |||||
"internal": True | |||||
} | |||||
]) | |||||
nodes[0].walletlock() | |||||
# Keep creating keys | # Keep creating keys | ||||
addr = nodes[0].getnewaddress() | addr = nodes[0].getnewaddress() | ||||
addr_data = nodes[0].getaddressinfo(addr) | addr_data = nodes[0].getaddressinfo(addr) | ||||
wallet_info = nodes[0].getwalletinfo() | wallet_info = nodes[0].getwalletinfo() | ||||
assert addr_before_encrypting_data[ | if not self.options.descriptors: | ||||
'hdseedid'] != wallet_info['hdseedid'] | # For Core, getaddressinfo also returns 'hdmasterfingerprint' | ||||
# with --descriptors. Our codebase diverged after D3122, | |||||
# GetKeyForDestination works only for P2PKH. | |||||
assert addr_before_encrypting_data['hdmasterfingerprint'] != addr_data['hdmasterfingerprint'] | |||||
assert addr_data['hdseedid'] == wallet_info['hdseedid'] | assert addr_data['hdseedid'] == wallet_info['hdseedid'] | ||||
assert_raises_rpc_error( | assert_raises_rpc_error(-12, | ||||
-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) | "Error: Keypool ran out, please call keypoolrefill first", | ||||
nodes[0].getnewaddress) | |||||
# put six (plus 2) new keys in the keypool (100% external-, +100% | # put six (plus 2) new keys in the keypool (100% external-, +100% | ||||
# internal-keys, 1 in min) | # internal-keys, 1 in min) | ||||
nodes[0].walletpassphrase('test', 12000) | nodes[0].walletpassphrase('test', 12000) | ||||
nodes[0].keypoolrefill(6) | nodes[0].keypoolrefill(6) | ||||
nodes[0].walletlock() | nodes[0].walletlock() | ||||
wi = nodes[0].getwalletinfo() | wi = nodes[0].getwalletinfo() | ||||
# This would be 18, for Core is using --descriptors. Our version | |||||
# of KeypoolCountExternalKeys has only LegacyScriptPubKeyMan | |||||
# when Core's version has 2 additional managers (BECH32, P2SH_SEGWIT). | |||||
assert_equal(wi['keypoolsize_hd_internal'], 6) | assert_equal(wi['keypoolsize_hd_internal'], 6) | ||||
assert_equal(wi['keypoolsize'], 6) | assert_equal(wi['keypoolsize'], 6) | ||||
# drain the internal keys | # drain the internal keys | ||||
nodes[0].getrawchangeaddress() | nodes[0].getrawchangeaddress() | ||||
nodes[0].getrawchangeaddress() | nodes[0].getrawchangeaddress() | ||||
nodes[0].getrawchangeaddress() | nodes[0].getrawchangeaddress() | ||||
nodes[0].getrawchangeaddress() | nodes[0].getrawchangeaddress() | ||||
Show All 31 Lines | def run_test(self): | ||||
nodes[0].walletpassphrase('test', 100) | nodes[0].walletpassphrase('test', 100) | ||||
nodes[0].keypoolrefill(100) | nodes[0].keypoolrefill(100) | ||||
wi = nodes[0].getwalletinfo() | wi = nodes[0].getwalletinfo() | ||||
assert_equal(wi['keypoolsize_hd_internal'], 100) | assert_equal(wi['keypoolsize_hd_internal'], 100) | ||||
assert_equal(wi['keypoolsize'], 100) | assert_equal(wi['keypoolsize'], 100) | ||||
# create a blank wallet | # create a blank wallet | ||||
nodes[0].createwallet(wallet_name='w2', blank=True) | nodes[0].createwallet( | ||||
wallet_name='w2', | |||||
blank=True, | |||||
disable_private_keys=True) | |||||
w2 = nodes[0].get_wallet_rpc('w2') | w2 = nodes[0].get_wallet_rpc('w2') | ||||
# refer to initial wallet as w1 | # refer to initial wallet as w1 | ||||
w1 = nodes[0].get_wallet_rpc('') | w1 = nodes[0].get_wallet_rpc('') | ||||
# import private key and fund it | # import private key and fund it | ||||
address = addr.pop() | address = addr.pop() | ||||
privkey = w1.dumpprivkey(address) | desc = w1.getaddressinfo(address)['desc'] | ||||
res = w2.importmulti( | self.log.info(desc) | ||||
[{'scriptPubKey': {'address': address}, 'keys': [privkey], 'timestamp': 'now'}]) | if self.options.descriptors: | ||||
res = w2.importdescriptors([{'desc': desc, 'timestamp': 'now'}]) | |||||
else: | |||||
res = w2.importmulti([{'desc': desc, 'timestamp': 'now'}]) | |||||
assert_equal(res[0]['success'], True) | assert_equal(res[0]['success'], True) | ||||
w1.walletpassphrase('test', 100) | w1.walletpassphrase('test', 100) | ||||
res = w1.sendtoaddress(address=address, amount=100.00) | res = w1.sendtoaddress(address=address, amount=100.00) | ||||
nodes[0].generate(1) | nodes[0].generate(1) | ||||
destination = addr.pop() | destination = addr.pop() | ||||
# Using a fee rate (10 sat / byte) well above the minimum relay rate | # Using a fee rate (10 sat / byte) well above the minimum relay rate | ||||
Show All 16 Lines | def run_test(self): | ||||
# creating a 10,000 sat transaction without change should still be | # creating a 10,000 sat transaction without change should still be | ||||
# possible | # possible | ||||
res = w2.walletcreatefundedpsbt( | res = w2.walletcreatefundedpsbt( | ||||
inputs=[], | inputs=[], | ||||
outputs=[{destination: 100.00}], | outputs=[{destination: 100.00}], | ||||
options={"subtractFeeFromOutputs": [0], "feeRate": 100}) | options={"subtractFeeFromOutputs": [0], "feeRate": 100}) | ||||
assert_equal("psbt" in res, True) | assert_equal("psbt" in res, True) | ||||
if not self.options.descriptors: | |||||
# FIXME: make the following work with --descriptors, find out why | |||||
# it affects the way the fees are calculated | |||||
# should work without subtractFeeFromOutputs if the exact fee is | # should work without subtractFeeFromOutputs if the exact fee is | ||||
# subtracted from the amount | # subtracted from the amount | ||||
res = w2.walletcreatefundedpsbt(inputs=[], | res = w2.walletcreatefundedpsbt(inputs=[], | ||||
outputs=[{destination: 80.00}], | outputs=[{destination: 80.00}], | ||||
options={"feeRate": 100}) | options={"feeRate": 100}) | ||||
assert_equal("psbt" in res, True) | assert_equal("psbt" in res, True) | ||||
# dust change should be removed | # dust change should be removed | ||||
res = w2.walletcreatefundedpsbt(inputs=[], | res = w2.walletcreatefundedpsbt(inputs=[], | ||||
outputs=[{destination: 79.00}], | # Note: without --descriptors, we could | ||||
# raise this amount the 80.00 | |||||
outputs=[{destination: 78.40}], | |||||
options={"feeRate": 100}) | options={"feeRate": 100}) | ||||
assert_equal("psbt" in res, True) | assert_equal("psbt" in res, True) | ||||
if not self.options.descriptors: | |||||
# FIXME: this should theoretically work with --descriptors | |||||
# create a transaction without change at the maximum fee rate, such | # create a transaction without change at the maximum fee rate, such | ||||
# that the output is still spendable: | # that the output is still spendable: | ||||
res = w2.walletcreatefundedpsbt( | res = w2.walletcreatefundedpsbt( | ||||
inputs=[], | inputs=[], | ||||
outputs=[{destination: 100.00}], | outputs=[{destination: 100.00}], | ||||
options={"subtractFeeFromOutputs": [0], "feeRate": 494.90}) | options={"subtractFeeFromOutputs": [0], "feeRate": 492.30}) | ||||
assert_equal("psbt" in res, True) | assert_equal("psbt" in res, True) | ||||
assert_equal(res["fee"], Decimal("94.53")) | assert_equal(res["fee"], Decimal("94.53")) | ||||
# creating a 10,000 sat transaction with a manual change address should | # creating a 10,000 sat transaction with a manual change address should | ||||
# be possible | # be possible | ||||
res = w2.walletcreatefundedpsbt(inputs=[], | res = w2.walletcreatefundedpsbt(inputs=[], | ||||
outputs=[{destination: 100.00}], | outputs=[{destination: 100.00}], | ||||
options={"subtractFeeFromOutputs": [0], | options={"subtractFeeFromOutputs": [0], | ||||
"feeRate": 100, | "feeRate": 100, | ||||
"changeAddress": addr.pop()}) | "changeAddress": addr.pop()}) | ||||
assert_equal("psbt" in res, True) | assert_equal("psbt" in res, True) | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
KeyPoolTest().main() | KeyPoolTest().main() |