diff --git a/CHANGELOG.md b/CHANGELOG.md index eb90a9ec..3c4ed353 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (evm) [tharsis#461](https://github.com/tharsis/ethermint/pull/461) Increase performance of `StateDB` transaction log storage (r/w). * (evm) [tharsis#566](https://github.com/tharsis/ethermint/pull/566) Introduce `stateErr` store in `StateDB` to avoid meaningless operations if any error happened before +* (evm) [tharsis#586](https://github.com/tharsis/ethermint/pull/586) Benchmark evm keeper ## [v0.5.0] - 2021-08-20 diff --git a/x/evm/keeper/benchmark_test.go b/x/evm/keeper/benchmark_test.go index 4ae6bddd..66cfeffd 100644 --- a/x/evm/keeper/benchmark_test.go +++ b/x/evm/keeper/benchmark_test.go @@ -77,3 +77,21 @@ func BenchmarkEmitLogs(b *testing.B) { return types.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &contract, big.NewInt(0), 4100000, big.NewInt(1), input, nil) }) } + +func BenchmarkTokenTransferFrom(b *testing.B) { + DoBenchmark(b, func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx { + input, err := ContractABI.Pack("transferFrom", suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(0)) + require.NoError(b, err) + nonce := suite.app.EvmKeeper.GetNonce(suite.address) + return types.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &contract, big.NewInt(0), 410000, big.NewInt(1), input, nil) + }) +} + +func BenchmarkTokenMint(b *testing.B) { + DoBenchmark(b, func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx { + input, err := ContractABI.Pack("mint", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000)) + require.NoError(b, err) + nonce := suite.app.EvmKeeper.GetNonce(suite.address) + return types.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &contract, big.NewInt(0), 410000, big.NewInt(1), input, nil) + }) +} diff --git a/x/evm/keeper/state_transition_benchmark_test.go b/x/evm/keeper/state_transition_benchmark_test.go new file mode 100644 index 00000000..54ac09c8 --- /dev/null +++ b/x/evm/keeper/state_transition_benchmark_test.go @@ -0,0 +1,220 @@ +package keeper_test + +import ( + "errors" + "math/big" + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + "github.com/stretchr/testify/require" + evmtypes "github.com/tharsis/ethermint/x/evm/types" +) + +var templateAccessListTx = ðtypes.AccessListTx{ + GasPrice: big.NewInt(1), + Gas: 21000, + To: &common.Address{}, + Value: big.NewInt(0), + Data: []byte{}, +} + +var templateLegacyTx = ðtypes.LegacyTx{ + GasPrice: big.NewInt(1), + Gas: 21000, + To: &common.Address{}, + Value: big.NewInt(0), + Data: []byte{}, +} + +func newSignedEthTx( + txData ethtypes.TxData, + nonce uint64, + addr sdk.Address, + krSigner keyring.Signer, + ethSigner ethtypes.Signer, +) (*ethtypes.Transaction, error) { + var ethTx *ethtypes.Transaction + switch txData := txData.(type) { + case *ethtypes.AccessListTx: + txData.Nonce = nonce + ethTx = ethtypes.NewTx(txData) + case *ethtypes.LegacyTx: + txData.Nonce = nonce + ethTx = ethtypes.NewTx(txData) + default: + return nil, errors.New("unknown transaction type!") + } + + sig, _, err := krSigner.SignByAddress(addr, ethTx.Hash().Bytes()) + if err != nil { + return nil, err + } + + ethTx, err = ethTx.WithSignature(ethSigner, sig) + if err != nil { + return nil, err + } + + return ethTx, nil +} + +func newNativeMessage( + nonce uint64, + blockHeight int64, + address common.Address, + cfg *params.ChainConfig, + krSigner keyring.Signer, + ethSigner ethtypes.Signer, + isLegacy bool, +) (core.Message, error) { + msgSigner := ethtypes.MakeSigner(cfg, big.NewInt(blockHeight)) + + var ethTx *ethtypes.Transaction + if isLegacy { + templateLegacyTx.Nonce = nonce + ethTx = ethtypes.NewTx(templateLegacyTx) + } else { + templateAccessListTx.Nonce = nonce + ethTx = ethtypes.NewTx(templateAccessListTx) + } + + msg := &evmtypes.MsgEthereumTx{} + msg.FromEthereumTx(ethTx) + msg.From = address.Hex() + + if err := msg.Sign(ethSigner, krSigner); err != nil { + return nil, err + } + + m, err := msg.AsMessage(msgSigner) + if err != nil { + return nil, err + } + + return m, nil +} + +func BenchmarkApplyTransaction(b *testing.B) { + suite := KeeperTestSuite{} + suite.DoSetupTest(b) + + ethSigner := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()) + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + b.StopTimer() + tx, err := newSignedEthTx(templateAccessListTx, + suite.app.EvmKeeper.GetNonce(suite.address), + sdk.AccAddress(suite.address.Bytes()), + suite.signer, + ethSigner, + ) + require.NoError(b, err) + + b.StartTimer() + resp, err := suite.app.EvmKeeper.ApplyTransaction(tx) + b.StopTimer() + + require.NoError(b, err) + require.False(b, resp.Failed()) + } +} + +func BenchmarkApplyTransactionWithLegacyTx(b *testing.B) { + suite := KeeperTestSuite{} + suite.DoSetupTest(b) + + ethSigner := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()) + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + b.StopTimer() + tx, err := newSignedEthTx(templateLegacyTx, + suite.app.EvmKeeper.GetNonce(suite.address), + sdk.AccAddress(suite.address.Bytes()), + suite.signer, + ethSigner, + ) + require.NoError(b, err) + + b.StartTimer() + resp, err := suite.app.EvmKeeper.ApplyTransaction(tx) + b.StopTimer() + + require.NoError(b, err) + require.False(b, resp.Failed()) + } +} + +func BenchmarkApplyNativeMessage(b *testing.B) { + suite := KeeperTestSuite{} + suite.DoSetupTest(b) + + params := suite.app.EvmKeeper.GetParams(suite.ctx) + ethCfg := params.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID()) + signer := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()) + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + b.StopTimer() + + m, err := newNativeMessage( + suite.app.EvmKeeper.GetNonce(suite.address), + suite.ctx.BlockHeight(), + suite.address, + ethCfg, + suite.signer, + signer, + false, + ) + require.NoError(b, err) + + b.StartTimer() + resp, err := suite.app.EvmKeeper.ApplyNativeMessage(m) + b.StopTimer() + + require.NoError(b, err) + require.False(b, resp.Failed()) + } +} + +func BenchmarkApplyNativeMessageWithLegacyTx(b *testing.B) { + suite := KeeperTestSuite{} + suite.DoSetupTest(b) + + params := suite.app.EvmKeeper.GetParams(suite.ctx) + ethCfg := params.ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID()) + signer := ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()) + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + b.StopTimer() + + m, err := newNativeMessage( + suite.app.EvmKeeper.GetNonce(suite.address), + suite.ctx.BlockHeight(), + suite.address, + ethCfg, + suite.signer, + signer, + true, + ) + require.NoError(b, err) + + b.StartTimer() + resp, err := suite.app.EvmKeeper.ApplyNativeMessage(m) + b.StopTimer() + + require.NoError(b, err) + require.False(b, resp.Failed()) + } +} diff --git a/x/evm/keeper/statedb_benchmark_test.go b/x/evm/keeper/statedb_benchmark_test.go index 10ddf7fb..baaa27a4 100644 --- a/x/evm/keeper/statedb_benchmark_test.go +++ b/x/evm/keeper/statedb_benchmark_test.go @@ -126,3 +126,57 @@ func BenchmarkSnapshot(b *testing.B) { }) } } + +func BenchmarkSubBalance(b *testing.B) { + suite := KeeperTestSuite{} + suite.DoSetupTest(b) + + amt := big.NewInt(10) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + suite.app.EvmKeeper.SubBalance(suite.address, amt) + } +} + +func BenchmarkSetNonce(b *testing.B) { + suite := KeeperTestSuite{} + suite.DoSetupTest(b) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + suite.app.EvmKeeper.SetNonce(suite.address, 1) + } +} + +func BenchmarkAddRefund(b *testing.B) { + suite := KeeperTestSuite{} + suite.DoSetupTest(b) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + suite.app.EvmKeeper.AddRefund(1) + } +} + +func BenchmarkSuicide(b *testing.B) { + suite := KeeperTestSuite{} + suite.DoSetupTest(b) + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + b.StopTimer() + addr := tests.GenerateAddress() + suite.app.EvmKeeper.CreateAccount(addr) + b.StartTimer() + + suite.app.EvmKeeper.Suicide(addr) + } +}