evm: replace block hash storage (#80)

* evm: replace block hash storage

* c++
This commit is contained in:
Federico Kunze 2021-06-07 07:00:14 -04:00 committed by GitHub
parent e639cb4a82
commit 1ff3c46663
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 36 additions and 50 deletions

View File

@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### State Machine Breaking ### State Machine Breaking
* (evm) [tharsis#72](https://github.com/tharsis/ethermint/issues/72) Update `AccessList` to use `TransientStore` instead of map. * (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 ### API Breaking

View File

@ -311,7 +311,8 @@ func NewEthermintApp(
// Create Ethermint keepers // Create Ethermint keepers
app.EvmKeeper = evmkeeper.NewKeeper( 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 // Create IBC Keeper

View File

@ -27,6 +27,8 @@ import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
paramkeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramkeeper "github.com/cosmos/cosmos-sdk/x/params/keeper"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" 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/encoding/codec"
"github.com/cosmos/ethermint/types" "github.com/cosmos/ethermint/types"
@ -183,13 +185,14 @@ func TestImportBlocks(t *testing.T) {
authStoreKey := sdk.NewKVStoreKey(authtypes.StoreKey) authStoreKey := sdk.NewKVStoreKey(authtypes.StoreKey)
bankStoreKey := sdk.NewKVStoreKey(banktypes.StoreKey) bankStoreKey := sdk.NewKVStoreKey(banktypes.StoreKey)
stakingStoreKey := sdk.NewKVStoreKey(stakingtypes.StoreKey)
evmStoreKey := sdk.NewKVStoreKey(evmtypes.StoreKey) evmStoreKey := sdk.NewKVStoreKey(evmtypes.StoreKey)
paramsStoreKey := sdk.NewKVStoreKey(paramtypes.StoreKey) paramsStoreKey := sdk.NewKVStoreKey(paramtypes.StoreKey)
evmTransientStoreKey := sdk.NewTransientStoreKey(evmtypes.TransientKey) evmTransientStoreKey := sdk.NewTransientStoreKey(evmtypes.TransientKey)
paramsTransientStoreKey := sdk.NewTransientStoreKey(paramtypes.TStoreKey) paramsTransientStoreKey := sdk.NewTransientStoreKey(paramtypes.TStoreKey)
// mount stores // mount stores
keys := []*sdk.KVStoreKey{authStoreKey, bankStoreKey, evmStoreKey, paramsStoreKey} keys := []*sdk.KVStoreKey{authStoreKey, bankStoreKey, stakingStoreKey, evmStoreKey, paramsStoreKey}
tkeys := []*sdk.TransientStoreKey{paramsTransientStoreKey, evmTransientStoreKey} tkeys := []*sdk.TransientStoreKey{paramsTransientStoreKey, evmTransientStoreKey}
for _, key := range keys { for _, key := range keys {
cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, nil) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, nil)
@ -204,12 +207,14 @@ func TestImportBlocks(t *testing.T) {
// Set specific subspaces // Set specific subspaces
authSubspace := paramsKeeper.Subspace(authtypes.ModuleName) authSubspace := paramsKeeper.Subspace(authtypes.ModuleName)
bankSubspace := paramsKeeper.Subspace(banktypes.ModuleName) bankSubspace := paramsKeeper.Subspace(banktypes.ModuleName)
stakingSubspace := paramsKeeper.Subspace(stakingtypes.ModuleName)
evmSubspace := paramsKeeper.Subspace(evmtypes.ModuleName).WithKeyTable(evmtypes.ParamKeyTable()) evmSubspace := paramsKeeper.Subspace(evmtypes.ModuleName).WithKeyTable(evmtypes.ParamKeyTable())
// create keepers // create keepers
ak := authkeeper.NewAccountKeeper(cdc, authStoreKey, authSubspace, types.ProtoAccount, nil) ak := authkeeper.NewAccountKeeper(cdc, authStoreKey, authSubspace, types.ProtoAccount, nil)
bk := bankkeeper.NewBaseKeeper(cdc, bankStoreKey, ak, bankSubspace, 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) cms.SetPruning(sdkstore.PruneNothing)

View File

@ -20,20 +20,7 @@ import (
func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker)
k.WithContext(ctx) 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) 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 // EndBlock updates the accounts and commits state objects to the KV Store, while

View File

@ -35,6 +35,7 @@ type Keeper struct {
paramSpace paramtypes.Subspace paramSpace paramtypes.Subspace
accountKeeper types.AccountKeeper accountKeeper types.AccountKeeper
bankKeeper types.BankKeeper bankKeeper types.BankKeeper
stakingKeeper types.StakingKeeper
ctx sdk.Context ctx sdk.Context
// chain ID number obtained from the context's chain id // chain ID number obtained from the context's chain id
@ -52,7 +53,7 @@ type Keeper struct {
// NewKeeper generates new evm module keeper // NewKeeper generates new evm module keeper
func NewKeeper( func NewKeeper(
cdc codec.BinaryMarshaler, storeKey, transientKey sdk.StoreKey, paramSpace paramtypes.Subspace, 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 { ) *Keeper {
// set KeyTable if it has not already been set // set KeyTable if it has not already been set
if !paramSpace.HasKeyTable() { if !paramSpace.HasKeyTable() {
@ -65,6 +66,7 @@ func NewKeeper(
paramSpace: paramSpace, paramSpace: paramSpace,
accountKeeper: ak, accountKeeper: ak,
bankKeeper: bankKeeper, bankKeeper: bankKeeper,
stakingKeeper: sk,
storeKey: storeKey, storeKey: storeKey,
transientKey: transientKey, transientKey: transientKey,
CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, transientKey, paramSpace, ak, bankKeeper), CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, transientKey, paramSpace, ak, bankKeeper),
@ -146,26 +148,6 @@ func (k Keeper) SetBlockBloomTransient(bloom *big.Int) {
// Block // 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 // SetTxReceiptToHash sets the mapping from tx hash to tx receipt
func (k Keeper) SetTxReceiptToHash(ctx sdk.Context, hash common.Hash, receipt *types.TxReceipt) { func (k Keeper) SetTxReceiptToHash(ctx sdk.Context, hash common.Hash, receipt *types.TxReceipt) {
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) 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) 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 // Tx
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -7,6 +7,8 @@ import (
"os" "os"
"time" "time"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/telemetry" "github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" 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 // 3. The requested height is from a height greater than the latest one
func (k Keeper) GetHashFn() vm.GetHashFunc { func (k Keeper) GetHashFn() vm.GetHashFunc {
return func(height uint64) common.Hash { return func(height uint64) common.Hash {
h := int64(height)
switch { 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 // Case 1: The requested height matches the one from the context so we can retrieve the header
// hash directly from the context. // hash directly from the context.
// TODO: deprecate field from the keeper on next SDK release // TODO: deprecate field from the keeper on next SDK release
return k.headerHash 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 // 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. // 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: default:
// Case 3: heights greater than the current one returns an empty hash. // Case 3: heights greater than the current one returns an empty hash.
return common.Hash{} return common.Hash{}

View File

@ -3,6 +3,7 @@ package types
import ( import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/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 // 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 SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error
SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) 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)
}