2021-02-01 18:12:51 +01:00
# standard imports
import logging
2021-03-29 15:27:53 +02:00
# external imports
2021-02-01 18:12:51 +01:00
import celery
2021-03-29 15:27:53 +02:00
from chainlib . chain import ChainSpec
2021-05-27 19:21:30 +02:00
from chainlib . connection import RPCConnection
from chainlib . eth . tx import (
unpack ,
TxFactory ,
)
from chainlib . eth . gas import OverrideGasOracle
2021-04-04 14:40:59 +02:00
from chainqueue . query import get_tx
from chainqueue . state import set_cancel
from chainqueue . db . models . otx import Otx
from chainqueue . db . models . tx import TxCache
2021-05-27 19:21:30 +02:00
from hexathon import strip_0x
from potaahto . symbols import snake_and_camel
2021-02-01 18:12:51 +01:00
# local imports
from cic_eth . db . models . base import SessionBase
from cic_eth . db . models . nonce import Nonce
2021-03-29 15:27:53 +02:00
from cic_eth . admin . ctrl import (
lock_send ,
unlock_send ,
lock_queue ,
unlock_queue ,
)
2021-04-04 14:40:59 +02:00
from cic_eth . queue . tx import queue_create
from cic_eth . eth . gas import create_check_gas_task
2021-02-01 18:12:51 +01:00
celery_app = celery . current_app
logg = logging . getLogger ( )
@celery_app.task ( bind = True )
def shift_nonce ( self , chain_str , tx_hash_orig_hex , delta = 1 ) :
""" Shift all transactions with nonces higher than the offset by the provided position delta.
Transactions who are replaced by transactions that move nonces will be marked as OVERRIDDEN .
: param chainstr : Chain specification string representation
: type chainstr : str
: param tx_hash_orig_hex : Transaction hash to resolve to sender and nonce to use as shift offset
: type tx_hash_orig_hex : str , 0 x - hex
: param delta : Amount
"""
2021-05-27 19:21:30 +02:00
chain_spec = ChainSpec . from_chain_str ( chain_str )
rpc = RPCConnection . connect ( chain_spec , ' default ' )
rpc_signer = RPCConnection . connect ( chain_spec , ' signer ' )
2021-02-01 18:12:51 +01:00
queue = None
try :
queue = self . request . delivery_info . get ( ' routing_key ' )
except AttributeError :
pass
2021-05-27 19:21:30 +02:00
session = SessionBase . create_session ( )
tx_brief = get_tx ( chain_spec , tx_hash_orig_hex , session = session )
tx_raw = bytes . fromhex ( strip_0x ( tx_brief [ ' signed_tx ' ] ) )
2021-04-04 14:40:59 +02:00
tx = unpack ( tx_raw , chain_spec )
2021-02-01 18:12:51 +01:00
nonce = tx_brief [ ' nonce ' ]
address = tx [ ' from ' ]
logg . debug ( ' shifting nonce {} position(s) for address {} , offset {} ' . format ( delta , address , nonce ) )
2021-05-27 19:21:30 +02:00
lock_queue ( None , chain_spec . asdict ( ) , address = address )
lock_send ( None , chain_spec . asdict ( ) , address = address )
2021-02-01 18:12:51 +01:00
q = session . query ( Otx )
q = q . join ( TxCache )
q = q . filter ( TxCache . sender == address )
q = q . filter ( Otx . nonce > = nonce + delta )
q = q . order_by ( Otx . nonce . asc ( ) )
otxs = q . all ( )
tx_hashes = [ ]
txs = [ ]
for otx in otxs :
2021-04-04 14:40:59 +02:00
tx_raw = bytes . fromhex ( strip_0x ( otx . signed_tx ) )
tx_new = unpack ( tx_raw , chain_spec )
2021-05-27 19:21:30 +02:00
tx_new = snake_and_camel ( tx_new )
2021-02-01 18:12:51 +01:00
tx_previous_hash_hex = tx_new [ ' hash ' ]
tx_previous_nonce = tx_new [ ' nonce ' ]
del ( tx_new [ ' hash ' ] )
del ( tx_new [ ' hash_unsigned ' ] )
2021-05-27 19:21:30 +02:00
tx_new [ ' gas_price ' ] + = 1
tx_new [ ' gasPrice ' ] = tx_new [ ' gas_price ' ]
2021-02-01 18:12:51 +01:00
tx_new [ ' nonce ' ] - = delta
2021-05-27 19:21:30 +02:00
logg . debug ( ' tx_nex {} ' . format ( tx_new ) )
gas_oracle = OverrideGasOracle ( limit = tx_new [ ' gas ' ] , price = tx_new [ ' gas_price ' ] + 1 ) # TODO: it should be possible to merely set this price here and if missing in the existing struct then fill it in (chainlib.eth.tx)
c = TxFactory ( chain_spec , signer = rpc_signer , gas_oracle = gas_oracle )
#(tx_hash_hex, tx_signed_raw_hex) = sign_tx(tx_new, chain_str)
( tx_hash_hex , tx_signed_raw_hex ) = c . build_raw ( tx_new )
2021-02-01 18:12:51 +01:00
logg . debug ( ' tx {} -> {} nonce {} -> {} ' . format ( tx_previous_hash_hex , tx_hash_hex , tx_previous_nonce , tx_new [ ' nonce ' ] ) )
2021-05-27 19:21:30 +02:00
# otx = Otx(
# nonce=tx_new['nonce'],
# address=tx_new['from'],
# tx_hash=tx_hash_hex,
# signed_tx=tx_signed_raw_hex,
# )
2021-02-01 18:12:51 +01:00
otx = Otx (
2021-05-27 19:21:30 +02:00
tx_new [ ' nonce ' ] ,
tx_hash_hex ,
tx_signed_raw_hex ,
)
2021-02-01 18:12:51 +01:00
session . add ( otx )
session . commit ( )
# TODO: cancel all first, then replace. Otherwise we risk two non-locked states for two different nonces.
2021-05-27 19:21:30 +02:00
set_cancel ( chain_spec , tx_previous_hash_hex , manual = True , session = session )
2021-02-01 18:12:51 +01:00
2021-05-27 19:21:30 +02:00
TxCache . clone ( tx_previous_hash_hex , tx_hash_hex , session = session )
2021-02-01 18:12:51 +01:00
tx_hashes . append ( tx_hash_hex )
txs . append ( tx_signed_raw_hex )
session . close ( )
2021-05-27 19:21:30 +02:00
s = create_check_gas_task (
2021-02-01 18:12:51 +01:00
txs ,
2021-05-27 19:21:30 +02:00
chain_spec ,
2021-02-01 18:12:51 +01:00
tx_new [ ' from ' ] ,
2021-05-27 19:21:30 +02:00
gas = tx_new [ ' gas ' ] ,
tx_hashes_hex = tx_hashes ,
queue = queue ,
2021-02-01 18:12:51 +01:00
)
s_unlock_send = celery . signature (
' cic_eth.admin.ctrl.unlock_send ' ,
[
2021-05-27 19:21:30 +02:00
chain_spec . asdict ( ) ,
2021-02-01 18:12:51 +01:00
tx_new [ ' from ' ] ,
] ,
queue = queue ,
)
s_unlock_direct = celery . signature (
' cic_eth.admin.ctrl.unlock_queue ' ,
[
2021-05-27 19:21:30 +02:00
chain_spec . asdict ( ) ,
2021-02-01 18:12:51 +01:00
tx_new [ ' from ' ] ,
] ,
queue = queue ,
)
s_unlocks = celery . group ( s_unlock_send , s_unlock_direct )
s . link ( s_unlocks )
s . apply_async ( )