eth-cache

Ethereum chain data caching tools
Info | Log | Files | Refs | LICENSE

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)