chainlib-eth

Ethereum implementation of the chainlib interface
Log | Files | Refs | README | LICENSE

commit 7c27c78ba51b25c4c3568db40e12b8d8a9c700af
parent 01f55363db5a8323c289ab82b996b66ebd0e9fff
Author: lash <dev@holbrook.no>
Date:   Fri, 16 Dec 2022 08:32:55 +0000

Add support for custom processing of tx, block sources

Diffstat:
MCHANGELOG | 2++
Mchainlib/eth/block.py | 9+++++++--
Mchainlib/eth/dialect/__init__.py | 14++++++++++++++
Mchainlib/eth/tx.py | 31+++++++++++++++----------------
Msetup.cfg | 2+-
Mtests/test_block.py | 43+++++++++++++++++++++++++++++++++++++++++++
6 files changed, 82 insertions(+), 19 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,3 +1,5 @@ +- 0.4.8 + * Add support for dialect differences in tx and block processing - 0.4.7 * Add support for all power of two uint sizes - 0.4.6 diff --git a/chainlib/eth/block.py b/chainlib/eth/block.py @@ -93,9 +93,11 @@ class Block(BaseBlock, Src): tx_generator = Tx - def __init__(self, src=None): - super(Block, self).__init__(src=src) + def __init__(self, src=None, dialect_filter=None): + super(Block, self).__init__(src=src, dialect_filter=dialect_filter) + + def load_src(self, dialect_filter=None): self.set_hash(self.src['hash']) try: self.number = int(strip_0x(self.src['number']), 16) @@ -117,6 +119,9 @@ class Block(BaseBlock, Src): self.fee_cost = self.src['gas_used'] self.parent_hash = self.src['parent_hash'] + if dialect_filter != None: + dialect_filter.apply_block(self) + def tx_index_by_hash(self, tx_hash): i = 0 diff --git a/chainlib/eth/dialect/__init__.py b/chainlib/eth/dialect/__init__.py @@ -1,5 +1,8 @@ +# external imports + # local imports from chainlib.eth.error import EthException +from chainlib.dialect import DialectFilter class DefaultErrorParser: @@ -7,3 +10,14 @@ class DefaultErrorParser: """ def translate(self, error): return EthException('default parser codeĀ {}'.format(error)) + + +class DefaultDialectFilter(DialectFilter): + + def apply_src(self, src): + try: + inpt = src['input'] + except KeyError: + inpt = src['data'] + src['input'] = src['data'] + return src diff --git a/chainlib/eth/tx.py b/chainlib/eth/tx.py @@ -47,9 +47,11 @@ from .constant import ( from .contract import ABIContractEncoder from .jsonrpc import to_blockheight_param from .src import Src +from .dialect import DefaultDialectFilter logg = logging.getLogger(__name__) +eth_dialect_filter = DefaultDialectFilter() class TxFormat(enum.IntEnum): @@ -581,7 +583,7 @@ class Tx(BaseTx, Src): #:todo: divide up constructor method """ - def __init__(self, src, block=None, result=None, strict=False, rcpt=None): + def __init__(self, src, block=None, result=None, strict=False, rcpt=None, dialect_filter=eth_dialect_filter): # backwards compat self.gas_price = None self.gas_limit = None @@ -590,20 +592,16 @@ class Tx(BaseTx, Src): self.r = None self.s = None - super(Tx, self).__init__(src, block=block, result=result, strict=strict) + super(Tx, self).__init__(src, block=block, result=result, strict=strict, dialect_filter=dialect_filter) if result == None and rcpt != None: self.apply_receipt(rcpt) + if dialect_filter != None: + dialect_filter.apply_result(rcpt) - def apply_src(self, src): - try: - inpt = src['input'] - except KeyError: - inpt = src['data'] - src['input'] = src['data'] - - src = super(Tx, self).apply_src(src) + def apply_src(self, src, dialect_filter=None): + src = super(Tx, self).apply_src(src, dialect_filter=dialect_filter) hsh = self.normal(src['hash'], SrcItem.HASH) self.set_hash(hsh) @@ -651,18 +649,20 @@ class Tx(BaseTx, Src): self.s = src.get('s') #self.status = Status.PENDING + if dialect_filter != None: + dialect_filter.apply_tx(self) def as_dict(self): return self.src - def apply_receipt(self, rcpt, strict=False): + def apply_receipt(self, rcpt, strict=False, dialect_filter=None): result = TxResult(src=rcpt) self.apply_result(result) - def apply_result(self, result, strict=False): + def apply_result(self, result, strict=False, dialect_filter=None): """Apply receipt data to transaction object. Effect is the same as passing a receipt at construction. @@ -680,7 +680,7 @@ class Tx(BaseTx, Src): super(Tx, self).apply_result(result) - def apply_block(self, block): + def apply_block(self, block, dialect_filter=None): """Apply block to transaction object. :param block: Block object @@ -705,18 +705,17 @@ class Tx(BaseTx, Src): @staticmethod - def from_src(src, block=None, rcpt=None, strict=False, chain_spec=None): + def from_src(src, block=None, rcpt=None, strict=False, chain_spec=None, dialect_filter=eth_dialect_filter): """Creates a new Tx object. Alias of constructor. """ - tx = Tx(src, block=block, rcpt=rcpt, strict=strict) + tx = Tx(src, block=block, rcpt=rcpt, strict=strict, dialect_filter=dialect_filter) if chain_spec != None: tx.generate_wire(chain_spec) return tx - def __str__(self): if self.block != None: return 'tx {} status {} block {} index {}'.format(add_0x(self.hash), self.status.name, self.block.number, self.index) diff --git a/setup.cfg b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = chainlib-eth -version = 0.4.7 +version = 0.4.8 description = Ethereum implementation of the chainlib interface author = Louis Holbrook author_email = dev@holbrook.no diff --git a/tests/test_block.py b/tests/test_block.py @@ -7,6 +7,7 @@ import logging # local imports from chainlib.eth.jsonrpc import to_blockheight_param from chainlib.eth.block import Block +from chainlib.eth.dialect import DialectFilter logging.basicConfig(level=logging.DEBUG) @@ -70,5 +71,47 @@ class TestBlock(unittest.TestCase): self.assertEqual(to_blockheight_param(1), '0x0000000000000001') + def test_block_filter(self): + class TestFilter(DialectFilter): + + def apply_block(self, block): + block.extra['foo'] = 'bar' + block.number = 24 + return block + + tx_one_src = { + 'hash': os.urandom(32).hex(), + 'from': os.urandom(20).hex(), + 'to': os.urandom(20).hex(), + 'value': 13, + 'data': '0xdeadbeef', + 'nonce': 666, + 'gasPrice': 100, + 'gas': 21000, + } + tx_two_src_hash = os.urandom(32).hex() + + block_hash = os.urandom(32).hex() + parent_hash = os.urandom(32).hex() + block_author = os.urandom(20).hex() + block_time = datetime.datetime.utcnow().timestamp() + block_src = { + 'number': 42, + 'hash': block_hash, + 'author': block_author, + 'transactions': [ + tx_one_src, + tx_two_src_hash, + ], + 'timestamp': block_time, + 'gas_used': '0x1234', + 'gas_limit': '0x2345', + 'parent_hash': parent_hash + } + block = Block(block_src, dialect_filter=TestFilter()) + self.assertEqual(block.extra['foo'], 'bar') + self.assertEqual(block.number, 24) + + if __name__ == '__main__': unittest.main()