Add nonce list test

This commit is contained in:
nolash 2021-04-02 14:45:05 +02:00
parent 5ea1b15c53
commit fb14961c1b
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
5 changed files with 60 additions and 37 deletions

View File

@ -14,3 +14,10 @@ class TxStateChangeError(ChainQueueException):
"""Raised when an invalid state change of a queued transaction occurs """Raised when an invalid state change of a queued transaction occurs
""" """
pass pass
class CacheIntegrityError(ChainQueueException):
"""Raised when cached data does not match raw transaction data
"""
pass

View File

@ -8,8 +8,12 @@ from sqlalchemy import or_
from sqlalchemy import not_ from sqlalchemy import not_
from sqlalchemy import tuple_ from sqlalchemy import tuple_
from sqlalchemy import func from sqlalchemy import func
from hexathon import add_0x
# local imports # local imports
from chainqueue.db.models.otx import Otx
from chainqueue.db.models.tx import TxCache
from chainqueue.db.models.base import SessionBase
from chainqueue.db.enum import status_str from chainqueue.db.enum import status_str
from chainqueue.db.enum import ( from chainqueue.db.enum import (
StatusEnum, StatusEnum,
@ -17,11 +21,14 @@ from chainqueue.db.enum import (
is_alive, is_alive,
dead, dead,
) )
from chainqueue.error import (
NotLocalTxError,
)
logg = logging.getLogger().getChild(__name__) logg = logging.getLogger().getChild(__name__)
def get_tx_cache(tx_hash): def get_tx_cache(chain_spec, tx_hash):
"""Returns an aggregate dictionary of outgoing transaction data and metadata """Returns an aggregate dictionary of outgoing transaction data and metadata
:param tx_hash: Transaction hash of record to modify :param tx_hash: Transaction hash of record to modify
@ -31,10 +38,8 @@ def get_tx_cache(tx_hash):
:rtype: dict :rtype: dict
""" """
session = SessionBase.create_session() session = SessionBase.create_session()
q = session.query(Otx)
q = q.filter(Otx.tx_hash==tx_hash)
otx = q.first()
otx = Otx.load(tx_hash, session=session)
if otx == None: if otx == None:
session.close() session.close()
raise NotLocalTxError(tx_hash) raise NotLocalTxError(tx_hash)
@ -47,18 +52,19 @@ def get_tx_cache(tx_hash):
session.close() session.close()
# TODO: DRY, get_tx_cache / get_tx
tx = { tx = {
'tx_hash': otx.tx_hash, 'tx_hash': add_0x(otx.tx_hash),
'signed_tx': otx.signed_tx, 'signed_tx': add_0x(otx.signed_tx),
'nonce': otx.nonce, 'nonce': otx.nonce,
'status': status_str(otx.status), 'status': status_str(otx.status),
'status_code': otx.status, 'status_code': otx.status,
'source_token': txc.source_token_address, 'source_token': add_0x(txc.source_token_address),
'destination_token': txc.destination_token_address, 'destination_token': add_0x(txc.destination_token_address),
'block_number': txc.block_number, 'block_number': otx.block,
'tx_index': txc.tx_index, 'tx_index': txc.tx_index,
'sender': txc.sender, 'sender': add_0x(txc.sender),
'recipient': txc.recipient, 'recipient': add_0x(txc.recipient),
'from_value': int(txc.from_value), 'from_value': int(txc.from_value),
'to_value': int(txc.to_value), 'to_value': int(txc.to_value),
'date_created': txc.date_created, 'date_created': txc.date_created,
@ -69,8 +75,7 @@ def get_tx_cache(tx_hash):
return tx return tx
@celery_app.task(base=CriticalSQLAlchemyTask) def get_tx(chain_spec, tx_hash):
def get_tx(tx_hash):
"""Retrieve a transaction queue record by transaction hash """Retrieve a transaction queue record by transaction hash
:param tx_hash: Transaction hash of record to modify :param tx_hash: Transaction hash of record to modify
@ -80,25 +85,23 @@ def get_tx(tx_hash):
:rtype: dict :rtype: dict
""" """
session = SessionBase.create_session() session = SessionBase.create_session()
q = session.query(Otx) otx = Otx.load(tx_hash, session=session)
q = q.filter(Otx.tx_hash==tx_hash) if otx == None:
tx = q.first()
if tx == None:
session.close() session.close()
raise NotLocalTxError('queue does not contain tx hash {}'.format(tx_hash)) raise NotLocalTxError('queue does not contain tx hash {}'.format(tx_hash))
o = { o = {
'otx_id': tx.id, 'otx_id': otx.id,
'nonce': tx.nonce, 'nonce': otx.nonce,
'signed_tx': tx.signed_tx, 'signed_tx': otx.signed_tx,
'status': tx.status, 'status': otx.status,
} }
logg.debug('get tx {}'.format(o)) logg.debug('get tx {}'.format(o))
session.close() session.close()
return o return o
def get_nonce_tx(nonce, sender, chain_spec): def get_nonce_tx_cache(chain_spec, nonce, sender, decoder=None):
"""Retrieve all transactions for address with specified nonce """Retrieve all transactions for address with specified nonce
:param nonce: Nonce :param nonce: Nonce
@ -108,6 +111,8 @@ def get_nonce_tx(nonce, sender, chain_spec):
:returns: Transactions :returns: Transactions
:rtype: dict, with transaction hash as key, signed raw transaction as value :rtype: dict, with transaction hash as key, signed raw transaction as value
""" """
chain_id = chain_spec.chain_id()
session = SessionBase.create_session() session = SessionBase.create_session()
q = session.query(Otx) q = session.query(Otx)
q = q.join(TxCache) q = q.join(TxCache)
@ -116,18 +121,19 @@ def get_nonce_tx(nonce, sender, chain_spec):
txs = {} txs = {}
for r in q.all(): for r in q.all():
tx_signed_bytes = bytes.fromhex(r.signed_tx[2:]) tx_signed_bytes = bytes.fromhex(r.signed_tx)
tx = unpack(tx_signed_bytes, chain_id) if decoder != None:
if sender == None or tx['from'] == sender: tx = unpack(tx_signed_bytes, chain_id)
txs[r.tx_hash] = r.signed_tx if sender != None and tx['from'] != sender:
raise IntegrityError('Cache sender {} does not match sender in tx {} using decoder {}'.format(sender, r.tx_hash, str(decoder)))
txs[r.tx_hash] = r.signed_tx
session.close() session.close()
return txs return txs
def get_paused_tx_cache(chain_spec, status=None, sender=None, session=None, decoder=None):
def get_paused_txs(chain_spec, status=None, sender=None, session=None):
"""Returns not finalized transactions that have been attempted sent without success. """Returns not finalized transactions that have been attempted sent without success.
:param status: If set, will return transactions with this local queue status only :param status: If set, will return transactions with this local queue status only
@ -157,13 +163,19 @@ def get_paused_txs(chain_spec, status=None, sender=None, session=None):
q = q.filter(TxCache.sender==sender) q = q.filter(TxCache.sender==sender)
txs = {} txs = {}
gas = 0
for r in q.all(): for r in q.all():
tx_signed_bytes = bytes.fromhex(r.signed_tx[2:]) tx_signed_bytes = bytes.fromhex(r.signed_tx)
tx = unpack(tx_signed_bytes, chain_id) if decoder != None:
if sender == None or tx['from'] == sender: tx = unpack(tx_signed_bytes, chain_id)
#gas += tx['gas'] * tx['gasPrice'] if sender != None and tx['from'] != sender:
txs[r.tx_hash] = r.signed_tx raise IntegrityError('Cache sender {} does not match sender in tx {} using decoder {}'.format(sender, r.tx_hash, str(decoder)))
gas += tx['gas'] * tx['gasPrice']
#tx = unpack(tx_signed_bytes, chain_id)
#if sender == None or tx['from'] == sender:
txs[r.tx_hash] = r.signed_tx
SessionBase.release_session(session) SessionBase.release_session(session)

View File

@ -101,9 +101,6 @@ def set_final(tx_hash, block=None, fail=False):
q = q.filter(Otx.tx_hash==strip_0x(tx_hash)) q = q.filter(Otx.tx_hash==strip_0x(tx_hash))
o = q.first() o = q.first()
if o != None:
session.close() session.close()
return tx_hash return tx_hash

View File

@ -20,6 +20,7 @@ from chainqueue.tx import create
script_dir = os.path.realpath(os.path.dirname(__file__)) script_dir = os.path.realpath(os.path.dirname(__file__))
logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger().getChild(__name__) logg = logging.getLogger().getChild(__name__)
@ -44,7 +45,7 @@ class TestBase(unittest.TestCase):
SessionBase.poolable = False SessionBase.poolable = False
SessionBase.transactional = False SessionBase.transactional = False
SessionBase.procedural = False SessionBase.procedural = False
SessionBase.connect(dsn, debug=False) SessionBase.connect(dsn, debug=True)
ac = alembic.config.Config(os.path.join(migrationsdir, 'alembic.ini')) ac = alembic.config.Config(os.path.join(migrationsdir, 'alembic.ini'))
ac.set_main_option('sqlalchemy.url', dsn) ac.set_main_option('sqlalchemy.url', dsn)

View File

@ -5,6 +5,7 @@ import unittest
from chainqueue.db.models.tx import TxCache from chainqueue.db.models.tx import TxCache
from chainqueue.error import NotLocalTxError from chainqueue.error import NotLocalTxError
from chainqueue.state import * from chainqueue.state import *
from chainqueue.query import get_tx_cache
# test imports # test imports
from tests.base import TestTxBase from tests.base import TestTxBase
@ -31,5 +32,10 @@ class TestTxCache(TestTxBase):
self.assertEqual(txc.tx_index, 13) self.assertEqual(txc.tx_index, 13)
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)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()