From 9079697ee570f71af855a178d1c955c572cb89b5 Mon Sep 17 00:00:00 2001 From: nolash Date: Wed, 14 Jul 2021 11:07:05 +0200 Subject: [PATCH] Expand token symbol and decimals in tx_collate --- apps/cic-eth/cic_eth/ext/tx.py | 39 +++++++--- apps/cic-eth/tests/task/test_task_list.py | 89 +++++++++++++++++++++++ apps/contract-migration/reset.sh | 1 - 3 files changed, 117 insertions(+), 12 deletions(-) create mode 100644 apps/cic-eth/tests/task/test_task_list.py diff --git a/apps/cic-eth/cic_eth/ext/tx.py b/apps/cic-eth/cic_eth/ext/tx.py index 007b4136..799b076f 100644 --- a/apps/cic-eth/cic_eth/ext/tx.py +++ b/apps/cic-eth/cic_eth/ext/tx.py @@ -17,6 +17,7 @@ from chainlib.eth.contract import abi_decode_single from hexathon import strip_0x from cic_eth_registry import CICRegistry from cic_eth_registry.erc20 import ERC20Token +from cic_eth_registry.error import UnknownContractError from chainqueue.db.models.otx import Otx from chainqueue.db.enum import StatusEnum from chainqueue.sql.query import get_tx_cache @@ -114,9 +115,6 @@ def list_tx_by_bloom(self, bloomspec, address, chain_spec_dict): # TODO: pass through registry to validate declarator entry of token #token = registry.by_address(tx['to'], sender_address=self.call_address) - token = ERC20Token(chain_spec, rpc, tx['to']) - token_symbol = token.symbol - token_decimals = token.decimals times = tx_times(tx['hash'], chain_spec) tx_r = { 'hash': tx['hash'], @@ -126,12 +124,6 @@ def list_tx_by_bloom(self, bloomspec, address, chain_spec_dict): 'destination_value': tx_token_value, 'source_token': tx['to'], 'destination_token': tx['to'], - 'source_token_symbol': token_symbol, - 'destination_token_symbol': token_symbol, - 'source_token_decimals': token_decimals, - 'destination_token_decimals': token_decimals, - 'source_token_chain': chain_str, - 'destination_token_chain': chain_str, 'nonce': tx['nonce'], } if times['queue'] != None: @@ -147,7 +139,7 @@ def list_tx_by_bloom(self, bloomspec, address, chain_spec_dict): # TODO: DRY this with callback filter in cic_eth/runnable/manager # TODO: Remove redundant fields from end representation (timestamp, tx_hash) @celery_app.task() -def tx_collate(tx_batches, chain_spec_dict, offset, limit, newest_first=True): +def tx_collate(tx_batches, chain_spec_dict, offset, limit, newest_first=True, verify_contracts=True): """Merges transaction data from multiple sources and sorts them in chronological order. :param tx_batches: Transaction data inputs @@ -196,6 +188,31 @@ def tx_collate(tx_batches, chain_spec_dict, offset, limit, newest_first=True): if newest_first: ks.reverse() for k in ks: - txs.append(txs_by_block[k]) + tx = txs_by_block[k] + if verify_contracts: + try: + tx = verify_and_expand(tx, chain_spec) + except UnknownContractError: + logg.error('verify failed on tx {}, skipping'.format(tx['hash'])) + txs.append(tx) return txs + + +def verify_and_expand(tx, chain_spec): + rpc = RPCConnection.connect(chain_spec, 'default') + registry = CICRegistry(chain_spec, rpc) + + if tx.get('source_token_symbol') == None: + registry.lookup_reverse(tx['source_token']) + token = ERC20Token(chain_spec, rpc, tx['source_token']) + tx['source_token_symbol'] = token.symbol + tx['source_token_decimals'] = token.decimals + + if tx.get('destination_token_symbol') == None: + registry.lookup_reverse(tx['destination_token']) + token = ERC20Token(chain_spec, rpc, tx['destination_token']) + tx['destination_token_symbol'] = token.symbol + tx['destination_token_decimals'] = token.decimals + + return tx diff --git a/apps/cic-eth/tests/task/test_task_list.py b/apps/cic-eth/tests/task/test_task_list.py new file mode 100644 index 00000000..ba5957c2 --- /dev/null +++ b/apps/cic-eth/tests/task/test_task_list.py @@ -0,0 +1,89 @@ +# external imports +import celery +import pytest +from chainlib.connection import RPCConnection +from chainlib.eth.constant import ZERO_ADDRESS +from chainlib.eth.gas import ( + RPCGasOracle, + ) +from chainlib.eth.tx import ( + TxFormat, + unpack, + ) +from chainlib.eth.nonce import RPCNonceOracle +from eth_erc20 import ERC20 +from hexathon import ( + add_0x, + strip_0x, + ) +from chainqueue.db.models.tx import TxCache +from chainqueue.db.models.otx import Otx + + +def test_ext_tx_collate( + default_chain_spec, + init_database, + eth_rpc, + eth_signer, + custodial_roles, + agent_roles, + foo_token, + register_tokens, + cic_registry, + register_lookups, + celery_worker, + ): + + rpc = RPCConnection.connect(default_chain_spec, 'default') + nonce_oracle = RPCNonceOracle(custodial_roles['FOO_TOKEN_GIFTER'], eth_rpc) + gas_oracle = RPCGasOracle(eth_rpc) + + c = ERC20(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle) + transfer_value = 1000 + (tx_hash_hex, tx_signed_raw_hex) = c.transfer(foo_token, custodial_roles['FOO_TOKEN_GIFTER'], agent_roles['ALICE'], transfer_value, tx_format=TxFormat.RLP_SIGNED) + tx = unpack(bytes.fromhex(strip_0x(tx_signed_raw_hex)), default_chain_spec) + + otx = Otx( + tx['nonce'], + tx_hash_hex, + tx_signed_raw_hex, + ) + init_database.add(otx) + init_database.commit() + + txc = TxCache( + tx_hash_hex, + tx['from'], + tx['to'], + foo_token, + foo_token, + transfer_value, + transfer_value, + 666, + 13, + session=init_database, + ) + init_database.add(txc) + init_database.commit() + + s = celery.signature( + 'cic_eth.ext.tx.tx_collate', + [ + {tx_hash_hex: tx_signed_raw_hex}, + default_chain_spec.asdict(), + 0, + 100, + ], + queue=None, + ) + t = s.apply_async() + r = t.get_leaf() + assert t.successful() + + assert len(r) == 1 + + tx = r[0] + assert tx['source_token_symbol'] == 'FOO' + assert tx['source_token_decimals'] == 6 + assert tx['destination_token_symbol'] == 'FOO' + assert tx['destination_token_decimals'] == 6 diff --git a/apps/contract-migration/reset.sh b/apps/contract-migration/reset.sh index 445b1e95..2066e4c5 100755 --- a/apps/contract-migration/reset.sh +++ b/apps/contract-migration/reset.sh @@ -165,4 +165,3 @@ set +e echo -n 2 > $init_level_file exec "$@" -l:83