Fix merge conflict

This commit is contained in:
Maran
2013-03-16 21:38:12 +01:00
28 changed files with 881 additions and 698 deletions

View File

@@ -364,10 +364,9 @@ random_seed = lambda n: "%032x"%ecdsa.util.randrange( pow(2,n) )
def bip32_init(seed):
import hmac
seed = seed.decode('hex')
I = hmac.new("Bitcoin seed", seed, hashlib.sha512).digest()
print "seed", seed.encode('hex')
master_secret = I[0:32]
master_chain = I[32:]
@@ -415,8 +414,8 @@ def CKD_prime(K, c, n):
class ElectrumSequence:
""" Privatekey(type,n) = Master_private_key + H(n|S|type) """
def __init__(self, master_public_key, mpk2 = None, mpk3 = None):
self.master_public_key = master_public_key
def __init__(self, mpk, mpk2 = None, mpk3 = None):
self.mpk = mpk
self.mpk2 = mpk2
self.mpk3 = mpk3
@@ -445,7 +444,7 @@ class ElectrumSequence:
address = public_key_to_bc_address( pubkey.decode('hex') )
elif not self.mpk3:
pubkey1 = self.get_pubkey(sequence)
pubkey2 = self.get_pubkey(sequence, use_mpk2=True)
pubkey2 = self.get_pubkey(sequence, mpk = self.mpk2)
address = Transaction.multisig_script([pubkey1, pubkey2], 2)["address"]
else:
pubkey1 = self.get_pubkey(sequence)
@@ -456,7 +455,7 @@ class ElectrumSequence:
def get_pubkey(self, sequence, mpk=None):
curve = SECP256k1
if mpk is None: mpk = self.master_public_key
if mpk is None: mpk = self.mpk
z = self.get_sequence(sequence, mpk)
master_public_key = ecdsa.VerifyingKey.from_string( mpk.decode('hex'), curve = SECP256k1 )
pubkey_point = master_public_key.pubkey.point + z*curve.generator
@@ -465,7 +464,7 @@ class ElectrumSequence:
def get_private_key_from_stretched_exponent(self, sequence, secexp):
order = generator_secp256k1.order()
secexp = ( secexp + self.get_sequence(sequence, self.master_public_key) ) % order
secexp = ( secexp + self.get_sequence(sequence, self.mpk) ) % order
pk = number_to_string( secexp, generator_secp256k1.order() )
compressed = False
return SecretToASecret( pk, compressed )
@@ -483,7 +482,7 @@ class ElectrumSequence:
secexp = self.stretch_key(seed)
master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
master_public_key = master_private_key.get_verifying_key().to_string().encode('hex')
if master_public_key != self.master_public_key:
if master_public_key != self.mpk:
print_error('invalid password (mpk)')
raise BaseException('Invalid password')
return True
@@ -499,8 +498,8 @@ class ElectrumSequence:
redeemScript = Transaction.multisig_script([pubkey1, pubkey2], 2)['redeemScript']
else:
pubkey1 = self.get_pubkey(sequence)
pubkey2 = self.get_pubkey(sequence,mpk=self.mpk2)
pubkey3 = self.get_pubkey(sequence,mpk=self.mpk3)
pubkey2 = self.get_pubkey(sequence, mpk=self.mpk2)
pubkey3 = self.get_pubkey(sequence, mpk=self.mpk3)
pk_addr = public_key_to_bc_address( pubkey1.decode('hex') ) # we need to return that address to get the right private key
redeemScript = Transaction.multisig_script([pubkey1, pubkey2, pubkey3], 2)['redeemScript']
return pk_addr, redeemScript
@@ -510,43 +509,71 @@ class ElectrumSequence:
class BIP32Sequence:
def __init__(self, mpkc, mpkc2 = None):
self.master_public_key, self.master_chain = mpkc
if mpkc2:
self.master_public_key2, self.master_chain2 = mpkc2
self.is_p2sh = True
else:
self.is_p2sh = False
def __init__(self, mpk, mpk2 = None, mpk3 = None):
self.mpk = mpk
self.mpk2 = mpk2
self.mpk3 = mpk3
@classmethod
def mpk_from_seed(klass, seed):
master_secret, master_chain, master_public_key, master_public_key_compressed = bip32_init(seed)
return master_public_key.encode('hex'), master_chain.encode('hex')
def get_pubkey(self, sequence, use_mpk2=False):
if not use_mpl2:
K = self.master_public_key.decode('hex')
chain = self.master_chain.decode('hex')
else:
K = self.master_public_key_2.decode('hex')
chain = self.master_chain_2.decode('hex')
def get_pubkey(self, sequence, mpk = None):
if not mpk: mpk = self.mpk
master_public_key, master_chain = self.mpk
K = master_public_key.decode('hex')
chain = master_chain.decode('hex')
for i in sequence:
K, K_compressed, chain = CKD_prime(K, chain, i)
return K_compressed
return K_compressed.encode('hex')
def get_address(self, sequence):
return hash_160_to_bc_address(hash_160(self.get_pubkey(sequence)))
if not self.mpk2:
pubkey = self.get_pubkey(sequence)
address = public_key_to_bc_address( pubkey.decode('hex') )
elif not self.mpk3:
pubkey1 = self.get_pubkey(sequence)
pubkey2 = self.get_pubkey(sequence, mpk = self.mpk2)
address = Transaction.multisig_script([pubkey1, pubkey2], 2)["address"]
else:
pubkey1 = self.get_pubkey(sequence)
pubkey2 = self.get_pubkey(sequence, mpk = self.mpk2)
pubkey3 = self.get_pubkey(sequence, mpk = self.mpk3)
address = Transaction.multisig_script([pubkey1, pubkey2, pubkey3], 2)["address"]
return address
def get_private_key(self, seed, sequence):
k = self.master_secret
chain = self.master_chain
def get_private_key(self, sequence, seed):
master_secret, master_chain, master_public_key, master_public_key_compressed = bip32_init(seed)
chain = master_chain
k = master_secret
for i in sequence:
k, k_compressed, chain = CKD(k, chain, i)
return SecretToASecret(k0, True)
k, chain = CKD(k, chain, i)
return SecretToASecret(k, True)
def get_private_keys(self, sequence_list, seed):
return [ self.get_private_key( sequence, seed) for sequence in sequence_list]
def check_seed(self, seed):
master_secret, master_chain, master_public_key, master_public_key_compressed = bip32_init(seed)
assert self.master_public_key == master_public_key
assert self.mpk == (master_public_key.encode('hex'), master_chain.encode('hex'))
def get_input_info(self, sequence):
if not self.mpk2:
pk_addr = self.get_address(sequence)
redeemScript = None
elif not self.mpk3:
pubkey1 = self.get_pubkey(sequence)
pubkey2 = self.get_pubkey(sequence, mpk=self.mpk2)
pk_addr = public_key_to_bc_address( pubkey1.decode('hex') ) # we need to return that address to get the right private key
redeemScript = Transaction.multisig_script([pubkey1, pubkey2], 2)['redeemScript']
else:
pubkey1 = self.get_pubkey(sequence)
pubkey2 = self.get_pubkey(sequence, mpk=self.mpk2)
pubkey3 = self.get_pubkey(sequence, mpk=self.mpk3)
pk_addr = public_key_to_bc_address( pubkey1.decode('hex') ) # we need to return that address to get the right private key
redeemScript = Transaction.multisig_script([pubkey1, pubkey2, pubkey3], 2)['redeemScript']
return pk_addr, redeemScript
################################## transactions
@@ -842,7 +869,7 @@ class Transaction:
def test_bip32():
seed = "ff000000000000000000000000000000".decode('hex')
seed = "ff000000000000000000000000000000"
master_secret, master_chain, master_public_key, master_public_key_compressed = bip32_init(seed)
print "secret key", master_secret.encode('hex')

View File

@@ -82,9 +82,10 @@ class Commands:
self.wallet = wallet
self.interface = interface
self._callback = callback
self.password = None
def _run(self, method, args, password_getter):
if method in protected_commands:
if method in protected_commands and self.wallet.use_encryption:
self.password = apply(password_getter,())
f = eval('self.'+method)
result = apply(f,args)

View File

@@ -3,6 +3,7 @@
#
from bitcoin import public_key_to_bc_address, hash_160_to_bc_address, hash_encode, hash_160
from util import print_error
#import socket
import time
import struct
@@ -356,7 +357,8 @@ def get_address_from_input_script(bytes):
pubkeys = [ dec2[1][1].encode('hex'), dec2[2][1].encode('hex'), dec2[3][1].encode('hex') ]
return pubkeys, signatures, hash_160_to_bc_address(hash_160(redeemScript), 5)
raise BaseException("no match for scriptsig")
print_error("cannot find address in input script", bytes.encode('hex'))
return [], [], "(None)"

View File

@@ -595,8 +595,8 @@ class Interface(threading.Thread):
# wait until connection is established
self.connect_event.wait()
if not self.is_connected:
print_msg("Not connected, aborting.")
sys.exit(1)
return False
return True
def run(self):
while True:

View File

@@ -1,4 +1,4 @@
import os, sys
import os, sys, re
import platform
import shutil
from datetime import datetime
@@ -147,3 +147,36 @@ def age(from_date, since_date = None, target_tz=None, include_seconds=False):
return "about 1 year ago"
else:
return "over %d years ago" % (round(distance_in_minutes / 525600))
# URL decode
_ud = re.compile('%([0-9a-hA-H]{2})', re.MULTILINE)
urldecode = lambda x: _ud.sub(lambda m: chr(int(m.group(1), 16)), x)
def parse_url(url):
o = url[8:].split('?')
address = o[0]
if len(o)>1:
params = o[1].split('&')
else:
params = []
amount = label = message = signature = identity = ''
for p in params:
k,v = p.split('=')
uv = urldecode(v)
if k == 'amount': amount = uv
elif k == 'message': message = uv
elif k == 'label': label = uv
elif k == 'signature':
identity, signature = uv.split(':')
url = url.replace('&%s=%s'%(k,v),'')
else:
print k,v
return address, amount, label, message, signature, identity, url

View File

@@ -49,14 +49,10 @@ class WalletVerifier(threading.Thread):
def get_confirmations(self, tx):
""" return the number of confirmations of a monitored transaction. """
with self.lock:
if tx in self.transactions.keys():
if tx in self.verified_tx:
height, timestamp = self.verified_tx[tx]
conf = (self.local_height - height + 1)
else:
conf = -1
if tx in self.verified_tx:
height, timestamp = self.verified_tx[tx]
conf = (self.local_height - height + 1)
else:
#print "verifier: tx not in list", tx
conf = 0
if conf <= 0:
@@ -65,6 +61,13 @@ class WalletVerifier(threading.Thread):
return conf, timestamp
def get_height(self, tx_hash):
with self.lock:
v = self.verified_tx.get(tx_hash)
height = v[0] if v else None
return height
def add(self, tx_hash, tx_height):
""" add a transaction to the list of monitored transactions. """
assert tx_height > 0
@@ -145,6 +148,10 @@ class WalletVerifier(threading.Thread):
continue
if not r: continue
if r.get('error'):
print_error('Verifier received an error:', r)
continue
# 3. handle response
method = r['method']
params = r['params']
@@ -183,7 +190,8 @@ class WalletVerifier(threading.Thread):
# we passed all the tests
header = self.read_header(tx_height)
timestamp = header.get('timestamp')
self.verified_tx[tx_hash] = (tx_height, timestamp)
with self.lock:
self.verified_tx[tx_hash] = (tx_height, timestamp)
print_error("verified %s"%tx_hash)
self.config.set_key('verified_tx2', self.verified_tx, True)
self.interface.trigger_callback('updated')
@@ -241,12 +249,16 @@ class WalletVerifier(threading.Thread):
# this can be caused by a reorg.
print_error("verify header failed"+ repr(header))
# undo verifications
for tx_hash, item in self.verified_tx.items():
with self.lock:
items = self.verified_tx.items()[:]
for tx_hash, item in items:
tx_height, timestamp = item
if tx_height >= height:
print_error("redoing", tx_hash)
self.verified_tx.pop(tx_hash)
if tx_hash in self.merkle_roots: self.merkle_roots.pop(tx_hash)
with self.lock:
self.verified_tx.pop(tx_hash)
if tx_hash in self.merkle_roots:
self.merkle_roots.pop(tx_hash)
# return False to request previous header.
return False

View File

@@ -33,9 +33,6 @@ import time
from util import print_msg, print_error, user_dir, format_satoshis
from bitcoin import *
# URL decode
_ud = re.compile('%([0-9a-hA-H]{2})', re.MULTILINE)
urldecode = lambda x: _ud.sub(lambda m: chr(int(m.group(1), 16)), x)
# AES encryption
EncodeAES = lambda secret, s: base64.b64encode(aes.encryptData(secret,s))
@@ -82,19 +79,16 @@ class Wallet:
self.use_encryption = config.get('use_encryption', False)
self.seed = config.get('seed', '') # encrypted
self.labels = config.get('labels', {})
self.aliases = config.get('aliases', {}) # aliases for addresses
self.authorities = config.get('authorities', {}) # trusted addresses
self.frozen_addresses = config.get('frozen_addresses',[])
self.prioritized_addresses = config.get('prioritized_addresses',[])
self.receipts = config.get('receipts',{}) # signed URIs
self.addressbook = config.get('contacts', [])
self.imported_keys = config.get('imported_keys',{})
self.history = config.get('addr_history',{}) # address -> list(txid, height)
self.tx_height = config.get('tx_height',{})
self.accounts = config.get('accounts', {}) # this should not include public keys
self.SequenceClass = ElectrumSequence
self.sequences = {}
self.sequences[0] = ElectrumSequence(self.config.get('master_public_key'))
self.sequences[0] = self.SequenceClass(self.config.get('master_public_key'))
if self.accounts.get(0) is None:
self.accounts[0] = { 0:[], 1:[], 'name':'Main account' }
@@ -161,13 +155,13 @@ class Wallet:
self.seed = seed
self.config.set_key('seed', self.seed, True)
self.config.set_key('seed_version', self.seed_version, True)
mpk = ElectrumSequence.mpk_from_seed(self.seed)
mpk = self.SequenceClass.mpk_from_seed(self.seed)
self.init_sequence(mpk)
def init_sequence(self, mpk):
self.config.set_key('master_public_key', mpk, True)
self.sequences[0] = ElectrumSequence(mpk)
self.sequences[0] = self.SequenceClass(mpk)
self.accounts[0] = { 0:[], 1:[], 'name':'Main account' }
self.config.set_key('accounts', self.accounts, True)
@@ -184,8 +178,8 @@ class Wallet:
return address in self.addresses(True)
def is_change(self, address):
#return address in self.change_addresses
return False
acct, s = self.get_address_index(address)
return s[0] == 1
def get_master_public_key(self):
return self.sequences[0].master_public_key
@@ -302,6 +296,7 @@ class Wallet:
address = self.get_new_address( account, for_change, n)
self.accounts[account][for_change].append(address)
self.history[address] = []
print_msg(address)
return address
@@ -412,6 +407,12 @@ class Wallet:
# redo labels
# self.update_tx_labels()
def get_num_tx(self, address):
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 "-"
@@ -424,46 +425,6 @@ class Wallet:
return tx.get_value(addresses, self.prevout_values)
def get_tx_details(self, tx_hash):
import datetime
if not tx_hash: return ''
tx = self.transactions.get(tx_hash)
is_mine, v, fee = self.get_tx_value(tx)
conf, timestamp = self.verifier.get_confirmations(tx_hash)
if timestamp:
time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
else:
time_str = 'pending'
inputs = map(lambda x: x.get('address'), tx.inputs)
outputs = map(lambda x: x.get('address'), tx.d['outputs'])
tx_details = "Transaction Details" +"\n\n" \
+ "Transaction ID:\n" + tx_hash + "\n\n" \
+ "Status: %d confirmations\n"%conf
if is_mine:
if fee:
tx_details += "Amount sent: %s\n"% format_satoshis(v-fee, False) \
+ "Transaction fee: %s\n"% format_satoshis(fee, False)
else:
tx_details += "Amount sent: %s\n"% format_satoshis(v, False) \
+ "Transaction fee: unknown\n"
else:
tx_details += "Amount received: %s\n"% format_satoshis(v, False) \
tx_details += "Date: %s\n\n"%time_str \
+ "Inputs:\n-"+ '\n-'.join(inputs) + "\n\n" \
+ "Outputs:\n-"+ '\n-'.join(outputs)
r = self.receipts.get(tx_hash)
if r:
tx_details += "\n_______________________________________" \
+ '\n\nSigned URI: ' + r[2] \
+ "\n\nSigned by: " + r[0] \
+ '\n\nSignature: ' + r[1]
return tx_details
def update_tx_outputs(self, tx_hash):
tx = self.transactions.get(tx_hash)
@@ -566,6 +527,7 @@ class Wallet:
if h == ['*']: continue
for tx_hash, tx_height in h:
tx = self.transactions.get(tx_hash)
if tx is None: raise BaseException("Wallet not synchronized")
for output in tx.d.get('outputs'):
if output.get('address') != addr: continue
key = tx_hash + ":%d" % output.get('index')
@@ -640,11 +602,12 @@ class Wallet:
def receive_tx_callback(self, tx_hash, tx, tx_height):
if not self.check_new_tx(tx_hash, tx):
raise BaseException("error: received transaction is not consistent with history", tx_hash)
# may happen due to pruning
print_error("received transaction that is no longer referenced in history", tx_hash)
return
with self.lock:
self.transactions[tx_hash] = tx
self.tx_height[tx_hash] = tx_height
#tx_height = tx.get('height')
if self.verifier and tx_height>0:
@@ -669,17 +632,12 @@ class Wallet:
if tx_height>0:
# add it in case it was previously unconfirmed
if self.verifier: self.verifier.add(tx_hash, tx_height)
# set the height in case it changed
txh = self.tx_height.get(tx_hash)
if txh is not None and txh != tx_height:
print_error( "changing height for tx", tx_hash )
self.tx_height[tx_hash] = tx_height
def get_tx_history(self):
with self.lock:
history = self.transactions.items()
history.sort(key = lambda x: self.tx_height.get(x[0]) if self.tx_height.get(x[0]) else 1e12)
history.sort(key = lambda x: self.verifier.get_height(x[0]) if self.verifier.get_height(x[0]) else 1e12)
result = []
balance = 0
@@ -724,6 +682,9 @@ class Wallet:
default_label = self.labels[o_addr]
except KeyError:
default_label = o_addr
break
else:
default_label = '(internal)'
else:
for o in tx.outputs:
o_addr, _ = o
@@ -812,48 +773,6 @@ class Wallet:
return True, out
def read_alias(self, alias):
# this might not be the right place for this function.
import urllib
m1 = re.match('([\w\-\.]+)@((\w[\w\-]+\.)+[\w\-]+)', alias)
m2 = re.match('((\w[\w\-]+\.)+[\w\-]+)', alias)
if m1:
url = 'https://' + m1.group(2) + '/bitcoin.id/' + m1.group(1)
elif m2:
url = 'https://' + alias + '/bitcoin.id'
else:
return ''
try:
lines = urllib.urlopen(url).readlines()
except:
return ''
# line 0
line = lines[0].strip().split(':')
if len(line) == 1:
auth_name = None
target = signing_addr = line[0]
else:
target, auth_name, signing_addr, signature = line
msg = "alias:%s:%s:%s"%(alias,target,auth_name)
print msg, signature
EC_KEY.verify_message(signing_addr, signature, msg)
# other lines are signed updates
for line in lines[1:]:
line = line.strip()
if not line: continue
line = line.split(':')
previous = target
print repr(line)
target, signature = line
EC_KEY.verify_message(previous, signature, "alias:%s:%s"%(alias,target))
if not is_valid(target):
raise ValueError("Invalid bitcoin address")
return target, signing_addr, auth_name
def update_password(self, seed, old_password, new_password):
if new_password == '': new_password = None
@@ -867,96 +786,6 @@ class Wallet:
self.imported_keys[k] = c
self.save()
def get_alias(self, alias, interactive = False, show_message=None, question = None):
try:
target, signing_address, auth_name = self.read_alias(alias)
except BaseException, e:
# raise exception if verify fails (verify the chain)
if interactive:
show_message("Alias error: " + str(e))
return
print target, signing_address, auth_name
if auth_name is None:
a = self.aliases.get(alias)
if not a:
msg = "Warning: the alias '%s' is self-signed.\nThe signing address is %s.\n\nDo you want to add this alias to your list of contacts?"%(alias,signing_address)
if interactive and question( msg ):
self.aliases[alias] = (signing_address, target)
else:
target = None
else:
if signing_address != a[0]:
msg = "Warning: the key of alias '%s' has changed since your last visit! It is possible that someone is trying to do something nasty!!!\nDo you accept to change your trusted key?"%alias
if interactive and question( msg ):
self.aliases[alias] = (signing_address, target)
else:
target = None
else:
if signing_address not in self.authorities.keys():
msg = "The alias: '%s' links to %s\n\nWarning: this alias was signed by an unknown key.\nSigning authority: %s\nSigning address: %s\n\nDo you want to add this key to your list of trusted keys?"%(alias,target,auth_name,signing_address)
if interactive and question( msg ):
self.authorities[signing_address] = auth_name
else:
target = None
if target:
self.aliases[alias] = (signing_address, target)
return target
def parse_url(self, url, show_message, question):
o = url[8:].split('?')
address = o[0]
if len(o)>1:
params = o[1].split('&')
else:
params = []
amount = label = message = signature = identity = ''
for p in params:
k,v = p.split('=')
uv = urldecode(v)
if k == 'amount': amount = uv
elif k == 'message': message = uv
elif k == 'label': label = uv
elif k == 'signature':
identity, signature = uv.split(':')
url = url.replace('&%s=%s'%(k,v),'')
else:
print k,v
if label and self.labels.get(address) != label:
if question('Give label "%s" to address %s ?'%(label,address)):
if address not in self.addressbook and not self.is_mine(address):
self.addressbook.append(address)
self.labels[address] = label
if signature:
if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', identity):
signing_address = self.get_alias(identity, True, show_message, question)
elif is_valid(identity):
signing_address = identity
else:
signing_address = None
if not signing_address:
return
try:
EC_KEY.verify_message(signing_address, signature, url )
self.receipt = (signing_address, signature, url)
except:
show_message('Warning: the URI contains a bad signature.\nThe identity of the recipient cannot be verified.')
address = amount = label = identity = message = ''
if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', address):
payto_address = self.get_alias(address, True, show_message, question)
if payto_address:
address = address + ' <' + payto_address + '>'
return address, amount, label, message, signature, identity, url
def freeze(self,addr):
@@ -1007,15 +836,11 @@ class Wallet:
'labels': self.labels,
'contacts': self.addressbook,
'imported_keys': self.imported_keys,
'aliases': self.aliases,
'authorities': self.authorities,
'receipts': self.receipts,
'num_zeros': self.num_zeros,
'frozen_addresses': self.frozen_addresses,
'prioritized_addresses': self.prioritized_addresses,
'gap_limit': self.gap_limit,
'transactions': tx,
'tx_height': self.tx_height,
}
for k, v in s.items():
self.config.set_key(k,v)
@@ -1024,17 +849,6 @@ class Wallet:
def set_verifier(self, verifier):
self.verifier = verifier
# review stored transactions and send them to the verifier
# (they are not necessarily in the history, because history items might have have been pruned)
for tx_hash, tx in self.transactions.items():
tx_height = self.tx_height[tx_hash]
if tx_height <1:
print_error( "skipping", tx_hash, tx_height )
continue
if tx_height>0:
self.verifier.add(tx_hash, tx_height)
# review transactions that are in the history
for addr, hist in self.history.items():
if hist == ['*']: continue
@@ -1042,11 +856,6 @@ class Wallet:
if tx_height>0:
# add it in case it was previously unconfirmed
self.verifier.add(tx_hash, tx_height)
# set the height in case it changed
txh = self.tx_height.get(tx_hash)
if txh is not None and txh != tx_height:
print_error( "changing height for tx", tx_hash )
self.tx_height[tx_hash] = tx_height
@@ -1082,7 +891,7 @@ class Wallet:
if not tx: continue
# already verified?
if self.tx_height.get(tx_hash):
if self.verifier.get_height(tx_hash):
continue
# unconfirmed tx
print_error("new history is orphaning transaction:", tx_hash)
@@ -1099,7 +908,6 @@ class Wallet:
for item in h:
if item.get('tx_hash') == tx_hash:
height = item.get('height')
self.tx_height[tx_hash] = height
if height:
print_error("found height for", tx_hash, height)
self.verifier.add(tx_hash, height)
@@ -1155,22 +963,6 @@ class WalletSynchronizer(threading.Thread):
def is_running(self):
with self.lock: return self.running
def synchronize_wallet(self):
new_addresses = self.wallet.synchronize()
if new_addresses:
self.subscribe_to_addresses(new_addresses)
self.wallet.up_to_date = False
return
if not self.interface.is_up_to_date('synchronizer'):
if self.wallet.is_up_to_date():
self.wallet.set_up_to_date(False)
self.was_updated = True
return
self.wallet.set_up_to_date(True)
self.was_updated = True
def subscribe_to_addresses(self, addresses):
messages = []
@@ -1202,15 +994,30 @@ class WalletSynchronizer(threading.Thread):
self.subscribe_to_addresses(self.wallet.addresses(True))
while self.is_running():
# 1. send new requests
self.synchronize_wallet()
# 1. create new addresses
new_addresses = self.wallet.synchronize()
# request missing addresses
if new_addresses:
self.subscribe_to_addresses(new_addresses)
# request missing transactions
for tx_hash, tx_height in missing_tx:
if (tx_hash, tx_height) not in requested_tx:
self.interface.send([ ('blockchain.transaction.get',[tx_hash, tx_height]) ], 'synchronizer')
requested_tx.append( (tx_hash, tx_height) )
missing_tx = []
# detect if situation has changed
if not self.interface.is_up_to_date('synchronizer'):
if self.wallet.is_up_to_date():
self.wallet.set_up_to_date(False)
self.was_updated = True
else:
if not self.wallet.is_up_to_date():
self.wallet.set_up_to_date(True)
self.was_updated = True
if self.was_updated:
self.interface.trigger_callback('updated')
self.was_updated = False