lbry-sdk/lbrynet/wallet/account.py

84 lines
2.4 KiB
Python
Raw Normal View History

import logging
from lbryschema.address import public_key_to_address
from .lbrycrd import deserialize_xkey
from .lbrycrd import CKD_pub
log = logging.getLogger(__name__)
def get_key_chain_from_xpub(xpub):
_, _, _, chain, key = deserialize_xkey(xpub)
return key, chain
def derive_key(parent_key, chain, sequence):
return CKD_pub(parent_key, chain, sequence)[0]
class AddressSequence:
def __init__(self, derived_keys, gap, age_checker, pub_key, chain_key):
self.gap = gap
self.is_old = age_checker
self.pub_key = pub_key
self.chain_key = chain_key
self.derived_keys = derived_keys
self.addresses = [
public_key_to_address(key.decode('hex'))
for key in derived_keys
]
def generate_next_address(self):
new_key, _ = derive_key(self.pub_key, self.chain_key, len(self.derived_keys))
address = public_key_to_address(new_key)
self.derived_keys.append(new_key.encode('hex'))
self.addresses.append(address)
return address
def has_gap(self):
if len(self.addresses) < self.gap:
return False
for address in self.addresses[-self.gap:]:
if self.is_old(address):
return False
return True
def ensure_enough_addresses(self):
starting_length = len(self.addresses)
while not self.has_gap():
self.generate_next_address()
return self.addresses[starting_length:]
class Account:
def __init__(self, data, receiving_gap, change_gap, age_checker):
self.xpub = data['xpub']
master_key, master_chain = get_key_chain_from_xpub(data['xpub'])
self.receiving = AddressSequence(
data.get('receiving', []), receiving_gap, age_checker,
*derive_key(master_key, master_chain, 0)
)
self.change = AddressSequence(
data.get('change', []), change_gap, age_checker,
*derive_key(master_key, master_chain, 1)
)
self.is_old = age_checker
def as_dict(self):
return {
'receiving': self.receiving.derived_keys,
'change': self.change.derived_keys,
'xpub': self.xpub
}
def ensure_enough_addresses(self):
return self.receiving.ensure_enough_addresses() + \
self.change.ensure_enough_addresses()
@property
def sequences(self):
return self.receiving, self.change