diff --git a/chainqueue/db/migrations/default/alembic.ini b/chainqueue/db/migrations/default/alembic.ini index ab88225..c88a93b 100644 --- a/chainqueue/db/migrations/default/alembic.ini +++ b/chainqueue/db/migrations/default/alembic.ini @@ -60,7 +60,7 @@ keys = console keys = generic [logger_root] -level = WARN +#level = WARN handlers = console qualname = diff --git a/chainqueue/db/models/otx.py b/chainqueue/db/models/otx.py index 4d7b3c8..deeea0c 100644 --- a/chainqueue/db/models/otx.py +++ b/chainqueue/db/models/otx.py @@ -151,7 +151,7 @@ class Otx(SessionBase): if not self.status & StatusBits.RESERVED: status = status_str(self.status) SessionBase.release_session(session) - raise TxStateChangeError('FUBAR on tx that has not been RESEREVED ({})'.format(status)) + raise TxStateChangeError('FUBAR on tx that has not been RESERVED ({})'.format(status)) self.__set_status(StatusBits.UNKNOWN_ERROR | StatusBits.FINAL, session) @@ -187,7 +187,7 @@ class Otx(SessionBase): if not self.status & StatusBits.RESERVED: status = status_str(self.status) SessionBase.release_session(session) - raise TxStateChangeError('REJECTED on tx that has not been RESEREVED ({})'.format(status)) + raise TxStateChangeError('REJECTED on tx that has not been RESERVED ({})'.format(status)) @@ -219,8 +219,8 @@ class Otx(SessionBase): raise TxStateChangeError('OVERRIDDEN/OBSOLETED cannot be set on an entry already OBSOLETE ({})'.format(status)) self.__set_status(StatusBits.OBSOLETE, session) - #if manual: - # self.__set_status(StatusBits.MANUAL, session) + if manual: + self.manual(session=session) self.__reset_status(StatusBits.QUEUED | StatusBits.IN_NETWORK, session) if self.tracing: @@ -246,6 +246,7 @@ class Otx(SessionBase): SessionBase.release_session(session) + def retry(self, session=None): """Marks transaction as ready to retry after a timeout following a sendfail or a completed gas funding. @@ -326,7 +327,7 @@ class Otx(SessionBase): if not self.status & StatusBits.RESERVED: status = self.status SessionBase.release_session(session) - raise TxStateChangeError('SENT on tx that has not been RESEREVED ({})'.format(status)) + raise TxStateChangeError('SENT on tx that has not been RESERVED ({})'.format(status)) self.__set_status(StatusBits.IN_NETWORK, session) self.__reset_status(StatusBits.RESERVED | StatusBits.DEFERRED | StatusBits.QUEUED | StatusBits.LOCAL_ERROR | StatusBits.NODE_ERROR, session) @@ -360,7 +361,7 @@ class Otx(SessionBase): if not self.status & StatusBits.RESERVED: status = self.status SessionBase.release_session(session) - raise TxStateChangeError('SENDFAIL on tx that has not been RESEREVED ({})'.format(status)) + raise TxStateChangeError('SENDFAIL on tx that has not been RESERVED ({})'.format(status)) self.__set_status(StatusBits.LOCAL_ERROR | StatusBits.DEFERRED, session) self.__reset_status(StatusBits.RESERVED | StatusBits.QUEUED | StatusBits.GAS_ISSUES, session) diff --git a/chainqueue/sql/state.py b/chainqueue/sql/state.py index c169cf0..c0646df 100644 --- a/chainqueue/sql/state.py +++ b/chainqueue/sql/state.py @@ -95,7 +95,10 @@ def set_final(chain_spec, tx_hash, block=None, tx_index=None, fail=False, sessio raise(e) if block != None: - TxCache.set_final(o.tx_hash, block, tx_index, session=session) + try: + TxCache.set_final(o.tx_hash, block, tx_index, session=session) + except NotLocalTxError: + logg.debug('otx for {} does not have cache complement'.format(tx_hash)) session.commit() @@ -115,7 +118,6 @@ def set_cancel(chain_spec, tx_hash, manual=False, session=None): :type manual: boolean :raises NotLocalTxError: If transaction not found in queue. """ - session = SessionBase.bind_session(session) o = Otx.load(tx_hash, session=session) if o == None: diff --git a/setup.cfg b/setup.cfg index c913e32..2485138 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = chainqueue -version = 0.0.2a2 +version = 0.0.2b1 description = Generic blockchain transaction queue control author = Louis Holbrook author_email = dev@holbrook.no @@ -31,6 +31,7 @@ packages = chainqueue.db chainqueue.db.models chainqueue.db.migrations + chainqueue.sql #[options.entry_points] #console_scripts = diff --git a/test_requirements.txt b/test_requirements.txt index e69de29..7b4f8ca 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -0,0 +1 @@ +chainlib==0.0.3rc2 diff --git a/tests/base.py b/tests/base.py index 5fc6e7e..83b0de0 100644 --- a/tests/base.py +++ b/tests/base.py @@ -11,17 +11,20 @@ from chainqueue.db.models.tx import TxCache from chainlib.chain import ChainSpec import alembic import alembic.config -from hexathon import add_0x +from hexathon import ( + add_0x, + strip_0x, + ) # local imports from chainqueue.db import dsn_from_config from chainqueue.db.models.base import SessionBase -from chainqueue.tx import create +from chainqueue.sql.tx import create script_dir = os.path.realpath(os.path.dirname(__file__)) -logging.basicConfig(level=logging.WARNING) -logg = logging.getLogger().getChild(__name__) +#logg = logging.getLogger().getChild(__name__) +logg = logging.getLogger() class TestBase(unittest.TestCase): @@ -45,7 +48,7 @@ class TestBase(unittest.TestCase): SessionBase.poolable = False SessionBase.transactional = False SessionBase.procedural = False - SessionBase.connect(dsn, debug=True) + SessionBase.connect(dsn, debug=bool(os.environ.get('DATABASE_DEBUG'))) # TODO: evaluates to "true" even if string is 0 ac = alembic.config.Config(os.path.join(migrationsdir, 'alembic.ini')) ac.set_main_option('sqlalchemy.url', dsn) @@ -57,7 +60,7 @@ class TestBase(unittest.TestCase): self.session = SessionBase.create_session() self.chain_spec = ChainSpec('evm', 'foo', 42, 'bar') - + def tearDown(self): self.session.commit() @@ -68,13 +71,16 @@ class TestOtxBase(TestBase): def setUp(self): super(TestOtxBase, self).setUp() - self.tx_hash = add_0x(os.urandom(32).hex()) - self.tx = add_0x(os.urandom(128).hex()) + self.tx_hash = os.urandom(32).hex() + self.tx = os.urandom(128).hex() self.nonce = 42 self.alice = add_0x(os.urandom(20).hex()) tx_hash = create(self.chain_spec, self.nonce, self.alice, self.tx_hash, self.tx, session=self.session) self.assertEqual(tx_hash, self.tx_hash) + self.session.commit() + + logg.info('using tx hash {}'.format(self.tx_hash)) class TestTxBase(TestOtxBase): diff --git a/tests/test_otx.py b/tests/test_otx.py index 4961833..53198e0 100644 --- a/tests/test_otx.py +++ b/tests/test_otx.py @@ -8,11 +8,11 @@ from chainlib.chain import ChainSpec # local imports from chainqueue.db.models.otx import Otx -from chainqueue.state import * from chainqueue.db.enum import ( is_alive, is_error_status, ) +from chainqueue.sql.state import * # test imports from tests.base import TestOtxBase @@ -24,7 +24,7 @@ logg = logging.getLogger() class TestOtx(TestOtxBase): def test_ideal_state_sequence(self): - set_ready(self.chain_spec, self.tx_hash) + set_ready(self.chain_spec, self.tx_hash, session=self.session) otx = Otx.load(self.tx_hash, session=self.session) self.assertEqual(otx.status, StatusBits.QUEUED) @@ -32,85 +32,85 @@ class TestOtx(TestOtxBase): self.session.refresh(otx) self.assertEqual(otx.status, StatusBits.RESERVED) - set_sent(self.chain_spec, self.tx_hash) + set_sent(self.chain_spec, self.tx_hash, session=self.session) self.session.refresh(otx) self.assertEqual(otx.status, StatusBits.IN_NETWORK) - set_final(self.chain_spec, self.tx_hash, block=1024) + set_final(self.chain_spec, self.tx_hash, block=1024, session=self.session) self.session.refresh(otx) self.assertFalse(is_alive(otx.status)) self.assertFalse(is_error_status(otx.status)) def test_send_fail_and_retry(self): - set_ready(self.chain_spec, self.tx_hash) + set_ready(self.chain_spec, self.tx_hash, session=self.session) otx = Otx.load(self.tx_hash, session=self.session) self.assertEqual(otx.status, StatusBits.QUEUED) - set_reserved(self.chain_spec, self.tx_hash) + set_reserved(self.chain_spec, self.tx_hash, session=self.session) self.session.refresh(otx) self.assertEqual(otx.status, StatusBits.RESERVED) - set_sent(self.chain_spec, self.tx_hash, fail=True) + set_sent(self.chain_spec, self.tx_hash, fail=True, session=self.session) self.session.refresh(otx) self.assertTrue(is_error_status(otx.status)) - set_ready(self.chain_spec, self.tx_hash) + set_ready(self.chain_spec, self.tx_hash, session=self.session) self.session.refresh(otx) self.assertEqual(otx.status & StatusBits.QUEUED, StatusBits.QUEUED) self.assertTrue(is_error_status(otx.status)) - set_reserved(self.chain_spec, self.tx_hash) + set_reserved(self.chain_spec, self.tx_hash, session=self.session) self.session.refresh(otx) self.assertEqual(otx.status & StatusBits.RESERVED, StatusBits.RESERVED) self.assertTrue(is_error_status(otx.status)) - set_sent(self.chain_spec, self.tx_hash) + set_sent(self.chain_spec, self.tx_hash, session=self.session) self.session.refresh(otx) self.assertEqual(otx.status, StatusBits.IN_NETWORK) self.assertFalse(is_error_status(otx.status)) - set_final(self.chain_spec, self.tx_hash, block=1024) + set_final(self.chain_spec, self.tx_hash, block=1024, session=self.session) self.session.refresh(otx) self.assertFalse(is_alive(otx.status)) self.assertFalse(is_error_status(otx.status)) def test_fubar(self): - set_ready(self.chain_spec, self.tx_hash) + set_ready(self.chain_spec, self.tx_hash, session=self.session) otx = Otx.load(self.tx_hash, session=self.session) self.assertEqual(otx.status, StatusBits.QUEUED) - set_reserved(self.chain_spec, self.tx_hash) + set_reserved(self.chain_spec, self.tx_hash, session=self.session) self.session.refresh(otx) self.assertEqual(otx.status & StatusBits.RESERVED, StatusBits.RESERVED) - set_fubar(self.chain_spec, self.tx_hash) + set_fubar(self.chain_spec, self.tx_hash, session=self.session) self.session.refresh(otx) self.assertTrue(is_error_status(otx.status)) self.assertEqual(otx.status & StatusBits.UNKNOWN_ERROR, StatusBits.UNKNOWN_ERROR) def test_reject(self): - set_ready(self.chain_spec, self.tx_hash) + set_ready(self.chain_spec, self.tx_hash, session=self.session) otx = Otx.load(self.tx_hash, session=self.session) self.assertEqual(otx.status, StatusBits.QUEUED) - set_reserved(self.chain_spec, self.tx_hash) + set_reserved(self.chain_spec, self.tx_hash, session=self.session) self.session.refresh(otx) self.assertEqual(otx.status & StatusBits.RESERVED, StatusBits.RESERVED) - set_rejected(self.chain_spec, self.tx_hash) + set_rejected(self.chain_spec, self.tx_hash, session=self.session) self.session.refresh(otx) self.assertTrue(is_error_status(otx.status)) self.assertEqual(otx.status & StatusBits.NODE_ERROR, StatusBits.NODE_ERROR) def test_final_fail(self): - set_ready(self.chain_spec, self.tx_hash) - set_reserved(self.chain_spec, self.tx_hash) - set_sent(self.chain_spec, self.tx_hash) - set_final(self.chain_spec, self.tx_hash, block=1042, fail=True) + set_ready(self.chain_spec, self.tx_hash, session=self.session) + set_reserved(self.chain_spec, self.tx_hash, session=self.session) + set_sent(self.chain_spec, self.tx_hash, session=self.session) + set_final(self.chain_spec, self.tx_hash, block=1042, fail=True, session=self.session) otx = Otx.load(self.tx_hash, session=self.session) self.assertFalse(is_alive(otx.status)) self.assertTrue(is_error_status(otx.status)) @@ -118,47 +118,47 @@ class TestOtx(TestOtxBase): def test_final_protected(self): - set_ready(self.chain_spec, self.tx_hash) - set_reserved(self.chain_spec, self.tx_hash) - set_sent(self.chain_spec, self.tx_hash) - set_final(self.chain_spec, self.tx_hash, block=1042) + set_ready(self.chain_spec, self.tx_hash, session=self.session) + set_reserved(self.chain_spec, self.tx_hash, session=self.session) + set_sent(self.chain_spec, self.tx_hash, session=self.session) + set_final(self.chain_spec, self.tx_hash, block=1042, session=self.session) otx = Otx.load(self.tx_hash, session=self.session) self.assertEqual(otx.status & StatusBits.FINAL, StatusBits.FINAL) with self.assertRaises(TxStateChangeError): - set_ready(self.chain_spec, self.tx_hash) + set_ready(self.chain_spec, self.tx_hash, session=self.session) with self.assertRaises(TxStateChangeError): - set_fubar(self.chain_spec, self.tx_hash) + set_fubar(self.chain_spec, self.tx_hash, session=self.session) with self.assertRaises(TxStateChangeError): - set_rejected(self.chain_spec, self.tx_hash) + set_rejected(self.chain_spec, self.tx_hash, session=self.session) - set_cancel(self.chain_spec, self.tx_hash) + set_cancel(self.chain_spec, self.tx_hash, session=self.session) self.session.refresh(otx) self.assertEqual(otx.status & StatusBits.OBSOLETE, 0) - set_cancel(self.chain_spec, self.tx_hash, manual=True) + set_cancel(self.chain_spec, self.tx_hash, manual=True, session=self.session) self.session.refresh(otx) self.assertEqual(otx.status & StatusBits.OBSOLETE, 0) with self.assertRaises(TxStateChangeError): - set_reserved(self.chain_spec, self.tx_hash) + set_reserved(self.chain_spec, self.tx_hash, session=self.session) with self.assertRaises(TxStateChangeError): - set_waitforgas(self.chain_spec, self.tx_hash) + set_waitforgas(self.chain_spec, self.tx_hash, session=self.session) with self.assertRaises(TxStateChangeError): - set_manual(self.chain_spec, self.tx_hash) + set_manual(self.chain_spec, self.tx_hash, session=self.session) def test_manual_persist(self): - set_manual(self.chain_spec, self.tx_hash) - set_ready(self.chain_spec, self.tx_hash) - set_reserved(self.chain_spec, self.tx_hash) - set_sent(self.chain_spec, self.tx_hash) - set_final(self.chain_spec, self.tx_hash, block=1042) + set_manual(self.chain_spec, self.tx_hash, session=self.session) + set_ready(self.chain_spec, self.tx_hash, session=self.session) + set_reserved(self.chain_spec, self.tx_hash, session=self.session) + set_sent(self.chain_spec, self.tx_hash, session=self.session) + set_final(self.chain_spec, self.tx_hash, block=1042, session=self.session) otx = Otx.load(self.tx_hash, session=self.session) self.assertEqual(otx.status & StatusBits.MANUAL, StatusBits.MANUAL) diff --git a/tests/test_otx_status_log.py b/tests/test_otx_status_log.py index b1ea201..be01d38 100644 --- a/tests/test_otx_status_log.py +++ b/tests/test_otx_status_log.py @@ -3,7 +3,7 @@ import unittest # local imports from chainqueue.db.models.otx import Otx -from chainqueue.state import * +from chainqueue.sql.state import * # test imports from tests.base import TestOtxBase @@ -19,10 +19,10 @@ class TestOtxState(TestOtxBase): def test_state_log(self): - set_ready(self.chain_spec, self.tx_hash) - set_reserved(self.chain_spec, self.tx_hash) - set_sent(self.chain_spec, self.tx_hash) - set_final(self.chain_spec, self.tx_hash, block=1042) + set_ready(self.chain_spec, self.tx_hash, session=self.session) + set_reserved(self.chain_spec, self.tx_hash, session=self.session) + set_sent(self.chain_spec, self.tx_hash, session=self.session) + set_final(self.chain_spec, self.tx_hash, block=1042, session=self.session) state_log = get_state_log(self.chain_spec, self.tx_hash) self.assertEqual(state_log[0][1], StatusEnum.READYSEND) diff --git a/tests/test_query.py b/tests/test_query.py index 79d266b..c4bb2bf 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -3,15 +3,17 @@ import os import logging import unittest -# local imports -from chainqueue.query import * -from chainqueue.tx import create -from chainqueue.state import set_waitforgas +# external imports from hexathon import ( add_0x, strip_0x, ) +# local imports +from chainqueue.sql.query import * +from chainqueue.sql.tx import create +from chainqueue.sql.state import set_waitforgas + # test imports from tests.base import TestTxBase diff --git a/tests/test_tx_cache.py b/tests/test_tx_cache.py index 8dc7507..e5dbb36 100644 --- a/tests/test_tx_cache.py +++ b/tests/test_tx_cache.py @@ -1,11 +1,14 @@ # standard imports import unittest +# external imports +from hexathon import add_0x + # local imports from chainqueue.db.models.tx import TxCache from chainqueue.error import NotLocalTxError -from chainqueue.state import * -from chainqueue.query import get_tx_cache +from chainqueue.sql.state import * +from chainqueue.sql.query import get_tx_cache # test imports from tests.base import TestTxBase @@ -16,10 +19,10 @@ class TestTxCache(TestTxBase): with self.assertRaises(NotLocalTxError): TxCache.set_final(self.tx_hash, 1024, 13, session=self.session) - set_ready(self.chain_spec, self.tx_hash) - set_reserved(self.chain_spec, self.tx_hash) - set_sent(self.chain_spec, self.tx_hash) - set_final(self.chain_spec, self.tx_hash, block=1024) + set_ready(self.chain_spec, self.tx_hash, session=self.session) + set_reserved(self.chain_spec, self.tx_hash, session=self.session) + set_sent(self.chain_spec, self.tx_hash, session=self.session) + set_final(self.chain_spec, self.tx_hash, block=1024, session=self.session) with self.assertRaises(NotLocalTxError): TxCache.set_final(self.tx_hash, 1023, 13, session=self.session) @@ -34,7 +37,7 @@ class TestTxCache(TestTxBase): def test_get(self): tx_extended_dict = get_tx_cache(self.chain_spec, self.tx_hash) - self.assertEqual(tx_extended_dict['tx_hash'], self.tx_hash) + self.assertEqual(tx_extended_dict['tx_hash'], add_0x(self.tx_hash)) if __name__ == '__main__':