evm: implement vm.GetHashFn (#620)
* evm: implement vm.GetHashFn * check nil case * test * handle 3 cases * use switch statement * stateDB tests * abci changes * fix LGTM issue * final tests * changelog * remove epoch * update test * clean test * rm epoch
This commit is contained in:
parent
7efd10eb21
commit
c4a3c0a96e
@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* (evm) [\#621](https://github.com/cosmos/ethermint/issues/621) EVM `GenesisAccount` fields now share the same format as the auth module `Account`.
|
* (evm) [\#621](https://github.com/cosmos/ethermint/issues/621) EVM `GenesisAccount` fields now share the same format as the auth module `Account`.
|
||||||
|
* (evm) [\#618](https://github.com/cosmos/ethermint/issues/618) Add missing EVM `Context` `GetHash` field that retrieves a the header hash from a given block height.
|
||||||
* (app) [\#617](https://github.com/cosmos/ethermint/issues/617) Fix genesis export functionality.
|
* (app) [\#617](https://github.com/cosmos/ethermint/issues/617) Fix genesis export functionality.
|
||||||
|
|
||||||
## [v0.3.1] - 2020-11-24
|
## [v0.3.1] - 2020-11-24
|
||||||
|
@ -28,7 +28,6 @@ func NewDefaultGenesisState() simapp.GenesisState {
|
|||||||
func (app *EthermintApp) ExportAppStateAndValidators(
|
func (app *EthermintApp) ExportAppStateAndValidators(
|
||||||
forZeroHeight bool, jailWhiteList []string,
|
forZeroHeight bool, jailWhiteList []string,
|
||||||
) (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
) (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
||||||
|
|
||||||
// Creates context with current height and checks txs for ctx to be usable by start of next block
|
// Creates context with current height and checks txs for ctx to be usable by start of next block
|
||||||
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
|
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
|
"github.com/cosmos/ethermint/x/evm/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BeginBlock sets the block hash -> block height map for the previous block height
|
// BeginBlock sets the block hash -> block height map for the previous block height
|
||||||
@ -29,18 +31,25 @@ func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
|
|||||||
|
|
||||||
// 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
|
||||||
// deleting the empty ones. It also sets the bloom filers for the request block to
|
// deleting the empty ones. It also sets the bloom filers for the request block to
|
||||||
// the store. The EVM end block loginc doesn't update the validator set, thus it returns
|
// the store. The EVM end block logic doesn't update the validator set, thus it returns
|
||||||
// an empty slice.
|
// an empty slice.
|
||||||
func (k Keeper) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate {
|
func (k Keeper) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate {
|
||||||
// Gas costs are handled within msg handler so costs should be ignored
|
// Gas costs are handled within msg handler so costs should be ignored
|
||||||
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||||
|
|
||||||
|
// Set the hash for the current height.
|
||||||
|
// NOTE: we set the hash here instead of on BeginBlock in order to set the final block prior to
|
||||||
|
// an upgrade. If we set it on BeginBlock the last block from prior to the upgrade wouldn't be
|
||||||
|
// included on the store.
|
||||||
|
hash := types.HashFromContext(ctx)
|
||||||
|
k.SetHeightHash(ctx, uint64(ctx.BlockHeight()), hash)
|
||||||
|
|
||||||
// Update account balances before committing other parts of state
|
// Update account balances before committing other parts of state
|
||||||
k.UpdateAccounts(ctx)
|
k.UpdateAccounts(ctx)
|
||||||
|
|
||||||
// Commit state objects to KV store
|
// Commit state objects to KV store
|
||||||
_, err := k.Commit(ctx, true)
|
if _, err := k.Commit(ctx, true); err != nil {
|
||||||
if err != nil {
|
k.Logger(ctx).Error("failed to commit state objects", "error", err, "height", ctx.BlockHeight())
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +88,21 @@ func (k Keeper) SetBlockHash(ctx sdk.Context, hash []byte, height int64) {
|
|||||||
store.Set(hash, bz)
|
store.Set(hash, bz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Epoch Height -> hash mapping functions
|
||||||
|
// Required by EVM context's GetHashFunc
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Block bloom bits mapping functions
|
// Block bloom bits mapping functions
|
||||||
// Required by Web3 API.
|
// Required by Web3 API.
|
||||||
|
@ -42,7 +42,7 @@ func (suite *KeeperTestSuite) SetupTest() {
|
|||||||
checkTx := false
|
checkTx := false
|
||||||
|
|
||||||
suite.app = app.Setup(checkTx)
|
suite.app = app.Setup(checkTx)
|
||||||
suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()})
|
suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()})
|
||||||
suite.querier = keeper.NewQuerier(suite.app.EvmKeeper)
|
suite.querier = keeper.NewQuerier(suite.app.EvmKeeper)
|
||||||
suite.address = ethcmn.HexToAddress(addrHex)
|
suite.address = ethcmn.HexToAddress(addrHex)
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ func (suite *JournalTestSuite) setup() {
|
|||||||
evmSubspace := paramsKeeper.Subspace(types.DefaultParamspace).WithKeyTable(ParamKeyTable())
|
evmSubspace := paramsKeeper.Subspace(types.DefaultParamspace).WithKeyTable(ParamKeyTable())
|
||||||
|
|
||||||
ak := auth.NewAccountKeeper(cdc, authKey, authSubspace, ethermint.ProtoAccount)
|
ak := auth.NewAccountKeeper(cdc, authKey, authSubspace, ethermint.ProtoAccount)
|
||||||
suite.ctx = sdk.NewContext(cms, abci.Header{ChainID: "8"}, false, tmlog.NewNopLogger())
|
suite.ctx = sdk.NewContext(cms, abci.Header{ChainID: "ethermint-8"}, false, tmlog.NewNopLogger())
|
||||||
suite.stateDB = NewCommitStateDB(suite.ctx, storeKey, evmSubspace, ak).WithContext(suite.ctx)
|
suite.stateDB = NewCommitStateDB(suite.ctx, storeKey, evmSubspace, ak).WithContext(suite.ctx)
|
||||||
suite.stateDB.SetParams(DefaultParams())
|
suite.stateDB.SetParams(DefaultParams())
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,18 @@ var (
|
|||||||
KeyPrefixCode = []byte{0x04}
|
KeyPrefixCode = []byte{0x04}
|
||||||
KeyPrefixStorage = []byte{0x05}
|
KeyPrefixStorage = []byte{0x05}
|
||||||
KeyPrefixChainConfig = []byte{0x06}
|
KeyPrefixChainConfig = []byte{0x06}
|
||||||
|
KeyPrefixHeightHash = []byte{0x07}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HeightHashKey returns the key for the given chain epoch and height.
|
||||||
|
// The key will be composed in the following order:
|
||||||
|
// key = prefix + bytes(height)
|
||||||
|
// This ordering facilitates the iteration by height for the EVM GetHashFn
|
||||||
|
// queries.
|
||||||
|
func HeightHashKey(height uint64) []byte {
|
||||||
|
return sdk.Uint64ToBigEndian(height)
|
||||||
|
}
|
||||||
|
|
||||||
// BloomKey defines the store key for a block Bloom
|
// BloomKey defines the store key for a block Bloom
|
||||||
func BloomKey(height int64) []byte {
|
func BloomKey(height int64) []byte {
|
||||||
return sdk.Uint64ToBigEndian(uint64(height))
|
return sdk.Uint64ToBigEndian(uint64(height))
|
||||||
|
@ -47,11 +47,42 @@ type ExecutionResult struct {
|
|||||||
GasInfo GasInfo
|
GasInfo GasInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit uint64, gasPrice *big.Int, config ChainConfig) *vm.EVM {
|
// GetHashFn implements vm.GetHashFunc for Ethermint. It handles 3 cases:
|
||||||
|
// 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 GetHashFn(ctx sdk.Context, csdb *CommitStateDB) vm.GetHashFunc {
|
||||||
|
return func(height uint64) common.Hash {
|
||||||
|
switch {
|
||||||
|
case ctx.BlockHeight() == int64(height):
|
||||||
|
// Case 1: The requested height matches the one from the context so we can retrieve the header
|
||||||
|
// hash directly from the context.
|
||||||
|
return HashFromContext(ctx)
|
||||||
|
|
||||||
|
case ctx.BlockHeight() > int64(height):
|
||||||
|
// 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 csdb.WithContext(ctx).GetHeightHash(height)
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Case 3: heights greater than the current one returns an empty hash.
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st StateTransition) newEVM(
|
||||||
|
ctx sdk.Context,
|
||||||
|
csdb *CommitStateDB,
|
||||||
|
gasLimit uint64,
|
||||||
|
gasPrice *big.Int,
|
||||||
|
config ChainConfig,
|
||||||
|
) *vm.EVM {
|
||||||
// Create context for evm
|
// Create context for evm
|
||||||
context := vm.Context{
|
context := vm.Context{
|
||||||
CanTransfer: core.CanTransfer,
|
CanTransfer: core.CanTransfer,
|
||||||
Transfer: core.Transfer,
|
Transfer: core.Transfer,
|
||||||
|
GetHash: GetHashFn(ctx, csdb),
|
||||||
Origin: st.Sender,
|
Origin: st.Sender,
|
||||||
Coinbase: common.Address{}, // there's no benefitiary since we're not mining
|
Coinbase: common.Address{}, // there's no benefitiary since we're not mining
|
||||||
BlockNumber: big.NewInt(ctx.BlockHeight()),
|
BlockNumber: big.NewInt(ctx.BlockHeight()),
|
||||||
@ -134,7 +165,7 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
|
|||||||
recipientLog = fmt.Sprintf("contract address %s", contractAddress.String())
|
recipientLog = fmt.Sprintf("contract address %s", contractAddress.String())
|
||||||
default:
|
default:
|
||||||
if !params.EnableCall {
|
if !params.EnableCall {
|
||||||
return nil, ErrCreateDisabled
|
return nil, ErrCallDisabled
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment the nonce for the next transaction (just for evm state transition)
|
// Increment the nonce for the next transaction (just for evm state transition)
|
||||||
@ -223,3 +254,21 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
|
|||||||
|
|
||||||
return executionResult, nil
|
return executionResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HashFromContext returns the Ethereum Header hash from the context's Tendermint
|
||||||
|
// block header.
|
||||||
|
func HashFromContext(ctx sdk.Context) common.Hash {
|
||||||
|
// cast the ABCI header to tendermint Header type
|
||||||
|
tmHeader := AbciHeaderToTendermint(ctx.BlockHeader())
|
||||||
|
|
||||||
|
// get the Tendermint block hash from the current header
|
||||||
|
tmBlockHash := tmHeader.Hash()
|
||||||
|
|
||||||
|
// NOTE: if the validator set hash is missing the hash will be returned as nil,
|
||||||
|
// so we need to check for this case to prevent a panic when calling Bytes()
|
||||||
|
if tmBlockHash == nil {
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return common.BytesToHash(tmBlockHash.Bytes())
|
||||||
|
}
|
||||||
|
@ -3,16 +3,108 @@ package types_test
|
|||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
|
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
|
||||||
ethermint "github.com/cosmos/ethermint/types"
|
ethermint "github.com/cosmos/ethermint/types"
|
||||||
"github.com/cosmos/ethermint/x/evm/types"
|
"github.com/cosmos/ethermint/x/evm/types"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (suite *StateDBTestSuite) TestGetHashFn() {
|
||||||
|
testCase := []struct {
|
||||||
|
name string
|
||||||
|
height uint64
|
||||||
|
malleate func()
|
||||||
|
expEmptyHash bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"valid hash, case 1",
|
||||||
|
1,
|
||||||
|
func() {
|
||||||
|
suite.ctx = suite.ctx.WithBlockHeader(
|
||||||
|
abci.Header{
|
||||||
|
ChainID: "ethermint-1",
|
||||||
|
Height: 1,
|
||||||
|
ValidatorsHash: []byte("val_hash"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case 1, nil tendermint hash",
|
||||||
|
1,
|
||||||
|
func() {},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"valid hash, case 2",
|
||||||
|
1,
|
||||||
|
func() {
|
||||||
|
suite.ctx = suite.ctx.WithBlockHeader(
|
||||||
|
abci.Header{
|
||||||
|
ChainID: "ethermint-1",
|
||||||
|
Height: 100,
|
||||||
|
ValidatorsHash: []byte("val_hash"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
hash := types.HashFromContext(suite.ctx)
|
||||||
|
suite.stateDB.WithContext(suite.ctx).SetHeightHash(1, hash)
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height not found, case 2",
|
||||||
|
1,
|
||||||
|
func() {
|
||||||
|
suite.ctx = suite.ctx.WithBlockHeader(
|
||||||
|
abci.Header{
|
||||||
|
ChainID: "ethermint-1",
|
||||||
|
Height: 100,
|
||||||
|
ValidatorsHash: []byte("val_hash"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"empty hash, case 3",
|
||||||
|
1000,
|
||||||
|
func() {
|
||||||
|
suite.ctx = suite.ctx.WithBlockHeader(
|
||||||
|
abci.Header{
|
||||||
|
ChainID: "ethermint-1",
|
||||||
|
Height: 100,
|
||||||
|
ValidatorsHash: []byte("val_hash"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCase {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.SetupTest() // reset
|
||||||
|
|
||||||
|
tc.malleate()
|
||||||
|
|
||||||
|
hash := types.GetHashFn(suite.ctx, suite.stateDB)(tc.height)
|
||||||
|
if tc.expEmptyHash {
|
||||||
|
suite.Require().Equal(common.Hash{}.String(), hash.String())
|
||||||
|
} else {
|
||||||
|
suite.Require().NotEqual(common.Hash{}.String(), hash.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *StateDBTestSuite) TestTransitionDb() {
|
func (suite *StateDBTestSuite) TestTransitionDb() {
|
||||||
suite.stateDB.SetNonce(suite.address, 123)
|
suite.stateDB.SetNonce(suite.address, 123)
|
||||||
|
|
||||||
@ -104,9 +196,52 @@ func (suite *StateDBTestSuite) TestTransitionDb() {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"call disabled",
|
||||||
|
func() {
|
||||||
|
params := types.NewParams(ethermint.AttoPhoton, true, false)
|
||||||
|
suite.stateDB.SetParams(params)
|
||||||
|
},
|
||||||
|
types.StateTransition{
|
||||||
|
AccountNonce: 123,
|
||||||
|
Price: big.NewInt(10),
|
||||||
|
GasLimit: 11,
|
||||||
|
Recipient: &recipient,
|
||||||
|
Amount: big.NewInt(50),
|
||||||
|
Payload: []byte("data"),
|
||||||
|
ChainID: big.NewInt(1),
|
||||||
|
Csdb: suite.stateDB,
|
||||||
|
TxHash: ðcmn.Hash{},
|
||||||
|
Sender: suite.address,
|
||||||
|
Simulate: suite.ctx.IsCheckTx(),
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create disabled",
|
||||||
|
func() {
|
||||||
|
params := types.NewParams(ethermint.AttoPhoton, false, true)
|
||||||
|
suite.stateDB.SetParams(params)
|
||||||
|
},
|
||||||
|
types.StateTransition{
|
||||||
|
AccountNonce: 123,
|
||||||
|
Price: big.NewInt(10),
|
||||||
|
GasLimit: 11,
|
||||||
|
Recipient: nil,
|
||||||
|
Amount: big.NewInt(50),
|
||||||
|
Payload: []byte("data"),
|
||||||
|
ChainID: big.NewInt(1),
|
||||||
|
Csdb: suite.stateDB,
|
||||||
|
TxHash: ðcmn.Hash{},
|
||||||
|
Sender: suite.address,
|
||||||
|
Simulate: suite.ctx.IsCheckTx(),
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"nil gas price",
|
"nil gas price",
|
||||||
func() {
|
func() {
|
||||||
|
suite.stateDB.SetParams(types.DefaultParams())
|
||||||
invalidGas := sdk.DecCoins{
|
invalidGas := sdk.DecCoins{
|
||||||
{Denom: ethermint.AttoPhoton},
|
{Denom: ethermint.AttoPhoton},
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/params"
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
|
|
||||||
emint "github.com/cosmos/ethermint/types"
|
ethermint "github.com/cosmos/ethermint/types"
|
||||||
|
|
||||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
ethstate "github.com/ethereum/go-ethereum/core/state"
|
ethstate "github.com/ethereum/go-ethereum/core/state"
|
||||||
@ -107,7 +107,7 @@ func NewCommitStateDB(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithContext returns a Database with an updated sdk context
|
// WithContext returns a Database with an updated SDK context
|
||||||
func (csdb *CommitStateDB) WithContext(ctx sdk.Context) *CommitStateDB {
|
func (csdb *CommitStateDB) WithContext(ctx sdk.Context) *CommitStateDB {
|
||||||
csdb.ctx = ctx
|
csdb.ctx = ctx
|
||||||
return csdb
|
return csdb
|
||||||
@ -117,6 +117,13 @@ func (csdb *CommitStateDB) WithContext(ctx sdk.Context) *CommitStateDB {
|
|||||||
// Setters
|
// Setters
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// SetHeightHash sets the block header hash associated with a given height.
|
||||||
|
func (csdb *CommitStateDB) SetHeightHash(height uint64, hash ethcmn.Hash) {
|
||||||
|
store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixHeightHash)
|
||||||
|
key := HeightHashKey(height)
|
||||||
|
store.Set(key, hash.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
// SetParams sets the evm parameters to the param space.
|
// SetParams sets the evm parameters to the param space.
|
||||||
func (csdb *CommitStateDB) SetParams(params Params) {
|
func (csdb *CommitStateDB) SetParams(params Params) {
|
||||||
csdb.paramSpace.SetParamSet(csdb.ctx, ¶ms)
|
csdb.paramSpace.SetParamSet(csdb.ctx, ¶ms)
|
||||||
@ -286,6 +293,18 @@ func (csdb *CommitStateDB) SlotInAccessList(addr ethcmn.Address, slot ethcmn.Has
|
|||||||
// Getters
|
// Getters
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// GetHeightHash returns the block header hash associated with a given block height and chain epoch number.
|
||||||
|
func (csdb *CommitStateDB) GetHeightHash(height uint64) ethcmn.Hash {
|
||||||
|
store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixHeightHash)
|
||||||
|
key := HeightHashKey(height)
|
||||||
|
bz := store.Get(key)
|
||||||
|
if len(bz) == 0 {
|
||||||
|
return ethcmn.Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ethcmn.BytesToHash(bz)
|
||||||
|
}
|
||||||
|
|
||||||
// GetParams returns the total set of evm parameters.
|
// GetParams returns the total set of evm parameters.
|
||||||
func (csdb *CommitStateDB) GetParams() (params Params) {
|
func (csdb *CommitStateDB) GetParams() (params Params) {
|
||||||
csdb.paramSpace.GetParamSet(csdb.ctx, ¶ms)
|
csdb.paramSpace.GetParamSet(csdb.ctx, ¶ms)
|
||||||
@ -680,7 +699,7 @@ func (csdb *CommitStateDB) Reset(_ ethcmn.Hash) error {
|
|||||||
func (csdb *CommitStateDB) UpdateAccounts() {
|
func (csdb *CommitStateDB) UpdateAccounts() {
|
||||||
for _, stateEntry := range csdb.stateObjects {
|
for _, stateEntry := range csdb.stateObjects {
|
||||||
currAcc := csdb.accountKeeper.GetAccount(csdb.ctx, sdk.AccAddress(stateEntry.address.Bytes()))
|
currAcc := csdb.accountKeeper.GetAccount(csdb.ctx, sdk.AccAddress(stateEntry.address.Bytes()))
|
||||||
emintAcc, ok := currAcc.(*emint.EthAccount)
|
ethermintAcc, ok := currAcc.(*ethermint.EthAccount)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -688,12 +707,12 @@ func (csdb *CommitStateDB) UpdateAccounts() {
|
|||||||
evmDenom := csdb.GetParams().EvmDenom
|
evmDenom := csdb.GetParams().EvmDenom
|
||||||
balance := sdk.Coin{
|
balance := sdk.Coin{
|
||||||
Denom: evmDenom,
|
Denom: evmDenom,
|
||||||
Amount: emintAcc.GetCoins().AmountOf(evmDenom),
|
Amount: ethermintAcc.GetCoins().AmountOf(evmDenom),
|
||||||
}
|
}
|
||||||
|
|
||||||
if stateEntry.stateObject.Balance() != balance.Amount.BigInt() && balance.IsValid() ||
|
if stateEntry.stateObject.Balance() != balance.Amount.BigInt() && balance.IsValid() ||
|
||||||
stateEntry.stateObject.Nonce() != emintAcc.GetSequence() {
|
stateEntry.stateObject.Nonce() != ethermintAcc.GetSequence() {
|
||||||
stateEntry.stateObject.account = emintAcc
|
stateEntry.stateObject.account = ethermintAcc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func (suite *StateDBTestSuite) SetupTest() {
|
|||||||
checkTx := false
|
checkTx := false
|
||||||
|
|
||||||
suite.app = app.Setup(checkTx)
|
suite.app = app.Setup(checkTx)
|
||||||
suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1})
|
suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "ethermint-1"})
|
||||||
suite.stateDB = suite.app.EvmKeeper.CommitStateDB.WithContext(suite.ctx)
|
suite.stateDB = suite.app.EvmKeeper.CommitStateDB.WithContext(suite.ctx)
|
||||||
|
|
||||||
privkey, err := ethsecp256k1.GenerateKey()
|
privkey, err := ethsecp256k1.GenerateKey()
|
||||||
@ -67,6 +67,17 @@ func (suite *StateDBTestSuite) TestParams() {
|
|||||||
suite.Require().Equal(newParams, params)
|
suite.Require().Equal(newParams, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *StateDBTestSuite) TestGetHeightHash() {
|
||||||
|
hash := suite.stateDB.GetHeightHash(0)
|
||||||
|
suite.Require().Equal(ethcmn.Hash{}.String(), hash.String())
|
||||||
|
|
||||||
|
expHash := ethcmn.BytesToHash([]byte("hash"))
|
||||||
|
suite.stateDB.SetHeightHash(10, expHash)
|
||||||
|
|
||||||
|
hash = suite.stateDB.GetHeightHash(10)
|
||||||
|
suite.Require().Equal(expHash.String(), hash.String())
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *StateDBTestSuite) TestBloomFilter() {
|
func (suite *StateDBTestSuite) TestBloomFilter() {
|
||||||
// Prepare db for logs
|
// Prepare db for logs
|
||||||
tHash := ethcmn.BytesToHash([]byte{0x1})
|
tHash := ethcmn.BytesToHash([]byte{0x1})
|
||||||
|
@ -8,6 +8,10 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
"github.com/tendermint/tendermint/version"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
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"
|
||||||
@ -152,3 +156,36 @@ func recoverEthSig(R, S, Vb *big.Int, sigHash ethcmn.Hash) (ethcmn.Address, erro
|
|||||||
|
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AbciHeaderToTendermint is a util function to parse a tendermint ABCI Header to
|
||||||
|
// tendermint types Header.
|
||||||
|
func AbciHeaderToTendermint(header abci.Header) tmtypes.Header {
|
||||||
|
return tmtypes.Header{
|
||||||
|
Version: version.Consensus{
|
||||||
|
Block: version.Protocol(header.Version.Block),
|
||||||
|
App: version.Protocol(header.Version.App),
|
||||||
|
},
|
||||||
|
ChainID: header.ChainID,
|
||||||
|
Height: header.Height,
|
||||||
|
Time: header.Time,
|
||||||
|
|
||||||
|
LastBlockID: tmtypes.BlockID{
|
||||||
|
Hash: header.LastBlockId.Hash,
|
||||||
|
PartsHeader: tmtypes.PartSetHeader{
|
||||||
|
Total: int(header.LastBlockId.PartsHeader.Total),
|
||||||
|
Hash: header.LastBlockId.PartsHeader.Hash,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LastCommitHash: header.LastCommitHash,
|
||||||
|
DataHash: header.DataHash,
|
||||||
|
|
||||||
|
ValidatorsHash: header.ValidatorsHash,
|
||||||
|
NextValidatorsHash: header.NextValidatorsHash,
|
||||||
|
ConsensusHash: header.ConsensusHash,
|
||||||
|
AppHash: header.AppHash,
|
||||||
|
LastResultsHash: header.LastResultsHash,
|
||||||
|
|
||||||
|
EvidenceHash: header.EvidenceHash,
|
||||||
|
ProposerAddress: header.ProposerAddress,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user