1
0

verifier: request proofs in batches

This commit is contained in:
SomberNight
2018-08-31 19:51:32 +02:00
parent c89020725b
commit 2187615c08
2 changed files with 24 additions and 26 deletions

View File

@@ -719,7 +719,6 @@ class Network(PrintError):
pass pass
async def get_merkle_for_transaction(self, tx_hash, tx_height): async def get_merkle_for_transaction(self, tx_hash, tx_height):
print("getting merkle for transaction", tx_hash, tx_height)
return await self.interface.session.send_request('blockchain.transaction.get_merkle', [tx_hash, tx_height]) return await self.interface.session.send_request('blockchain.transaction.get_merkle', [tx_hash, tx_height])
def broadcast_transaction(self, tx): def broadcast_transaction(self, tx):

View File

@@ -24,6 +24,8 @@
import asyncio import asyncio
from typing import Sequence, Optional from typing import Sequence, Optional
from aiorpcx import TaskGroup
from .util import ThreadJob, bh2u, VerifiedTxInfo, aiosafe from .util import ThreadJob, bh2u, VerifiedTxInfo, aiosafe
from .bitcoin import Hash, hash_decode, hash_encode from .bitcoin import Hash, hash_decode, hash_encode
from .transaction import Transaction from .transaction import Transaction
@@ -49,10 +51,10 @@ class SPV(ThreadJob):
@aiosafe @aiosafe
async def main(self): async def main(self):
while True: while True:
await self.run() await self._request_proofs()
await asyncio.sleep(1) await asyncio.sleep(1)
async def run(self): async def _request_proofs(self):
blockchain = self.network.blockchain() blockchain = self.network.blockchain()
if not blockchain: if not blockchain:
self.print_error("no blockchain") self.print_error("no blockchain")
@@ -60,33 +62,30 @@ class SPV(ThreadJob):
local_height = self.network.get_local_height() local_height = self.network.get_local_height()
unverified = self.wallet.get_unverified_txs() unverified = self.wallet.get_unverified_txs()
#print("verifier run", len(unverified))
for tx_hash, tx_height in unverified.items():
# do not request merkle branch before headers are available
if tx_height <= 0 or tx_height > local_height:
continue
header = blockchain.read_header(tx_height) async with TaskGroup() as group:
if header is None: for tx_hash, tx_height in unverified.items():
index = tx_height // 2016 # do not request merkle branch before headers are available
if index < len(blockchain.checkpoints): if tx_height <= 0 or tx_height > local_height:
await self.network.request_chunk(tx_height, None) continue
elif (tx_hash not in self.requested_merkle
and tx_hash not in self.merkle_roots): header = blockchain.read_header(tx_height)
self.print_error('requested merkle', tx_hash) if header is None:
self.requested_merkle.add(tx_hash) index = tx_height // 2016
self.verify_merkle(tx_hash, await self.network.get_merkle_for_transaction( if index < len(blockchain.checkpoints):
tx_hash, await group.spawn(self.network.request_chunk, tx_height, None)
tx_height elif (tx_hash not in self.requested_merkle
)) and tx_hash not in self.merkle_roots):
self.print_error('requested merkle', tx_hash)
self.requested_merkle.add(tx_hash)
await group.spawn(self._request_and_verify_single_proof, tx_hash, tx_height)
if self.network.blockchain() != self.blockchain: if self.network.blockchain() != self.blockchain:
self.blockchain = self.network.blockchain() self.blockchain = self.network.blockchain()
self.undo_verifications() self._undo_verifications()
def verify_merkle(self, tx_hash, merkle): async def _request_and_verify_single_proof(self, tx_hash, tx_height):
if self.wallet.verifier is None: merkle = await self.network.get_merkle_for_transaction(tx_hash, tx_height)
return # we have been killed, this was just an orphan callback
# Verify the hash of the server-provided merkle branch to a # Verify the hash of the server-provided merkle branch to a
# transaction matches the merkle root of its block # transaction matches the merkle root of its block
tx_height = merkle.get('block_height') tx_height = merkle.get('block_height')
@@ -143,7 +142,7 @@ class SPV(ThreadJob):
else: else:
raise InnerNodeOfSpvProofIsValidTx() raise InnerNodeOfSpvProofIsValidTx()
def undo_verifications(self): def _undo_verifications(self):
height = self.blockchain.get_forkpoint() height = self.blockchain.get_forkpoint()
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: