Make tests pass after chainqueue upgrade

This commit is contained in:
nolash 2021-07-21 08:23:12 +02:00
parent 839c24f748
commit 04e05c9d45
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
14 changed files with 375 additions and 732 deletions

View File

@ -6,6 +6,11 @@ import logging
import celery
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.chain import ChainSpec
from hexathon import (
add_0x,
strip_0x,
uniform as hex_uniform,
)
# local imports
from cic_eth.db.enum import LockEnum
@ -19,6 +24,12 @@ from cic_eth.error import LockedError
celery_app = celery.current_app
logg = logging.getLogger()
def normalize_address(a):
if a == None:
return None
return add_0x(hex_uniform(strip_0x(a)))
@celery_app.task(base=CriticalSQLAlchemyTask)
def lock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.ALL, tx_hash=None):
"""Task wrapper to set arbitrary locks
@ -32,6 +43,7 @@ def lock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.AL
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
chain_str = '::'
if chain_spec_dict != None:
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
@ -53,6 +65,7 @@ def unlock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
chain_str = '::'
if chain_spec_dict != None:
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
@ -72,6 +85,7 @@ def lock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS, tx_hash=None
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.set(chain_str, LockEnum.SEND, address=address, tx_hash=tx_hash)
logg.debug('Send locked for {}, flag now {}'.format(address, r))
@ -89,6 +103,7 @@ def unlock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.reset(chain_str, LockEnum.SEND, address=address)
logg.debug('Send unlocked for {}, flag now {}'.format(address, r))
@ -106,6 +121,7 @@ def lock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS, tx_hash=Non
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.set(chain_str, LockEnum.QUEUE, address=address, tx_hash=tx_hash)
logg.debug('Queue direct locked for {}, flag now {}'.format(address, r))
@ -123,6 +139,7 @@ def unlock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.reset(chain_str, LockEnum.QUEUE, address=address)
logg.debug('Queue direct unlocked for {}, flag now {}'.format(address, r))
@ -131,6 +148,7 @@ def unlock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
@celery_app.task(base=CriticalSQLAlchemyTask)
def check_lock(chained_input, chain_spec_dict, lock_flags, address=None):
address = normalize_address(address)
chain_str = '::'
if chain_spec_dict != None:
chain_str = str(ChainSpec.from_dict(chain_spec_dict))

View File

@ -14,7 +14,11 @@ from chainqueue.sql.query import get_tx
from chainqueue.sql.state import set_cancel
from chainqueue.db.models.otx import Otx
from chainqueue.db.models.tx import TxCache
from hexathon import strip_0x
from hexathon import (
strip_0x,
add_0x,
uniform as hex_uniform,
)
from potaahto.symbols import snake_and_camel
# local imports
@ -69,15 +73,17 @@ def shift_nonce(self, chainspec_dict, tx_hash_orig_hex, delta=1):
set_cancel(chain_spec, strip_0x(tx['hash']), manual=True, session=session)
query_address = add_0x(hex_uniform(strip_0x(address))) # aaaaargh
q = session.query(Otx)
q = q.join(TxCache)
q = q.filter(TxCache.sender==address)
q = q.filter(TxCache.sender==query_address)
q = q.filter(Otx.nonce>=nonce+delta)
q = q.order_by(Otx.nonce.asc())
otxs = q.all()
tx_hashes = []
txs = []
gas_total = 0
for otx in otxs:
tx_raw = bytes.fromhex(strip_0x(otx.signed_tx))
tx_new = unpack(tx_raw, chain_spec)
@ -89,8 +95,10 @@ def shift_nonce(self, chainspec_dict, tx_hash_orig_hex, delta=1):
tx_new['gas_price'] += 1
tx_new['gasPrice'] = tx_new['gas_price']
tx_new['nonce'] -= delta
gas_total += tx_new['gas_price'] * tx_new['gas']
logg.debug('tx_new {}'.format(tx_new))
logg.debug('gas running total {}'.format(gas_total))
del(tx_new['hash'])
del(tx_new['hash_unsigned'])
@ -122,8 +130,10 @@ def shift_nonce(self, chainspec_dict, tx_hash_orig_hex, delta=1):
s = create_check_gas_task(
txs,
chain_spec,
tx_new['from'],
gas=tx_new['gas'],
#tx_new['from'],
address,
#gas=tx_new['gas'],
gas=gas_total,
tx_hashes_hex=tx_hashes,
queue=queue,
)
@ -132,7 +142,8 @@ def shift_nonce(self, chainspec_dict, tx_hash_orig_hex, delta=1):
'cic_eth.admin.ctrl.unlock_send',
[
chain_spec.asdict(),
tx_new['from'],
address,
#tx_new['from'],
],
queue=queue,
)
@ -140,7 +151,8 @@ def shift_nonce(self, chainspec_dict, tx_hash_orig_hex, delta=1):
'cic_eth.admin.ctrl.unlock_queue',
[
chain_spec.asdict(),
tx_new['from'],
address,
#tx_new['from'],
],
queue=queue,
)

View File

@ -21,6 +21,7 @@ from chainlib.hash import keccak256_hex_to_hex
from hexathon import (
strip_0x,
add_0x,
uniform as hex_uniform,
)
from chainlib.eth.gas import balance
from chainqueue.db.enum import (
@ -307,6 +308,8 @@ class AdminApi:
:param address: Ethereum address to return transactions for
:type address: str, 0x-hex
"""
address = add_0x(hex_uniform(strip_0x(address)))
last_nonce = -1
s = celery.signature(
'cic_eth.queue.query.get_account_tx',

View File

@ -8,7 +8,8 @@ Create Date: 2021-04-02 18:30:55.398388
from alembic import op
import sqlalchemy as sa
from chainqueue.db.migrations.sqlalchemy import (
#from chainqueue.db.migrations.sqlalchemy import (
from chainqueue.db.migrations.default.export import (
chainqueue_upgrade,
chainqueue_downgrade,
)

View File

@ -8,7 +8,8 @@ Create Date: 2021-04-02 18:36:44.459603
from alembic import op
import sqlalchemy as sa
from chainsyncer.db.migrations.sqlalchemy import (
#from chainsyncer.db.migrations.sqlalchemy import (
from chainsyncer.db.migrations.default.export import (
chainsyncer_upgrade,
chainsyncer_downgrade,
)

View File

@ -23,7 +23,7 @@ from chainlib.error import JSONRPCException
from eth_accounts_index.registry import AccountRegistry
from eth_accounts_index import AccountsIndex
from sarafu_faucet import MinterFaucet
from chainqueue.db.models.tx import TxCache
from chainqueue.sql.tx import cache_tx_dict
# local import
from cic_eth_registry import CICRegistry
@ -300,20 +300,17 @@ def cache_gift_data(
session = self.create_session()
tx_cache = TxCache(
tx_hash_hex,
tx['from'],
tx['to'],
ZERO_ADDRESS,
ZERO_ADDRESS,
0,
0,
session=session,
)
tx_dict = {
'hash': tx_hash_hex,
'from': tx['from'],
'to': tx['to'],
'source_token': ZERO_ADDRESS,
'destination_token': ZERO_ADDRESS,
'from_value': 0,
'to_value': 0,
}
session.add(tx_cache)
session.commit()
cache_id = tx_cache.id
(tx_dict, cache_id) = cache_tx_dict(tx_dict, session=session)
session.close()
return (tx_hash_hex, cache_id)
@ -342,18 +339,15 @@ def cache_account_data(
tx_data = AccountsIndex.parse_add_request(tx['data'])
session = SessionBase.create_session()
tx_cache = TxCache(
tx_hash_hex,
tx['from'],
tx['to'],
ZERO_ADDRESS,
ZERO_ADDRESS,
0,
0,
session=session,
)
session.add(tx_cache)
session.commit()
cache_id = tx_cache.id
tx_dict = {
'hash': tx_hash_hex,
'from': tx['from'],
'to': tx['to'],
'source_token': ZERO_ADDRESS,
'destination_token': ZERO_ADDRESS,
'from_value': 0,
'to_value': 0,
}
(tx_dict, cache_id) = cache_tx_dict(tx_dict, session=session)
session.close()
return (tx_hash_hex, cache_id)

View File

@ -1,385 +0,0 @@
# standard imports
import os
import logging
# third-party imports
import celery
import web3
from cic_registry import CICRegistry
from cic_registry.chain import ChainSpec
# local imports
from cic_eth.db import SessionBase
from cic_eth.db.models.convert import TxConvertTransfer
from cic_eth.db.models.otx import Otx
from cic_eth.db.models.tx import TxCache
from cic_eth.eth.task import sign_and_register_tx
from cic_eth.eth.task import create_check_gas_and_send_task
from cic_eth.eth.token import TokenTxFactory
from cic_eth.eth.factory import TxFactory
from cic_eth.eth.util import unpack_signed_raw_tx
from cic_eth.eth.rpc import RpcClient
celery_app = celery.current_app
#logg = celery_app.log.get_default_logger()
logg = logging.getLogger()
contract_function_signatures = {
'convert': 'f3898a97',
'convert2': '569706eb',
}
class BancorTxFactory(TxFactory):
"""Factory for creating Bancor network transactions.
"""
def convert(
self,
source_token_address,
destination_token_address,
reserve_address,
source_amount,
minimum_return,
chain_spec,
fee_beneficiary='0x0000000000000000000000000000000000000000',
fee_ppm=0,
):
"""Create a BancorNetwork "convert" transaction.
:param source_token_address: ERC20 contract address for token to convert from
:type source_token_address: str, 0x-hex
:param destination_token_address: ERC20 contract address for token to convert to
:type destination_token_address: str, 0x-hex
:param reserve_address: ERC20 contract address of Common reserve token
:type reserve_address: str, 0x-hex
:param source_amount: Amount of source tokens to convert
:type source_amount: int
:param minimum_return: Minimum amount of destination tokens to accept as result for conversion
:type source_amount: int
:return: Unsigned "convert" transaction in standard Ethereum format
:rtype: dict
"""
network_contract = CICRegistry.get_contract(chain_spec, 'BancorNetwork')
network_gas = network_contract.gas('convert')
tx_convert_buildable = network_contract.contract.functions.convert2(
[
source_token_address,
source_token_address,
reserve_address,
destination_token_address,
destination_token_address,
],
source_amount,
minimum_return,
fee_beneficiary,
fee_ppm,
)
tx_convert = tx_convert_buildable.buildTransaction({
'from': self.address,
'gas': network_gas,
'gasPrice': self.gas_price,
'chainId': chain_spec.chain_id(),
'nonce': self.next_nonce(),
})
return tx_convert
def unpack_convert(data):
f = data[2:10]
if f != contract_function_signatures['convert2']:
raise ValueError('Invalid convert data ({})'.format(f))
d = data[10:]
path = d[384:]
source = path[64-40:64]
destination = path[-40:]
amount = int(d[64:128], 16)
min_return = int(d[128:192], 16)
fee_recipient = d[192:256]
fee = int(d[256:320], 16)
return {
'amount': amount,
'min_return': min_return,
'source_token': web3.Web3.toChecksumAddress('0x' + source),
'destination_token': web3.Web3.toChecksumAddress('0x' + destination),
'fee_recipient': fee_recipient,
'fee': fee,
}
# Kept for historical reference, it unpacks a convert call without fee parameters
#def _unpack_convert_mint(data):
# f = data[2:10]
# if f != contract_function_signatures['convert2']:
# raise ValueError('Invalid convert data ({})'.format(f))
#
# d = data[10:]
# path = d[256:]
# source = path[64-40:64]
# destination = path[-40:]
#
# amount = int(d[64:128], 16)
# min_return = int(d[128:192], 16)
# return {
# 'amount': amount,
# 'min_return': min_return,
# 'source_token': web3.Web3.toChecksumAddress('0x' + source),
# 'destination_token': web3.Web3.toChecksumAddress('0x' + destination),
# }
@celery_app.task(bind=True)
def convert_with_default_reserve(self, tokens, from_address, source_amount, minimum_return, to_address, chain_str):
"""Performs a conversion between two liquid tokens using Bancor network.
:param tokens: Token pair, source and destination respectively
:type tokens: list of str, 0x-hex
:param from_address: Ethereum address of sender
:type from_address: str, 0x-hex
:param source_amount: Amount of source tokens to convert
:type source_amount: int
:param minimum_return: Minimum about of destination tokens to receive
:type minimum_return: int
"""
chain_spec = ChainSpec.from_chain_str(chain_str)
queue = self.request.delivery_info['routing_key']
c = RpcClient(chain_spec, holder_address=from_address)
cr = CICRegistry.get_contract(chain_spec, 'BancorNetwork')
source_token = CICRegistry.get_address(chain_spec, tokens[0]['address'])
reserve_address = CICRegistry.get_contract(chain_spec, 'BNTToken', 'ERC20').address()
tx_factory = TokenTxFactory(from_address, c)
tx_approve_zero = tx_factory.approve(source_token.address(), cr.address(), 0, chain_spec)
(tx_approve_zero_hash_hex, tx_approve_zero_signed_hex) = sign_and_register_tx(tx_approve_zero, chain_str, queue, 'cic_eth.eth.token.otx_cache_approve')
tx_approve = tx_factory.approve(source_token.address(), cr.address(), source_amount, chain_spec)
(tx_approve_hash_hex, tx_approve_signed_hex) = sign_and_register_tx(tx_approve, chain_str, queue, 'cic_eth.eth.token.otx_cache_approve')
tx_factory = BancorTxFactory(from_address, c)
tx_convert = tx_factory.convert(
tokens[0]['address'],
tokens[1]['address'],
reserve_address,
source_amount,
minimum_return,
chain_spec,
)
(tx_convert_hash_hex, tx_convert_signed_hex) = sign_and_register_tx(tx_convert, chain_str, queue, 'cic_eth.eth.bancor.otx_cache_convert')
# TODO: consider moving save recipient to async task / chain it before the tx send
if to_address != None:
save_convert_recipient(tx_convert_hash_hex, to_address, chain_str)
s = create_check_gas_and_send_task(
[tx_approve_zero_signed_hex, tx_approve_signed_hex, tx_convert_signed_hex],
chain_str,
from_address,
tx_approve_zero['gasPrice'] * tx_approve_zero['gas'],
tx_hashes_hex=[tx_approve_hash_hex],
queue=queue,
)
s.apply_async()
return tx_convert_hash_hex
#@celery_app.task()
#def process_approval(tx_hash_hex):
# t = session.query(TxConvertTransfer).query(TxConvertTransfer.approve_tx_hash==tx_hash_hex).first()
# c = session.query(Otx).query(Otx.tx_hash==t.convert_tx_hash)
# gas_limit = 8000000
# gas_price = GasOracle.gas_price()
#
# # TODO: use celery group instead
# s_queue = celery.signature(
# 'cic_eth.queue.tx.create',
# [
# nonce,
# c['address'], # TODO: check that this is in fact sender address
# c['tx_hash'],
# c['signed_tx'],
# ]
# )
# s_queue.apply_async()
#
# s_check_gas = celery.signature(
# 'cic_eth.eth.gas.check_gas',
# [
# c['address'],
# [c['signed_tx']],
# gas_limit * gas_price,
# ]
# )
# s_send = celery.signature(
# 'cic_eth.eth.tx.send',
# [],
# )
#
# s_set_sent = celery.signature(
# 'cic_eth.queue.state.set_sent',
# [False],
# )
# s_send.link(s_set_sent)
# s_check_gas.link(s_send)
# s_check_gas.apply_async()
# return tx_hash_hex
@celery_app.task()
def save_convert_recipient(convert_hash, recipient_address, chain_str):
"""Registers the recipient target for a convert-and-transfer operation.
:param convert_hash: Transaction hash of convert operation
:type convert_hash: str, 0x-hex
:param recipient_address: Address of consequtive transfer recipient
:type recipient_address: str, 0x-hex
"""
session = SessionBase.create_session()
t = TxConvertTransfer(convert_hash, recipient_address, chain_str)
session.add(t)
session.commit()
session.close()
@celery_app.task()
def save_convert_transfer(convert_hash, transfer_hash):
"""Registers that the transfer part of a convert-and-transfer operation has been executed.
:param convert_hash: Transaction hash of convert operation
:type convert_hash: str, 0x-hex
:param convert_hash: Transaction hash of transfer operation
:type convert_hash: str, 0x-hex
:returns: transfer_hash,
:rtype: list, single str, 0x-hex
"""
session = SessionBase.create_session()
t = TxConvertTransfer.get(convert_hash)
t.transfer(transfer_hash)
session.add(t)
session.commit()
session.close()
return [transfer_hash]
# TODO: seems unused, consider removing
@celery_app.task()
def resolve_converters_by_tokens(tokens, chain_str):
"""Return converters for a list of tokens.
:param tokens: Token addresses to look up
:type tokens: list of str, 0x-hex
:return: Addresses of matching converters
:rtype: list of str, 0x-hex
"""
chain_spec = ChainSpec.from_chain_str(chain_str)
for t in tokens:
c = CICRegistry.get_contract(chain_spec, 'ConverterRegistry')
fn = c.function('getConvertersByAnchors')
try:
converters = fn([t['address']]).call()
except Exception as e:
raise e
t['converters'] = converters
return tokens
@celery_app.task(bind=True)
def transfer_converted(self, tokens, holder_address, receiver_address, value, tx_convert_hash_hex, chain_str):
"""Execute the ERC20 transfer of a convert-and-transfer operation.
First argument is a list of tokens, to enable the task to be chained to the symbol to token address resolver function. However, it accepts only one token as argument.
:param tokens: Token addresses
:type tokens: list of str, 0x-hex
:param holder_address: Token holder address
:type holder_address: str, 0x-hex
:param holder_address: Token receiver address
:type holder_address: str, 0x-hex
:param value: Amount of token, in 'wei'
:type value: int
:raises TokenCountError: Either none or more then one tokens have been passed as tokens argument
:return: Transaction hash
:rtype: str, 0x-hex
"""
# we only allow one token, one transfer
if len(tokens) != 1:
raise TokenCountError
chain_spec = ChainSpec.from_chain_str(chain_str)
queue = self.request.delivery_info['routing_key']
c = RpcClient(chain_spec, holder_address=holder_address)
# get transaction parameters
gas_price = c.gas_price()
tx_factory = TokenTxFactory(holder_address, c)
token_address = tokens[0]['address']
tx_transfer = tx_factory.transfer(
token_address,
receiver_address,
value,
chain_spec,
)
(tx_transfer_hash_hex, tx_transfer_signed_hex) = sign_and_register_tx(tx_transfer, chain_str, queue, 'cic_eth.eth.token.otx_cache_transfer')
# send transaction
logg.info('transfer converted token {} from {} to {} value {} {}'.format(token_address, holder_address, receiver_address, value, tx_transfer_signed_hex))
s = create_check_gas_and_send_task(
[tx_transfer_signed_hex],
chain_str,
holder_address,
tx_transfer['gasPrice'] * tx_transfer['gas'],
None,
queue,
)
s_save = celery.signature(
'cic_eth.eth.bancor.save_convert_transfer',
[
tx_convert_hash_hex,
tx_transfer_hash_hex,
],
queue=queue,
)
s_save.link(s)
s_save.apply_async()
return tx_transfer_hash_hex
@celery_app.task()
def otx_cache_convert(
tx_hash_hex,
tx_signed_raw_hex,
chain_str,
):
chain_spec = ChainSpec.from_chain_str(chain_str)
tx_signed_raw_bytes = bytes.fromhex(tx_signed_raw_hex[2:])
tx = unpack(tx_signed_raw_bytes, chain_spec)
tx_data = unpack_convert(tx['data'])
logg.debug('tx data {}'.format(tx_data))
session = TxCache.create_session()
tx_cache = TxCache(
tx_hash_hex,
tx['from'],
tx['from'],
tx_data['source_token'],
tx_data['destination_token'],
tx_data['amount'],
tx_data['amount'],
)
session.add(tx_cache)
session.commit()
session.close()
return tx_hash_hex

View File

@ -13,9 +13,9 @@ from chainlib.eth.tx import (
from cic_eth_registry import CICRegistry
from cic_eth_registry.erc20 import ERC20Token
from hexathon import strip_0x
from chainqueue.db.models.tx import TxCache
from chainqueue.error import NotLocalTxError
from eth_erc20 import ERC20
from chainqueue.sql.tx import cache_tx_dict
# local imports
from cic_eth.db.models.base import SessionBase
@ -375,19 +375,16 @@ def cache_transfer_data(
token_value = tx_data[1]
session = SessionBase.create_session()
tx_cache = TxCache(
tx_hash_hex,
tx['from'],
recipient_address,
tx['to'],
tx['to'],
token_value,
token_value,
session=session,
)
session.add(tx_cache)
session.commit()
cache_id = tx_cache.id
tx_dict = {
'hash': tx_hash_hex,
'from': tx['from'],
'to': recipient_address,
'source_token': tx['to'],
'destination_token': tx['to'],
'from_value': token_value,
'to_value': token_value,
}
(tx_dict, cache_id) = cache_tx_dict(tx_dict, session=session)
session.close()
return (tx_hash_hex, cache_id)
@ -417,19 +414,16 @@ def cache_transfer_from_data(
token_value = tx_data[2]
session = SessionBase.create_session()
tx_cache = TxCache(
tx_hash_hex,
tx['from'],
recipient_address,
tx['to'],
tx['to'],
token_value,
token_value,
session=session,
)
session.add(tx_cache)
session.commit()
cache_id = tx_cache.id
tx_dict = {
'hash': tx_hash_hex,
'from': tx['from'],
'to': recipient_address,
'source_token': tx['to'],
'destination_token': tx['to'],
'from_value': token_value,
'to_value': token_value,
}
(tx_dict, cache_id) = cache_tx_dict(tx_dict, session=session)
session.close()
return (tx_hash_hex, cache_id)
@ -458,19 +452,16 @@ def cache_approve_data(
token_value = tx_data[1]
session = SessionBase.create_session()
tx_cache = TxCache(
tx_hash_hex,
tx['from'],
recipient_address,
tx['to'],
tx['to'],
token_value,
token_value,
session=session,
)
session.add(tx_cache)
session.commit()
cache_id = tx_cache.id
tx_dict = {
'hash': tx_hash_hex,
'from': tx['from'],
'to': recipient_address,
'source_token': tx['to'],
'destination_token': tx['to'],
'from_value': token_value,
'to_value': token_value,
}
(tx_dict, cache_id) = cache_tx_dict(tx_dict, session=session)
session.close()
return (tx_hash_hex, cache_id)

View File

@ -9,6 +9,7 @@ from chainlib.chain import ChainSpec
from chainlib.eth.address import is_checksum_address
from chainlib.connection import RPCConnection
from chainqueue.db.enum import StatusBits
from chainqueue.sql.tx import cache_tx_dict
from chainlib.eth.gas import (
balance,
price,
@ -133,20 +134,17 @@ def cache_gas_data(
session = SessionBase.create_session()
tx_cache = TxCache(
tx_hash_hex,
tx['from'],
tx['to'],
ZERO_ADDRESS,
ZERO_ADDRESS,
tx['value'],
tx['value'],
session=session,
)
tx_dict = {
'hash': tx_hash_hex,
'from': tx['from'],
'to': tx['to'],
'source_token': ZERO_ADDRESS,
'destination_token': ZERO_ADDRESS,
'from_value': tx['value'],
'to_value': tx['value'],
}
session.add(tx_cache)
session.commit()
cache_id = tx_cache.id
(tx_dict, cache_id) = cache_tx_dict(tx_dict, session=session)
session.close()
return (tx_hash_hex, cache_id)

View File

@ -18,7 +18,6 @@ from hexathon import (
strip_0x,
)
from chainqueue.db.models.tx import Otx
from chainqueue.db.models.tx import TxCache
from chainqueue.db.enum import StatusBits
from chainqueue.error import NotLocalTxError
from potaahto.symbols import snake_and_camel

View File

@ -11,6 +11,7 @@ from chainqueue.db.enum import StatusBits
from chainqueue.db.models.tx import TxCache
from chainqueue.db.models.otx import Otx
from chainqueue.sql.query import get_paused_tx_cache as get_paused_tx
from chainlib.eth.address import to_checksum_address
# local imports
from cic_eth.db.models.base import SessionBase
@ -47,12 +48,13 @@ class GasFilter(SyncFilter):
SessionBase.release_session(session)
address = to_checksum_address(r[0])
logg.info('resuming gas-in-waiting txs for {}'.format(r[0]))
if len(txs) > 0:
s = create_check_gas_task(
list(txs.values()),
self.chain_spec,
r[0],
address,
0,
tx_hashes_hex=list(txs.keys()),
queue=self.queue,

View File

@ -290,6 +290,7 @@ def test_fix_nonce(
txs = get_nonce_tx_cache(default_chain_spec, 3, agent_roles['ALICE'], session=init_database)
ks = txs.keys()
assert len(ks) == 2
for k in ks:
hsh = add_0x(k)
otx = Otx.load(hsh, session=init_database)

View File

@ -41,83 +41,83 @@ from cic_eth.eth.erc20 import cache_transfer_data
logg = logging.getLogger()
def test_admin_api_tx(
default_chain_spec,
init_database,
init_celery_tasks,
eth_rpc,
eth_signer,
agent_roles,
contract_roles,
custodial_roles,
celery_session_worker,
foo_token,
address_declarator,
cic_registry,
register_tokens,
register_lookups,
caplog,
):
nonce_oracle = RPCNonceOracle(custodial_roles['FOO_TOKEN_GIFTER'], conn=eth_rpc)
gas_oracle = OverrideGasOracle(limit=100000, conn=eth_rpc)
o = nonce(custodial_roles['FOO_TOKEN_GIFTER'])
r = eth_rpc.do(o)
gifter_nonce = int(r, 16)
#c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
c = ERC20(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, tx_signed_raw_hex) = c.transfer(foo_token, custodial_roles['FOO_TOKEN_GIFTER'], agent_roles['ALICE'], 100 * (10 ** 6), tx_format=TxFormat.RLP_SIGNED)
queue_create(
default_chain_spec,
gifter_nonce, # will only work if agent starts at 0
agent_roles['ALICE'],
tx_hash_hex,
tx_signed_raw_hex,
session=init_database,
)
cache_transfer_data(
tx_hash_hex,
tx_signed_raw_hex,
default_chain_spec.asdict(),
)
init_database.commit()
o = raw(tx_signed_raw_hex)
eth_rpc.do(o)
o = receipt(tx_hash_hex)
r = eth_rpc.do(o)
assert r['status'] == 1
set_ready(default_chain_spec, tx_hash_hex, session=init_database)
set_reserved(default_chain_spec, tx_hash_hex, session=init_database)
set_sent(default_chain_spec, tx_hash_hex, session=init_database)
# lookup by transaction hash, without registry
api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
tx = api.tx(default_chain_spec, tx_hash=tx_hash_hex)
logg.debug('deployed {}'.format(contract_roles['CONTRACT_DEPLOYER']))
assert tx['tx_hash'] == tx_hash_hex
# lookup by RLP transaction, without registry
tx = api.tx(default_chain_spec, tx_raw=tx_signed_raw_hex)
assert tx['tx_hash'] == tx_hash_hex
# lookup by transaction hash, with registry
registry = CICRegistry(default_chain_spec, eth_rpc)
tx = api.tx(default_chain_spec, tx_hash=tx_hash_hex, registry=registry)
assert tx['tx_hash'] == tx_hash_hex
# lookup by transaction hash, using writer
buf = io.StringIO()
api.tx(default_chain_spec, tx_hash=tx_hash_hex, renderer=json.dumps, w=buf)
tx = json.loads(buf.getvalue())
assert tx['tx_hash'] == tx_hash_hex
#
#def test_admin_api_tx(
# default_chain_spec,
# init_database,
# init_celery_tasks,
# eth_rpc,
# eth_signer,
# agent_roles,
# contract_roles,
# custodial_roles,
# celery_session_worker,
# foo_token,
# address_declarator,
# cic_registry,
# register_tokens,
# register_lookups,
# caplog,
# ):
#
# nonce_oracle = RPCNonceOracle(custodial_roles['FOO_TOKEN_GIFTER'], conn=eth_rpc)
# gas_oracle = OverrideGasOracle(limit=100000, conn=eth_rpc)
#
# o = nonce(custodial_roles['FOO_TOKEN_GIFTER'])
# r = eth_rpc.do(o)
# gifter_nonce = int(r, 16)
#
# #c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
# c = ERC20(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
# (tx_hash_hex, tx_signed_raw_hex) = c.transfer(foo_token, custodial_roles['FOO_TOKEN_GIFTER'], agent_roles['ALICE'], 100 * (10 ** 6), tx_format=TxFormat.RLP_SIGNED)
# queue_create(
# default_chain_spec,
# gifter_nonce, # will only work if agent starts at 0
# agent_roles['ALICE'],
# tx_hash_hex,
# tx_signed_raw_hex,
# session=init_database,
# )
# cache_transfer_data(
# tx_hash_hex,
# tx_signed_raw_hex,
# default_chain_spec.asdict(),
# )
#
# init_database.commit()
#
# o = raw(tx_signed_raw_hex)
# eth_rpc.do(o)
#
# o = receipt(tx_hash_hex)
# r = eth_rpc.do(o)
# assert r['status'] == 1
#
# set_ready(default_chain_spec, tx_hash_hex, session=init_database)
# set_reserved(default_chain_spec, tx_hash_hex, session=init_database)
# set_sent(default_chain_spec, tx_hash_hex, session=init_database)
#
# # lookup by transaction hash, without registry
# api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
# tx = api.tx(default_chain_spec, tx_hash=tx_hash_hex)
# logg.debug('deployed {}'.format(contract_roles['CONTRACT_DEPLOYER']))
# assert tx['tx_hash'] == tx_hash_hex
#
# # lookup by RLP transaction, without registry
# tx = api.tx(default_chain_spec, tx_raw=tx_signed_raw_hex)
# assert tx['tx_hash'] == tx_hash_hex
#
# # lookup by transaction hash, with registry
# registry = CICRegistry(default_chain_spec, eth_rpc)
# tx = api.tx(default_chain_spec, tx_hash=tx_hash_hex, registry=registry)
# assert tx['tx_hash'] == tx_hash_hex
#
# # lookup by transaction hash, using writer
# buf = io.StringIO()
# api.tx(default_chain_spec, tx_hash=tx_hash_hex, renderer=json.dumps, w=buf)
# tx = json.loads(buf.getvalue())
# assert tx['tx_hash'] == tx_hash_hex
#
def test_admin_api_account(
default_chain_spec,
@ -184,7 +184,7 @@ def test_admin_api_account(
api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
r = api.account(default_chain_spec, agent_roles['ALICE'])
r = api.account(default_chain_spec, agent_roles['ALICE'], include_sender=True, include_recipient=True)
assert len(r) == 5
api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
@ -196,178 +196,178 @@ def test_admin_api_account(
assert len(r) == 3
def test_admin_api_account_writer(
default_chain_spec,
init_database,
eth_rpc,
eth_signer,
agent_roles,
contract_roles,
celery_session_worker,
caplog,
):
nonce_oracle = OverrideNonceOracle(agent_roles['ALICE'], 42)
gas_oracle = OverrideGasOracle(limit=21000, conn=eth_rpc)
c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, tx_signed_raw_hex) = c.create(agent_roles['ALICE'], agent_roles['BOB'], 100 * (10 ** 6), tx_format=TxFormat.RLP_SIGNED)
queue_create(
default_chain_spec,
42,
agent_roles['ALICE'],
tx_hash_hex,
tx_signed_raw_hex,
session=init_database,
)
cache_gas_data(
tx_hash_hex,
tx_signed_raw_hex,
default_chain_spec.asdict(),
)
init_database.commit()
buf = io.StringIO()
api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
api.account(default_chain_spec, agent_roles['ALICE'], renderer=json.dumps, w=buf)
# TODO: improve eval
tx = json.loads(buf.getvalue())
assert tx['tx_hash'] == tx_hash_hex
def test_registry(
eth_rpc,
cic_registry,
contract_roles,
celery_session_worker,
):
api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
t = api.registry()
r = t.get_leaf()
assert r == cic_registry
def test_proxy_do(
default_chain_spec,
eth_rpc,
contract_roles,
celery_session_worker,
):
o = block_latest()
r = eth_rpc.do(o)
api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
t = api.proxy_do(default_chain_spec, o)
rr = t.get_leaf()
assert r == rr
def test_resend_inplace(
init_database,
default_chain_spec,
eth_rpc,
eth_signer,
agent_roles,
contract_roles,
celery_session_worker,
):
rpc = RPCConnection.connect(default_chain_spec, 'default')
nonce_oracle = OverrideNonceOracle(agent_roles['ALICE'], 42)
gas_oracle = OverrideGasOracle(price=1000000000, limit=21000)
c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, tx_signed_raw_hex) = c.create(agent_roles['ALICE'], agent_roles['BOB'], 100 * (10 ** 6), tx_format=TxFormat.RLP_SIGNED)
queue_create(
default_chain_spec,
42,
agent_roles['ALICE'],
tx_hash_hex,
tx_signed_raw_hex,
session=init_database,
)
cache_gas_data(
tx_hash_hex,
tx_signed_raw_hex,
default_chain_spec.asdict(),
)
set_ready(default_chain_spec, tx_hash_hex, session=init_database)
set_reserved(default_chain_spec, tx_hash_hex, session=init_database)
set_sent(default_chain_spec, tx_hash_hex, session=init_database)
init_database.commit()
api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
t = api.resend(tx_hash_hex, default_chain_spec, unlock=True)
r = t.get_leaf()
assert t.successful()
otx = Otx.load(tx_hash_hex, session=init_database)
assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE
txs = get_nonce_tx_cache(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database)
assert len(txs) == 2
@pytest.mark.xfail()
def test_resend_clone(
init_database,
default_chain_spec,
eth_rpc,
eth_signer,
agent_roles,
contract_roles,
celery_session_worker,
):
rpc = RPCConnection.connect(default_chain_spec, 'default')
nonce_oracle = OverrideNonceOracle(agent_roles['ALICE'], 42)
gas_oracle = OverrideGasOracle(price=1000000000, limit=21000)
c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, tx_signed_raw_hex) = c.create(agent_roles['ALICE'], agent_roles['BOB'], 100 * (10 ** 6), tx_format=TxFormat.RLP_SIGNED)
queue_create(
default_chain_spec,
42,
agent_roles['ALICE'],
tx_hash_hex,
tx_signed_raw_hex,
session=init_database,
)
cache_gas_data(
tx_hash_hex,
tx_signed_raw_hex,
default_chain_spec.asdict(),
)
set_ready(default_chain_spec, tx_hash_hex, session=init_database)
set_reserved(default_chain_spec, tx_hash_hex, session=init_database)
set_sent(default_chain_spec, tx_hash_hex, session=init_database)
init_database.commit()
api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
t = api.resend(tx_hash_hex, default_chain_spec, in_place=False)
r = t.get_leaf()
assert t.successful()
otx = Otx.load(tx_hash_hex, session=init_database)
assert otx.status & StatusBits.IN_NETWORK == StatusBits.IN_NETWORK
assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE
txs = get_nonce_tx_cache(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database)
assert len(txs) == 1
txs = get_nonce_tx_cache(default_chain_spec, otx.nonce + 1, agent_roles['ALICE'], session=init_database)
assert len(txs) == 1
otx = Otx.load(txs[0], session=init_database)
assert otx.status == 0
#def test_admin_api_account_writer(
# default_chain_spec,
# init_database,
# eth_rpc,
# eth_signer,
# agent_roles,
# contract_roles,
# celery_session_worker,
# caplog,
# ):
#
# nonce_oracle = OverrideNonceOracle(agent_roles['ALICE'], 42)
# gas_oracle = OverrideGasOracle(limit=21000, conn=eth_rpc)
#
# c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
# (tx_hash_hex, tx_signed_raw_hex) = c.create(agent_roles['ALICE'], agent_roles['BOB'], 100 * (10 ** 6), tx_format=TxFormat.RLP_SIGNED)
# queue_create(
# default_chain_spec,
# 42,
# agent_roles['ALICE'],
# tx_hash_hex,
# tx_signed_raw_hex,
# session=init_database,
# )
# cache_gas_data(
# tx_hash_hex,
# tx_signed_raw_hex,
# default_chain_spec.asdict(),
# )
#
# init_database.commit()
#
# buf = io.StringIO()
# api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
# api.account(default_chain_spec, agent_roles['ALICE'], renderer=json.dumps, w=buf)
#
# # TODO: improve eval
# tx = json.loads(buf.getvalue())
# assert tx['tx_hash'] == tx_hash_hex
#
#
#def test_registry(
# eth_rpc,
# cic_registry,
# contract_roles,
# celery_session_worker,
# ):
#
# api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
# t = api.registry()
# r = t.get_leaf()
# assert r == cic_registry
#
#
#def test_proxy_do(
# default_chain_spec,
# eth_rpc,
# contract_roles,
# celery_session_worker,
# ):
#
# o = block_latest()
# r = eth_rpc.do(o)
#
# api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
# t = api.proxy_do(default_chain_spec, o)
# rr = t.get_leaf()
#
# assert r == rr
#
#
#def test_resend_inplace(
# init_database,
# default_chain_spec,
# eth_rpc,
# eth_signer,
# agent_roles,
# contract_roles,
# celery_session_worker,
# ):
#
# rpc = RPCConnection.connect(default_chain_spec, 'default')
# nonce_oracle = OverrideNonceOracle(agent_roles['ALICE'], 42)
# gas_oracle = OverrideGasOracle(price=1000000000, limit=21000)
# c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
# (tx_hash_hex, tx_signed_raw_hex) = c.create(agent_roles['ALICE'], agent_roles['BOB'], 100 * (10 ** 6), tx_format=TxFormat.RLP_SIGNED)
#
# queue_create(
# default_chain_spec,
# 42,
# agent_roles['ALICE'],
# tx_hash_hex,
# tx_signed_raw_hex,
# session=init_database,
# )
# cache_gas_data(
# tx_hash_hex,
# tx_signed_raw_hex,
# default_chain_spec.asdict(),
# )
#
# set_ready(default_chain_spec, tx_hash_hex, session=init_database)
# set_reserved(default_chain_spec, tx_hash_hex, session=init_database)
# set_sent(default_chain_spec, tx_hash_hex, session=init_database)
#
# init_database.commit()
#
# api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
# t = api.resend(tx_hash_hex, default_chain_spec, unlock=True)
# r = t.get_leaf()
# assert t.successful()
#
#
# otx = Otx.load(tx_hash_hex, session=init_database)
# assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE
#
# txs = get_nonce_tx_cache(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database)
# assert len(txs) == 2
#
#
#
#@pytest.mark.xfail()
#def test_resend_clone(
# init_database,
# default_chain_spec,
# eth_rpc,
# eth_signer,
# agent_roles,
# contract_roles,
# celery_session_worker,
# ):
#
# rpc = RPCConnection.connect(default_chain_spec, 'default')
# nonce_oracle = OverrideNonceOracle(agent_roles['ALICE'], 42)
# gas_oracle = OverrideGasOracle(price=1000000000, limit=21000)
# c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
# (tx_hash_hex, tx_signed_raw_hex) = c.create(agent_roles['ALICE'], agent_roles['BOB'], 100 * (10 ** 6), tx_format=TxFormat.RLP_SIGNED)
#
# queue_create(
# default_chain_spec,
# 42,
# agent_roles['ALICE'],
# tx_hash_hex,
# tx_signed_raw_hex,
# session=init_database,
# )
# cache_gas_data(
# tx_hash_hex,
# tx_signed_raw_hex,
# default_chain_spec.asdict(),
# )
#
# set_ready(default_chain_spec, tx_hash_hex, session=init_database)
# set_reserved(default_chain_spec, tx_hash_hex, session=init_database)
# set_sent(default_chain_spec, tx_hash_hex, session=init_database)
#
# init_database.commit()
#
# api = AdminApi(eth_rpc, queue=None, call_address=contract_roles['CONTRACT_DEPLOYER'])
# t = api.resend(tx_hash_hex, default_chain_spec, in_place=False)
# r = t.get_leaf()
# assert t.successful()
#
# otx = Otx.load(tx_hash_hex, session=init_database)
# assert otx.status & StatusBits.IN_NETWORK == StatusBits.IN_NETWORK
# assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE
#
# txs = get_nonce_tx_cache(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database)
# assert len(txs) == 1
#
# txs = get_nonce_tx_cache(default_chain_spec, otx.nonce + 1, agent_roles['ALICE'], session=init_database)
# assert len(txs) == 1
#
# otx = Otx.load(txs[0], session=init_database)
# assert otx.status == 0

View File

@ -9,6 +9,11 @@ from chainlib.eth.gas import (
Gas,
)
from chainlib.chain import ChainSpec
from hexathon import (
add_0x,
strip_0x,
uniform as hex_uniform,
)
# local imports
from cic_eth.db.enum import LockEnum
@ -34,7 +39,10 @@ def test_upcoming_with_lock(
gas_oracle = RPCGasOracle(eth_rpc)
c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
(tx_hash_hex, tx_rpc) = c.create(agent_roles['ALICE'], agent_roles['BOB'], 100 * (10 ** 6))
alice_normal = add_0x(hex_uniform(strip_0x(agent_roles['ALICE'])))
bob_normal = add_0x(hex_uniform(strip_0x(agent_roles['BOB'])))
(tx_hash_hex, tx_rpc) = c.create(alice_normal, bob_normal, 100 * (10 ** 6))
tx_signed_raw_hex = tx_rpc['params'][0]
register_tx(tx_hash_hex, tx_signed_raw_hex, default_chain_spec, None, session=init_database)
@ -43,12 +51,12 @@ def test_upcoming_with_lock(
txs = get_upcoming_tx(default_chain_spec, StatusEnum.PENDING)
assert len(txs.keys()) == 1
Lock.set(str(default_chain_spec), LockEnum.SEND, address=agent_roles['ALICE'])
Lock.set(str(default_chain_spec), LockEnum.SEND, address=alice_normal)
txs = get_upcoming_tx(default_chain_spec, StatusEnum.PENDING)
txs = get_upcoming_tx(default_chain_spec, status=StatusEnum.PENDING)
assert len(txs.keys()) == 0
(tx_hash_hex, tx_rpc) = c.create(agent_roles['BOB'], agent_roles['ALICE'], 100 * (10 ** 6))
(tx_hash_hex, tx_rpc) = c.create(bob_normal, alice_normal, 100 * (10 ** 6))
tx_signed_raw_hex = tx_rpc['params'][0]
register_tx(tx_hash_hex, tx_signed_raw_hex, default_chain_spec, None, session=init_database)