use multi_get
for fetching transactions #25
2 changed files with 38 additions and 17 deletions
|
@ -1020,35 +1020,36 @@ class HubDB:
|
|||
|
||||
if needed_confirmed:
|
||||
needed_heights = set()
|
||||
tx_heights_and_positions = {}
|
||||
tx_heights_and_positions = defaultdict(list)
|
||||
for (tx_hash_bytes, tx_num), tx in zip(needed_confirmed, await run_in_executor(
|
||||
self._executor, self.prefix_db.tx.multi_get, [(tx_hash,) for tx_hash, _ in needed_confirmed],
|
||||
True, False)):
|
||||
tx_height = bisect_right(self.tx_counts, tx_num)
|
||||
needed_heights.add(tx_height)
|
||||
tx_pos = tx_num - self.tx_counts[tx_height - 1]
|
||||
tx_heights_and_positions[tx_hash_bytes] = (tx, tx_num, tx_height, tx_pos)
|
||||
tx_heights_and_positions[tx_height].append((tx_hash_bytes, tx, tx_num, tx_pos))
|
||||
|
||||
sorted_heights = list(sorted(needed_heights))
|
||||
block_txs = await run_in_executor(
|
||||
self._executor, self.prefix_db.block_txs.multi_get, [(height,) for height in sorted_heights]
|
||||
)
|
||||
block_txs = {height: v.tx_hashes for height, v in zip(sorted_heights, block_txs)}
|
||||
for tx_hash_bytes, (tx, tx_num, tx_height, tx_pos) in tx_heights_and_positions.items():
|
||||
branch, root = self.merkle.branch_and_root(
|
||||
block_txs[tx_height], tx_pos
|
||||
for tx_height, v in tx_heights_and_positions.items():
|
||||
branches, root = self.merkle.branches_and_root(
|
||||
block_txs[tx_height], [tx_pos for (tx_hash_bytes, tx, tx_num, tx_pos) in v]
|
||||
)
|
||||
merkle = {
|
||||
'block_height': tx_height,
|
||||
'merkle': [
|
||||
hash_to_hex_str(_hash)
|
||||
for _hash in branch
|
||||
],
|
||||
'pos': tx_pos
|
||||
}
|
||||
tx_infos[tx_hash_bytes[::-1].hex()] = None if not tx else tx.hex(), merkle
|
||||
if tx_height > 0 and tx_height + 10 < self.db_height:
|
||||
self._tx_and_merkle_cache[tx_hash_bytes[::-1].hex()] = tx, merkle
|
||||
for (tx_hash_bytes, tx, tx_num, tx_pos) in v:
|
||||
merkle = {
|
||||
'block_height': tx_height,
|
||||
'merkle': [
|
||||
hash_to_hex_str(_hash)
|
||||
for _hash in branches[tx_pos]
|
||||
],
|
||||
'pos': tx_pos
|
||||
}
|
||||
tx_infos[tx_hash_bytes[::-1].hex()] = None if not tx else tx.hex(), merkle
|
||||
if tx_height > 0 and tx_height + 10 < self.db_height:
|
||||
self._tx_and_merkle_cache[tx_hash_bytes[::-1].hex()] = tx, merkle
|
||||
await asyncio.sleep(0)
|
||||
if needed_mempool:
|
||||
for tx_hash_bytes, tx in zip(needed_mempool, await run_in_executor(
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
# and warranty status of this software.
|
||||
|
||||
"""Merkle trees, branches, proofs and roots."""
|
||||
|
||||
import typing
|
||||
from asyncio import Event
|
||||
from math import ceil, log
|
||||
|
||||
|
@ -87,6 +87,26 @@ class Merkle:
|
|||
|
||||
return branch, hashes[0]
|
||||
|
||||
@staticmethod
|
||||
def branches_and_root(block_tx_hashes: typing.List[bytes], tx_positions: typing.List[int]):
|
||||
block_tx_hashes = list(block_tx_hashes)
|
||||
positions = list(tx_positions)
|
||||
length = ceil(log(len(block_tx_hashes), 2))
|
||||
branches = [[] for _ in range(len(tx_positions))]
|
||||
for _ in range(length):
|
||||
if len(block_tx_hashes) & 1:
|
||||
h = block_tx_hashes[-1]
|
||||
block_tx_hashes.append(h)
|
||||
for idx, tx_position in enumerate(tx_positions):
|
||||
h = block_tx_hashes[tx_position ^ 1]
|
||||
branches[idx].append(h)
|
||||
tx_positions[idx] >>= 1
|
||||
block_tx_hashes = [
|
||||
double_sha256(block_tx_hashes[n] + block_tx_hashes[n + 1]) for n in
|
||||
range(0, len(block_tx_hashes), 2)
|
||||
]
|
||||
return {tx_position: branch for tx_position, branch in zip(positions, branches)}, block_tx_hashes[0]
|
||||
|
||||
@staticmethod
|
||||
def root(hashes, length=None):
|
||||
"""Return the merkle root of a non-empty iterable of binary hashes."""
|
||||
|
|
Loading…
Reference in a new issue