First cleanup branch commit

This fixes some import and whitespace issues to align closer to pep8.
I added a few comments to make further contributions easier.
This commit is contained in:
Chris Glass 2014-06-24 16:12:43 +03:00
parent 2c7bf3ca1a
commit 01f3e31c6b
2 changed files with 75 additions and 208 deletions

View File

@ -16,13 +16,16 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import datetime
import time
from util import *
from bitcoin import *
import copy
from util import print_msg, format_satoshis
from bitcoin import is_valid, hash_160_to_bc_address, hash_160
from decimal import Decimal
import bitcoin
from transaction import Transaction
class Command:
def __init__(self, name, min_args, max_args, requires_network, requires_wallet, requires_password, description, syntax = '', options_syntax = ''):
self.name = name
@ -35,7 +38,10 @@ class Command:
self.syntax = syntax
self.options = options_syntax
known_commands = {}
def register_command(*args):
global known_commands
name = args[0]
@ -105,8 +111,6 @@ register_command('getutxoaddress', 2, 2, True, False, False, 'get the addr
register_command('sweep', 2, 3, True, False, False, 'Sweep a private key.', 'sweep privkey addr [fee]')
class Commands:
def __init__(self, wallet, network, callback = None):
@ -115,7 +119,6 @@ class Commands:
self._callback = callback
self.password = None
def _run(self, method, args, password_getter):
cmd = known_commands[method]
if cmd.requires_password and self.wallet.use_encryption:
@ -127,40 +130,33 @@ class Commands:
apply(self._callback, ())
return result
def getaddresshistory(self, addr):
return self.network.synchronous_get([ ('blockchain.address.get_history',[addr]) ])[0]
def daemon(self, arg):
if arg=='stop':
return self.network.stop()
elif arg=='status':
return {
'server':self.network.main_server(),
return {
'server':self.network.main_server(),
'connected':self.network.is_connected()
}
else:
return "unknown command \"%s\""% arg
def listunspent(self):
import copy
l = copy.deepcopy(self.wallet.get_unspent_coins())
for i in l: i["value"] = str(Decimal(i["value"])/100000000)
return l
def getaddressunspent(self, addr):
return self.network.synchronous_get([ ('blockchain.address.listunspent',[addr]) ])[0]
def getutxoaddress(self, txid, num):
r = self.network.synchronous_get([ ('blockchain.utxo.get_address',[txid, num]) ])
if r:
if r:
return {'address':r[0] }
def createrawtransaction(self, inputs, outputs):
for i in inputs:
i['prevout_hash'] = i['txid']
@ -169,7 +165,6 @@ class Commands:
tx = Transaction.from_io(inputs, outputs)
return tx
def signrawtransaction(self, raw_tx, private_keys):
tx = Transaction(raw_tx)
self.wallet.signrawtransaction(tx, private_keys, self.password)
@ -188,10 +183,10 @@ class Commands:
redeem_script = Transaction.multisig_script(pubkeys, num)
address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 5)
return {'address':address, 'redeemScript':redeem_script}
def freeze(self,addr):
return self.wallet.freeze(addr)
def unfreeze(self,addr):
return self.wallet.unfreeze(addr)
@ -215,7 +210,6 @@ class Commands:
out['pubkeys'] = self.wallet.getpubkeys(addr)
return out
def getbalance(self, account= None):
if account is None:
c, u = self.wallet.get_balance()
@ -232,7 +226,6 @@ class Commands:
out["unconfirmed"] = str(Decimal(out["unconfirmed"])/100000000)
return out
def getproof(self, addr):
p = self.network.synchronous_get([ ('blockchain.address.get_proof',[addr]) ])[0]
out = []
@ -246,9 +239,9 @@ class Commands:
return self.network.get_servers()
def getversion(self):
import electrum
import electrum # Needs to stay here to prevent ciruclar imports
return electrum.ELECTRUM_VERSION
def getmpk(self):
return self.wallet.get_master_public_keys()
@ -264,20 +257,16 @@ class Commands:
out = "Error: Keypair import failed: " + str(e)
return out
def sweep(self, privkey, to_address, fee = 0.0001):
fee = int(Decimal(fee)*100000000)
return Transaction.sweep([privkey], self.network, to_address, fee)
def signmessage(self, address, message):
return self.wallet.sign_message(address, message, self.password)
def verifymessage(self, address, signature, message):
return bitcoin.verify_message(address, signature, message)
def _mktx(self, outputs, fee = None, change_addr = None, domain = None):
for to_address, amount in outputs:
@ -292,7 +281,7 @@ class Commands:
for addr in domain:
if not is_valid(addr):
raise Exception("invalid Bitcoin address", addr)
if not self.wallet.is_mine(addr):
raise Exception("address not in wallet", addr)
@ -310,11 +299,10 @@ class Commands:
amount = int(100000000*amount)
final_outputs.append((to_address, amount))
if fee: fee = int(100000000*fee)
return self.wallet.mktx(final_outputs, self.password, fee , change_addr, domain)
def mktx(self, to_address, amount, fee = None, change_addr = None, domain = None):
tx = self._mktx([(to_address, amount)], fee, change_addr, domain)
return tx
@ -323,7 +311,6 @@ class Commands:
tx = self._mktx(outputs, fee, change_addr, domain)
return tx
def payto(self, to_address, amount, fee = None, change_addr = None, domain = None):
tx = self._mktx([(to_address, amount)], fee, change_addr, domain)
r, h = self.wallet.sendtx( tx )
@ -334,9 +321,7 @@ class Commands:
r, h = self.wallet.sendtx( tx )
return h
def history(self):
import datetime
balance = 0
out = []
for item in self.wallet.get_tx_history():
@ -351,20 +336,15 @@ class Commands:
out.append({'txid':tx_hash, 'date':"%16s"%time_str, 'label':label, 'value':format_satoshis(value)})
return out
def setlabel(self, key, label):
self.wallet.set_label(key, label)
def contacts(self):
c = {}
for addr in self.wallet.addressbook:
c[addr] = self.wallet.labels.get(addr)
return c
def listaddresses(self, show_all = False, show_label = False):
out = []
for addr in self.wallet.addresses(True):
@ -379,7 +359,7 @@ class Commands:
item = addr
out.append( item )
return out
def help(self, cmd=None):
if cmd not in known_commands:
print_msg("\nList of commands:", ', '.join(sorted(known_commands)))
@ -390,9 +370,7 @@ class Commands:
if cmd.options: print_msg("options:\n" + cmd.options)
return None
def getrawtransaction(self, tx_hash):
import transaction
if self.wallet:
tx = self.wallet.transactions.get(tx_hash)
if tx:
@ -400,17 +378,12 @@ class Commands:
r = self.network.synchronous_get([ ('blockchain.transaction.get',[tx_hash]) ])[0]
if r:
return transaction.Transaction(r)
return Transaction(r)
else:
return "unknown transaction"
def encrypt(self, pubkey, message):
return bitcoin.encrypt_message(message, pubkey)
def decrypt(self, pubkey, message):
return self.wallet.decrypt_message(pubkey, message, self.password)

View File

@ -17,24 +17,21 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import base64
import os
import re
import hashlib
import copy
import operator
import ast
import threading
import random
import aes
import Queue
import time
import math
from util import print_msg, print_error, format_satoshis
from util import print_msg, print_error
from bitcoin import *
from account import *
from transaction import Transaction, is_extended_pubkey
from version import *
from transaction import Transaction
from plugins import run_hook
import bitcoin
from synchronizer import WalletSynchronizer
@ -47,9 +44,6 @@ IMPORTED_ACCOUNT = '/x'
from version import *
class WalletStorage:
def __init__(self, config):
@ -109,7 +103,7 @@ class WalletStorage:
def get(self, key, default=None):
v = self.data.get(key)
if v is None:
if v is None:
v = default
return v
@ -120,7 +114,7 @@ class WalletStorage:
self.data[key] = value
elif key in self.data:
self.data.pop(key)
if save:
if save:
self.write()
def write(self):
@ -129,19 +123,13 @@ class WalletStorage:
f.write( s )
f.close()
if 'ANDROID_DATA' not in os.environ:
import stat
import stat #XXX: IS this really android only?
os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE)
class Abstract_Wallet:
def __init__(self, storage):
self.storage = storage
self.electrum_version = ELECTRUM_VERSION
self.gap_limit_for_change = 3 # constant
@ -198,16 +186,14 @@ class Abstract_Wallet:
# there is a difference between wallet.up_to_date and interface.is_up_to_date()
# interface.is_up_to_date() returns true when all requests have been answered and processed
# wallet.up_to_date is true when the wallet is synchronized (stronger requirement)
self.up_to_date = False
self.lock = threading.Lock()
self.transaction_lock = threading.Lock()
self.tx_event = threading.Event()
for tx_hash, tx in self.transactions.items():
self.update_tx_outputs(tx_hash)
def add_extra_addresses(self, tx):
h = tx.hash()
# find the address corresponding to pay-to-pubkey inputs
@ -217,11 +203,9 @@ class Abstract_Wallet:
for tx2 in self.transactions.values():
tx2.add_extra_addresses({h:tx})
def get_action(self):
pass
def convert_imported_keys(self, password):
for k, v in self.imported_keys.items():
sec = pw_decode(v, password)
@ -232,7 +216,6 @@ class Abstract_Wallet:
self.imported_keys.pop(k)
self.storage.put('imported_keys', self.imported_keys)
def load_accounts(self):
self.accounts = {}
self.imported_keys = self.storage.get('imported_keys',{})
@ -255,7 +238,6 @@ class Abstract_Wallet:
else:
print_error("cannot load account", v)
def synchronize(self):
pass
@ -268,15 +250,14 @@ class Abstract_Wallet:
def is_up_to_date(self):
with self.lock: return self.up_to_date
def update(self):
self.up_to_date = False
while not self.is_up_to_date():
while not self.is_up_to_date():
time.sleep(0.1)
def is_imported(self, addr):
account = self.accounts.get(IMPORTED_ACCOUNT)
if account:
if account:
return addr in account.get_addresses(0)
else:
return False
@ -294,16 +275,15 @@ class Abstract_Wallet:
if self.is_mine(address):
raise Exception('Address already in wallet')
if self.accounts.get(IMPORTED_ACCOUNT) is None:
self.accounts[IMPORTED_ACCOUNT] = ImportedAccount({'imported':{}})
self.accounts[IMPORTED_ACCOUNT].add(address, pubkey, sec, password)
self.save_accounts()
if self.synchronizer:
self.synchronizer.subscribe_to_addresses([address])
return address
def delete_imported_key(self, addr):
account = self.accounts[IMPORTED_ACCOUNT]
@ -312,7 +292,6 @@ class Abstract_Wallet:
self.accounts.pop(IMPORTED_ACCOUNT)
self.save_accounts()
def set_label(self, name, text = None):
changed = False
old_text = self.labels.get(name)
@ -331,9 +310,6 @@ class Abstract_Wallet:
run_hook('set_label', name, text, changed)
return changed
def addresses(self, include_change = True, _next=True):
o = []
for a in self.accounts.keys():
@ -345,10 +321,8 @@ class Abstract_Wallet:
o += [addr]
return o
def is_mine(self, address):
return address in self.addresses(True)
return address in self.addresses(True)
def is_change(self, address):
if not self.is_mine(address): return False
@ -356,7 +330,6 @@ class Abstract_Wallet:
if s is None: return False
return s[0] == 1
def get_address_index(self, address):
for account in self.accounts.keys():
@ -372,26 +345,22 @@ class Abstract_Wallet:
raise Exception("Address not found", address)
def getpubkeys(self, addr):
assert is_valid(addr) and self.is_mine(addr)
account, sequence = self.get_address_index(addr)
a = self.accounts[account]
return a.get_pubkeys( sequence )
def get_private_key(self, address, password):
if self.is_watching_only():
return []
account_id, sequence = self.get_address_index(address)
return self.accounts[account_id].get_private_key(sequence, self, password)
def get_public_keys(self, address):
account_id, sequence = self.get_address_index(address)
return self.accounts[account_id].get_pubkeys(sequence)
def can_sign(self, tx):
if self.is_watching_only():
@ -411,15 +380,11 @@ class Abstract_Wallet:
return True
return False
def add_keypairs(self, tx, keypairs, password):
# first check the provided password
seed = self.get_seed(password)
# first check the provided password. This will raise if invalid.
self.get_seed(password)
addr_list, xpub_list = tx.inputs_to_sign()
for addr in addr_list:
if self.is_mine(addr):
private_keys = self.get_private_key(address, password)
@ -441,12 +406,9 @@ class Abstract_Wallet:
pubkey = public_key_from_private_key(sec)
keypairs[pubkey] = sec
def signrawtransaction(self, tx, private_keys, password):
# check that the password is correct
seed = self.get_seed(password)
# check that the password is correct. This will raise if it's not.
self.get_seed(password)
# build a list of public/private keys
keypairs = {}
@ -462,7 +424,6 @@ class Abstract_Wallet:
# sign the transaction
self.sign_transaction(tx, keypairs, password)
def sign_message(self, address, message, password):
keys = self.get_private_key(address, password)
assert len(keys) == 1
@ -471,8 +432,6 @@ class Abstract_Wallet:
compressed = is_compressed(sec)
return key.sign_message(message, compressed, address)
def decrypt_message(self, pubkey, message, password):
address = public_key_to_bc_address(pubkey.decode('hex'))
keys = self.get_private_key(address, password)
@ -481,25 +440,20 @@ class Abstract_Wallet:
decrypted = ec.decrypt_message(message)
return decrypted
def is_found(self):
return self.history.values() != [[]] * len(self.history)
return self.history.values() != [[]] * len(self.history)
def add_contact(self, address, label=None):
self.addressbook.append(address)
self.storage.put('contacts', self.addressbook, True)
if label:
if label:
self.set_label(address, label)
def delete_contact(self, addr):
if addr in self.addressbook:
self.addressbook.remove(addr)
self.storage.put('addressbook', self.addressbook, True)
def fill_addressbook(self):
for tx_hash, tx in self.transactions.items():
is_relevant, is_send, _, _ = self.get_tx_value(tx)
@ -511,23 +465,20 @@ class Abstract_Wallet:
# self.update_tx_labels()
def get_num_tx(self, address):
n = 0
n = 0
for tx in self.transactions.values():
if address in map(lambda x:x[0], tx.outputs): n += 1
return n
def get_address_flags(self, addr):
flags = "C" if self.is_change(addr) else "I" if addr in self.imported_keys.keys() else "-"
flags = "C" if self.is_change(addr) else "I" if addr in self.imported_keys.keys() else "-"
flags += "F" if addr in self.frozen_addresses else "-"
return flags
def get_tx_value(self, tx, account=None):
domain = self.get_account_addresses(account)
return tx.get_value(domain, self.prevout_values)
def update_tx_outputs(self, tx_hash):
tx = self.transactions.get(tx_hash)
@ -540,7 +491,6 @@ class Abstract_Wallet:
key = item['prevout_hash'] + ':%d'%item['prevout_n']
self.spent_outputs.append(key)
def get_addr_balance(self, address):
#assert self.is_mine(address)
h = self.history.get(address,[])
@ -567,7 +517,7 @@ class Abstract_Wallet:
if addr == address:
key = item['prevout_hash'] + ':%d'%item['prevout_n']
value = self.prevout_values.get( key )
if key in received_coins:
if key in received_coins:
v -= value
for i, (addr, value) in enumerate(tx.outputs):
@ -581,18 +531,15 @@ class Abstract_Wallet:
u += v
return c, u
def get_account_name(self, k):
return self.labels.get(k, self.accounts[k].get_name(k))
def get_account_names(self):
account_names = {}
for k in self.accounts.keys():
account_names[k] = self.get_account_name(k)
return account_names
def get_account_addresses(self, a, include_change=True):
if a is None:
o = self.addresses(True)
@ -602,13 +549,12 @@ class Abstract_Wallet:
if include_change: o += ac.get_addresses(1)
return o
def get_account_balance(self, account):
return self.get_balance(self.get_account_addresses(account))
def get_frozen_balance(self):
return self.get_balance(self.frozen_addresses)
def get_balance(self, domain=None):
if domain is None: domain = self.addresses(True)
cc = uu = 0
@ -618,7 +564,6 @@ class Abstract_Wallet:
uu += u
return cc, uu
def get_unspent_coins(self, domain=None):
coins = []
if domain is None: domain = self.addresses(True)
@ -643,11 +588,10 @@ class Abstract_Wallet:
if coins:
coins = sorted(coins)
if coins[-1][0] != 0:
while coins[0][0] == 0:
while coins[0][0] == 0:
coins = coins[1:] + [ coins[0] ]
return [x[1] for x in coins]
def choose_tx_inputs( self, amount, fixed_fee, num_outputs, domain = None, coins = None ):
""" todo: minimize tx size """
total = 0
@ -665,7 +609,6 @@ class Abstract_Wallet:
for item in coins:
if item.get('coinbase') and item.get('height') + COINBASE_MATURITY > self.network.get_local_height():
continue
addr = item.get('address')
v = item.get('value')
total += v
inputs.append(item)
@ -676,18 +619,16 @@ class Abstract_Wallet:
return inputs, total, fee
def set_fee(self, fee):
if self.fee != fee:
self.fee = fee
self.storage.put('fee_per_kb', self.fee, True)
def estimated_fee(self, inputs, num_outputs):
estimated_size = len(inputs) * 180 + num_outputs * 34 # this assumes non-compressed keys
fee = self.fee * int(math.ceil(estimated_size/1000.))
return fee
def add_tx_change( self, inputs, outputs, amount, fee, total, change_addr=None):
"add change to a transaction"
change_amount = total - ( amount + fee )
@ -708,12 +649,10 @@ class Abstract_Wallet:
outputs[posn:posn] = [( change_addr, change_amount)]
return outputs
def get_history(self, address):
with self.lock:
return self.history.get(address)
def get_status(self, h):
if not h: return None
if h == ['*']: return '*'
@ -722,7 +661,6 @@ class Abstract_Wallet:
status += tx_hash + ':%d:' % height
return hashlib.sha256( status ).digest().encode('hex')
def receive_tx_callback(self, tx_hash, tx, tx_height):
with self.transaction_lock:
@ -734,11 +672,10 @@ class Abstract_Wallet:
self.transactions[tx_hash] = tx
self.network.pending_transactions_for_notifications.append(tx)
self.save_transactions()
if self.verifier and tx_height>0:
if self.verifier and tx_height>0:
self.verifier.add(tx_hash, tx_height)
self.update_tx_outputs(tx_hash)
def save_transactions(self):
tx = {}
for k,v in self.transactions.items():
@ -749,7 +686,7 @@ class Abstract_Wallet:
if not self.check_new_history(addr, hist):
raise Exception("error: received history for %s is not consistent with known transactions"%addr)
with self.lock:
self.history[addr] = hist
self.storage.put('addr_history', self.history, True)
@ -760,7 +697,6 @@ class Abstract_Wallet:
# add it in case it was previously unconfirmed
if self.verifier: self.verifier.add(tx_hash, tx_height)
def get_tx_history(self, account=None):
if not self.verifier:
return []
@ -769,7 +705,7 @@ class Abstract_Wallet:
history = self.transactions.items()
history.sort(key = lambda x: self.verifier.get_txpos(x[0]))
result = []
balance = 0
for tx_hash, tx in history:
is_relevant, is_mine, v, fee = self.get_tx_value(tx, account)
@ -793,14 +729,12 @@ class Abstract_Wallet:
return result
def get_label(self, tx_hash):
label = self.labels.get(tx_hash)
is_default = (label == '') or (label is None)
if is_default: label = self.get_default_label(tx_hash)
return label, is_default
def get_default_label(self, tx_hash):
tx = self.transactions.get(tx_hash)
default_label = ''
@ -831,7 +765,6 @@ class Abstract_Wallet:
o_addr = None
if o_addr:
dest_label = self.labels.get(o_addr)
try:
default_label = self.labels[o_addr]
except KeyError:
@ -839,7 +772,6 @@ class Abstract_Wallet:
return default_label
def make_unsigned_transaction(self, outputs, fee=None, change_addr=None, domain=None, coins=None ):
for address, x in outputs:
assert is_valid(address), "Address " + address + " is invalid!"
@ -852,7 +784,6 @@ class Abstract_Wallet:
outputs = self.add_tx_change(inputs, outputs, amount, fee, total, change_addr)
return Transaction.from_io(inputs, outputs)
def mktx(self, outputs, password, fee=None, change_addr=None, domain= None, coins = None ):
tx = self.make_unsigned_transaction(outputs, fee, change_addr, domain, coins)
keypairs = {}
@ -861,7 +792,6 @@ class Abstract_Wallet:
self.sign_transaction(tx, keypairs, password)
return tx
def add_input_info(self, txin):
address = txin['address']
account_id, sequence = self.get_address_index(address)
@ -871,19 +801,17 @@ class Abstract_Wallet:
txin['pubkeys'] = pubkeys = account.get_pubkeys(sequence)
txin['signatures'] = [None] * len(pubkeys)
if redeemScript:
if redeemScript:
txin['redeemScript'] = redeemScript
txin['num_sig'] = 2
else:
txin['redeemPubkey'] = account.get_pubkey(*sequence)
txin['num_sig'] = 1
def sign_transaction(self, tx, keypairs, password):
tx.sign(keypairs)
run_hook('sign_transaction', tx, password)
def sendtx(self, tx):
# synchronous
h = self.send_tx(tx)
@ -901,15 +829,14 @@ class Abstract_Wallet:
self.tx_event.set()
def receive_tx(self, tx_hash, tx):
out = self.tx_result
out = self.tx_result
if out != tx_hash:
return False, "error: " + out
run_hook('receive_tx', tx, self)
return True, out
def update_password(self, old_password, new_password):
if new_password == '':
if new_password == '':
new_password = None
if self.has_seed():
@ -918,7 +845,7 @@ class Abstract_Wallet:
self.storage.put('seed', self.seed, True)
imported_account = self.accounts.get(IMPORTED_ACCOUNT)
if imported_account:
if imported_account:
imported_account.update_password(old_password, new_password)
self.save_accounts()
@ -931,7 +858,6 @@ class Abstract_Wallet:
self.use_encryption = (new_password != None)
self.storage.put('use_encryption', self.use_encryption,True)
def freeze(self,addr):
if self.is_mine(addr) and addr not in self.frozen_addresses:
self.frozen_addresses.append(addr)
@ -940,7 +866,6 @@ class Abstract_Wallet:
else:
return False
def unfreeze(self,addr):
if self.is_mine(addr) and addr in self.frozen_addresses:
self.frozen_addresses.remove(addr)
@ -949,7 +874,6 @@ class Abstract_Wallet:
else:
return False
def set_verifier(self, verifier):
self.verifier = verifier
@ -967,9 +891,7 @@ class Abstract_Wallet:
if tx_hash not in vr:
self.transactions.pop(tx_hash)
def check_new_history(self, addr, hist):
# check that all tx in hist are relevant
if hist != ['*']:
for tx_hash, height in hist:
@ -997,7 +919,7 @@ class Abstract_Wallet:
tx = self.transactions.get(tx_hash)
# tx might not be there
if not tx: continue
# already verified?
if self.verifier.get_height(tx_hash):
continue
@ -1026,14 +948,13 @@ class Abstract_Wallet:
return True
def check_new_tx(self, tx_hash, tx):
# 1 check that tx is referenced in addr_history.
# 1 check that tx is referenced in addr_history.
addresses = []
for addr, hist in self.history.items():
if hist == ['*']:continue
for txh, height in hist:
if txh == tx_hash:
if txh == tx_hash:
addresses.append(addr)
if not addresses:
@ -1046,7 +967,6 @@ class Abstract_Wallet:
return True
def start_threads(self, network):
from verifier import TxVerifier
self.network = network
@ -1084,7 +1004,7 @@ class Abstract_Wallet:
h = self.history.get(address,[])
c, u = self.get_addr_balance(address)
return len(h), len(h) > 0 and c == -u
class Imported_Wallet(Abstract_Wallet):
@ -1095,7 +1015,6 @@ class Imported_Wallet(Abstract_Wallet):
self.accounts[IMPORTED_ACCOUNT] = ImportedAccount({'imported':{}})
self.storage.put('wallet_type', 'imported', True)
def is_watching_only(self):
acc = self.accounts[IMPORTED_ACCOUNT]
n = acc.keypairs.values()
@ -1130,11 +1049,11 @@ class Deterministic_Wallet(Abstract_Wallet):
return not self.has_seed()
def add_seed(self, seed, password):
if self.seed:
if self.seed:
raise Exception("a seed exists")
self.seed_version, self.seed = self.prepare_seed(seed)
if password:
if password:
self.seed = pw_encode( self.seed, password)
self.use_encryption = True
else:
@ -1150,7 +1069,7 @@ class Deterministic_Wallet(Abstract_Wallet):
def get_mnemonic(self, password):
return self.get_seed(password)
def change_gap_limit(self, value):
if value >= self.gap_limit:
self.gap_limit = value
@ -1196,7 +1115,6 @@ class Deterministic_Wallet(Abstract_Wallet):
if n > nmax: nmax = n
return nmax + 1
def address_is_old(self, address):
age = -1
h = self.history.get(address, [])
@ -1211,7 +1129,6 @@ class Deterministic_Wallet(Abstract_Wallet):
age = tx_age
return age > 2
def synchronize_sequence(self, account, for_change):
limit = self.gap_limit_for_change if for_change else self.gap_limit
new_addresses = []
@ -1231,7 +1148,6 @@ class Deterministic_Wallet(Abstract_Wallet):
new_addresses.append( address )
return new_addresses
def check_pending_accounts(self):
for account_id, addr in self.next_addresses.items():
@ -1242,14 +1158,12 @@ class Deterministic_Wallet(Abstract_Wallet):
self.add_account(account_id, account)
self.next_addresses.pop(account_id)
def synchronize_account(self, account):
new = []
new += self.synchronize_sequence(account, 0)
new += self.synchronize_sequence(account, 1)
return new
def synchronize(self):
self.check_pending_accounts()
new = []
@ -1262,7 +1176,6 @@ class Deterministic_Wallet(Abstract_Wallet):
self.storage.put('addr_history', self.history, True)
return new
def restore(self, callback):
from i18n import _
def wait_for_wallet():
@ -1271,8 +1184,8 @@ class Deterministic_Wallet(Abstract_Wallet):
msg = "%s\n%s %d\n%s %.1f"%(
_("Please wait..."),
_("Addresses generated:"),
len(self.addresses(True)),
_("Kilobytes received:"),
len(self.addresses(True)),
_("Kilobytes received:"),
self.network.interface.bytes_received/1024.)
apply(callback, (msg,))
@ -1290,10 +1203,8 @@ class Deterministic_Wallet(Abstract_Wallet):
wait_for_wallet()
else:
self.synchronize()
self.fill_addressbook()
def create_account(self, name, password):
i = self.num_accounts()
account_id = self.account_id(i)
@ -1310,8 +1221,6 @@ class Deterministic_Wallet(Abstract_Wallet):
self.accounts[account_id] = account
self.save_accounts()
def account_is_pending(self, k):
return type(self.accounts.get(k)) == PendingAccount
@ -1327,8 +1236,6 @@ class Deterministic_Wallet(Abstract_Wallet):
self.save_accounts()
class NewWallet(Deterministic_Wallet):
def __init__(self, storage):
@ -1365,25 +1272,22 @@ class NewWallet(Deterministic_Wallet):
account = BIP32_Account({'xpub':xpub})
self.add_account("m/", account)
def create_accounts(self, password):
seed = pw_decode(self.seed, password)
# First check the password is valid (this raises if it isn't).
pw_decode(self.seed, password)
self.create_account('Main account', password)
def add_master_public_key(self, name, mpk):
self.master_public_keys[name] = mpk
self.storage.put('master_public_keys', self.master_public_keys, True)
def add_master_private_key(self, name, xpriv, password):
self.master_private_keys[name] = pw_encode(xpriv, password)
self.storage.put('master_private_keys', self.master_private_keys, True)
def add_master_keys(self, root, account_id, password):
x = self.master_private_keys.get(root)
if x:
if x:
master_xpriv = pw_decode(x, password )
xpriv, xpub = bip32_private_derivation(master_xpriv, root, account_id)
self.add_master_public_key(account_id, xpub)
@ -1394,20 +1298,17 @@ class NewWallet(Deterministic_Wallet):
self.add_master_public_key(account_id, xpub)
return xpub
def create_master_keys(self, password):
xpriv, xpub = bip32_root(mnemonic_to_seed(self.get_seed(password),'').encode('hex'))
self.add_master_public_key("m/", xpub)
self.add_master_private_key("m/", xpriv, password)
def find_root_by_master_key(self, xpub):
for key, xpub2 in self.master_public_keys.items():
if key == "m/":continue
if xpub == xpub2:
return key
def num_accounts(self):
keys = []
for k, v in self.accounts.items():
@ -1422,13 +1323,12 @@ class NewWallet(Deterministic_Wallet):
i += 1
return i
def next_account_address(self, password):
i = self.num_accounts()
account_id = self.account_id(i)
addr = self.next_addresses.get(account_id)
if not addr:
if not addr:
account = self.make_account(account_id, password)
addr = account.first_address()
self.next_addresses[account_id] = addr
@ -1445,7 +1345,6 @@ class NewWallet(Deterministic_Wallet):
account = BIP32_Account({'xpub':xpub})
return account
def make_seed(self):
import mnemonic, ecdsa
entropy = ecdsa.util.randrange( pow(2,160) )
@ -1454,7 +1353,7 @@ class NewWallet(Deterministic_Wallet):
ss = "%040x"%(entropy+nonce)
s = hashlib.sha256(ss.decode('hex')).digest().encode('hex')
# we keep only 13 words, that's approximately 139 bits of entropy
words = mnemonic.mn_encode(s)[0:13]
words = mnemonic.mn_encode(s)[0:13]
seed = ' '.join(words)
if is_new_seed(seed):
break # this will remove 8 bits of entropy
@ -1466,8 +1365,8 @@ class NewWallet(Deterministic_Wallet):
return NEW_SEED_VERSION, unicodedata.normalize('NFC', unicode(seed.strip()))
class Wallet_2of2(NewWallet):
""" This class is used for multisignature addresses"""
def __init__(self, storage):
NewWallet.__init__(self, storage)
@ -1499,8 +1398,8 @@ class Wallet_2of2(NewWallet):
return 'create_2of2_2'
class Wallet_2of3(Wallet_2of2):
""" This class is used for multisignature addresses"""
def __init__(self, storage):
Wallet_2of2.__init__(self, storage)
@ -1532,9 +1431,6 @@ class Wallet_2of3(Wallet_2of2):
return 'create_2of3_2'
class OldWallet(Deterministic_Wallet):
def make_seed(self):
@ -1557,9 +1453,8 @@ class OldWallet(Deterministic_Wallet):
seed = mnemonic.mn_decode(words)
if not seed:
raise Exception("Invalid seed")
return OLD_SEED_VERSION, seed
return OLD_SEED_VERSION, seed
def create_master_keys(self, password):
seed = self.get_seed(password)
@ -1605,6 +1500,9 @@ class OldWallet(Deterministic_Wallet):
# former WalletFactory
class Wallet(object):
"""The main wallet "entry point".
This class is actually a factory that will return a wallet of the correct
type when passed a WalletStorage instance."""
def __new__(self, storage):
config = storage.config
@ -1623,7 +1521,6 @@ class Wallet(object):
if storage.get('wallet_type') == 'imported':
return Imported_Wallet(storage)
if not storage.file_exists:
seed_version = NEW_SEED_VERSION if config.get('bip32') is True else OLD_SEED_VERSION
else:
@ -1642,8 +1539,6 @@ class Wallet(object):
print msg
sys.exit(1)
@classmethod
def is_seed(self, seed):
if not seed:
@ -1652,7 +1547,7 @@ class Wallet(object):
return True
elif is_new_seed(seed):
return True
else:
else:
return False
@classmethod
@ -1662,7 +1557,7 @@ class Wallet(object):
old = True
except:
old = False
if old:
return len(mpk) == 128
else:
@ -1716,7 +1611,6 @@ class Wallet(object):
@classmethod
def from_mpk(self, mpk, storage):
try:
int(mpk, 16)
old = True