From 7c7f3f02bb91cac6b2214f58d7120efdd333f656 Mon Sep 17 00:00:00 2001 From: yihuang Date: Mon, 8 Nov 2021 21:04:49 +0800 Subject: [PATCH] tests: add message call benchmark (#717) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> --- scripts/gen-tests-artifacts.sh | 4 ++ .../basic/contracts/TestMessageCall.sol | 25 +++++++++ x/evm/keeper/benchmark_test.go | 47 ++++++++++++++++ x/evm/keeper/keeper_test.go | 55 +++++++++++++++++++ x/evm/types/TestMessageCall.json | 4 ++ x/evm/types/compiled_contract.go | 15 +++++ 6 files changed, 150 insertions(+) create mode 100644 tests/solidity/suites/basic/contracts/TestMessageCall.sol create mode 100644 x/evm/types/TestMessageCall.json diff --git a/scripts/gen-tests-artifacts.sh b/scripts/gen-tests-artifacts.sh index 86a90749..4e602740 100755 --- a/scripts/gen-tests-artifacts.sh +++ b/scripts/gen-tests-artifacts.sh @@ -4,3 +4,7 @@ solc --combined-json bin,abi --allow-paths . ./tests/solidity/suites/staking/contracts/test/mocks/StandardTokenMock.sol \ | jq ".contracts.\"./tests/solidity/suites/staking/contracts/test/mocks/StandardTokenMock.sol:StandardTokenMock\"" \ > x/evm/types/ERC20Contract.json + +solc --combined-json bin,abi --allow-paths . ./tests/solidity/suites/basic/contracts/TestMessageCall.sol \ + | jq ".contracts.\"./tests/solidity/suites/basic/contracts/TestMessageCall.sol:TestMessageCall\"" \ + > x/evm/types/TestMessageCall.json diff --git a/tests/solidity/suites/basic/contracts/TestMessageCall.sol b/tests/solidity/suites/basic/contracts/TestMessageCall.sol new file mode 100644 index 00000000..3f74a518 --- /dev/null +++ b/tests/solidity/suites/basic/contracts/TestMessageCall.sol @@ -0,0 +1,25 @@ +pragma solidity 0.5.17; + +contract Inner { + event TestEvent(uint256); + function test() public returns (uint256) { + emit TestEvent(42); + return 42; + } +} + +contract TestMessageCall { + Inner _inner; + constructor() public { + _inner = new Inner(); + } + + // benchmarks + function benchmarkMessageCall(uint iterations) public returns (uint256) { + uint256 n = 0; + for (uint i=0; i < iterations; i++) { + n += _inner.test(); + } + return n; + } +} diff --git a/x/evm/keeper/benchmark_test.go b/x/evm/keeper/benchmark_test.go index 7d1c80db..c3126815 100644 --- a/x/evm/keeper/benchmark_test.go +++ b/x/evm/keeper/benchmark_test.go @@ -32,6 +32,22 @@ func SetupContract(b *testing.B) (*KeeperTestSuite, common.Address) { return &suite, contractAddr } +func SetupTestMessageCall(b *testing.B) (*KeeperTestSuite, common.Address) { + suite := KeeperTestSuite{} + suite.DoSetupTest(b) + + amt := sdk.Coins{ethermint.NewPhotonCoinInt64(1000000000000000000)} + err := suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, amt) + require.NoError(b, err) + err = suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, suite.address.Bytes(), amt) + require.NoError(b, err) + + contractAddr := suite.DeployTestMessageCall(b) + suite.Commit() + + return &suite, contractAddr +} + type TxBuilder func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx func DoBenchmark(b *testing.B, txBuilder TxBuilder) { @@ -97,6 +113,37 @@ func BenchmarkTokenMint(b *testing.B) { }) } +func BenchmarkMessageCall(b *testing.B) { + suite, contract := SetupTestMessageCall(b) + + input, err := types.TestMessageCall.ABI.Pack("benchmarkMessageCall", big.NewInt(10000)) + require.NoError(b, err) + nonce := suite.app.EvmKeeper.GetNonce(suite.address) + msg := types.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &contract, big.NewInt(0), 25000000, big.NewInt(1), nil, nil, input, nil) + + msg.From = suite.address.Hex() + err = msg.Sign(ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()), suite.signer) + require.NoError(b, err) + + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + ctx, _ := suite.ctx.CacheContext() + + // deduct fee first + txData, err := types.UnpackTxData(msg.Data) + require.NoError(b, err) + + fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdk.NewIntFromBigInt(txData.Fee()))} + err = authante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees) + require.NoError(b, err) + + rsp, err := suite.app.EvmKeeper.EthereumTx(sdk.WrapSDKContext(ctx), msg) + require.NoError(b, err) + require.False(b, rsp.Failed()) + } +} + func DoBenchmarkDeepContextStack(b *testing.B, depth int) { begin := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} end := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index 5f881f34..c76be742 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -311,6 +311,61 @@ func (suite *KeeperTestSuite) TransferERC20Token(t require.TestingT, contractAdd return ercTransferTx } +// DeployTestMessageCall deploy a test erc20 contract and returns the contract address +func (suite *KeeperTestSuite) DeployTestMessageCall(t require.TestingT) common.Address { + ctx := sdk.WrapSDKContext(suite.ctx) + chainID := suite.app.EvmKeeper.ChainID() + + data := types.TestMessageCall.Bin + args, err := json.Marshal(&types.TransactionArgs{ + From: &suite.address, + Data: (*hexutil.Bytes)(&data), + }) + require.NoError(t, err) + + res, err := suite.queryClient.EstimateGas(ctx, &types.EthCallRequest{ + Args: args, + GasCap: uint64(config.DefaultGasCap), + }) + require.NoError(t, err) + + nonce := suite.app.EvmKeeper.GetNonce(suite.address) + + var erc20DeployTx *types.MsgEthereumTx + if suite.dynamicTxFee { + erc20DeployTx = types.NewTxContract( + chainID, + nonce, + nil, // amount + res.Gas, // gasLimit + nil, // gasPrice + suite.app.FeeMarketKeeper.GetBaseFee(suite.ctx), + big.NewInt(1), + data, // input + ðtypes.AccessList{}, // accesses + ) + } else { + erc20DeployTx = types.NewTxContract( + chainID, + nonce, + nil, // amount + res.Gas, // gasLimit + nil, // gasPrice + nil, nil, + data, // input + nil, // accesses + ) + } + + erc20DeployTx.From = suite.address.Hex() + err = erc20DeployTx.Sign(ethtypes.LatestSignerForChainID(chainID), suite.signer) + require.NoError(t, err) + rsp, err := suite.app.EvmKeeper.EthereumTx(ctx, erc20DeployTx) + require.NoError(t, err) + require.Empty(t, rsp.VmError) + return crypto.CreateAddress(suite.address, nonce) +} + func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } diff --git a/x/evm/types/TestMessageCall.json b/x/evm/types/TestMessageCall.json new file mode 100644 index 00000000..616ae16a --- /dev/null +++ b/x/evm/types/TestMessageCall.json @@ -0,0 +1,4 @@ +{ + "abi": "[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"iterations\",\"type\":\"uint256\"}],\"name\":\"benchmarkMessageCall\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + "bin": "608060405234801561001057600080fd5b5060405161001d9061007e565b604051809103906000f080158015610039573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061008a565b60dd8061021483390190565b61017b806100996000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c806376e489f014610030575b600080fd5b61005c6004803603602081101561004657600080fd5b8101908080359060200190929190505050610072565b6040518082815260200191505060405180910390f35b6000806000905060008090505b8381101561013c576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f8a8fd6d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156100f057600080fd5b505af1158015610104573d6000803e3d6000fd5b505050506040513d602081101561011a57600080fd5b810190808051906020019092919050505082019150808060010191505061007f565b508091505091905056fea265627a7a723158203bb5ea1d2b128eb07e834f8b4cab93aab73270ef20cb80c1d5e0e2ee4f10b7c264736f6c634300051100326080604052348015600f57600080fd5b5060bf8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063f8a8fd6d14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b60007f1440c4dd67b4344ea1905ec0318995133b550f168b4ee959a0da6b503d7d2414602a6040518082815260200191505060405180910390a1602a90509056fea265627a7a723158209236549244199cceaef9525385c8b6fccaf6390440ece080e2046d9f4a0035f564736f6c63430005110032" +} diff --git a/x/evm/types/compiled_contract.go b/x/evm/types/compiled_contract.go index e83ee459..19fb0b4e 100644 --- a/x/evm/types/compiled_contract.go +++ b/x/evm/types/compiled_contract.go @@ -74,6 +74,12 @@ var ( // ERC20Contract is the compiled test erc20 contract ERC20Contract CompiledContract + + //go:embed TestMessageCall.json + testMessageCallJSON []byte + + // TestMessageCall is the compiled message call benchmark contract + TestMessageCall CompiledContract ) func init() { @@ -85,4 +91,13 @@ func init() { if len(ERC20Contract.Bin) == 0 { panic("load contract failed") } + + err = json.Unmarshal(testMessageCallJSON, &TestMessageCall) + if err != nil { + panic(err) + } + + if len(TestMessageCall.Bin) == 0 { + panic("load contract failed") + } }