Skip to content

Commit

Permalink
Problem: erc20 benchmark don't support multiple accounts (#1385)
Browse files Browse the repository at this point in the history
* Problem: erc20 benchmark don't support multiple accounts

Update the benchmark for comparison with block-stm version

* cleanup
  • Loading branch information
yihuang authored Apr 10, 2024
1 parent c5a4c81 commit 7472947
Showing 1 changed file with 85 additions and 28 deletions.
113 changes: 85 additions & 28 deletions app/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package app
import (
"encoding/binary"
"encoding/json"
"math"
"math/big"
"math/rand"
"os"
"path/filepath"
"testing"
Expand All @@ -15,6 +17,7 @@ import (
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
tmtypes "github.com/cometbft/cometbft/types"
baseapp "github.com/cosmos/cosmos-sdk/baseapp"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/testutil/mock"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -46,10 +49,18 @@ func BenchmarkERC20Transfer(b *testing.B) {
})
}

type TestAccount struct {
Address common.Address
Priv cryptotypes.PrivKey
Nonce uint64
}

// pass `nil` to db to use memiavl
func benchmarkERC20Transfer(b *testing.B, db dbm.DB) {
txsPerBlock := 1000
txsPerBlock := 5000
accounts := 100
gasPrice := big.NewInt(100000000000)
bigZero := big.NewInt(0)
var appOpts servertypes.AppOptions = EmptyAppOptions{}
if db == nil {
appOpts = AppOptionsMap(map[string]interface{}{
Expand All @@ -61,18 +72,22 @@ func benchmarkERC20Transfer(b *testing.B, db dbm.DB) {
app := New(log.NewNopLogger(), db, nil, true, true, map[int64]bool{}, DefaultNodeHome, 0, encodingConfig, appOpts, baseapp.SetChainID(TestAppChainID))
defer app.Close()

priv, err := ethsecp256k1.GenerateKey()
address := common.BytesToAddress(priv.PubKey().Address().Bytes())
signer := tests.NewSigner(priv)
chainID := big.NewInt(777)
ethSigner := ethtypes.LatestSignerForChainID(chainID)

signTx := func(msg *evmtypes.MsgEthereumTx) ([]byte, error) {
msg.From = address.Bytes()
if err := msg.Sign(ethSigner, signer); err != nil {
var testAccounts []TestAccount
for i := 0; i < accounts; i++ {
priv, err := ethsecp256k1.GenerateKey()
require.NoError(b, err)
address := common.BytesToAddress(priv.PubKey().Address().Bytes())
testAccounts = append(testAccounts, TestAccount{Address: address, Priv: priv})
}

signTx := func(acc *TestAccount, msg *evmtypes.MsgEthereumTx) ([]byte, error) {
msg.From = acc.Address.Bytes()
if err := msg.Sign(ethSigner, tests.NewSigner(acc.Priv)); err != nil {
return nil, err
}
require.NoError(b, err)
tx, err := msg.BuildTx(encodingConfig.TxConfig.NewTxBuilder(), evmtypes.DefaultEVMDenom)
if err != nil {
return nil, err
Expand All @@ -82,24 +97,47 @@ func benchmarkERC20Transfer(b *testing.B, db dbm.DB) {

privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
consAddress := sdk.ConsAddress(pubKey.Address())
require.NoError(b, err)

consAddress := sdk.ConsAddress(pubKey.Address())
validator := tmtypes.NewValidator(pubKey, 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
acc := authtypes.NewBaseAccount(priv.PubKey().Address().Bytes(), priv.PubKey(), 0, 0)
balance := banktypes.Balance{
Address: acc.GetAddress().String(),
Coins: sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewIntWithDecimal(10000000, 18))),

var (
balances []banktypes.Balance
accs []authtypes.GenesisAccount
)
for _, acc := range testAccounts {
baseAcct := authtypes.NewBaseAccount(acc.Priv.PubKey().Address().Bytes(), acc.Priv.PubKey(), 0, 0)
accs = append(accs, baseAcct)
balances = append(balances, banktypes.Balance{
Address: baseAcct.GetAddress().String(),
Coins: sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewIntWithDecimal(10000000, 18))),
})
}
genesisState := NewDefaultGenesisState(encodingConfig.Codec)
genesisState = genesisStateWithValSet(b, app, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance)
genesisState = genesisStateWithValSet(
b,
app,
genesisState,
valSet,
accs,
balances...,
)

appState, err := json.MarshalIndent(genesisState, "", " ")
require.NoError(b, err)

blockParams := tmproto.BlockParams{
MaxBytes: math.MaxInt64,
MaxGas: math.MaxInt64,
}
consensusParams := *DefaultConsensusParams
consensusParams.Block = &blockParams
app.InitChain(abci.RequestInitChain{
ChainId: TestAppChainID,
AppStateBytes: appState,
ConsensusParams: DefaultConsensusParams,
ConsensusParams: &consensusParams,
})
app.BeginBlock(abci.RequestBeginBlock{
Header: tmproto.Header{
Expand All @@ -114,15 +152,20 @@ func benchmarkERC20Transfer(b *testing.B, db dbm.DB) {
contractAddr, err := app.CronosKeeper.DeployModuleCRC21(ctx, "test")
require.NoError(b, err)

// mint to sender
// mint to senders
amount := int64(100000000)
_, err = app.CronosKeeper.CallModuleCRC21(ctx, contractAddr, "mint_by_cronos_module", address, big.NewInt(amount))
require.NoError(b, err)
{
for _, acc := range testAccounts {
_, err = app.CronosKeeper.CallModuleCRC21(ctx, contractAddr, "mint_by_cronos_module", acc.Address, big.NewInt(amount))
require.NoError(b, err)
}

// check balance
ret, err := app.CronosKeeper.CallModuleCRC21(ctx, contractAddr, "balanceOf", address)
// check balance
ret, err := app.CronosKeeper.CallModuleCRC21(ctx, contractAddr, "balanceOf", testAccounts[0].Address)
require.NoError(b, err)
require.Equal(b, uint64(amount), binary.BigEndian.Uint64(ret[32-8:]))
}
require.NoError(b, err)
require.Equal(b, uint64(amount), binary.BigEndian.Uint64(ret[32-8:]))

app.EndBlock(abci.RequestEndBlock{})
app.Commit()
Expand All @@ -131,11 +174,25 @@ func benchmarkERC20Transfer(b *testing.B, db dbm.DB) {
var transferTxs [][]byte
for i := 0; i < b.N; i++ {
for j := 0; j < txsPerBlock; j++ {
idx := int64(i*txsPerBlock + j)
recipient := common.BigToAddress(big.NewInt(idx))
idx := rand.Int() % len(testAccounts)
acct := &testAccounts[idx]
recipient := common.BigToAddress(big.NewInt(int64(idx)))
data, err := types.ModuleCRC21Contract.ABI.Pack("transfer", recipient, big.NewInt(1))
require.NoError(b, err)
bz, err := signTx(evmtypes.NewTx(chainID, uint64(idx), &contractAddr, big.NewInt(0), 210000, gasPrice, nil, nil, data, nil))
tx := evmtypes.NewTx(
chainID,
acct.Nonce, // nonce
&contractAddr, // to
big.NewInt(0), // value
210000, // gas limit
nil, // gas price
gasPrice, // gasFeeCap
bigZero, // gasTipCap
data, // data
nil, // access list
)
acct.Nonce++
bz, err := signTx(acct, tx)
require.NoError(b, err)
transferTxs = append(transferTxs, bz)
}
Expand All @@ -155,14 +212,14 @@ func benchmarkERC20Transfer(b *testing.B, db dbm.DB) {
res := app.DeliverTx(abci.RequestDeliverTx{
Tx: transferTxs[idx],
})
require.Equal(b, 0, int(res.Code))
require.Equal(b, 0, int(res.Code), res.Log)
}

// check remaining balance
// check remaining balance, only check one account to avoid slow down benchmark itself
ctx := app.GetContextForDeliverTx(nil)
ret, err = app.CronosKeeper.CallModuleCRC21(ctx, contractAddr, "balanceOf", address)
ret, err := app.CronosKeeper.CallModuleCRC21(ctx, contractAddr, "balanceOf", testAccounts[0].Address)
require.NoError(b, err)
require.Equal(b, uint64(amount)-uint64((i+1)*txsPerBlock), binary.BigEndian.Uint64(ret[32-8:]))
require.Equal(b, uint64(amount)-testAccounts[0].Nonce, binary.BigEndian.Uint64(ret[32-8:]))

app.EndBlock(abci.RequestEndBlock{})
app.Commit()
Expand Down

0 comments on commit 7472947

Please sign in to comment.