verifier: request proofs in batches
This commit is contained in:
@@ -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):
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user