tests: add message call benchmark (#717)

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
yihuang 2021-11-08 21:04:49 +08:00 committed by GitHub
parent e04422b6ff
commit 7c7f3f02bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 150 additions and 0 deletions

View File

@ -4,3 +4,7 @@
solc --combined-json bin,abi --allow-paths . ./tests/solidity/suites/staking/contracts/test/mocks/StandardTokenMock.sol \ 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\"" \ | jq ".contracts.\"./tests/solidity/suites/staking/contracts/test/mocks/StandardTokenMock.sol:StandardTokenMock\"" \
> x/evm/types/ERC20Contract.json > 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

View File

@ -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;
}
}

View File

@ -32,6 +32,22 @@ func SetupContract(b *testing.B) (*KeeperTestSuite, common.Address) {
return &suite, contractAddr 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 type TxBuilder func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx
func DoBenchmark(b *testing.B, txBuilder TxBuilder) { 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) { func DoBenchmarkDeepContextStack(b *testing.B, depth int) {
begin := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} begin := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
end := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} end := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}

View File

@ -311,6 +311,61 @@ func (suite *KeeperTestSuite) TransferERC20Token(t require.TestingT, contractAdd
return ercTransferTx 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
&ethtypes.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) { func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite)) suite.Run(t, new(KeeperTestSuite))
} }

View File

@ -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"
}

View File

@ -74,6 +74,12 @@ var (
// ERC20Contract is the compiled test erc20 contract // ERC20Contract is the compiled test erc20 contract
ERC20Contract CompiledContract ERC20Contract CompiledContract
//go:embed TestMessageCall.json
testMessageCallJSON []byte
// TestMessageCall is the compiled message call benchmark contract
TestMessageCall CompiledContract
) )
func init() { func init() {
@ -85,4 +91,13 @@ func init() {
if len(ERC20Contract.Bin) == 0 { if len(ERC20Contract.Bin) == 0 {
panic("load contract failed") panic("load contract failed")
} }
err = json.Unmarshal(testMessageCallJSON, &TestMessageCall)
if err != nil {
panic(err)
}
if len(TestMessageCall.Bin) == 0 {
panic("load contract failed")
}
} }