chainqueue

Blockchain transaction queue control
Log | Files | Refs | LICENSE

commit fce9bce6fcd9b5f97d3fa3846bdfb78f5c6be0f7
parent 5a92058e74e62202e9e84943d357fcb497881334
Author: lash <dev@holbrook.no>
Date:   Fri, 11 Mar 2022 11:02:47 +0000

Initial shep provisions

Diffstat:
MCHANGELOG | 2++
Achainqueue/__init__.py | 1+
Achainqueue/state.py | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Achainqueue/tx.py | 21+++++++++++++++++++++
Mrequirements.txt | 7++++---
Atests/test_shep.py | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 144 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,3 +1,5 @@ +- 0.1.0 + * Replace state transitions with shep - 0.0.3 * cli tool for listing queue by address * ensure lowercase hex input in db diff --git a/chainqueue/__init__.py b/chainqueue/__init__.py @@ -0,0 +1 @@ +from .state import Status diff --git a/chainqueue/state.py b/chainqueue/state.py @@ -0,0 +1,65 @@ +# standard imports +import logging + +# external imports +import shep.persist + +logg = logging.getLogger(__name__) + + +class Verify: + + def verify(self, state_store, from_state, to_state): + to_state_name = state_store.name(to_state) + m = None + try: + m = getattr(self, 'verify_' + to_state_name) + except AttributeError: + logg.debug('foo {}'.format(to_state_name)) + return None + + r = m(state_store, from_state) + if r != None: + from_state_name = state_store.name(from_state) + r = '{} -> {}: {}'.format(from_state_name, to_state_name, r) + + return r + + + def verify_GAS_ISSUES(self, state_store, from_state): + if from_state & state_store.FINAL: + return 'already finalized' + if from_state & state_store.GAS_ISSUES: + return 'already in network' + + + +class Status(shep.persist.PersistedState): + + def __init__(self, store_factory): + verify = Verify().verify + self.set_default_state('PENDING') + super(Status, self).__init__(store_factory, 12, verifier=verify) + self.add('QUEUED') + self.add('RESERVED') + self.add('IN_NETWORK') + self.add('DEFERRED') + self.add('GAS_ISSUES') + self.add('LOCAL_ERROR') + self.add('NODE_ERROR') + self.add('NETWORK_ERROR') + self.add('UNKNOWN_ERROR') + self.add('FINAL') + self.add('OBSOLETE') + self.add('MANUAL') + + self.alias('SENDFAIL', self.DEFERRED | self.LOCAL_ERROR) + self.alias('RETRY', self.DEFERRED | self.QUEUED) + self.alias('OBSOLETED', self.OBSOLETE | self.IN_NETWORK) + self.alias('FUBAR', self.FINAL | self.UNKNOWN_ERROR) + self.alias('CANCELLED', self.IN_NETWORK | self.FINAL | self.OBSOLETE) + self.alias('OVERRIDDEN', self.FINAL | self.OBSOLETE | self.MANUAL) + self.alias('REJECTED', self.NODE_ERROR | self.FINAL) + self.alias('REVERTED', self.IN_NETWORK | self.FINAL, self.NETWORK_ERROR) + self.alias('SUCCESS', self.IN_NETWORK | self.FINAL) + diff --git a/chainqueue/tx.py b/chainqueue/tx.py @@ -0,0 +1,21 @@ +class Tx: + + def __init__(self, store, seq, tx_hash, signed_tx, cache=None): + self.store = store + self.seq = seq + self.tx_hash = tx_hash + self.signed_tx = signed_tx + self.cache = cache + + + def __to_key(self, k, v): + return '{:>010s}_{}'.format(k, v) + + + def create(self): + k = self.__to_key(str(self.seq), self.tx_hash) + self.store.put(k, self.signed_tx) + + + def waitforgas(self): + pass diff --git a/requirements.txt b/requirements.txt @@ -1,8 +1,9 @@ pysha3==1.0.2 -hexathon~=0.1.0 +hexathon~=0.1.5 leveldir~=0.3.0 alembic==1.4.2 SQLAlchemy==1.3.20 -confini~=0.5.1 +confini~=0.6.0 pyxdg~=0.27 -chainlib~=0.0.12 +chainlib>=0.1.0b1,<=0.1.0 +shep~=0.1.1 diff --git a/tests/test_shep.py b/tests/test_shep.py @@ -0,0 +1,51 @@ +# standard imports +import os +import logging +import unittest +import tempfile + +# external imports +from hexathon import add_0x +from shep.store.file import SimpleFileStoreFactory +from shep.error import StateTransitionInvalid + +# local imports +from chainqueue import Status +from chainqueue.tx import Tx + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + + +class TestShepBase(unittest.TestCase): + + def setUp(self): + self.path = tempfile.mkdtemp() + factory = SimpleFileStoreFactory(self.path).add + self.state = Status(factory) + + +class TestShep(TestShepBase): + + def test_shep_setup(self): + pass + + + def test_shep_tx(self): + tx_hash = add_0x(os.urandom(20).hex()) + signed_tx = add_0x(os.urandom(128).hex()) + nonce = 42 + tx = Tx(self.state, nonce, tx_hash, signed_tx) + tx.create() + logg.debug('file {}'.format(self.path)) + + + def test_shep_invalid(self): + self.state.put('foo', 'bar') + self.state.set('foo', self.state.FINAL) + with self.assertRaises(StateTransitionInvalid): + self.state.move('foo', self.state.GAS_ISSUES) + + +if __name__ == '__main__': + unittest.main()