Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Commit

Permalink
imp, ci: address pending issues from EVM simulation (#1063)
Browse files Browse the repository at this point in the history
* add note

fix note

* add TestAppStateFn TestRandomAccounts

* marshal int slice to json

* add paramschange for enableCreate and enableCall

* AppStateFn -> StateFn

* add TestDecodeStore

* update github actions to run evm simulation

* add TestParamChanges

* add TestRandomizedGenState

* use go install for runsim

* resolve conflict

* use random gasCap to estimate gas

* use estimateGas to calculate max transferableAmount

* update godoc

* TestAppStateFn -> TestStateFn

* Update x/evm/simulation/genesis.go

* comment

Co-authored-by: Federico Kunze Küllmer <[email protected]>
Co-authored-by: Federico Kunze Küllmer <[email protected]>
  • Loading branch information
3 people authored May 2, 2022
1 parent c25669c commit 4ea9b6d
Show file tree
Hide file tree
Showing 12 changed files with 348 additions and 27 deletions.
80 changes: 80 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,84 @@ jobs:
- name: Test e2e
run: |
make test-integration
if: env.GIT_DIFF

test-sim-nondeterminism:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.17
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/[email protected]
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Test x/evm simulation nondeterminism
run: |
make test-sim-nondeterminism
if: env.GIT_DIFF

test-sim-random-genesis-fast:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.17
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/[email protected]
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Test x/evm simulation with random genesis
run: |
make test-sim-random-genesis-fast
if: env.GIT_DIFF

test-sim-import-export:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.17
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/[email protected]
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Test x/evm simulation import and export
run: |
make test-sim-import-export
if: env.GIT_DIFF

test-sim-after-import:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.17
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/[email protected]
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Test x/evm simulation after import
run: |
make test-sim-after-import
if: env.GIT_DIFF
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
* Move `rpc/ethereum/backend` -> `rpc/backend`
* Move `rpc/ethereum/namespaces` -> `rpc/namespaces/ethereum`

### Improvements

* (ci, evm) [tharsis#1063](https://github.com/tharsis/ethermint/pull/1063) Run simulations on CI.

### Bug Fixes

* (rpc) [tharsis#1059](https://github.com/tharsis/ethermint/pull/1059) Remove unnecessary event filtering logic on the `eth_baseFee` JSON-RPC endpoint.
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ RUNSIM = $(TOOLS_DESTDIR)/runsim
runsim: $(RUNSIM)
$(RUNSIM):
@echo "Installing runsim..."
@(cd /tmp && ${GO_MOD} go get github.com/cosmos/tools/cmd/runsim@master)
@(cd /tmp && ${GO_MOD} go install github.com/cosmos/tools/cmd/runsim@master)

statik: $(STATIK)
$(STATIK):
Expand Down Expand Up @@ -343,7 +343,7 @@ test-sim-nondeterminism:
-NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h

test-sim-random-genesis-fast:
@echo "Running custom genesis simulation..."
@echo "Running random genesis simulation..."
@go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation \
-Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h

Expand Down
2 changes: 1 addition & 1 deletion app/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func RandomAccounts(r *rand.Rand, n int) []simtypes.Account {

prv := secp256k1.GenPrivKeyFromSecret(privkeySeed)
ethPrv := &ethsecp256k1.PrivKey{}
_ = ethPrv.UnmarshalAmino(prv.Bytes())
_ = ethPrv.UnmarshalAmino(prv.Bytes()) // UnmarshalAmino simply copies the bytes and assigns them to ethPrv.Key
accs[i].PrivKey = ethPrv
accs[i].PubKey = accs[i].PrivKey.PubKey()
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
Expand Down
56 changes: 56 additions & 0 deletions app/utils_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package app

import (
"encoding/json"
"math/rand"
"os"
"testing"

"github.com/stretchr/testify/require"
Expand All @@ -11,7 +13,10 @@ import (
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
evmtypes "github.com/tharsis/ethermint/x/evm/types"

"github.com/tharsis/ethermint/crypto/ethsecp256k1"
ethermint "github.com/tharsis/ethermint/types"

"github.com/cosmos/cosmos-sdk/simapp"
Expand Down Expand Up @@ -53,3 +58,54 @@ func TestRandomGenesisAccounts(t *testing.T) {
require.True(t, ok)
}
}

func TestStateFn(t *testing.T) {
config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
if skip {
t.Skip("skipping AppStateFn testing")
}
require.NoError(t, err, "simulation setup failed")

config.ChainID = SimAppChainID
config.Commit = true

defer func() {
db.Close()
require.NoError(t, os.RemoveAll(dir))
}()

app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
require.Equal(t, appName, app.Name())

appStateFn := StateFn(app.AppCodec(), app.SimulationManager())
r := rand.New(rand.NewSource(seed))
accounts := RandomAccounts(r, rand.Intn(maxTestingAccounts))
appState, _, _, _ := appStateFn(r, accounts, config)

rawState := make(map[string]json.RawMessage)
err = json.Unmarshal(appState, &rawState)
require.NoError(t, err)

stakingStateBz, ok := rawState[stakingtypes.ModuleName]
require.True(t, ok)

stakingState := new(stakingtypes.GenesisState)
app.AppCodec().MustUnmarshalJSON(stakingStateBz, stakingState)
bondDenom := stakingState.Params.BondDenom

evmStateBz, ok := rawState[evmtypes.ModuleName]
require.True(t, ok)

evmState := new(evmtypes.GenesisState)
app.AppCodec().MustUnmarshalJSON(evmStateBz, evmState)
require.Equal(t, bondDenom, evmState.Params.EvmDenom)
}

func TestRandomAccounts(t *testing.T) {
r := rand.New(rand.NewSource(seed))
accounts := RandomAccounts(r, rand.Intn(maxTestingAccounts))
for _, acc := range accounts {
_, ok := acc.PrivKey.(*ethsecp256k1.PrivKey)
require.True(t, ok)
}
}
12 changes: 6 additions & 6 deletions x/evm/simulation/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ import (
)

// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
// Value to the corresponding evm type.
// value to the corresponding EVM type.
func NewDecodeStore() func(kvA, kvB kv.Pair) string {
return func(kvA, kvB kv.Pair) string {
switch {
case bytes.Equal(kvA.Key[:1], types.KeyPrefixStorage):
storageHashA := common.BytesToHash(kvA.Value).Hex()
storageHashB := common.BytesToHash(kvB.Value).Hex()
storageA := common.BytesToHash(kvA.Value).Hex()
storageB := common.BytesToHash(kvB.Value).Hex()

return fmt.Sprintf("%v\n%v", storageHashA, storageHashB)
return fmt.Sprintf("%v\n%v", storageA, storageB)
case bytes.Equal(kvA.Key[:1], types.KeyPrefixCode):
codeHashA := common.BytesToHash(kvA.Value).Hex()
codeHashB := common.BytesToHash(kvB.Value).Hex()
codeHashA := common.Bytes2Hex(kvA.Value)
codeHashB := common.Bytes2Hex(kvB.Value)

return fmt.Sprintf("%v\n%v", codeHashA, codeHashB)
default:
Expand Down
47 changes: 47 additions & 0 deletions x/evm/simulation/decoder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package simulation

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/ethereum/go-ethereum/common"
"github.com/tharsis/ethermint/x/evm/types"
)

// TestDecodeStore tests that evm simulation decoder decodes the key value pairs as expected.
func TestDecodeStore(t *testing.T) {
dec := NewDecodeStore()

hash := common.BytesToHash([]byte("hash"))
code := common.Bytes2Hex([]byte{1, 2, 3})

kvPairs := kv.Pairs{
Pairs: []kv.Pair{
{Key: types.KeyPrefixCode, Value: common.FromHex(code)},
{Key: types.KeyPrefixStorage, Value: hash.Bytes()},
},
}

tests := []struct {
name string
expectedLog string
}{
{"Code", fmt.Sprintf("%v\n%v", code, code)},
{"Storage", fmt.Sprintf("%v\n%v", hash, hash)},
{"other", ""},
}
for i, tt := range tests {
i, tt := i, tt
t.Run(tt.name, func(t *testing.T) {
switch i {
case len(tests) - 1:
require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name)
default:
require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name)
}
})
}
}
36 changes: 31 additions & 5 deletions x/evm/simulation/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,44 @@ import (
"github.com/tharsis/ethermint/x/evm/types"
)

// GenExtraEIPs randomly generates specific extra eips or not.
func genExtraEIPs(r *rand.Rand) []int64 {
const (
extraEIPsKey = "extra_eips"
)

// GenExtraEIPs defines a set of extra EIPs with 50% probability
func GenExtraEIPs(r *rand.Rand) []int64 {
var extraEIPs []int64
if r.Uint32()%2 == 0 {
// 50% chance of having extra EIPs
if r.Intn(2) == 0 {
extraEIPs = []int64{1344, 1884, 2200, 2929, 3198, 3529}
}
return extraEIPs
}

// RandomizedGenState generates a random GenesisState for nft
// GenEnableCreate enables the EnableCreate param with 80% probability
func GenEnableCreate(r *rand.Rand) bool {
// 80% chance of enabling create contract
enableCreate := r.Intn(100) < 80
return enableCreate
}

// GenEnableCall enables the EnableCall param with 80% probability
func GenEnableCall(r *rand.Rand) bool {
// 80% chance of enabling evm account transfer and calling contract
enableCall := r.Intn(100) < 80
return enableCall
}

// RandomizedGenState generates a random GenesisState for the EVM module
func RandomizedGenState(simState *module.SimulationState) {
extraEIPs := genExtraEIPs(simState.Rand)
// evm params
var extraEIPs []int64

simState.AppParams.GetOrGenerate(
simState.Cdc, extraEIPsKey, &extraEIPs, simState.Rand,
func(r *rand.Rand) { extraEIPs = GenExtraEIPs(r) },
)

params := types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig(), extraEIPs...)
evmGenesis := types.NewGenesisState(params, []types.GenesisAccount{})

Expand Down
50 changes: 50 additions & 0 deletions x/evm/simulation/genesis_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package simulation_test

import (
"encoding/json"
"math/rand"
"testing"

"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/tharsis/ethermint/x/evm/simulation"
"github.com/tharsis/ethermint/x/evm/types"
)

// TestRandomizedGenState tests the normal scenario of applying RandomizedGenState.
// Abonormal scenarios are not tested here.
func TestRandomizedGenState(t *testing.T) {
registry := codectypes.NewInterfaceRegistry()
types.RegisterInterfaces(registry)
cdc := codec.NewProtoCodec(registry)

s := rand.NewSource(1)
r := rand.New(s)

simState := module.SimulationState{
AppParams: make(simtypes.AppParams),
Cdc: cdc,
Rand: r,
NumBonded: 3,
Accounts: simtypes.RandomAccounts(r, 3),
InitialStake: 1000,
GenState: make(map[string]json.RawMessage),
}

simulation.RandomizedGenState(&simState)

var evmGenesis types.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &evmGenesis)

require.Equal(t, true, evmGenesis.Params.GetEnableCreate())
require.Equal(t, true, evmGenesis.Params.GetEnableCall())
require.Equal(t, types.DefaultEVMDenom, evmGenesis.Params.GetEvmDenom())
require.Equal(t, simulation.GenExtraEIPs(r), evmGenesis.Params.GetExtraEIPs())
require.Equal(t, types.DefaultChainConfig(), evmGenesis.Params.GetChainConfig())

require.Equal(t, len(evmGenesis.Accounts), 0)
}
Loading

0 comments on commit 4ea9b6d

Please sign in to comment.