Merge pull request #730 from chrisglass/pep8ing-phase-one

First cleanup branch
This commit is contained in:
ThomasV 2014-06-24 16:30:22 +02:00
commit c7489092bc
2 changed files with 74 additions and 207 deletions

View File

@ -16,13 +16,16 @@
# 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/>.
import datetime
import time import time
from util import * import copy
from bitcoin import * from util import print_msg, format_satoshis
from bitcoin import is_valid, hash_160_to_bc_address, hash_160
from decimal import Decimal from decimal import Decimal
import bitcoin import bitcoin
from transaction import Transaction from transaction import Transaction
class Command: class Command:
def __init__(self, name, min_args, max_args, requires_network, requires_wallet, requires_password, description, syntax = '', options_syntax = ''): def __init__(self, name, min_args, max_args, requires_network, requires_wallet, requires_password, description, syntax = '', options_syntax = ''):
self.name = name self.name = name
@ -35,7 +38,10 @@ class Command:
self.syntax = syntax self.syntax = syntax
self.options = options_syntax self.options = options_syntax
known_commands = {} known_commands = {}
def register_command(*args): def register_command(*args):
global known_commands global known_commands
name = args[0] 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]') register_command('sweep', 2, 3, True, False, False, 'Sweep a private key.', 'sweep privkey addr [fee]')
class Commands: class Commands:
def __init__(self, wallet, network, callback = None): def __init__(self, wallet, network, callback = None):
@ -115,7 +119,6 @@ class Commands:
self._callback = callback self._callback = callback
self.password = None self.password = None
def _run(self, method, args, password_getter): def _run(self, method, args, password_getter):
cmd = known_commands[method] cmd = known_commands[method]
if cmd.requires_password and self.wallet.use_encryption: if cmd.requires_password and self.wallet.use_encryption:
@ -127,40 +130,33 @@ class Commands:
apply(self._callback, ()) apply(self._callback, ())
return result return result
def getaddresshistory(self, addr): def getaddresshistory(self, addr):
return self.network.synchronous_get([ ('blockchain.address.get_history',[addr]) ])[0] return self.network.synchronous_get([ ('blockchain.address.get_history',[addr]) ])[0]
def daemon(self, arg): def daemon(self, arg):
if arg=='stop': if arg=='stop':
return self.network.stop() return self.network.stop()
elif arg=='status': elif arg=='status':
return { return {
'server':self.network.main_server(), 'server':self.network.main_server(),
'connected':self.network.is_connected() 'connected':self.network.is_connected()
} }
else: else:
return "unknown command \"%s\""% arg return "unknown command \"%s\""% arg
def listunspent(self): def listunspent(self):
import copy
l = copy.deepcopy(self.wallet.get_unspent_coins()) l = copy.deepcopy(self.wallet.get_unspent_coins())
for i in l: i["value"] = str(Decimal(i["value"])/100000000) for i in l: i["value"] = str(Decimal(i["value"])/100000000)
return l return l
def getaddressunspent(self, addr): def getaddressunspent(self, addr):
return self.network.synchronous_get([ ('blockchain.address.listunspent',[addr]) ])[0] return self.network.synchronous_get([ ('blockchain.address.listunspent',[addr]) ])[0]
def getutxoaddress(self, txid, num): def getutxoaddress(self, txid, num):
r = self.network.synchronous_get([ ('blockchain.utxo.get_address',[txid, num]) ]) r = self.network.synchronous_get([ ('blockchain.utxo.get_address',[txid, num]) ])
if r: if r:
return {'address':r[0] } return {'address':r[0] }
def createrawtransaction(self, inputs, outputs): def createrawtransaction(self, inputs, outputs):
for i in inputs: for i in inputs:
i['prevout_hash'] = i['txid'] i['prevout_hash'] = i['txid']
@ -169,7 +165,6 @@ class Commands:
tx = Transaction.from_io(inputs, outputs) tx = Transaction.from_io(inputs, outputs)
return tx return tx
def signrawtransaction(self, raw_tx, private_keys): def signrawtransaction(self, raw_tx, private_keys):
tx = Transaction(raw_tx) tx = Transaction(raw_tx)
self.wallet.signrawtransaction(tx, private_keys, self.password) self.wallet.signrawtransaction(tx, private_keys, self.password)
@ -188,10 +183,10 @@ class Commands:
redeem_script = Transaction.multisig_script(pubkeys, num) redeem_script = Transaction.multisig_script(pubkeys, num)
address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 5) address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 5)
return {'address':address, 'redeemScript':redeem_script} return {'address':address, 'redeemScript':redeem_script}
def freeze(self,addr): def freeze(self,addr):
return self.wallet.freeze(addr) return self.wallet.freeze(addr)
def unfreeze(self,addr): def unfreeze(self,addr):
return self.wallet.unfreeze(addr) return self.wallet.unfreeze(addr)
@ -215,7 +210,6 @@ class Commands:
out['pubkeys'] = self.wallet.getpubkeys(addr) out['pubkeys'] = self.wallet.getpubkeys(addr)
return out return out
def getbalance(self, account= None): def getbalance(self, account= None):
if account is None: if account is None:
c, u = self.wallet.get_balance() c, u = self.wallet.get_balance()
@ -232,7 +226,6 @@ class Commands:
out["unconfirmed"] = str(Decimal(out["unconfirmed"])/100000000) out["unconfirmed"] = str(Decimal(out["unconfirmed"])/100000000)
return out return out
def getproof(self, addr): def getproof(self, addr):
p = self.network.synchronous_get([ ('blockchain.address.get_proof',[addr]) ])[0] p = self.network.synchronous_get([ ('blockchain.address.get_proof',[addr]) ])[0]
out = [] out = []
@ -246,9 +239,9 @@ class Commands:
return self.network.get_servers() return self.network.get_servers()
def getversion(self): def getversion(self):
import electrum import electrum # Needs to stay here to prevent ciruclar imports
return electrum.ELECTRUM_VERSION return electrum.ELECTRUM_VERSION
def getmpk(self): def getmpk(self):
return self.wallet.get_master_public_keys() return self.wallet.get_master_public_keys()
@ -264,20 +257,16 @@ class Commands:
out = "Error: Keypair import failed: " + str(e) out = "Error: Keypair import failed: " + str(e)
return out return out
def sweep(self, privkey, to_address, fee = 0.0001): def sweep(self, privkey, to_address, fee = 0.0001):
fee = int(Decimal(fee)*100000000) fee = int(Decimal(fee)*100000000)
return Transaction.sweep([privkey], self.network, to_address, fee) return Transaction.sweep([privkey], self.network, to_address, fee)
def signmessage(self, address, message): def signmessage(self, address, message):
return self.wallet.sign_message(address, message, self.password) return self.wallet.sign_message(address, message, self.password)
def verifymessage(self, address, signature, message): def verifymessage(self, address, signature, message):
return bitcoin.verify_message(address, signature, message) return bitcoin.verify_message(address, signature, message)
def _mktx(self, outputs, fee = None, change_addr = None, domain = None): def _mktx(self, outputs, fee = None, change_addr = None, domain = None):
for to_address, amount in outputs: for to_address, amount in outputs:
@ -292,7 +281,7 @@ class Commands:
for addr in domain: for addr in domain:
if not is_valid(addr): if not is_valid(addr):
raise Exception("invalid Bitcoin address", addr) raise Exception("invalid Bitcoin address", addr)
if not self.wallet.is_mine(addr): if not self.wallet.is_mine(addr):
raise Exception("address not in wallet", addr) raise Exception("address not in wallet", addr)
@ -310,11 +299,10 @@ class Commands:
amount = int(100000000*amount) amount = int(100000000*amount)
final_outputs.append((to_address, amount)) final_outputs.append((to_address, amount))
if fee: fee = int(100000000*fee) if fee: fee = int(100000000*fee)
return self.wallet.mktx(final_outputs, self.password, fee , change_addr, domain) 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): def mktx(self, to_address, amount, fee = None, change_addr = None, domain = None):
tx = self._mktx([(to_address, amount)], fee, change_addr, domain) tx = self._mktx([(to_address, amount)], fee, change_addr, domain)
return tx return tx
@ -323,7 +311,6 @@ class Commands:
tx = self._mktx(outputs, fee, change_addr, domain) tx = self._mktx(outputs, fee, change_addr, domain)
return tx return tx
def payto(self, to_address, amount, fee = None, change_addr = None, domain = None): def payto(self, to_address, amount, fee = None, change_addr = None, domain = None):
tx = self._mktx([(to_address, amount)], fee, change_addr, domain) tx = self._mktx([(to_address, amount)], fee, change_addr, domain)
r, h = self.wallet.sendtx( tx ) r, h = self.wallet.sendtx( tx )
@ -334,9 +321,7 @@ class Commands:
r, h = self.wallet.sendtx( tx ) r, h = self.wallet.sendtx( tx )
return h return h
def history(self): def history(self):
import datetime
balance = 0 balance = 0
out = [] out = []
for item in self.wallet.get_tx_history(): 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)}) out.append({'txid':tx_hash, 'date':"%16s"%time_str, 'label':label, 'value':format_satoshis(value)})
return out return out
def setlabel(self, key, label): def setlabel(self, key, label):
self.wallet.set_label(key, label) self.wallet.set_label(key, label)
def contacts(self): def contacts(self):
c = {} c = {}
for addr in self.wallet.addressbook: for addr in self.wallet.addressbook:
c[addr] = self.wallet.labels.get(addr) c[addr] = self.wallet.labels.get(addr)
return c return c
def listaddresses(self, show_all = False, show_label = False): def listaddresses(self, show_all = False, show_label = False):
out = [] out = []
for addr in self.wallet.addresses(True): for addr in self.wallet.addresses(True):
@ -379,7 +359,7 @@ class Commands:
item = addr item = addr
out.append( item ) out.append( item )
return out return out
def help(self, cmd=None): def help(self, cmd=None):
if cmd not in known_commands: if cmd not in known_commands:
print_msg("\nList of commands:", ', '.join(sorted(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) if cmd.options: print_msg("options:\n" + cmd.options)
return None return None
def getrawtransaction(self, tx_hash): def getrawtransaction(self, tx_hash):
import transaction
if self.wallet: if self.wallet:
tx = self.wallet.transactions.get(tx_hash) tx = self.wallet.transactions.get(tx_hash)
if tx: if tx:
@ -400,17 +378,12 @@ class Commands:
r = self.network.synchronous_get([ ('blockchain.transaction.get',[tx_hash]) ])[0] r = self.network.synchronous_get([ ('blockchain.transaction.get',[tx_hash]) ])[0]
if r: if r:
return transaction.Transaction(r) return Transaction(r)
else: else:
return "unknown transaction" return "unknown transaction"
def encrypt(self, pubkey, message): def encrypt(self, pubkey, message):
return bitcoin.encrypt_message(message, pubkey) return bitcoin.encrypt_message(message, pubkey)
def decrypt(self, pubkey, message): def decrypt(self, pubkey, message):
return self.wallet.decrypt_message(pubkey, message, self.password) 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys import sys
import base64
import os import os
import re
import hashlib import hashlib
import copy
import operator
import ast import ast
import threading import threading
import random import random
import aes
import Queue
import time import time
import math import math
from util import print_msg, print_error, format_satoshis from util import print_msg, print_error
from bitcoin import * from bitcoin import *
from account import * from account import *
from transaction import Transaction, is_extended_pubkey from version import *
from transaction import Transaction
from plugins import run_hook from plugins import run_hook
import bitcoin import bitcoin
from synchronizer import WalletSynchronizer from synchronizer import WalletSynchronizer
@ -47,9 +44,6 @@ IMPORTED_ACCOUNT = '/x'
from version import *
class WalletStorage: class WalletStorage:
def __init__(self, config): def __init__(self, config):
@ -109,7 +103,7 @@ class WalletStorage:
def get(self, key, default=None): def get(self, key, default=None):
v = self.data.get(key) v = self.data.get(key)
if v is None: if v is None:
v = default v = default
return v return v
@ -120,7 +114,7 @@ class WalletStorage:
self.data[key] = value self.data[key] = value
elif key in self.data: elif key in self.data:
self.data.pop(key) self.data.pop(key)
if save: if save:
self.write() self.write()
def write(self): def write(self):
@ -133,15 +127,9 @@ class WalletStorage:
os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE) os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE)
class Abstract_Wallet: class Abstract_Wallet:
def __init__(self, storage): def __init__(self, storage):
self.storage = storage self.storage = storage
self.electrum_version = ELECTRUM_VERSION self.electrum_version = ELECTRUM_VERSION
self.gap_limit_for_change = 3 # constant 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() # 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 # 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) # wallet.up_to_date is true when the wallet is synchronized (stronger requirement)
self.up_to_date = False self.up_to_date = False
self.lock = threading.Lock() self.lock = threading.Lock()
self.transaction_lock = threading.Lock() self.transaction_lock = threading.Lock()
self.tx_event = threading.Event() self.tx_event = threading.Event()
for tx_hash, tx in self.transactions.items(): for tx_hash, tx in self.transactions.items():
self.update_tx_outputs(tx_hash) self.update_tx_outputs(tx_hash)
def add_extra_addresses(self, tx): def add_extra_addresses(self, tx):
h = tx.hash() h = tx.hash()
# find the address corresponding to pay-to-pubkey inputs # find the address corresponding to pay-to-pubkey inputs
@ -217,11 +203,9 @@ class Abstract_Wallet:
for tx2 in self.transactions.values(): for tx2 in self.transactions.values():
tx2.add_extra_addresses({h:tx}) tx2.add_extra_addresses({h:tx})
def get_action(self): def get_action(self):
pass pass
def convert_imported_keys(self, password): def convert_imported_keys(self, password):
for k, v in self.imported_keys.items(): for k, v in self.imported_keys.items():
sec = pw_decode(v, password) sec = pw_decode(v, password)
@ -232,7 +216,6 @@ class Abstract_Wallet:
self.imported_keys.pop(k) self.imported_keys.pop(k)
self.storage.put('imported_keys', self.imported_keys) self.storage.put('imported_keys', self.imported_keys)
def load_accounts(self): def load_accounts(self):
self.accounts = {} self.accounts = {}
self.imported_keys = self.storage.get('imported_keys',{}) self.imported_keys = self.storage.get('imported_keys',{})
@ -255,7 +238,6 @@ class Abstract_Wallet:
else: else:
print_error("cannot load account", v) print_error("cannot load account", v)
def synchronize(self): def synchronize(self):
pass pass
@ -268,15 +250,14 @@ class Abstract_Wallet:
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
def update(self): def update(self):
self.up_to_date = False self.up_to_date = False
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): def is_imported(self, addr):
account = self.accounts.get(IMPORTED_ACCOUNT) account = self.accounts.get(IMPORTED_ACCOUNT)
if account: if account:
return addr in account.get_addresses(0) return addr in account.get_addresses(0)
else: else:
return False return False
@ -294,16 +275,15 @@ class Abstract_Wallet:
if self.is_mine(address): if self.is_mine(address):
raise Exception('Address already in wallet') raise Exception('Address already in wallet')
if self.accounts.get(IMPORTED_ACCOUNT) is None: if self.accounts.get(IMPORTED_ACCOUNT) is None:
self.accounts[IMPORTED_ACCOUNT] = ImportedAccount({'imported':{}}) self.accounts[IMPORTED_ACCOUNT] = ImportedAccount({'imported':{}})
self.accounts[IMPORTED_ACCOUNT].add(address, pubkey, sec, password) self.accounts[IMPORTED_ACCOUNT].add(address, pubkey, sec, password)
self.save_accounts() self.save_accounts()
if self.synchronizer: if self.synchronizer:
self.synchronizer.subscribe_to_addresses([address]) self.synchronizer.subscribe_to_addresses([address])
return address return address
def delete_imported_key(self, addr): def delete_imported_key(self, addr):
account = self.accounts[IMPORTED_ACCOUNT] account = self.accounts[IMPORTED_ACCOUNT]
@ -312,7 +292,6 @@ class Abstract_Wallet:
self.accounts.pop(IMPORTED_ACCOUNT) self.accounts.pop(IMPORTED_ACCOUNT)
self.save_accounts() self.save_accounts()
def set_label(self, name, text = None): def set_label(self, name, text = None):
changed = False changed = False
old_text = self.labels.get(name) old_text = self.labels.get(name)
@ -331,9 +310,6 @@ class Abstract_Wallet:
run_hook('set_label', name, text, changed) run_hook('set_label', name, text, changed)
return changed return changed
def addresses(self, include_change = True, _next=True): def addresses(self, include_change = True, _next=True):
o = [] o = []
for a in self.accounts.keys(): for a in self.accounts.keys():
@ -345,10 +321,8 @@ class Abstract_Wallet:
o += [addr] o += [addr]
return o return o
def is_mine(self, address): def is_mine(self, address):
return address in self.addresses(True) return address in self.addresses(True)
def is_change(self, address): def is_change(self, address):
if not self.is_mine(address): return False if not self.is_mine(address): return False
@ -356,7 +330,6 @@ class Abstract_Wallet:
if s is None: return False if s is None: return False
return s[0] == 1 return s[0] == 1
def get_address_index(self, address): def get_address_index(self, address):
for account in self.accounts.keys(): for account in self.accounts.keys():
@ -372,26 +345,22 @@ class Abstract_Wallet:
raise Exception("Address not found", address) raise Exception("Address not found", address)
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)
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) account_id, sequence = self.get_address_index(address)
return self.accounts[account_id].get_private_key(sequence, self, password) return self.accounts[account_id].get_private_key(sequence, self, password)
def get_public_keys(self, address): def get_public_keys(self, address):
account_id, sequence = self.get_address_index(address) account_id, sequence = self.get_address_index(address)
return self.accounts[account_id].get_pubkeys(sequence) return self.accounts[account_id].get_pubkeys(sequence)
def can_sign(self, tx): def can_sign(self, tx):
if self.is_watching_only(): if self.is_watching_only():
@ -411,15 +380,11 @@ class Abstract_Wallet:
return True return True
return False return False
def add_keypairs(self, tx, keypairs, password): def add_keypairs(self, tx, keypairs, password):
# first check the provided password # first check the provided password. This will raise if invalid.
seed = self.get_seed(password) self.get_seed(password)
addr_list, xpub_list = tx.inputs_to_sign() addr_list, xpub_list = tx.inputs_to_sign()
for addr in addr_list: for addr in addr_list:
if self.is_mine(addr): if self.is_mine(addr):
private_keys = self.get_private_key(address, password) private_keys = self.get_private_key(address, password)
@ -441,12 +406,9 @@ class Abstract_Wallet:
pubkey = public_key_from_private_key(sec) pubkey = public_key_from_private_key(sec)
keypairs[pubkey] = sec keypairs[pubkey] = sec
def signrawtransaction(self, tx, private_keys, password): def signrawtransaction(self, tx, private_keys, password):
# check that the password is correct. This will raise if it's not.
# check that the password is correct self.get_seed(password)
seed = self.get_seed(password)
# build a list of public/private keys # build a list of public/private keys
keypairs = {} keypairs = {}
@ -462,7 +424,6 @@ class Abstract_Wallet:
# sign the transaction # sign the transaction
self.sign_transaction(tx, keypairs, password) self.sign_transaction(tx, keypairs, password)
def sign_message(self, address, message, password): def sign_message(self, address, message, password):
keys = self.get_private_key(address, password) keys = self.get_private_key(address, password)
assert len(keys) == 1 assert len(keys) == 1
@ -471,8 +432,6 @@ class Abstract_Wallet:
compressed = is_compressed(sec) compressed = is_compressed(sec)
return key.sign_message(message, compressed, address) return key.sign_message(message, compressed, address)
def decrypt_message(self, pubkey, message, password): def decrypt_message(self, pubkey, message, password):
address = public_key_to_bc_address(pubkey.decode('hex')) address = public_key_to_bc_address(pubkey.decode('hex'))
keys = self.get_private_key(address, password) keys = self.get_private_key(address, password)
@ -481,25 +440,20 @@ class Abstract_Wallet:
decrypted = ec.decrypt_message(message) decrypted = ec.decrypt_message(message)
return decrypted return decrypted
def is_found(self): 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): def add_contact(self, address, label=None):
self.addressbook.append(address) self.addressbook.append(address)
self.storage.put('contacts', self.addressbook, True) self.storage.put('contacts', self.addressbook, True)
if label: if label:
self.set_label(address, label) self.set_label(address, label)
def delete_contact(self, addr): def delete_contact(self, addr):
if addr in self.addressbook: if addr in self.addressbook:
self.addressbook.remove(addr) self.addressbook.remove(addr)
self.storage.put('addressbook', self.addressbook, True) self.storage.put('addressbook', self.addressbook, True)
def fill_addressbook(self): def fill_addressbook(self):
for tx_hash, tx in self.transactions.items(): for tx_hash, tx in self.transactions.items():
is_relevant, is_send, _, _ = self.get_tx_value(tx) is_relevant, is_send, _, _ = self.get_tx_value(tx)
@ -511,23 +465,20 @@ class Abstract_Wallet:
# self.update_tx_labels() # self.update_tx_labels()
def get_num_tx(self, address): def get_num_tx(self, address):
n = 0 n = 0
for tx in self.transactions.values(): for tx in self.transactions.values():
if address in map(lambda x:x[0], tx.outputs): n += 1 if address in map(lambda x:x[0], tx.outputs): n += 1
return n return n
def get_address_flags(self, addr): 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 "-" flags += "F" if addr in self.frozen_addresses else "-"
return flags return flags
def get_tx_value(self, tx, account=None): def get_tx_value(self, tx, account=None):
domain = self.get_account_addresses(account) domain = self.get_account_addresses(account)
return tx.get_value(domain, self.prevout_values) return tx.get_value(domain, self.prevout_values)
def update_tx_outputs(self, tx_hash): def update_tx_outputs(self, tx_hash):
tx = self.transactions.get(tx_hash) tx = self.transactions.get(tx_hash)
@ -540,7 +491,6 @@ class Abstract_Wallet:
key = item['prevout_hash'] + ':%d'%item['prevout_n'] key = item['prevout_hash'] + ':%d'%item['prevout_n']
self.spent_outputs.append(key) self.spent_outputs.append(key)
def get_addr_balance(self, address): def get_addr_balance(self, address):
#assert self.is_mine(address) #assert self.is_mine(address)
h = self.history.get(address,[]) h = self.history.get(address,[])
@ -567,7 +517,7 @@ class Abstract_Wallet:
if addr == address: if addr == address:
key = item['prevout_hash'] + ':%d'%item['prevout_n'] key = item['prevout_hash'] + ':%d'%item['prevout_n']
value = self.prevout_values.get( key ) value = self.prevout_values.get( key )
if key in received_coins: if key in received_coins:
v -= value v -= value
for i, (addr, value) in enumerate(tx.outputs): for i, (addr, value) in enumerate(tx.outputs):
@ -581,18 +531,15 @@ class Abstract_Wallet:
u += v u += v
return c, u return c, u
def get_account_name(self, k): def get_account_name(self, k):
return self.labels.get(k, self.accounts[k].get_name(k)) return self.labels.get(k, self.accounts[k].get_name(k))
def get_account_names(self): def get_account_names(self):
account_names = {} account_names = {}
for k in self.accounts.keys(): for k in self.accounts.keys():
account_names[k] = self.get_account_name(k) account_names[k] = self.get_account_name(k)
return account_names return account_names
def get_account_addresses(self, a, include_change=True): def get_account_addresses(self, a, include_change=True):
if a is None: if a is None:
o = self.addresses(True) o = self.addresses(True)
@ -602,13 +549,12 @@ class Abstract_Wallet:
if include_change: o += ac.get_addresses(1) if include_change: o += ac.get_addresses(1)
return o return o
def get_account_balance(self, account): def get_account_balance(self, account):
return self.get_balance(self.get_account_addresses(account)) return self.get_balance(self.get_account_addresses(account))
def get_frozen_balance(self): def get_frozen_balance(self):
return self.get_balance(self.frozen_addresses) return self.get_balance(self.frozen_addresses)
def get_balance(self, domain=None): def get_balance(self, domain=None):
if domain is None: domain = self.addresses(True) if domain is None: domain = self.addresses(True)
cc = uu = 0 cc = uu = 0
@ -618,7 +564,6 @@ class Abstract_Wallet:
uu += u uu += u
return cc, uu return cc, uu
def get_unspent_coins(self, domain=None): def get_unspent_coins(self, domain=None):
coins = [] coins = []
if domain is None: domain = self.addresses(True) if domain is None: domain = self.addresses(True)
@ -643,11 +588,10 @@ class Abstract_Wallet:
if coins: if coins:
coins = sorted(coins) coins = sorted(coins)
if coins[-1][0] != 0: if coins[-1][0] != 0:
while coins[0][0] == 0: while coins[0][0] == 0:
coins = coins[1:] + [ coins[0] ] coins = coins[1:] + [ coins[0] ]
return [x[1] for x in coins] return [x[1] for x in coins]
def choose_tx_inputs( self, amount, fixed_fee, num_outputs, domain = None, coins = None ): def choose_tx_inputs( self, amount, fixed_fee, num_outputs, domain = None, coins = None ):
""" todo: minimize tx size """ """ todo: minimize tx size """
total = 0 total = 0
@ -665,7 +609,6 @@ class Abstract_Wallet:
for item in coins: for item in coins:
if item.get('coinbase') and item.get('height') + COINBASE_MATURITY > self.network.get_local_height(): if item.get('coinbase') and item.get('height') + COINBASE_MATURITY > self.network.get_local_height():
continue continue
addr = item.get('address')
v = item.get('value') v = item.get('value')
total += v total += v
inputs.append(item) inputs.append(item)
@ -676,18 +619,16 @@ class Abstract_Wallet:
return inputs, total, fee return inputs, total, fee
def set_fee(self, fee): def set_fee(self, fee):
if self.fee != fee: if self.fee != fee:
self.fee = fee self.fee = fee
self.storage.put('fee_per_kb', self.fee, True) self.storage.put('fee_per_kb', self.fee, True)
def estimated_fee(self, inputs, num_outputs): def estimated_fee(self, inputs, num_outputs):
estimated_size = len(inputs) * 180 + num_outputs * 34 # this assumes non-compressed keys estimated_size = len(inputs) * 180 + num_outputs * 34 # this assumes non-compressed keys
fee = self.fee * int(math.ceil(estimated_size/1000.)) fee = self.fee * int(math.ceil(estimated_size/1000.))
return fee return fee
def add_tx_change( self, inputs, outputs, amount, fee, total, change_addr=None): def add_tx_change( self, inputs, outputs, amount, fee, total, change_addr=None):
"add change to a transaction" "add change to a transaction"
change_amount = total - ( amount + fee ) change_amount = total - ( amount + fee )
@ -708,12 +649,10 @@ class Abstract_Wallet:
outputs[posn:posn] = [( change_addr, change_amount)] outputs[posn:posn] = [( change_addr, change_amount)]
return outputs return outputs
def get_history(self, address): def get_history(self, address):
with self.lock: with self.lock:
return self.history.get(address) return self.history.get(address)
def get_status(self, h): def get_status(self, h):
if not h: return None if not h: return None
if h == ['*']: return '*' if h == ['*']: return '*'
@ -722,7 +661,6 @@ class Abstract_Wallet:
status += tx_hash + ':%d:' % height status += tx_hash + ':%d:' % height
return hashlib.sha256( status ).digest().encode('hex') return hashlib.sha256( status ).digest().encode('hex')
def receive_tx_callback(self, tx_hash, tx, tx_height): def receive_tx_callback(self, tx_hash, tx, tx_height):
with self.transaction_lock: with self.transaction_lock:
@ -734,11 +672,10 @@ class Abstract_Wallet:
self.transactions[tx_hash] = tx self.transactions[tx_hash] = tx
self.network.pending_transactions_for_notifications.append(tx) self.network.pending_transactions_for_notifications.append(tx)
self.save_transactions() 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.verifier.add(tx_hash, tx_height)
self.update_tx_outputs(tx_hash) self.update_tx_outputs(tx_hash)
def save_transactions(self): def save_transactions(self):
tx = {} tx = {}
for k,v in self.transactions.items(): for k,v in self.transactions.items():
@ -749,7 +686,7 @@ class Abstract_Wallet:
if not self.check_new_history(addr, hist): if not self.check_new_history(addr, hist):
raise Exception("error: received history for %s is not consistent with known transactions"%addr) raise Exception("error: received history for %s is not consistent with known transactions"%addr)
with self.lock: with self.lock:
self.history[addr] = hist self.history[addr] = hist
self.storage.put('addr_history', self.history, True) self.storage.put('addr_history', self.history, True)
@ -760,7 +697,6 @@ class Abstract_Wallet:
# add it in case it was previously unconfirmed # add it in case it was previously unconfirmed
if self.verifier: self.verifier.add(tx_hash, tx_height) if self.verifier: self.verifier.add(tx_hash, tx_height)
def get_tx_history(self, account=None): def get_tx_history(self, account=None):
if not self.verifier: if not self.verifier:
return [] return []
@ -769,7 +705,7 @@ class Abstract_Wallet:
history = self.transactions.items() history = self.transactions.items()
history.sort(key = lambda x: self.verifier.get_txpos(x[0])) history.sort(key = lambda x: self.verifier.get_txpos(x[0]))
result = [] result = []
balance = 0 balance = 0
for tx_hash, tx in history: for tx_hash, tx in history:
is_relevant, is_mine, v, fee = self.get_tx_value(tx, account) is_relevant, is_mine, v, fee = self.get_tx_value(tx, account)
@ -793,14 +729,12 @@ class Abstract_Wallet:
return result return result
def get_label(self, tx_hash): def get_label(self, tx_hash):
label = self.labels.get(tx_hash) label = self.labels.get(tx_hash)
is_default = (label == '') or (label is None) is_default = (label == '') or (label is None)
if is_default: label = self.get_default_label(tx_hash) if is_default: label = self.get_default_label(tx_hash)
return label, is_default return label, is_default
def get_default_label(self, tx_hash): def get_default_label(self, tx_hash):
tx = self.transactions.get(tx_hash) tx = self.transactions.get(tx_hash)
default_label = '' default_label = ''
@ -831,7 +765,6 @@ class Abstract_Wallet:
o_addr = None o_addr = None
if o_addr: if o_addr:
dest_label = self.labels.get(o_addr)
try: try:
default_label = self.labels[o_addr] default_label = self.labels[o_addr]
except KeyError: except KeyError:
@ -839,7 +772,6 @@ class Abstract_Wallet:
return default_label return default_label
def make_unsigned_transaction(self, outputs, fee=None, change_addr=None, domain=None, coins=None ): def make_unsigned_transaction(self, outputs, fee=None, change_addr=None, domain=None, coins=None ):
for address, x in outputs: for address, x in outputs:
assert is_valid(address), "Address " + address + " is invalid!" 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) outputs = self.add_tx_change(inputs, outputs, amount, fee, total, change_addr)
return Transaction.from_io(inputs, outputs) return Transaction.from_io(inputs, outputs)
def mktx(self, outputs, password, fee=None, change_addr=None, domain= None, coins = None ): 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) tx = self.make_unsigned_transaction(outputs, fee, change_addr, domain, coins)
keypairs = {} keypairs = {}
@ -861,7 +792,6 @@ class Abstract_Wallet:
self.sign_transaction(tx, keypairs, password) self.sign_transaction(tx, keypairs, password)
return tx return tx
def add_input_info(self, txin): def add_input_info(self, txin):
address = txin['address'] address = txin['address']
account_id, sequence = self.get_address_index(address) account_id, sequence = self.get_address_index(address)
@ -871,19 +801,17 @@ class Abstract_Wallet:
txin['pubkeys'] = pubkeys = account.get_pubkeys(sequence) txin['pubkeys'] = pubkeys = account.get_pubkeys(sequence)
txin['signatures'] = [None] * len(pubkeys) txin['signatures'] = [None] * len(pubkeys)
if redeemScript: if redeemScript:
txin['redeemScript'] = redeemScript txin['redeemScript'] = redeemScript
txin['num_sig'] = 2 txin['num_sig'] = 2
else: else:
txin['redeemPubkey'] = account.get_pubkey(*sequence) txin['redeemPubkey'] = account.get_pubkey(*sequence)
txin['num_sig'] = 1 txin['num_sig'] = 1
def sign_transaction(self, tx, keypairs, password): def sign_transaction(self, tx, keypairs, password):
tx.sign(keypairs) tx.sign(keypairs)
run_hook('sign_transaction', tx, password) run_hook('sign_transaction', tx, password)
def sendtx(self, tx): def sendtx(self, tx):
# synchronous # synchronous
h = self.send_tx(tx) h = self.send_tx(tx)
@ -901,15 +829,14 @@ class Abstract_Wallet:
self.tx_event.set() self.tx_event.set()
def receive_tx(self, tx_hash, tx): def receive_tx(self, tx_hash, tx):
out = self.tx_result out = self.tx_result
if out != tx_hash: if out != tx_hash:
return False, "error: " + out return False, "error: " + out
run_hook('receive_tx', tx, self) run_hook('receive_tx', tx, self)
return True, out return True, out
def update_password(self, old_password, new_password): def update_password(self, old_password, new_password):
if new_password == '': if new_password == '':
new_password = None new_password = None
if self.has_seed(): if self.has_seed():
@ -918,7 +845,7 @@ class Abstract_Wallet:
self.storage.put('seed', self.seed, True) self.storage.put('seed', self.seed, True)
imported_account = self.accounts.get(IMPORTED_ACCOUNT) imported_account = self.accounts.get(IMPORTED_ACCOUNT)
if imported_account: if imported_account:
imported_account.update_password(old_password, new_password) imported_account.update_password(old_password, new_password)
self.save_accounts() self.save_accounts()
@ -931,7 +858,6 @@ class Abstract_Wallet:
self.use_encryption = (new_password != None) self.use_encryption = (new_password != None)
self.storage.put('use_encryption', self.use_encryption,True) self.storage.put('use_encryption', self.use_encryption,True)
def freeze(self,addr): def freeze(self,addr):
if self.is_mine(addr) and addr not in self.frozen_addresses: if self.is_mine(addr) and addr not in self.frozen_addresses:
self.frozen_addresses.append(addr) self.frozen_addresses.append(addr)
@ -940,7 +866,6 @@ class Abstract_Wallet:
else: else:
return False return False
def unfreeze(self,addr): def unfreeze(self,addr):
if self.is_mine(addr) and addr in self.frozen_addresses: if self.is_mine(addr) and addr in self.frozen_addresses:
self.frozen_addresses.remove(addr) self.frozen_addresses.remove(addr)
@ -949,7 +874,6 @@ class Abstract_Wallet:
else: else:
return False return False
def set_verifier(self, verifier): def set_verifier(self, verifier):
self.verifier = verifier self.verifier = verifier
@ -967,9 +891,7 @@ class Abstract_Wallet:
if tx_hash not in vr: if tx_hash not in vr:
self.transactions.pop(tx_hash) self.transactions.pop(tx_hash)
def check_new_history(self, addr, hist): def check_new_history(self, addr, hist):
# check that all tx in hist are relevant # check that all tx in hist are relevant
if hist != ['*']: if hist != ['*']:
for tx_hash, height in hist: for tx_hash, height in hist:
@ -997,7 +919,7 @@ class Abstract_Wallet:
tx = self.transactions.get(tx_hash) tx = self.transactions.get(tx_hash)
# tx might not be there # tx might not be there
if not tx: continue if not tx: continue
# already verified? # already verified?
if self.verifier.get_height(tx_hash): if self.verifier.get_height(tx_hash):
continue continue
@ -1026,14 +948,13 @@ class Abstract_Wallet:
return True return True
def check_new_tx(self, tx_hash, tx): 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 = [] addresses = []
for addr, hist in self.history.items(): for addr, hist in self.history.items():
if hist == ['*']:continue if hist == ['*']:continue
for txh, height in hist: for txh, height in hist:
if txh == tx_hash: if txh == tx_hash:
addresses.append(addr) addresses.append(addr)
if not addresses: if not addresses:
@ -1046,7 +967,6 @@ class Abstract_Wallet:
return True return True
def start_threads(self, network): def start_threads(self, network):
from verifier import TxVerifier from verifier import TxVerifier
self.network = network self.network = network
@ -1084,7 +1004,7 @@ class Abstract_Wallet:
h = self.history.get(address,[]) h = self.history.get(address,[])
c, u = self.get_addr_balance(address) c, u = self.get_addr_balance(address)
return len(h), len(h) > 0 and c == -u return len(h), len(h) > 0 and c == -u
class Imported_Wallet(Abstract_Wallet): class Imported_Wallet(Abstract_Wallet):
@ -1095,7 +1015,6 @@ class Imported_Wallet(Abstract_Wallet):
self.accounts[IMPORTED_ACCOUNT] = ImportedAccount({'imported':{}}) self.accounts[IMPORTED_ACCOUNT] = ImportedAccount({'imported':{}})
self.storage.put('wallet_type', 'imported', True) self.storage.put('wallet_type', 'imported', True)
def is_watching_only(self): def is_watching_only(self):
acc = self.accounts[IMPORTED_ACCOUNT] acc = self.accounts[IMPORTED_ACCOUNT]
n = acc.keypairs.values() n = acc.keypairs.values()
@ -1130,11 +1049,11 @@ class Deterministic_Wallet(Abstract_Wallet):
return not self.has_seed() return not self.has_seed()
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")
self.seed_version, self.seed = self.prepare_seed(seed) self.seed_version, self.seed = self.prepare_seed(seed)
if password: if password:
self.seed = pw_encode( self.seed, password) self.seed = pw_encode( self.seed, password)
self.use_encryption = True self.use_encryption = True
else: else:
@ -1150,7 +1069,7 @@ class Deterministic_Wallet(Abstract_Wallet):
def get_mnemonic(self, password): def get_mnemonic(self, password):
return self.get_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:
self.gap_limit = value self.gap_limit = value
@ -1196,7 +1115,6 @@ class Deterministic_Wallet(Abstract_Wallet):
if n > nmax: nmax = n if n > nmax: nmax = n
return nmax + 1 return nmax + 1
def address_is_old(self, address): def address_is_old(self, address):
age = -1 age = -1
h = self.history.get(address, []) h = self.history.get(address, [])
@ -1211,7 +1129,6 @@ class Deterministic_Wallet(Abstract_Wallet):
age = tx_age age = tx_age
return age > 2 return age > 2
def synchronize_sequence(self, account, for_change): def synchronize_sequence(self, account, for_change):
limit = self.gap_limit_for_change if for_change else self.gap_limit limit = self.gap_limit_for_change if for_change else self.gap_limit
new_addresses = [] new_addresses = []
@ -1231,7 +1148,6 @@ class Deterministic_Wallet(Abstract_Wallet):
new_addresses.append( address ) new_addresses.append( address )
return new_addresses return new_addresses
def check_pending_accounts(self): def check_pending_accounts(self):
for account_id, addr in self.next_addresses.items(): 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.add_account(account_id, account)
self.next_addresses.pop(account_id) self.next_addresses.pop(account_id)
def synchronize_account(self, account): def synchronize_account(self, account):
new = [] new = []
new += self.synchronize_sequence(account, 0) new += self.synchronize_sequence(account, 0)
new += self.synchronize_sequence(account, 1) new += self.synchronize_sequence(account, 1)
return new return new
def synchronize(self): def synchronize(self):
self.check_pending_accounts() self.check_pending_accounts()
new = [] new = []
@ -1262,7 +1176,6 @@ class Deterministic_Wallet(Abstract_Wallet):
self.storage.put('addr_history', self.history, True) self.storage.put('addr_history', self.history, True)
return new return new
def restore(self, callback): def restore(self, callback):
from i18n import _ from i18n import _
def wait_for_wallet(): def wait_for_wallet():
@ -1271,8 +1184,8 @@ class Deterministic_Wallet(Abstract_Wallet):
msg = "%s\n%s %d\n%s %.1f"%( msg = "%s\n%s %d\n%s %.1f"%(
_("Please wait..."), _("Please wait..."),
_("Addresses generated:"), _("Addresses generated:"),
len(self.addresses(True)), len(self.addresses(True)),
_("Kilobytes received:"), _("Kilobytes received:"),
self.network.interface.bytes_received/1024.) self.network.interface.bytes_received/1024.)
apply(callback, (msg,)) apply(callback, (msg,))
@ -1290,10 +1203,8 @@ class Deterministic_Wallet(Abstract_Wallet):
wait_for_wallet() wait_for_wallet()
else: else:
self.synchronize() self.synchronize()
self.fill_addressbook() self.fill_addressbook()
def create_account(self, name, password): def create_account(self, name, password):
i = self.num_accounts() i = self.num_accounts()
account_id = self.account_id(i) account_id = self.account_id(i)
@ -1310,8 +1221,6 @@ class Deterministic_Wallet(Abstract_Wallet):
self.accounts[account_id] = account self.accounts[account_id] = account
self.save_accounts() self.save_accounts()
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
@ -1327,8 +1236,6 @@ class Deterministic_Wallet(Abstract_Wallet):
self.save_accounts() self.save_accounts()
class NewWallet(Deterministic_Wallet): class NewWallet(Deterministic_Wallet):
def __init__(self, storage): def __init__(self, storage):
@ -1365,25 +1272,22 @@ class NewWallet(Deterministic_Wallet):
account = BIP32_Account({'xpub':xpub}) account = BIP32_Account({'xpub':xpub})
self.add_account("m/", account) self.add_account("m/", account)
def create_accounts(self, password): 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) self.create_account('Main account', password)
def add_master_public_key(self, name, mpk): def add_master_public_key(self, name, mpk):
self.master_public_keys[name] = mpk self.master_public_keys[name] = mpk
self.storage.put('master_public_keys', self.master_public_keys, True) self.storage.put('master_public_keys', self.master_public_keys, True)
def add_master_private_key(self, name, xpriv, password): def add_master_private_key(self, name, xpriv, password):
self.master_private_keys[name] = pw_encode(xpriv, password) self.master_private_keys[name] = pw_encode(xpriv, password)
self.storage.put('master_private_keys', self.master_private_keys, True) self.storage.put('master_private_keys', self.master_private_keys, True)
def add_master_keys(self, root, account_id, password): def add_master_keys(self, root, account_id, password):
x = self.master_private_keys.get(root) x = self.master_private_keys.get(root)
if x: if x:
master_xpriv = pw_decode(x, password ) master_xpriv = pw_decode(x, password )
xpriv, xpub = bip32_private_derivation(master_xpriv, root, account_id) xpriv, xpub = bip32_private_derivation(master_xpriv, root, account_id)
self.add_master_public_key(account_id, xpub) self.add_master_public_key(account_id, xpub)
@ -1394,20 +1298,17 @@ class NewWallet(Deterministic_Wallet):
self.add_master_public_key(account_id, xpub) self.add_master_public_key(account_id, xpub)
return xpub return xpub
def create_master_keys(self, password): def create_master_keys(self, password):
xpriv, xpub = bip32_root(mnemonic_to_seed(self.get_seed(password),'').encode('hex')) xpriv, xpub = bip32_root(mnemonic_to_seed(self.get_seed(password),'').encode('hex'))
self.add_master_public_key("m/", xpub) self.add_master_public_key("m/", xpub)
self.add_master_private_key("m/", xpriv, password) self.add_master_private_key("m/", xpriv, password)
def find_root_by_master_key(self, xpub): def find_root_by_master_key(self, xpub):
for key, xpub2 in self.master_public_keys.items(): for key, xpub2 in self.master_public_keys.items():
if key == "m/":continue if key == "m/":continue
if xpub == xpub2: if xpub == xpub2:
return key return key
def num_accounts(self): def num_accounts(self):
keys = [] keys = []
for k, v in self.accounts.items(): for k, v in self.accounts.items():
@ -1422,13 +1323,12 @@ class NewWallet(Deterministic_Wallet):
i += 1 i += 1
return i return i
def next_account_address(self, password): def next_account_address(self, password):
i = self.num_accounts() i = self.num_accounts()
account_id = self.account_id(i) account_id = self.account_id(i)
addr = self.next_addresses.get(account_id) addr = self.next_addresses.get(account_id)
if not addr: if not addr:
account = self.make_account(account_id, password) account = self.make_account(account_id, password)
addr = account.first_address() addr = account.first_address()
self.next_addresses[account_id] = addr self.next_addresses[account_id] = addr
@ -1445,7 +1345,6 @@ class NewWallet(Deterministic_Wallet):
account = BIP32_Account({'xpub':xpub}) account = BIP32_Account({'xpub':xpub})
return account return account
def make_seed(self): def make_seed(self):
import mnemonic, ecdsa import mnemonic, ecdsa
entropy = ecdsa.util.randrange( pow(2,160) ) entropy = ecdsa.util.randrange( pow(2,160) )
@ -1454,7 +1353,7 @@ class NewWallet(Deterministic_Wallet):
ss = "%040x"%(entropy+nonce) ss = "%040x"%(entropy+nonce)
s = hashlib.sha256(ss.decode('hex')).digest().encode('hex') s = hashlib.sha256(ss.decode('hex')).digest().encode('hex')
# we keep only 13 words, that's approximately 139 bits of entropy # 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) seed = ' '.join(words)
if is_new_seed(seed): if is_new_seed(seed):
break # this will remove 8 bits of entropy 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())) return NEW_SEED_VERSION, unicodedata.normalize('NFC', unicode(seed.strip()))
class Wallet_2of2(NewWallet): class Wallet_2of2(NewWallet):
""" This class is used for multisignature addresses"""
def __init__(self, storage): def __init__(self, storage):
NewWallet.__init__(self, storage) NewWallet.__init__(self, storage)
@ -1499,8 +1398,8 @@ class Wallet_2of2(NewWallet):
return 'create_2of2_2' return 'create_2of2_2'
class Wallet_2of3(Wallet_2of2): class Wallet_2of3(Wallet_2of2):
""" This class is used for multisignature addresses"""
def __init__(self, storage): def __init__(self, storage):
Wallet_2of2.__init__(self, storage) Wallet_2of2.__init__(self, storage)
@ -1532,9 +1431,6 @@ class Wallet_2of3(Wallet_2of2):
return 'create_2of3_2' return 'create_2of3_2'
class OldWallet(Deterministic_Wallet): class OldWallet(Deterministic_Wallet):
def make_seed(self): def make_seed(self):
@ -1557,9 +1453,8 @@ class OldWallet(Deterministic_Wallet):
seed = mnemonic.mn_decode(words) seed = mnemonic.mn_decode(words)
if not seed: if not seed:
raise Exception("Invalid seed") raise Exception("Invalid seed")
return OLD_SEED_VERSION, seed
return OLD_SEED_VERSION, seed
def create_master_keys(self, password): def create_master_keys(self, password):
seed = self.get_seed(password) seed = self.get_seed(password)
@ -1605,6 +1500,9 @@ class OldWallet(Deterministic_Wallet):
# former WalletFactory # former WalletFactory
class Wallet(object): 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): def __new__(self, storage):
config = storage.config config = storage.config
@ -1623,7 +1521,6 @@ class Wallet(object):
if storage.get('wallet_type') == 'imported': if storage.get('wallet_type') == 'imported':
return Imported_Wallet(storage) return Imported_Wallet(storage)
if not storage.file_exists: if not storage.file_exists:
seed_version = NEW_SEED_VERSION if config.get('bip32') is True else OLD_SEED_VERSION seed_version = NEW_SEED_VERSION if config.get('bip32') is True else OLD_SEED_VERSION
else: else:
@ -1642,8 +1539,6 @@ class Wallet(object):
print msg print msg
sys.exit(1) sys.exit(1)
@classmethod @classmethod
def is_seed(self, seed): def is_seed(self, seed):
if not seed: if not seed:
@ -1652,7 +1547,7 @@ class Wallet(object):
return True return True
elif is_new_seed(seed): elif is_new_seed(seed):
return True return True
else: else:
return False return False
@classmethod @classmethod
@ -1662,7 +1557,7 @@ class Wallet(object):
old = True old = True
except: except:
old = False old = False
if old: if old:
return len(mpk) == 128 return len(mpk) == 128
else: else:
@ -1716,7 +1611,6 @@ class Wallet(object):
@classmethod @classmethod
def from_mpk(self, mpk, storage): def from_mpk(self, mpk, storage):
try: try:
int(mpk, 16) int(mpk, 16)
old = True old = True