Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
591 changes: 325 additions & 266 deletions api/cosmos/evm/vm/v1/evm.pulsar.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions proto/cosmos/evm/vm/v1/evm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ message Params {
// active_static_precompiles defines the slice of hex addresses of the
// precompiled contracts that are active
repeated string active_static_precompiles = 9;
uint64 history_serve_window = 10;
}

// AccessControl defines the permission policy of the EVM
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/x/vm/test_genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func (s *GenesisTestSuite) TestExportGenesis() {

genState := vm.ExportGenesis(s.network.GetContext(), s.network.App.GetEVMKeeper())
// Exported accounts 4 default preinstalls
s.Require().Len(genState.Accounts, 7)
s.Require().Len(genState.Accounts, 8)

addrs := make([]string, len(genState.Accounts))
for i, acct := range genState.Accounts {
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/x/vm/test_iterate_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func TestIterateContracts(t *testing.T, create network.CreateEvmApp, options ...
return false
})

require.Len(t, foundAddrs, 6, "expected 6 contracts to be found when iterating (4 preinstalled + 2 deployed)")
require.Len(t, foundAddrs, 7, "expected 7 contracts to be found when iterating (5 preinstalled + 2 deployed)")
require.Contains(t, foundAddrs, contractAddr, "expected contract 1 to be found when iterating")
require.Contains(t, foundAddrs, contractAddr2, "expected contract 2 to be found when iterating")

Expand Down
3 changes: 2 additions & 1 deletion tests/integration/x/vm/test_keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"math/big"

"github.com/ethereum/go-ethereum/common"
ethparams "github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"

"github.com/cosmos/evm/utils"
Expand Down Expand Up @@ -89,7 +90,7 @@ func (s *KeeperTestSuite) TestGetAccountStorage() {

storage := s.Network.App.GetEVMKeeper().GetAccountStorage(ctx, address)

if address == contractAddr {
if address == contractAddr || address == ethparams.HistoryStorageAddress {
s.Require().NotEqual(0, len(storage),
"expected account %d to have non-zero amount of storage slots, got %d",
i, len(storage),
Expand Down
53 changes: 12 additions & 41 deletions tests/integration/x/vm/test_state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (

"github.com/cometbft/cometbft/crypto/tmhash"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
cmttypes "github.com/cometbft/cometbft/types"

"github.com/cosmos/evm/testutil/config"
"github.com/cosmos/evm/testutil/integration/evm/factory"
Expand All @@ -33,7 +32,6 @@ import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

func (s *KeeperTestSuite) TestContextSetConsensusParams() {
Expand Down Expand Up @@ -81,9 +79,11 @@ func (s *KeeperTestSuite) TestContextSetConsensusParams() {

func (s *KeeperTestSuite) TestGetHashFn() {
s.SetupTest()
header := s.Network.GetContext().BlockHeader()
h, _ := cmttypes.HeaderFromProto(&header)
hash := h.Hash()
s.Require().NoError(s.Network.NextBlock())
ctx := s.Network.GetContext()
height := uint64(ctx.BlockHeight()) //nolint:gosec // G115
headerHash := common.BytesToHash(ctx.HeaderHash())
fmt.Println("get headerHash", height, headerHash)

testCases := []struct {
msg string
Expand All @@ -93,7 +93,7 @@ func (s *KeeperTestSuite) TestGetHashFn() {
}{
{
"case 1.1: context hash cached",
uint64(s.Network.GetContext().BlockHeight()), //nolint:gosec // G115
height,
func() sdk.Context {
return s.Network.GetContext().WithHeaderHash(
tmhash.Sum([]byte("header")),
Expand All @@ -102,51 +102,22 @@ func (s *KeeperTestSuite) TestGetHashFn() {
common.BytesToHash(tmhash.Sum([]byte("header"))),
},
{
"case 1.2: failed to cast CometBFT header",
uint64(s.Network.GetContext().BlockHeight()), //nolint:gosec // G115
"case 1.2: works for invalid CometBFT header",
height,
func() sdk.Context {
header := tmproto.Header{}
header.Height = s.Network.GetContext().BlockHeight()
return s.Network.GetContext().WithBlockHeader(header)
},
common.Hash{},
},
{
"case 1.3: hash calculated from CometBFT header",
uint64(s.Network.GetContext().BlockHeight()), //nolint:gosec // G115
func() sdk.Context {
return s.Network.GetContext().WithBlockHeader(header)
},
common.BytesToHash(hash),
headerHash,
},
{
"case 2.1: height lower than current one, hist info not found",
1,
"case 2.1: height lower than current one works",
height,
func() sdk.Context {
return s.Network.GetContext().WithBlockHeight(10)
},
common.Hash{},
},
{
"case 2.2: height lower than current one, invalid hist info header",
1,
func() sdk.Context {
s.Require().NoError(s.Network.App.GetStakingKeeper().SetHistoricalInfo(s.Network.GetContext(), 1, &stakingtypes.HistoricalInfo{}))
return s.Network.GetContext().WithBlockHeight(10)
},
common.Hash{},
},
{
"case 2.3: height lower than current one, calculated from hist info header",
1,
func() sdk.Context {
histInfo := &stakingtypes.HistoricalInfo{
Header: header,
}
s.Require().NoError(s.Network.App.GetStakingKeeper().SetHistoricalInfo(s.Network.GetContext(), 1, histInfo))
return s.Network.GetContext().WithBlockHeight(10)
},
common.BytesToHash(hash),
headerHash,
},
{
"case 3: height greater than current one",
Expand Down
1 change: 1 addition & 0 deletions testutil/integration/evm/network/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func (n *IntegrationNetwork) finalizeBlockAndCommit(duration time.Duration, txBy
// This might have to be changed with time if we want to test gas limits
newCtx = newCtx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter())
newCtx = newCtx.WithVoteInfos(req.DecidedLastCommit.GetVotes())
newCtx = newCtx.WithHeaderHash(header.AppHash)
n.ctx = newCtx

// commit changes
Expand Down
2 changes: 2 additions & 0 deletions x/vm/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
),
})
}

k.SetHeaderHash(ctx)

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods Warning

path flow from Begin/EndBlock to a panic call
path flow from Begin/EndBlock to a panic call
return nil
}

Expand Down
34 changes: 34 additions & 0 deletions x/vm/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper

import (
"encoding/binary"
"math/big"

"github.com/ethereum/go-ethereum/common"
Expand All @@ -8,7 +9,8 @@
"github.com/ethereum/go-ethereum/core/tracing"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"

Check failure on line 12 in x/vm/keeper/keeper.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

ST1019: package "github.com/ethereum/go-ethereum/params" is being imported more than once (staticcheck)
ethparams "github.com/ethereum/go-ethereum/params"

Check failure on line 13 in x/vm/keeper/keeper.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

ST1019(related information): other import of "github.com/ethereum/go-ethereum/params" (staticcheck)
"github.com/holiman/uint256"

evmmempool "github.com/cosmos/evm/mempool"
Expand Down Expand Up @@ -401,3 +403,35 @@
func (k Keeper) GetEvmMempool() *evmmempool.ExperimentalEVMMempool {
return k.evmMempool
}

// SetHeaderHash sets current block hash into EIP-2935 compatible storage contract.
func (k Keeper) SetHeaderHash(ctx sdk.Context) {
window := uint64(types.DefaultHistoryServeWindow)
params := k.GetParams(ctx)
if params.HistoryServeWindow > 0 {
window = params.HistoryServeWindow
}

acct := k.GetAccount(ctx, ethparams.HistoryStorageAddress)
if acct != nil && acct.IsContract() {
// set current block hash in the contract storage, compatible with EIP-2935
ringIndex := uint64(ctx.BlockHeight()) % window //nolint:gosec // G115 // won't exceed uint64
var key common.Hash
binary.BigEndian.PutUint64(key[24:], ringIndex)
k.SetState(ctx, ethparams.HistoryStorageAddress, key, ctx.HeaderHash())
}
}

// GetHeaderHash sets block hash into EIP-2935 compatible storage contract.
func (k Keeper) GetHeaderHash(ctx sdk.Context, height uint64) common.Hash {
window := uint64(types.DefaultHistoryServeWindow)
params := k.GetParams(ctx)
if params.HistoryServeWindow > 0 {
window = params.HistoryServeWindow
}

ringIndex := height % window
var key common.Hash
binary.BigEndian.PutUint64(key[24:], ringIndex)
return k.GetState(ctx, ethparams.HistoryStorageAddress, key)
}
20 changes: 4 additions & 16 deletions x/vm/keeper/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,23 +112,11 @@ func (k Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc {
return common.BytesToHash(headerHash)

case 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.
histInfo, err := k.stakingKeeper.GetHistoricalInfo(ctx, h)
if err != nil {
k.Logger(ctx).Debug("error while getting historical info", "height", h, "error", err.Error())
return common.Hash{}
}

header, err := cmttypes.HeaderFromProto(&histInfo.Header)
if err != nil {
k.Logger(ctx).Error("failed to cast CometBFT header from proto", "error", err)
return common.Hash{}
}

return common.BytesToHash(header.Hash())
// Case 2: The requested height is historical, query EIP-2935 contract storage for that
// see: https://github.com/cosmos/evm/issues/406
return k.GetHeaderHash(ctx, height)
default:
// Case 3: heights greater than the current one returns an empty hash.
// Case 3: The requested height is greater than the latest one, return empty hash
return common.Hash{}
}
}
Expand Down
Loading
Loading