commit 18384d95b35b66f064306f8075048b7acfb79bd8
parent 8e3490c4d35014cfbfa5dd153bd60c20a68bb744
Author: lash <dev@holbrook.no>
Date:   Sun, 16 Jun 2024 23:04:52 +0100
Factor out test setup, implement lmdb class
Diffstat:
7 files changed, 178 insertions(+), 45 deletions(-)
diff --git a/eth_cache/store/lmdb.py b/eth_cache/store/lmdb.py
@@ -0,0 +1,66 @@
+# standard imports
+import os
+import json
+import logging
+
+# external imports
+import lmdb
+from hexathon import strip_0x
+from chainlib.eth.tx import (
+        Tx,
+        pack,
+        )
+
+
+logg = logging.getLogger(__name__)
+
+default_base_dir = '/var/lib'
+
+
+def chain_dir_for(chain_spec, base_dir=default_base_dir):
+    chain_dir = os.path.join(base_dir, str(chain_spec).replace(':', '/'))
+    return os.path.join(chain_dir, 'eth_cache')
+
+
+class LmdbStore:
+
+    def __init__(self, chain_spec, cache_root=default_base_dir, address_rules=None):
+        # TODO: perhaps common for all
+        self.chain_spec = chain_spec
+        self.address_rules = address_rules
+        # TODO: perhaps common for all fs
+        self.chain_dir = chain_dir_for(chain_spec, cache_root)
+        self.cache_dir = self.chain_dir
+        os.makedirs(self.cache_dir, exist_ok=True)
+        self.block_src_path = os.path.join(self.cache_dir, 'block', 'src')
+        self.block_num_path = os.path.join(self.cache_dir, 'block', 'num')
+        self.block_hash_path = os.path.join(self.cache_dir, 'block', 'hash')
+        self.tx_path = os.path.join(self.cache_dir, 'tx', 'src')
+        self.tx_raw_path = os.path.join(self.cache_dir, 'tx', 'raw')
+        self.rcpt_path = os.path.join(self.cache_dir, 'rcpt', 'src')
+        self.rcpt_raw_path = os.path.join(self.cache_dir, 'rcpt', 'raw')
+        self.address_path = os.path.join(self.cache_dir, 'address')
+        self.db = lmdb.open(self.cache_dir, create=True)
+
+
+    def __to_path_key(self, path, k):
+        if path[len(path)-1] != '/':
+            path += '/'
+        return path.encode('utf-8') + k
+
+
+    def put_tx(self, tx, include_data=False):
+        raw = pack(tx.src, self.chain_spec)
+        tx_hash_dirnormal = strip_0x(tx.hash).upper()
+        tx_hash_bytes = bytes.fromhex(tx_hash_dirnormal)
+        k = self.__to_path_key('tx_raw', tx_hash_bytes)
+        with self.db.begin(write=True) as tx:
+            tx.put(k, raw)
+
+
+    def get_tx(self, tx_hash):
+        self.__to_path_key(self, path, key)
+
+
+    def __str__(self):
+        return 'RockDbStore: root {}'.format(self.cache_dir)
diff --git a/requirements.txt b/requirements.txt
@@ -1,4 +1,4 @@
 hexathon~=0.1.7
 jsonrpc-std~=0.1.0
 leveldir~=0.3.0
-chainlib-eth~=0.6.0
+chainlib-eth~=0.6.3
diff --git a/setup.py b/setup.py
@@ -1,5 +1,5 @@
 from setuptools import setup
-import configparser
+#import configparser
 import os
 
 
diff --git a/test_requirements.txt b/test_requirements.txt
@@ -1,5 +1,6 @@
-eth_tester==0.5.0b3
-py-evm==0.3.0a20
-rlp==2.0.1
-pytest==6.0.1
+eth_tester==0.10.0b4
+py-evm==0.10.0b4
+rlp==3.0.0
+#pytest==6.0.1
 coverage==5.5
+#setuptools==70.0.0
diff --git a/tests/test_basic.py b/tests/test_basic.py
@@ -6,64 +6,38 @@ import logging
 import json
 
 # external imports
-from chainlib.chain import ChainSpec
+from chainlib.eth.address import is_same_address
+from hexathon import strip_0x
+from chainlib.eth.nonce import RPCNonceOracle
 from chainlib.eth.gas import (
         Gas,
         OverrideGasOracle,
         )
-from chainlib.eth.nonce import RPCNonceOracle
-from chainlib.eth.unittest.ethtester import EthTesterCase
-from chainlib.eth.tx import (
-        transaction,
-        receipt,
-        TxFormat,
-        Tx,
-        )
 from chainlib.eth.block import (
         block_by_hash,
         block_by_number,
         Block,
         )
-from chainlib.eth.address import is_same_address
-from hexathon import strip_0x
-
+from chainlib.eth.tx import (
+        transaction,
+        Tx,
+        )
+        
 # local imports
 from eth_cache.store.file import FileStore
 from eth_cache.rpc import CacheRPC
+from tests.util import TestCache
+
 
 logging.basicConfig(level=logging.DEBUG)
 logg = logging.getLogger()
 
 
-class TestCache(EthTesterCase):
+class TestCacheBasic(TestCache):
 
     def setUp(self):
-        super(TestCache, self).setUp()
-        fp = tempfile.mkdtemp()
-        self.cache_dir = fp
-
-        class Applier:
-            def apply_rules_addresses(self, sender, recipient, address):
-                return True
-
-        self.store = FileStore(self.chain_spec, cache_root=self.cache_dir, address_rules=Applier())
-        nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
-        gas_oracle = OverrideGasOracle(price=100000000000, limit=30000)
-        c = Gas(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
-        (tx_hash, o) = c.create(self.accounts[0], self.accounts[1], 1024)
-        r = self.rpc.do(o)
-
-        o = transaction(tx_hash)
-        tx_src = self.rpc.do(o)
-
-        o = receipt(tx_hash)
-        rcpt_src = self.rpc.do(o)
-
-        o = block_by_hash(tx_src['block_hash'])
-        block_src = self.rpc.do(o)
-
-        self.block = Block(block_src)
-        self.tx = Tx(tx_src, block=self.block, rcpt=rcpt_src)
+        super(TestCacheBasic, self).setUp()
+        self.store = FileStore(self.chain_spec, cache_root=self.cache_dir, address_rules=self.address_rules)
 
 
     def tearDown(self):
diff --git a/tests/test_lmdb.py b/tests/test_lmdb.py
@@ -0,0 +1,24 @@
+# standard imports
+import unittest
+
+# local imports
+from eth_cache.store.lmdb import LmdbStore
+from tests.util import TestCache
+
+
+class TestCacheBasic(TestCache):
+
+    def setUp(self):
+        super(TestCacheBasic, self).setUp()
+        self.store = LmdbStore(self.chain_spec, cache_root=self.cache_dir, address_rules=self.address_rules)
+
+
+    def test_tx(self):
+        self.store.put_tx(self.tx, include_data=True)
+        #j = self.store.get_tx(self.tx.hash)
+        #tx = json.loads(j)
+        #self.assertTrue(is_same_address(tx['hash'], self.tx.hash))
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/util.py b/tests/util.py
@@ -0,0 +1,68 @@
+# standard imports
+import tempfile
+import shutil
+import unittest
+
+# external imports
+from chainlib.chain import ChainSpec
+from chainlib.eth.gas import (
+        Gas,
+        OverrideGasOracle,
+        )
+from chainlib.eth.nonce import RPCNonceOracle
+from chainlib.eth.tx import (
+        transaction,
+        receipt,
+        TxFormat,
+        Tx,
+        )
+from chainlib.eth.block import (
+        block_by_hash,
+        Block,
+        )
+from chainlib.eth.dialect import DialectFilter as EthDialectFilter
+
+from chainlib.eth.unittest.ethtester import EthTesterCase
+
+# TODO: 2024-06-16 suddenly state_root value is binary, which breaks the json serializer. this seems to be a bug in the eth-tester, and this code should probably be moved to chainlib-eth unittest and implemented by default in test cases
+class DialectFilter(EthDialectFilter):
+    
+    def apply_src(self, src, dialect_filter=None):
+
+        for k in src.keys():
+            if type(src[k]) == bytes:
+                src[k] = '0x' + src[k].hex()
+
+        return src
+
+
+class TestCache(EthTesterCase):
+
+    def setUp(self):
+        super(TestCache, self).setUp()
+        fp = tempfile.mkdtemp()
+        self.cache_dir = fp
+
+        class Applier:
+            def apply_rules_addresses(self, sender, recipient, address):
+                return True
+
+        self.address_rules = Applier()
+        nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc)
+        gas_oracle = OverrideGasOracle(price=100000000000, limit=30000)
+        c = Gas(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
+        (tx_hash, o) = c.create(self.accounts[0], self.accounts[1], 1024)
+        r = self.rpc.do(o)
+
+        o = transaction(tx_hash)
+        tx_src = self.rpc.do(o)
+
+        o = receipt(tx_hash)
+        rcpt_src = self.rpc.do(o)
+
+        o = block_by_hash(tx_src['block_hash'])
+        block_src = self.rpc.do(o)
+
+        fltr = DialectFilter()
+        self.block = Block(block_src, dialect_filter=fltr)
+        self.tx = Tx(tx_src, block=self.block, rcpt=rcpt_src, dialect_filter=fltr)