diff --git a/CHANGELOG.md b/CHANGELOG.md index e53bbb23..4c402745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking * (evm) [tharsis#72](https://github.com/tharsis/ethermint/issues/72) Update `AccessList` to use `TransientStore` instead of map. +* (evm) [tharsis#68](https://github.com/tharsis/ethermint/issues/68) Replace block hash storage map to use staking `HistoricalInfo`. ### API Breaking diff --git a/app/app.go b/app/app.go index 213554a6..5b66492f 100644 --- a/app/app.go +++ b/app/app.go @@ -311,7 +311,8 @@ func NewEthermintApp( // Create Ethermint keepers app.EvmKeeper = evmkeeper.NewKeeper( - appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName), app.AccountKeeper, app.BankKeeper, + appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName), + app.AccountKeeper, app.BankKeeper, app.StakingKeeper, ) // Create IBC Keeper diff --git a/tests/importer/importer_test.go b/tests/importer/importer_test.go index 7d4fbb57..8065ec63 100644 --- a/tests/importer/importer_test.go +++ b/tests/importer/importer_test.go @@ -27,6 +27,8 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" paramkeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/ethermint/encoding/codec" "github.com/cosmos/ethermint/types" @@ -183,13 +185,14 @@ func TestImportBlocks(t *testing.T) { authStoreKey := sdk.NewKVStoreKey(authtypes.StoreKey) bankStoreKey := sdk.NewKVStoreKey(banktypes.StoreKey) + stakingStoreKey := sdk.NewKVStoreKey(stakingtypes.StoreKey) evmStoreKey := sdk.NewKVStoreKey(evmtypes.StoreKey) paramsStoreKey := sdk.NewKVStoreKey(paramtypes.StoreKey) evmTransientStoreKey := sdk.NewTransientStoreKey(evmtypes.TransientKey) paramsTransientStoreKey := sdk.NewTransientStoreKey(paramtypes.TStoreKey) // mount stores - keys := []*sdk.KVStoreKey{authStoreKey, bankStoreKey, evmStoreKey, paramsStoreKey} + keys := []*sdk.KVStoreKey{authStoreKey, bankStoreKey, stakingStoreKey, evmStoreKey, paramsStoreKey} tkeys := []*sdk.TransientStoreKey{paramsTransientStoreKey, evmTransientStoreKey} for _, key := range keys { cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, nil) @@ -204,12 +207,14 @@ func TestImportBlocks(t *testing.T) { // Set specific subspaces authSubspace := paramsKeeper.Subspace(authtypes.ModuleName) bankSubspace := paramsKeeper.Subspace(banktypes.ModuleName) + stakingSubspace := paramsKeeper.Subspace(stakingtypes.ModuleName) evmSubspace := paramsKeeper.Subspace(evmtypes.ModuleName).WithKeyTable(evmtypes.ParamKeyTable()) // create keepers ak := authkeeper.NewAccountKeeper(cdc, authStoreKey, authSubspace, types.ProtoAccount, nil) bk := bankkeeper.NewBaseKeeper(cdc, bankStoreKey, ak, bankSubspace, nil) - evmKeeper := evmkeeper.NewKeeper(cdc, evmStoreKey, evmTransientStoreKey, evmSubspace, ak, bk) + sk := stakingkeeper.NewKeeper(cdc, stakingStoreKey, ak, bk, stakingSubspace) + evmKeeper := evmkeeper.NewKeeper(cdc, evmStoreKey, evmTransientStoreKey, evmSubspace, ak, bk, sk) cms.SetPruning(sdkstore.PruneNothing) diff --git a/x/evm/keeper/abci.go b/x/evm/keeper/abci.go index e772944a..da0ad620 100644 --- a/x/evm/keeper/abci.go +++ b/x/evm/keeper/abci.go @@ -20,20 +20,7 @@ import ( func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) k.WithContext(ctx) - - if req.Header.Height < 1 { - return - } - - // Gas costs are handled within msg handler so costs should be ignored - ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) - k.headerHash = common.BytesToHash(req.Hash) - - // set height -> hash - - // TODO: prune - k.SetHeaderHash(ctx, req.Header.Height, k.headerHash) } // EndBlock updates the accounts and commits state objects to the KV Store, while diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index df7978f6..805a9da3 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -35,6 +35,7 @@ type Keeper struct { paramSpace paramtypes.Subspace accountKeeper types.AccountKeeper bankKeeper types.BankKeeper + stakingKeeper types.StakingKeeper ctx sdk.Context // chain ID number obtained from the context's chain id @@ -52,7 +53,7 @@ type Keeper struct { // NewKeeper generates new evm module keeper func NewKeeper( cdc codec.BinaryMarshaler, storeKey, transientKey sdk.StoreKey, paramSpace paramtypes.Subspace, - ak types.AccountKeeper, bankKeeper types.BankKeeper, + ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper, ) *Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { @@ -65,6 +66,7 @@ func NewKeeper( paramSpace: paramSpace, accountKeeper: ak, bankKeeper: bankKeeper, + stakingKeeper: sk, storeKey: storeKey, transientKey: transientKey, CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, transientKey, paramSpace, ak, bankKeeper), @@ -146,26 +148,6 @@ func (k Keeper) SetBlockBloomTransient(bloom *big.Int) { // Block // ---------------------------------------------------------------------------- -// GetHeaderHash gets the header hash from a given height -func (k Keeper) GetHeaderHash(ctx sdk.Context, height int64) common.Hash { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixHeightToHeaderHash) - key := sdk.Uint64ToBigEndian(uint64(height)) - - bz := store.Get(key) - if len(bz) == 0 { - return common.Hash{} - } - - return common.BytesToHash(bz) -} - -// SetBlockHash sets the mapping from heigh -> header hash -func (k Keeper) SetHeaderHash(ctx sdk.Context, height int64, hash common.Hash) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixHeightToHeaderHash) - key := sdk.Uint64ToBigEndian(uint64(height)) - store.Set(key, hash.Bytes()) -} - // SetTxReceiptToHash sets the mapping from tx hash to tx receipt func (k Keeper) SetTxReceiptToHash(ctx sdk.Context, hash common.Hash, receipt *types.TxReceipt) { ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) @@ -176,16 +158,6 @@ func (k Keeper) SetTxReceiptToHash(ctx sdk.Context, hash common.Hash, receipt *t store.Set(types.KeyHashTxReceipt(hash), data) } -// GetHeightHash returns the block header hash associated with a given block height and chain epoch number. -func (k Keeper) GetHeightHash(ctx sdk.Context, height uint64) common.Hash { - return k.CommitStateDB.WithContext(ctx).GetHeightHash(height) -} - -// SetHeightHash sets the block header hash associated with a given height. -func (k Keeper) SetHeightHash(ctx sdk.Context, height uint64, hash common.Hash) { - k.CommitStateDB.WithContext(ctx).SetHeightHash(height, hash) -} - // ---------------------------------------------------------------------------- // Tx // ---------------------------------------------------------------------------- diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index ed915017..85a6bc72 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -7,6 +7,8 @@ import ( "os" "time" + tmtypes "github.com/tendermint/tendermint/types" + "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -58,18 +60,30 @@ func (k Keeper) VMConfig() vm.Config { // 3. The requested height is from a height greater than the latest one func (k Keeper) GetHashFn() vm.GetHashFunc { return func(height uint64) common.Hash { + h := int64(height) switch { - case k.ctx.BlockHeight() == int64(height): + case k.ctx.BlockHeight() == h: // Case 1: The requested height matches the one from the context so we can retrieve the header // hash directly from the context. // TODO: deprecate field from the keeper on next SDK release return k.headerHash - case k.ctx.BlockHeight() > int64(height): + case k.ctx.BlockHeight() > h: // Case 2: if the chain is not the current height we need to retrieve the hash from the store for the // current chain epoch. This only applies if the current height is greater than the requested height. - return k.GetHeightHash(k.ctx, height) + histInfo, found := k.stakingKeeper.GetHistoricalInfo(k.ctx, h) + if !found { + k.Logger(k.ctx).Debug("historical info not found", "height", h) + return common.Hash{} + } + header, err := tmtypes.HeaderFromProto(&histInfo.Header) + if err != nil { + k.Logger(k.ctx).Error("failed to cast tendermint header from proto", "error", err) + return common.Hash{} + } + + return common.BytesToHash(header.Hash()) default: // Case 3: heights greater than the current one returns an empty hash. return common.Hash{} diff --git a/x/evm/types/interfaces.go b/x/evm/types/interfaces.go index 012212e4..347fed1c 100644 --- a/x/evm/types/interfaces.go +++ b/x/evm/types/interfaces.go @@ -3,6 +3,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) // AccountKeeper defines the expected account keeper interface @@ -24,3 +25,8 @@ type BankKeeper interface { SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error } + +// StakingKeeper returns the historical headers kept in store. +type StakingKeeper interface { + GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool) +}