lmdb.py (3515B)
1 # standard imports 2 import os 3 import json 4 import logging 5 6 # external imports 7 import lmdb 8 from hexathon import strip_0x 9 from chainlib.eth.tx import ( 10 Tx, 11 pack, 12 ) 13 14 # local imports 15 from . import StoreAction 16 from eth_cache.store.fs import FsStore 17 18 logg = logging.getLogger(__name__) 19 20 21 def to_path_key(path, k): 22 if type(k) == str: 23 k = k.encode('utf-8') 24 elif type(k) == int: 25 k = k.to_bytes(8, byteorder='big') 26 if path[len(path)-1] != '/': 27 path += '/' 28 return path.encode('utf-8') + k 29 30 31 class LmdbStoreAdder: 32 33 def __init__(self, action, db): 34 self.action = action 35 self.db = db 36 37 38 def add(self, k, v): 39 dbk = to_path_key(self.action.value, k) 40 with self.db.begin(write=True) as dbtx: 41 dbtx.put(dbk, v) 42 43 44 class LmdbStore(FsStore): 45 46 def __init__(self, chain_spec, cache_root=None, address_rules=None): 47 super(LmdbStore, self).__init__(chain_spec, cache_root=cache_root, address_rules=address_rules) 48 self.db = lmdb.open(self.cache_dir, create=True) 49 for action in StoreAction: 50 self.register_adder(action, LmdbStoreAdder(action, self.db)) 51 52 53 def put_tx(self, tx, include_data=False): 54 super(LmdbStore, self).put_tx(tx, include_data=include_data) 55 56 57 def get_tx(self, tx_hash): 58 tx = None 59 k = bytes.fromhex(tx_hash) 60 k = to_path_key(StoreAction.TX.value, k) 61 with self.db.begin() as dbtx: 62 tx = dbtx.get(k) 63 if tx == None: 64 raise FileNotFoundError(tx_hash) 65 return tx 66 67 68 def get_rcpt(self, tx_hash): 69 rcpt = None 70 k = bytes.fromhex(tx_hash) 71 k = to_path_key(StoreAction.RCPT.value, k) 72 with self.db.begin() as dbtx: 73 rcpt = dbtx.get(k) 74 if rcpt == None: 75 raise FileNotFoundError(tx_hash) 76 return rcpt 77 78 79 def get_block(self, block_hash): 80 k = bytes.fromhex(block_hash) 81 k = to_path_key(StoreAction.BLOCK.value, k) 82 with self.db.begin() as dbtx: 83 return dbtx.get(k) 84 85 86 def get_block_number(self, block_number): 87 block =None 88 r = None 89 k = block_number.to_bytes(8, byteorder='big') 90 k = to_path_key(StoreAction.BLOCK_NUM.value, k) 91 with self.db.begin() as dbtx: 92 r = dbtx.get(k) 93 try: 94 block = self.get_block(r.hex()) 95 except AttributeError: 96 raise FileNotFoundError(str(block_number)) 97 98 return block 99 100 101 def get_address_tx(self, address): 102 k = bytes.fromhex(address) 103 ok = to_path_key(StoreAction.ADDRESS.value, k) 104 tx_hashes = [] 105 with self.db.begin() as dbtx: 106 dbcr = dbtx.cursor() 107 v = dbcr.set_range(ok) 108 if v == None: 109 return tx_hashes 110 l = len(ok) 111 for k, v in dbcr: 112 if k[:l] != ok: 113 return tx_hashes 114 tx_hashes.append(v) 115 116 117 def put_address(self, tx, address): 118 address_bytes = bytes.fromhex(strip_0x(address)) 119 tx_hash_bytes = bytes.fromhex(strip_0x(tx.hash)) 120 k = address_bytes + tx_hash_bytes + b'.start' 121 122 with self.db.begin() as dbtx: 123 r = dbtx.get(k) 124 if r != None: 125 return 126 127 num = tx.block.number 128 v = num.to_bytes(8, byteorder='big') 129 self.add(StoreAction.ADDRESS, k, v) 130 131 132 def __str__(self): 133 return 'LmdbStore: root {}'.format(self.cache_dir)