From 46ae30539924cc8aa1b4ae0d0a43f1fa3d1453b8 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 18 Aug 2020 14:05:54 +0200 Subject: [PATCH 01/27] evm: params --- app/ethermint.go | 1 + x/evm/alias.go | 7 +- x/evm/types/params.go | 214 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 x/evm/types/params.go diff --git a/app/ethermint.go b/app/ethermint.go index 8a6a36ce1..58315d789 100644 --- a/app/ethermint.go +++ b/app/ethermint.go @@ -179,6 +179,7 @@ func NewEthermintApp( app.subspaces[gov.ModuleName] = app.ParamsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable()) app.subspaces[crisis.ModuleName] = app.ParamsKeeper.Subspace(crisis.DefaultParamspace) app.subspaces[evidence.ModuleName] = app.ParamsKeeper.Subspace(evidence.DefaultParamspace) + app.subspaces[evm.ModuleName] = app.ParamsKeeper.Subspace(evm.DefaultParamspace) // use custom Ethermint account for contracts app.AccountKeeper = auth.NewAccountKeeper( diff --git a/x/evm/alias.go b/x/evm/alias.go index e86b47dfb..32bc4647d 100644 --- a/x/evm/alias.go +++ b/x/evm/alias.go @@ -7,9 +7,10 @@ import ( // nolint const ( - ModuleName = types.ModuleName - StoreKey = types.StoreKey - RouterKey = types.RouterKey + ModuleName = types.ModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + DefaultParamspace = types.DefaultParamspace ) // nolint diff --git a/x/evm/types/params.go b/x/evm/types/params.go new file mode 100644 index 000000000..7986b55f8 --- /dev/null +++ b/x/evm/types/params.go @@ -0,0 +1,214 @@ +package types + +import ( + "fmt" + + "gopkg.in/yaml.v2" + + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/ethereum/go-ethereum/common" +) + +const ( + // DefaultParamspace for params keeper + DefaultParamspace = ModuleName + + homesteadBlock = "HomesteadBlock" + daoForkBlock = "DAOForkBlock" + eip150Block = "EIP150Block" + eip150Hash = "EIP150Hash" + eip155Block = "EIP155Block" + eip158Block = "EIP158Block" + byzantiumBlock = "ByzantiumBlock" + constantinopleBlock = "ConstantinopleBlock" + petersburgBlock = "PetersburgBlock" + istanbulBlock = "IstanbulBlock" + muirGlacierBlock = "MuirGlacierBlock" + yoloV1Block = "YoloV1Block" + eWASMBlock = "EWASMBlock" +) + +// Parameter keys +var ( + ParamStoreKeyHomesteadBlock = []byte(homesteadBlock) + + ParamStoreKeyDAOForkBlock = []byte(daoForkBlock) + ParamStoreKeyDAOForkSupport = []byte("DAOForkSupport") + + ParamStoreKeyEIP150Block = []byte(eip150Block) + ParamStoreKeyEIP150Hash = []byte(eip150Hash) + + ParamStoreKeyEIP155Block = []byte(eip155Block) + ParamStoreKeyEIP158Block = []byte(eip158Block) + + ParamStoreKeyByzantiumBlock = []byte(byzantiumBlock) + ParamStoreKeyConstantinopleBlock = []byte(constantinopleBlock) + ParamStoreKeyPetersburgBlock = []byte(petersburgBlock) + ParamStoreKeyIstanbulBlock = []byte(istanbulBlock) + ParamStoreKeyMuirGlacierBlock = []byte(muirGlacierBlock) + + ParamStoreKeyYoloV1Block = []byte(yoloV1Block) + ParamStoreKeyEWASMBlock = []byte(eWASMBlock) +) + +// ParamKeyTable returns the parameter key table. +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// Params defines the Ethereum ChainConfig as SDK parameters +type Params struct { + HomesteadBlock sdk.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead) + + DAOForkBlock sdk.Int `json:"daoForkBlock,omitempty"` // TheDAO hard-fork switch block (nil = no fork) + DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork + + // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) + EIP150Block sdk.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) + EIP150Hash string `json:"eip150Hash,omitempty"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) + + EIP155Block sdk.Int `json:"eip155Block,omitempty"` // EIP155 HF block + EIP158Block sdk.Int `json:"eip158Block,omitempty"` // EIP158 HF block + + ByzantiumBlock sdk.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) + ConstantinopleBlock sdk.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated) + PetersburgBlock sdk.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople) + IstanbulBlock sdk.Int `json:"istanbulBlock,omitempty"` // Istanbul switch block (nil = no fork, 0 = already on istanbul) + MuirGlacierBlock sdk.Int `json:"muirGlacierBlock,omitempty"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 = already activated) + + YoloV1Block sdk.Int `json:"yoloV1Block,omitempty"` // YOLO v1: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet) + EWASMBlock sdk.Int `json:"ewasmBlock,omitempty"` // EWASM switch block (nil = no fork, 0 = already activated) +} + +// DefaultParams returns default evm parameters +func DefaultParams() Params { + return Params{ + HomesteadBlock: sdk.ZeroInt(), + DAOForkBlock: sdk.ZeroInt(), + DAOForkSupport: true, + EIP150Block: sdk.ZeroInt(), + EIP150Hash: "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + EIP155Block: sdk.ZeroInt(), + EIP158Block: sdk.ZeroInt(), + ByzantiumBlock: sdk.ZeroInt(), + ConstantinopleBlock: sdk.ZeroInt(), + PetersburgBlock: sdk.ZeroInt(), + IstanbulBlock: sdk.Int{}, + MuirGlacierBlock: sdk.Int{}, + YoloV1Block: sdk.Int{}, + EWASMBlock: sdk.Int{}, + } +} + +func (p Params) String() string { + out, _ := yaml.Marshal(p) + return string(out) +} + +// ParamSetPairs returns the parameter set pairs. +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(ParamStoreKeyHomesteadBlock, &p.HomesteadBlock, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyDAOForkBlock, &p.DAOForkBlock, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyDAOForkSupport, &p.DAOForkSupport, validateDAOForkSupport), + paramtypes.NewParamSetPair(ParamStoreKeyEIP150Block, &p.EIP150Block, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyEIP150Hash, &p.EIP150Hash, validateHash), + paramtypes.NewParamSetPair(ParamStoreKeyEIP155Block, &p.EIP155Block, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyEIP158Block, &p.EIP158Block, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyByzantiumBlock, &p.ByzantiumBlock, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyConstantinopleBlock, &p.ConstantinopleBlock, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyPetersburgBlock, &p.PetersburgBlock, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyIstanbulBlock, &p.IstanbulBlock, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyMuirGlacierBlock, &p.MuirGlacierBlock, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyYoloV1Block, &p.YoloV1Block, validateInt), + paramtypes.NewParamSetPair(ParamStoreKeyEWASMBlock, &p.EWASMBlock, validateInt), + } +} + +// ValidateBasic performs basic validation on evm parameters. +func (p Params) ValidateBasic() error { + if err := validateInt(p.HomesteadBlock); err != nil { + return fmt.Errorf("%s: %w", homesteadBlock, err) + } + if err := validateInt(p.DAOForkBlock); err != nil { + return fmt.Errorf("%s: %w", daoForkBlock, err) + } + if err := validateDAOForkSupport(p.DAOForkSupport); err != nil { + return err + } + if err := validateInt(p.EIP150Block); err != nil { + return fmt.Errorf("%s: %w", eip150Block, err) + } + if err := validateHash(p.EIP150Hash); err != nil { + return err + } + if err := validateInt(p.EIP155Block); err != nil { + return fmt.Errorf("%s: %w", eip155Block, err) + } + if err := validateInt(p.EIP158Block); err != nil { + return fmt.Errorf("%s: %w", eip158Block, err) + } + if err := validateInt(p.ByzantiumBlock); err != nil { + return fmt.Errorf("%s: %w", byzantiumBlock, err) + } + if err := validateInt(p.ConstantinopleBlock); err != nil { + return fmt.Errorf("%s: %w", constantinopleBlock, err) + } + if err := validateInt(p.PetersburgBlock); err != nil { + return fmt.Errorf("%s: %w", petersburgBlock, err) + } + if err := validateInt(p.IstanbulBlock); err != nil { + return fmt.Errorf("%s: %w", istanbulBlock, err) + } + if err := validateInt(p.MuirGlacierBlock); err != nil { + return fmt.Errorf("%s: %w", muirGlacierBlock, err) + } + if err := validateInt(p.YoloV1Block); err != nil { + return fmt.Errorf("%s: %w", yoloV1Block, err) + } + if err := validateInt(p.EWASMBlock); err != nil { + return fmt.Errorf("%s: %w", eWASMBlock, err) + } + return nil +} + +func validateInt(i interface{}) error { + v, ok := i.(sdk.Int) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.BigInt() == nil { + return nil + } + + if v.IsNegative() { + return fmt.Errorf("parameter value cannot be negative: %s", v) + } + + return nil +} + +func validateDAOForkSupport(i interface{}) error { + _, ok := i.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} + +func validateHash(i interface{}) error { + hex, ok := i.(string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + bz := common.FromHex(hex) + if len(bz) != common.HashLength { + return fmt.Errorf("invalid hash length, expected 32, got %d", len(bz)) + } + + return nil +} From 3bd141b16a4dc69d77f3b3768b4dd23630faa111 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 18 Aug 2020 14:36:58 +0200 Subject: [PATCH 02/27] setup --- app/ethermint.go | 2 +- x/evm/genesis.go | 3 +++ x/evm/handler.go | 7 ++++--- x/evm/keeper/keeper.go | 12 ++++++++++-- x/evm/keeper/params.go | 18 ++++++++++++++++++ x/evm/types/chain_config.go | 27 +++++++++++++++------------ x/evm/types/genesis.go | 4 +++- x/evm/types/params.go | 5 +++-- x/evm/types/state_transition.go | 8 ++++---- x/evm/types/state_transition_test.go | 2 +- 10 files changed, 62 insertions(+), 26 deletions(-) create mode 100644 x/evm/keeper/params.go diff --git a/app/ethermint.go b/app/ethermint.go index 58315d789..4580b8f61 100644 --- a/app/ethermint.go +++ b/app/ethermint.go @@ -209,7 +209,7 @@ func NewEthermintApp( app.subspaces[crisis.ModuleName], invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName, ) app.EvmKeeper = evm.NewKeeper( - app.cdc, keys[evm.StoreKey], app.AccountKeeper, + app.cdc, keys[evm.StoreKey], app.subspaces[evm.ModuleName], app.AccountKeeper, app.BankKeeper, ) // TODO: use protobuf diff --git a/x/evm/genesis.go b/x/evm/genesis.go index 1a45a5c46..22f580bb9 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -30,6 +30,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU } } + k.SetParams(ctx, data.Params) + // set state objects and code to store _, err = k.Commit(ctx, false) if err != nil { @@ -81,5 +83,6 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta return GenesisState{ Accounts: ethGenAccounts, TxsLogs: k.GetAllTxLogs(ctx), + Params: k.GetParams(ctx), } } diff --git a/x/evm/handler.go b/x/evm/handler.go index 0f0c421d2..00648af6f 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -65,8 +65,8 @@ func handleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*s k.CommitStateDB.Prepare(ethHash, common.Hash{}, k.TxCount) k.TxCount++ - // TODO: move to keeper - executionResult, err := st.TransitionDb(ctx) + params := k.GetParams(ctx) + executionResult, err := st.TransitionDb(ctx, params) if err != nil { return nil, err } @@ -142,7 +142,8 @@ func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk k.CommitStateDB.Prepare(ethHash, common.Hash{}, k.TxCount) k.TxCount++ - executionResult, err := st.TransitionDb(ctx) + params := k.GetParams(ctx) + executionResult, err := st.TransitionDb(ctx, params) if err != nil { return nil, err } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 452e9f365..06c53e5aa 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/ethermint/x/evm/types" @@ -21,7 +22,8 @@ import ( // to the StateDB interface. type Keeper struct { // Amino codec - cdc *codec.Codec + cdc *codec.Codec + paramSpace paramtypes.Subspace // Store key required for the EVM Prefix KVStore. It is required by: // - storing Account's Storage State // - storing Account's Code @@ -39,10 +41,16 @@ type Keeper struct { // NewKeeper generates new evm module keeper func NewKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, bk types.BankKeeper, + cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, ak types.AccountKeeper, bk types.BankKeeper, ) Keeper { + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + return Keeper{ cdc: cdc, + paramSpace: paramSpace, storeKey: storeKey, CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, ak, bk), TxCount: 0, diff --git a/x/evm/keeper/params.go b/x/evm/keeper/params.go new file mode 100644 index 000000000..72f07f92e --- /dev/null +++ b/x/evm/keeper/params.go @@ -0,0 +1,18 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ethermint/x/evm/types" +) + +// GetParams returns the total set of evidence parameters. +func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { + k.paramSpace.GetParamSet(ctx, ¶ms) + return params +} + +// SetParams sets the evidence parameters to the param space. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) +} diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index 9db2fc94a..3a531b7c4 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -8,19 +8,22 @@ import ( ) // GenerateChainConfig returns an Ethereum chainconfig for EVM state transitions -func GenerateChainConfig(chainID *big.Int) *params.ChainConfig { - // TODO: Update chainconfig to take in parameters for fork blocks +func GenerateChainConfig(chainID *big.Int, parameters Params) *params.ChainConfig { return ¶ms.ChainConfig{ ChainID: chainID, - HomesteadBlock: big.NewInt(0), - DAOForkBlock: big.NewInt(0), - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), + HomesteadBlock: parameters.HomesteadBlock.BigInt(), + DAOForkBlock: parameters.DAOForkBlock.BigInt(), + DAOForkSupport: parameters.DAOForkSupport, + EIP150Block: parameters.EIP150Block.BigInt(), + EIP150Hash: common.HexToHash(parameters.EIP150Hash), + EIP155Block: parameters.EIP155Block.BigInt(), + EIP158Block: parameters.EIP158Block.BigInt(), + ByzantiumBlock: parameters.ByzantiumBlock.BigInt(), + ConstantinopleBlock: parameters.ConstantinopleBlock.BigInt(), + PetersburgBlock: parameters.PetersburgBlock.BigInt(), + IstanbulBlock: parameters.IstanbulBlock.BigInt(), + MuirGlacierBlock: parameters.MuirGlacierBlock.BigInt(), + YoloV1Block: parameters.YoloV1Block.BigInt(), + EWASMBlock: parameters.EWASMBlock.BigInt(), } } diff --git a/x/evm/types/genesis.go b/x/evm/types/genesis.go index 9b808a34d..da6e95bf2 100644 --- a/x/evm/types/genesis.go +++ b/x/evm/types/genesis.go @@ -15,6 +15,7 @@ type ( GenesisState struct { Accounts []GenesisAccount `json:"accounts"` TxsLogs []TransactionLogs `json:"txs_logs"` + Params Params `json:"params"` } // GenesisAccount defines an account to be initialized in the genesis state. @@ -51,6 +52,7 @@ func DefaultGenesisState() GenesisState { return GenesisState{ Accounts: []GenesisAccount{}, TxsLogs: []TransactionLogs{}, + Params: DefaultParams(), } } @@ -80,5 +82,5 @@ func (gs GenesisState) Validate() error { seenTxs[tx.Hash.String()] = true } - return nil + return gs.Params.Validate() } diff --git a/x/evm/types/params.go b/x/evm/types/params.go index 7986b55f8..4187cd1e4 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -101,6 +101,7 @@ func DefaultParams() Params { } } +// String implements the fmt.Stringer interface func (p Params) String() string { out, _ := yaml.Marshal(p) return string(out) @@ -126,8 +127,8 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { } } -// ValidateBasic performs basic validation on evm parameters. -func (p Params) ValidateBasic() error { +// Validate performs basic validation on evm parameters. +func (p Params) Validate() error { if err := validateInt(p.HomesteadBlock); err != nil { return fmt.Errorf("%s: %w", homesteadBlock, err) } diff --git a/x/evm/types/state_transition.go b/x/evm/types/state_transition.go index beaa767a8..acb59fe03 100644 --- a/x/evm/types/state_transition.go +++ b/x/evm/types/state_transition.go @@ -49,7 +49,7 @@ type ExecutionResult struct { GasInfo GasInfo } -func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit uint64, gasPrice *big.Int) *vm.EVM { +func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit uint64, gasPrice *big.Int, params Params) *vm.EVM { // Create context for evm context := vm.Context{ CanTransfer: core.CanTransfer, @@ -63,13 +63,13 @@ func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit GasPrice: gasPrice, } - return vm.NewEVM(context, csdb, GenerateChainConfig(st.ChainID), vm.Config{}) + return vm.NewEVM(context, csdb, GenerateChainConfig(st.ChainID, params), vm.Config{}) } // TransitionDb will transition the state by applying the current transaction and // returning the evm execution result. // NOTE: State transition checks are run during AnteHandler execution. -func (st StateTransition) TransitionDb(ctx sdk.Context) (*ExecutionResult, error) { +func (st StateTransition) TransitionDb(ctx sdk.Context, params Params) (*ExecutionResult, error) { contractCreation := st.Recipient == nil cost, err := core.IntrinsicGas(st.Payload, contractCreation, true, false) @@ -108,7 +108,7 @@ func (st StateTransition) TransitionDb(ctx sdk.Context) (*ExecutionResult, error return nil, errors.New("gas price cannot be nil") } - evm := st.newEVM(ctx, csdb, gasLimit, gasPrice.BigInt()) + evm := st.newEVM(ctx, csdb, gasLimit, gasPrice.BigInt(), params) var ( ret []byte diff --git a/x/evm/types/state_transition_test.go b/x/evm/types/state_transition_test.go index ba8f40a49..db7cd4dfe 100644 --- a/x/evm/types/state_transition_test.go +++ b/x/evm/types/state_transition_test.go @@ -148,7 +148,7 @@ func (suite *StateDBTestSuite) TestTransitionDb() { for _, tc := range testCase { tc.malleate() - _, err = tc.state.TransitionDb(suite.ctx) + _, err = tc.state.TransitionDb(suite.ctx, types.DefaultParams()) if tc.expPass { suite.Require().NoError(err, tc.name) From 72fc40e20bbb3c5c1f8eac8fcba8ee8ad4d2efbb Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 18 Aug 2020 16:08:49 +0200 Subject: [PATCH 03/27] bump commit --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a2d858e42..dbd687838 100644 --- a/go.mod +++ b/go.mod @@ -33,4 +33,4 @@ require ( ) // forked SDK to avoid breaking changes -replace github.com/cosmos/cosmos-sdk => github.com/Chainsafe/cosmos-sdk v0.34.4-0.20200811134358-723463e1daec +replace github.com/cosmos/cosmos-sdk => github.com/Chainsafe/cosmos-sdk v0.34.4-0.20200818140608-c36255272967 diff --git a/go.sum b/go.sum index 4c899230b..f3bd37bb5 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,8 @@ github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f h1:4O1om+U github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= -github.com/Chainsafe/cosmos-sdk v0.34.4-0.20200811134358-723463e1daec h1:xcqymee4N5YPH9+NKmrNGw0pdfM82VOoohiXIaQwLzo= -github.com/Chainsafe/cosmos-sdk v0.34.4-0.20200811134358-723463e1daec/go.mod h1:brXC4wuGawcC5pQebaWER22hzunmXFLgN8vajUh+xhE= +github.com/Chainsafe/cosmos-sdk v0.34.4-0.20200818140608-c36255272967 h1:z1RIzTYD0uPyf6al0ElgRfnY7Urc7fiD/iVxI4WSCwo= +github.com/Chainsafe/cosmos-sdk v0.34.4-0.20200818140608-c36255272967/go.mod h1:brXC4wuGawcC5pQebaWER22hzunmXFLgN8vajUh+xhE= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= From 7d041d7a2d0e3d3b1ad53ef423047f51da416d48 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 18 Aug 2020 16:20:25 +0200 Subject: [PATCH 04/27] fixes --- x/evm/types/chain_config.go | 2 +- x/evm/types/params.go | 5 +++-- x/evm/types/querier.go | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index 3a531b7c4..d24ca3ba9 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -24,6 +24,6 @@ func GenerateChainConfig(chainID *big.Int, parameters Params) *params.ChainConfi IstanbulBlock: parameters.IstanbulBlock.BigInt(), MuirGlacierBlock: parameters.MuirGlacierBlock.BigInt(), YoloV1Block: parameters.YoloV1Block.BigInt(), - EWASMBlock: parameters.EWASMBlock.BigInt(), + EWASMBlock: nil, } } diff --git a/x/evm/types/params.go b/x/evm/types/params.go index 4187cd1e4..e136806b4 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -207,8 +207,9 @@ func validateHash(i interface{}) error { } bz := common.FromHex(hex) - if len(bz) != common.HashLength { - return fmt.Errorf("invalid hash length, expected 32, got %d", len(bz)) + lenHex := len(bz) + if lenHex > 0 && lenHex != common.HashLength { + return fmt.Errorf("invalid hash length, expected %d, got %d", common.HashLength, lenHex) } return nil diff --git a/x/evm/types/querier.go b/x/evm/types/querier.go index ba40665b9..397c37ca2 100644 --- a/x/evm/types/querier.go +++ b/x/evm/types/querier.go @@ -46,7 +46,7 @@ type QueryResBlockNumber struct { } func (q QueryResBlockNumber) String() string { - return string(q.Number) + return fmt.Sprint(q.Number) } // QueryResStorage is response type for storage query @@ -73,7 +73,7 @@ type QueryResNonce struct { } func (q QueryResNonce) String() string { - return string(q.Nonce) + return fmt.Sprint(q.Nonce) } // QueryETHLogs is response type for tx logs query From 7b4e423c29e6d129878d774481773b2bbbe87be8 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 18 Aug 2020 21:06:10 +0200 Subject: [PATCH 05/27] increase gas usage --- tests/rpc_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rpc_test.go b/tests/rpc_test.go index 165ba31a3..eb972489e 100644 --- a/tests/rpc_test.go +++ b/tests/rpc_test.go @@ -773,7 +773,7 @@ func TestEth_EstimateGas_ContractDeployment(t *testing.T) { err := json.Unmarshal(rpcRes.Result, &gas) require.NoError(t, err) - require.Equal(t, hexutil.Uint64(0x1cab2), gas) + require.Equal(t, hexutil.Uint64(0x1d7ac), gas) } func TestEth_ExportAccount(t *testing.T) { From 6fa8e293a0ca789889f7dbfe899e8e06e35ce8f0 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 18 Aug 2020 22:18:27 +0200 Subject: [PATCH 06/27] tests --- x/evm/keeper/params_test.go | 16 +++ x/evm/types/params_test.go | 216 ++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 x/evm/keeper/params_test.go create mode 100644 x/evm/types/params_test.go diff --git a/x/evm/keeper/params_test.go b/x/evm/keeper/params_test.go new file mode 100644 index 000000000..4cdb6fb6e --- /dev/null +++ b/x/evm/keeper/params_test.go @@ -0,0 +1,16 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ethermint/x/evm/types" +) + +func (suite *KeeperTestSuite) TestParams() { + params := suite.app.EvmKeeper.GetParams(suite.ctx) + + suite.Require().Equal(types.DefaultParams().IstanbulBlock.BigInt(), params.IstanbulBlock.BigInt()) + + params.EIP150Block = sdk.NewInt(10000) + suite.app.EvmKeeper.SetParams(suite.ctx, params) +} diff --git a/x/evm/types/params_test.go b/x/evm/types/params_test.go new file mode 100644 index 000000000..158f17166 --- /dev/null +++ b/x/evm/types/params_test.go @@ -0,0 +1,216 @@ +package types + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestParamsValidate(t *testing.T) { + testCases := []struct { + name string + params Params + expError bool + }{ + {"default", DefaultParams(), false}, + { + "valid", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + PetersburgBlock: sdk.OneInt(), + IstanbulBlock: sdk.OneInt(), + MuirGlacierBlock: sdk.OneInt(), + YoloV1Block: sdk.OneInt(), + EWASMBlock: sdk.OneInt(), + }, + false, + }, + { + "empty", + Params{}, + false, + }, + { + "invalid HomesteadBlock", + Params{ + HomesteadBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid DAOForkBlock", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid EIP150Block", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.NewInt(-1), + }, + true, + }, + { + "invalid EIP155Block", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.NewInt(-1), + }, + true, + }, + { + "invalid EIP158Block", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.NewInt(-1), + }, + true, + }, + { + "invalid ByzantiumBlock", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid ConstantinopleBlock", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid PetersburgBlock", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + PetersburgBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid IstanbulBlock", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + IstanbulBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid MuirGlacierBlock", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + PetersburgBlock: sdk.OneInt(), + IstanbulBlock: sdk.OneInt(), + MuirGlacierBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid YoloV1Block", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + PetersburgBlock: sdk.OneInt(), + IstanbulBlock: sdk.OneInt(), + MuirGlacierBlock: sdk.OneInt(), + YoloV1Block: sdk.NewInt(-1), + }, + true, + }, + { + "invalid EWASMBlock", + Params{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + PetersburgBlock: sdk.OneInt(), + IstanbulBlock: sdk.OneInt(), + MuirGlacierBlock: sdk.OneInt(), + YoloV1Block: sdk.OneInt(), + EWASMBlock: sdk.NewInt(-1), + }, + true, + }, + } + + for _, tc := range testCases { + err := tc.params.Validate() + + if tc.expError { + require.Error(t, err, tc.name) + } else { + require.NoError(t, err, tc.name) + } + } +} + +func TestValidate(t *testing.T) { + require.Error(t, validateInt("")) + require.Error(t, validateDAOForkSupport("")) + require.Error(t, validateHash(1)) +} From 9ffd1e8b6481bed10c1ce4129e39dc720103372f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 12:21:47 +0200 Subject: [PATCH 07/27] evm denom param --- x/evm/handler.go | 16 +- x/evm/keeper/keeper.go | 33 ++++- x/evm/keeper/params.go | 9 +- x/evm/keeper/params_test.go | 10 +- x/evm/types/chain_config.go | 112 ++++++++++++-- x/evm/types/chain_config_test.go | 212 +++++++++++++++++++++++++++ x/evm/types/codec.go | 1 + x/evm/types/errors.go | 3 + x/evm/types/journal_test.go | 4 +- x/evm/types/key.go | 1 + x/evm/types/params.go | 189 +++--------------------- x/evm/types/params_test.go | 179 +--------------------- x/evm/types/state_transition.go | 8 +- x/evm/types/state_transition_test.go | 2 +- x/evm/types/statedb.go | 18 ++- 15 files changed, 416 insertions(+), 381 deletions(-) create mode 100644 x/evm/types/chain_config_test.go diff --git a/x/evm/handler.go b/x/evm/handler.go index f1d70d0ca..36510d097 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -65,8 +65,12 @@ func handleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*s k.CommitStateDB.Prepare(ethHash, common.Hash{}, k.TxCount) k.TxCount++ - params := k.GetParams(ctx) - executionResult, err := st.TransitionDb(ctx, params) + config, found := k.GetChainConfig(ctx) + if !found { + return nil, types.ErrChainConfigNotFound + } + + executionResult, err := st.TransitionDb(ctx, config) if err != nil { return nil, err } @@ -142,8 +146,12 @@ func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk k.CommitStateDB.Prepare(ethHash, common.Hash{}, k.TxCount) k.TxCount++ - params := k.GetParams(ctx) - executionResult, err := st.TransitionDb(ctx, params) + config, found := k.GetChainConfig(ctx) + if !found { + return nil, types.ErrChainConfigNotFound + } + + executionResult, err := st.TransitionDb(ctx, config) if err != nil { return nil, err } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 75c88eb08..97f5d0b72 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -10,7 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/ethermint/x/evm/types" @@ -23,7 +23,6 @@ import ( type Keeper struct { // Amino codec cdc *codec.Codec - paramSpace paramtypes.Subspace // Store key required for the EVM Prefix KVStore. It is required by: // - storing Account's Storage State // - storing Account's Code @@ -31,6 +30,7 @@ type Keeper struct { // - storing block height -> bloom filter map. Needed for the Web3 API. // - storing block hash -> block height map. Needed for the Web3 API. storeKey sdk.StoreKey + // Ethermint concrete implementation on the EVM StateDB interface CommitStateDB *types.CommitStateDB // Transaction counter in a block. Used on StateSB's Prepare function. // It is reset to 0 every block on BeginBlock so there's no point in storing the counter @@ -41,18 +41,18 @@ type Keeper struct { // NewKeeper generates new evm module keeper func NewKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, ak types.AccountKeeper, + cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace params.Subspace, ak types.AccountKeeper, ) Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) } + // NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations return Keeper{ cdc: cdc, - paramSpace: paramSpace, storeKey: storeKey, - CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, ak), + CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, paramSpace, ak), TxCount: 0, Bloom: big.NewInt(0), } @@ -142,3 +142,26 @@ func (k Keeper) GetAccountStorage(ctx sdk.Context, address common.Address) (type return storage, nil } + + +// GetChainConfig gets block height from block consensus hash +func (k Keeper) GetChainConfig(ctx sdk.Context) (types.ChainConfig, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixChainConfig) + // get from an empty key that's already prefixed by KeyPrefixChainConfig + bz := store.Get([]byte{}) + if len(bz) == 0 { + return types.ChainConfig{}, false + } + + var config types.ChainConfig + k.cdc.MustUnmarshalBinaryBare(bz, config) + return config, true +} + +// SetChainConfig sets the mapping from block consensus hash to block height +func (k Keeper) SetChainConfig(ctx sdk.Context, config types.ChainConfig) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixChainConfig) + bz := k.cdc.MustMarshalBinaryBare(config) + // get to an empty key that's already prefixed by KeyPrefixChainConfig + store.Set([]byte{}, bz) +} \ No newline at end of file diff --git a/x/evm/keeper/params.go b/x/evm/keeper/params.go index 72f07f92e..c24ec8e4a 100644 --- a/x/evm/keeper/params.go +++ b/x/evm/keeper/params.go @@ -6,13 +6,12 @@ import ( "github.com/cosmos/ethermint/x/evm/types" ) -// GetParams returns the total set of evidence parameters. +// GetParams returns the total set of evm parameters. func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { - k.paramSpace.GetParamSet(ctx, ¶ms) - return params + return k.CommitStateDB.WithContext(ctx).GetParams() } -// SetParams sets the evidence parameters to the param space. +// SetParams sets the evm parameters to the param space. func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { - k.paramSpace.SetParamSet(ctx, ¶ms) + k.CommitStateDB.WithContext(ctx).SetParams(params) } diff --git a/x/evm/keeper/params_test.go b/x/evm/keeper/params_test.go index 4cdb6fb6e..4eda8b737 100644 --- a/x/evm/keeper/params_test.go +++ b/x/evm/keeper/params_test.go @@ -1,16 +1,14 @@ package keeper_test import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ethermint/x/evm/types" ) func (suite *KeeperTestSuite) TestParams() { params := suite.app.EvmKeeper.GetParams(suite.ctx) - - suite.Require().Equal(types.DefaultParams().IstanbulBlock.BigInt(), params.IstanbulBlock.BigInt()) - - params.EIP150Block = sdk.NewInt(10000) + suite.Require().Equal(types.DefaultParams(), params) + params.EvmDenom = "ara" suite.app.EvmKeeper.SetParams(suite.ctx, params) + newParams := suite.app.EvmKeeper.GetParams(suite.ctx) + suite.Require().Equal(newParams, params) } diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index d24ca3ba9..aa3cbf07f 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -1,29 +1,109 @@ package types import ( + "fmt" "math/big" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" + "gopkg.in/yaml.v2" ) -// GenerateChainConfig returns an Ethereum chainconfig for EVM state transitions -func GenerateChainConfig(chainID *big.Int, parameters Params) *params.ChainConfig { +// ChainConfig defines the Ethereum ChainConfig parameters +type ChainConfig struct { + HomesteadBlock sdk.Int `json:"homestead_block"` // Homestead switch block (nil = no fork, 0 = already homestead) + + DAOForkBlock sdk.Int `json:"dao_fork_block"` // TheDAO hard-fork switch block (nil = no fork) + DAOForkSupport bool `json:"dao_fork_support"` // Whether the nodes supports or opposes the DAO hard-fork + + // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) + EIP150Block sdk.Int `json:"eip150_block"` // EIP150 HF block (nil = no fork) + EIP150Hash string `json:"eip150_hash"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) + + EIP155Block sdk.Int `json:"eip155_block"` // EIP155 HF block + EIP158Block sdk.Int `json:"eip158_block"` // EIP158 HF block + + ByzantiumBlock sdk.Int `json:"byzantium_block"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) + ConstantinopleBlock sdk.Int `json:"constantinople_block"` // Constantinople switch block (nil = no fork, 0 = already activated) + PetersburgBlock sdk.Int `json:"petersburg_block"` // Petersburg switch block (nil = same as Constantinople) + IstanbulBlock sdk.Int `json:"istanbul_block"` // Istanbul switch block (nil = no fork, 0 = already on istanbul) + MuirGlacierBlock sdk.Int `json:"muir_glacier_block"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 = already activated) + + YoloV1Block sdk.Int `json:"yoloV1_block"` // YOLO v1: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet) + EWASMBlock sdk.Int `json:"ewasm_block"` // EWASM switch block (nil = no fork, 0 = already activated) +} + +// EthereumConfig returns an Ethereum ChainConfig for EVM state transitions +func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig { return ¶ms.ChainConfig{ ChainID: chainID, - HomesteadBlock: parameters.HomesteadBlock.BigInt(), - DAOForkBlock: parameters.DAOForkBlock.BigInt(), - DAOForkSupport: parameters.DAOForkSupport, - EIP150Block: parameters.EIP150Block.BigInt(), - EIP150Hash: common.HexToHash(parameters.EIP150Hash), - EIP155Block: parameters.EIP155Block.BigInt(), - EIP158Block: parameters.EIP158Block.BigInt(), - ByzantiumBlock: parameters.ByzantiumBlock.BigInt(), - ConstantinopleBlock: parameters.ConstantinopleBlock.BigInt(), - PetersburgBlock: parameters.PetersburgBlock.BigInt(), - IstanbulBlock: parameters.IstanbulBlock.BigInt(), - MuirGlacierBlock: parameters.MuirGlacierBlock.BigInt(), - YoloV1Block: parameters.YoloV1Block.BigInt(), - EWASMBlock: nil, + HomesteadBlock: getBlockValue(cc.HomesteadBlock), + DAOForkBlock: getBlockValue(cc.DAOForkBlock), + DAOForkSupport: cc.DAOForkSupport, + EIP150Block: getBlockValue(cc.EIP150Block), + EIP150Hash: common.HexToHash(cc.EIP150Hash), + EIP155Block: getBlockValue(cc.EIP155Block), + EIP158Block: getBlockValue(cc.EIP158Block), + ByzantiumBlock: getBlockValue(cc.ByzantiumBlock), + ConstantinopleBlock: getBlockValue(cc.ConstantinopleBlock), + PetersburgBlock: getBlockValue(cc.PetersburgBlock), + IstanbulBlock: getBlockValue(cc.IstanbulBlock), + MuirGlacierBlock: getBlockValue(cc.MuirGlacierBlock), + YoloV1Block: getBlockValue(cc.YoloV1Block), + EWASMBlock: getBlockValue(cc.EWASMBlock), + } +} + +// String implements the fmt.Stringer interface +func (cc ChainConfig) String() string { + out, _ := yaml.Marshal(cc) + return string(out) +} + +// DefaultChainConfig returns default evm parameters +func DefaultChainConfig() ChainConfig { + return ChainConfig{ + HomesteadBlock: sdk.ZeroInt(), + DAOForkBlock: sdk.ZeroInt(), + DAOForkSupport: true, + EIP150Block: sdk.ZeroInt(), + EIP150Hash: "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + EIP155Block: sdk.ZeroInt(), + EIP158Block: sdk.ZeroInt(), + ByzantiumBlock: sdk.ZeroInt(), + ConstantinopleBlock: sdk.ZeroInt(), + PetersburgBlock: sdk.ZeroInt(), + IstanbulBlock: sdk.NewInt(-1), + MuirGlacierBlock: sdk.NewInt(-1), + YoloV1Block: sdk.NewInt(-1), + EWASMBlock: sdk.NewInt(-1), } } + +func getBlockValue(block sdk.Int) *big.Int { + if block.BigInt() == nil || block.IsNegative() { + return nil + } + + return block.BigInt() +} + +func (cc ChainConfig) Validate() error { + if err := validateHash(cc.EIP150Hash); err != nil { + return err + } + + return nil +} + + +func validateHash(hex string) error { + bz := common.FromHex(hex) + lenHex := len(bz) + if lenHex > 0 && lenHex != common.HashLength { + return fmt.Errorf("invalid hash length, expected %d, got %d", common.HashLength, lenHex) + } + + return nil +} \ No newline at end of file diff --git a/x/evm/types/chain_config_test.go b/x/evm/types/chain_config_test.go new file mode 100644 index 000000000..aaebb5e82 --- /dev/null +++ b/x/evm/types/chain_config_test.go @@ -0,0 +1,212 @@ +package types + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +const defaultEIP150Hash = "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0" + +func TestChainConfigValidate(t *testing.T) { + testCases := []struct { + name string + config ChainConfig + expError bool + }{ + {"default", DefaultChainConfig(), false}, + { + "valid", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + PetersburgBlock: sdk.OneInt(), + IstanbulBlock: sdk.OneInt(), + MuirGlacierBlock: sdk.OneInt(), + YoloV1Block: sdk.OneInt(), + EWASMBlock: sdk.OneInt(), + }, + false, + }, + { + "empty", + ChainConfig{}, + false, + }, + { + "invalid HomesteadBlock", + ChainConfig{ + HomesteadBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid DAOForkBlock", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid EIP150Block", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.NewInt(-1), + }, + true, + }, + { + "invalid EIP155Block", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.NewInt(-1), + }, + true, + }, + { + "invalid EIP158Block", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.NewInt(-1), + }, + true, + }, + { + "invalid ByzantiumBlock", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid ConstantinopleBlock", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid PetersburgBlock", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + PetersburgBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid IstanbulBlock", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + IstanbulBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid MuirGlacierBlock", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + PetersburgBlock: sdk.OneInt(), + IstanbulBlock: sdk.OneInt(), + MuirGlacierBlock: sdk.NewInt(-1), + }, + true, + }, + { + "invalid YoloV1Block", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + PetersburgBlock: sdk.OneInt(), + IstanbulBlock: sdk.OneInt(), + MuirGlacierBlock: sdk.OneInt(), + YoloV1Block: sdk.NewInt(-1), + }, + true, + }, + { + "invalid EWASMBlock", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: defaultEIP150Hash, + EIP155Block: sdk.OneInt(), + EIP158Block: sdk.OneInt(), + ByzantiumBlock: sdk.OneInt(), + ConstantinopleBlock: sdk.OneInt(), + PetersburgBlock: sdk.OneInt(), + IstanbulBlock: sdk.OneInt(), + MuirGlacierBlock: sdk.OneInt(), + YoloV1Block: sdk.OneInt(), + EWASMBlock: sdk.NewInt(-1), + }, + true, + }, + } + + for _, tc := range testCases { + err := tc.config.Validate() + + if tc.expError { + require.Error(t, err, tc.name) + } else { + require.NoError(t, err, tc.name) + } + } +} diff --git a/x/evm/types/codec.go b/x/evm/types/codec.go index d10108673..6ccbd5624 100644 --- a/x/evm/types/codec.go +++ b/x/evm/types/codec.go @@ -13,6 +13,7 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgEthereumTx{}, "ethermint/MsgEthereumTx", nil) cdc.RegisterConcrete(MsgEthermint{}, "ethermint/MsgEthermint", nil) cdc.RegisterConcrete(TxData{}, "ethermint/TxData", nil) + cdc.RegisterConcrete(ChainConfig{}, "ethermint/ChainConfig", nil) } func init() { diff --git a/x/evm/types/errors.go b/x/evm/types/errors.go index aff740dd0..fdb2fd6a5 100644 --- a/x/evm/types/errors.go +++ b/x/evm/types/errors.go @@ -9,4 +9,7 @@ import ( var ( // ErrInvalidState returns an error resulting from an invalid Storage State. ErrInvalidState = sdkerrors.Register(ModuleName, 2, "invalid storage state") + + // ErrChainConfigNotFound returns an error if the chain config cannot be found on the store. + ErrChainConfigNotFound = sdkerrors.Register(ModuleName, 3, "chain configuration not found") ) diff --git a/x/evm/types/journal_test.go b/x/evm/types/journal_test.go index 04ce0b5b0..a74028e4a 100644 --- a/x/evm/types/journal_test.go +++ b/x/evm/types/journal_test.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/params" ethcmn "github.com/ethereum/go-ethereum/common" @@ -118,11 +119,12 @@ func (suite *JournalTestSuite) setup() { paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams) authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace) + evmSubspace := paramsKeeper.Subspace(types.DefaultParamspace) ak := auth.NewAccountKeeper(cdc, authKey, authSubspace, ethermint.ProtoAccount) suite.ctx = sdk.NewContext(cms, abci.Header{ChainID: "8"}, false, tmlog.NewNopLogger()) - suite.stateDB = NewCommitStateDB(suite.ctx, storeKey, ak).WithContext(suite.ctx) + suite.stateDB = NewCommitStateDB(suite.ctx, storeKey, evmSubspace, ak).WithContext(suite.ctx) } func TestJournalTestSuite(t *testing.T) { diff --git a/x/evm/types/key.go b/x/evm/types/key.go index 6e07641e1..6f03a18fa 100644 --- a/x/evm/types/key.go +++ b/x/evm/types/key.go @@ -26,6 +26,7 @@ var ( KeyPrefixLogs = []byte{0x03} KeyPrefixCode = []byte{0x04} KeyPrefixStorage = []byte{0x05} + KeyPrefixChainConfig = []byte{0x06} ) // BloomKey defines the store key for a block Bloom diff --git a/x/evm/types/params.go b/x/evm/types/params.go index e136806b4..9ceb55204 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -6,98 +6,44 @@ import ( "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/ethereum/go-ethereum/common" + "github.com/cosmos/cosmos-sdk/x/params" + + ethermint "github.com/cosmos/ethermint/types" ) const ( // DefaultParamspace for params keeper DefaultParamspace = ModuleName - - homesteadBlock = "HomesteadBlock" - daoForkBlock = "DAOForkBlock" - eip150Block = "EIP150Block" - eip150Hash = "EIP150Hash" - eip155Block = "EIP155Block" - eip158Block = "EIP158Block" - byzantiumBlock = "ByzantiumBlock" - constantinopleBlock = "ConstantinopleBlock" - petersburgBlock = "PetersburgBlock" - istanbulBlock = "IstanbulBlock" - muirGlacierBlock = "MuirGlacierBlock" - yoloV1Block = "YoloV1Block" - eWASMBlock = "EWASMBlock" ) // Parameter keys var ( - ParamStoreKeyHomesteadBlock = []byte(homesteadBlock) - - ParamStoreKeyDAOForkBlock = []byte(daoForkBlock) - ParamStoreKeyDAOForkSupport = []byte("DAOForkSupport") - - ParamStoreKeyEIP150Block = []byte(eip150Block) - ParamStoreKeyEIP150Hash = []byte(eip150Hash) - - ParamStoreKeyEIP155Block = []byte(eip155Block) - ParamStoreKeyEIP158Block = []byte(eip158Block) - - ParamStoreKeyByzantiumBlock = []byte(byzantiumBlock) - ParamStoreKeyConstantinopleBlock = []byte(constantinopleBlock) - ParamStoreKeyPetersburgBlock = []byte(petersburgBlock) - ParamStoreKeyIstanbulBlock = []byte(istanbulBlock) - ParamStoreKeyMuirGlacierBlock = []byte(muirGlacierBlock) + ParamStoreKeyEVMDenom = []byte("EVMDenom") - ParamStoreKeyYoloV1Block = []byte(yoloV1Block) - ParamStoreKeyEWASMBlock = []byte(eWASMBlock) ) // ParamKeyTable returns the parameter key table. -func ParamKeyTable() paramtypes.KeyTable { - return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +func ParamKeyTable() params.KeyTable { + return params.NewKeyTable().RegisterParamSet(&Params{}) } -// Params defines the Ethereum ChainConfig as SDK parameters -type Params struct { - HomesteadBlock sdk.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead) - - DAOForkBlock sdk.Int `json:"daoForkBlock,omitempty"` // TheDAO hard-fork switch block (nil = no fork) - DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork - - // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) - EIP150Block sdk.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) - EIP150Hash string `json:"eip150Hash,omitempty"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) - EIP155Block sdk.Int `json:"eip155Block,omitempty"` // EIP155 HF block - EIP158Block sdk.Int `json:"eip158Block,omitempty"` // EIP158 HF block - - ByzantiumBlock sdk.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) - ConstantinopleBlock sdk.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated) - PetersburgBlock sdk.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople) - IstanbulBlock sdk.Int `json:"istanbulBlock,omitempty"` // Istanbul switch block (nil = no fork, 0 = already on istanbul) - MuirGlacierBlock sdk.Int `json:"muirGlacierBlock,omitempty"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 = already activated) +// Params defines the EVM module parameters +type Params struct { + EvmDenom string `json:"evm_denom" yaml:"evm_denom"` +} - YoloV1Block sdk.Int `json:"yoloV1Block,omitempty"` // YOLO v1: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet) - EWASMBlock sdk.Int `json:"ewasmBlock,omitempty"` // EWASM switch block (nil = no fork, 0 = already activated) +// NewParams creates a new Params instance +func NewParams(evmDenom string) Params { + return Params{ + EvmDenom: evmDenom, + } } // DefaultParams returns default evm parameters func DefaultParams() Params { return Params{ - HomesteadBlock: sdk.ZeroInt(), - DAOForkBlock: sdk.ZeroInt(), - DAOForkSupport: true, - EIP150Block: sdk.ZeroInt(), - EIP150Hash: "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", - EIP155Block: sdk.ZeroInt(), - EIP158Block: sdk.ZeroInt(), - ByzantiumBlock: sdk.ZeroInt(), - ConstantinopleBlock: sdk.ZeroInt(), - PetersburgBlock: sdk.ZeroInt(), - IstanbulBlock: sdk.Int{}, - MuirGlacierBlock: sdk.Int{}, - YoloV1Block: sdk.Int{}, - EWASMBlock: sdk.Int{}, + EvmDenom: ethermint.DenomDefault, } } @@ -108,109 +54,22 @@ func (p Params) String() string { } // ParamSetPairs returns the parameter set pairs. -func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{ - paramtypes.NewParamSetPair(ParamStoreKeyHomesteadBlock, &p.HomesteadBlock, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyDAOForkBlock, &p.DAOForkBlock, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyDAOForkSupport, &p.DAOForkSupport, validateDAOForkSupport), - paramtypes.NewParamSetPair(ParamStoreKeyEIP150Block, &p.EIP150Block, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyEIP150Hash, &p.EIP150Hash, validateHash), - paramtypes.NewParamSetPair(ParamStoreKeyEIP155Block, &p.EIP155Block, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyEIP158Block, &p.EIP158Block, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyByzantiumBlock, &p.ByzantiumBlock, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyConstantinopleBlock, &p.ConstantinopleBlock, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyPetersburgBlock, &p.PetersburgBlock, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyIstanbulBlock, &p.IstanbulBlock, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyMuirGlacierBlock, &p.MuirGlacierBlock, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyYoloV1Block, &p.YoloV1Block, validateInt), - paramtypes.NewParamSetPair(ParamStoreKeyEWASMBlock, &p.EWASMBlock, validateInt), +func (p *Params) ParamSetPairs() params.ParamSetPairs { + return params.ParamSetPairs{ + params.NewParamSetPair(ParamStoreKeyEVMDenom, &p.EvmDenom, validateEVMDenom), } } // Validate performs basic validation on evm parameters. func (p Params) Validate() error { - if err := validateInt(p.HomesteadBlock); err != nil { - return fmt.Errorf("%s: %w", homesteadBlock, err) - } - if err := validateInt(p.DAOForkBlock); err != nil { - return fmt.Errorf("%s: %w", daoForkBlock, err) - } - if err := validateDAOForkSupport(p.DAOForkSupport); err != nil { - return err - } - if err := validateInt(p.EIP150Block); err != nil { - return fmt.Errorf("%s: %w", eip150Block, err) - } - if err := validateHash(p.EIP150Hash); err != nil { - return err - } - if err := validateInt(p.EIP155Block); err != nil { - return fmt.Errorf("%s: %w", eip155Block, err) - } - if err := validateInt(p.EIP158Block); err != nil { - return fmt.Errorf("%s: %w", eip158Block, err) - } - if err := validateInt(p.ByzantiumBlock); err != nil { - return fmt.Errorf("%s: %w", byzantiumBlock, err) - } - if err := validateInt(p.ConstantinopleBlock); err != nil { - return fmt.Errorf("%s: %w", constantinopleBlock, err) - } - if err := validateInt(p.PetersburgBlock); err != nil { - return fmt.Errorf("%s: %w", petersburgBlock, err) - } - if err := validateInt(p.IstanbulBlock); err != nil { - return fmt.Errorf("%s: %w", istanbulBlock, err) - } - if err := validateInt(p.MuirGlacierBlock); err != nil { - return fmt.Errorf("%s: %w", muirGlacierBlock, err) - } - if err := validateInt(p.YoloV1Block); err != nil { - return fmt.Errorf("%s: %w", yoloV1Block, err) - } - if err := validateInt(p.EWASMBlock); err != nil { - return fmt.Errorf("%s: %w", eWASMBlock, err) - } - return nil + return sdk.ValidateDenom(p.EvmDenom) } -func validateInt(i interface{}) error { - v, ok := i.(sdk.Int) +func validateEVMDenom(i interface{}) error { + denom, ok := i.(string) if !ok { return fmt.Errorf("invalid parameter type: %T", i) } - if v.BigInt() == nil { - return nil - } - - if v.IsNegative() { - return fmt.Errorf("parameter value cannot be negative: %s", v) - } - - return nil -} - -func validateDAOForkSupport(i interface{}) error { - _, ok := i.(bool) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - return nil -} - -func validateHash(i interface{}) error { - hex, ok := i.(string) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - bz := common.FromHex(hex) - lenHex := len(bz) - if lenHex > 0 && lenHex != common.HashLength { - return fmt.Errorf("invalid hash length, expected %d, got %d", common.HashLength, lenHex) - } - - return nil -} + return sdk.ValidateDenom(denom) +} \ No newline at end of file diff --git a/x/evm/types/params_test.go b/x/evm/types/params_test.go index 158f17166..a6c78b899 100644 --- a/x/evm/types/params_test.go +++ b/x/evm/types/params_test.go @@ -3,7 +3,6 @@ package types import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) @@ -16,21 +15,7 @@ func TestParamsValidate(t *testing.T) { {"default", DefaultParams(), false}, { "valid", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.OneInt(), - EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.OneInt(), - EIP158Block: sdk.OneInt(), - ByzantiumBlock: sdk.OneInt(), - ConstantinopleBlock: sdk.OneInt(), - PetersburgBlock: sdk.OneInt(), - IstanbulBlock: sdk.OneInt(), - MuirGlacierBlock: sdk.OneInt(), - YoloV1Block: sdk.OneInt(), - EWASMBlock: sdk.OneInt(), - }, + NewParams("ara"), false, }, { @@ -39,163 +24,13 @@ func TestParamsValidate(t *testing.T) { false, }, { - "invalid HomesteadBlock", - Params{ - HomesteadBlock: sdk.NewInt(-1), - }, - true, - }, - { - "invalid DAOForkBlock", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.NewInt(-1), - }, - true, - }, - { - "invalid EIP150Block", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.NewInt(-1), - }, - true, - }, - { - "invalid EIP155Block", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.OneInt(), - EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.NewInt(-1), - }, - true, - }, - { - "invalid EIP158Block", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.OneInt(), - EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.OneInt(), - EIP158Block: sdk.NewInt(-1), - }, - true, - }, - { - "invalid ByzantiumBlock", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.OneInt(), - EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.OneInt(), - EIP158Block: sdk.OneInt(), - ByzantiumBlock: sdk.NewInt(-1), - }, - true, - }, - { - "invalid ConstantinopleBlock", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.OneInt(), - EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.OneInt(), - EIP158Block: sdk.OneInt(), - ByzantiumBlock: sdk.OneInt(), - ConstantinopleBlock: sdk.NewInt(-1), - }, - true, - }, - { - "invalid PetersburgBlock", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.OneInt(), - EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.OneInt(), - EIP158Block: sdk.OneInt(), - ByzantiumBlock: sdk.OneInt(), - ConstantinopleBlock: sdk.OneInt(), - PetersburgBlock: sdk.NewInt(-1), - }, - true, - }, - { - "invalid IstanbulBlock", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.OneInt(), - EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.OneInt(), - EIP158Block: sdk.OneInt(), - ByzantiumBlock: sdk.OneInt(), - ConstantinopleBlock: sdk.OneInt(), - IstanbulBlock: sdk.NewInt(-1), - }, - true, - }, - { - "invalid MuirGlacierBlock", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.OneInt(), - EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.OneInt(), - EIP158Block: sdk.OneInt(), - ByzantiumBlock: sdk.OneInt(), - ConstantinopleBlock: sdk.OneInt(), - PetersburgBlock: sdk.OneInt(), - IstanbulBlock: sdk.OneInt(), - MuirGlacierBlock: sdk.NewInt(-1), - }, - true, - }, - { - "invalid YoloV1Block", - Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.OneInt(), - EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.OneInt(), - EIP158Block: sdk.OneInt(), - ByzantiumBlock: sdk.OneInt(), - ConstantinopleBlock: sdk.OneInt(), - PetersburgBlock: sdk.OneInt(), - IstanbulBlock: sdk.OneInt(), - MuirGlacierBlock: sdk.OneInt(), - YoloV1Block: sdk.NewInt(-1), - }, - true, - }, - { - "invalid EWASMBlock", + "invalid evm denom", Params{ - HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.OneInt(), - EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.OneInt(), - EIP158Block: sdk.OneInt(), - ByzantiumBlock: sdk.OneInt(), - ConstantinopleBlock: sdk.OneInt(), - PetersburgBlock: sdk.OneInt(), - IstanbulBlock: sdk.OneInt(), - MuirGlacierBlock: sdk.OneInt(), - YoloV1Block: sdk.OneInt(), - EWASMBlock: sdk.NewInt(-1), + EvmDenom: "@!#!@$!@5^32", }, true, }, + } for _, tc := range testCases { @@ -209,8 +44,6 @@ func TestParamsValidate(t *testing.T) { } } -func TestValidate(t *testing.T) { - require.Error(t, validateInt("")) - require.Error(t, validateDAOForkSupport("")) - require.Error(t, validateHash(1)) +func TestParamsValidatePriv(t *testing.T) { + require.Error(t, validateEVMDenom(false)) } diff --git a/x/evm/types/state_transition.go b/x/evm/types/state_transition.go index 5c536dc17..88cce02f1 100644 --- a/x/evm/types/state_transition.go +++ b/x/evm/types/state_transition.go @@ -49,7 +49,7 @@ type ExecutionResult struct { GasInfo GasInfo } -func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit uint64, gasPrice *big.Int, params Params) *vm.EVM { +func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit uint64, gasPrice *big.Int, config ChainConfig) *vm.EVM { // Create context for evm context := vm.Context{ CanTransfer: core.CanTransfer, @@ -63,13 +63,13 @@ func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit GasPrice: gasPrice, } - return vm.NewEVM(context, csdb, GenerateChainConfig(st.ChainID, params), vm.Config{}) + return vm.NewEVM(context, csdb, config.EthereumConfig(st.ChainID), vm.Config{}) } // TransitionDb will transition the state by applying the current transaction and // returning the evm execution result. // NOTE: State transition checks are run during AnteHandler execution. -func (st StateTransition) TransitionDb(ctx sdk.Context, params Params) (*ExecutionResult, error) { +func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*ExecutionResult, error) { contractCreation := st.Recipient == nil cost, err := core.IntrinsicGas(st.Payload, contractCreation, true, false) @@ -108,7 +108,7 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, params Params) (*Executi return nil, errors.New("gas price cannot be nil") } - evm := st.newEVM(ctx, csdb, gasLimit, gasPrice.Int, params) + evm := st.newEVM(ctx, csdb, gasLimit, gasPrice.Int, config) var ( ret []byte diff --git a/x/evm/types/state_transition_test.go b/x/evm/types/state_transition_test.go index 7b6cd6a53..9196469b5 100644 --- a/x/evm/types/state_transition_test.go +++ b/x/evm/types/state_transition_test.go @@ -132,7 +132,7 @@ func (suite *StateDBTestSuite) TestTransitionDb() { for _, tc := range testCase { tc.malleate() - _, err = tc.state.TransitionDb(suite.ctx, types.DefaultParams()) + _, err = tc.state.TransitionDb(suite.ctx, types.DefaultChainConfig()) if tc.expPass { suite.Require().NoError(err, tc.name) diff --git a/x/evm/types/statedb.go b/x/evm/types/statedb.go index 3fdc0b33d..dc2e5f7c5 100644 --- a/x/evm/types/statedb.go +++ b/x/evm/types/statedb.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/params" emint "github.com/cosmos/ethermint/types" @@ -42,6 +43,7 @@ type CommitStateDB struct { ctx sdk.Context storeKey sdk.StoreKey + paramSpace params.Subspace accountKeeper AccountKeeper // array that hold 'live' objects, which will get modified while processing a @@ -86,11 +88,12 @@ type CommitStateDB struct { // CONTRACT: Stores used for state must be cache-wrapped as the ordering of the // key/value space matters in determining the merkle root. func NewCommitStateDB( - ctx sdk.Context, storeKey sdk.StoreKey, ak AccountKeeper, + ctx sdk.Context, storeKey sdk.StoreKey, paramSpace params.Subspace, ak AccountKeeper, ) *CommitStateDB { return &CommitStateDB{ ctx: ctx, storeKey: storeKey, + paramSpace: paramSpace, accountKeeper: ak, stateObjects: []stateEntry{}, addressToObjectIndex: make(map[ethcmn.Address]int), @@ -110,6 +113,12 @@ func (csdb *CommitStateDB) WithContext(ctx sdk.Context) *CommitStateDB { // Setters // ---------------------------------------------------------------------------- +// SetParams sets the evm parameters to the param space. +func (csdb *CommitStateDB) SetParams(params Params) { + csdb.paramSpace.SetParamSet(csdb.ctx, ¶ms) +} + + // SetBalance sets the balance of an account. func (csdb *CommitStateDB) SetBalance(addr ethcmn.Address, amount *big.Int) { so := csdb.GetOrNewStateObject(addr) @@ -237,6 +246,13 @@ func (csdb *CommitStateDB) SubRefund(gas uint64) { // Getters // ---------------------------------------------------------------------------- + +// GetParams returns the total set of evm parameters. +func (csdb *CommitStateDB) GetParams() (params Params) { + csdb.paramSpace.GetParamSet(csdb.ctx, ¶ms) + return params +} + // GetBalance retrieves the balance from the given address or 0 if object not // found. func (csdb *CommitStateDB) GetBalance(addr ethcmn.Address) *big.Int { From 452cc78ac100ecf967396d9e99ee520cd4b5eb30 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 13:25:33 +0200 Subject: [PATCH 08/27] more config updates --- x/evm/types/chain_config.go | 105 ++++++++++++++++++++++++------- x/evm/types/chain_config_test.go | 37 +++++++---- x/evm/types/errors.go | 3 + x/evm/types/genesis_test.go | 8 +++ x/evm/types/params_test.go | 2 +- 5 files changed, 120 insertions(+), 35 deletions(-) diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index aa3cbf07f..b00f2bb9a 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -1,40 +1,50 @@ package types import ( - "fmt" "math/big" + "strings" + + "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" - "gopkg.in/yaml.v2" ) -// ChainConfig defines the Ethereum ChainConfig parameters +// ChainConfig defines the Ethereum ChainConfig parameters using sdk.Int values instead of big.Int. +// +// NOTE 1: Since empty Int (i.e with a nil big.Int value) are parsed to zero, we need to manually +// specify +// NOTE 2: This type is not a configurable Param since the SDK does not allow for validation against +// previous stored parameter values or current block height. In order to update the values, a +// hard-fork upgrade must be done. type ChainConfig struct { - HomesteadBlock sdk.Int `json:"homestead_block"` // Homestead switch block (nil = no fork, 0 = already homestead) + HomesteadBlock sdk.Int `json:"homestead_block" yaml:"homestead_block"` // Homestead switch block (nil = no fork, 0 < already homestead) - DAOForkBlock sdk.Int `json:"dao_fork_block"` // TheDAO hard-fork switch block (nil = no fork) - DAOForkSupport bool `json:"dao_fork_support"` // Whether the nodes supports or opposes the DAO hard-fork + DAOForkBlock sdk.Int `json:"dao_fork_block" yaml:"dao_fork_block"` // TheDAO hard-fork switch block (nil = no fork) + DAOForkSupport bool `json:"dao_fork_support" yaml:"dao_fork_support"` // Whether the nodes supports or opposes the DAO hard-fork // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) - EIP150Block sdk.Int `json:"eip150_block"` // EIP150 HF block (nil = no fork) - EIP150Hash string `json:"eip150_hash"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) + EIP150Block sdk.Int `json:"eip150_block" yaml:"eip150_block"` // EIP150 HF block (nil = no fork) + EIP150Hash string `json:"eip150_hash" yaml:"eip150_hash"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) - EIP155Block sdk.Int `json:"eip155_block"` // EIP155 HF block - EIP158Block sdk.Int `json:"eip158_block"` // EIP158 HF block + EIP155Block sdk.Int `json:"eip155_block" yaml:"eip155_block"` // EIP155 HF block + EIP158Block sdk.Int `json:"eip158_block" yaml:"eip158_block"` // EIP158 HF block - ByzantiumBlock sdk.Int `json:"byzantium_block"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) - ConstantinopleBlock sdk.Int `json:"constantinople_block"` // Constantinople switch block (nil = no fork, 0 = already activated) - PetersburgBlock sdk.Int `json:"petersburg_block"` // Petersburg switch block (nil = same as Constantinople) - IstanbulBlock sdk.Int `json:"istanbul_block"` // Istanbul switch block (nil = no fork, 0 = already on istanbul) - MuirGlacierBlock sdk.Int `json:"muir_glacier_block"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 = already activated) + ByzantiumBlock sdk.Int `json:"byzantium_block" yaml:"byzantium_block"` // Byzantium switch block (nil = no fork, 0 < already on byzantium) + ConstantinopleBlock sdk.Int `json:"constantinople_block" yaml:"constantinople_block"` // Constantinople switch block (nil = no fork, 0 < already activated) + PetersburgBlock sdk.Int `json:"petersburg_block" yaml:"petersburg_block"` // Petersburg switch block (nil = same as Constantinople) + IstanbulBlock sdk.Int `json:"istanbul_block" yaml:"istanbul_block"` // Istanbul switch block (nil = no fork, 0 < already on istanbul) + MuirGlacierBlock sdk.Int `json:"muir_glacier_block" yaml:"muir_glacier_block"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 < already activated) - YoloV1Block sdk.Int `json:"yoloV1_block"` // YOLO v1: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet) - EWASMBlock sdk.Int `json:"ewasm_block"` // EWASM switch block (nil = no fork, 0 = already activated) + YoloV1Block sdk.Int `json:"yoloV1_block" yaml:"yoloV1_block"` // YOLO v1: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet) + EWASMBlock sdk.Int `json:"ewasm_block" yaml:"ewasm_block"` // EWASM switch block (nil = no fork, 0 = already activated) } -// EthereumConfig returns an Ethereum ChainConfig for EVM state transitions +// EthereumConfig returns an Ethereum ChainConfig for EVM state transitions. +// All the negative or nil values are converted to nil func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig { return ¶ms.ChainConfig{ ChainID: chainID, @@ -61,7 +71,7 @@ func (cc ChainConfig) String() string { return string(out) } -// DefaultChainConfig returns default evm parameters +// DefaultChainConfig returns default evm parameters. Th func DefaultChainConfig() ChainConfig { return ChainConfig{ HomesteadBlock: sdk.ZeroInt(), @@ -82,27 +92,80 @@ func DefaultChainConfig() ChainConfig { } func getBlockValue(block sdk.Int) *big.Int { - if block.BigInt() == nil || block.IsNegative() { + if block.IsNegative() { return nil } return block.BigInt() } +// Validate performs a basic validation of the ChainConfig params. The function will return an error +// if any of the block values is uninitialized (i.e nil) or if the EIP150Hash is an invalid hash. func (cc ChainConfig) Validate() error { + if err := validateBlock(cc.HomesteadBlock); err != nil { + return sdkerrors.Wrap(err, "homesteadBlock") + } + if err := validateBlock(cc.DAOForkBlock); err != nil { + return sdkerrors.Wrap(err, "daoForkBlock") + } + if err := validateBlock(cc.EIP150Block); err != nil { + return sdkerrors.Wrap(err, "eip150Block") + } if err := validateHash(cc.EIP150Hash); err != nil { return err } + if err := validateBlock(cc.EIP155Block); err != nil { + return sdkerrors.Wrap(err, "eip155Block") + } + if err := validateBlock(cc.EIP158Block); err != nil { + return sdkerrors.Wrap(err, "eip158Block") + } + if err := validateBlock(cc.ByzantiumBlock); err != nil { + return sdkerrors.Wrap(err, "byzantiumBlock") + } + if err := validateBlock(cc.ConstantinopleBlock); err != nil { + return sdkerrors.Wrap(err, "constantinopleBlock") + } + if err := validateBlock(cc.PetersburgBlock); err != nil { + return sdkerrors.Wrap(err, "petersburgBlock") + } + if err := validateBlock(cc.IstanbulBlock); err != nil { + return sdkerrors.Wrap(err, "istanbulBlock") + } + if err := validateBlock(cc.MuirGlacierBlock); err != nil { + return sdkerrors.Wrap(err, "muirGlacierBlock") + } + if err := validateBlock(cc.YoloV1Block); err != nil { + return sdkerrors.Wrap(err, "yoloV1Block") + } + if err := validateBlock(cc.EWASMBlock); err != nil { + return sdkerrors.Wrap(err, "eWASMBlock") + } return nil } func validateHash(hex string) error { + if strings.TrimSpace(hex) == "" { + return sdkerrors.Wrapf(ErrInvalidChainConfig, "hash cannot be blank") + } + bz := common.FromHex(hex) lenHex := len(bz) if lenHex > 0 && lenHex != common.HashLength { - return fmt.Errorf("invalid hash length, expected %d, got %d", common.HashLength, lenHex) + return sdkerrors.Wrapf(ErrInvalidChainConfig, "invalid hash length, expected %d, got %d", common.HashLength, lenHex) + } + + return nil +} + +func validateBlock(block sdk.Int) error { + if block == (sdk.Int{}) || block.BigInt() == nil { + return sdkerrors.Wrapf( + ErrInvalidChainConfig, + "cannot use uninitialized or nil values for Int, set a negative Int value if you want to define a nil Ethereum block", + ) } return nil diff --git a/x/evm/types/chain_config_test.go b/x/evm/types/chain_config_test.go index aaebb5e82..90dac3cdb 100644 --- a/x/evm/types/chain_config_test.go +++ b/x/evm/types/chain_config_test.go @@ -38,12 +38,12 @@ func TestChainConfigValidate(t *testing.T) { { "empty", ChainConfig{}, - false, + true, }, { "invalid HomesteadBlock", ChainConfig{ - HomesteadBlock: sdk.NewInt(-1), + HomesteadBlock: sdk.Int{}, }, true, }, @@ -51,7 +51,7 @@ func TestChainConfigValidate(t *testing.T) { "invalid DAOForkBlock", ChainConfig{ HomesteadBlock: sdk.OneInt(), - DAOForkBlock: sdk.NewInt(-1), + DAOForkBlock: sdk.Int{}, }, true, }, @@ -60,7 +60,17 @@ func TestChainConfigValidate(t *testing.T) { ChainConfig{ HomesteadBlock: sdk.OneInt(), DAOForkBlock: sdk.OneInt(), - EIP150Block: sdk.NewInt(-1), + EIP150Block: sdk.Int{}, + }, + true, + }, + { + "invalid EIP150Hash", + ChainConfig{ + HomesteadBlock: sdk.OneInt(), + DAOForkBlock: sdk.OneInt(), + EIP150Block: sdk.OneInt(), + EIP150Hash: "", }, true, }, @@ -71,7 +81,7 @@ func TestChainConfigValidate(t *testing.T) { DAOForkBlock: sdk.OneInt(), EIP150Block: sdk.OneInt(), EIP150Hash: defaultEIP150Hash, - EIP155Block: sdk.NewInt(-1), + EIP155Block: sdk.Int{}, }, true, }, @@ -83,7 +93,7 @@ func TestChainConfigValidate(t *testing.T) { EIP150Block: sdk.OneInt(), EIP150Hash: defaultEIP150Hash, EIP155Block: sdk.OneInt(), - EIP158Block: sdk.NewInt(-1), + EIP158Block: sdk.Int{}, }, true, }, @@ -96,7 +106,7 @@ func TestChainConfigValidate(t *testing.T) { EIP150Hash: defaultEIP150Hash, EIP155Block: sdk.OneInt(), EIP158Block: sdk.OneInt(), - ByzantiumBlock: sdk.NewInt(-1), + ByzantiumBlock: sdk.Int{}, }, true, }, @@ -110,7 +120,7 @@ func TestChainConfigValidate(t *testing.T) { EIP155Block: sdk.OneInt(), EIP158Block: sdk.OneInt(), ByzantiumBlock: sdk.OneInt(), - ConstantinopleBlock: sdk.NewInt(-1), + ConstantinopleBlock: sdk.Int{}, }, true, }, @@ -125,7 +135,7 @@ func TestChainConfigValidate(t *testing.T) { EIP158Block: sdk.OneInt(), ByzantiumBlock: sdk.OneInt(), ConstantinopleBlock: sdk.OneInt(), - PetersburgBlock: sdk.NewInt(-1), + PetersburgBlock: sdk.Int{}, }, true, }, @@ -140,7 +150,8 @@ func TestChainConfigValidate(t *testing.T) { EIP158Block: sdk.OneInt(), ByzantiumBlock: sdk.OneInt(), ConstantinopleBlock: sdk.OneInt(), - IstanbulBlock: sdk.NewInt(-1), + PetersburgBlock: sdk.OneInt(), + IstanbulBlock: sdk.Int{}, }, true, }, @@ -157,7 +168,7 @@ func TestChainConfigValidate(t *testing.T) { ConstantinopleBlock: sdk.OneInt(), PetersburgBlock: sdk.OneInt(), IstanbulBlock: sdk.OneInt(), - MuirGlacierBlock: sdk.NewInt(-1), + MuirGlacierBlock: sdk.Int{}, }, true, }, @@ -175,7 +186,7 @@ func TestChainConfigValidate(t *testing.T) { PetersburgBlock: sdk.OneInt(), IstanbulBlock: sdk.OneInt(), MuirGlacierBlock: sdk.OneInt(), - YoloV1Block: sdk.NewInt(-1), + YoloV1Block: sdk.Int{}, }, true, }, @@ -194,7 +205,7 @@ func TestChainConfigValidate(t *testing.T) { IstanbulBlock: sdk.OneInt(), MuirGlacierBlock: sdk.OneInt(), YoloV1Block: sdk.OneInt(), - EWASMBlock: sdk.NewInt(-1), + EWASMBlock: sdk.Int{}, }, true, }, diff --git a/x/evm/types/errors.go b/x/evm/types/errors.go index fdb2fd6a5..321b1747d 100644 --- a/x/evm/types/errors.go +++ b/x/evm/types/errors.go @@ -12,4 +12,7 @@ var ( // ErrChainConfigNotFound returns an error if the chain config cannot be found on the store. ErrChainConfigNotFound = sdkerrors.Register(ModuleName, 3, "chain configuration not found") + + // ErrInvalidChainConfig returns an error resulting from an invalid ChainConfig. + ErrInvalidChainConfig = sdkerrors.Register(ModuleName, 4, "invalid chain configuration") ) diff --git a/x/evm/types/genesis_test.go b/x/evm/types/genesis_test.go index 72c7b0101..c532fbc4d 100644 --- a/x/evm/types/genesis_test.go +++ b/x/evm/types/genesis_test.go @@ -122,6 +122,7 @@ func TestValidateGenesis(t *testing.T) { }, }, }, + Params: DefaultParams(), }, expPass: true, }, @@ -227,6 +228,13 @@ func TestValidateGenesis(t *testing.T) { }, expPass: false, }, + { + name: "invalid params", + genState: GenesisState{ + Params: Params{}, + }, + expPass: false, + }, } for _, tc := range testCases { diff --git a/x/evm/types/params_test.go b/x/evm/types/params_test.go index a6c78b899..71ebcb5ba 100644 --- a/x/evm/types/params_test.go +++ b/x/evm/types/params_test.go @@ -21,7 +21,7 @@ func TestParamsValidate(t *testing.T) { { "empty", Params{}, - false, + true, }, { "invalid evm denom", From 82697460913c24202576791163c41943e909deb2 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 13:34:54 +0200 Subject: [PATCH 09/27] update genesis --- x/evm/genesis.go | 4 ++++ x/evm/keeper/keeper.go | 2 +- x/evm/types/genesis.go | 9 ++++++++- x/evm/types/genesis_test.go | 15 +++++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/x/evm/genesis.go b/x/evm/genesis.go index 8759b3450..b2cda9ad5 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -28,6 +28,7 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU } } + k.SetChainConfig(ctx, data.ChainConfig) k.SetParams(ctx, data.Params) // set state objects and code to store @@ -76,9 +77,12 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta ethGenAccounts = append(ethGenAccounts, genAccount) } + config, _ := k.GetChainConfig(ctx) + return GenesisState{ Accounts: ethGenAccounts, TxsLogs: k.GetAllTxLogs(ctx), + ChainConfig: config, Params: k.GetParams(ctx), } } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 97f5d0b72..3f76a5086 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -154,7 +154,7 @@ func (k Keeper) GetChainConfig(ctx sdk.Context) (types.ChainConfig, bool) { } var config types.ChainConfig - k.cdc.MustUnmarshalBinaryBare(bz, config) + k.cdc.MustUnmarshalBinaryBare(bz, &config) return config, true } diff --git a/x/evm/types/genesis.go b/x/evm/types/genesis.go index da6e95bf2..c7ab538cf 100644 --- a/x/evm/types/genesis.go +++ b/x/evm/types/genesis.go @@ -15,6 +15,7 @@ type ( GenesisState struct { Accounts []GenesisAccount `json:"accounts"` TxsLogs []TransactionLogs `json:"txs_logs"` + ChainConfig ChainConfig `json:"chain_config"` Params Params `json:"params"` } @@ -47,11 +48,13 @@ func (ga GenesisAccount) Validate() error { return ga.Storage.Validate() } -// DefaultGenesisState sets default evm genesis state with empty accounts. +// DefaultGenesisState sets default evm genesis state with empty accounts and default params and +// chain config values. func DefaultGenesisState() GenesisState { return GenesisState{ Accounts: []GenesisAccount{}, TxsLogs: []TransactionLogs{}, + ChainConfig: DefaultChainConfig(), Params: DefaultParams(), } } @@ -82,5 +85,9 @@ func (gs GenesisState) Validate() error { seenTxs[tx.Hash.String()] = true } + if err := gs.ChainConfig.Validate(); err != nil { + return err + } + return gs.Params.Validate() } diff --git a/x/evm/types/genesis_test.go b/x/evm/types/genesis_test.go index c532fbc4d..6352e51ba 100644 --- a/x/evm/types/genesis_test.go +++ b/x/evm/types/genesis_test.go @@ -122,10 +122,16 @@ func TestValidateGenesis(t *testing.T) { }, }, }, + ChainConfig: DefaultChainConfig(), Params: DefaultParams(), }, expPass: true, }, + { + name: "empty genesis", + genState: GenesisState{}, + expPass: false, + }, { name: "invalid genesis", genState: GenesisState{ @@ -231,10 +237,19 @@ func TestValidateGenesis(t *testing.T) { { name: "invalid params", genState: GenesisState{ + ChainConfig: DefaultChainConfig(), Params: Params{}, }, expPass: false, }, + { + name: "invalid chain config", + genState: GenesisState{ + ChainConfig: ChainConfig{}, + Params: DefaultParams(), + }, + expPass: false, + }, } for _, tc := range testCases { From 39048afc23ee56575b6974dbc5a6f884ccf44633 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 16:11:50 +0200 Subject: [PATCH 10/27] update ante handler --- app/ante/ante.go | 9 +++---- app/ante/ante_test.go | 2 +- app/ante/eth.go | 44 ++++++++++++++++++++++----------- app/ante/utils_test.go | 2 +- app/ethermint.go | 2 +- x/evm/types/state_object.go | 11 ++++++--- x/evm/types/state_transition.go | 5 ++-- x/evm/types/statedb.go | 8 +++--- 8 files changed, 51 insertions(+), 32 deletions(-) diff --git a/app/ante/ante.go b/app/ante/ante.go index 86be60c58..581601504 100644 --- a/app/ante/ante.go +++ b/app/ante/ante.go @@ -6,7 +6,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" authante "github.com/cosmos/cosmos-sdk/x/auth/ante" "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/ethermint/crypto" evmtypes "github.com/cosmos/ethermint/x/evm/types" @@ -29,7 +28,7 @@ const ( // Ethereum or SDK transaction to an internal ante handler for performing // transaction-level processing (e.g. fee payment, signature verification) before // being passed onto it's respective handler. -func NewAnteHandler(ak auth.AccountKeeper, bk bank.Keeper, sk types.SupplyKeeper) sdk.AnteHandler { +func NewAnteHandler(ak auth.AccountKeeper, evmKeeper EVMKeeper, sk types.SupplyKeeper) sdk.AnteHandler { return func( ctx sdk.Context, tx sdk.Tx, sim bool, ) (newCtx sdk.Context, err error) { @@ -53,11 +52,11 @@ func NewAnteHandler(ak auth.AccountKeeper, bk bank.Keeper, sk types.SupplyKeeper case evmtypes.MsgEthereumTx: anteHandler = sdk.ChainAnteDecorators( NewEthSetupContextDecorator(), // outermost AnteDecorator. EthSetUpContext must be called first - NewEthMempoolFeeDecorator(), + NewEthMempoolFeeDecorator(evmKeeper), NewEthSigVerificationDecorator(), - NewAccountVerificationDecorator(ak, bk), + NewAccountVerificationDecorator(ak, evmKeeper), NewNonceVerificationDecorator(ak), - NewEthGasConsumeDecorator(ak, sk), + NewEthGasConsumeDecorator(ak, sk, evmKeeper), NewIncrementSenderSequenceDecorator(ak), // innermost AnteDecorator. ) default: diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index 385ac91e6..c9e2dc45d 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -254,7 +254,7 @@ func (suite *AnteTestSuite) TestEthInvalidMempoolFees() { // setup app with checkTx = true suite.app = app.Setup(true) suite.ctx = suite.app.BaseApp.NewContext(true, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()}) - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.SupplyKeeper) + suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper) suite.ctx = suite.ctx.WithMinGasPrices(sdk.NewDecCoins(sdk.NewDecCoin(types.DenomDefault, sdk.NewInt(500000)))) addr1, priv1 := newTestAddrKey() diff --git a/app/ante/eth.go b/app/ante/eth.go index 1688053a2..8dc13fd06 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -9,7 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" authante "github.com/cosmos/cosmos-sdk/x/auth/ante" "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/bank" emint "github.com/cosmos/ethermint/types" evmtypes "github.com/cosmos/ethermint/x/evm/types" @@ -18,6 +17,11 @@ import ( ethcore "github.com/ethereum/go-ethereum/core" ) +// EVMKeeper defines the expected keeper interface used on the Eth AnteHandler +type EVMKeeper interface { + GetParams(ctx sdk.Context) evmtypes.Params +} + // EthSetupContextDecorator sets the infinite GasMeter in the Context and wraps // the next AnteHandler with a defer clause to recover from any downstream // OutOfGas panics in the AnteHandler chain to return an error with information @@ -68,11 +72,15 @@ func (escd EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu // EthMempoolFeeDecorator validates that sufficient fees have been provided that // meet a minimum threshold defined by the proposer (for mempool purposes during CheckTx). -type EthMempoolFeeDecorator struct{} +type EthMempoolFeeDecorator struct{ + evmKeeper EVMKeeper +} // NewEthMempoolFeeDecorator creates a new EthMempoolFeeDecorator -func NewEthMempoolFeeDecorator() EthMempoolFeeDecorator { - return EthMempoolFeeDecorator{} +func NewEthMempoolFeeDecorator(ek EVMKeeper) EthMempoolFeeDecorator { + return EthMempoolFeeDecorator{ + evmKeeper: ek, + } } // AnteHandle verifies that enough fees have been provided by the @@ -90,8 +98,10 @@ func (emfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx) } + evmDenom := emfd.evmKeeper.GetParams(ctx).EvmDenom + // fee = GP * GL - fee := sdk.NewInt64DecCoin(emint.DenomDefault, msgEthTx.Fee().Int64()) + fee := sdk.NewInt64DecCoin(evmDenom, msgEthTx.Fee().Int64()) minGasPrices := ctx.MinGasPrices() @@ -99,7 +109,7 @@ func (emfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula // NOTE: we only check if aphotons are present in min gas prices. It is up to the // sender if they want to send additional fees in other denominations. var hasEnoughFees bool - if fee.Amount.GTE(minGasPrices.AmountOf(emint.DenomDefault)) { + if fee.Amount.GTE(minGasPrices.AmountOf(evmDenom)) { hasEnoughFees = true } @@ -151,14 +161,14 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s // AccountVerificationDecorator validates an account balance checks type AccountVerificationDecorator struct { ak auth.AccountKeeper - bk bank.Keeper + evmKeeper EVMKeeper } // NewAccountVerificationDecorator creates a new AccountVerificationDecorator -func NewAccountVerificationDecorator(ak auth.AccountKeeper, bk bank.Keeper) AccountVerificationDecorator { +func NewAccountVerificationDecorator(ak auth.AccountKeeper, ek EVMKeeper) AccountVerificationDecorator { return AccountVerificationDecorator{ ak: ak, - bk: bk, + evmKeeper: ek, } } @@ -192,12 +202,14 @@ func (avd AccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s ) } + evmDenom := avd.evmKeeper.GetParams(ctx).EvmDenom + // validate sender has enough funds to pay for gas cost - balance := sdk.Coin{Denom: emint.DenomDefault, Amount: acc.GetCoins().AmountOf(emint.DenomDefault)} - if balance.Amount.BigInt().Cmp(msgEthTx.Cost()) < 0 { + balance := acc.GetCoins().AmountOf(evmDenom) + if balance.BigInt().Cmp(msgEthTx.Cost()) < 0 { return ctx, sdkerrors.Wrapf( sdkerrors.ErrInsufficientFunds, - "sender balance < tx gas cost (%s < %s%s)", balance.String(), msgEthTx.Cost().String(), emint.DenomDefault, + "sender balance < tx gas cost (%s%s < %s%s)", balance.String(), evmDenom, msgEthTx.Cost().String(), evmDenom, ) } @@ -252,13 +264,15 @@ func (nvd NonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim type EthGasConsumeDecorator struct { ak auth.AccountKeeper sk types.SupplyKeeper + evmKeeper EVMKeeper } // NewEthGasConsumeDecorator creates a new EthGasConsumeDecorator -func NewEthGasConsumeDecorator(ak auth.AccountKeeper, sk types.SupplyKeeper) EthGasConsumeDecorator { +func NewEthGasConsumeDecorator(ak auth.AccountKeeper, sk types.SupplyKeeper, ek EVMKeeper) EthGasConsumeDecorator { return EthGasConsumeDecorator{ ak: ak, sk: sk, + evmKeeper: ek, } } @@ -307,8 +321,10 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula // Cost calculates the fees paid to validators based on gas limit and price cost := new(big.Int).Mul(msgEthTx.Data.Price, new(big.Int).SetUint64(gasLimit)) + evmDenom := egcd.evmKeeper.GetParams(ctx).EvmDenom + feeAmt := sdk.NewCoins( - sdk.NewCoin(emint.DenomDefault, sdk.NewIntFromBigInt(cost)), + sdk.NewCoin(evmDenom, sdk.NewIntFromBigInt(cost)), ) err = auth.DeductFees(egcd.sk, ctx, senderAcc, feeAmt) diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index a8cadaa69..3ff2218cf 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -38,7 +38,7 @@ func (suite *AnteTestSuite) SetupTest() { suite.app.Codec().RegisterConcrete(&sdk.TestMsg{}, "test/TestMsg", nil) suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()}) - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.SupplyKeeper) + suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper) } func TestAnteTestSuite(t *testing.T) { diff --git a/app/ethermint.go b/app/ethermint.go index fc52b50af..46f185e49 100644 --- a/app/ethermint.go +++ b/app/ethermint.go @@ -312,7 +312,7 @@ func NewEthermintApp( // initialize BaseApp app.SetInitChainer(app.InitChainer) app.SetBeginBlocker(app.BeginBlocker) - app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.BankKeeper, app.SupplyKeeper)) + app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.EvmKeeper, app.SupplyKeeper)) app.SetEndBlocker(app.EndBlocker) if loadLatest { diff --git a/x/evm/types/state_object.go b/x/evm/types/state_object.go index cbf226550..d7c6c749a 100644 --- a/x/evm/types/state_object.go +++ b/x/evm/types/state_object.go @@ -176,8 +176,8 @@ func (so *stateObject) AddBalance(amount *big.Int) { return } - // newBalance := so.balance.Add(amt) - newBalance := so.account.GetCoins().AmountOf(types.DenomDefault).Add(amt) + evmDenom := so.stateDB.GetParams().EvmDenom + newBalance := so.account.GetCoins().AmountOf(evmDenom).Add(amt) so.SetBalance(newBalance.BigInt()) } @@ -188,7 +188,9 @@ func (so *stateObject) SubBalance(amount *big.Int) { if amt.IsZero() { return } - newBalance := so.account.GetCoins().AmountOf(types.DenomDefault).Sub(amt) + + evmDenom := so.stateDB.GetParams().EvmDenom + newBalance := so.account.GetCoins().AmountOf(evmDenom).Sub(amt) so.SetBalance(newBalance.BigInt()) } @@ -196,9 +198,10 @@ func (so *stateObject) SubBalance(amount *big.Int) { func (so *stateObject) SetBalance(amount *big.Int) { amt := sdk.NewIntFromBigInt(amount) + evmDenom := so.stateDB.GetParams().EvmDenom so.stateDB.journal.append(balanceChange{ account: &so.address, - prev: so.account.GetCoins().AmountOf(types.DenomDefault), + prev: so.account.GetCoins().AmountOf(evmDenom), }) so.setBalance(amt) diff --git a/x/evm/types/state_transition.go b/x/evm/types/state_transition.go index 88cce02f1..bf3b62683 100644 --- a/x/evm/types/state_transition.go +++ b/x/evm/types/state_transition.go @@ -10,8 +10,6 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - emint "github.com/cosmos/ethermint/types" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -103,7 +101,8 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex // Clear cache of accounts to handle changes outside of the EVM csdb.UpdateAccounts() - gasPrice := ctx.MinGasPrices().AmountOf(emint.DenomDefault) + evmDenom := st.Csdb.GetParams().EvmDenom + gasPrice := ctx.MinGasPrices().AmountOf(evmDenom) if gasPrice.IsNil() { return nil, errors.New("gas price cannot be nil") } diff --git a/x/evm/types/statedb.go b/x/evm/types/statedb.go index dc2e5f7c5..526bf86f8 100644 --- a/x/evm/types/statedb.go +++ b/x/evm/types/statedb.go @@ -498,8 +498,9 @@ func (csdb *CommitStateDB) IntermediateRoot(deleteEmptyObjects bool) (ethcmn.Has // updateStateObject writes the given state object to the store. func (csdb *CommitStateDB) updateStateObject(so *stateObject) error { + evmDenom := csdb.GetParams().EvmDenom // NOTE: we don't use sdk.NewCoin here to avoid panic on test importer's genesis - newBalance := sdk.Coin{Denom: emint.DenomDefault, Amount: sdk.NewIntFromBigInt(so.Balance())} + newBalance := sdk.Coin{Denom: evmDenom, Amount: sdk.NewIntFromBigInt(so.Balance())} if !newBalance.IsValid() { return fmt.Errorf("invalid balance %s", newBalance) } @@ -639,9 +640,10 @@ func (csdb *CommitStateDB) UpdateAccounts() { continue } + evmDenom := csdb.GetParams().EvmDenom balance := sdk.Coin{ - Denom: emint.DenomDefault, - Amount: emintAcc.GetCoins().AmountOf(emint.DenomDefault), + Denom: evmDenom, + Amount: emintAcc.GetCoins().AmountOf(evmDenom), } if stateEntry.stateObject.Balance() != balance.Amount.BigInt() && balance.IsValid() || From 2289f343ff5db36e8c70b118b04f13ff116045e2 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 16:34:03 +0200 Subject: [PATCH 11/27] csdb param test --- x/evm/types/statedb_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/x/evm/types/statedb_test.go b/x/evm/types/statedb_test.go index 158df4103..455da85df 100644 --- a/x/evm/types/statedb_test.go +++ b/x/evm/types/statedb_test.go @@ -57,6 +57,16 @@ func (suite *StateDBTestSuite) SetupTest() { suite.app.AccountKeeper.SetAccount(suite.ctx, acc) suite.stateObject = suite.stateDB.GetOrNewStateObject(suite.address) } + +func (suite *StateDBTestSuite) TestParams() { + params := suite.stateDB.GetParams() + suite.Require().Equal(types.DefaultParams(), params) + params.EvmDenom = "ara" + suite.stateDB.SetParams(params) + newParams := suite.stateDB.GetParams() + suite.Require().Equal(newParams, params) +} + func (suite *StateDBTestSuite) TestBloomFilter() { // Prepare db for logs tHash := ethcmn.BytesToHash([]byte{0x1}) From 2a364e7345ce560c26f594e7ea438d20670c476c Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 16:53:14 +0200 Subject: [PATCH 12/27] more tests and fixes --- app/ethermint.go | 2 +- importer/importer_test.go | 13 +++++++------ x/evm/module_test.go | 7 +++++-- x/evm/types/params_test.go | 5 ++++- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/ethermint.go b/app/ethermint.go index 46f185e49..6ee053079 100644 --- a/app/ethermint.go +++ b/app/ethermint.go @@ -148,7 +148,7 @@ func NewEthermintApp( cdc := ethermintcodec.MakeCodec(ModuleBasics) - // use custom Ethermint transaction decoder + // NOTE we use custom Ethermint transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx bApp := bam.NewBaseApp(appName, logger, db, evm.TxDecoder(cdc), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) bApp.SetAppVersion(version.Version) diff --git a/importer/importer_test.go b/importer/importer_test.go index b676823ed..38acd2d38 100644 --- a/importer/importer_test.go +++ b/importer/importer_test.go @@ -101,12 +101,12 @@ func trapSignals() { } // nolint: interfacer -func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak auth.AccountKeeper) { +func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak auth.AccountKeeper, paramsSpace params.Subspace) { genBlock := ethcore.DefaultGenesisBlock() ms := cms.CacheMultiStore() ctx := sdk.NewContext(ms, abci.Header{}, false, logger) - stateDB := evmtypes.NewCommitStateDB(ctx, storeKey, ak) + stateDB := evmtypes.NewCommitStateDB(ctx, storeKey, paramsSpace, ak) // sort the addresses and insertion of key/value pairs matters genAddrs := make([]string, len(genBlock.Alloc)) @@ -182,6 +182,7 @@ func TestImportBlocks(t *testing.T) { paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams) // Set specific supspaces authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace) + evmSubspace := paramsKeeper.Subspace(evmtypes.DefaultParamspace) ak := auth.NewAccountKeeper(cdc, accKey, authSubspace, types.ProtoAccount) // mount stores @@ -197,7 +198,7 @@ func TestImportBlocks(t *testing.T) { require.NoError(t, err) // set and test genesis block - createAndTestGenesis(t, cms, ak) + createAndTestGenesis(t, cms, ak, evmSubspace) // open blockchain export file blockchainInput, err := os.Open(flagBlockchain) @@ -242,7 +243,7 @@ func TestImportBlocks(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, false, logger) ctx = ctx.WithBlockHeight(int64(block.NumberU64())) - stateDB := createStateDB(ctx, ak) + stateDB := createStateDB(ctx, ak, evmSubspace) if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 { applyDAOHardFork(stateDB) @@ -277,8 +278,8 @@ func TestImportBlocks(t *testing.T) { } // nolint: interfacer -func createStateDB(ctx sdk.Context, ak auth.AccountKeeper) *evmtypes.CommitStateDB { - return evmtypes.NewCommitStateDB(ctx, storeKey, ak) +func createStateDB(ctx sdk.Context, ak auth.AccountKeeper, paramsSpace params.Subspace) *evmtypes.CommitStateDB { + return evmtypes.NewCommitStateDB(ctx, storeKey, paramsSpace, ak) } // accumulateRewards credits the coinbase of the given block with the mining diff --git a/x/evm/module_test.go b/x/evm/module_test.go index d1d232ea5..561210c8d 100644 --- a/x/evm/module_test.go +++ b/x/evm/module_test.go @@ -18,8 +18,11 @@ var testJSON = `{ "address": "0x2cc7fdf9fde6746731d7f11979609d455c2c197a", "balance": 0, "code": "0x60806040" - } - ] + } + ], + "params": { + "evm_denom": "aphoton" + } }` func (suite *EvmTestSuite) TestInitGenesis() { diff --git a/x/evm/types/params_test.go b/x/evm/types/params_test.go index 71ebcb5ba..244e360c4 100644 --- a/x/evm/types/params_test.go +++ b/x/evm/types/params_test.go @@ -30,7 +30,6 @@ func TestParamsValidate(t *testing.T) { }, true, }, - } for _, tc := range testCases { @@ -47,3 +46,7 @@ func TestParamsValidate(t *testing.T) { func TestParamsValidatePriv(t *testing.T) { require.Error(t, validateEVMDenom(false)) } + +func TestParams_String(t *testing.T) { + require.Equal(t, "evm_denom: aphoton\n", DefaultParams().String()) +} From fa83504ad3909ccb0afc300da458978daaaba0f3 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 17:03:59 +0200 Subject: [PATCH 13/27] update statedb.Copy --- x/evm/types/state_transition.go | 2 +- x/evm/types/statedb.go | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/x/evm/types/state_transition.go b/x/evm/types/state_transition.go index bf3b62683..40767031b 100644 --- a/x/evm/types/state_transition.go +++ b/x/evm/types/state_transition.go @@ -101,7 +101,7 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex // Clear cache of accounts to handle changes outside of the EVM csdb.UpdateAccounts() - evmDenom := st.Csdb.GetParams().EvmDenom + evmDenom := csdb.GetParams().EvmDenom gasPrice := ctx.MinGasPrices().AmountOf(evmDenom) if gasPrice.IsNil() { return nil, errors.New("gas price cannot be nil") diff --git a/x/evm/types/statedb.go b/x/evm/types/statedb.go index 526bf86f8..1d47f39db 100644 --- a/x/evm/types/statedb.go +++ b/x/evm/types/statedb.go @@ -43,7 +43,7 @@ type CommitStateDB struct { ctx sdk.Context storeKey sdk.StoreKey - paramSpace params.Subspace + paramSpace params.Subspace accountKeeper AccountKeeper // array that hold 'live' objects, which will get modified while processing a @@ -93,7 +93,7 @@ func NewCommitStateDB( return &CommitStateDB{ ctx: ctx, storeKey: storeKey, - paramSpace: paramSpace, + paramSpace: paramSpace, accountKeeper: ak, stateObjects: []stateEntry{}, addressToObjectIndex: make(map[ethcmn.Address]int), @@ -118,7 +118,6 @@ func (csdb *CommitStateDB) SetParams(params Params) { csdb.paramSpace.SetParamSet(csdb.ctx, ¶ms) } - // SetBalance sets the balance of an account. func (csdb *CommitStateDB) SetBalance(addr ethcmn.Address, amount *big.Int) { so := csdb.GetOrNewStateObject(addr) @@ -246,7 +245,6 @@ func (csdb *CommitStateDB) SubRefund(gas uint64) { // Getters // ---------------------------------------------------------------------------- - // GetParams returns the total set of evm parameters. func (csdb *CommitStateDB) GetParams() (params Params) { csdb.paramSpace.GetParamSet(csdb.ctx, ¶ms) @@ -702,6 +700,7 @@ func (csdb *CommitStateDB) Copy() *CommitStateDB { state := &CommitStateDB{ ctx: csdb.ctx, storeKey: csdb.storeKey, + paramSpace: csdb.paramSpace, accountKeeper: csdb.accountKeeper, stateObjects: make([]stateEntry, len(csdb.journal.dirties)), addressToObjectIndex: make(map[ethcmn.Address]int, len(csdb.journal.dirties)), From ab18272a863fa438c3180139583ad0f99d5a8116 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 17:10:26 +0200 Subject: [PATCH 14/27] lint --- app/ante/eth.go | 14 +++++++------- x/evm/genesis.go | 6 +++--- x/evm/keeper/keeper.go | 7 +++---- x/evm/types/chain_config.go | 19 +++++++++---------- x/evm/types/errors.go | 2 +- x/evm/types/genesis.go | 14 +++++++------- x/evm/types/genesis_test.go | 10 +++++----- x/evm/types/key.go | 12 ++++++------ x/evm/types/params.go | 4 +--- 9 files changed, 42 insertions(+), 46 deletions(-) diff --git a/app/ante/eth.go b/app/ante/eth.go index 8dc13fd06..0cd6b437f 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -72,7 +72,7 @@ func (escd EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu // EthMempoolFeeDecorator validates that sufficient fees have been provided that // meet a minimum threshold defined by the proposer (for mempool purposes during CheckTx). -type EthMempoolFeeDecorator struct{ +type EthMempoolFeeDecorator struct { evmKeeper EVMKeeper } @@ -160,14 +160,14 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s // AccountVerificationDecorator validates an account balance checks type AccountVerificationDecorator struct { - ak auth.AccountKeeper + ak auth.AccountKeeper evmKeeper EVMKeeper } // NewAccountVerificationDecorator creates a new AccountVerificationDecorator func NewAccountVerificationDecorator(ak auth.AccountKeeper, ek EVMKeeper) AccountVerificationDecorator { return AccountVerificationDecorator{ - ak: ak, + ak: ak, evmKeeper: ek, } } @@ -262,16 +262,16 @@ func (nvd NonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim // EthGasConsumeDecorator validates enough intrinsic gas for the transaction and // gas consumption. type EthGasConsumeDecorator struct { - ak auth.AccountKeeper - sk types.SupplyKeeper + ak auth.AccountKeeper + sk types.SupplyKeeper evmKeeper EVMKeeper } // NewEthGasConsumeDecorator creates a new EthGasConsumeDecorator func NewEthGasConsumeDecorator(ak auth.AccountKeeper, sk types.SupplyKeeper, ek EVMKeeper) EthGasConsumeDecorator { return EthGasConsumeDecorator{ - ak: ak, - sk: sk, + ak: ak, + sk: sk, evmKeeper: ek, } } diff --git a/x/evm/genesis.go b/x/evm/genesis.go index b2cda9ad5..da55321d3 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -80,9 +80,9 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta config, _ := k.GetChainConfig(ctx) return GenesisState{ - Accounts: ethGenAccounts, - TxsLogs: k.GetAllTxLogs(ctx), + Accounts: ethGenAccounts, + TxsLogs: k.GetAllTxLogs(ctx), ChainConfig: config, - Params: k.GetParams(ctx), + Params: k.GetParams(ctx), } } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 3f76a5086..9706d16df 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -22,14 +22,14 @@ import ( // to the StateDB interface. type Keeper struct { // Amino codec - cdc *codec.Codec + cdc *codec.Codec // Store key required for the EVM Prefix KVStore. It is required by: // - storing Account's Storage State // - storing Account's Code // - storing transaction Logs // - storing block height -> bloom filter map. Needed for the Web3 API. // - storing block hash -> block height map. Needed for the Web3 API. - storeKey sdk.StoreKey + storeKey sdk.StoreKey // Ethermint concrete implementation on the EVM StateDB interface CommitStateDB *types.CommitStateDB // Transaction counter in a block. Used on StateSB's Prepare function. @@ -143,7 +143,6 @@ func (k Keeper) GetAccountStorage(ctx sdk.Context, address common.Address) (type return storage, nil } - // GetChainConfig gets block height from block consensus hash func (k Keeper) GetChainConfig(ctx sdk.Context) (types.ChainConfig, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixChainConfig) @@ -164,4 +163,4 @@ func (k Keeper) SetChainConfig(ctx sdk.Context, config types.ChainConfig) { bz := k.cdc.MustMarshalBinaryBare(config) // get to an empty key that's already prefixed by KeyPrefixChainConfig store.Set([]byte{}, bz) -} \ No newline at end of file +} diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index b00f2bb9a..56e2e7955 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -23,24 +23,24 @@ import ( type ChainConfig struct { HomesteadBlock sdk.Int `json:"homestead_block" yaml:"homestead_block"` // Homestead switch block (nil = no fork, 0 < already homestead) - DAOForkBlock sdk.Int `json:"dao_fork_block" yaml:"dao_fork_block"` // TheDAO hard-fork switch block (nil = no fork) + DAOForkBlock sdk.Int `json:"dao_fork_block" yaml:"dao_fork_block"` // TheDAO hard-fork switch block (nil = no fork) DAOForkSupport bool `json:"dao_fork_support" yaml:"dao_fork_support"` // Whether the nodes supports or opposes the DAO hard-fork // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) EIP150Block sdk.Int `json:"eip150_block" yaml:"eip150_block"` // EIP150 HF block (nil = no fork) - EIP150Hash string `json:"eip150_hash" yaml:"eip150_hash"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) + EIP150Hash string `json:"eip150_hash" yaml:"eip150_hash"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) EIP155Block sdk.Int `json:"eip155_block" yaml:"eip155_block"` // EIP155 HF block EIP158Block sdk.Int `json:"eip158_block" yaml:"eip158_block"` // EIP158 HF block - ByzantiumBlock sdk.Int `json:"byzantium_block" yaml:"byzantium_block"` // Byzantium switch block (nil = no fork, 0 < already on byzantium) + ByzantiumBlock sdk.Int `json:"byzantium_block" yaml:"byzantium_block"` // Byzantium switch block (nil = no fork, 0 < already on byzantium) ConstantinopleBlock sdk.Int `json:"constantinople_block" yaml:"constantinople_block"` // Constantinople switch block (nil = no fork, 0 < already activated) - PetersburgBlock sdk.Int `json:"petersburg_block" yaml:"petersburg_block"` // Petersburg switch block (nil = same as Constantinople) - IstanbulBlock sdk.Int `json:"istanbul_block" yaml:"istanbul_block"` // Istanbul switch block (nil = no fork, 0 < already on istanbul) - MuirGlacierBlock sdk.Int `json:"muir_glacier_block" yaml:"muir_glacier_block"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 < already activated) + PetersburgBlock sdk.Int `json:"petersburg_block" yaml:"petersburg_block"` // Petersburg switch block (nil = same as Constantinople) + IstanbulBlock sdk.Int `json:"istanbul_block" yaml:"istanbul_block"` // Istanbul switch block (nil = no fork, 0 < already on istanbul) + MuirGlacierBlock sdk.Int `json:"muir_glacier_block" yaml:"muir_glacier_block"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 < already activated) YoloV1Block sdk.Int `json:"yoloV1_block" yaml:"yoloV1_block"` // YOLO v1: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet) - EWASMBlock sdk.Int `json:"ewasm_block" yaml:"ewasm_block"` // EWASM switch block (nil = no fork, 0 = already activated) + EWASMBlock sdk.Int `json:"ewasm_block" yaml:"ewasm_block"` // EWASM switch block (nil = no fork, 0 = already activated) } // EthereumConfig returns an Ethereum ChainConfig for EVM state transitions. @@ -145,7 +145,6 @@ func (cc ChainConfig) Validate() error { return nil } - func validateHash(hex string) error { if strings.TrimSpace(hex) == "" { return sdkerrors.Wrapf(ErrInvalidChainConfig, "hash cannot be blank") @@ -161,7 +160,7 @@ func validateHash(hex string) error { } func validateBlock(block sdk.Int) error { - if block == (sdk.Int{}) || block.BigInt() == nil { + if block == (sdk.Int{}) || block.BigInt() == nil { return sdkerrors.Wrapf( ErrInvalidChainConfig, "cannot use uninitialized or nil values for Int, set a negative Int value if you want to define a nil Ethereum block", @@ -169,4 +168,4 @@ func validateBlock(block sdk.Int) error { } return nil -} \ No newline at end of file +} diff --git a/x/evm/types/errors.go b/x/evm/types/errors.go index 321b1747d..7754f555f 100644 --- a/x/evm/types/errors.go +++ b/x/evm/types/errors.go @@ -9,7 +9,7 @@ import ( var ( // ErrInvalidState returns an error resulting from an invalid Storage State. ErrInvalidState = sdkerrors.Register(ModuleName, 2, "invalid storage state") - + // ErrChainConfigNotFound returns an error if the chain config cannot be found on the store. ErrChainConfigNotFound = sdkerrors.Register(ModuleName, 3, "chain configuration not found") diff --git a/x/evm/types/genesis.go b/x/evm/types/genesis.go index c7ab538cf..82db992d3 100644 --- a/x/evm/types/genesis.go +++ b/x/evm/types/genesis.go @@ -13,10 +13,10 @@ import ( type ( // GenesisState defines the evm module genesis state GenesisState struct { - Accounts []GenesisAccount `json:"accounts"` - TxsLogs []TransactionLogs `json:"txs_logs"` - ChainConfig ChainConfig `json:"chain_config"` - Params Params `json:"params"` + Accounts []GenesisAccount `json:"accounts"` + TxsLogs []TransactionLogs `json:"txs_logs"` + ChainConfig ChainConfig `json:"chain_config"` + Params Params `json:"params"` } // GenesisAccount defines an account to be initialized in the genesis state. @@ -52,10 +52,10 @@ func (ga GenesisAccount) Validate() error { // chain config values. func DefaultGenesisState() GenesisState { return GenesisState{ - Accounts: []GenesisAccount{}, - TxsLogs: []TransactionLogs{}, + Accounts: []GenesisAccount{}, + TxsLogs: []TransactionLogs{}, ChainConfig: DefaultChainConfig(), - Params: DefaultParams(), + Params: DefaultParams(), } } diff --git a/x/evm/types/genesis_test.go b/x/evm/types/genesis_test.go index 6352e51ba..8f499aab0 100644 --- a/x/evm/types/genesis_test.go +++ b/x/evm/types/genesis_test.go @@ -123,14 +123,14 @@ func TestValidateGenesis(t *testing.T) { }, }, ChainConfig: DefaultChainConfig(), - Params: DefaultParams(), + Params: DefaultParams(), }, expPass: true, }, { - name: "empty genesis", + name: "empty genesis", genState: GenesisState{}, - expPass: false, + expPass: false, }, { name: "invalid genesis", @@ -238,7 +238,7 @@ func TestValidateGenesis(t *testing.T) { name: "invalid params", genState: GenesisState{ ChainConfig: DefaultChainConfig(), - Params: Params{}, + Params: Params{}, }, expPass: false, }, @@ -246,7 +246,7 @@ func TestValidateGenesis(t *testing.T) { name: "invalid chain config", genState: GenesisState{ ChainConfig: ChainConfig{}, - Params: DefaultParams(), + Params: DefaultParams(), }, expPass: false, }, diff --git a/x/evm/types/key.go b/x/evm/types/key.go index 6f03a18fa..a5e7d665a 100644 --- a/x/evm/types/key.go +++ b/x/evm/types/key.go @@ -21,12 +21,12 @@ const ( // KVStore key prefixes var ( - KeyPrefixBlockHash = []byte{0x01} - KeyPrefixBloom = []byte{0x02} - KeyPrefixLogs = []byte{0x03} - KeyPrefixCode = []byte{0x04} - KeyPrefixStorage = []byte{0x05} - KeyPrefixChainConfig = []byte{0x06} + KeyPrefixBlockHash = []byte{0x01} + KeyPrefixBloom = []byte{0x02} + KeyPrefixLogs = []byte{0x03} + KeyPrefixCode = []byte{0x04} + KeyPrefixStorage = []byte{0x05} + KeyPrefixChainConfig = []byte{0x06} ) // BloomKey defines the store key for a block Bloom diff --git a/x/evm/types/params.go b/x/evm/types/params.go index 9ceb55204..59d837d91 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -19,7 +19,6 @@ const ( // Parameter keys var ( ParamStoreKeyEVMDenom = []byte("EVMDenom") - ) // ParamKeyTable returns the parameter key table. @@ -27,7 +26,6 @@ func ParamKeyTable() params.KeyTable { return params.NewKeyTable().RegisterParamSet(&Params{}) } - // Params defines the EVM module parameters type Params struct { EvmDenom string `json:"evm_denom" yaml:"evm_denom"` @@ -72,4 +70,4 @@ func validateEVMDenom(i interface{}) error { } return sdk.ValidateDenom(denom) -} \ No newline at end of file +} From c7c89ab368ca99bde9d843703bf665b9280f68a7 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 17:22:56 +0200 Subject: [PATCH 15/27] additional test --- x/evm/keeper/keeper_test.go | 13 +++++++++++++ x/evm/types/chain_config.go | 27 ++++++++++++++------------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index b02eee92e..2483ff06d 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/ethermint/app" ethermint "github.com/cosmos/ethermint/types" "github.com/cosmos/ethermint/x/evm/keeper" + "github.com/cosmos/ethermint/x/evm/types" ethcmn "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -148,3 +149,15 @@ func (suite *KeeperTestSuite) TestDBStorage() { // simulate BaseApp EndBlocker commitment suite.app.Commit() } + +func (suite *KeeperTestSuite) TestChainConfig() { + config, found := suite.app.EvmKeeper.GetChainConfig(suite.ctx) + suite.Require().True(found) + suite.Require().Equal(types.DefaultChainConfig(), config) + + config.EIP150Block = sdk.NewInt(100) + suite.app.EvmKeeper.SetChainConfig(suite.ctx, config) + newConfig, found := suite.app.EvmKeeper.GetChainConfig(suite.ctx) + suite.Require().True(found) + suite.Require().Equal(config, newConfig) +} diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index 56e2e7955..d7941be50 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -15,32 +15,33 @@ import ( // ChainConfig defines the Ethereum ChainConfig parameters using sdk.Int values instead of big.Int. // -// NOTE 1: Since empty Int (i.e with a nil big.Int value) are parsed to zero, we need to manually -// specify +// NOTE 1: Since empty/uninitialized Ints (i.e with a nil big.Int value) are parsed to zero, we need to manually +// specify that negative Int values will be considered as nil. See getBlockValue for reference. +// // NOTE 2: This type is not a configurable Param since the SDK does not allow for validation against -// previous stored parameter values or current block height. In order to update the values, a -// hard-fork upgrade must be done. +// a previous stored parameter values or the current block height (retrieved from context). If you +// want to update the config values, use an software upgrade procedure. type ChainConfig struct { - HomesteadBlock sdk.Int `json:"homestead_block" yaml:"homestead_block"` // Homestead switch block (nil = no fork, 0 < already homestead) + HomesteadBlock sdk.Int `json:"homestead_block" yaml:"homestead_block"` // Homestead switch block (< 0 no fork, 0 = already homestead) - DAOForkBlock sdk.Int `json:"dao_fork_block" yaml:"dao_fork_block"` // TheDAO hard-fork switch block (nil = no fork) + DAOForkBlock sdk.Int `json:"dao_fork_block" yaml:"dao_fork_block"` // TheDAO hard-fork switch block (< 0 no fork) DAOForkSupport bool `json:"dao_fork_support" yaml:"dao_fork_support"` // Whether the nodes supports or opposes the DAO hard-fork // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) - EIP150Block sdk.Int `json:"eip150_block" yaml:"eip150_block"` // EIP150 HF block (nil = no fork) + EIP150Block sdk.Int `json:"eip150_block" yaml:"eip150_block"` // EIP150 HF block (< 0 no fork) EIP150Hash string `json:"eip150_hash" yaml:"eip150_hash"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) EIP155Block sdk.Int `json:"eip155_block" yaml:"eip155_block"` // EIP155 HF block EIP158Block sdk.Int `json:"eip158_block" yaml:"eip158_block"` // EIP158 HF block - ByzantiumBlock sdk.Int `json:"byzantium_block" yaml:"byzantium_block"` // Byzantium switch block (nil = no fork, 0 < already on byzantium) - ConstantinopleBlock sdk.Int `json:"constantinople_block" yaml:"constantinople_block"` // Constantinople switch block (nil = no fork, 0 < already activated) - PetersburgBlock sdk.Int `json:"petersburg_block" yaml:"petersburg_block"` // Petersburg switch block (nil = same as Constantinople) - IstanbulBlock sdk.Int `json:"istanbul_block" yaml:"istanbul_block"` // Istanbul switch block (nil = no fork, 0 < already on istanbul) - MuirGlacierBlock sdk.Int `json:"muir_glacier_block" yaml:"muir_glacier_block"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 < already activated) + ByzantiumBlock sdk.Int `json:"byzantium_block" yaml:"byzantium_block"` // Byzantium switch block (< 0 no fork, 0 = already on byzantium) + ConstantinopleBlock sdk.Int `json:"constantinople_block" yaml:"constantinople_block"` // Constantinople switch block (< 0 no fork, 0 = already activated) + PetersburgBlock sdk.Int `json:"petersburg_block" yaml:"petersburg_block"` // Petersburg switch block (< 0 same as Constantinople) + IstanbulBlock sdk.Int `json:"istanbul_block" yaml:"istanbul_block"` // Istanbul switch block (< 0 no fork, 0 = already on istanbul) + MuirGlacierBlock sdk.Int `json:"muir_glacier_block" yaml:"muir_glacier_block"` // Eip-2384 (bomb delay) switch block (< 0 no fork, 0 = already activated) YoloV1Block sdk.Int `json:"yoloV1_block" yaml:"yoloV1_block"` // YOLO v1: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet) - EWASMBlock sdk.Int `json:"ewasm_block" yaml:"ewasm_block"` // EWASM switch block (nil = no fork, 0 = already activated) + EWASMBlock sdk.Int `json:"ewasm_block" yaml:"ewasm_block"` // EWASM switch block (< 0 no fork, 0 = already activated) } // EthereumConfig returns an Ethereum ChainConfig for EVM state transitions. From d1c1e0a56fca3d6e227121ff3f6253f6b066be39 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 18:12:51 +0200 Subject: [PATCH 16/27] fix importer tests --- Makefile | 2 +- importer/importer_test.go | 94 +++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 04ed50003..eb2f57395 100644 --- a/Makefile +++ b/Makefile @@ -211,7 +211,7 @@ test-race: test-import: @go test ./importer -v --vet=off --run=TestImportBlocks --datadir tmp \ - --blockchain blockchain --timeout=10m + --blockchain blockchain rm -rf importer/tmp test-rpc: diff --git a/importer/importer_test.go b/importer/importer_test.go index 38acd2d38..9aebb3050 100644 --- a/importer/importer_test.go +++ b/importer/importer_test.go @@ -26,6 +26,7 @@ import ( "github.com/cosmos/ethermint/core" emintcrypto "github.com/cosmos/ethermint/crypto" "github.com/cosmos/ethermint/types" + "github.com/cosmos/ethermint/x/evm" evmtypes "github.com/cosmos/ethermint/x/evm/types" ethcmn "github.com/ethereum/go-ethereum/common" @@ -49,9 +50,6 @@ var ( genInvestor = ethcmn.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b5a0") - accKey = sdk.NewKVStoreKey(auth.StoreKey) - storeKey = sdk.NewKVStoreKey(evmtypes.StoreKey) - logger = tmlog.NewNopLogger() rewardBig8 = big.NewInt(8) @@ -101,12 +99,13 @@ func trapSignals() { } // nolint: interfacer -func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak auth.AccountKeeper, paramsSpace params.Subspace) { +func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak auth.AccountKeeper, evmKeeper evm.Keeper) { genBlock := ethcore.DefaultGenesisBlock() ms := cms.CacheMultiStore() ctx := sdk.NewContext(ms, abci.Header{}, false, logger) - stateDB := evmtypes.NewCommitStateDB(ctx, storeKey, paramsSpace, ak) + // Set the default Ethermint parameters to the parameter keeper store + evmKeeper.SetParams(ctx, evmtypes.DefaultParams()) // sort the addresses and insertion of key/value pairs matters genAddrs := make([]string, len(genBlock.Alloc)) @@ -122,23 +121,23 @@ func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak auth.Accoun addr := ethcmn.HexToAddress(addrStr) acc := genBlock.Alloc[addr] - stateDB.AddBalance(addr, acc.Balance) - stateDB.SetCode(addr, acc.Code) - stateDB.SetNonce(addr, acc.Nonce) + evmKeeper.AddBalance(ctx, addr, acc.Balance) + evmKeeper.SetCode(ctx, addr, acc.Code) + evmKeeper.SetNonce(ctx, addr, acc.Nonce) for key, value := range acc.Storage { - stateDB.SetState(addr, key, value) + evmKeeper.SetState(ctx, addr, key, value) } } // get balance of one of the genesis account having 400 ETH - b := stateDB.GetBalance(genInvestor) + b := evmKeeper.GetBalance(ctx, genInvestor) require.Equal(t, "200000000000000000000", b.String()) // commit the stateDB with 'false' to delete empty objects // // NOTE: Commit does not yet return the intra merkle root (version) - _, err := stateDB.Commit(false) + _, err := evmKeeper.Commit(ctx, false) require.NoError(t, err) // persist multi-store cache state @@ -176,21 +175,27 @@ func TestImportBlocks(t *testing.T) { cms := store.NewCommitMultiStore(db) - // The ParamsKeeper handles parameter storage for the application - keyParams := sdk.NewKVStoreKey(params.StoreKey) - tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey) - paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams) - // Set specific supspaces - authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace) - evmSubspace := paramsKeeper.Subspace(evmtypes.DefaultParamspace) - ak := auth.NewAccountKeeper(cdc, accKey, authSubspace, types.ProtoAccount) + authStoreKey := sdk.NewKVStoreKey(auth.StoreKey) + evmStoreKey := sdk.NewKVStoreKey(evmtypes.StoreKey) + paramsStoreKey := sdk.NewKVStoreKey(params.StoreKey) + paramsTransientStoreKey := sdk.NewTransientStoreKey(params.TStoreKey) // mount stores - keys := []*sdk.KVStoreKey{accKey, storeKey} + keys := []*sdk.KVStoreKey{authStoreKey, evmStoreKey, paramsStoreKey} for _, key := range keys { cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, nil) } + cms.MountStoreWithDB(paramsTransientStoreKey, sdk.StoreTypeTransient, nil) + + paramsKeeper := params.NewKeeper(cdc, paramsStoreKey, paramsTransientStoreKey) + + // Set specific subspaces + authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace) + evmSubspace := paramsKeeper.Subspace(evmtypes.DefaultParamspace).WithKeyTable(evmtypes.ParamKeyTable()) + ak := auth.NewAccountKeeper(cdc, authStoreKey, authSubspace, types.ProtoAccount) + evmKeeper := evm.NewKeeper(cdc, evmStoreKey, evmSubspace, ak) + cms.SetPruning(sdkstore.PruneNothing) // load latest version (root) @@ -198,7 +203,7 @@ func TestImportBlocks(t *testing.T) { require.NoError(t, err) // set and test genesis block - createAndTestGenesis(t, cms, ak, evmSubspace) + createAndTestGenesis(t, cms, ak, evmKeeper) // open blockchain export file blockchainInput, err := os.Open(flagBlockchain) @@ -243,27 +248,25 @@ func TestImportBlocks(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, false, logger) ctx = ctx.WithBlockHeight(int64(block.NumberU64())) - stateDB := createStateDB(ctx, ak, evmSubspace) - if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 { - applyDAOHardFork(stateDB) + applyDAOHardFork(evmKeeper) } for i, tx := range block.Transactions() { - stateDB.Prepare(tx.Hash(), block.Hash(), i) + evmKeeper.Prepare(ctx, tx.Hash(), block.Hash(), i) receipt, gas, err := applyTransaction( - chainConfig, chainContext, nil, gp, stateDB, header, tx, usedGas, vmConfig, + chainConfig, chainContext, nil, gp, evmKeeper, header, tx, usedGas, vmConfig, ) require.NoError(t, err, "failed to apply tx at block %d; tx: %X; gas %d; receipt:%v", block.NumberU64(), tx.Hash(), gas, receipt) require.NotNil(t, receipt) } // apply mining rewards - accumulateRewards(chainConfig, stateDB, header, block.Uncles()) + accumulateRewards(chainConfig, evmKeeper, header, block.Uncles()) // commit stateDB - _, err := stateDB.Commit(chainConfig.IsEIP158(block.Number())) + _, err := evmKeeper.CommitStateDB.Commit(chainConfig.IsEIP158(block.Number())) require.NoError(t, err, "failed to commit StateDB") // simulate BaseApp EndBlocker commitment @@ -277,16 +280,11 @@ func TestImportBlocks(t *testing.T) { } } -// nolint: interfacer -func createStateDB(ctx sdk.Context, ak auth.AccountKeeper, paramsSpace params.Subspace) *evmtypes.CommitStateDB { - return evmtypes.NewCommitStateDB(ctx, storeKey, paramsSpace, ak) -} - // accumulateRewards credits the coinbase of the given block with the mining // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. func accumulateRewards( - config *ethparams.ChainConfig, stateDB *evmtypes.CommitStateDB, + config *ethparams.ChainConfig, evmKeeper evm.Keeper, header *ethtypes.Header, uncles []*ethtypes.Header, ) { @@ -305,12 +303,12 @@ func accumulateRewards( r.Sub(r, header.Number) r.Mul(r, blockReward) r.Div(r, rewardBig8) - stateDB.AddBalance(uncle.Coinbase, r) + evmKeeper.CommitStateDB.AddBalance(uncle.Coinbase, r) r.Div(blockReward, rewardBig32) reward.Add(reward, r) } - stateDB.AddBalance(header.Coinbase, reward) + evmKeeper.CommitStateDB.AddBalance(header.Coinbase, reward) } // ApplyDAOHardFork modifies the state database according to the DAO hard-fork @@ -319,16 +317,16 @@ func accumulateRewards( // Code is pulled from go-ethereum 1.9 because the StateDB interface does not include the // SetBalance function implementation // Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/consensus/misc/dao.go#L74 -func applyDAOHardFork(statedb *evmtypes.CommitStateDB) { +func applyDAOHardFork(evmKeeper evm.Keeper) { // Retrieve the contract to refund balances into - if !statedb.Exist(ethparams.DAORefundContract) { - statedb.CreateAccount(ethparams.DAORefundContract) + if !evmKeeper.CommitStateDB.Exist(ethparams.DAORefundContract) { + evmKeeper.CommitStateDB.CreateAccount(ethparams.DAORefundContract) } // Move every DAO account and extra-balance account funds into the refund contract for _, addr := range ethparams.DAODrainList() { - statedb.AddBalance(ethparams.DAORefundContract, statedb.GetBalance(addr)) - statedb.SetBalance(addr, new(big.Int)) + evmKeeper.CommitStateDB.AddBalance(ethparams.DAORefundContract, evmKeeper.CommitStateDB.GetBalance(addr)) + evmKeeper.CommitStateDB.SetBalance(addr, new(big.Int)) } } @@ -340,7 +338,7 @@ func applyDAOHardFork(statedb *evmtypes.CommitStateDB) { // Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/core/state_processor.go#L88 func applyTransaction( config *ethparams.ChainConfig, bc ethcore.ChainContext, author *ethcmn.Address, - gp *ethcore.GasPool, statedb *evmtypes.CommitStateDB, header *ethtypes.Header, + gp *ethcore.GasPool, evmKeeper evm.Keeper, header *ethtypes.Header, tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config, ) (*ethtypes.Receipt, uint64, error) { msg, err := tx.AsMessage(ethtypes.MakeSigner(config, header.Number)) @@ -353,7 +351,7 @@ func applyTransaction( // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. - vmenv := ethvm.NewEVM(context, statedb, config, cfg) + vmenv := ethvm.NewEVM(context, evmKeeper.CommitStateDB, config, cfg) // Apply the transaction to the current state (included in the env) execResult, err := ethcore.ApplyMessage(vmenv, msg, gp) @@ -365,9 +363,9 @@ func applyTransaction( // Update the state with pending changes var intRoot ethcmn.Hash if config.IsByzantium(header.Number) { - err = statedb.Finalise(true) + err = evmKeeper.CommitStateDB.Finalise(true) } else { - intRoot, err = statedb.IntermediateRoot(config.IsEIP158(header.Number)) + intRoot, err = evmKeeper.CommitStateDB.IntermediateRoot(config.IsEIP158(header.Number)) } if err != nil { @@ -389,11 +387,11 @@ func applyTransaction( } // Set the receipt logs and create a bloom for filtering - receipt.Logs, err = statedb.GetLogs(tx.Hash()) + receipt.Logs, err = evmKeeper.CommitStateDB.GetLogs(tx.Hash()) receipt.Bloom = ethtypes.CreateBloom(ethtypes.Receipts{receipt}) - receipt.BlockHash = statedb.BlockHash() + receipt.BlockHash = evmKeeper.CommitStateDB.BlockHash() receipt.BlockNumber = header.Number - receipt.TransactionIndex = uint(statedb.TxIndex()) + receipt.TransactionIndex = uint(evmKeeper.CommitStateDB.TxIndex()) return receipt, execResult.UsedGas, err } From d267cc3a571c1e51aa4f7134709e04295dae1c36 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 18:30:22 +0200 Subject: [PATCH 17/27] fix AnteHandler test --- app/ante/ante_test.go | 3 ++- app/ante/utils_test.go | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index c9e2dc45d..4288bb630 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -254,8 +254,9 @@ func (suite *AnteTestSuite) TestEthInvalidMempoolFees() { // setup app with checkTx = true suite.app = app.Setup(true) suite.ctx = suite.app.BaseApp.NewContext(true, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()}) - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper) + suite.app.EvmKeeper.SetParams(suite.ctx, evmtypes.DefaultParams()) + suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper) suite.ctx = suite.ctx.WithMinGasPrices(sdk.NewDecCoins(sdk.NewDecCoin(types.DenomDefault, sdk.NewInt(500000)))) addr1, priv1 := newTestAddrKey() addr2, _ := newTestAddrKey() diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index 3ff2218cf..30fbcbd55 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -38,6 +38,8 @@ func (suite *AnteTestSuite) SetupTest() { suite.app.Codec().RegisterConcrete(&sdk.TestMsg{}, "test/TestMsg", nil) suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()}) + suite.app.EvmKeeper.SetParams(suite.ctx, evmtypes.DefaultParams()) + suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper) } From 7fe95ba7216521a40fbdc042c25755086f0e4b3f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 18:32:03 +0200 Subject: [PATCH 18/27] minor update --- app/ante/ante_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index 4288bb630..d8d7219f5 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -254,8 +254,6 @@ func (suite *AnteTestSuite) TestEthInvalidMempoolFees() { // setup app with checkTx = true suite.app = app.Setup(true) suite.ctx = suite.app.BaseApp.NewContext(true, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()}) - suite.app.EvmKeeper.SetParams(suite.ctx, evmtypes.DefaultParams()) - suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper) suite.ctx = suite.ctx.WithMinGasPrices(sdk.NewDecCoins(sdk.NewDecCoin(types.DenomDefault, sdk.NewInt(500000)))) addr1, priv1 := newTestAddrKey() From 94adf0fd94a4ec5d527b50c617cbc71f45b4a8f0 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 18:35:50 +0200 Subject: [PATCH 19/27] revert --- app/ante/ante_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index d8d7219f5..4288bb630 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -254,6 +254,8 @@ func (suite *AnteTestSuite) TestEthInvalidMempoolFees() { // setup app with checkTx = true suite.app = app.Setup(true) suite.ctx = suite.app.BaseApp.NewContext(true, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()}) + suite.app.EvmKeeper.SetParams(suite.ctx, evmtypes.DefaultParams()) + suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper) suite.ctx = suite.ctx.WithMinGasPrices(sdk.NewDecCoins(sdk.NewDecCoin(types.DenomDefault, sdk.NewInt(500000)))) addr1, priv1 := newTestAddrKey() From 86dbdb5b29d67c7c9c42658fe4146db33689f6e7 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 18:41:58 +0200 Subject: [PATCH 20/27] undo gas update --- tests/rpc_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rpc_test.go b/tests/rpc_test.go index 5e9d90efd..5793e5776 100644 --- a/tests/rpc_test.go +++ b/tests/rpc_test.go @@ -773,7 +773,7 @@ func TestEth_EstimateGas_ContractDeployment(t *testing.T) { err := json.Unmarshal(rpcRes.Result, &gas) require.NoError(t, err) - require.Equal(t, hexutil.Uint64(0x1d7ac), gas) + require.Equal(t, hexutil.Uint64(0x1cab2), gas) } func TestEth_ExportAccount(t *testing.T) { From 64957ac14c2e7cb46291e91d90ab492238284e5a Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 18:49:18 +0200 Subject: [PATCH 21/27] stringer test --- x/evm/types/chain_config_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/x/evm/types/chain_config_test.go b/x/evm/types/chain_config_test.go index 90dac3cdb..5e01fa44e 100644 --- a/x/evm/types/chain_config_test.go +++ b/x/evm/types/chain_config_test.go @@ -221,3 +221,22 @@ func TestChainConfigValidate(t *testing.T) { } } } + +func TestChainConfig_String(t *testing.T) { + configStr := `homestead_block: "0" +dao_fork_block: "0" +dao_fork_support: true +eip150_block: "0" +eip150_hash: 0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0 +eip155_block: "0" +eip158_block: "0" +byzantium_block: "0" +constantinople_block: "0" +petersburg_block: "0" +istanbul_block: "-1" +muir_glacier_block: "-1" +yoloV1_block: "-1" +ewasm_block: "-1" +` + require.Equal(t, configStr, DefaultChainConfig().String()) +} From 7c09c2332b11febe8884a8c7780f7a3962277b11 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 1 Sep 2020 22:58:55 +0200 Subject: [PATCH 22/27] changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 986269800..41972304f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements * (app) [\#471](https://github.com/ChainSafe/ethermint/pull/471) Add `x/upgrade` module for managing software updates. +* (`x/evm`) [\#458](https://github.com/ChainSafe/ethermint/pull/458) Define parameter for token denomination used for the EVM module. +* (`x/evm`) [\#443](https://github.com/ChainSafe/ethermint/issues/443) Support custom Ethereum `ChainConfig` params. +* (types) [\#434](https://github.com/ChainSafe/ethermint/issues/434) Update default denomination to Atto Photon (`aphoton`). ### Bug Fixes From 8fa07a842a881a4da21b0b9b08cfe29b18d7bca4 Mon Sep 17 00:00:00 2001 From: noot <36753753+noot@users.noreply.github.com> Date: Tue, 1 Sep 2020 17:36:33 -0400 Subject: [PATCH 23/27] fix csdb index error (#493) * attempt to fix * cleanup * add idx check * update csdb.Copy --- x/evm/types/statedb.go | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/x/evm/types/statedb.go b/x/evm/types/statedb.go index 1d47f39db..44df93cb8 100644 --- a/x/evm/types/statedb.go +++ b/x/evm/types/statedb.go @@ -471,7 +471,7 @@ func (csdb *CommitStateDB) Finalise(deleteEmptyObjects bool) error { } } - csdb.stateObjectsDirty[dirty.address] = struct{}{} + delete(csdb.stateObjectsDirty, dirty.address) } // invalidate journal because reverting across transactions is not allowed @@ -702,9 +702,9 @@ func (csdb *CommitStateDB) Copy() *CommitStateDB { storeKey: csdb.storeKey, paramSpace: csdb.paramSpace, accountKeeper: csdb.accountKeeper, - stateObjects: make([]stateEntry, len(csdb.journal.dirties)), - addressToObjectIndex: make(map[ethcmn.Address]int, len(csdb.journal.dirties)), - stateObjectsDirty: make(map[ethcmn.Address]struct{}, len(csdb.journal.dirties)), + stateObjects: []stateEntry{}, + addressToObjectIndex: make(map[ethcmn.Address]int), + stateObjectsDirty: make(map[ethcmn.Address]struct{}), refund: csdb.refund, logSize: csdb.logSize, preimages: make(map[ethcmn.Hash][]byte), @@ -712,18 +712,19 @@ func (csdb *CommitStateDB) Copy() *CommitStateDB { } // copy the dirty states, logs, and preimages - for i, dirty := range csdb.journal.dirties { + for _, dirty := range csdb.journal.dirties { // There is a case where an object is in the journal but not in the // stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we // need to check for nil. // // Ref: https://github.com/ethereum/go-ethereum/pull/16485#issuecomment-380438527 if idx, exist := csdb.addressToObjectIndex[dirty.address]; exist { - state.stateObjects[i] = stateEntry{ + state.stateObjects = append(state.stateObjects, stateEntry{ address: dirty.address, stateObject: csdb.stateObjects[idx].stateObject.deepCopy(state), - } - state.stateObjectsDirty[dirty.address] = struct{}{} + }) + delete(state.stateObjectsDirty, dirty.address) + state.addressToObjectIndex[dirty.address] = len(state.stateObjects) - 1 } } @@ -731,9 +732,11 @@ func (csdb *CommitStateDB) Copy() *CommitStateDB { // copied, the loop above will be a no-op, since the copy's journal is empty. // Thus, here we iterate over stateObjects, to enable copies of copies. for addr := range csdb.stateObjectsDirty { - if idx, exist := state.addressToObjectIndex[addr]; !exist { - state.setStateObject(csdb.stateObjects[idx].stateObject.deepCopy(state)) - state.stateObjectsDirty[addr] = struct{}{} + if _, exist := state.addressToObjectIndex[addr]; !exist { + if idx, ok := csdb.addressToObjectIndex[addr]; ok { + state.setStateObject(csdb.stateObjects[idx].stateObject.deepCopy(state)) + delete(state.stateObjectsDirty, addr) + } } } @@ -821,8 +824,7 @@ func (csdb *CommitStateDB) setError(err error) { // getStateObject attempts to retrieve a state object given by the address. // Returns nil and sets an error if not found. func (csdb *CommitStateDB) getStateObject(addr ethcmn.Address) (stateObject *stateObject) { - idx, found := csdb.addressToObjectIndex[addr] - if found { + if idx, found := csdb.addressToObjectIndex[addr]; found && idx < len(csdb.stateObjects) { // prefer 'live' (cached) objects if so := csdb.stateObjects[idx].stateObject; so != nil { if so.deleted { @@ -848,8 +850,7 @@ func (csdb *CommitStateDB) getStateObject(addr ethcmn.Address) (stateObject *sta } func (csdb *CommitStateDB) setStateObject(so *stateObject) { - idx, found := csdb.addressToObjectIndex[so.Address()] - if found { + if idx, found := csdb.addressToObjectIndex[so.Address()]; found && idx < len(csdb.stateObjects) { // update the existing object csdb.stateObjects[idx].stateObject = so return From 7958be1b091dc3c1ab9a079cf826b2fbf0b797c7 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 2 Sep 2020 12:09:47 +0200 Subject: [PATCH 24/27] update default hash --- x/evm/types/chain_config.go | 4 ++-- x/evm/types/chain_config_test.go | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index d7941be50..a923bc97a 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -79,7 +79,7 @@ func DefaultChainConfig() ChainConfig { DAOForkBlock: sdk.ZeroInt(), DAOForkSupport: true, EIP150Block: sdk.ZeroInt(), - EIP150Hash: "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + EIP150Hash: common.Hash{}.String(), EIP155Block: sdk.ZeroInt(), EIP158Block: sdk.ZeroInt(), ByzantiumBlock: sdk.ZeroInt(), @@ -147,7 +147,7 @@ func (cc ChainConfig) Validate() error { } func validateHash(hex string) error { - if strings.TrimSpace(hex) == "" { + if hex != "" && strings.TrimSpace(hex) == "" { return sdkerrors.Wrapf(ErrInvalidChainConfig, "hash cannot be blank") } diff --git a/x/evm/types/chain_config_test.go b/x/evm/types/chain_config_test.go index 5e01fa44e..00b6d9489 100644 --- a/x/evm/types/chain_config_test.go +++ b/x/evm/types/chain_config_test.go @@ -3,11 +3,14 @@ package types import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/common" ) -const defaultEIP150Hash = "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0" +var defaultEIP150Hash = common.Hash{}.String() func TestChainConfigValidate(t *testing.T) { testCases := []struct { @@ -70,7 +73,7 @@ func TestChainConfigValidate(t *testing.T) { HomesteadBlock: sdk.OneInt(), DAOForkBlock: sdk.OneInt(), EIP150Block: sdk.OneInt(), - EIP150Hash: "", + EIP150Hash: " ", }, true, }, @@ -227,7 +230,7 @@ func TestChainConfig_String(t *testing.T) { dao_fork_block: "0" dao_fork_support: true eip150_block: "0" -eip150_hash: 0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0 +eip150_hash: "0x0000000000000000000000000000000000000000000000000000000000000000" eip155_block: "0" eip158_block: "0" byzantium_block: "0" From 6fd7af7163c2baace133753fdeb8bb0c5036d0e5 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 2 Sep 2020 12:26:54 +0200 Subject: [PATCH 25/27] update querier --- x/evm/keeper/querier.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/evm/keeper/querier.go b/x/evm/keeper/querier.go index 5d18e1605..9b062849d 100644 --- a/x/evm/keeper/querier.go +++ b/x/evm/keeper/querier.go @@ -21,7 +21,7 @@ import ( // NewQuerier is the module level router for state queries func NewQuerier(keeper Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { + return func(ctx sdk.Context, path []string, _ abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryProtocolVersion: return queryProtocolVersion(keeper) @@ -203,7 +203,7 @@ func queryExportAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte, addr := ethcmn.HexToAddress(path[1]) var storage types.Storage - err := keeper.CommitStateDB.ForEachStorage(addr, func(key, value ethcmn.Hash) bool { + err := keeper.ForEachStorage(ctx, addr, func(key, value ethcmn.Hash) bool { storage = append(storage, types.NewState(key, value)) return false }) From 0ec092dd23a5b2689b1804f35bd925d90c509bca Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 2 Sep 2020 12:44:21 +0200 Subject: [PATCH 26/27] update rpc tests --- tests/rpc_test.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/rpc_test.go b/tests/rpc_test.go index 5793e5776..6e7b0518d 100644 --- a/tests/rpc_test.go +++ b/tests/rpc_test.go @@ -751,10 +751,12 @@ func TestEth_EstimateGas(t *testing.T) { param[0]["to"] = "0x1122334455667788990011223344556677889900" param[0]["value"] = "0x1" rpcRes := call(t, "eth_estimateGas", param) + require.NotNil(t, rpcRes) + require.NotEmpty(t, rpcRes.Result) var gas hexutil.Bytes err := json.Unmarshal(rpcRes.Result, &gas) - require.NoError(t, err) + require.NoError(t, err, string(rpcRes.Result)) require.Equal(t, "0xffdf", gas.String()) } @@ -768,12 +770,14 @@ func TestEth_EstimateGas_ContractDeployment(t *testing.T) { param[0]["data"] = bytecode rpcRes := call(t, "eth_estimateGas", param) + require.NotNil(t, rpcRes) + require.NotEmpty(t, rpcRes.Result) var gas hexutil.Uint64 err := json.Unmarshal(rpcRes.Result, &gas) - require.NoError(t, err) + require.NoError(t, err, string(rpcRes.Result)) - require.Equal(t, hexutil.Uint64(0x1cab2), gas) + require.Equal(t, "0x1cab2", gas.String()) } func TestEth_ExportAccount(t *testing.T) { @@ -831,10 +835,10 @@ func TestEth_ExportAccount_WithStorage(t *testing.T) { require.NoError(t, err) // deployed bytecode - bytecode := ethcmn.FromHex("0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063eb8ac92114602d575b600080fd5b606060048036036040811015604157600080fd5b8101908080359060200190929190803590602001909291905050506062565b005b8160008190555080827ff3ca124a697ba07e8c5e80bebcfcc48991fc16a63170e8a9206e30508960d00360405160405180910390a3505056fea265627a7a723158201d94d2187aaf3a6790527b615fcc40970febf0385fa6d72a2344848ebd0df3e964736f6c63430005110032") + bytecode := "0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063eb8ac92114602d575b600080fd5b606060048036036040811015604157600080fd5b8101908080359060200190929190803590602001909291905050506062565b005b8160008190555080827ff3ca124a697ba07e8c5e80bebcfcc48991fc16a63170e8a9206e30508960d00360405160405180910390a3505056fea265627a7a723158201d94d2187aaf3a6790527b615fcc40970febf0385fa6d72a2344848ebd0df3e964736f6c63430005110032" require.Equal(t, addr, strings.ToLower(account.Address.Hex())) require.Equal(t, big.NewInt(0), account.Balance) - require.Equal(t, hexutil.Bytes(bytecode), account.Code) + require.Equal(t, bytecode, account.Code.String()) require.NotEqual(t, types.Storage(nil), account.Storage) } From 1b8a25b9f1838412e0d6c580615f1e6c3be74cf0 Mon Sep 17 00:00:00 2001 From: noot Date: Wed, 2 Sep 2020 15:30:34 -0400 Subject: [PATCH 27/27] fix estimate gas test --- tests/rpc_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/rpc_test.go b/tests/rpc_test.go index 6e7b0518d..bf775b92d 100644 --- a/tests/rpc_test.go +++ b/tests/rpc_test.go @@ -754,11 +754,11 @@ func TestEth_EstimateGas(t *testing.T) { require.NotNil(t, rpcRes) require.NotEmpty(t, rpcRes.Result) - var gas hexutil.Bytes + var gas string err := json.Unmarshal(rpcRes.Result, &gas) require.NoError(t, err, string(rpcRes.Result)) - require.Equal(t, "0xffdf", gas.String()) + require.Equal(t, "0x1051d", gas) } func TestEth_EstimateGas_ContractDeployment(t *testing.T) {