Move the verified and unverified txs to the wallet.
This commit is contained in:
parent
656560be72
commit
a47881d72b
|
@ -25,41 +25,23 @@ import util
|
||||||
from bitcoin import *
|
from bitcoin import *
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SPV(util.DaemonThread):
|
class SPV(util.DaemonThread):
|
||||||
""" Simple Payment Verification """
|
""" Simple Payment Verification """
|
||||||
|
|
||||||
def __init__(self, network, storage):
|
def __init__(self, network, wallet):
|
||||||
util.DaemonThread.__init__(self)
|
util.DaemonThread.__init__(self)
|
||||||
self.storage = storage
|
self.wallet = wallet
|
||||||
self.network = network
|
self.network = network
|
||||||
self.transactions = {} # requested verifications (with height sent by the requestor)
|
|
||||||
self.verified_tx = storage.get('verified_tx3',{}) # height, timestamp of verified transactions
|
|
||||||
self.merkle_roots = {} # hashed by me
|
self.merkle_roots = {} # hashed by me
|
||||||
self.lock = threading.Lock()
|
|
||||||
self.queue = Queue.Queue()
|
self.queue = Queue.Queue()
|
||||||
|
|
||||||
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
|
|
||||||
with self.lock:
|
|
||||||
if tx_hash not in self.transactions.keys():
|
|
||||||
self.transactions[tx_hash] = tx_height
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
requested_merkle = []
|
requested_merkle = []
|
||||||
while self.is_running():
|
while self.is_running():
|
||||||
|
verified_tx, unverified_tx = self.wallet.get_transactions()
|
||||||
# request missing tx
|
# request missing tx
|
||||||
for tx_hash, tx_height in self.transactions.items():
|
for tx_hash, tx_height in unverified_tx.items():
|
||||||
if tx_hash not in self.verified_tx:
|
if tx_hash not in verified_tx:
|
||||||
# do not request merkle branch before headers are available
|
# do not request merkle branch before headers are available
|
||||||
if tx_height > self.network.get_local_height():
|
if tx_height > self.network.get_local_height():
|
||||||
continue
|
continue
|
||||||
|
@ -102,12 +84,8 @@ class SPV(util.DaemonThread):
|
||||||
|
|
||||||
# we passed all the tests
|
# we passed all the tests
|
||||||
self.merkle_roots[tx_hash] = merkle_root
|
self.merkle_roots[tx_hash] = merkle_root
|
||||||
timestamp = header.get('timestamp')
|
|
||||||
with self.lock:
|
|
||||||
self.verified_tx[tx_hash] = (tx_height, timestamp, pos)
|
|
||||||
self.print_error("verified %s" % tx_hash)
|
self.print_error("verified %s" % tx_hash)
|
||||||
self.storage.put('verified_tx3', self.verified_tx, True)
|
self.wallet.add_verified_tx(tx_hash, (tx_height, header.get('timestamp'), pos))
|
||||||
self.network.trigger_callback('updated')
|
|
||||||
|
|
||||||
|
|
||||||
def hash_merkle_root(self, merkle_s, target_hash, pos):
|
def hash_merkle_root(self, merkle_s, target_hash, pos):
|
||||||
|
@ -118,15 +96,13 @@ class SPV(util.DaemonThread):
|
||||||
return hash_encode(h)
|
return hash_encode(h)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def undo_verifications(self, height):
|
def undo_verifications(self, height):
|
||||||
with self.lock:
|
verified_tx, unverified_tx = self.wallet.get_transactions()
|
||||||
items = self.verified_tx.items()[:]
|
txs = []
|
||||||
for tx_hash, item in items:
|
for tx_hash, item in verified_tx:
|
||||||
tx_height, timestamp, pos = item
|
tx_height, timestamp, pos = item
|
||||||
if tx_height >= height:
|
if tx_height >= height:
|
||||||
self.print_error("redoing", tx_hash)
|
self.print_error("redoing", tx_hash)
|
||||||
with self.lock:
|
txs.append(tx_hash)
|
||||||
self.verified_tx.pop(tx_hash)
|
self.merkle_roots.pop(tx_hash, None)
|
||||||
if tx_hash in self.merkle_roots:
|
self.wallet.unverify_txs(txs)
|
||||||
self.merkle_roots.pop(tx_hash)
|
|
||||||
|
|
|
@ -182,6 +182,11 @@ class Abstract_Wallet(object):
|
||||||
|
|
||||||
# spv
|
# spv
|
||||||
self.verifier = None
|
self.verifier = None
|
||||||
|
# Transactions pending verification. Each value is the transaction height. Access with self.lock.
|
||||||
|
self.unverified_tx = {}
|
||||||
|
# Verified transactions. Each value is a (height, timestamp, block_pos) tuple. Access with self.lock.
|
||||||
|
self.verified_tx = storage.get('verified_tx3',{})
|
||||||
|
|
||||||
# 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)
|
||||||
|
@ -388,19 +393,35 @@ class Abstract_Wallet(object):
|
||||||
return decrypted
|
return decrypted
|
||||||
|
|
||||||
def add_unverified_tx(self, tx_hash, tx_height):
|
def add_unverified_tx(self, tx_hash, tx_height):
|
||||||
if self.verifier and tx_height > 0:
|
if tx_height > 0:
|
||||||
self.verifier.add(tx_hash, tx_height)
|
with self.lock:
|
||||||
|
self.unverified_tx[tx_hash] = tx_height
|
||||||
|
|
||||||
|
def add_verified_tx(self, tx_hash, info):
|
||||||
|
with self.lock:
|
||||||
|
self.verified_tx[tx_hash] = info # (tx_height, timestamp, pos)
|
||||||
|
self.storage.put('verified_tx3', self.verified_tx, True)
|
||||||
|
self.network.trigger_callback('updated')
|
||||||
|
|
||||||
|
def unverify_txs(self, txs):
|
||||||
|
'''Used by the verifier when a reorg has happened'''
|
||||||
|
with self.lock:
|
||||||
|
for tx_hash in txs:
|
||||||
|
self.verified_tx.pop(tx_hash, None)
|
||||||
|
|
||||||
|
def get_transactions(self):
|
||||||
|
'''Return the verified and unverified tx dicts'''
|
||||||
|
with self.lock:
|
||||||
|
return self.verified_tx, self.unverified_tx
|
||||||
|
|
||||||
def get_confirmations(self, tx):
|
def get_confirmations(self, tx):
|
||||||
""" return the number of confirmations of a monitored transaction. """
|
""" return the number of confirmations of a monitored transaction. """
|
||||||
if not self.verifier:
|
verified_tx, unverified_tx = self.get_transactions()
|
||||||
return (None, None)
|
if tx in verified_tx:
|
||||||
with self.verifier.lock:
|
height, timestamp, pos = verified_tx[tx]
|
||||||
if tx in self.verifier.verified_tx:
|
|
||||||
height, timestamp, pos = self.verifier.verified_tx[tx]
|
|
||||||
conf = (self.network.get_local_height() - height + 1)
|
conf = (self.network.get_local_height() - height + 1)
|
||||||
if conf <= 0: timestamp = None
|
if conf <= 0: timestamp = None
|
||||||
elif tx in self.verifier.transactions:
|
elif tx in unverified_tx:
|
||||||
conf = -1
|
conf = -1
|
||||||
timestamp = None
|
timestamp = None
|
||||||
else:
|
else:
|
||||||
|
@ -411,9 +432,9 @@ class Abstract_Wallet(object):
|
||||||
|
|
||||||
def get_txpos(self, tx_hash):
|
def get_txpos(self, tx_hash):
|
||||||
"return position, even if the tx is unverified"
|
"return position, even if the tx is unverified"
|
||||||
with self.verifier.lock:
|
verified_tx, unverified_tx = self.get_transactions()
|
||||||
x = self.verifier.verified_tx.get(tx_hash)
|
x = verified_tx.get(tx_hash)
|
||||||
y = self.verifier.transactions.get(tx_hash)
|
y = unverified_tx.get(tx_hash)
|
||||||
if x:
|
if x:
|
||||||
height, timestamp, pos = x
|
height, timestamp, pos = x
|
||||||
return height, pos
|
return height, pos
|
||||||
|
@ -1000,7 +1021,8 @@ class Abstract_Wallet(object):
|
||||||
self.add_unverified_tx (tx_hash, tx_height)
|
self.add_unverified_tx (tx_hash, tx_height)
|
||||||
|
|
||||||
# if we are on a pruning server, remove unverified transactions
|
# if we are on a pruning server, remove unverified transactions
|
||||||
vr = self.verifier.transactions.keys() + self.verifier.verified_tx.keys()
|
verified_tx, unverified_tx = self.get_transactions()
|
||||||
|
vr = verified_tx.keys() + unverified_tx.keys()
|
||||||
for tx_hash in self.transactions.keys():
|
for tx_hash in self.transactions.keys():
|
||||||
if tx_hash not in vr:
|
if tx_hash not in vr:
|
||||||
print_error("removing transaction", tx_hash)
|
print_error("removing transaction", tx_hash)
|
||||||
|
@ -1016,6 +1038,7 @@ class Abstract_Wallet(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# check that we are not "orphaning" a transaction
|
# check that we are not "orphaning" a transaction
|
||||||
|
verified_tx, unverified_tx = self.get_transactions()
|
||||||
old_hist = self.history.get(addr,[])
|
old_hist = self.history.get(addr,[])
|
||||||
for tx_hash, height in old_hist:
|
for tx_hash, height in old_hist:
|
||||||
if tx_hash in map(lambda x:x[0], hist):
|
if tx_hash in map(lambda x:x[0], hist):
|
||||||
|
@ -1035,7 +1058,7 @@ class Abstract_Wallet(object):
|
||||||
if not tx: continue
|
if not tx: continue
|
||||||
|
|
||||||
# already verified?
|
# already verified?
|
||||||
if self.verifier.get_height(tx_hash):
|
if tx_hash in verified_tx:
|
||||||
continue
|
continue
|
||||||
# unconfirmed tx
|
# unconfirmed tx
|
||||||
print_error("new history is orphaning transaction:", tx_hash)
|
print_error("new history is orphaning transaction:", tx_hash)
|
||||||
|
@ -1065,7 +1088,7 @@ class Abstract_Wallet(object):
|
||||||
from verifier import SPV
|
from verifier import SPV
|
||||||
self.network = network
|
self.network = network
|
||||||
if self.network is not None:
|
if self.network is not None:
|
||||||
self.verifier = SPV(self.network, self.storage)
|
self.verifier = SPV(self.network, self)
|
||||||
self.verifier.start()
|
self.verifier.start()
|
||||||
self.set_verifier(self.verifier)
|
self.set_verifier(self.verifier)
|
||||||
self.synchronizer = WalletSynchronizer(self, network)
|
self.synchronizer = WalletSynchronizer(self, network)
|
||||||
|
|
Loading…
Reference in New Issue