wallet/verifier: persist wallet.verified_tx when verifier finishes
Previously verified_tx was only persisted in wallet.stop_threads(), hence only on clean shutdowns.
This commit is contained in:
parent
4159322db0
commit
060404e17c
@ -31,9 +31,8 @@ class SPV(ThreadJob):
|
|||||||
self.wallet = wallet
|
self.wallet = wallet
|
||||||
self.network = network
|
self.network = network
|
||||||
self.blockchain = network.blockchain()
|
self.blockchain = network.blockchain()
|
||||||
# Keyed by tx hash. Value is None if the merkle branch was
|
self.merkle_roots = {} # txid -> merkle root (once it has been verified)
|
||||||
# requested, and the merkle root once it has been verified
|
self.requested_merkle = set() # txid set of pending requests
|
||||||
self.merkle_roots = {}
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
interface = self.network.interface
|
interface = self.network.interface
|
||||||
@ -53,12 +52,13 @@ class SPV(ThreadJob):
|
|||||||
if index < len(blockchain.checkpoints):
|
if index < len(blockchain.checkpoints):
|
||||||
self.network.request_chunk(interface, index)
|
self.network.request_chunk(interface, index)
|
||||||
else:
|
else:
|
||||||
if tx_hash not in self.merkle_roots:
|
if (tx_hash not in self.requested_merkle
|
||||||
|
and tx_hash not in self.merkle_roots):
|
||||||
request = ('blockchain.transaction.get_merkle',
|
request = ('blockchain.transaction.get_merkle',
|
||||||
[tx_hash, tx_height])
|
[tx_hash, tx_height])
|
||||||
self.network.send([request], self.verify_merkle)
|
self.network.send([request], self.verify_merkle)
|
||||||
self.print_error('requested merkle', tx_hash)
|
self.print_error('requested merkle', tx_hash)
|
||||||
self.merkle_roots[tx_hash] = None
|
self.requested_merkle.add(tx_hash)
|
||||||
|
|
||||||
if self.network.blockchain() != self.blockchain:
|
if self.network.blockchain() != self.blockchain:
|
||||||
self.blockchain = self.network.blockchain()
|
self.blockchain = self.network.blockchain()
|
||||||
@ -94,8 +94,15 @@ class SPV(ThreadJob):
|
|||||||
return
|
return
|
||||||
# we passed all the tests
|
# we passed all the tests
|
||||||
self.merkle_roots[tx_hash] = merkle_root
|
self.merkle_roots[tx_hash] = merkle_root
|
||||||
|
try:
|
||||||
|
# note: we could pop in the beginning, but then we would request
|
||||||
|
# this proof again in case of verification failure from the same server
|
||||||
|
self.requested_merkle.remove(tx_hash)
|
||||||
|
except KeyError: pass
|
||||||
self.print_error("verified %s" % tx_hash)
|
self.print_error("verified %s" % tx_hash)
|
||||||
self.wallet.add_verified_tx(tx_hash, (tx_height, header.get('timestamp'), pos))
|
self.wallet.add_verified_tx(tx_hash, (tx_height, header.get('timestamp'), pos))
|
||||||
|
if self.is_up_to_date() and self.wallet.is_up_to_date():
|
||||||
|
self.wallet.save_verified_tx(write=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def hash_merkle_root(cls, merkle_s, target_hash, pos):
|
def hash_merkle_root(cls, merkle_s, target_hash, pos):
|
||||||
@ -110,4 +117,14 @@ class SPV(ThreadJob):
|
|||||||
tx_hashes = self.wallet.undo_verifications(self.blockchain, height)
|
tx_hashes = self.wallet.undo_verifications(self.blockchain, height)
|
||||||
for tx_hash in tx_hashes:
|
for tx_hash in tx_hashes:
|
||||||
self.print_error("redoing", tx_hash)
|
self.print_error("redoing", tx_hash)
|
||||||
self.merkle_roots.pop(tx_hash, None)
|
self.remove_spv_proof_for_tx(tx_hash)
|
||||||
|
|
||||||
|
def remove_spv_proof_for_tx(self, tx_hash):
|
||||||
|
self.merkle_roots.pop(tx_hash, None)
|
||||||
|
try:
|
||||||
|
self.requested_merkle.remove(tx_hash)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def is_up_to_date(self):
|
||||||
|
return not self.requested_merkle
|
||||||
|
|||||||
@ -222,9 +222,10 @@ class Abstract_Wallet(PrintError):
|
|||||||
self.load_unverified_transactions()
|
self.load_unverified_transactions()
|
||||||
self.remove_local_transactions_we_dont_have()
|
self.remove_local_transactions_we_dont_have()
|
||||||
|
|
||||||
# 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 network.is_up_to_date().
|
||||||
# interface.is_up_to_date() returns true when all requests have been answered and processed
|
# network.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)
|
||||||
|
# Neither of them considers the verifier.
|
||||||
self.up_to_date = False
|
self.up_to_date = False
|
||||||
|
|
||||||
# save wallet type the first time
|
# save wallet type the first time
|
||||||
@ -291,6 +292,12 @@ class Abstract_Wallet(PrintError):
|
|||||||
if write:
|
if write:
|
||||||
self.storage.write()
|
self.storage.write()
|
||||||
|
|
||||||
|
def save_verified_tx(self, write=False):
|
||||||
|
with self.lock:
|
||||||
|
self.storage.put('verified_tx3', self.verified_tx)
|
||||||
|
if write:
|
||||||
|
self.storage.write()
|
||||||
|
|
||||||
def clear_history(self):
|
def clear_history(self):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
with self.transaction_lock:
|
with self.transaction_lock:
|
||||||
@ -365,6 +372,10 @@ class Abstract_Wallet(PrintError):
|
|||||||
self.up_to_date = up_to_date
|
self.up_to_date = up_to_date
|
||||||
if up_to_date:
|
if up_to_date:
|
||||||
self.save_transactions(write=True)
|
self.save_transactions(write=True)
|
||||||
|
# if the verifier is also up to date, persist that too;
|
||||||
|
# otherwise it will persist its results when it finishes
|
||||||
|
if self.verifier and self.verifier.is_up_to_date():
|
||||||
|
self.save_verified_tx(write=True)
|
||||||
|
|
||||||
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
|
||||||
@ -445,7 +456,7 @@ class Abstract_Wallet(PrintError):
|
|||||||
with self.lock:
|
with self.lock:
|
||||||
self.verified_tx.pop(tx_hash)
|
self.verified_tx.pop(tx_hash)
|
||||||
if self.verifier:
|
if self.verifier:
|
||||||
self.verifier.merkle_roots.pop(tx_hash, None)
|
self.verifier.remove_spv_proof_for_tx(tx_hash)
|
||||||
|
|
||||||
# tx will be verified only if height > 0
|
# tx will be verified only if height > 0
|
||||||
if tx_hash not in self.verified_tx:
|
if tx_hash not in self.verified_tx:
|
||||||
@ -965,7 +976,7 @@ class Abstract_Wallet(PrintError):
|
|||||||
self.unverified_tx.pop(tx_hash, None)
|
self.unverified_tx.pop(tx_hash, None)
|
||||||
self.verified_tx.pop(tx_hash, None)
|
self.verified_tx.pop(tx_hash, None)
|
||||||
if self.verifier:
|
if self.verifier:
|
||||||
self.verifier.merkle_roots.pop(tx_hash, None)
|
self.verifier.remove_spv_proof_for_tx(tx_hash)
|
||||||
# but remove completely if not is_mine
|
# but remove completely if not is_mine
|
||||||
if self.txi[tx_hash] == {}:
|
if self.txi[tx_hash] == {}:
|
||||||
# FIXME the test here should be for "not all is_mine"; cannot detect conflict in some cases
|
# FIXME the test here should be for "not all is_mine"; cannot detect conflict in some cases
|
||||||
@ -1322,8 +1333,7 @@ class Abstract_Wallet(PrintError):
|
|||||||
# remain so they will be GC-ed
|
# remain so they will be GC-ed
|
||||||
self.storage.put('stored_height', self.get_local_height())
|
self.storage.put('stored_height', self.get_local_height())
|
||||||
self.save_transactions()
|
self.save_transactions()
|
||||||
with self.lock:
|
self.save_verified_tx()
|
||||||
self.storage.put('verified_tx3', self.verified_tx)
|
|
||||||
self.storage.write()
|
self.storage.write()
|
||||||
|
|
||||||
def wait_until_synchronized(self, callback=None):
|
def wait_until_synchronized(self, callback=None):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user