Changeset View
Changeset View
Standalone View
Standalone View
test/functional/wallet_address_types.py
Show First 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | def get_balances(self, confirmed=True): | ||||
else: | else: | ||||
return [self.nodes[i].getunconfirmedbalance() for i in range(4)] | return [self.nodes[i].getunconfirmedbalance() for i in range(4)] | ||||
def test_address(self, node, address, multisig, typ): | def test_address(self, node, address, multisig, typ): | ||||
"""Run sanity checks on an address.""" | """Run sanity checks on an address.""" | ||||
self.log.info(address) | self.log.info(address) | ||||
info = self.nodes[node].getaddressinfo(address) | info = self.nodes[node].getaddressinfo(address) | ||||
assert(self.nodes[node].validateaddress(address)['isvalid']) | 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 | # P2PKH | ||||
assert(not info['isscript']) | assert(not info['isscript']) | ||||
assert('pubkey' in info) | assert('pubkey' in info) | ||||
elif typ == 'legacy': | elif typ == 'legacy': | ||||
# P2SH-multisig | # P2SH-multisig | ||||
assert(info['isscript']) | assert(info['isscript']) | ||||
assert_equal(info['script'], 'multisig') | assert_equal(info['script'], 'multisig') | ||||
assert('pubkeys' in info) | assert('pubkeys' in info) | ||||
else: | else: | ||||
# Unknown type | # Unknown type | ||||
assert(False) | assert(False) | ||||
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_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: 0.00010000}]) | |||||
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'] | |||||
if not multisig and typ == 'legacy': | |||||
# P2PKH | |||||
assert_equal(info['desc'], | |||||
"pkh({})".format(key_descs[info['pubkey']])) | |||||
elif typ == 'legacy': | |||||
# P2SH-multisig | |||||
assert_equal(info['desc'], "sh(multi(2,{},{}))".format( | |||||
key_descs[info['pubkeys'][0]], key_descs[info['pubkeys'][1]])) | |||||
else: | |||||
# Unknown type | |||||
assert(False) | |||||
def test_change_output_type( | def test_change_output_type( | ||||
self, node_sender, destinations, expected_type): | self, node_sender, destinations, expected_type): | ||||
txid = self.nodes[node_sender].sendmany( | txid = self.nodes[node_sender].sendmany( | ||||
dummy="", amounts=dict.fromkeys( | dummy="", amounts=dict.fromkeys( | ||||
destinations, 0.001)) | destinations, 0.001)) | ||||
raw_tx = self.nodes[node_sender].getrawtransaction(txid) | raw_tx = self.nodes[node_sender].getrawtransaction(txid) | ||||
tx = self.nodes[node_sender].decoderawtransaction(raw_tx) | tx = self.nodes[node_sender].decoderawtransaction(raw_tx) | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
"Sending from node {} with{} multisig".format(from_node, "" if multisig else "out")) | "Sending from node {} with{} multisig".format(from_node, "" if multisig else "out")) | ||||
old_balances = self.get_balances() | old_balances = self.get_balances() | ||||
self.log.debug("Old balances are {}".format(old_balances)) | self.log.debug("Old balances are {}".format(old_balances)) | ||||
to_send = ( | to_send = ( | ||||
old_balances[from_node] / | old_balances[from_node] / | ||||
101).quantize( | 101).quantize( | ||||
Decimal("0.00000001")) | Decimal("0.00000001")) | ||||
sends = {} | sends = {} | ||||
addresses = {} | |||||
self.log.debug("Prepare sends") | self.log.debug("Prepare sends") | ||||
for n, to_node in enumerate(range(from_node, from_node + 4)): | for n, to_node in enumerate(range(from_node, from_node + 4)): | ||||
to_node %= 4 | to_node %= 4 | ||||
if not multisig: | if not multisig: | ||||
if from_node == to_node: | if from_node == to_node: | ||||
# When sending non-multisig to self, use | # When sending non-multisig to self, use | ||||
# getrawchangeaddress | # getrawchangeaddress | ||||
address = self.nodes[to_node].getrawchangeaddress() | address = self.nodes[to_node].getrawchangeaddress() | ||||
else: | else: | ||||
address = self.nodes[to_node].getnewaddress() | address = self.nodes[to_node].getnewaddress() | ||||
else: | else: | ||||
addr1 = self.nodes[to_node].getnewaddress() | addr1 = self.nodes[to_node].getnewaddress() | ||||
addr2 = self.nodes[to_node].getnewaddress() | addr2 = self.nodes[to_node].getnewaddress() | ||||
address = self.nodes[to_node].addmultisigaddress(2, [addr1, addr2])[ | address = self.nodes[to_node].addmultisigaddress(2, [addr1, addr2])[ | ||||
'address'] | 'address'] | ||||
# Do some sanity checking on the created address | # Do some sanity checking on the created address | ||||
typ = 'legacy' | typ = 'legacy' | ||||
self.test_address(to_node, address, multisig, typ) | self.test_address(to_node, address, multisig, typ) | ||||
# Output entry | # Output entry | ||||
sends[address] = to_send * 10 * (1 + n) | sends[address] = to_send * 10 * (1 + n) | ||||
addresses[to_node] = (address, typ) | |||||
self.log.debug("Sending: {}".format(sends)) | self.log.debug("Sending: {}".format(sends)) | ||||
self.nodes[from_node].sendmany("", sends) | self.nodes[from_node].sendmany("", sends) | ||||
sync_mempools(self.nodes) | sync_mempools(self.nodes) | ||||
unconf_balances = self.get_balances(False) | unconf_balances = self.get_balances(False) | ||||
self.log.debug( | self.log.debug( | ||||
"Check unconfirmed balances: {}".format(unconf_balances)) | "Check unconfirmed balances: {}".format(unconf_balances)) | ||||
assert_equal(unconf_balances[from_node], 0) | assert_equal(unconf_balances[from_node], 0) | ||||
for n, to_node in enumerate(range(from_node + 1, from_node + 4)): | for n, to_node in enumerate(range(from_node + 1, from_node + 4)): | ||||
to_node %= 4 | to_node %= 4 | ||||
assert_equal(unconf_balances[to_node], to_send * 10 * (2 + n)) | assert_equal(unconf_balances[to_node], to_send * 10 * (2 + n)) | ||||
# node4 collects fee and block subsidy to keep accounting simple | # node4 collects fee and block subsidy to keep accounting simple | ||||
self.nodes[4].generate(1) | self.nodes[4].generate(1) | ||||
sync_blocks(self.nodes) | sync_blocks(self.nodes) | ||||
# Verify that the receiving wallet contains a UTXO with the | |||||
# expected address, and expected descriptor | |||||
for n, to_node in enumerate(range(from_node, from_node + 4)): | |||||
to_node %= 4 | |||||
found = False | |||||
for utxo in self.nodes[to_node].listunspent(): | |||||
if utxo['address'] == addresses[to_node][0]: | |||||
found = True | |||||
self.test_desc( | |||||
to_node, | |||||
addresses[to_node][0], | |||||
multisig, | |||||
addresses[to_node][1], | |||||
utxo) | |||||
break | |||||
assert found | |||||
new_balances = self.get_balances() | new_balances = self.get_balances() | ||||
self.log.debug("Check new balances: {}".format(new_balances)) | self.log.debug("Check new balances: {}".format(new_balances)) | ||||
# We don't know what fee was set, so we can only check bounds on | # We don't know what fee was set, so we can only check bounds on | ||||
# the balance of the sending node | # the balance of the sending node | ||||
assert_greater_than(new_balances[from_node], to_send * 10) | assert_greater_than(new_balances[from_node], to_send * 10) | ||||
assert_greater_than(to_send * 11, new_balances[from_node]) | assert_greater_than(to_send * 11, new_balances[from_node]) | ||||
for n, to_node in enumerate(range(from_node + 1, from_node + 4)): | for n, to_node in enumerate(range(from_node + 1, from_node + 4)): | ||||
to_node %= 4 | to_node %= 4 | ||||
Show All 28 Lines |