From 64b3312668b5399991b6e209b95e3cc746d5f1d4 Mon Sep 17 00:00:00 2001 From: HuangYi Date: Fri, 14 Jan 2022 15:57:26 +0800 Subject: [PATCH] Problem: batched eth tx is not tested Closes: #305 - add batch tx integration test --- integration_tests/cosmoscli.py | 21 ++++++++-- integration_tests/test_basic.py | 71 +++++++++++++++++++++++++++++++++ integration_tests/utils.py | 9 ++++- 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/integration_tests/cosmoscli.py b/integration_tests/cosmoscli.py index a68b2b53f1..1bbe422f4a 100644 --- a/integration_tests/cosmoscli.py +++ b/integration_tests/cosmoscli.py @@ -496,10 +496,9 @@ def combine_batch_multisig_tx( ) return r.decode("utf-8") - def broadcast_tx(self, tx_file): - r = self.raw( - "tx", "broadcast", tx_file, node=self.node_rpc, broadcast_mode="block" - ) + def broadcast_tx(self, tx_file, **kwargs): + kwargs.setdefault("broadcast_mode", "block") + r = self.raw("tx", "broadcast", tx_file, node=self.node_rpc, **kwargs) return r.decode("utf-8") def unjail(self, addr): @@ -1012,3 +1011,17 @@ def update_token_mapping(self, denom, contract, **kwargs): **kwargs, ) ) + + def build_evm_tx(self, raw_tx: str, **kwargs): + return json.loads( + self.raw( + "tx", + "evm", + "raw", + raw_tx, + "-y", + "--generate-only", + home=self.data_dir, + **kwargs, + ) + ) diff --git a/integration_tests/test_basic.py b/integration_tests/test_basic.py index 1f430e35c8..322169bda1 100644 --- a/integration_tests/test_basic.py +++ b/integration_tests/test_basic.py @@ -1,4 +1,6 @@ import concurrent.futures +import json +import tempfile import time from pathlib import Path @@ -15,9 +17,11 @@ KEYS, Greeter, RevertTestContract, + contract_address, contract_path, deploy_contract, send_transaction, + sign_transaction, wait_for_block, wait_for_port, ) @@ -454,3 +458,70 @@ def test_suicide(cluster): assert receipt.status == 1 assert len(w3.eth.get_code(destroyee.address)) == 0 + + +def test_batch_tx(cronos): + "send multiple eth txs in single cosmos tx" + w3 = cronos.w3 + sender = ADDRS["validator"] + recipient = ADDRS["community"] + nonce = w3.eth.get_transaction_count(sender) + info = json.load(open(CONTRACTS["TestERC20Utility"])) + contract = w3.eth.contract(abi=info["abi"], bytecode=info["bytecode"]) + deploy_tx = contract.constructor().buildTransaction( + {"from": sender, "nonce": nonce} + ) + contract = w3.eth.contract(address=contract_address(sender, nonce), abi=info["abi"]) + transfer_tx1 = contract.functions.transfer(recipient, 1000).buildTransaction( + {"from": sender, "nonce": nonce + 1} + ) + transfer_tx2 = contract.functions.transfer(recipient, 1000).buildTransaction( + {"from": sender, "nonce": nonce + 2} + ) + + signed_txs = [ + sign_transaction(w3, deploy_tx, KEYS["validator"]), + sign_transaction(w3, transfer_tx1, KEYS["validator"]), + sign_transaction(w3, transfer_tx2, KEYS["validator"]), + ] + tmp_txs = [ + cronos.cosmos_cli().build_evm_tx(signed.rawTransaction.hex()) + for signed in signed_txs + ] + + msgs = [tx["body"]["messages"][0] for tx in tmp_txs] + fee = sum(int(tx["auth_info"]["fee"]["amount"][0]["amount"]) for tx in tmp_txs) + gas_limit = sum(int(tx["auth_info"]["fee"]["gas_limit"]) for tx in tmp_txs) + + # build batch cosmos tx + cosmos_tx = { + "body": { + "messages": msgs, + "memo": "", + "timeout_height": "0", + "extension_options": [ + {"@type": "/ethermint.evm.v1.ExtensionOptionsEthereumTx"} + ], + "non_critical_extension_options": [], + }, + "auth_info": { + "signer_infos": [], + "fee": { + "amount": [{"denom": "basetcro", "amount": str(fee)}], + "gas_limit": str(gas_limit), + "payer": "", + "granter": "", + }, + }, + "signatures": [], + } + with tempfile.NamedTemporaryFile("w") as fp: + json.dump(cosmos_tx, fp) + fp.flush() + rsp = cronos.cosmos_cli().broadcast_tx(fp.name) + print("rsp", rsp) + + receipts = [ + w3.eth.wait_for_transaction_receipt(signed.hash) for signed in signed_txs + ] + print("receipts", receipts) diff --git a/integration_tests/utils.py b/integration_tests/utils.py index 01bc4635a0..c205874d64 100644 --- a/integration_tests/utils.py +++ b/integration_tests/utils.py @@ -339,12 +339,17 @@ def deploy_contract(w3, jsonfile, args=(), key=KEYS["validator"]): return w3.eth.contract(address=address, abi=info["abi"]) -def send_transaction(w3, tx, key=KEYS["validator"]): +def sign_transaction(w3, tx, key=KEYS["validator"]): + "fill default fields and sign" acct = Account.from_key(key) tx["from"] = acct.address tx = fill_transaction_defaults(w3, tx) tx = fill_nonce(w3, tx) - signed = acct.sign_transaction(tx) + return acct.sign_transaction(tx) + + +def send_transaction(w3, tx, key=KEYS["validator"]): + signed = sign_transaction(w3, tx, key) txhash = w3.eth.send_raw_transaction(signed.rawTransaction) return w3.eth.wait_for_transaction_receipt(txhash)