imp, ci: address pending issues from EVM simulation (#1063)
* 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 <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze Küllmer <federico.kunze94@gmail.com>
This commit is contained in:
parent
c25669c761
commit
4ea9b6dc6d
80
.github/workflows/test.yml
vendored
80
.github/workflows/test.yml
vendored
@ -118,3 +118,83 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make test-integration
|
make test-integration
|
||||||
if: env.GIT_DIFF
|
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/get-diff-action@v6.0.1
|
||||||
|
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/get-diff-action@v6.0.1
|
||||||
|
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/get-diff-action@v6.0.1
|
||||||
|
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/get-diff-action@v6.0.1
|
||||||
|
with:
|
||||||
|
PATTERNS: |
|
||||||
|
**/**.go
|
||||||
|
go.mod
|
||||||
|
go.sum
|
||||||
|
- name: Test x/evm simulation after import
|
||||||
|
run: |
|
||||||
|
make test-sim-after-import
|
||||||
|
if: env.GIT_DIFF
|
@ -47,6 +47,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||||||
* Move `rpc/ethereum/backend` -> `rpc/backend`
|
* Move `rpc/ethereum/backend` -> `rpc/backend`
|
||||||
* Move `rpc/ethereum/namespaces` -> `rpc/namespaces/ethereum`
|
* 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
|
### Bug Fixes
|
||||||
|
|
||||||
* (rpc) [tharsis#1059](https://github.com/tharsis/ethermint/pull/1059) Remove unnecessary event filtering logic on the `eth_baseFee` JSON-RPC endpoint.
|
* (rpc) [tharsis#1059](https://github.com/tharsis/ethermint/pull/1059) Remove unnecessary event filtering logic on the `eth_baseFee` JSON-RPC endpoint.
|
||||||
|
4
Makefile
4
Makefile
@ -201,7 +201,7 @@ RUNSIM = $(TOOLS_DESTDIR)/runsim
|
|||||||
runsim: $(RUNSIM)
|
runsim: $(RUNSIM)
|
||||||
$(RUNSIM):
|
$(RUNSIM):
|
||||||
@echo "Installing 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: $(STATIK)
|
||||||
$(STATIK):
|
$(STATIK):
|
||||||
@ -343,7 +343,7 @@ test-sim-nondeterminism:
|
|||||||
-NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h
|
-NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h
|
||||||
|
|
||||||
test-sim-random-genesis-fast:
|
test-sim-random-genesis-fast:
|
||||||
@echo "Running custom genesis simulation..."
|
@echo "Running random genesis simulation..."
|
||||||
@go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation \
|
@go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation \
|
||||||
-Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h
|
-Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ func RandomAccounts(r *rand.Rand, n int) []simtypes.Account {
|
|||||||
|
|
||||||
prv := secp256k1.GenPrivKeyFromSecret(privkeySeed)
|
prv := secp256k1.GenPrivKeyFromSecret(privkeySeed)
|
||||||
ethPrv := ðsecp256k1.PrivKey{}
|
ethPrv := ðsecp256k1.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].PrivKey = ethPrv
|
||||||
accs[i].PubKey = accs[i].PrivKey.PubKey()
|
accs[i].PubKey = accs[i].PrivKey.PubKey()
|
||||||
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
|
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -11,7 +13,10 @@ import (
|
|||||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
paramstypes "github.com/cosmos/cosmos-sdk/x/params/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"
|
ethermint "github.com/tharsis/ethermint/types"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/simapp"
|
"github.com/cosmos/cosmos-sdk/simapp"
|
||||||
@ -53,3 +58,54 @@ func TestRandomGenesisAccounts(t *testing.T) {
|
|||||||
require.True(t, ok)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,18 +10,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
|
// 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 {
|
func NewDecodeStore() func(kvA, kvB kv.Pair) string {
|
||||||
return func(kvA, kvB kv.Pair) string {
|
return func(kvA, kvB kv.Pair) string {
|
||||||
switch {
|
switch {
|
||||||
case bytes.Equal(kvA.Key[:1], types.KeyPrefixStorage):
|
case bytes.Equal(kvA.Key[:1], types.KeyPrefixStorage):
|
||||||
storageHashA := common.BytesToHash(kvA.Value).Hex()
|
storageA := common.BytesToHash(kvA.Value).Hex()
|
||||||
storageHashB := common.BytesToHash(kvB.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):
|
case bytes.Equal(kvA.Key[:1], types.KeyPrefixCode):
|
||||||
codeHashA := common.BytesToHash(kvA.Value).Hex()
|
codeHashA := common.Bytes2Hex(kvA.Value)
|
||||||
codeHashB := common.BytesToHash(kvB.Value).Hex()
|
codeHashB := common.Bytes2Hex(kvB.Value)
|
||||||
|
|
||||||
return fmt.Sprintf("%v\n%v", codeHashA, codeHashB)
|
return fmt.Sprintf("%v\n%v", codeHashA, codeHashB)
|
||||||
default:
|
default:
|
||||||
|
47
x/evm/simulation/decoder_test.go
Normal file
47
x/evm/simulation/decoder_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -10,18 +10,44 @@ import (
|
|||||||
"github.com/tharsis/ethermint/x/evm/types"
|
"github.com/tharsis/ethermint/x/evm/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenExtraEIPs randomly generates specific extra eips or not.
|
const (
|
||||||
func genExtraEIPs(r *rand.Rand) []int64 {
|
extraEIPsKey = "extra_eips"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenExtraEIPs defines a set of extra EIPs with 50% probability
|
||||||
|
func GenExtraEIPs(r *rand.Rand) []int64 {
|
||||||
var extraEIPs []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}
|
extraEIPs = []int64{1344, 1884, 2200, 2929, 3198, 3529}
|
||||||
}
|
}
|
||||||
return extraEIPs
|
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) {
|
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...)
|
params := types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig(), extraEIPs...)
|
||||||
evmGenesis := types.NewGenesisState(params, []types.GenesisAccount{})
|
evmGenesis := types.NewGenesisState(params, []types.GenesisAccount{})
|
||||||
|
|
||||||
|
50
x/evm/simulation/genesis_test.go
Normal file
50
x/evm/simulation/genesis_test.go
Normal file
@ -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)
|
||||||
|
}
|
@ -25,7 +25,6 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/x/auth/signing"
|
"github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/tharsis/ethermint/encoding"
|
"github.com/tharsis/ethermint/encoding"
|
||||||
"github.com/tharsis/ethermint/server/config"
|
|
||||||
"github.com/tharsis/ethermint/tests"
|
"github.com/tharsis/ethermint/tests"
|
||||||
"github.com/tharsis/ethermint/x/evm/keeper"
|
"github.com/tharsis/ethermint/x/evm/keeper"
|
||||||
"github.com/tharsis/ethermint/x/evm/types"
|
"github.com/tharsis/ethermint/x/evm/types"
|
||||||
@ -203,10 +202,12 @@ func SimulateEthTx(
|
|||||||
|
|
||||||
// CreateRandomValidEthTx create the ethereum tx with valid random values
|
// CreateRandomValidEthTx create the ethereum tx with valid random values
|
||||||
func CreateRandomValidEthTx(ctx *simulateContext, from, to *common.Address, amount *big.Int, data *hexutil.Bytes) (ethTx *types.MsgEthereumTx, err error) {
|
func CreateRandomValidEthTx(ctx *simulateContext, from, to *common.Address, amount *big.Int, data *hexutil.Bytes) (ethTx *types.MsgEthereumTx, err error) {
|
||||||
estimateGas, err := EstimateGas(ctx, from, to, data)
|
gasCap := ctx.rand.Uint64()
|
||||||
|
estimateGas, err := EstimateGas(ctx, from, to, data, gasCap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// we suppose that gasLimit should be larger than estimateGas to ensure tx validity
|
||||||
gasLimit := estimateGas + uint64(ctx.rand.Intn(int(sdktx.MaxGasWanted-estimateGas)))
|
gasLimit := estimateGas + uint64(ctx.rand.Intn(int(sdktx.MaxGasWanted-estimateGas)))
|
||||||
ethChainID := ctx.keeper.ChainID()
|
ethChainID := ctx.keeper.ChainID()
|
||||||
chainConfig := ctx.keeper.GetParams(ctx.context).ChainConfig.EthereumConfig(ethChainID)
|
chainConfig := ctx.keeper.GetParams(ctx.context).ChainConfig.EthereumConfig(ethChainID)
|
||||||
@ -216,7 +217,7 @@ func CreateRandomValidEthTx(ctx *simulateContext, from, to *common.Address, amou
|
|||||||
nonce := ctx.keeper.GetNonce(ctx.context, *from)
|
nonce := ctx.keeper.GetNonce(ctx.context, *from)
|
||||||
|
|
||||||
if amount == nil {
|
if amount == nil {
|
||||||
amount, err = RandomTransferableAmount(ctx, *from, gasLimit, gasFeeCap)
|
amount, err = RandomTransferableAmount(ctx, *from, estimateGas, gasFeeCap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -228,7 +229,7 @@ func CreateRandomValidEthTx(ctx *simulateContext, from, to *common.Address, amou
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EstimateGas estimates the gas used by quering the keeper.
|
// EstimateGas estimates the gas used by quering the keeper.
|
||||||
func EstimateGas(ctx *simulateContext, from, to *common.Address, data *hexutil.Bytes) (gas uint64, err error) {
|
func EstimateGas(ctx *simulateContext, from, to *common.Address, data *hexutil.Bytes, gasCap uint64) (gas uint64, err error) {
|
||||||
args, err := json.Marshal(&types.TransactionArgs{To: to, From: from, Data: data})
|
args, err := json.Marshal(&types.TransactionArgs{To: to, From: from, Data: data})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@ -236,7 +237,7 @@ func EstimateGas(ctx *simulateContext, from, to *common.Address, data *hexutil.B
|
|||||||
|
|
||||||
res, err := ctx.keeper.EstimateGas(sdk.WrapSDKContext(ctx.context), &types.EthCallRequest{
|
res, err := ctx.keeper.EstimateGas(sdk.WrapSDKContext(ctx.context), &types.EthCallRequest{
|
||||||
Args: args,
|
Args: args,
|
||||||
GasCap: config.DefaultGasCap,
|
GasCap: gasCap,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@ -246,9 +247,9 @@ func EstimateGas(ctx *simulateContext, from, to *common.Address, data *hexutil.B
|
|||||||
|
|
||||||
// RandomTransferableAmount generates a random valid transferable amount.
|
// RandomTransferableAmount generates a random valid transferable amount.
|
||||||
// Transferable amount is between the range [0, spendable), spendable = balance - gasFeeCap * GasLimit.
|
// Transferable amount is between the range [0, spendable), spendable = balance - gasFeeCap * GasLimit.
|
||||||
func RandomTransferableAmount(ctx *simulateContext, address common.Address, gasLimit uint64, gasFeeCap *big.Int) (amount *big.Int, err error) {
|
func RandomTransferableAmount(ctx *simulateContext, address common.Address, estimateGas uint64, gasFeeCap *big.Int) (amount *big.Int, err error) {
|
||||||
balance := ctx.keeper.GetBalance(ctx.context, address)
|
balance := ctx.keeper.GetBalance(ctx.context, address)
|
||||||
feeLimit := new(big.Int).Mul(gasFeeCap, big.NewInt(int64(gasLimit)))
|
feeLimit := new(big.Int).Mul(gasFeeCap, big.NewInt(int64(estimateGas)))
|
||||||
if (feeLimit.Cmp(balance)) > 0 {
|
if (feeLimit.Cmp(balance)) > 0 {
|
||||||
return nil, ErrNoEnoughBalance
|
return nil, ErrNoEnoughBalance
|
||||||
}
|
}
|
||||||
|
@ -6,22 +6,35 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
|
amino "github.com/cosmos/cosmos-sdk/codec"
|
||||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||||
"github.com/tharsis/ethermint/x/evm/types"
|
"github.com/tharsis/ethermint/x/evm/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
keyExtraEIPs = "ExtraEIPs"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ParamChanges defines the parameters that can be modified by param change proposals
|
// ParamChanges defines the parameters that can be modified by param change proposals
|
||||||
// on the simulation.
|
// on the simulation.
|
||||||
func ParamChanges(r *rand.Rand) []simtypes.ParamChange {
|
func ParamChanges(r *rand.Rand) []simtypes.ParamChange {
|
||||||
return []simtypes.ParamChange{
|
return []simtypes.ParamChange{
|
||||||
simulation.NewSimParamChange(types.ModuleName, keyExtraEIPs,
|
simulation.NewSimParamChange(types.ModuleName, string(types.ParamStoreKeyExtraEIPs),
|
||||||
func(r *rand.Rand) string {
|
func(r *rand.Rand) string {
|
||||||
return fmt.Sprintf("\"%d\"", genExtraEIPs(r))
|
extraEIPs := GenExtraEIPs(r)
|
||||||
|
amino := amino.NewLegacyAmino()
|
||||||
|
bz, err := amino.MarshalJSON(extraEIPs)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return string(bz)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
simulation.NewSimParamChange(types.ModuleName, string(types.ParamStoreKeyEnableCreate),
|
||||||
|
func(r *rand.Rand) string {
|
||||||
|
return fmt.Sprintf("%v", GenEnableCreate(r))
|
||||||
|
},
|
||||||
|
),
|
||||||
|
simulation.NewSimParamChange(types.ModuleName, string(types.ParamStoreKeyEnableCall),
|
||||||
|
func(r *rand.Rand) string {
|
||||||
|
return fmt.Sprintf("%v", GenEnableCall(r))
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
44
x/evm/simulation/params_test.go
Normal file
44
x/evm/simulation/params_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package simulation_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/tharsis/ethermint/x/evm/simulation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestParamChanges tests the paramChanges are generated as expected.
|
||||||
|
func TestParamChanges(t *testing.T) {
|
||||||
|
s := rand.NewSource(1)
|
||||||
|
r := rand.New(s)
|
||||||
|
|
||||||
|
extraEIPs := simulation.GenExtraEIPs(r)
|
||||||
|
bz, err := json.Marshal(extraEIPs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expected := []struct {
|
||||||
|
composedKey string
|
||||||
|
key string
|
||||||
|
simValue string
|
||||||
|
subspace string
|
||||||
|
}{
|
||||||
|
{"evm/EnableExtraEIPs", "EnableExtraEIPs", string(bz), "evm"},
|
||||||
|
{"evm/EnableCreate", "EnableCreate", fmt.Sprintf("%v", simulation.GenEnableCreate(r)), "evm"},
|
||||||
|
{"evm/EnableCall", "EnableCall", fmt.Sprintf("%v", simulation.GenEnableCall(r)), "evm"},
|
||||||
|
}
|
||||||
|
|
||||||
|
paramChanges := simulation.ParamChanges(r)
|
||||||
|
|
||||||
|
require.Len(t, paramChanges, 3)
|
||||||
|
|
||||||
|
for i, p := range paramChanges {
|
||||||
|
require.Equal(t, expected[i].composedKey, p.ComposedKey())
|
||||||
|
require.Equal(t, expected[i].key, p.Key())
|
||||||
|
require.Equal(t, expected[i].simValue, p.SimValue()(r))
|
||||||
|
require.Equal(t, expected[i].subspace, p.Subspace())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user