diff --git a/app/ethermint.go b/app/ethermint.go index 5d601dba..78804741 100644 --- a/app/ethermint.go +++ b/app/ethermint.go @@ -37,13 +37,13 @@ import ( const appName = "Ethermint" var ( - // default home directories for the application CLI + // DefaultCLIHome sets the default home directories for the application CLI DefaultCLIHome = os.ExpandEnv("$HOME/.emintcli") // DefaultNodeHome sets the folder where the applcation data and configuration will be stored DefaultNodeHome = os.ExpandEnv("$HOME/.emintd") - // The module BasicManager is in charge of setting up basic, + // ModuleBasics is the module BasicManager is in charge of setting up basic, // non-dependant module elements, such as codec registration // and genesis verification. ModuleBasics = module.NewBasicManager( @@ -131,7 +131,7 @@ func NewEthermintApp( keys := sdk.NewKVStoreKeys(bam.MainStoreKey, auth.StoreKey, staking.StoreKey, supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey, - gov.StoreKey, params.StoreKey, evmtypes.EvmStoreKey, evmtypes.EvmCodeKey) + gov.StoreKey, params.StoreKey, evmtypes.EvmStoreKey, evmtypes.EvmCodeKey, evmtypes.EvmBlockKey) tkeys := sdk.NewTransientStoreKeys(staking.TStoreKey, params.TStoreKey) app := &EthermintApp{ @@ -165,7 +165,7 @@ func NewEthermintApp( app.slashingKeeper = slashing.NewKeeper(app.cdc, keys[slashing.StoreKey], &stakingKeeper, slashingSubspace, slashing.DefaultCodespace) app.crisisKeeper = crisis.NewKeeper(crisisSubspace, invCheckPeriod, app.supplyKeeper, auth.FeeCollectorName) - app.evmKeeper = evm.NewKeeper(app.accountKeeper, keys[evmtypes.EvmStoreKey], keys[evmtypes.EvmCodeKey], cdc) + app.evmKeeper = evm.NewKeeper(app.accountKeeper, keys[evmtypes.EvmStoreKey], keys[evmtypes.EvmCodeKey], keys[evmtypes.EvmBlockKey], cdc) // register the proposal types govRouter := gov.NewRouter() @@ -199,9 +199,9 @@ func NewEthermintApp( // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. - app.mm.SetOrderBeginBlockers(mint.ModuleName, distr.ModuleName, slashing.ModuleName) + app.mm.SetOrderBeginBlockers(mint.ModuleName, distr.ModuleName, slashing.ModuleName, evmtypes.ModuleName) - app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName) + app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName, evmtypes.ModuleName) // NOTE: The genutils module must occur after staking so that pools are // properly initialized with tokens from genesis accounts. @@ -233,28 +233,28 @@ func NewEthermintApp( return app } -// The genesis state of the blockchain is represented here as a map of raw json +// GenesisState is the state of the blockchain is represented here as a map of raw json // messages key'd by a identifier string. type GenesisState map[string]json.RawMessage -// application updates every begin block +// BeginBlocker updates every begin block func (app *EthermintApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { return app.mm.BeginBlock(ctx, req) } -// application updates every end block +// EndBlocker updates every end block func (app *EthermintApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { return app.mm.EndBlock(ctx, req) } -// application update at chain initialization +// InitChainer updates at chain initialization func (app *EthermintApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { var genesisState GenesisState app.cdc.MustUnmarshalJSON(req.AppStateBytes, &genesisState) return app.mm.InitGenesis(ctx, genesisState) } -// load a particular height +// LoadHeight loads state at a particular height func (app *EthermintApp) LoadHeight(height int64) error { return app.LoadVersion(height, app.keys[bam.MainStoreKey]) } diff --git a/app/test_utils.go b/app/test_utils.go index 2f90816c..3522a4e7 100644 --- a/app/test_utils.go +++ b/app/test_utils.go @@ -20,8 +20,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" tmcrypto "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tm-db" "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" ) type testSetup struct { diff --git a/cmd/emintcli/main.go b/cmd/emintcli/main.go index 2196e69e..7eda0471 100644 --- a/cmd/emintcli/main.go +++ b/cmd/emintcli/main.go @@ -11,8 +11,8 @@ import ( "github.com/cosmos/cosmos-sdk/client" sdkrpc "github.com/cosmos/cosmos-sdk/client/rpc" sdk "github.com/cosmos/cosmos-sdk/types" - emintkeys "github.com/cosmos/ethermint/keys" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + emintkeys "github.com/cosmos/ethermint/keys" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli" diff --git a/crypto/keys/codec.go b/crypto/keys/codec.go index ed71ff51..02cb1760 100644 --- a/crypto/keys/codec.go +++ b/crypto/keys/codec.go @@ -4,9 +4,9 @@ import ( cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/cosmos/cosmos-sdk/codec" + cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" emintCrypto "github.com/cosmos/ethermint/crypto" - cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys" ) var cdc *codec.Codec diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index 14c2534b..286149c1 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -13,8 +13,8 @@ import ( cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" - "github.com/cosmos/ethermint/crypto/keys/mintkey" "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ethermint/crypto/keys/mintkey" bip39 "github.com/cosmos/go-bip39" diff --git a/importer/importer_test.go b/importer/importer_test.go index 7692bb12..fe601943 100644 --- a/importer/importer_test.go +++ b/importer/importer_test.go @@ -35,8 +35,8 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tm-db" tmlog "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" ) var ( @@ -326,7 +326,7 @@ func applyDAOHardFork(statedb *evmtypes.CommitStateDB) { // and uses the input parameters for its environment. It returns the receipt // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. -// Function is also pulled from go-ethereum 1.9 because of the imcompatible usage +// Function is also pulled from go-ethereum 1.9 because of the incompatible usage // Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/core/state_processor.go#L88 func applyTransaction(config *ethparams.ChainConfig, bc ethcore.ChainContext, author *ethcmn.Address, gp *ethcore.GasPool, statedb *evmtypes.CommitStateDB, header *ethtypes.Header, tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config) (*ethtypes.Receipt, uint64, error) { msg, err := tx.AsMessage(ethtypes.MakeSigner(config, header.Number)) diff --git a/rpc/args/send_tx.go b/rpc/args/send_tx.go index 61d8a225..5d9fe58a 100644 --- a/rpc/args/send_tx.go +++ b/rpc/args/send_tx.go @@ -19,4 +19,4 @@ type SendTxArgs struct { // newer name and should be preferred by clients. Data *hexutil.Bytes `json:"data"` Input *hexutil.Bytes `json:"input"` -} \ No newline at end of file +} diff --git a/rpc/eth_api.go b/rpc/eth_api.go index 90abcbbc..b83b9b62 100644 --- a/rpc/eth_api.go +++ b/rpc/eth_api.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/ethermint/rpc/args" "github.com/cosmos/ethermint/utils" "github.com/cosmos/ethermint/version" + "github.com/cosmos/ethermint/x/evm" "github.com/cosmos/ethermint/x/evm/types" tmtypes "github.com/tendermint/tendermint/types" @@ -332,14 +333,24 @@ func (e *PublicEthAPI) EstimateGas(args CallArgs, blockNum BlockNumber) hexutil. } // GetBlockByHash returns the block identified by hash. -func (e *PublicEthAPI) GetBlockByHash(hash common.Hash, fullTx bool) map[string]interface{} { - return nil +func (e *PublicEthAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) { + res, _, err := e.cliCtx.Query(fmt.Sprintf("custom/%s/%s/%s", types.ModuleName, evm.QueryHashToHeight, hash.Hex())) + if err != nil { + return nil, err + } + + var out types.QueryResBlockNumber + e.cliCtx.Codec.MustUnmarshalJSON(res, &out) + return e.getEthBlockByNumber(out.Number, fullTx) } // GetBlockByNumber returns the block identified by number. func (e *PublicEthAPI) GetBlockByNumber(blockNum BlockNumber, fullTx bool) (map[string]interface{}, error) { value := blockNum.Int64() + return e.getEthBlockByNumber(value, fullTx) +} +func (e *PublicEthAPI) getEthBlockByNumber(value int64, fullTx bool) (map[string]interface{}, error) { // Remove this check when 0 query is fixed ref: (https://github.com/tendermint/tendermint/issues/4014) var blkNumPtr *int64 if value != 0 { @@ -363,7 +374,7 @@ func (e *PublicEthAPI) GetBlockByNumber(blockNum BlockNumber, fullTx bool) (map[ if fullTx { // Populate full transaction data transactions, gasUsed = convertTransactionsToRPC(e.cliCtx, block.Block.Txs, - common.BytesToHash(header.ConsensusHash.Bytes()), uint64(header.Height)) + common.BytesToHash(header.Hash()), uint64(header.Height)) } else { // TODO: Gas used not saved and cannot be calculated by hashes // Return slice of transaction hashes @@ -382,7 +393,7 @@ func formatBlock( ) map[string]interface{} { return map[string]interface{}{ "number": hexutil.Uint64(header.Height), - "hash": hexutil.Bytes(header.ConsensusHash), + "hash": hexutil.Bytes(header.Hash()), "parentHash": hexutil.Bytes(header.LastBlockID.Hash), "nonce": nil, // PoW specific "sha3Uncles": nil, // No uncles in Tendermint @@ -485,7 +496,7 @@ func (e *PublicEthAPI) GetTransactionByHash(hash common.Hash) (*Transaction, err if err != nil { return nil, err } - blockHash := common.BytesToHash(block.BlockMeta.Header.ConsensusHash) + blockHash := common.BytesToHash(block.BlockMeta.Header.Hash()) ethTx, err := bytesToEthTx(e.cliCtx, tx.Tx) if err != nil { @@ -518,7 +529,7 @@ func (e *PublicEthAPI) GetTransactionByBlockNumberAndIndex(blockNum BlockNumber, return nil, err } - transaction := newRPCTransaction(ethTx, common.BytesToHash(header.ConsensusHash.Bytes()), uint64(header.Height), uint64(idx)) + transaction := newRPCTransaction(ethTx, common.BytesToHash(header.Hash()), uint64(header.Height), uint64(idx)) return transaction, nil } @@ -535,7 +546,7 @@ func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]inter if err != nil { return nil, err } - blockHash := common.BytesToHash(block.BlockMeta.Header.ConsensusHash) + blockHash := common.BytesToHash(block.BlockMeta.Header.Hash()) // Convert tx bytes to eth transaction ethTx, err := bytesToEthTx(e.cliCtx, tx.Tx) diff --git a/x/evm/client/utils/tx.go b/x/evm/client/utils/tx.go index 749d7020..ad627c69 100644 --- a/x/evm/client/utils/tx.go +++ b/x/evm/client/utils/tx.go @@ -127,7 +127,7 @@ func completeAndBroadcastETHTxCLI(txBldr authtypes.TxBuilder, cliCtx context.CLI } } - // * This function is overriden to change the keybase reference here + // * This function is overridden to change the keybase reference here passphrase, err := emintkeys.GetPassphrase(fromName) if err != nil { return err @@ -151,7 +151,7 @@ func completeAndBroadcastETHTxCLI(txBldr authtypes.TxBuilder, cliCtx context.CLI // BuildAndSign builds a single message to be signed, and signs a transaction // with the built message given a name, passphrase, and a set of messages. -// * overriden from github.com/cosmos/cosmos-sdk/x/auth/types/txbuilder.go +// * overridden from github.com/cosmos/cosmos-sdk/x/auth/types/txbuilder.go // * This is just modified to change the functionality in makeSignature, through sign func buildAndSign(bldr authtypes.TxBuilder, name, passphrase string, msgs []sdk.Msg) ([]byte, error) { msg, err := bldr.BuildSignMsg(msgs) @@ -179,7 +179,7 @@ func sign(bldr authtypes.TxBuilder, name, passphrase string, msg authtypes.StdSi func makeSignature(keybase crkeys.Keybase, name, passphrase string, msg authtypes.StdSignMsg) (sig authtypes.StdSignature, err error) { if keybase == nil { - // * This is overriden to allow ethermint keys, but not used because keybase is set + // * This is overridden to allow ethermint keys, but not used because keybase is set keybase, err = emintkeys.NewKeyBaseFromHomeFlag() if err != nil { return @@ -212,7 +212,7 @@ func makeSignature(keybase crkeys.Keybase, name, passphrase string, ethTx.Sign(chainID, emintKey.ToECDSA()) - // * This is needed to be overriden to get bytes to sign (RLPSignBytes) with the chainID + // * This is needed to be overridden to get bytes to sign (RLPSignBytes) with the chainID sigBytes, pubkey, err := keybase.Sign(name, passphrase, ethTx.RLPSignBytes(chainID).Bytes()) if err != nil { return @@ -321,7 +321,7 @@ func getFromFields(from string, genOnly bool) (sdk.AccAddress, string, error) { return addr, "", nil } - // * This is the line that needed to be overriden, change could be to pass in optional keybase? + // * This is the line that needed to be overridden, change could be to pass in optional keybase? keybase, err := emintkeys.NewKeyBaseFromHomeFlag() if err != nil { return nil, "", err diff --git a/x/evm/genesis.go b/x/evm/genesis.go index eaa7e062..81078e04 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -2,11 +2,12 @@ package evm import ( "fmt" + "math/big" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ethermint/types" ethcmn "github.com/ethereum/go-ethereum/common" abci "github.com/tendermint/tendermint/abci/types" - "math/big" ) type ( @@ -25,6 +26,7 @@ type ( } ) +// ValidateGenesis validates evm genesis config func ValidateGenesis(data GenesisState) error { for _, acct := range data.Accounts { if len(acct.Address.Bytes()) == 0 { @@ -37,12 +39,14 @@ func ValidateGenesis(data GenesisState) error { return nil } +// DefaultGenesisState sets default evm genesis config func DefaultGenesisState() GenesisState { return GenesisState{ Accounts: []GenesisAccount{}, } } +// InitGenesis initializes genesis state based on exported genesis func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) []abci.ValidatorUpdate { for _, record := range data.Accounts { keeper.SetCode(ctx, record.Address, record.Code) @@ -51,7 +55,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) []abci.Valid return []abci.ValidatorUpdate{} } -// TODO: Implement +// ExportGenesis exports genesis state func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState { return GenesisState{Accounts: nil} } diff --git a/x/evm/keeper.go b/x/evm/keeper.go index f52f20ca..4eb14f42 100644 --- a/x/evm/keeper.go +++ b/x/evm/keeper.go @@ -1,6 +1,9 @@ package evm import ( + "bytes" + "fmt" + "github.com/cosmos/cosmos-sdk/codec" ethcmn "github.com/ethereum/go-ethereum/common" ethvm "github.com/ethereum/go-ethereum/core/vm" @@ -17,17 +20,45 @@ import ( // Keeper wraps the CommitStateDB, allowing us to pass in SDK context while adhering // to the StateDB interface type Keeper struct { - csdb *types.CommitStateDB - cdc *codec.Codec + csdb *types.CommitStateDB + cdc *codec.Codec + blockKey sdk.StoreKey } -func NewKeeper(ak auth.AccountKeeper, storageKey, codeKey sdk.StoreKey, cdc *codec.Codec) Keeper { +// NewKeeper generates new evm module keeper +func NewKeeper(ak auth.AccountKeeper, storageKey, codeKey sdk.StoreKey, + blockKey sdk.StoreKey, cdc *codec.Codec) Keeper { return Keeper{ - csdb: types.NewCommitStateDB(sdk.Context{}, ak, storageKey, codeKey), - cdc: cdc, + csdb: types.NewCommitStateDB(sdk.Context{}, ak, storageKey, codeKey), + cdc: cdc, + blockKey: blockKey, } } +// ---------------------------------------------------------------------------- +// Block hash mapping functions +// May be removed when using only as module (only required by rpc api) +// ---------------------------------------------------------------------------- + +// SetBlockHashMapping sets the mapping from block consensus hash to block height +func (k *Keeper) SetBlockHashMapping(ctx sdk.Context, hash []byte, height int64) { + store := ctx.KVStore(k.blockKey) + if !bytes.Equal(hash, []byte{}) { + store.Set(hash, k.cdc.MustMarshalBinaryLengthPrefixed(height)) + } +} + +// GetBlockHashMapping gets block height from block consensus hash +func (k *Keeper) GetBlockHashMapping(ctx sdk.Context, hash []byte) (height int64) { + store := ctx.KVStore(k.blockKey) + bz := store.Get(hash) + if bytes.Equal(bz, []byte{}) { + panic(fmt.Errorf("block with hash %s not found", ethcmn.Bytes2Hex(hash))) + } + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &height) + return +} + // ---------------------------------------------------------------------------- // Genesis // ---------------------------------------------------------------------------- @@ -47,52 +78,52 @@ func (k *Keeper) CreateGenesisAccount(ctx sdk.Context, account GenesisAccount) { // Setters // ---------------------------------------------------------------------------- -// Calls CommitStateDB.SetBalance using the passed in context +// SetBalance calls CommitStateDB.SetBalance using the passed in context func (k *Keeper) SetBalance(ctx sdk.Context, addr ethcmn.Address, amount *big.Int) { k.csdb.WithContext(ctx).SetBalance(addr, amount) } -// Calls CommitStateDB.AddBalance using the passed in context +// AddBalance calls CommitStateDB.AddBalance using the passed in context func (k *Keeper) AddBalance(ctx sdk.Context, addr ethcmn.Address, amount *big.Int) { k.csdb.WithContext(ctx).AddBalance(addr, amount) } -// Calls CommitStateDB.SubBalance using the passed in context +// SubBalance calls CommitStateDB.SubBalance using the passed in context func (k *Keeper) SubBalance(ctx sdk.Context, addr ethcmn.Address, amount *big.Int) { k.csdb.WithContext(ctx).SubBalance(addr, amount) } -// Calls CommitStateDB.SetNonce using the passed in context +// SetNonce calls CommitStateDB.SetNonce using the passed in context func (k *Keeper) SetNonce(ctx sdk.Context, addr ethcmn.Address, nonce uint64) { k.csdb.WithContext(ctx).SetNonce(addr, nonce) } -// Calls CommitStateDB.SetState using the passed in context +// SetState calls CommitStateDB.SetState using the passed in context func (k *Keeper) SetState(ctx sdk.Context, addr ethcmn.Address, key, value ethcmn.Hash) { k.csdb.WithContext(ctx).SetState(addr, key, value) } -// Calls CommitStateDB.SetCode using the passed in context +// SetCode calls CommitStateDB.SetCode using the passed in context func (k *Keeper) SetCode(ctx sdk.Context, addr ethcmn.Address, code []byte) { k.csdb.WithContext(ctx).SetCode(addr, code) } -// Calls CommitStateDB.AddLog using the passed in context +// AddLog calls CommitStateDB.AddLog using the passed in context func (k *Keeper) AddLog(ctx sdk.Context, log *ethtypes.Log) { k.csdb.WithContext(ctx).AddLog(log) } -// Calls CommitStateDB.AddPreimage using the passed in context +// AddPreimage calls CommitStateDB.AddPreimage using the passed in context func (k *Keeper) AddPreimage(ctx sdk.Context, hash ethcmn.Hash, preimage []byte) { k.csdb.WithContext(ctx).AddPreimage(hash, preimage) } -// Calls CommitStateDB.AddRefund using the passed in context +// AddRefund calls CommitStateDB.AddRefund using the passed in context func (k *Keeper) AddRefund(ctx sdk.Context, gas uint64) { k.csdb.WithContext(ctx).AddRefund(gas) } -// Calls CommitStateDB.SubRefund using the passed in context +// SubRefund calls CommitStateDB.SubRefund using the passed in context func (k *Keeper) SubRefund(ctx sdk.Context, gas uint64) { k.csdb.WithContext(ctx).SubRefund(gas) } @@ -101,77 +132,77 @@ func (k *Keeper) SubRefund(ctx sdk.Context, gas uint64) { // Getters // ---------------------------------------------------------------------------- -// Calls CommitStateDB.GetBalance using the passed in context +// GetBalance calls CommitStateDB.GetBalance using the passed in context func (k *Keeper) GetBalance(ctx sdk.Context, addr ethcmn.Address) *big.Int { return k.csdb.WithContext(ctx).GetBalance(addr) } -// Calls CommitStateDB.GetNonce using the passed in context +// GetNonce calls CommitStateDB.GetNonce using the passed in context func (k *Keeper) GetNonce(ctx sdk.Context, addr ethcmn.Address) uint64 { return k.csdb.WithContext(ctx).GetNonce(addr) } -// Calls CommitStateDB.TxIndex using the passed in context +// TxIndex calls CommitStateDB.TxIndex using the passed in context func (k *Keeper) TxIndex(ctx sdk.Context) int { return k.csdb.WithContext(ctx).TxIndex() } -// Calls CommitStateDB.BlockHash using the passed in context +// BlockHash calls CommitStateDB.BlockHash using the passed in context func (k *Keeper) BlockHash(ctx sdk.Context) ethcmn.Hash { return k.csdb.WithContext(ctx).BlockHash() } -// Calls CommitStateDB.GetCode using the passed in context +// GetCode calls CommitStateDB.GetCode using the passed in context func (k *Keeper) GetCode(ctx sdk.Context, addr ethcmn.Address) []byte { return k.csdb.WithContext(ctx).GetCode(addr) } -// Calls CommitStateDB.GetCodeSize using the passed in context +// GetCodeSize calls CommitStateDB.GetCodeSize using the passed in context func (k *Keeper) GetCodeSize(ctx sdk.Context, addr ethcmn.Address) int { return k.csdb.WithContext(ctx).GetCodeSize(addr) } -// Calls CommitStateDB.GetCodeHash using the passed in context +// GetCodeHash calls CommitStateDB.GetCodeHash using the passed in context func (k *Keeper) GetCodeHash(ctx sdk.Context, addr ethcmn.Address) ethcmn.Hash { return k.csdb.WithContext(ctx).GetCodeHash(addr) } -// Calls CommitStateDB.GetState using the passed in context +// GetState calls CommitStateDB.GetState using the passed in context func (k *Keeper) GetState(ctx sdk.Context, addr ethcmn.Address, hash ethcmn.Hash) ethcmn.Hash { return k.csdb.WithContext(ctx).GetState(addr, hash) } -// Calls CommitStateDB.GetCommittedState using the passed in context +// GetCommittedState calls CommitStateDB.GetCommittedState using the passed in context func (k *Keeper) GetCommittedState(ctx sdk.Context, addr ethcmn.Address, hash ethcmn.Hash) ethcmn.Hash { return k.csdb.WithContext(ctx).GetCommittedState(addr, hash) } -// Calls CommitStateDB.GetLogs using the passed in context +// GetLogs calls CommitStateDB.GetLogs using the passed in context func (k *Keeper) GetLogs(ctx sdk.Context, hash ethcmn.Hash) []*ethtypes.Log { return k.csdb.WithContext(ctx).GetLogs(hash) } -// Calls CommitStateDB.Logs using the passed in context +// Logs calls CommitStateDB.Logs using the passed in context func (k *Keeper) Logs(ctx sdk.Context) []*ethtypes.Log { return k.csdb.WithContext(ctx).Logs() } -// Calls CommitStateDB.GetRefund using the passed in context +// GetRefund calls CommitStateDB.GetRefund using the passed in context func (k *Keeper) GetRefund(ctx sdk.Context) uint64 { return k.csdb.WithContext(ctx).GetRefund() } -// Calls CommitStateDB.Preimages using the passed in context +// Preimages calls CommitStateDB.Preimages using the passed in context func (k *Keeper) Preimages(ctx sdk.Context) map[ethcmn.Hash][]byte { return k.csdb.WithContext(ctx).Preimages() } -// Calls CommitStateDB.HasSuicided using the passed in context +// HasSuicided calls CommitStateDB.HasSuicided using the passed in context func (k *Keeper) HasSuicided(ctx sdk.Context, addr ethcmn.Address) bool { return k.csdb.WithContext(ctx).HasSuicided(addr) } -// Calls CommitStateDB.StorageTrie using the passed in context +// StorageTrie calls CommitStateDB.StorageTrie using the passed in context func (k *Keeper) StorageTrie(ctx sdk.Context, addr ethcmn.Address) ethstate.Trie { return k.csdb.WithContext(ctx).StorageTrie(addr) } @@ -180,17 +211,17 @@ func (k *Keeper) StorageTrie(ctx sdk.Context, addr ethcmn.Address) ethstate.Trie // Persistence // ---------------------------------------------------------------------------- -// Calls CommitStateDB.Commit using the passed in context +// Commit calls CommitStateDB.Commit using the passed { in context func (k *Keeper) Commit(ctx sdk.Context, deleteEmptyObjects bool) (root ethcmn.Hash, err error) { return k.csdb.WithContext(ctx).Commit(deleteEmptyObjects) } -// Calls CommitStateDB.Finalise using the passed in context +// Finalise calls CommitStateDB.Finalise using the passed in context func (k *Keeper) Finalise(ctx sdk.Context, deleteEmptyObjects bool) { k.csdb.WithContext(ctx).Finalise(deleteEmptyObjects) } -// Calls CommitStateDB.IntermediateRoot using the passed in context +// IntermediateRoot calls CommitStateDB.IntermediateRoot using the passed in context func (k *Keeper) IntermediateRoot(ctx sdk.Context, deleteEmptyObjects bool) { k.csdb.WithContext(ctx).IntermediateRoot(deleteEmptyObjects) } @@ -199,12 +230,12 @@ func (k *Keeper) IntermediateRoot(ctx sdk.Context, deleteEmptyObjects bool) { // Snapshotting // ---------------------------------------------------------------------------- -// Calls CommitStateDB.Snapshot using the passed in context +// Snapshot calls CommitStateDB.Snapshot using the passed in context func (k *Keeper) Snapshot(ctx sdk.Context) int { return k.csdb.WithContext(ctx).Snapshot() } -// Calls CommitStateDB.RevertToSnapshot using the passed in context +// RevertToSnapshot calls CommitStateDB.RevertToSnapshot using the passed in context func (k *Keeper) RevertToSnapshot(ctx sdk.Context, revID int) { k.csdb.WithContext(ctx).RevertToSnapshot(revID) } @@ -213,57 +244,57 @@ func (k *Keeper) RevertToSnapshot(ctx sdk.Context, revID int) { // Auxiliary // ---------------------------------------------------------------------------- -// Calls CommitStateDB.Database using the passed in context +// Database calls CommitStateDB.Database using the passed in context func (k *Keeper) Database(ctx sdk.Context) ethstate.Database { return k.csdb.WithContext(ctx).Database() } -// Calls CommitStateDB.Empty using the passed in context +// Empty calls CommitStateDB.Empty using the passed in context func (k *Keeper) Empty(ctx sdk.Context, addr ethcmn.Address) bool { return k.csdb.WithContext(ctx).Empty(addr) } -// Calls CommitStateDB.Exist using the passed in context +// Exist calls CommitStateDB.Exist using the passed in context func (k *Keeper) Exist(ctx sdk.Context, addr ethcmn.Address) bool { return k.csdb.WithContext(ctx).Exist(addr) } -// Calls CommitStateDB.Error using the passed in context +// Error calls CommitStateDB.Error using the passed in context func (k *Keeper) Error(ctx sdk.Context) error { return k.csdb.WithContext(ctx).Error() } -// Calls CommitStateDB.Suicide using the passed in context +// Suicide calls CommitStateDB.Suicide using the passed in context func (k *Keeper) Suicide(ctx sdk.Context, addr ethcmn.Address) bool { return k.csdb.WithContext(ctx).Suicide(addr) } -// Calls CommitStateDB.Reset using the passed in context +// Reset calls CommitStateDB.Reset using the passed in context func (k *Keeper) Reset(ctx sdk.Context, root ethcmn.Hash) error { return k.csdb.WithContext(ctx).Reset(root) } -// Calls CommitStateDB.Prepare using the passed in context +// Prepare calls CommitStateDB.Prepare using the passed in context func (k *Keeper) Prepare(ctx sdk.Context, thash, bhash ethcmn.Hash, txi int) { k.csdb.WithContext(ctx).Prepare(thash, bhash, txi) } -// Calls CommitStateDB.CreateAccount using the passed in context +// CreateAccount calls CommitStateDB.CreateAccount using the passed in context func (k *Keeper) CreateAccount(ctx sdk.Context, addr ethcmn.Address) { k.csdb.WithContext(ctx).CreateAccount(addr) } -// Calls CommitStateDB.Copy using the passed in context +// Copy calls CommitStateDB.Copy using the passed in context func (k *Keeper) Copy(ctx sdk.Context) ethvm.StateDB { return k.csdb.WithContext(ctx).Copy() } -// Calls CommitStateDB.ForEachStorage using passed in context +// ForEachStorage calls CommitStateDB.ForEachStorage using passed in context func (k *Keeper) ForEachStorage(ctx sdk.Context, addr ethcmn.Address, cb func(key, value ethcmn.Hash) bool) error { return k.csdb.WithContext(ctx).ForEachStorage(addr, cb) } -// Calls CommitStateDB.GetOrNetStateObject using the passed in context +// GetOrNewStateObject calls CommitStateDB.GetOrNetStateObject using the passed in context func (k *Keeper) GetOrNewStateObject(ctx sdk.Context, addr ethcmn.Address) types.StateObject { return k.csdb.WithContext(ctx).GetOrNewStateObject(addr) } diff --git a/x/evm/keeper_test.go b/x/evm/keeper_test.go index ea016394..9a2d304c 100644 --- a/x/evm/keeper_test.go +++ b/x/evm/keeper_test.go @@ -27,6 +27,7 @@ var ( accKey = sdk.NewKVStoreKey("acc") storageKey = sdk.NewKVStoreKey(evmtypes.EvmStoreKey) codeKey = sdk.NewKVStoreKey(evmtypes.EvmCodeKey) + blockKey = sdk.NewKVStoreKey(evmtypes.EvmBlockKey) logger = tmlog.NewNopLogger() ) @@ -54,12 +55,12 @@ func TestDBStorage(t *testing.T) { // Set specific supspaces authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace) ak := auth.NewAccountKeeper(cdc, accKey, authSubspace, types.ProtoBaseAccount) - ek := NewKeeper(ak, storageKey, codeKey, cdc) + ek := NewKeeper(ak, storageKey, codeKey, blockKey, cdc) db := dbm.NewMemDB() cms := store.NewCommitMultiStore(db) // mount stores - keys := []*sdk.KVStoreKey{accKey, storageKey, codeKey} + keys := []*sdk.KVStoreKey{accKey, storageKey, codeKey, blockKey} for _, key := range keys { cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, nil) } @@ -79,12 +80,19 @@ func TestDBStorage(t *testing.T) { ek.SetState(ctx, address, ethcmn.HexToHash("0x2"), ethcmn.HexToHash("0x3")) ek.SetCode(ctx, address, []byte{0x1}) + // Test block hash mapping functionality + ek.SetBlockHashMapping(ctx, ethcmn.FromHex("0x0d87a3a5f73140f46aac1bf419263e4e94e87c292f25007700ab7f2060e2af68"), 7) + ek.SetBlockHashMapping(ctx, []byte{0x43, 0x32}, 8) + // Get those state transitions require.Equal(t, ek.GetBalance(ctx, address).Cmp(big.NewInt(5)), 0) require.Equal(t, ek.GetNonce(ctx, address), uint64(4)) require.Equal(t, ek.GetState(ctx, address, ethcmn.HexToHash("0x2")), ethcmn.HexToHash("0x3")) require.Equal(t, ek.GetCode(ctx, address), []byte{0x1}) + require.Equal(t, ek.GetBlockHashMapping(ctx, ethcmn.FromHex("0x0d87a3a5f73140f46aac1bf419263e4e94e87c292f25007700ab7f2060e2af68")), int64(7)) + require.Equal(t, ek.GetBlockHashMapping(ctx, []byte{0x43, 0x32}), int64(8)) + // commit stateDB _, err = ek.Commit(ctx, false) require.NoError(t, err, "failed to commit StateDB") diff --git a/x/evm/module.go b/x/evm/module.go index d09715b5..3f403f0e 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -104,7 +104,10 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { } // BeginBlock function for module at start of each block -func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} +func (am AppModule) BeginBlock(ctx sdk.Context, bl abci.RequestBeginBlock) { + // Consider removing this when using evm as module without web3 API + am.keeper.SetBlockHashMapping(ctx, bl.Header.LastBlockId.GetHash(), bl.Header.GetHeight()-1) +} // EndBlock function for module at end of block func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { diff --git a/x/evm/querier.go b/x/evm/querier.go index a983938c..96159e86 100644 --- a/x/evm/querier.go +++ b/x/evm/querier.go @@ -19,6 +19,7 @@ const ( QueryStorage = "storage" QueryCode = "code" QueryNonce = "nonce" + QueryHashToHeight = "hashToHeight" ) // NewQuerier is the module level router for state queries @@ -37,6 +38,8 @@ func NewQuerier(keeper Keeper) sdk.Querier { return queryCode(ctx, path, keeper) case QueryNonce: return queryNonce(ctx, path, keeper) + case QueryHashToHeight: + return queryHashToHeight(ctx, path, keeper) default: return nil, sdk.ErrUnknownRequest("unknown query endpoint") } @@ -113,3 +116,16 @@ func queryNonce(ctx sdk.Context, path []string, keeper Keeper) ([]byte, sdk.Erro return res, nil } + +func queryHashToHeight(ctx sdk.Context, path []string, keeper Keeper) ([]byte, sdk.Error) { + blockHash := ethcmn.FromHex(path[1]) + blockNumber := keeper.GetBlockHashMapping(ctx, blockHash) + + bRes := types.QueryResBlockNumber{Number: blockNumber} + res, err := codec.MarshalJSONIndent(keeper.cdc, bRes) + if err != nil { + panic("could not marshal result to JSON: " + err.Error()) + } + + return res, nil +} diff --git a/x/evm/types/key.go b/x/evm/types/key.go index b22b328d..d257084f 100644 --- a/x/evm/types/key.go +++ b/x/evm/types/key.go @@ -1,11 +1,16 @@ package types const ( - // module name + // ModuleName string name of module ModuleName = "ethermint" + // EvmStoreKey key for ethereum storage data EvmStoreKey = "evmstore" - EvmCodeKey = "evmcode" + // EvmCodeKey key for ethereum code data + EvmCodeKey = "evmcode" + // EvmBlockKey key for ethereum block data + EvmBlockKey = "evmblock" + // RouterKey uses module name for routing RouterKey = ModuleName )