Improve merkle proof and tx cache performance #29

Merged
jackrobison merged 4 commits from improve-tx-caches into master 2022-05-01 01:23:52 +02:00
2 changed files with 28 additions and 1 deletions
Showing only changes of commit 2d75d62d3f - Show all commits

View file

@ -18,7 +18,7 @@ from scribe.schema.claim import guess_stream_type
from scribe.schema.result import Censor from scribe.schema.result import Censor
from scribe.blockchain.transaction import TxInput from scribe.blockchain.transaction import TxInput
from scribe.common import hash_to_hex_str, hash160, LRUCacheWithMetrics from scribe.common import hash_to_hex_str, hash160, LRUCacheWithMetrics
from scribe.db.merkle import Merkle, MerkleCache from scribe.db.merkle import Merkle, MerkleCache, FastMerkleCacheItem
from scribe.db.common import ResolveResult, STREAM_TYPES, CLAIM_TYPES, ExpandedResolveResult, DBError, UTXO from scribe.db.common import ResolveResult, STREAM_TYPES, CLAIM_TYPES, ExpandedResolveResult, DBError, UTXO
from scribe.db.prefixes import PendingActivationValue, ClaimTakeoverValue, ClaimToTXOValue, PrefixDB from scribe.db.prefixes import PendingActivationValue, ClaimTakeoverValue, ClaimToTXOValue, PrefixDB
from scribe.db.prefixes import ACTIVATED_CLAIM_TXO_TYPE, ACTIVATED_SUPPORT_TXO_TYPE, EffectiveAmountKey from scribe.db.prefixes import ACTIVATED_CLAIM_TXO_TYPE, ACTIVATED_SUPPORT_TXO_TYPE, EffectiveAmountKey

View file

@ -276,3 +276,30 @@ class MerkleCache:
level = await self._level_for(length) level = await self._level_for(length)
return self.merkle.branch_and_root_from_level( return self.merkle.branch_and_root_from_level(
level, leaf_hashes, index, self.depth_higher) level, leaf_hashes, index, self.depth_higher)
class FastMerkleCacheItem:
__slots__ = ['tx_hashes', 'tree', 'root_hash']
def __init__(self, tx_hashes: typing.List[bytes]):
self.tx_hashes = tuple(tx_hashes)
self.tree: typing.List[typing.List[bytes]] = []
self.root_hash = self._walk_merkle(tx_hashes, self.tree.append)
@staticmethod
def _walk_merkle(items: typing.List[bytes], append_layer) -> bytes:
if len(items) == 1:
return items[0]
append_layer(items)
layer = [
double_sha256(items[index] + items[index])
if index + 1 == len(items) else double_sha256(items[index] + items[index + 1])
for index in range(0, len(items), 2)
]
return FastMerkleCacheItem._walk_merkle(layer, append_layer)
def branch(self, tx_position: int) -> typing.List[str]:
return [
(layer[-1] if (tx_position >> shift) ^ 1 == len(layer) else layer[(tx_position >> shift) ^ 1])[::-1].hex()
for shift, layer in enumerate(self.tree)
]