Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 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
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
57 changes: 15 additions & 42 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 @@ -23,6 +22,7 @@ import (
utiltx "github.com/cosmos/evm/testutil/tx"
feemarkettypes "github.com/cosmos/evm/x/feemarket/types"
"github.com/cosmos/evm/x/vm/keeper"
"github.com/cosmos/evm/x/vm/statedb"
"github.com/cosmos/evm/x/vm/types"

sdkmath "cosmossdk.io/math"
Expand All @@ -33,7 +33,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 +80,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 +94,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 +103,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 All @@ -161,7 +133,8 @@ func (s *KeeperTestSuite) TestGetHashFn() {
ctx := tc.malleate()

// Function being tested
hash := s.Network.App.GetEVMKeeper().GetHashFn(ctx)(tc.height)
db := statedb.New(ctx, s.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig(common.Hash{}))
hash := s.Network.App.GetEVMKeeper().GetHashFn(ctx, db)(tc.height)
s.Require().Equal(tc.expHash, hash)

err := s.Network.NextBlock()
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
10 changes: 10 additions & 0 deletions x/vm/keeper/abci.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package keeper

import (
"encoding/binary"

"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethparams "github.com/ethereum/go-ethereum/params"

evmtypes "github.com/cosmos/evm/x/vm/types"

Expand Down Expand Up @@ -31,6 +35,12 @@ func (k *Keeper) BeginBlock(ctx sdk.Context) error {
),
})
}

// set current block hash in the contract storage, compatible with EIP-2935
ringIndex := uint64(ctx.BlockHeight() % ethparams.HistoryServeWindow) //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())
return nil
}

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

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

Expand Down Expand Up @@ -46,7 +47,7 @@ func (k *Keeper) NewEVM(
blockCtx := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetHash: k.GetHashFn(ctx),
GetHash: k.GetHashFn(ctx, stateDB),
Coinbase: cfg.CoinBase,
GasLimit: cosmosevmtypes.BlockGasLimit(ctx),
BlockNumber: big.NewInt(ctx.BlockHeight()),
Expand Down Expand Up @@ -82,7 +83,7 @@ func (k *Keeper) NewEVM(
// 1. The requested height matches the current height from context (and thus same epoch number)
// 2. The requested height is from an previous height from the same chain epoch
// 3. The requested height is from a height greater than the latest one
func (k Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc {
func (k Keeper) GetHashFn(ctx sdk.Context, db vm.StateDB) vm.GetHashFunc {
return func(height uint64) common.Hash {
h, err := cosmosevmtypes.SafeInt64(height)
if err != nil {
Expand Down Expand Up @@ -112,23 +113,14 @@ 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 for that
// see: https://github.com/cosmos/evm/issues/406
ringIndex := height % params.HistoryServeWindow
var key common.Hash
binary.BigEndian.PutUint64(key[24:], ringIndex)
return db.GetState(params.HistoryStorageAddress, key)
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
6 changes: 6 additions & 0 deletions x/vm/types/preinstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)

var DefaultPreinstalls = []Preinstall{
Expand All @@ -30,6 +31,11 @@ var DefaultPreinstalls = []Preinstall{
Address: "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7",
Code: "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3",
},
{
Name: "EIP-2935 - Serve historical block hashes from state",
Address: params.HistoryStorageAddress.String(),
Code: common.Bytes2Hex(params.HistoryStorageCode),
},
}

// Validate performs basic validation checks on the Preinstall
Expand Down
Loading