use separata class for old wallets; decide with WalletFactory
This commit is contained in:
211
lib/wallet.py
211
lib/wallet.py
@@ -308,29 +308,6 @@ class Wallet:
|
||||
self.seed = unicodedata.normalize('NFC', unicode(seed.strip()))
|
||||
return
|
||||
|
||||
# find out what kind of wallet we are
|
||||
try:
|
||||
seed.strip().decode('hex')
|
||||
self.seed_version = 4
|
||||
self.seed = str(seed)
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
words = seed.split()
|
||||
try:
|
||||
mnemonic.mn_decode(words)
|
||||
uses_electrum_words = True
|
||||
except Exception:
|
||||
uses_electrum_words = False
|
||||
|
||||
if uses_electrum_words and len(words) != 13:
|
||||
self.seed_version = 4
|
||||
self.seed = mnemonic.mn_decode(words)
|
||||
else:
|
||||
#assert is_seed(seed)
|
||||
self.seed_version = SEED_VERSION
|
||||
self.seed = seed
|
||||
|
||||
|
||||
def save_seed(self, password):
|
||||
@@ -343,18 +320,8 @@ class Wallet:
|
||||
self.create_accounts(password)
|
||||
|
||||
|
||||
def create_watching_only_wallet(self, params):
|
||||
K0, c0 = params
|
||||
if not K0:
|
||||
return
|
||||
|
||||
if not c0:
|
||||
self.seed_version = 4
|
||||
self.storage.put('seed_version', self.seed_version, True)
|
||||
self.create_old_account(K0)
|
||||
return
|
||||
|
||||
cK0 = ""
|
||||
def create_watching_only_wallet(self, K0, c0):
|
||||
cK0 = "" #FIXME
|
||||
self.master_public_keys = {
|
||||
"m/0'/": (c0, K0, cK0),
|
||||
}
|
||||
@@ -365,14 +332,9 @@ class Wallet:
|
||||
|
||||
def create_accounts(self, password):
|
||||
seed = pw_decode(self.seed, password)
|
||||
|
||||
if self.seed_version == 4:
|
||||
mpk = OldAccount.mpk_from_seed(seed)
|
||||
self.create_old_account(mpk)
|
||||
else:
|
||||
# create default account
|
||||
self.create_master_keys('1', password)
|
||||
self.create_account('1','Main account')
|
||||
# create default account
|
||||
self.create_master_keys('1', password)
|
||||
self.create_account('1','Main account')
|
||||
|
||||
|
||||
def create_master_keys(self, account_type, password):
|
||||
@@ -532,12 +494,6 @@ class Wallet:
|
||||
self.set_label(k, name)
|
||||
|
||||
|
||||
def create_old_account(self, mpk):
|
||||
self.storage.put('master_public_key', mpk, True)
|
||||
self.accounts[0] = OldAccount({'mpk':mpk, 0:[], 1:[]})
|
||||
self.save_accounts()
|
||||
|
||||
|
||||
def save_accounts(self):
|
||||
d = {}
|
||||
for k, v in self.accounts.items():
|
||||
@@ -602,11 +558,8 @@ class Wallet:
|
||||
return s[0] == 1
|
||||
|
||||
def get_master_public_key(self):
|
||||
if self.seed_version == 4:
|
||||
return self.storage.get("master_public_key")
|
||||
else:
|
||||
c, K, cK = self.storage.get("master_public_keys")["m/0'/"]
|
||||
return repr((c, K))
|
||||
c, K, cK = self.storage.get("master_public_keys")["m/0'/"]
|
||||
return repr((c, K))
|
||||
|
||||
def get_master_private_key(self, account, password):
|
||||
k = self.master_private_keys.get(account)
|
||||
@@ -685,21 +638,12 @@ class Wallet:
|
||||
|
||||
def get_seed(self, password):
|
||||
s = pw_decode(self.seed, password)
|
||||
if self.seed_version == 4:
|
||||
seed = s
|
||||
self.accounts[0].check_seed(seed)
|
||||
else:
|
||||
seed = mnemonic_to_seed(s,'').encode('hex')
|
||||
seed = mnemonic_to_seed(s,'').encode('hex')
|
||||
return seed
|
||||
|
||||
|
||||
|
||||
def get_mnemonic(self, password):
|
||||
import mnemonic
|
||||
s = pw_decode(self.seed, password)
|
||||
if self.seed_version == 4:
|
||||
return ' '.join(mnemonic.mn_encode(s))
|
||||
else:
|
||||
return s
|
||||
return pw_decode(self.seed, password)
|
||||
|
||||
|
||||
def get_private_key(self, address, password):
|
||||
@@ -752,23 +696,6 @@ class Wallet:
|
||||
for txin in tx.inputs:
|
||||
keyid = txin.get('KeyID')
|
||||
if keyid:
|
||||
|
||||
if self.seed_version == 4:
|
||||
m = re.match("old\(([0-9a-f]+),(\d+),(\d+)", keyid)
|
||||
if not m: continue
|
||||
mpk = m.group(1)
|
||||
if mpk != self.storage.get('master_public_key'): continue
|
||||
for_change = int(m.group(2))
|
||||
num = int(m.group(3))
|
||||
account = self.accounts[0]
|
||||
addr = account.get_address(for_change, num)
|
||||
txin['address'] = addr # fixme: side effect
|
||||
pk = account.get_private_key(seed, (for_change, num))
|
||||
pubkey = public_key_from_private_key(pk)
|
||||
keypairs[pubkey] = pk
|
||||
continue
|
||||
|
||||
|
||||
roots = []
|
||||
for s in keyid.split('&'):
|
||||
m = re.match("bip32\(([0-9a-f]+),([0-9a-f]+),(/\d+/\d+/\d+)", s)
|
||||
@@ -1056,29 +983,23 @@ class Wallet:
|
||||
|
||||
|
||||
def get_account_name(self, k):
|
||||
if k == 0:
|
||||
if self.seed_version == 4:
|
||||
name = 'Main account'
|
||||
default = "Unnamed account"
|
||||
m = re.match("m/0'/(\d+)", k)
|
||||
if m:
|
||||
num = m.group(1)
|
||||
if num == '0':
|
||||
default = "Main account"
|
||||
else:
|
||||
name = 'Old account'
|
||||
else:
|
||||
default = "Unnamed account"
|
||||
m = re.match("m/0'/(\d+)", k)
|
||||
if m:
|
||||
num = m.group(1)
|
||||
if num == '0':
|
||||
default = "Main account"
|
||||
else:
|
||||
default = "Account %s"%num
|
||||
default = "Account %s"%num
|
||||
|
||||
m = re.match("m/1'/(\d+) & m/2'/(\d+)", k)
|
||||
if m:
|
||||
num = m.group(1)
|
||||
default = "2of2 account %s"%num
|
||||
name = self.labels.get(k, default)
|
||||
|
||||
m = re.match("m/1'/(\d+) & m/2'/(\d+)", k)
|
||||
if m:
|
||||
num = m.group(1)
|
||||
default = "2of2 account %s"%num
|
||||
name = self.labels.get(k, default)
|
||||
return name
|
||||
|
||||
|
||||
def get_account_names(self):
|
||||
accounts = {}
|
||||
for k, account in self.accounts.items():
|
||||
@@ -1087,6 +1008,7 @@ class Wallet:
|
||||
accounts[-1] = 'Imported keys'
|
||||
return accounts
|
||||
|
||||
|
||||
def get_account_addresses(self, a, include_change=True):
|
||||
if a is None:
|
||||
o = self.addresses(True)
|
||||
@@ -1764,3 +1686,88 @@ class WalletSynchronizer(threading.Thread):
|
||||
self.was_updated = False
|
||||
|
||||
|
||||
|
||||
|
||||
class OldWallet(Wallet):
|
||||
|
||||
def init_seed(self, seed):
|
||||
import mnemonic
|
||||
|
||||
if self.seed:
|
||||
raise Exception("a seed exists")
|
||||
|
||||
if not seed:
|
||||
raise
|
||||
|
||||
self.seed_version = 4
|
||||
|
||||
# see if seed was entered as hex
|
||||
try:
|
||||
seed.strip().decode('hex')
|
||||
self.seed = str(seed)
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
words = seed.split()
|
||||
try:
|
||||
mnemonic.mn_decode(words)
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
self.seed = mnemonic.mn_decode(words)
|
||||
|
||||
|
||||
def get_master_public_key(self):
|
||||
return self.storage.get("master_public_key")
|
||||
|
||||
def create_accounts(self, password):
|
||||
seed = pw_decode(self.seed, password)
|
||||
mpk = OldAccount.mpk_from_seed(seed)
|
||||
self.create_account(mpk)
|
||||
|
||||
def create_account(self, mpk):
|
||||
self.storage.put('master_public_key', mpk, True)
|
||||
self.accounts[0] = OldAccount({'mpk':mpk, 0:[], 1:[]})
|
||||
self.save_accounts()
|
||||
|
||||
def create_watching_only_wallet(self, K0):
|
||||
self.seed_version = 4
|
||||
self.storage.put('seed_version', self.seed_version, True)
|
||||
self.create_account(K0)
|
||||
|
||||
def get_seed(self, password):
|
||||
seed = pw_decode(self.seed, password)
|
||||
self.accounts[0].check_seed(seed)
|
||||
return seed
|
||||
|
||||
def get_mnemonic(self, password):
|
||||
import mnemonic
|
||||
s = pw_decode(self.seed, password)
|
||||
return ' '.join(mnemonic.mn_encode(s))
|
||||
|
||||
|
||||
def add_keypairs_from_KeyID(self, tx, keypairs, password):
|
||||
# first check the provided password
|
||||
seed = self.get_seed(password)
|
||||
for txin in tx.inputs:
|
||||
keyid = txin.get('KeyID')
|
||||
if keyid:
|
||||
m = re.match("old\(([0-9a-f]+),(\d+),(\d+)", keyid)
|
||||
if not m: continue
|
||||
mpk = m.group(1)
|
||||
if mpk != self.storage.get('master_public_key'): continue
|
||||
for_change = int(m.group(2))
|
||||
num = int(m.group(3))
|
||||
account = self.accounts[0]
|
||||
addr = account.get_address(for_change, num)
|
||||
txin['address'] = addr # fixme: side effect
|
||||
pk = account.get_private_key(seed, (for_change, num))
|
||||
pubkey = public_key_from_private_key(pk)
|
||||
keypairs[pubkey] = pk
|
||||
|
||||
|
||||
def get_account_name(self, k):
|
||||
assert k == 0
|
||||
return 'Main account'
|
||||
|
||||
|
||||
@@ -1,11 +1,53 @@
|
||||
from version import SEED_VERSION
|
||||
from wallet import OldWallet, Wallet
|
||||
|
||||
class WalletFactory(object):
|
||||
def __new__(cls, config):
|
||||
if config.get('bitkey', False):
|
||||
def __new__(self, storage):
|
||||
|
||||
if storage.get('bitkey', False):
|
||||
# if user requested support for Bitkey device,
|
||||
# import Bitkey driver
|
||||
from wallet_bitkey import WalletBitkey
|
||||
return WalletBitkey(config)
|
||||
|
||||
# Load standard wallet
|
||||
from wallet import Wallet
|
||||
return Wallet(config)
|
||||
seed_version = storage.get('seed_version', SEED_VERSION)
|
||||
if seed_version not in [4, 6]:
|
||||
msg = "This wallet seed is not supported."
|
||||
if seed_version in [5]:
|
||||
msg += "\nTo open this wallet, try 'git checkout seed_v%d'"%seed_version
|
||||
print msg
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if seed_version == 4:
|
||||
return OldWallet(storage)
|
||||
else:
|
||||
return Wallet(storage)
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_seed(self, seed, storage):
|
||||
import mnemonic
|
||||
words = seed.strip().split()
|
||||
try:
|
||||
mnemonic.mn_decode(words)
|
||||
uses_electrum_words = True
|
||||
except Exception:
|
||||
uses_electrum_words = False
|
||||
|
||||
try:
|
||||
seed.decode('hex')
|
||||
is_hex = True
|
||||
except Exception:
|
||||
is_hex = False
|
||||
|
||||
if is_hex or (uses_electrum_words and len(words) != 13):
|
||||
print "old style wallet", len(words), words
|
||||
w = OldWallet(storage)
|
||||
w.init_seed(seed) #hex
|
||||
else:
|
||||
#assert is_seed(seed)
|
||||
w = Wallet(storage)
|
||||
w.init_seed(seed)
|
||||
|
||||
return w
|
||||
|
||||
Reference in New Issue
Block a user