move private key methods from wallet to accounts
This commit is contained in:
parent
9b8ad42a66
commit
c9fc6275ab
|
@ -1077,7 +1077,7 @@ class ElectrumWindow(QMainWindow):
|
||||||
menu.addAction(_("Private key"), lambda: self.show_private_key(addr))
|
menu.addAction(_("Private key"), lambda: self.show_private_key(addr))
|
||||||
menu.addAction(_("Sign/verify message"), lambda: self.sign_verify_message(addr))
|
menu.addAction(_("Sign/verify message"), lambda: self.sign_verify_message(addr))
|
||||||
#menu.addAction(_("Encrypt/decrypt message"), lambda: self.encrypt_message(addr))
|
#menu.addAction(_("Encrypt/decrypt message"), lambda: self.encrypt_message(addr))
|
||||||
if addr in self.wallet.imported_keys:
|
if self.wallet.is_imported(addr):
|
||||||
menu.addAction(_("Remove from wallet"), lambda: self.delete_imported_key(addr))
|
menu.addAction(_("Remove from wallet"), lambda: self.delete_imported_key(addr))
|
||||||
|
|
||||||
if any(addr not in self.wallet.frozen_addresses for addr in addrs):
|
if any(addr not in self.wallet.frozen_addresses for addr in addrs):
|
||||||
|
|
|
@ -124,6 +124,8 @@ class PasswordDialog(QDialog):
|
||||||
try:
|
try:
|
||||||
self.wallet.update_password(password, new_password)
|
self.wallet.update_password(password, new_password)
|
||||||
except:
|
except:
|
||||||
|
import traceback, sys
|
||||||
|
traceback.print_exc(file=sys.stdout)
|
||||||
QMessageBox.warning(self.parent, _('Error'), _('Failed to update password'), _('OK'))
|
QMessageBox.warning(self.parent, _('Error'), _('Failed to update password'), _('OK'))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,12 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
from bitcoin import *
|
from bitcoin import *
|
||||||
from i18n import _
|
from i18n import _
|
||||||
from transaction import Transaction
|
from transaction import Transaction
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Account(object):
|
class Account(object):
|
||||||
def __init__(self, v):
|
def __init__(self, v):
|
||||||
self.addresses = v.get('0', [])
|
self.addresses = v.get('0', [])
|
||||||
|
@ -52,6 +53,12 @@ class Account(object):
|
||||||
def get_name(self, k):
|
def get_name(self, k):
|
||||||
return _('Main account')
|
return _('Main account')
|
||||||
|
|
||||||
|
def get_keyID(self, *sequence):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def redeem_script(self, *sequence):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PendingAccount(Account):
|
class PendingAccount(Account):
|
||||||
def __init__(self, v):
|
def __init__(self, v):
|
||||||
|
@ -70,18 +77,52 @@ class PendingAccount(Account):
|
||||||
|
|
||||||
class ImportedAccount(Account):
|
class ImportedAccount(Account):
|
||||||
def __init__(self, d):
|
def __init__(self, d):
|
||||||
self.addresses = d.keys()
|
self.keypairs = d['imported']
|
||||||
|
|
||||||
def get_addresses(self, for_change):
|
def get_addresses(self, for_change):
|
||||||
return [] if for_change else sorted(self.addresses[:])
|
return [] if for_change else sorted(self.keypairs.keys())
|
||||||
|
|
||||||
|
def get_pubkey(self, *sequence):
|
||||||
|
for_change, i = sequence
|
||||||
|
assert for_change == 0
|
||||||
|
addr = self.get_addresses(0)[i]
|
||||||
|
return self.keypairs[addr][i][0]
|
||||||
|
|
||||||
|
def get_private_key(self, sequence, wallet, password):
|
||||||
|
from wallet import pw_decode
|
||||||
|
for_change, i = sequence
|
||||||
|
assert for_change == 0
|
||||||
|
address = self.get_addresses(0)[i]
|
||||||
|
pk = pw_decode(self.keypairs[address][1], password)
|
||||||
|
# this checks the password
|
||||||
|
assert address == address_from_private_key(pk)
|
||||||
|
return [pk]
|
||||||
|
|
||||||
def has_change(self):
|
def has_change(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def add(self, address, pubkey, privkey, password):
|
||||||
|
from wallet import pw_encode
|
||||||
|
self.keypairs[address] = (pubkey, pw_encode(privkey, password ))
|
||||||
|
|
||||||
|
def remove(self, address):
|
||||||
|
self.keypairs.pop(address)
|
||||||
|
|
||||||
|
def dump(self):
|
||||||
|
return {'imported':self.keypairs}
|
||||||
|
|
||||||
def get_name(self, k):
|
def get_name(self, k):
|
||||||
return _('Imported keys')
|
return _('Imported keys')
|
||||||
|
|
||||||
|
|
||||||
|
def update_password(self, old_password, new_password):
|
||||||
|
for k, v in self.keypairs.items():
|
||||||
|
pubkey, a = v
|
||||||
|
b = pw_decode(a, old_password)
|
||||||
|
c = pw_encode(b, new_password)
|
||||||
|
self.keypairs[k] = (pubkey, c)
|
||||||
|
|
||||||
|
|
||||||
class OldAccount(Account):
|
class OldAccount(Account):
|
||||||
""" Privatekey(type,n) = Master_private_key + H(n|S|type) """
|
""" Privatekey(type,n) = Master_private_key + H(n|S|type) """
|
||||||
|
|
||||||
|
@ -132,10 +173,15 @@ class OldAccount(Account):
|
||||||
compressed = False
|
compressed = False
|
||||||
return SecretToASecret( pk, compressed )
|
return SecretToASecret( pk, compressed )
|
||||||
|
|
||||||
def get_private_key(self, seed, sequence):
|
|
||||||
|
def get_private_key(self, sequence, wallet, password):
|
||||||
|
seed = wallet.get_seed(password)
|
||||||
|
self.check_seed(seed)
|
||||||
for_change, n = sequence
|
for_change, n = sequence
|
||||||
secexp = self.stretch_key(seed)
|
secexp = self.stretch_key(seed)
|
||||||
return self.get_private_key_from_stretched_exponent(for_change, n, secexp)
|
pk = self.get_private_key_from_stretched_exponent(for_change, n, secexp)
|
||||||
|
return [pk]
|
||||||
|
|
||||||
|
|
||||||
def check_seed(self, seed):
|
def check_seed(self, seed):
|
||||||
curve = SECP256k1
|
curve = SECP256k1
|
||||||
|
@ -196,6 +242,22 @@ class BIP32_Account(Account):
|
||||||
def get_pubkey(self, for_change, n):
|
def get_pubkey(self, for_change, n):
|
||||||
return self.get_pubkeys((for_change, n))[0]
|
return self.get_pubkeys((for_change, n))[0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_private_key(self, sequence, wallet, password):
|
||||||
|
out = []
|
||||||
|
xpubs = self.get_master_pubkeys()
|
||||||
|
roots = [k for k, v in wallet.master_public_keys.iteritems() if v in xpubs]
|
||||||
|
for root in roots:
|
||||||
|
xpriv = wallet.get_master_private_key(root, password)
|
||||||
|
if not xpriv:
|
||||||
|
continue
|
||||||
|
_, _, _, c, k = deserialize_xkey(xpriv)
|
||||||
|
pk = bip32_private_key( sequence, k, c )
|
||||||
|
out.append(pk)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def redeem_script(self, sequence):
|
def redeem_script(self, sequence):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,35 @@
|
||||||
|
|
||||||
import hashlib, base64, ecdsa, re
|
import hashlib, base64, ecdsa, re
|
||||||
import hmac
|
import hmac
|
||||||
|
import aes
|
||||||
from util import print_error
|
from util import print_error
|
||||||
|
|
||||||
|
# AES encryption
|
||||||
|
EncodeAES = lambda secret, s: base64.b64encode(aes.encryptData(secret,s))
|
||||||
|
DecodeAES = lambda secret, e: aes.decryptData(secret, base64.b64decode(e))
|
||||||
|
|
||||||
|
def pw_encode(s, password):
|
||||||
|
if password:
|
||||||
|
secret = Hash(password)
|
||||||
|
return EncodeAES(secret, s)
|
||||||
|
else:
|
||||||
|
return s
|
||||||
|
|
||||||
|
def pw_decode(s, password):
|
||||||
|
if password is not None:
|
||||||
|
secret = Hash(password)
|
||||||
|
try:
|
||||||
|
d = DecodeAES(secret, s)
|
||||||
|
except Exception:
|
||||||
|
raise Exception('Invalid password')
|
||||||
|
return d
|
||||||
|
else:
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def rev_hex(s):
|
def rev_hex(s):
|
||||||
return s.decode('hex')[::-1].encode('hex')
|
return s.decode('hex')[::-1].encode('hex')
|
||||||
|
|
||||||
|
@ -274,6 +301,7 @@ def public_key_from_private_key(sec):
|
||||||
pkey = regenerate_key(sec)
|
pkey = regenerate_key(sec)
|
||||||
assert pkey
|
assert pkey
|
||||||
compressed = is_compressed(sec)
|
compressed = is_compressed(sec)
|
||||||
|
print "is compressed", compressed
|
||||||
public_key = GetPubKey(pkey.pubkey, compressed)
|
public_key = GetPubKey(pkey.pubkey, compressed)
|
||||||
return public_key.encode('hex')
|
return public_key.encode('hex')
|
||||||
|
|
||||||
|
|
209
lib/wallet.py
209
lib/wallet.py
|
@ -45,30 +45,6 @@ DUST_THRESHOLD = 5430
|
||||||
# internal ID for imported account
|
# internal ID for imported account
|
||||||
IMPORTED_ACCOUNT = '/x'
|
IMPORTED_ACCOUNT = '/x'
|
||||||
|
|
||||||
# AES encryption
|
|
||||||
EncodeAES = lambda secret, s: base64.b64encode(aes.encryptData(secret,s))
|
|
||||||
DecodeAES = lambda secret, e: aes.decryptData(secret, base64.b64decode(e))
|
|
||||||
|
|
||||||
def pw_encode(s, password):
|
|
||||||
if password:
|
|
||||||
secret = Hash(password)
|
|
||||||
return EncodeAES(secret, s)
|
|
||||||
else:
|
|
||||||
return s
|
|
||||||
|
|
||||||
def pw_decode(s, password):
|
|
||||||
if password is not None:
|
|
||||||
secret = Hash(password)
|
|
||||||
try:
|
|
||||||
d = DecodeAES(secret, s)
|
|
||||||
except Exception:
|
|
||||||
raise Exception('Invalid password')
|
|
||||||
return d
|
|
||||||
else:
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from version import *
|
from version import *
|
||||||
|
@ -249,7 +225,26 @@ class Abstract_Wallet:
|
||||||
self.accounts = {}
|
self.accounts = {}
|
||||||
self.imported_keys = self.storage.get('imported_keys',{})
|
self.imported_keys = self.storage.get('imported_keys',{})
|
||||||
if self.imported_keys:
|
if self.imported_keys:
|
||||||
self.accounts['/x'] = ImportedAccount(self.imported_keys)
|
print_error("cannot load imported keys")
|
||||||
|
|
||||||
|
d = self.storage.get('accounts', {})
|
||||||
|
for k, v in d.items():
|
||||||
|
if k == 0:
|
||||||
|
v['mpk'] = self.storage.get('master_public_key')
|
||||||
|
self.accounts[k] = OldAccount(v)
|
||||||
|
elif v.get('imported'):
|
||||||
|
self.accounts[k] = ImportedAccount(v)
|
||||||
|
elif v.get('xpub3'):
|
||||||
|
self.accounts[k] = BIP32_Account_2of3(v)
|
||||||
|
elif v.get('xpub2'):
|
||||||
|
self.accounts[k] = BIP32_Account_2of2(v)
|
||||||
|
elif v.get('xpub'):
|
||||||
|
self.accounts[k] = BIP32_Account(v)
|
||||||
|
elif v.get('pending'):
|
||||||
|
self.accounts[k] = PendingAccount(v)
|
||||||
|
else:
|
||||||
|
print_error("cannot load account", v)
|
||||||
|
|
||||||
|
|
||||||
def synchronize(self):
|
def synchronize(self):
|
||||||
pass
|
pass
|
||||||
|
@ -257,14 +252,9 @@ class Abstract_Wallet:
|
||||||
def can_create_accounts(self):
|
def can_create_accounts(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_password(self, password):
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def set_up_to_date(self,b):
|
def set_up_to_date(self,b):
|
||||||
with self.lock: self.up_to_date = b
|
with self.lock: self.up_to_date = b
|
||||||
|
|
||||||
|
|
||||||
def is_up_to_date(self):
|
def is_up_to_date(self):
|
||||||
with self.lock: return self.up_to_date
|
with self.lock: return self.up_to_date
|
||||||
|
|
||||||
|
@ -274,21 +264,27 @@ class Abstract_Wallet:
|
||||||
while not self.is_up_to_date():
|
while not self.is_up_to_date():
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
def is_imported(self, addr):
|
||||||
|
account = self.accounts.get(IMPORTED_ACCOUNT)
|
||||||
|
if account:
|
||||||
|
return addr in account.get_addresses(0)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def import_key(self, sec, password):
|
def import_key(self, sec, password):
|
||||||
self.check_password(password)
|
|
||||||
try:
|
try:
|
||||||
address = address_from_private_key(sec)
|
pubkey = public_key_from_private_key(sec)
|
||||||
|
address = public_key_to_bc_address(pubkey.decode('hex'))
|
||||||
except Exception:
|
except Exception:
|
||||||
raise Exception('Invalid private key')
|
raise Exception('Invalid private key')
|
||||||
|
|
||||||
if self.is_mine(address):
|
if self.is_mine(address):
|
||||||
raise Exception('Address already in wallet')
|
raise Exception('Address already in wallet')
|
||||||
|
|
||||||
# store the originally requested keypair into the imported keys table
|
if self.accounts.get(IMPORTED_ACCOUNT) is None:
|
||||||
self.imported_keys[address] = pw_encode(sec, password )
|
self.accounts[IMPORTED_ACCOUNT] = ImportedAccount({'imported':{}})
|
||||||
self.storage.put('imported_keys', self.imported_keys, True)
|
self.accounts[IMPORTED_ACCOUNT].add(address, pubkey, sec, password)
|
||||||
self.accounts[IMPORTED_ACCOUNT] = ImportedAccount(self.imported_keys)
|
self.save_accounts()
|
||||||
|
|
||||||
if self.synchronizer:
|
if self.synchronizer:
|
||||||
self.synchronizer.subscribe_to_addresses([address])
|
self.synchronizer.subscribe_to_addresses([address])
|
||||||
|
@ -296,13 +292,11 @@ class Abstract_Wallet:
|
||||||
|
|
||||||
|
|
||||||
def delete_imported_key(self, addr):
|
def delete_imported_key(self, addr):
|
||||||
if addr in self.imported_keys:
|
account = self.accounts[IMPORTED_ACCOUNT]
|
||||||
self.imported_keys.pop(addr)
|
account.remove(addr)
|
||||||
self.storage.put('imported_keys', self.imported_keys, True)
|
if not account.get_addresses(0):
|
||||||
if self.imported_keys:
|
self.accounts.pop(IMPORTED_ACCOUNT)
|
||||||
self.accounts[IMPORTED_ACCOUNT] = ImportedAccount(self.imported_keys)
|
self.save_accounts()
|
||||||
else:
|
|
||||||
self.accounts.pop(IMPORTED_ACCOUNT)
|
|
||||||
|
|
||||||
|
|
||||||
def set_label(self, name, text = None):
|
def set_label(self, name, text = None):
|
||||||
|
@ -368,35 +362,15 @@ class Abstract_Wallet:
|
||||||
def getpubkeys(self, addr):
|
def getpubkeys(self, addr):
|
||||||
assert is_valid(addr) and self.is_mine(addr)
|
assert is_valid(addr) and self.is_mine(addr)
|
||||||
account, sequence = self.get_address_index(addr)
|
account, sequence = self.get_address_index(addr)
|
||||||
if account != IMPORTED_ACCOUNT:
|
a = self.accounts[account]
|
||||||
a = self.accounts[account]
|
return a.get_pubkeys( sequence )
|
||||||
return a.get_pubkeys( sequence )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_private_key(self, address, password):
|
def get_private_key(self, address, password):
|
||||||
if self.is_watching_only():
|
if self.is_watching_only():
|
||||||
return []
|
return []
|
||||||
|
account_id, sequence = self.get_address_index(address)
|
||||||
out = []
|
return self.accounts[account_id].get_private_key(sequence, self, password)
|
||||||
if address in self.imported_keys.keys():
|
|
||||||
self.check_password(password)
|
|
||||||
out.append( pw_decode( self.imported_keys[address], password ) )
|
|
||||||
else:
|
|
||||||
seed = self.get_seed(password)
|
|
||||||
account_id, sequence = self.get_address_index(address)
|
|
||||||
account = self.accounts[account_id]
|
|
||||||
xpubs = account.get_master_pubkeys()
|
|
||||||
roots = [k for k, v in self.master_public_keys.iteritems() if v in xpubs]
|
|
||||||
for root in roots:
|
|
||||||
xpriv = self.get_master_private_key(root, password)
|
|
||||||
if not xpriv:
|
|
||||||
continue
|
|
||||||
_, _, _, c, k = deserialize_xkey(xpriv)
|
|
||||||
pk = bip32_private_key( sequence, k, c )
|
|
||||||
out.append(pk)
|
|
||||||
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
def get_public_keys(self, address):
|
def get_public_keys(self, address):
|
||||||
|
@ -414,9 +388,6 @@ class Abstract_Wallet:
|
||||||
pubkey = public_key_from_private_key(sec)
|
pubkey = public_key_from_private_key(sec)
|
||||||
keypairs[ pubkey ] = sec
|
keypairs[ pubkey ] = sec
|
||||||
|
|
||||||
# this is needed because we don't store imported pubkeys
|
|
||||||
if address in self.imported_keys.keys():
|
|
||||||
txin['redeemPubkey'] = pubkey
|
|
||||||
|
|
||||||
|
|
||||||
def add_keypairs_from_KeyID(self, tx, keypairs, password):
|
def add_keypairs_from_KeyID(self, tx, keypairs, password):
|
||||||
|
@ -891,8 +862,6 @@ class Abstract_Wallet:
|
||||||
|
|
||||||
def add_input_info(self, txin):
|
def add_input_info(self, txin):
|
||||||
address = txin['address']
|
address = txin['address']
|
||||||
if address in self.imported_keys.keys():
|
|
||||||
return
|
|
||||||
account_id, sequence = self.get_address_index(address)
|
account_id, sequence = self.get_address_index(address)
|
||||||
account = self.accounts[account_id]
|
account = self.accounts[account_id]
|
||||||
txin['KeyID'] = account.get_keyID(sequence)
|
txin['KeyID'] = account.get_keyID(sequence)
|
||||||
|
@ -941,12 +910,10 @@ class Abstract_Wallet:
|
||||||
self.seed = pw_encode( decoded, new_password)
|
self.seed = pw_encode( decoded, new_password)
|
||||||
self.storage.put('seed', self.seed, True)
|
self.storage.put('seed', self.seed, True)
|
||||||
|
|
||||||
for k in self.imported_keys.keys():
|
imported_account = self.accounts.get(IMPORTED_ACCOUNT)
|
||||||
a = self.imported_keys[k]
|
if imported_account:
|
||||||
b = pw_decode(a, old_password)
|
imported_account.update_password(old_password, new_password)
|
||||||
c = pw_encode(b, new_password)
|
self.save_accounts()
|
||||||
self.imported_keys[k] = c
|
|
||||||
self.storage.put('imported_keys', self.imported_keys, True)
|
|
||||||
|
|
||||||
for k, v in self.master_private_keys.items():
|
for k, v in self.master_private_keys.items():
|
||||||
b = pw_decode(v, old_password)
|
b = pw_decode(v, old_password)
|
||||||
|
@ -1097,15 +1064,27 @@ class Abstract_Wallet:
|
||||||
def get_accounts(self):
|
def get_accounts(self):
|
||||||
return self.accounts
|
return self.accounts
|
||||||
|
|
||||||
|
def save_accounts(self):
|
||||||
|
d = {}
|
||||||
|
for k, v in self.accounts.items():
|
||||||
|
d[k] = v.dump()
|
||||||
|
self.storage.put('accounts', d, True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Imported_Wallet(Abstract_Wallet):
|
class Imported_Wallet(Abstract_Wallet):
|
||||||
|
|
||||||
def __init__(self, storage):
|
def __init__(self, storage):
|
||||||
Abstract_Wallet.__init__(self, storage)
|
Abstract_Wallet.__init__(self, storage)
|
||||||
|
a = self.accounts.get(IMPORTED_ACCOUNT)
|
||||||
|
if not a:
|
||||||
|
self.accounts[IMPORTED_ACCOUNT] = ImportedAccount({'imported':{}})
|
||||||
|
|
||||||
|
|
||||||
def is_watching_only(self):
|
def is_watching_only(self):
|
||||||
n = self.imported_keys.values()
|
acc = self.accounts[IMPORTED_ACCOUNT]
|
||||||
return n == [''] * len(n)
|
n = acc.keypairs.values()
|
||||||
|
return n == [(None, None)] * len(n)
|
||||||
|
|
||||||
def has_seed(self):
|
def has_seed(self):
|
||||||
return False
|
return False
|
||||||
|
@ -1114,12 +1093,7 @@ class Imported_Wallet(Abstract_Wallet):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_password(self, password):
|
def check_password(self, password):
|
||||||
if self.imported_keys:
|
self.accounts[IMPORTED_ACCOUNT].get_private_key((0,0), self, password)
|
||||||
k, v = self.imported_keys.items()[0]
|
|
||||||
sec = pw_decode(v, password)
|
|
||||||
address = address_from_private_key(sec)
|
|
||||||
assert address == k
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1137,9 +1111,6 @@ class Deterministic_Wallet(Abstract_Wallet):
|
||||||
def is_watching_only(self):
|
def is_watching_only(self):
|
||||||
return not self.has_seed()
|
return not self.has_seed()
|
||||||
|
|
||||||
def check_password(self, password):
|
|
||||||
self.get_seed(password)
|
|
||||||
|
|
||||||
def add_seed(self, seed, password):
|
def add_seed(self, seed, password):
|
||||||
if self.seed:
|
if self.seed:
|
||||||
raise Exception("a seed exists")
|
raise Exception("a seed exists")
|
||||||
|
@ -1157,12 +1128,10 @@ class Deterministic_Wallet(Abstract_Wallet):
|
||||||
self.create_master_keys(password)
|
self.create_master_keys(password)
|
||||||
|
|
||||||
def get_seed(self, password):
|
def get_seed(self, password):
|
||||||
s = pw_decode(self.seed, password)
|
return pw_decode(self.seed, password)
|
||||||
seed = mnemonic_to_seed(s,'').encode('hex')
|
|
||||||
return seed
|
|
||||||
|
|
||||||
def get_mnemonic(self, password):
|
def get_mnemonic(self, password):
|
||||||
return pw_decode(self.seed, password)
|
return self.get_seed(password)
|
||||||
|
|
||||||
def change_gap_limit(self, value):
|
def change_gap_limit(self, value):
|
||||||
if value >= self.gap_limit:
|
if value >= self.gap_limit:
|
||||||
|
@ -1324,32 +1293,6 @@ class Deterministic_Wallet(Abstract_Wallet):
|
||||||
self.save_accounts()
|
self.save_accounts()
|
||||||
|
|
||||||
|
|
||||||
def save_accounts(self):
|
|
||||||
d = {}
|
|
||||||
for k, v in self.accounts.items():
|
|
||||||
d[k] = v.dump()
|
|
||||||
self.storage.put('accounts', d, True)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def load_accounts(self):
|
|
||||||
Abstract_Wallet.load_accounts(self)
|
|
||||||
d = self.storage.get('accounts', {})
|
|
||||||
for k, v in d.items():
|
|
||||||
if k == 0:
|
|
||||||
v['mpk'] = self.storage.get('master_public_key')
|
|
||||||
self.accounts[k] = OldAccount(v)
|
|
||||||
elif v.get('xpub3'):
|
|
||||||
self.accounts[k] = BIP32_Account_2of3(v)
|
|
||||||
elif v.get('xpub2'):
|
|
||||||
self.accounts[k] = BIP32_Account_2of2(v)
|
|
||||||
elif v.get('xpub'):
|
|
||||||
self.accounts[k] = BIP32_Account(v)
|
|
||||||
elif v.get('pending'):
|
|
||||||
self.accounts[k] = PendingAccount(v)
|
|
||||||
else:
|
|
||||||
print_error("cannot load account", v)
|
|
||||||
|
|
||||||
|
|
||||||
def account_is_pending(self, k):
|
def account_is_pending(self, k):
|
||||||
return type(self.accounts.get(k)) == PendingAccount
|
return type(self.accounts.get(k)) == PendingAccount
|
||||||
|
@ -1393,6 +1336,10 @@ class NewWallet(Deterministic_Wallet):
|
||||||
xpriv = pw_decode( k, password)
|
xpriv = pw_decode( k, password)
|
||||||
return xpriv
|
return xpriv
|
||||||
|
|
||||||
|
def check_password(self, password):
|
||||||
|
xpriv = self.get_master_private_key( "m/", password )
|
||||||
|
xpub = self.master_public_keys["m/"]
|
||||||
|
assert deserialize_xkey(xpriv)[3] == deserialize_xkey(xpub)[3]
|
||||||
|
|
||||||
def create_watching_only_wallet(self, xpub):
|
def create_watching_only_wallet(self, xpub):
|
||||||
self.storage.put('seed_version', self.seed_version, True)
|
self.storage.put('seed_version', self.seed_version, True)
|
||||||
|
@ -1611,9 +1558,12 @@ class OldWallet(Deterministic_Wallet):
|
||||||
|
|
||||||
def get_seed(self, password):
|
def get_seed(self, password):
|
||||||
seed = pw_decode(self.seed, password)
|
seed = pw_decode(self.seed, password)
|
||||||
self.accounts[0].check_seed(seed)
|
|
||||||
return seed
|
return seed
|
||||||
|
|
||||||
|
def check_password(self, password):
|
||||||
|
seed = pw_decode(self.seed, password)
|
||||||
|
self.accounts[0].check_seed(seed)
|
||||||
|
|
||||||
def get_mnemonic(self, password):
|
def get_mnemonic(self, password):
|
||||||
import mnemonic
|
import mnemonic
|
||||||
s = pw_decode(self.seed, password)
|
s = pw_decode(self.seed, password)
|
||||||
|
@ -1641,21 +1591,6 @@ class OldWallet(Deterministic_Wallet):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_private_key(self, address, password):
|
|
||||||
if self.is_watching_only():
|
|
||||||
return []
|
|
||||||
|
|
||||||
out = []
|
|
||||||
if address in self.imported_keys.keys():
|
|
||||||
self.check_password(password)
|
|
||||||
out.append( pw_decode( self.imported_keys[address], password ) )
|
|
||||||
else:
|
|
||||||
seed = self.get_seed(password)
|
|
||||||
account_id, sequence = self.get_address_index(address)
|
|
||||||
pk = self.accounts[0].get_private_key(seed, sequence)
|
|
||||||
out.append(pk)
|
|
||||||
return out
|
|
||||||
|
|
||||||
def check_pending_accounts(self):
|
def check_pending_accounts(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -1757,8 +1692,8 @@ class Wallet(object):
|
||||||
def from_address(self, text, storage):
|
def from_address(self, text, storage):
|
||||||
w = Imported_Wallet(storage)
|
w = Imported_Wallet(storage)
|
||||||
for x in text.split():
|
for x in text.split():
|
||||||
w.imported_keys[x] = ''
|
w.accounts[IMPORTED_ACCOUNT].add(x, None, None, None)
|
||||||
w.storage.put('imported_keys', w.imported_keys, True)
|
w.save_accounts()
|
||||||
return w
|
return w
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
Loading…
Reference in New Issue