2021-04-02 11:51:00 +02:00
|
|
|
|
# standard imports
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
# external imports
|
|
|
|
|
from hexathon import strip_0x
|
|
|
|
|
|
|
|
|
|
# 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 (
|
|
|
|
|
StatusEnum,
|
|
|
|
|
StatusBits,
|
2021-04-02 14:02:22 +02:00
|
|
|
|
is_nascent,
|
2021-04-02 11:51:00 +02:00
|
|
|
|
)
|
|
|
|
|
from chainqueue.db.models.otx import OtxStateLog
|
|
|
|
|
from chainqueue.error import (
|
|
|
|
|
NotLocalTxError,
|
|
|
|
|
TxStateChangeError,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
logg = logging.getLogger().getChild(__name__)
|
|
|
|
|
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
def set_sent(chain_spec, tx_hash, fail=False, session=None):
|
2021-04-02 11:51:00 +02:00
|
|
|
|
"""Used to set the status after a send attempt
|
|
|
|
|
|
|
|
|
|
:param tx_hash: Transaction hash of record to modify
|
|
|
|
|
:type tx_hash: str, 0x-hex
|
|
|
|
|
:param fail: if True, will set a SENDFAIL status, otherwise a SENT status. (Default: False)
|
|
|
|
|
:type fail: boolean
|
|
|
|
|
:raises NotLocalTxError: If transaction not found in queue.
|
|
|
|
|
:returns: True if tx is known, False otherwise
|
|
|
|
|
:rtype: boolean
|
|
|
|
|
"""
|
2021-04-03 00:17:05 +02:00
|
|
|
|
session = SessionBase.bind_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
o = Otx.load(tx_hash, session=session)
|
|
|
|
|
if o == None:
|
|
|
|
|
logg.warning('not local tx, skipping {}'.format(tx_hash))
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
if fail:
|
|
|
|
|
o.sendfail(session=session)
|
|
|
|
|
else:
|
|
|
|
|
o.sent(session=session)
|
|
|
|
|
except TxStateChangeError as e:
|
|
|
|
|
logg.exception('set sent fail: {}'.format(e))
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise(e)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logg.exception('set sent UNEXPECED fail: {}'.format(e))
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise(e)
|
|
|
|
|
|
|
|
|
|
session.commit()
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return tx_hash
|
|
|
|
|
|
|
|
|
|
|
2021-04-06 10:33:23 +02:00
|
|
|
|
def set_final(chain_spec, tx_hash, block=None, tx_index=None, fail=False, session=None):
|
2021-04-02 11:51:00 +02:00
|
|
|
|
"""Used to set the status of an incoming transaction result.
|
|
|
|
|
|
|
|
|
|
:param tx_hash: Transaction hash of record to modify
|
|
|
|
|
:type tx_hash: str, 0x-hex
|
|
|
|
|
:param block: Block number if final status represents a confirmation on the network
|
|
|
|
|
:type block: number
|
|
|
|
|
:param fail: if True, will set a SUCCESS status, otherwise a REVERTED status. (Default: False)
|
|
|
|
|
:type fail: boolean
|
|
|
|
|
:raises NotLocalTxError: If transaction not found in queue.
|
|
|
|
|
"""
|
2021-04-03 00:17:05 +02:00
|
|
|
|
session = SessionBase.bind_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
o = Otx.load(tx_hash, session=session)
|
|
|
|
|
|
|
|
|
|
if o == None:
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise NotLocalTxError('queue does not contain tx hash {}'.format(tx_hash))
|
|
|
|
|
|
|
|
|
|
session.flush()
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
if fail:
|
|
|
|
|
o.minefail(block, session=session)
|
|
|
|
|
else:
|
|
|
|
|
o.success(block, session=session)
|
|
|
|
|
except TxStateChangeError as e:
|
|
|
|
|
logg.exception('set final fail: {}'.format(e))
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise(e)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logg.exception('set final UNEXPECTED fail: {}'.format(e))
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise(e)
|
|
|
|
|
|
2021-04-06 10:33:23 +02:00
|
|
|
|
if block != None:
|
2021-05-28 11:13:01 +02:00
|
|
|
|
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))
|
2021-04-06 10:33:23 +02:00
|
|
|
|
|
|
|
|
|
session.commit()
|
2021-04-02 14:02:22 +02:00
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return tx_hash
|
|
|
|
|
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
def set_cancel(chain_spec, tx_hash, manual=False, session=None):
|
2021-04-02 11:51:00 +02:00
|
|
|
|
"""Used to set the status when a transaction is cancelled.
|
|
|
|
|
|
|
|
|
|
Will set the state to CANCELLED or OVERRIDDEN
|
|
|
|
|
|
|
|
|
|
:param tx_hash: Transaction hash of record to modify
|
|
|
|
|
:type tx_hash: str, 0x-hex
|
|
|
|
|
:param manual: If set, status will be OVERRIDDEN. Otherwise CANCELLED.
|
|
|
|
|
:type manual: boolean
|
|
|
|
|
:raises NotLocalTxError: If transaction not found in queue.
|
|
|
|
|
"""
|
2021-04-03 00:17:05 +02:00
|
|
|
|
session = SessionBase.bind_session(session)
|
2021-04-02 13:04:31 +02:00
|
|
|
|
o = Otx.load(tx_hash, session=session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
if o == None:
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise NotLocalTxError('queue does not contain tx hash {}'.format(tx_hash))
|
|
|
|
|
|
|
|
|
|
session.flush()
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
if manual:
|
|
|
|
|
o.override(session=session)
|
|
|
|
|
else:
|
|
|
|
|
o.cancel(session=session)
|
|
|
|
|
session.commit()
|
|
|
|
|
except TxStateChangeError as e:
|
|
|
|
|
logg.exception('set cancel fail: {}'.format(e))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logg.exception('set cancel UNEXPECTED fail: {}'.format(e))
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return tx_hash
|
|
|
|
|
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
def set_rejected(chain_spec, tx_hash, session=None):
|
2021-04-02 11:51:00 +02:00
|
|
|
|
"""Used to set the status when the node rejects sending a transaction to network
|
|
|
|
|
|
|
|
|
|
Will set the state to REJECTED
|
|
|
|
|
|
|
|
|
|
:param tx_hash: Transaction hash of record to modify
|
|
|
|
|
:type tx_hash: str, 0x-hex
|
|
|
|
|
:raises NotLocalTxError: If transaction not found in queue.
|
|
|
|
|
"""
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
session = SessionBase.bind_session(session)
|
2021-04-02 13:04:31 +02:00
|
|
|
|
o = Otx.load(tx_hash, session=session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
if o == None:
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise NotLocalTxError('queue does not contain tx hash {}'.format(tx_hash))
|
|
|
|
|
|
|
|
|
|
session.flush()
|
|
|
|
|
|
|
|
|
|
o.reject(session=session)
|
|
|
|
|
session.commit()
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return tx_hash
|
|
|
|
|
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
def set_fubar(chain_spec, tx_hash, session=None):
|
2021-04-02 11:51:00 +02:00
|
|
|
|
"""Used to set the status when an unexpected error occurs.
|
|
|
|
|
|
|
|
|
|
Will set the state to FUBAR
|
|
|
|
|
|
|
|
|
|
:param tx_hash: Transaction hash of record to modify
|
|
|
|
|
:type tx_hash: str, 0x-hex
|
|
|
|
|
:raises NotLocalTxError: If transaction not found in queue.
|
|
|
|
|
"""
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
session = SessionBase.bind_session(session)
|
2021-04-02 13:04:31 +02:00
|
|
|
|
o = Otx.load(tx_hash, session=session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
if o == None:
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise NotLocalTxError('queue does not contain tx hash {}'.format(tx_hash))
|
|
|
|
|
|
|
|
|
|
session.flush()
|
|
|
|
|
|
|
|
|
|
o.fubar(session=session)
|
|
|
|
|
session.commit()
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return tx_hash
|
|
|
|
|
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
def set_manual(chain_spec, tx_hash, session=None):
|
2021-04-02 11:51:00 +02:00
|
|
|
|
"""Used to set the status when queue is manually changed
|
|
|
|
|
|
|
|
|
|
Will set the state to MANUAL
|
|
|
|
|
|
|
|
|
|
:param tx_hash: Transaction hash of record to modify
|
|
|
|
|
:type tx_hash: str, 0x-hex
|
|
|
|
|
:raises NotLocalTxError: If transaction not found in queue.
|
|
|
|
|
"""
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
session = SessionBase.bind_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
o = Otx.load(tx_hash, session=session)
|
|
|
|
|
if o == None:
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise NotLocalTxError('queue does not contain tx hash {}'.format(tx_hash))
|
|
|
|
|
|
|
|
|
|
session.flush()
|
|
|
|
|
|
|
|
|
|
o.manual(session=session)
|
|
|
|
|
session.commit()
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return tx_hash
|
|
|
|
|
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
def set_ready(chain_spec, tx_hash, session=None):
|
2021-04-02 11:51:00 +02:00
|
|
|
|
"""Used to mark a transaction as ready to be sent to network
|
|
|
|
|
|
|
|
|
|
:param tx_hash: Transaction hash of record to modify
|
|
|
|
|
:type tx_hash: str, 0x-hex
|
|
|
|
|
:raises NotLocalTxError: If transaction not found in queue.
|
|
|
|
|
"""
|
2021-04-03 00:17:05 +02:00
|
|
|
|
session = SessionBase.bind_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
o = Otx.load(tx_hash, session=session)
|
|
|
|
|
if o == None:
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise NotLocalTxError('queue does not contain tx hash {}'.format(tx_hash))
|
|
|
|
|
session.flush()
|
|
|
|
|
|
2021-04-02 14:02:22 +02:00
|
|
|
|
if o.status & StatusBits.GAS_ISSUES or is_nascent(o.status):
|
2021-04-02 11:51:00 +02:00
|
|
|
|
o.readysend(session=session)
|
|
|
|
|
else:
|
|
|
|
|
o.retry(session=session)
|
|
|
|
|
|
|
|
|
|
session.commit()
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return tx_hash
|
|
|
|
|
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
def set_reserved(chain_spec, tx_hash, session=None):
|
|
|
|
|
session = SessionBase.bind_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
o = Otx.load(tx_hash, session=session)
|
|
|
|
|
if o == None:
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise NotLocalTxError('queue does not contain tx hash {}'.format(tx_hash))
|
|
|
|
|
|
|
|
|
|
session.flush()
|
|
|
|
|
|
|
|
|
|
o.reserve(session=session)
|
|
|
|
|
session.commit()
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return tx_hash
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
def set_waitforgas(chain_spec, tx_hash, session=None):
|
2021-04-02 11:51:00 +02:00
|
|
|
|
"""Used to set the status when a transaction must be deferred due to gas refill
|
|
|
|
|
|
|
|
|
|
Will set the state to WAITFORGAS
|
|
|
|
|
|
|
|
|
|
:param tx_hash: Transaction hash of record to modify
|
|
|
|
|
:type tx_hash: str, 0x-hex
|
|
|
|
|
:raises NotLocalTxError: If transaction not found in queue.
|
|
|
|
|
"""
|
2021-04-03 00:17:05 +02:00
|
|
|
|
session = SessionBase.bind_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
o = Otx.load(tx_hash, session=session)
|
|
|
|
|
if o == None:
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
raise NotLocalTxError('queue does not contain tx hash {}'.format(tx_hash))
|
|
|
|
|
|
|
|
|
|
session.flush()
|
|
|
|
|
|
|
|
|
|
o.waitforgas(session=session)
|
|
|
|
|
session.commit()
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return tx_hash
|
|
|
|
|
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
def get_state_log(chain_spec, tx_hash, session=None):
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
logs = []
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
session = SessionBase.bind_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
q = session.query(OtxStateLog)
|
|
|
|
|
q = q.join(Otx)
|
2021-04-02 14:02:22 +02:00
|
|
|
|
q = q.filter(Otx.tx_hash==strip_0x(tx_hash))
|
2021-04-02 11:51:00 +02:00
|
|
|
|
q = q.order_by(OtxStateLog.date.asc())
|
|
|
|
|
for l in q.all():
|
|
|
|
|
logs.append((l.date, l.status,))
|
|
|
|
|
|
2021-04-03 00:17:05 +02:00
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return logs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-04-05 12:59:45 +02:00
|
|
|
|
def obsolete_by_cache(chain_spec, tx_hash, final, session=None):
|
|
|
|
|
session = SessionBase.bind_session(session)
|
|
|
|
|
|
2021-04-02 11:51:00 +02:00
|
|
|
|
q = session.query(
|
|
|
|
|
Otx.nonce.label('nonce'),
|
|
|
|
|
TxCache.sender.label('sender'),
|
|
|
|
|
Otx.id.label('otxid'),
|
|
|
|
|
)
|
|
|
|
|
q = q.join(TxCache)
|
|
|
|
|
q = q.filter(Otx.tx_hash==strip_0x(tx_hash))
|
|
|
|
|
o = q.first()
|
|
|
|
|
|
|
|
|
|
nonce = o.nonce
|
|
|
|
|
sender = o.sender
|
|
|
|
|
otxid = o.otxid
|
|
|
|
|
|
|
|
|
|
q = session.query(Otx)
|
|
|
|
|
q = q.join(TxCache)
|
|
|
|
|
q = q.filter(Otx.nonce==nonce)
|
|
|
|
|
q = q.filter(TxCache.sender==sender)
|
|
|
|
|
q = q.filter(Otx.tx_hash!=strip_0x(tx_hash))
|
|
|
|
|
|
|
|
|
|
for otwo in q.all():
|
|
|
|
|
try:
|
2021-04-05 12:59:45 +02:00
|
|
|
|
otwo.cancel(final, session=session)
|
|
|
|
|
logg.debug('cancel {} final {}'.format(tx_hash, final))
|
2021-04-02 11:51:00 +02:00
|
|
|
|
except TxStateChangeError as e:
|
|
|
|
|
logg.exception('cancel non-final fail: {}'.format(e))
|
|
|
|
|
session.close()
|
|
|
|
|
raise(e)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logg.exception('cancel non-final UNEXPECTED fail: {}'.format(e))
|
|
|
|
|
session.close()
|
|
|
|
|
raise(e)
|
|
|
|
|
session.commit()
|
2021-04-05 12:59:45 +02:00
|
|
|
|
|
|
|
|
|
SessionBase.release_session(session)
|
2021-04-02 11:51:00 +02:00
|
|
|
|
|
|
|
|
|
return tx_hash
|