99'''History by script hash (address).'''
1010
1111import ast
12- import bisect
1312import time
14- from array import array
1513from collections import defaultdict
1614from typing import TYPE_CHECKING , Type , Optional , Dict , Sequence , Tuple
1715import itertools
1816
1917import electrumx .lib .util as util
2018from electrumx .lib .hash import HASHX_LEN , hash_to_hex_str
21- from electrumx .lib .util import (pack_be_uint16 , pack_le_uint64 ,
22- unpack_be_uint16_from , unpack_le_uint64 ,
23- pack_le_uint32 , unpack_le_uint32 )
19+ from electrumx .lib .util import (pack_le_uint64 , unpack_le_uint64 ,
20+ pack_le_uint32 , unpack_le_uint32 ,
21+ pack_be_uint64 , unpack_be_uint64 )
2422
2523if TYPE_CHECKING :
2624 from electrumx .server .storage import Storage
3230TXOUTIDX_PADDING = bytes (4 - TXOUTIDX_LEN )
3331
3432
33+ def unpack_txnum (tx_numb : bytes ) -> int :
34+ return unpack_be_uint64 (TXNUM_PADDING + tx_numb )[0 ]
35+
36+
37+ def pack_txnum (tx_num : int ) -> bytes :
38+ return pack_be_uint64 (tx_num )[- TXNUM_LEN :]
39+
40+
3541class History :
3642
3743 DB_VERSIONS = (3 , )
@@ -115,23 +121,23 @@ def clear_excess(self, utxo_db_tx_count: int) -> None:
115121 hkeys = []
116122 for db_key , db_val in self .db .iterator (prefix = b'H' ):
117123 tx_numb = db_key [1 + HASHX_LEN : 1 + HASHX_LEN + TXNUM_LEN ]
118- tx_num , = unpack_le_uint64 (tx_numb + TXNUM_PADDING )
124+ tx_num = unpack_txnum (tx_numb )
119125 if tx_num >= utxo_db_tx_count :
120126 hkeys .append (db_key )
121127
122128 tkeys = []
123129 for db_key , db_val in self .db .iterator (prefix = b't' ):
124130 tx_numb = db_val
125- tx_num , = unpack_le_uint64 (tx_numb + TXNUM_PADDING )
131+ tx_num = unpack_txnum (tx_numb )
126132 if tx_num >= utxo_db_tx_count :
127133 tkeys .append (db_key )
128134
129135 skeys = []
130136 for db_key , db_val in self .db .iterator (prefix = b's' ):
131137 tx_numb1 = db_key [1 :1 + TXNUM_LEN ]
132138 tx_numb2 = db_val
133- tx_num1 , = unpack_le_uint64 (tx_numb1 + TXNUM_PADDING )
134- tx_num2 , = unpack_le_uint64 (tx_numb2 + TXNUM_PADDING )
139+ tx_num1 = unpack_txnum (tx_numb1 )
140+ tx_num2 = unpack_txnum (tx_numb2 )
135141 if max (tx_num1 , tx_num2 ) >= utxo_db_tx_count :
136142 skeys .append (db_key )
137143
@@ -183,7 +189,7 @@ def add_unflushed(
183189 spender_txnum = get_txnum_for_txhash (spender_hash )
184190 assert spender_txnum is not None
185191 prev_idx_packed = pack_le_uint32 (prev_idx )[:TXOUTIDX_LEN ]
186- prev_txnumb = pack_le_uint64 (prev_txnum )[: TXNUM_LEN ]
192+ prev_txnumb = pack_txnum (prev_txnum )
187193 unflushed_spenders [prev_txnumb + prev_idx_packed ] = spender_txnum
188194
189195 def unflushed_memsize (self ):
@@ -210,11 +216,11 @@ def flush(self):
210216 batch .put (db_key , b'' )
211217 for tx_hash , tx_num in sorted (self ._unflushed_txhash_to_txnum_map .items ()):
212218 db_key = b't' + tx_hash
213- tx_numb = pack_le_uint64 (tx_num )[: TXNUM_LEN ]
219+ tx_numb = pack_txnum (tx_num )
214220 batch .put (db_key , tx_numb )
215221 for prevout , spender_txnum in sorted (self ._unflushed_txo_to_spender .items ()):
216222 db_key = b's' + prevout
217- db_val = pack_le_uint64 (spender_txnum )[: TXNUM_LEN ]
223+ db_val = pack_txnum (spender_txnum )
218224 batch .put (db_key , db_val )
219225 self .hist_db_tx_count = self .hist_db_tx_count_next
220226 self .write_state (batch )
@@ -242,11 +248,12 @@ def backup(self, *, hashXs, tx_count, tx_hashes: Sequence[bytes], spends: Sequen
242248 prefix = b'H' + hashX
243249 for db_key , db_val in self .db .iterator (prefix = prefix , reverse = True ):
244250 tx_numb = db_key [1 + HASHX_LEN : 1 + HASHX_LEN + TXNUM_LEN ]
245- tx_num , = unpack_le_uint64 (tx_numb + TXNUM_PADDING )
251+ tx_num = unpack_txnum (tx_numb )
246252 if tx_num >= tx_count :
247253 nremoves_addr += 1
248254 deletes .append (db_key )
249255 else :
256+ # note: we can break now, due to 'reverse=True' and txnums being big endian
250257 break
251258 for key in deletes :
252259 batch .delete (key )
@@ -256,7 +263,7 @@ def backup(self, *, hashXs, tx_count, tx_hashes: Sequence[bytes], spends: Sequen
256263 assert len (prev_idx ) == TXOUTIDX_LEN
257264 prev_txnum = get_txnum_for_txhash (prev_hash )
258265 assert prev_txnum is not None
259- prev_txnumb = pack_le_uint64 (prev_txnum )[: TXNUM_LEN ]
266+ prev_txnumb = pack_txnum (prev_txnum )
260267 db_key = b's' + prev_txnumb + prev_idx
261268 batch .delete (db_key )
262269 for tx_hash in sorted (tx_hashes ):
@@ -282,7 +289,7 @@ def get_txnums(self, hashX: bytes, limit: Optional[int] = 1000) -> Sequence[int]
282289 break
283290 prev_txnumb = db_key [1 + HASHX_LEN : 1 + HASHX_LEN + TXNUM_LEN ]
284291 prev_idx_packed = db_key [- TXOUTIDX_LEN :]
285- prev_txnum , = unpack_le_uint64 (prev_txnumb + TXNUM_PADDING )
292+ prev_txnum = unpack_txnum (prev_txnumb )
286293 prev_idx , = unpack_le_uint32 (prev_idx_packed + TXOUTIDX_PADDING )
287294 txnum_set .add (prev_txnum )
288295 spender_txnum = self .get_spender_txnum_for_txo (prev_txnum , prev_idx )
@@ -299,20 +306,20 @@ def get_txnum_for_txhash(self, tx_hash: bytes) -> Optional[int]:
299306 db_key = b't' + tx_hash
300307 tx_numb = self .db .get (db_key )
301308 if tx_numb :
302- tx_num , = unpack_le_uint64 (tx_numb + TXNUM_PADDING )
309+ tx_num = unpack_txnum (tx_numb )
303310 return tx_num
304311
305312 def get_spender_txnum_for_txo (self , prev_txnum : int , txout_idx : int ) -> Optional [int ]:
306313 '''For an outpoint, returns the tx_num that spent it.
307314 If the outpoint is unspent, or even if it never existed (!), returns None.
308315 '''
309316 prev_idx_packed = pack_le_uint32 (txout_idx )[:TXOUTIDX_LEN ]
310- prev_txnumb = pack_le_uint64 (prev_txnum )[: TXNUM_LEN ]
317+ prev_txnumb = pack_txnum (prev_txnum )
311318 prevout = prev_txnumb + prev_idx_packed
312319 spender_txnum = self ._unflushed_txhash_to_txnum_map .get (prevout )
313320 if spender_txnum is None :
314321 db_key = b's' + prevout
315322 spender_txnumb = self .db .get (db_key )
316323 if spender_txnumb :
317- spender_txnum , = unpack_le_uint64 (spender_txnumb + TXNUM_PADDING )
324+ spender_txnum = unpack_txnum (spender_txnumb )
318325 return spender_txnum
0 commit comments