def get(self, key, default=None):
- return self.data.get(key, default)
+ v = self.data.get(key)
+ if v is None:
+ v = default
+ return v
def put(self, key, value, save = True):
self.seed = storage.get('seed', '') # encrypted
self.labels = storage.get('labels', {})
self.frozen_addresses = storage.get('frozen_addresses',[])
- self.prioritized_addresses = storage.get('prioritized_addresses',[])
self.addressbook = storage.get('contacts', [])
self.imported_keys = storage.get('imported_keys',{})
print msg
sys.exit(1)
+ # This attribute is set when wallet.start_threads is called.
+ self.synchronizer = None
self.load_accounts()
# find out what kind of wallet we are
try:
- seed.decode('hex')
+ seed.strip().decode('hex')
self.seed_version = 4
self.seed = str(seed)
return
# self.seed = seed
- def save_seed(self):
+ def save_seed(self, password):
+ if password:
+ self.seed = pw_encode( self.seed, password)
+ self.use_encryption = True
self.storage.put('seed', self.seed, True)
self.storage.put('seed_version', self.seed_version, True)
+ self.storage.put('use_encryption', self.use_encryption,True)
+ self.create_accounts(password)
+
def create_watching_only_wallet(self, params):
K0, c0 = params
self.create_account('1','Main account')
- def create_accounts(self):
+ def create_accounts(self, password):
+ seed = pw_decode(self.seed, password)
+
if self.seed_version == 4:
- mpk = OldAccount.mpk_from_seed(self.seed)
+ mpk = OldAccount.mpk_from_seed(seed)
self.create_old_account(mpk)
else:
# create default account
- self.create_master_keys('1')
+ self.create_master_keys('1', password)
self.create_account('1','Main account')
- def create_master_keys(self, account_type):
+ def create_master_keys(self, account_type, password):
master_k, master_c, master_K, master_cK = bip32_init(self.get_seed(None))
if account_type == '1':
k0, c0, K0, cK0 = bip32_private_derivation(master_k, master_c, "m/", "m/0'/")
self.master_public_keys["m/0'/"] = (c0, K0, cK0)
- self.master_private_keys["m/0'/"] = k0
+ self.master_private_keys["m/0'/"] = pw_encode(k0, password)
elif account_type == '2of2':
k1, c1, K1, cK1 = bip32_private_derivation(master_k, master_c, "m/", "m/1'/")
k2, c2, K2, cK2 = bip32_private_derivation(master_k, master_c, "m/", "m/2'/")
self.master_public_keys["m/1'/"] = (c1, K1, cK1)
self.master_public_keys["m/2'/"] = (c2, K2, cK2)
- self.master_private_keys["m/1'/"] = k1
- self.master_private_keys["m/2'/"] = k2
+ self.master_private_keys["m/1'/"] = pw_encode(k1, password)
+ self.master_private_keys["m/2'/"] = pw_encode(k2, password)
elif account_type == '2of3':
k3, c3, K3, cK3 = bip32_private_derivation(master_k, master_c, "m/", "m/3'/")
k4, c4, K4, cK4 = bip32_private_derivation(master_k, master_c, "m/", "m/4'/")
self.master_public_keys["m/3'/"] = (c3, K3, cK3)
self.master_public_keys["m/4'/"] = (c4, K4, cK4)
self.master_public_keys["m/5'/"] = (c5, K5, cK5)
- self.master_private_keys["m/3'/"] = k3
- self.master_private_keys["m/4'/"] = k4
- self.master_private_keys["m/5'/"] = k5
+ self.master_private_keys["m/3'/"] = pw_encode(k3, password)
+ self.master_private_keys["m/4'/"] = pw_encode(k4, password)
+ self.master_private_keys["m/5'/"] = pw_encode(k5, password)
self.storage.put('master_public_keys', self.master_public_keys, True)
self.storage.put('master_private_keys', self.master_private_keys, True)
def get_private_key(self, address, password):
+ if self.is_watching_only():
+ return []
+
+ # first check the provided password
+ seed = self.get_seed(password)
+
out = []
if address in self.imported_keys.keys():
out.append( pw_decode( self.imported_keys[address], password ) )
else:
account, sequence = self.get_address_index(address)
if account == 0:
- seed = self.get_seed(password)
pk = self.accounts[account].get_private_key(seed, sequence)
out.append(pk)
return out
def add_keypairs_from_wallet(self, tx, keypairs, password):
for txin in tx.inputs:
address = txin['address']
+ if not self.is_mine(address):
+ continue
private_keys = self.get_private_key(address, password)
for sec in private_keys:
pubkey = public_key_from_private_key(sec)
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:
- if self.seed_version==4:
+ 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
- index = int(m.group(2))
+ for_change = int(m.group(2))
num = int(m.group(3))
account = self.accounts[0]
- addr = account.get_address(index, num)
+ addr = account.get_address(for_change, num)
txin['address'] = addr # fixme: side effect
- pk = self.get_private_key(addr, password)
- for sec in pk:
- pubkey = public_key_from_private_key(sec)
- keypairs[pubkey] = sec
+ pk = account.get_private_key(seed, (for_change, num))
+ pubkey = public_key_from_private_key(pk)
+ keypairs[pubkey] = pk
continue
def get_address_flags(self, addr):
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 "P" if addr in self.prioritized_addresses else "-"
+ flags += "F" if addr in self.frozen_addresses else "-"
return flags
tx = self.transactions.get(tx_hash)
if tx is None: raise Exception("Wallet not synchronized")
is_coinbase = tx.inputs[0].get('prevout_hash') == '0'*64
- for output in tx.d.get('outputs'):
+ for o in tx.d.get('outputs'):
+ output = o.copy()
if output.get('address') != addr: continue
key = tx_hash + ":%d" % output.get('prevout_n')
if key in self.spent_outputs: continue
return [x[1] for x in coins]
-
- def choose_tx_inputs_from_account( self, amount, fixed_fee, account ):
- domain = self.get_account_addresses(account) if account else None
- return self.choose_tx_inputs( amount, fixed_fee, domain )
-
-
def choose_tx_inputs( self, amount, fixed_fee, domain = None ):
""" todo: minimize tx size """
total = 0
for i in self.frozen_addresses:
if i in domain: domain.remove(i)
- prioritized = []
- for i in self.prioritized_addresses:
- if i in domain:
- domain.remove(i)
- prioritized.append(i)
-
coins = self.get_unspent_coins(domain)
- prioritized_coins = self.get_unspent_coins(prioritized)
-
inputs = []
- coins = prioritized_coins + coins
for item in coins:
if item.get('coinbase') and item.get('height') + COINBASE_MATURITY > self.network.blockchain.height:
return Transaction.from_io(inputs, outputs)
- def mktx_from_account(self, outputs, password, fee=None, account=None):
- domain = self.get_account_addresses(account) if account else None
- return self.mktx(outputs, password, fee, change_addr=None, domain=domain)
-
-
def mktx(self, outputs, password, fee=None, change_addr=None, domain= None ):
tx = self.make_unsigned_transaction(outputs, fee, change_addr, domain)
keypairs = {}
# synchronous
h = self.send_tx(tx)
self.tx_event.wait()
- return self.receive_tx(h)
+ return self.receive_tx(h, tx)
def send_tx(self, tx):
# asynchronous
self.tx_result = r.get('result')
self.tx_event.set()
- def receive_tx(self,tx_hash):
+ def receive_tx(self, tx_hash, tx):
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 == '': new_password = None
- # this will throw an exception if unicode cannot be converted
- decoded = pw_decode(self.seed, old_password)
+ decoded = self.get_seed(old_password)
self.seed = pw_encode( decoded, new_password)
self.storage.put('seed', self.seed, True)
self.use_encryption = (new_password != None)
def freeze(self,addr):
if self.is_mine(addr) and addr not in self.frozen_addresses:
- self.unprioritize(addr)
self.frozen_addresses.append(addr)
self.storage.put('frozen_addresses', self.frozen_addresses, True)
return True
else:
return False
- def prioritize(self,addr):
- if self.is_mine(addr) and addr not in self.prioritized_addresses:
- self.unfreeze(addr)
- self.prioritized_addresses.append(addr)
- self.storage.put('prioritized_addresses', self.prioritized_addresses, True)
- return True
- else:
- return False
-
- def unprioritize(self,addr):
- if self.is_mine(addr) and addr in self.prioritized_addresses:
- self.prioritized_addresses.remove(addr)
- self.storage.put('prioritized_addresses', self.prioritized_addresses, True)
- return True
- else:
- return False
-
def set_verifier(self, verifier):
self.verifier = verifier
def start_threads(self, network):
from verifier import TxVerifier
self.network = network
- if self.network:
+ if self.network is not None:
self.verifier = TxVerifier(self.network, self.storage)
self.verifier.start()
self.set_verifier(self.verifier)
# wait until we are connected, because the user might have selected another server
if self.network:
wait_for_network()
-
- self.create_accounts()
-
- if self.network:
wait_for_wallet()
else:
self.synchronize()
self.running = True
while self.is_running():
-
+
if not self.network.is_connected():
- print_error("synchronizer: waiting for interface")
self.network.wait_until_connected()
- self.run_interface(self.network.interface)
+ self.run_interface()
- def run_interface(self, interface):
+ def run_interface(self):
- print_error("synchronizer: connected to", interface.server)
+ print_error("synchronizer: connected to", self.network.main_server())
requested_tx = []
missing_tx = []
# request missing transactions
for tx_hash, tx_height in missing_tx:
if (tx_hash, tx_height) not in requested_tx:
- interface.send([ ('blockchain.transaction.get',[tx_hash, tx_height]) ], lambda i,r: self.queue.put(r))
+ self.network.send([ ('blockchain.transaction.get',[tx_hash, tx_height]) ], lambda i,r: self.queue.put(r))
requested_tx.append( (tx_hash, tx_height) )
missing_tx = []
# detect if situation has changed
- if interface.is_up_to_date() and self.queue.empty():
+ if self.network.is_up_to_date() and self.queue.empty():
if not self.wallet.is_up_to_date():
self.wallet.set_up_to_date(True)
self.was_updated = True
self.was_updated = True
if self.was_updated:
- self.wallet.network.trigger_callback('updated')
+ self.network.trigger_callback('updated')
self.was_updated = False
# 2. get a response
except Queue.Empty:
continue
- if interface != self.network.interface:
- break
+ # see if it changed
+ #if interface != self.network.interface:
+ # break
if not r:
continue
addr = params[0]
if self.wallet.get_status(self.wallet.get_history(addr)) != result:
if requested_histories.get(addr) is None:
- interface.send([('blockchain.address.get_history', [addr])], lambda i,r:self.queue.put(r))
+ self.network.send([('blockchain.address.get_history', [addr])], lambda i,r:self.queue.put(r))
requested_histories[addr] = result
elif method == 'blockchain.address.get_history':
print_error("Error: Unknown message:" + method + ", " + repr(params) + ", " + repr(result) )
if self.was_updated and not requested_tx:
- self.wallet.network.trigger_callback('updated')
- self.wallet.network.trigger_callback("new_transaction") # Updated gets called too many times from other places as well; if we use that signal we get the notification three times
-
+ self.network.trigger_callback('updated')
+ # Updated gets called too many times from other places as well; if we use that signal we get the notification three times
+ self.network.trigger_callback("new_transaction")
self.was_updated = False