transactionjob updates and fixes

This commit is contained in:
Tim Olson
2023-10-20 01:08:59 -04:00
parent 558b94bfb2
commit 2fd378a936
7 changed files with 32 additions and 28 deletions

View File

@@ -58,11 +58,10 @@ def upgrade() -> None:
op.create_index(op.f('ix_transactionjob_completed'), 'transactionjob', ['completed'], unique=False) op.create_index(op.f('ix_transactionjob_completed'), 'transactionjob', ['completed'], unique=False)
op.create_index(op.f('ix_transactionjob_height'), 'transactionjob', ['height'], unique=False) op.create_index(op.f('ix_transactionjob_height'), 'transactionjob', ['height'], unique=False)
op.create_table('tx', op.create_table('tx',
sa.Column('id', sa.UUID(), nullable=False), sa.Column('id', postgresql.BYTEA(), nullable=False),
sa.Column('tx', postgresql.JSONB(astext_type=sa.Text()), nullable=False), sa.Column('job_id', sa.UUID(), nullable=False),
sa.Column('hash', postgresql.BYTEA(), nullable=False), sa.Column('receipt', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
sa.Column('receipt', postgresql.JSONB(astext_type=sa.Text()), nullable=False), sa.ForeignKeyConstraint(['job_id'], ['transactionjob.id'], ),
sa.ForeignKeyConstraint(['id'], ['transactionjob.id'], ),
sa.PrimaryKeyConstraint('id') sa.PrimaryKeyConstraint('id')
) )

View File

@@ -5,6 +5,7 @@ from uuid import uuid4
from dexorder import db, current_w3 from dexorder import db, current_w3
from dexorder.base.chain import current_chain from dexorder.base.chain import current_chain
from dexorder.base.order import TransactionRequest from dexorder.base.order import TransactionRequest
from dexorder.contract import Transaction
from dexorder.database.model.block import current_block from dexorder.database.model.block import current_block
from dexorder.database.model.transaction import TransactionJob, Transaction as DbTransaction from dexorder.database.model.transaction import TransactionJob, Transaction as DbTransaction
@@ -49,11 +50,12 @@ async def create_transaction(job: TransactionJob):
handler = TransactionHandler.of(job.request.type) handler = TransactionHandler.of(job.request.type)
except KeyError: except KeyError:
# todo remove bad request? # todo remove bad request?
log.warning(f'ignoring transaction request with bad type "{job.request.type}"') log.warning(f'ignoring transaction request with bad type "{job.request.type}": {",".join(TransactionHandler.instances.keys())}')
else: else:
tx = await handler.send_transaction(job.id, job.request) # noinspection PyTypeChecker
job.tx = dtx = DbTransaction(tx=tx, hash=tx['hash'], receipt=None) tx: Transaction = await handler.send_transaction(job.id, job.request)
db.session.add(dtx) dbtx = DbTransaction(id=tx.id_bytes, job=job, receipt=None)
db.session.add(dbtx)
log.info(f'servicing transaction request {job.request.__class__.__name__} {job.id} with tx {tx}') log.info(f'servicing transaction request {job.request.__class__.__name__} {job.id} with tx {tx}')
@@ -61,11 +63,10 @@ async def check_receipt(job: TransactionJob):
if not job.tx: if not job.tx:
return return
w3 = current_w3.get() w3 = current_w3.get()
receipt = await w3.eth.get_transaction_receipt(job.tx.hash) receipt = await w3.eth.get_transaction_receipt(job.tx.id)
if receipt is not None: if receipt is not None:
job.tx.receipt = receipt job.tx.receipt = receipt
job.completed = True job.completed = True
db.session.add(job.tx)
try: try:
handler = TransactionHandler.of(job.request.type) handler = TransactionHandler.of(job.request.type)
except KeyError: except KeyError:

View File

@@ -1,4 +1,5 @@
import logging import logging
from typing import Optional
from sqlalchemy import ForeignKey, UniqueConstraint from sqlalchemy import ForeignKey, UniqueConstraint
from sqlalchemy.orm import mapped_column, Mapped, relationship from sqlalchemy.orm import mapped_column, Mapped, relationship
@@ -17,13 +18,12 @@ class TransactionJob (Base):
height: Mapped[int] = mapped_column(index=True) # to be used for data rolloff and/or by Timescale height: Mapped[int] = mapped_column(index=True) # to be used for data rolloff and/or by Timescale
completed: Mapped[bool] = mapped_column(default=False, index=True) completed: Mapped[bool] = mapped_column(default=False, index=True)
request: Mapped[TransactionRequestDict] = mapped_column(DataclassDict(deserialize_transaction_request)) request: Mapped[TransactionRequestDict] = mapped_column(DataclassDict(deserialize_transaction_request))
tx: Mapped["Transaction"] = relationship(back_populates="job", uselist=False) tx: Mapped[list["Transaction"]] = relationship(back_populates='job', uselist=False)
class Transaction (Base): class Transaction (Base):
__tablename__ = 'tx' # avoid the keyword "transaction" __tablename__ = 'tx' # avoid the keyword "transaction"
id: Mapped[UUID] = mapped_column(ForeignKey("transactionjob.id"), primary_key=True) id: Mapped[Bytes] = mapped_column(primary_key=True)
job: Mapped[TransactionJob] = relationship(back_populates="tx", single_parent=True) job_id: Mapped[UUID] = mapped_column(ForeignKey("transactionjob.id"))
tx: Mapped[Dict] job: Mapped[TransactionJob] = relationship(back_populates='tx', single_parent=True)
hash: Mapped[Bytes] receipt: Mapped[Optional[Dict]]
receipt: Mapped[Dict]

View File

@@ -5,7 +5,7 @@ from web3.types import EventData
from dexorder import current_pub, db from dexorder import current_pub, db
from dexorder.base.chain import current_chain from dexorder.base.chain import current_chain
from dexorder.base.order import TrancheExecutionRequest, TrancheKey, ExecutionRequest, new_tranche_execution_request from dexorder.base.order import TrancheExecutionRequest, TrancheKey, ExecutionRequest, new_tranche_execution_request, OrderKey
from dexorder.blockchain.transaction import handle_transactions, submit_transaction from dexorder.blockchain.transaction import handle_transactions, submit_transaction
from dexorder.blockchain.uniswap import uniswap_price from dexorder.blockchain.uniswap import uniswap_price
from dexorder.contract.dexorder import get_factory_contract, vault_address, VaultContract, get_dexorder_contract from dexorder.contract.dexorder import get_factory_contract, vault_address, VaultContract, get_dexorder_contract
@@ -14,14 +14,14 @@ from dexorder.data import pool_prices, vault_owners, vault_tokens, underfunded_v
from dexorder.database.model.block import current_block from dexorder.database.model.block import current_block
from dexorder.database.model.transaction import TransactionJob from dexorder.database.model.transaction import TransactionJob
from dexorder.order.orderlib import SwapOrderState, SwapOrderStatus from dexorder.order.orderlib import SwapOrderState, SwapOrderStatus
from dexorder.order.orderstate import Order, active_orders from dexorder.order.orderstate import Order
from dexorder.order.triggers import OrderTriggers, close_order_and_disable_triggers, price_triggers, time_triggers, \ from dexorder.order.triggers import OrderTriggers, close_order_and_disable_triggers, price_triggers, time_triggers, \
unconstrained_price_triggers, execution_requests, inflight_execution_requests unconstrained_price_triggers, execution_requests, inflight_execution_requests
from dexorder.util import hexbytes from dexorder.util import hexbytes
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
LOG_ALL_EVENTS = False # for debug LOG_ALL_EVENTS = True # for debug
async def ensure_pool_price(pool_addr): async def ensure_pool_price(pool_addr):
@@ -30,7 +30,7 @@ async def ensure_pool_price(pool_addr):
pool_prices[pool_addr] = await UniswapV3Pool(pool_addr).price() pool_prices[pool_addr] = await UniswapV3Pool(pool_addr).price()
def dump_log(eventlog): def dump_log(eventlog):
log.debug(f'eventlog {eventlog}') log.debug(f'\t{eventlog}')
def setup_logevent_triggers(runner): def setup_logevent_triggers(runner):
runner.events.clear() runner.events.clear()
@@ -40,6 +40,7 @@ def setup_logevent_triggers(runner):
# before any order creations # before any order creations
if LOG_ALL_EVENTS: if LOG_ALL_EVENTS:
log.debug('all events:')
runner.add_event_trigger(dump_log, None, {}) runner.add_event_trigger(dump_log, None, {})
factory = get_factory_contract() factory = get_factory_contract()
@@ -82,7 +83,6 @@ async def handle_order_placed(event: EventData):
log.warning(f'block {current_block.get()} order from unknown vault {addr}') # todo insert (short) block hash into all logs log.warning(f'block {current_block.get()} order from unknown vault {addr}') # todo insert (short) block hash into all logs
# return todo discard rogues # return todo discard rogues
vault = VaultContract(addr) vault = VaultContract(addr)
log.debug(await vault.orderList())
for index in range(start_index, start_index+num_orders): for index in range(start_index, start_index+num_orders):
obj = await vault.swapOrderStatus(index) obj = await vault.swapOrderStatus(index)
log.debug(f'raw order status {obj}') log.debug(f'raw order status {obj}')
@@ -117,7 +117,7 @@ def handle_transfer(transfer: EventData):
if to_address in underfunded_vaults: if to_address in underfunded_vaults:
# todo possibly funded now # todo possibly funded now
pass pass
if from_address in active_orders: if from_address in Order.open_keys:
# todo possibly underfunded now # todo possibly underfunded now
pass pass
@@ -159,12 +159,12 @@ def handle_vault_created(created: EventData):
def handle_dexorderexecutions(event: EventData): def handle_dexorderexecutions(event: EventData):
log.debug(f'executions {event}') log.debug(f'executions {event}')
exe_id = UUID(hexbytes(event['args']['id'])) exe_id = UUID(bytes=event['args']['id'])
errors = event['args']['errors'] errors = event['args']['errors']
job = db.session.get(TransactionJob, exe_id) job = db.session.get(TransactionJob, exe_id)
req: TrancheExecutionRequest = job.request req: TrancheExecutionRequest = job.request
tk = TrancheKey( req.vault, req.order_index, req.tranche_index ) tk = TrancheKey( req.vault, req.order_index, req.tranche_index )
order = active_orders[tk] order = Order.of(req.vault, req.order_index)
if job is None: if job is None:
log.warning(f'Job {exe_id} not found!') log.warning(f'Job {exe_id} not found!')
return return
@@ -179,8 +179,9 @@ def handle_dexorderexecutions(event: EventData):
pass # execution success pass # execution success
elif error == 'IIA': elif error == 'IIA':
# insufficient input amount: suspend execution until new funds are sent # insufficient input amount: suspend execution until new funds are sent
# todo replace with vault balance checks
token = order.order.tokenIn token = order.order.tokenIn
underfunded_vaults[req.vault] = underfunded_vaults.get(req.vault, []) + [token] # underfunded_vaults[req.vault] = underfunded_vaults.get(req.vault, []) + [token]
log.debug(f'insufficient funds {req.vault} {token} ') log.debug(f'insufficient funds {req.vault} {token} ')
else: else:
log.error(f'Unhandled execution error for transaction request {req} ERROR: "{error}"') log.error(f'Unhandled execution error for transaction request {req} ERROR: "{error}"')

View File

@@ -1,3 +1,4 @@
from .executionhandler import TrancheExecutionHandler # do not remove. ensures the handler is registered.
def order_key(vault:str, ): def order_key(vault:str, ):
return f'{vault}' return f'{vault}'

View File

@@ -1,4 +1,5 @@
import logging import logging
from uuid import UUID
from dexorder.base.order import TrancheExecutionRequest from dexorder.base.order import TrancheExecutionRequest
from dexorder.blockchain.transaction import TransactionHandler from dexorder.blockchain.transaction import TransactionHandler
@@ -11,8 +12,8 @@ class TrancheExecutionHandler (TransactionHandler):
def __init__(self): def __init__(self):
super().__init__('te') super().__init__('te')
async def send_transaction(self, job_id: int, ter: TrancheExecutionRequest) -> dict: async def send_transaction(self, job_id: UUID, ter: TrancheExecutionRequest) -> dict:
return await get_dexorder_contract().transact.execute(job_id, (ter.vault, ter.order_index, ter.tranche_index, ter.price_proof)) return await get_dexorder_contract().transact.execute(job_id.bytes, (ter.vault, ter.order_index, ter.tranche_index, ter.price_proof))
async def complete_transaction(self, job: TransactionJob) -> None: async def complete_transaction(self, job: TransactionJob) -> None:
# anything to do? # anything to do?

View File

@@ -77,6 +77,7 @@ class Order:
self.amount = self.status.order.amount self.amount = self.status.order.amount
self.amount_is_input = self.status.order.amountIsInput self.amount_is_input = self.status.order.amountIsInput
self.tranche_amounts = [t.fraction_of(self.amount) for t in self.order.tranches] self.tranche_amounts = [t.fraction_of(self.amount) for t in self.order.tranches]
Order.instances[self.key] = self
@property @property
def state(self): def state(self):