Skip to content

Commit

Permalink
Merge pull request #331 from eosnetworkfoundation/elmato/merge-kayan_…
Browse files Browse the repository at this point in the history
…evmtx_order_test-to-main

[1.0 ->main] integration test for evmtx order
  • Loading branch information
elmato authored Nov 20, 2024
2 parents dbe52a1 + 01d8588 commit afb2f46
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 2 deletions.
3 changes: 3 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ configure_file(defertest.wasm . COPYONLY)
configure_file(defertest.abi . COPYONLY)
configure_file(defertest2.wasm . COPYONLY)
configure_file(defertest2.abi . COPYONLY)
configure_file(evmbridge.wasm . COPYONLY)
configure_file(evmbridge.abi . COPYONLY)

64 changes: 64 additions & 0 deletions tests/evmbridge.abi
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT ",
"version": "eosio::abi/1.2",
"types": [
{
"new_type_name": "bridge_message",
"type": "variant_bridge_message_v0"
}
],
"structs": [
{
"name": "bridge_message_v0",
"base": "",
"fields": [
{
"name": "receiver",
"type": "name"
},
{
"name": "sender",
"type": "bytes"
},
{
"name": "timestamp",
"type": "time_point"
},
{
"name": "value",
"type": "bytes"
},
{
"name": "data",
"type": "bytes"
}
]
},
{
"name": "onbridgemsg",
"base": "",
"fields": [
{
"name": "message",
"type": "bridge_message"
}
]
}
],
"actions": [
{
"name": "onbridgemsg",
"type": "onbridgemsg",
"ricardian_contract": ""
}
],
"tables": [],
"ricardian_clauses": [],
"variants": [
{
"name": "variant_bridge_message_v0",
"types": ["bridge_message_v0"]
}
],
"action_results": []
}
69 changes: 69 additions & 0 deletions tests/evmbridge.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <vector>
#include <variant>
#include <eosio/eosio.hpp>
#include <eosio/contract.hpp>

using namespace eosio;
using namespace std;

extern "C" {
__attribute__((eosio_wasm_import))
void set_action_return_value(void*, size_t);

__attribute__((eosio_wasm_import))
uint64_t get_sender();
}

typedef std::vector<char> bytes;

struct bridge_message_v0 {
name receiver;
bytes sender;
time_point timestamp;
bytes value;
bytes data;

EOSLIB_SERIALIZE(bridge_message_v0, (receiver)(sender)(timestamp)(value)(data));
};

using bridge_message = std::variant<bridge_message_v0>;

class [[eosio::contract("evmbridge")]] evmbridge : public contract {
public:
using contract::contract;
[[eosio::action]] void onbridgemsg(const bridge_message& message);


class contract_actions {
public:
void call(eosio::name from, const bytes &to, const bytes& value, const bytes &data, uint64_t gas_limit);
void assertnonce(eosio::name account, uint64_t next_nonce);
};

using call_action = action_wrapper<"call"_n, &contract_actions::call>;
};

void evmbridge::onbridgemsg(const bridge_message& message) {
const bridge_message_v0 &msg = std::get<bridge_message_v0>(message);
const char method[4] = {'\x00','\x8f','\xcf','\x3e'}; // function assertdata(uint256) payable

uint8_t value_buffer[32] = {};

if (msg.data.size() >= 32) {
std::copy(msg.data.end() - 32, msg.data.end(), value_buffer);
}

bytes call_data;
call_data.reserve(4 + 32);
call_data.insert(call_data.end(), method, method + 4);
call_data.insert(call_data.end(), value_buffer, value_buffer + 32);

call_action call_act("eosio.evm"_n, {{get_self(), "active"_n}});

bytes value;
value.resize(32, 0);
value[31] = 100;

call_act.send(get_self() /*from*/, msg.sender /*to*/, value /*value*/, call_data /*data*/, 100000 /*gas_limit*/);
}

Binary file added tests/evmbridge.wasm
Binary file not shown.
93 changes: 91 additions & 2 deletions tests/nodeos_eos_evm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ def prefix_0x(hexstr):
evmRPCPOpen = None
eosEvmMinerPOpen = None

def assert_contract_exist(contract_addr):
Utils.Print("ensure contract {0} exist".format(contract_addr))
if contract_addr[:2] == '0x':
contract_addr = contract_addr[2:]
rows=prodNode.getTable(evmAcc.name, evmAcc.name, "account")
for row in rows['rows']:
if (str(contract_addr) == str(row['eth_address'])):
assert row['code_id'] is not None, "contract {0} should exist".format(contract_addr)
return True
Utils.Print("evm account table rows: " + json.dumps(rows))
assert False, "contract {0} should exist".format(contract_addr)

def interact_with_storage_contract(dest, nonce):
for i in range(1, 5): # execute a few
Utils.Print("Execute ETH contract")
Expand Down Expand Up @@ -291,7 +303,7 @@ def toDict(dictToParse):
prodNode = cluster.getNode(0)
nonProdNode = cluster.getNode(1)

accounts=createAccountKeys(6)
accounts=createAccountKeys(7)
if accounts is None:
Utils.errorExit("FAILURE - create keys")

Expand All @@ -303,10 +315,13 @@ def toDict(dictToParse):
defertest2Acc = accounts[4]
aliceAcc = accounts[5]

accounts[6].name = "evmbridge"
evmbridgeAcc = accounts[6]

testWalletName="test"

Print("Creating wallet \"%s\"." % (testWalletName))
testWallet=walletMgr.create(testWalletName, [cluster.eosioAccount,accounts[0],accounts[1],accounts[2],accounts[3],accounts[4]])
testWallet=walletMgr.create(testWalletName, [cluster.eosioAccount,accounts[0],accounts[1],accounts[2],accounts[3],accounts[4],accounts[5],accounts[6]])

addys = {
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266":"0x038318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed75,0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
Expand Down Expand Up @@ -356,6 +371,15 @@ def toDict(dictToParse):
Utils.Print(f"Publish defertest2 contract {contractDir}/{wasmFile} to account {defertest2Acc}")
prodNode.publishContract(defertest2Acc, contractDir, wasmFile, abiFile, waitForTransBlock=True)

contractDir=eosEvmBuildRoot + "/tests"
wasmFile="evmbridge.wasm"
abiFile="evmbridge.abi"
Utils.Print(f"Publish evmbridge contract {contractDir}/{wasmFile} to account {evmbridgeAcc}")
prodNode.publishContract(evmbridgeAcc, contractDir, wasmFile, abiFile, waitForTransBlock=True)
# add eosio.code evmbridge
cmd="set account permission evmbridge active --add-code -p evmbridge@active"
prodNode.processCleosCmd(cmd, cmd, silentErrors=True, returnType=ReturnType.raw)

# add eosio.code permission to defertest2 account
cmd="set account permission " + defertest2Acc.name + " active --add-code -p " + defertest2Acc.name + "@active"
prodNode.processCleosCmd(cmd, cmd, silentErrors=False, returnType=ReturnType.raw)
Expand Down Expand Up @@ -527,6 +551,7 @@ def toDict(dictToParse):
actData = {"miner":minerAcc.name, "rlptx":Web3.to_hex(get_raw_transaction(signed_trx))[2:]}
retValue = prodNode.pushMessage(evmAcc.name, "pushtx", json.dumps(actData), '-p {0}'.format(minerAcc.name), silentErrors=True)
assert retValue[0], f"push trx should have succeeded: {retValue}"
assert_contract_exist(makeContractAddress(fromAdd, nonce))
nonce = interact_with_storage_contract(makeContractAddress(fromAdd, nonce), nonce)

if genesisJson[0] != '/': genesisJson = os.path.realpath(genesisJson)
Expand Down Expand Up @@ -820,6 +845,7 @@ def toDict(dictToParse):


# Launch eos-evm-node
Utils.Print("===== laucnhing eos-evm-node & eos-evm-rpc =====")
dataDir = Utils.DataDir + "eos_evm"
nodeStdOutDir = dataDir + "/eos-evm-node.stdout"
nodeStdErrDir = dataDir + "/eos-evm-node.stderr"
Expand Down Expand Up @@ -901,6 +927,69 @@ def get_block(num):
nonProdNode.transferFunds(cluster.eosioAccount, evmAcc, "111.0000 EOS", "0xB106D2C286183FFC3D1F0C4A6f0753bB20B407c2", waitForTransBlock=True)
time.sleep(2)

### evmtx event order test
Utils.Print("Test evmtx event order via evmbridge contract")
# // SPDX-License-Identifier: GPL-3.0
# pragma solidity >=0.7.0 <0.9.0;
# contract BridgeTest {
# uint256 number;
# constructor() {
# number = 41;
# }
# function assertdata(uint256 expect) payable public {
# require(number == expect, "assertdata failed");
# number = number + 1;
# }
# function sendbridgemsg() payable public {
# number = number + 1;
# bytes memory receiver_msg = abi.encodeWithSignature("test(uint256)", number);
# address evmaddr = 0xbBBBbBbbbBBBBbbbbbbBBbBB5530EA015b900000;//eosio.evm
# (bool success, ) = evmaddr.call{value: msg.value}(
# abi.encodeWithSignature("bridgeMsgV0(string,bool,bytes)", "evmbridge", true, receiver_msg ));
# if(!success) { revert(); }
# }
# }
#
nonce += 1
evmChainId = 15555
gasP = getGasPrice()
signed_trx = w3.eth.account.sign_transaction(dict(
nonce=nonce,
gas=5000000,
gasPrice=gasP,
data=Web3.to_bytes(hexstr='608060405234801561001057600080fd5b5060296000819055506105b2806100286000396000f3fe6080604052600436106100285760003560e01c80628fcf3e1461002d57806386bf4eff14610049575b600080fd5b610047600480360381019061004291906102b8565b610053565b005b6100516100af565b005b8060005414610097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161008e90610342565b60405180910390fd5b60016000546100a69190610391565b60008190555050565b60016000546100be9190610391565b600081905550600080546040516024016100d891906103d4565b6040516020818303038152906040527f29e99f07000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600073bbbbbbbbbbbbbbbbbbbbbbbb5530ea015b900000905060008173ffffffffffffffffffffffffffffffffffffffff163460018560405160240161019e9291906104e6565b6040516020818303038152906040527ff781185b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516102289190610565565b60006040518083038185875af1925050503d8060008114610265576040519150601f19603f3d011682016040523d82523d6000602084013e61026a565b606091505b505090508061027857600080fd5b505050565b600080fd5b6000819050919050565b61029581610282565b81146102a057600080fd5b50565b6000813590506102b28161028c565b92915050565b6000602082840312156102ce576102cd61027d565b5b60006102dc848285016102a3565b91505092915050565b600082825260208201905092915050565b7f61737365727464617461206661696c6564000000000000000000000000000000600082015250565b600061032c6011836102e5565b9150610337826102f6565b602082019050919050565b6000602082019050818103600083015261035b8161031f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061039c82610282565b91506103a783610282565b92508282019050808211156103bf576103be610362565b5b92915050565b6103ce81610282565b82525050565b60006020820190506103e960008301846103c5565b92915050565b7f65766d6272696467650000000000000000000000000000000000000000000000600082015250565b60006104256009836102e5565b9150610430826103ef565b602082019050919050565b60008115159050919050565b6104508161043b565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610490578082015181840152602081019050610475565b60008484015250505050565b6000601f19601f8301169050919050565b60006104b882610456565b6104c28185610461565b93506104d2818560208601610472565b6104db8161049c565b840191505092915050565b600060608201905081810360008301526104ff81610418565b905061050e6020830185610447565b818103604083015261052081846104ad565b90509392505050565b600081905092915050565b600061053f82610456565b6105498185610529565b9350610559818560208601610472565b80840191505092915050565b60006105718284610534565b91508190509291505056fea2646970667358221220ac18e6f72606f415174ea5fa2cf02da58e2ec7af6b59282e166efa50f79aef3164736f6c63430008120033'),
chainId=evmChainId
), evmSendKey)
actData = {"miner":minerAcc.name, "rlptx":Web3.to_hex(get_raw_transaction(signed_trx))[2:]}
retValue = prodNode.pushMessage(evmAcc.name, "pushtx", json.dumps(actData), '-p {0}'.format(minerAcc.name), silentErrors=True)
assert retValue[0], f"push trx should have succeeded: {retValue}"
bridgemsgcontractaddr = makeContractAddress("9E126C57330FA71556628e0aabd6B6B6783d99fA", nonce)
assert_contract_exist(bridgemsgcontractaddr)
Utils.Print("bridge msg contract addr is:" + str(bridgemsgcontractaddr))
row4=prodNode.getTableRow(evmAcc.name, evmAcc.name, "account", 4) # 4th balance of this integration test
Utils.Print("\taccount row4: ", row4)

Utils.Print("call bridgereg in evm runtime contract for account evmbridge")
prodNode.pushMessage(evmAcc.name, "bridgereg", '["evmbridge","evmbridge","1.0000 EOS"]', '-p {0} -p evmbridge'.format(evmAcc.name), silentErrors=False)

Utils.Print("push EVM trx to trigger bridgemsg from EVM to notify evmbridge account")
amount=1.0000
nonce += 1
signed_trx = w3.eth.account.sign_transaction(dict(
nonce=nonce,
gas=100000,
gasPrice=gasP,
to=Web3.to_checksum_address(bridgemsgcontractaddr),
data=Web3.to_bytes(hexstr='86bf4eff'), #function sendbridgemsg()
value=int(amount*10000*szabo*100),
chainId=evmChainId
), evmSendKey)
actData = {"miner":minerAcc.name, "rlptx":Web3.to_hex(get_raw_transaction(signed_trx))[2:]}
retValue = prodNode.pushMessage(evmAcc.name, "pushtx", json.dumps(actData), '-p {0}'.format(minerAcc.name), silentErrors=False)
assert retValue[0], f"push trx to bridge msg contract should have succeeded: {retValue}"
row4=prodNode.getTableRow(evmAcc.name, evmAcc.name, "account", 4) # 4th balance of this integration test
Utils.Print("\taccount row4: ", row4)

# update gas parameter
Utils.Print("Update gas parameter: ram price = 100 EOS per MB, gas price = 900Gwei")
trans = prodNode.pushMessage(evmAcc.name, "updtgasparam", json.dumps({"ram_price_mb":"100.0000 EOS","gas_price":900000000000}), '-p {0}'.format(evmAcc.name), silentErrors=False)
Expand Down

0 comments on commit afb2f46

Please sign in to comment.