29d3abcf09
* Reuse cosmos-sdk client library to create keyring Extracted from https://github.com/evmos/ethermint/pull/1168 Cleanup cmd code for easier to migration to cosmos-sdk 0.46 * Update cosmos-sdk v0.46 prepare for implementing cosmos-sdk feemarket and tx prioritization changelog refactor cmd use sdkmath fix lint fix unit tests fix unit test genesis fix unit tests fix unit test env setup fix unit tests fix unit tests register PrivKey impl fix extension options fix lint fix unit tests make HandlerOption.Validate private gofumpt fix msg response decoding fix sim test bump cosmos-sdk version fix sim test sdk 46 fix unit test fix unit tests update ibc-go
268 lines
9.4 KiB
Go
268 lines
9.4 KiB
Go
package app
|
|
|
|
import (
|
|
"encoding/json"
|
|
"math/rand"
|
|
"time"
|
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
|
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
|
"github.com/cosmos/cosmos-sdk/simapp"
|
|
"github.com/cosmos/cosmos-sdk/testutil/mock"
|
|
"github.com/cosmos/cosmos-sdk/types/module"
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
|
|
|
"github.com/evmos/ethermint/encoding"
|
|
ethermint "github.com/evmos/ethermint/types"
|
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
|
|
|
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/evmos/ethermint/crypto/ethsecp256k1"
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
|
dbm "github.com/tendermint/tm-db"
|
|
)
|
|
|
|
// DefaultConsensusParams defines the default Tendermint consensus params used in
|
|
// EthermintApp testing.
|
|
var DefaultConsensusParams = &abci.ConsensusParams{
|
|
Block: &abci.BlockParams{
|
|
MaxBytes: 200000,
|
|
MaxGas: -1, // no limit
|
|
},
|
|
Evidence: &tmproto.EvidenceParams{
|
|
MaxAgeNumBlocks: 302400,
|
|
MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration
|
|
MaxBytes: 10000,
|
|
},
|
|
Validator: &tmproto.ValidatorParams{
|
|
PubKeyTypes: []string{
|
|
tmtypes.ABCIPubKeyTypeEd25519,
|
|
},
|
|
},
|
|
}
|
|
|
|
// Setup initializes a new EthermintApp. A Nop logger is set in EthermintApp.
|
|
func Setup(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState) *EthermintApp {
|
|
return SetupWithDB(isCheckTx, patchGenesis, dbm.NewMemDB())
|
|
}
|
|
|
|
// SetupWithDB initializes a new EthermintApp. A Nop logger is set in EthermintApp.
|
|
func SetupWithDB(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState, db dbm.DB) *EthermintApp {
|
|
app := NewEthermintApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
|
if !isCheckTx {
|
|
// init chain must be called to stop deliverState from being nil
|
|
genesisState := NewTestGenesisState(app.AppCodec())
|
|
if patchGenesis != nil {
|
|
genesisState = patchGenesis(app, genesisState)
|
|
}
|
|
|
|
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Initialize the chain
|
|
app.InitChain(
|
|
abci.RequestInitChain{
|
|
ChainId: "ethermint_9000-1",
|
|
Validators: []abci.ValidatorUpdate{},
|
|
ConsensusParams: DefaultConsensusParams,
|
|
AppStateBytes: stateBytes,
|
|
},
|
|
)
|
|
}
|
|
|
|
return app
|
|
}
|
|
|
|
// RandomGenesisAccounts is used by the auth module to create random genesis accounts in simulation when a genesis.json is not specified.
|
|
// In contrast, the default auth module's RandomGenesisAccounts implementation creates only base accounts and vestings accounts.
|
|
func RandomGenesisAccounts(simState *module.SimulationState) authtypes.GenesisAccounts {
|
|
emptyCodeHash := crypto.Keccak256(nil)
|
|
genesisAccs := make(authtypes.GenesisAccounts, len(simState.Accounts))
|
|
for i, acc := range simState.Accounts {
|
|
bacc := authtypes.NewBaseAccountWithAddress(acc.Address)
|
|
|
|
ethacc := ðermint.EthAccount{
|
|
BaseAccount: bacc,
|
|
CodeHash: common.BytesToHash(emptyCodeHash).String(),
|
|
}
|
|
genesisAccs[i] = ethacc
|
|
}
|
|
|
|
return genesisAccs
|
|
}
|
|
|
|
// RandomAccounts creates random accounts with an ethsecp256k1 private key
|
|
// TODO: replace secp256k1.GenPrivKeyFromSecret() with similar function in go-ethereum
|
|
func RandomAccounts(r *rand.Rand, n int) []simtypes.Account {
|
|
accs := make([]simtypes.Account, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
// don't need that much entropy for simulation
|
|
privkeySeed := make([]byte, 15)
|
|
_, _ = r.Read(privkeySeed)
|
|
|
|
prv := secp256k1.GenPrivKeyFromSecret(privkeySeed)
|
|
ethPrv := ðsecp256k1.PrivKey{}
|
|
_ = 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())
|
|
|
|
accs[i].ConsKey = ed25519.GenPrivKeyFromSecret(privkeySeed)
|
|
}
|
|
|
|
return accs
|
|
}
|
|
|
|
// StateFn returns the initial application state using a genesis or the simulation parameters.
|
|
// It is a wrapper of simapp.AppStateFn to replace evm param EvmDenom with staking param BondDenom.
|
|
func StateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simtypes.AppStateFn {
|
|
return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config,
|
|
) (appState json.RawMessage, simAccs []simtypes.Account, chainID string, genesisTimestamp time.Time) {
|
|
appStateFn := simapp.AppStateFn(cdc, simManager)
|
|
appState, simAccs, chainID, genesisTimestamp = appStateFn(r, accs, config)
|
|
|
|
rawState := make(map[string]json.RawMessage)
|
|
err := json.Unmarshal(appState, &rawState)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
stakingStateBz, ok := rawState[stakingtypes.ModuleName]
|
|
if !ok {
|
|
panic("staking genesis state is missing")
|
|
}
|
|
|
|
stakingState := new(stakingtypes.GenesisState)
|
|
cdc.MustUnmarshalJSON(stakingStateBz, stakingState)
|
|
|
|
// we should get the BondDenom and make it the evmdenom.
|
|
// thus simulation accounts could have positive amount of gas token.
|
|
bondDenom := stakingState.Params.BondDenom
|
|
|
|
evmStateBz, ok := rawState[evmtypes.ModuleName]
|
|
if !ok {
|
|
panic("evm genesis state is missing")
|
|
}
|
|
|
|
evmState := new(evmtypes.GenesisState)
|
|
cdc.MustUnmarshalJSON(evmStateBz, evmState)
|
|
|
|
// we should replace the EvmDenom with BondDenom
|
|
evmState.Params.EvmDenom = bondDenom
|
|
|
|
// change appState back
|
|
rawState[evmtypes.ModuleName] = cdc.MustMarshalJSON(evmState)
|
|
|
|
// replace appstate
|
|
appState, err = json.Marshal(rawState)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return appState, simAccs, chainID, genesisTimestamp
|
|
}
|
|
}
|
|
|
|
// NewTestGenesisState generate genesis state with single validator
|
|
func NewTestGenesisState(codec codec.Codec) simapp.GenesisState {
|
|
privVal := mock.NewPV()
|
|
pubKey, err := privVal.GetPubKey()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
// create validator set with single validator
|
|
validator := tmtypes.NewValidator(pubKey, 1)
|
|
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
|
|
|
|
// generate genesis account
|
|
senderPrivKey := secp256k1.GenPrivKey()
|
|
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
|
|
balance := banktypes.Balance{
|
|
Address: acc.GetAddress().String(),
|
|
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
|
|
}
|
|
|
|
genesisState := NewDefaultGenesisState()
|
|
return genesisStateWithValSet(codec, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance)
|
|
}
|
|
|
|
func genesisStateWithValSet(codec codec.Codec, genesisState simapp.GenesisState,
|
|
valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount,
|
|
balances ...banktypes.Balance,
|
|
) simapp.GenesisState {
|
|
// set genesis accounts
|
|
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
|
|
genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis)
|
|
|
|
validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
|
|
delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))
|
|
|
|
bondAmt := sdk.DefaultPowerReduction
|
|
|
|
for _, val := range valSet.Validators {
|
|
pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
pkAny, err := codectypes.NewAnyWithValue(pk)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
validator := stakingtypes.Validator{
|
|
OperatorAddress: sdk.ValAddress(val.Address).String(),
|
|
ConsensusPubkey: pkAny,
|
|
Jailed: false,
|
|
Status: stakingtypes.Bonded,
|
|
Tokens: bondAmt,
|
|
DelegatorShares: sdk.OneDec(),
|
|
Description: stakingtypes.Description{},
|
|
UnbondingHeight: int64(0),
|
|
UnbondingTime: time.Unix(0, 0).UTC(),
|
|
Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
|
MinSelfDelegation: sdk.ZeroInt(),
|
|
}
|
|
validators = append(validators, validator)
|
|
delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))
|
|
|
|
}
|
|
// set validators and delegations
|
|
stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations)
|
|
genesisState[stakingtypes.ModuleName] = codec.MustMarshalJSON(stakingGenesis)
|
|
|
|
totalSupply := sdk.NewCoins()
|
|
for _, b := range balances {
|
|
// add genesis acc tokens to total supply
|
|
totalSupply = totalSupply.Add(b.Coins...)
|
|
}
|
|
|
|
for range delegations {
|
|
// add delegated tokens to total supply
|
|
totalSupply = totalSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))
|
|
}
|
|
|
|
// add bonded amount to bonded pool module account
|
|
balances = append(balances, banktypes.Balance{
|
|
Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(),
|
|
Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)},
|
|
})
|
|
|
|
// update total supply
|
|
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
|
|
genesisState[banktypes.ModuleName] = codec.MustMarshalJSON(bankGenesis)
|
|
|
|
return genesisState
|
|
}
|