-
Notifications
You must be signed in to change notification settings - Fork 559
benchmark contract execution #436
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package keeper_test | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante" | ||
"github.com/ethereum/go-ethereum/common" | ||
|
||
ethtypes "github.com/ethereum/go-ethereum/core/types" | ||
ethermint "github.com/tharsis/ethermint/types" | ||
"github.com/tharsis/ethermint/x/evm/types" | ||
) | ||
|
||
func SetupContract(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.DeployTestContract(b, suite.address, sdk.NewIntWithDecimal(1000, 18).BigInt()) | ||
suite.Commit() | ||
|
||
return &suite, contractAddr | ||
} | ||
|
||
type TxBuilder func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx | ||
|
||
func DoBenchmark(b *testing.B, txBuilder TxBuilder) { | ||
suite, contractAddr := SetupContract(b) | ||
|
||
msg := txBuilder(suite, contractAddr) | ||
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 BenchmarkTokenTransfer(b *testing.B) { | ||
DoBenchmark(b, func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx { | ||
input, err := ContractABI.Pack("transfer", 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) | ||
}) | ||
} | ||
|
||
func BenchmarkEmitLogs(b *testing.B) { | ||
DoBenchmark(b, func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx { | ||
input, err := ContractABI.Pack("benchmarkLogs", 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), 4100000, big.NewInt(1), input, nil) | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
package keeper_test | ||
|
||
import ( | ||
_ "embed" | ||
"encoding/json" | ||
"math/big" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/require" | ||
"github.com/stretchr/testify/suite" | ||
|
||
"github.com/cosmos/cosmos-sdk/baseapp" | ||
|
@@ -20,19 +24,46 @@ import ( | |
"github.com/tharsis/ethermint/app" | ||
"github.com/tharsis/ethermint/crypto/ethsecp256k1" | ||
"github.com/tharsis/ethermint/encoding" | ||
"github.com/tharsis/ethermint/server/config" | ||
"github.com/tharsis/ethermint/tests" | ||
ethermint "github.com/tharsis/ethermint/types" | ||
"github.com/tharsis/ethermint/x/evm/types" | ||
|
||
"github.com/ethereum/go-ethereum/accounts/abi" | ||
"github.com/ethereum/go-ethereum/common" | ||
ethcmn "github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/common/hexutil" | ||
ethtypes "github.com/ethereum/go-ethereum/core/types" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
ethcrypto "github.com/ethereum/go-ethereum/crypto" | ||
|
||
abci "github.com/tendermint/tendermint/abci/types" | ||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types" | ||
) | ||
|
||
var ( | ||
//go:embed ERC20Contract.json | ||
compiledContractJSON []byte | ||
ContractBin []byte | ||
ContractABI abi.ABI | ||
) | ||
|
||
func init() { | ||
var tmp struct { | ||
Abi string | ||
Bin string | ||
} | ||
err := json.Unmarshal(compiledContractJSON, &tmp) | ||
if err != nil { | ||
panic(err) | ||
} | ||
ContractBin = common.FromHex(tmp.Bin) | ||
err = json.Unmarshal([]byte(tmp.Abi), &ContractABI) | ||
if err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
var testTokens = sdk.NewIntWithDecimal(1000, 18) | ||
|
||
type KeeperTestSuite struct { | ||
|
@@ -52,18 +83,19 @@ type KeeperTestSuite struct { | |
signer keyring.Signer | ||
} | ||
|
||
func (suite *KeeperTestSuite) SetupTest() { | ||
/// DoSetupTest setup test environment, it uses`require.TestingT` to support both `testing.T` and `testing.B`. | ||
func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit, can you add a comment on why you are using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also on why you are using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To make it work on both testing.B and testing.T. Added a line of comment to explain. |
||
checkTx := false | ||
|
||
// account key | ||
priv, err := ethsecp256k1.GenerateKey() | ||
suite.Require().NoError(err) | ||
require.NoError(t, err) | ||
suite.address = ethcmn.BytesToAddress(priv.PubKey().Address().Bytes()) | ||
suite.signer = tests.NewSigner(priv) | ||
|
||
// consensus key | ||
priv, err = ethsecp256k1.GenerateKey() | ||
suite.Require().NoError(err) | ||
require.NoError(t, err) | ||
suite.consAddress = sdk.ConsAddress(priv.PubKey().Address()) | ||
|
||
suite.app = app.Setup(checkTx) | ||
|
@@ -89,9 +121,9 @@ func (suite *KeeperTestSuite) SetupTest() { | |
valAddr := sdk.ValAddress(suite.address.Bytes()) | ||
validator, err := stakingtypes.NewValidator(valAddr, priv.PubKey(), stakingtypes.Description{}) | ||
err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator) | ||
suite.Require().NoError(err) | ||
require.NoError(t, err) | ||
err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator) | ||
suite.Require().NoError(err) | ||
require.NoError(t, err) | ||
suite.app.StakingKeeper.SetValidator(suite.ctx, validator) | ||
|
||
encodingConfig := encoding.MakeConfig(app.ModuleBasics) | ||
|
@@ -101,13 +133,20 @@ func (suite *KeeperTestSuite) SetupTest() { | |
|
||
// mint some tokens to coinbase address | ||
_, bankKeeper := suite.initKeepersWithmAccPerms() | ||
ctx := sdk.WrapSDKContext(suite.ctx) | ||
rsp, err := suite.queryClient.Params(ctx, &types.QueryParamsRequest{}) | ||
suite.Require().NoError(err) | ||
initCoin := sdk.NewCoins(sdk.NewCoin(rsp.Params.EvmDenom, testTokens)) | ||
|
||
require.NoError(t, err) | ||
initCoin := sdk.NewCoins(sdk.NewCoin(suite.EvmDenom(), testTokens)) | ||
err = simapp.FundAccount(bankKeeper, suite.ctx, acc.GetAddress(), initCoin) | ||
suite.Require().NoError(err) | ||
require.NoError(t, err) | ||
} | ||
|
||
func (suite *KeeperTestSuite) SetupTest() { | ||
suite.DoSetupTest(suite.T()) | ||
} | ||
|
||
func (suite *KeeperTestSuite) EvmDenom() string { | ||
ctx := sdk.WrapSDKContext(suite.ctx) | ||
rsp, _ := suite.queryClient.Params(ctx, &types.QueryParamsRequest{}) | ||
return rsp.Params.EvmDenom | ||
} | ||
|
||
// Commit and begin new block | ||
|
@@ -146,6 +185,46 @@ func (suite *KeeperTestSuite) initKeepersWithmAccPerms() (authkeeper.AccountKeep | |
return authKeeper, keeper | ||
} | ||
|
||
// DeployTestContract deploy a test erc20 contract and returns the contract address | ||
func (suite *KeeperTestSuite) DeployTestContract(t require.TestingT, owner common.Address, supply *big.Int) common.Address { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. curious of why we are using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To make it work on both Added a line of comment to explain. |
||
ctx := sdk.WrapSDKContext(suite.ctx) | ||
chainID := suite.app.EvmKeeper.ChainID() | ||
|
||
ctorArgs, err := ContractABI.Pack("", owner, supply) | ||
require.NoError(t, err) | ||
|
||
data := append(ContractBin, ctorArgs...) | ||
args, err := json.Marshal(&types.CallArgs{ | ||
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) | ||
erc20DeployTx := types.NewTxContract( | ||
chainID, | ||
nonce, | ||
nil, // amount | ||
res.Gas, // gasLimit | ||
nil, // gasPrice | ||
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)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why cache context here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make each run independent, we don't want to mutate the shared storage for each runs.