Browse Source

BIP32_HD_Wallet: Fix address derivation

Unfortunately there was root_name and root_derivation confusion
in the past for classes derived from BIP_32_HD_Wallet.
Address derivation used root_name and so would begin with 'x/'
whereas it should have begun with root_derivation, and so started
with 'm/'.

This fixes that old wart and removes some fudges from the trezor
code that used to work around it.
283
Neil Booth 9 years ago
parent
commit
3d781a2d1b
  1. 20
      lib/wallet.py
  2. 4
      plugins/ledger/ledger.py
  3. 2
      plugins/trezor/client.py
  4. 1
      plugins/trezor/plugin.py

20
lib/wallet.py

@ -1668,19 +1668,15 @@ class BIP32_HD_Wallet(BIP32_Wallet):
# drop unused master public key to avoid duplicate errors # drop unused master public key to avoid duplicate errors
acc2 = storage.get('next_account2', None) acc2 = storage.get('next_account2', None)
if acc2: if acc2:
storage.put('next_account2', None)
self.master_public_keys.pop(self.root_name + acc2[0] + "'", None) self.master_public_keys.pop(self.root_name + acc2[0] + "'", None)
self.storage.put('master_public_keys', self.master_public_keys) storage.put('next_account2', None)
storage.put('master_public_keys', self.master_public_keys)
def next_account_number(self): def next_account_number(self):
assert (set(self.accounts.keys()) == assert (set(self.accounts.keys()) ==
set(['%d' % n for n in range(len(self.accounts))])) set(['%d' % n for n in range(len(self.accounts))]))
return len(self.accounts) return len(self.accounts)
def next_derivation(self):
account_id = '%d' % self.next_account_number()
return self.root_name + account_id + "'", account_id
def show_account(self, account_id): def show_account(self, account_id):
return self.account_is_used(account_id) or account_id in self.labels return self.account_is_used(account_id) or account_id in self.labels
@ -1711,8 +1707,10 @@ class BIP32_HD_Wallet(BIP32_Wallet):
self.create_next_account(password) self.create_next_account(password)
def create_next_account(self, password, label=None): def create_next_account(self, password, label=None):
derivation, account_id = self.next_derivation() account_id = '%d' % self.next_account_number()
xpub, xprv = self.derive_xkeys(self.root_name, derivation, password) derivation = self.account_derivation(account_id)
root_name = self.root_derivation.split('/')[0] # NOT self.root_name!
xpub, xprv = self.derive_xkeys(root_name, derivation, password)
self.add_master_public_key(derivation, xpub) self.add_master_public_key(derivation, xpub)
if xprv: if xprv:
self.add_master_private_key(derivation, xprv, password) self.add_master_private_key(derivation, xprv, password)
@ -1728,13 +1726,9 @@ class BIP32_HD_Wallet(BIP32_Wallet):
def accounts_all_used(self): def accounts_all_used(self):
return all(self.account_is_used(acc_id) for acc_id in self.accounts) return all(self.account_is_used(acc_id) for acc_id in self.accounts)
@classmethod
def prefix(self):
return "/".join(self.root_derivation.split("/")[1:])
@classmethod @classmethod
def account_derivation(self, account_id): def account_derivation(self, account_id):
return self.prefix() + "/" + account_id + "'" return self.root_derivation + "/" + account_id + "'"
@classmethod @classmethod
def address_derivation(self, account_id, change, address_index): def address_derivation(self, account_id, change, address_index):

4
plugins/ledger/ledger.py

@ -63,6 +63,10 @@ class BTChipWallet(BIP44_Wallet):
assert not self.has_seed() assert not self.has_seed()
return self.force_watching_only return self.force_watching_only
def address_id(self, address):
# Strip the leading "m/"
return BIP44_Wallet.address_id(self, address)[2:]
def get_client(self, noPin=False): def get_client(self, noPin=False):
if not BTCHIP: if not BTCHIP:
self.give_error('please install github.com/btchip/btchip-python') self.give_error('please install github.com/btchip/btchip-python')

2
plugins/trezor/client.py

@ -98,7 +98,7 @@ def trezor_client_class(protocol_mixin, base_client, proto):
'''Convert bip32 path to list of uint32 integers with prime flags '''Convert bip32 path to list of uint32 integers with prime flags
0/-1/1' -> [0, 0x80000001, 0x80000001]''' 0/-1/1' -> [0, 0x80000001, 0x80000001]'''
path = [] path = []
for x in n.split('/'): for x in n.split('/')[1:]:
prime = 0 prime = 0
if x.endswith("'"): if x.endswith("'"):
x = x.replace('\'', '') x = x.replace('\'', '')

1
plugins/trezor/plugin.py

@ -100,7 +100,6 @@ class TrezorCompatibleWallet(BIP44_Wallet):
# When creating a wallet we need to ask the device for the # When creating a wallet we need to ask the device for the
# master public key # master public key
derivation = derivation.replace(self.root_name, self.prefix() + "/")
xpub = self.get_public_key(derivation) xpub = self.get_public_key(derivation)
return xpub, None return xpub, None

Loading…
Cancel
Save