From ebaa99cc5e086d30d05db190558c52cdbaa38088 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 15 Apr 2020 20:10:07 -0400 Subject: [PATCH 01/14] evm: export genesis state --- app/ethermint.go | 2 +- x/evm/genesis.go | 33 ++++++++++++++++++++++++++++++--- x/evm/module.go | 6 ++++-- x/evm/types/expected_keepers.go | 1 + 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/app/ethermint.go b/app/ethermint.go index 79705be21..b88f6c96e 100644 --- a/app/ethermint.go +++ b/app/ethermint.go @@ -236,7 +236,7 @@ func NewEthermintApp( slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.StakingKeeper), distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.SupplyKeeper, app.StakingKeeper), staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), - evm.NewAppModule(app.EvmKeeper), + evm.NewAppModule(app.EvmKeeper, app.AccountKeeper), ) // During begin block slashing happens after distr.BeginBlocker so that diff --git a/x/evm/genesis.go b/x/evm/genesis.go index c97916f56..cc4491c9e 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -1,20 +1,47 @@ package evm import ( + "github.com/ethereum/go-ethereum/common" + sdk "github.com/cosmos/cosmos-sdk/types" + + emint "github.com/cosmos/ethermint/types" + "github.com/cosmos/ethermint/x/evm/types" abci "github.com/tendermint/tendermint/abci/types" ) // InitGenesis initializes genesis state based on exported genesis func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorUpdate { for _, record := range data.Accounts { - k.SetCode(ctx, record.Address, record.Code) k.CreateGenesisAccount(ctx, record) } return []abci.ValidatorUpdate{} } // ExportGenesis exports genesis state -func ExportGenesis(ctx sdk.Context, _ Keeper) GenesisState { - return GenesisState{Accounts: nil} +func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisState { + var ethGenAccounts []types.GenesisAccount + + accounts := ak.GetAllAccounts(ctx) + + for _, account := range accounts { + ethAccount, ok := account.(emint.Account) + if !ok { + continue + } + + addr := common.BytesToAddress(ethAccount.GetAddress().Bytes()) + + genAccount := types.GenesisAccount{ + Address: addr, + Balance: k.GetBalance(ctx, addr), + Code: k.GetCode(ctx, addr), + // Storage: k.GetStorage(ctx, addr), TODO: + } + + ethGenAccounts = append(ethGenAccounts, genAccount) + + } + + return GenesisState{Accounts: ethGenAccounts} } diff --git a/x/evm/module.go b/x/evm/module.go index 7b24e01b3..e904d88ca 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -69,13 +69,15 @@ func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { type AppModule struct { AppModuleBasic keeper Keeper + ak types.AccountKeeper } // NewAppModule creates a new AppModule Object -func NewAppModule(k Keeper) AppModule { +func NewAppModule(k Keeper, ak types.AccountKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: k, + ak: ak, } } @@ -126,6 +128,6 @@ func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.Va // ExportGenesis exports the genesis state to be used by daemon func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { - gs := ExportGenesis(ctx, am.keeper) + gs := ExportGenesis(ctx, am.keeper, am.ak) return types.ModuleCdc.MustMarshalJSON(gs) } diff --git a/x/evm/types/expected_keepers.go b/x/evm/types/expected_keepers.go index 5bcf05eed..8e0afc260 100644 --- a/x/evm/types/expected_keepers.go +++ b/x/evm/types/expected_keepers.go @@ -8,6 +8,7 @@ import ( // AccountKeeper defines the expected account keeper interface type AccountKeeper interface { NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authexported.Account + GetAllAccounts(ctx sdk.Context) (accounts []authexported.Account) GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account SetAccount(ctx sdk.Context, account authexported.Account) RemoveAccount(ctx sdk.Context, account authexported.Account) From 2a74def7ad4da02a81e3ece08e05bb275856a6ac Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 17 Apr 2020 22:34:03 -0400 Subject: [PATCH 02/14] x/evm: split keeper.go --- x/evm/handler.go | 2 +- x/evm/keeper/keeper.go | 245 +------------------------------------- x/evm/keeper/statedb.go | 253 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 255 insertions(+), 245 deletions(-) create mode 100644 x/evm/keeper/statedb.go diff --git a/x/evm/handler.go b/x/evm/handler.go index ac0a7c077..ec86327aa 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -76,7 +76,7 @@ func HandleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) sdk k.Bloom.Or(k.Bloom, returnData.Bloom) // update transaction logs in KVStore - err = k.SetTransactionLogs(ctx, returnData.Logs, txHash[:]) + err = k.SetTransactionLogs(ctx, txHash[:], returnData.Logs) if err != nil { return sdk.ResultFromError(err) } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 28e057b3e..4ea660a8c 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -8,11 +8,9 @@ import ( "github.com/cosmos/cosmos-sdk/codec" ethcmn "github.com/ethereum/go-ethereum/common" - ethvm "github.com/ethereum/go-ethereum/core/vm" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ethermint/x/evm/types" - ethstate "github.com/ethereum/go-ethereum/core/state" ethtypes "github.com/ethereum/go-ethereum/core/types" "math/big" @@ -101,7 +99,7 @@ func (k *Keeper) GetBlockBloomMapping(ctx sdk.Context, height int64) (ethtypes.B } // SetTransactionLogs sets the transaction's logs in the KVStore -func (k *Keeper) SetTransactionLogs(ctx sdk.Context, logs []*ethtypes.Log, hash []byte) error { +func (k *Keeper) SetTransactionLogs(ctx sdk.Context, hash []byte, logs []*ethtypes.Log) error { store := ctx.KVStore(k.blockKey) encLogs, err := types.EncodeLogs(logs) if err != nil { @@ -122,244 +120,3 @@ func (k *Keeper) GetTransactionLogs(ctx sdk.Context, hash []byte) ([]*ethtypes.L return types.DecodeLogs(encLogs) } - -// ---------------------------------------------------------------------------- -// Genesis -// ---------------------------------------------------------------------------- - -// CreateGenesisAccount initializes an account and its balance, code, and storage -func (k *Keeper) CreateGenesisAccount(ctx sdk.Context, account types.GenesisAccount) { - csdb := k.CommitStateDB.WithContext(ctx) - csdb.SetBalance(account.Address, account.Balance) - csdb.SetCode(account.Address, account.Code) - for _, key := range account.Storage { - csdb.SetState(account.Address, key, account.Storage[key]) - } - -} - -// ---------------------------------------------------------------------------- -// Setters -// ---------------------------------------------------------------------------- - -// SetBalance calls CommitStateDB.SetBalance using the passed in context -func (k *Keeper) SetBalance(ctx sdk.Context, addr ethcmn.Address, amount *big.Int) { - k.CommitStateDB.WithContext(ctx).SetBalance(addr, amount) -} - -// AddBalance calls CommitStateDB.AddBalance using the passed in context -func (k *Keeper) AddBalance(ctx sdk.Context, addr ethcmn.Address, amount *big.Int) { - k.CommitStateDB.WithContext(ctx).AddBalance(addr, amount) -} - -// SubBalance calls CommitStateDB.SubBalance using the passed in context -func (k *Keeper) SubBalance(ctx sdk.Context, addr ethcmn.Address, amount *big.Int) { - k.CommitStateDB.WithContext(ctx).SubBalance(addr, amount) -} - -// SetNonce calls CommitStateDB.SetNonce using the passed in context -func (k *Keeper) SetNonce(ctx sdk.Context, addr ethcmn.Address, nonce uint64) { - k.CommitStateDB.WithContext(ctx).SetNonce(addr, nonce) -} - -// SetState calls CommitStateDB.SetState using the passed in context -func (k *Keeper) SetState(ctx sdk.Context, addr ethcmn.Address, key, value ethcmn.Hash) { - k.CommitStateDB.WithContext(ctx).SetState(addr, key, value) -} - -// SetCode calls CommitStateDB.SetCode using the passed in context -func (k *Keeper) SetCode(ctx sdk.Context, addr ethcmn.Address, code []byte) { - k.CommitStateDB.WithContext(ctx).SetCode(addr, code) -} - -// AddLog calls CommitStateDB.AddLog using the passed in context -func (k *Keeper) AddLog(ctx sdk.Context, log *ethtypes.Log) { - k.CommitStateDB.WithContext(ctx).AddLog(log) -} - -// AddPreimage calls CommitStateDB.AddPreimage using the passed in context -func (k *Keeper) AddPreimage(ctx sdk.Context, hash ethcmn.Hash, preimage []byte) { - k.CommitStateDB.WithContext(ctx).AddPreimage(hash, preimage) -} - -// AddRefund calls CommitStateDB.AddRefund using the passed in context -func (k *Keeper) AddRefund(ctx sdk.Context, gas uint64) { - k.CommitStateDB.WithContext(ctx).AddRefund(gas) -} - -// SubRefund calls CommitStateDB.SubRefund using the passed in context -func (k *Keeper) SubRefund(ctx sdk.Context, gas uint64) { - k.CommitStateDB.WithContext(ctx).SubRefund(gas) -} - -// ---------------------------------------------------------------------------- -// Getters -// ---------------------------------------------------------------------------- - -// GetBalance calls CommitStateDB.GetBalance using the passed in context -func (k *Keeper) GetBalance(ctx sdk.Context, addr ethcmn.Address) *big.Int { - return k.CommitStateDB.WithContext(ctx).GetBalance(addr) -} - -// GetNonce calls CommitStateDB.GetNonce using the passed in context -func (k *Keeper) GetNonce(ctx sdk.Context, addr ethcmn.Address) uint64 { - return k.CommitStateDB.WithContext(ctx).GetNonce(addr) -} - -// TxIndex calls CommitStateDB.TxIndex using the passed in context -func (k *Keeper) TxIndex(ctx sdk.Context) int { - return k.CommitStateDB.WithContext(ctx).TxIndex() -} - -// BlockHash calls CommitStateDB.BlockHash using the passed in context -func (k *Keeper) BlockHash(ctx sdk.Context) ethcmn.Hash { - return k.CommitStateDB.WithContext(ctx).BlockHash() -} - -// GetCode calls CommitStateDB.GetCode using the passed in context -func (k *Keeper) GetCode(ctx sdk.Context, addr ethcmn.Address) []byte { - return k.CommitStateDB.WithContext(ctx).GetCode(addr) -} - -// GetCodeSize calls CommitStateDB.GetCodeSize using the passed in context -func (k *Keeper) GetCodeSize(ctx sdk.Context, addr ethcmn.Address) int { - return k.CommitStateDB.WithContext(ctx).GetCodeSize(addr) -} - -// GetCodeHash calls CommitStateDB.GetCodeHash using the passed in context -func (k *Keeper) GetCodeHash(ctx sdk.Context, addr ethcmn.Address) ethcmn.Hash { - return k.CommitStateDB.WithContext(ctx).GetCodeHash(addr) -} - -// 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.CommitStateDB.WithContext(ctx).GetState(addr, hash) -} - -// 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.CommitStateDB.WithContext(ctx).GetCommittedState(addr, hash) -} - -// GetLogs calls CommitStateDB.GetLogs using the passed in context -func (k *Keeper) GetLogs(ctx sdk.Context, hash ethcmn.Hash) ([]*ethtypes.Log, error) { - return k.CommitStateDB.WithContext(ctx).GetLogs(hash) -} - -// AllLogs calls CommitStateDB.AllLogs using the passed in context -func (k *Keeper) AllLogs(ctx sdk.Context) []*ethtypes.Log { - return k.CommitStateDB.WithContext(ctx).AllLogs() -} - -// GetRefund calls CommitStateDB.GetRefund using the passed in context -func (k *Keeper) GetRefund(ctx sdk.Context) uint64 { - return k.CommitStateDB.WithContext(ctx).GetRefund() -} - -// Preimages calls CommitStateDB.Preimages using the passed in context -func (k *Keeper) Preimages(ctx sdk.Context) map[ethcmn.Hash][]byte { - return k.CommitStateDB.WithContext(ctx).Preimages() -} - -// HasSuicided calls CommitStateDB.HasSuicided using the passed in context -func (k *Keeper) HasSuicided(ctx sdk.Context, addr ethcmn.Address) bool { - return k.CommitStateDB.WithContext(ctx).HasSuicided(addr) -} - -// StorageTrie calls CommitStateDB.StorageTrie using the passed in context -func (k *Keeper) StorageTrie(ctx sdk.Context, addr ethcmn.Address) ethstate.Trie { - return k.CommitStateDB.WithContext(ctx).StorageTrie(addr) -} - -// ---------------------------------------------------------------------------- -// Persistence -// ---------------------------------------------------------------------------- - -// 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.CommitStateDB.WithContext(ctx).Commit(deleteEmptyObjects) -} - -// Finalise calls CommitStateDB.Finalise using the passed in context -func (k *Keeper) Finalise(ctx sdk.Context, deleteEmptyObjects bool) error { - return k.CommitStateDB.WithContext(ctx).Finalise(deleteEmptyObjects) -} - -// IntermediateRoot calls CommitStateDB.IntermediateRoot using the passed in context -func (k *Keeper) IntermediateRoot(ctx sdk.Context, deleteEmptyObjects bool) error { - _, err := k.CommitStateDB.WithContext(ctx).IntermediateRoot(deleteEmptyObjects) - return err -} - -// ---------------------------------------------------------------------------- -// Snapshotting -// ---------------------------------------------------------------------------- - -// Snapshot calls CommitStateDB.Snapshot using the passed in context -func (k *Keeper) Snapshot(ctx sdk.Context) int { - return k.CommitStateDB.WithContext(ctx).Snapshot() -} - -// RevertToSnapshot calls CommitStateDB.RevertToSnapshot using the passed in context -func (k *Keeper) RevertToSnapshot(ctx sdk.Context, revID int) { - k.CommitStateDB.WithContext(ctx).RevertToSnapshot(revID) -} - -// ---------------------------------------------------------------------------- -// Auxiliary -// ---------------------------------------------------------------------------- - -// Database calls CommitStateDB.Database using the passed in context -func (k *Keeper) Database(ctx sdk.Context) ethstate.Database { - return k.CommitStateDB.WithContext(ctx).Database() -} - -// Empty calls CommitStateDB.Empty using the passed in context -func (k *Keeper) Empty(ctx sdk.Context, addr ethcmn.Address) bool { - return k.CommitStateDB.WithContext(ctx).Empty(addr) -} - -// Exist calls CommitStateDB.Exist using the passed in context -func (k *Keeper) Exist(ctx sdk.Context, addr ethcmn.Address) bool { - return k.CommitStateDB.WithContext(ctx).Exist(addr) -} - -// Error calls CommitStateDB.Error using the passed in context -func (k *Keeper) Error(ctx sdk.Context) error { - return k.CommitStateDB.WithContext(ctx).Error() -} - -// Suicide calls CommitStateDB.Suicide using the passed in context -func (k *Keeper) Suicide(ctx sdk.Context, addr ethcmn.Address) bool { - return k.CommitStateDB.WithContext(ctx).Suicide(addr) -} - -// Reset calls CommitStateDB.Reset using the passed in context -func (k *Keeper) Reset(ctx sdk.Context, root ethcmn.Hash) error { - return k.CommitStateDB.WithContext(ctx).Reset(root) -} - -// Prepare calls CommitStateDB.Prepare using the passed in context -func (k *Keeper) Prepare(ctx sdk.Context, thash, bhash ethcmn.Hash, txi int) { - k.CommitStateDB.WithContext(ctx).Prepare(thash, bhash, txi) -} - -// CreateAccount calls CommitStateDB.CreateAccount using the passed in context -func (k *Keeper) CreateAccount(ctx sdk.Context, addr ethcmn.Address) { - k.CommitStateDB.WithContext(ctx).CreateAccount(addr) -} - -// Copy calls CommitStateDB.Copy using the passed in context -func (k *Keeper) Copy(ctx sdk.Context) ethvm.StateDB { - return k.CommitStateDB.WithContext(ctx).Copy() -} - -// 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.CommitStateDB.WithContext(ctx).ForEachStorage(addr, cb) -} - -// GetOrNewStateObject calls CommitStateDB.GetOrNetStateObject using the passed in context -func (k *Keeper) GetOrNewStateObject(ctx sdk.Context, addr ethcmn.Address) types.StateObject { - return k.CommitStateDB.WithContext(ctx).GetOrNewStateObject(addr) -} diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go new file mode 100644 index 000000000..a0fea45a7 --- /dev/null +++ b/x/evm/keeper/statedb.go @@ -0,0 +1,253 @@ +package keeper + +import ( + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ethermint/x/evm/types" + ethcmn "github.com/ethereum/go-ethereum/common" + ethstate "github.com/ethereum/go-ethereum/core/state" + ethtypes "github.com/ethereum/go-ethereum/core/types" + ethvm "github.com/ethereum/go-ethereum/core/vm" +) + +// ---------------------------------------------------------------------------- +// Genesis +// ---------------------------------------------------------------------------- + +// CreateGenesisAccount initializes an account and its balance, code, and storage +func (k *Keeper) CreateGenesisAccount(ctx sdk.Context, account types.GenesisAccount) { + csdb := k.CommitStateDB.WithContext(ctx) + csdb.SetBalance(account.Address, account.Balance) + csdb.SetCode(account.Address, account.Code) + for _, key := range account.Storage { + csdb.SetState(account.Address, key, account.Storage[key]) + } + +} + +// ---------------------------------------------------------------------------- +// Setters +// ---------------------------------------------------------------------------- + +// SetBalance calls CommitStateDB.SetBalance using the passed in context +func (k *Keeper) SetBalance(ctx sdk.Context, addr ethcmn.Address, amount *big.Int) { + k.CommitStateDB.WithContext(ctx).SetBalance(addr, amount) +} + +// AddBalance calls CommitStateDB.AddBalance using the passed in context +func (k *Keeper) AddBalance(ctx sdk.Context, addr ethcmn.Address, amount *big.Int) { + k.CommitStateDB.WithContext(ctx).AddBalance(addr, amount) +} + +// SubBalance calls CommitStateDB.SubBalance using the passed in context +func (k *Keeper) SubBalance(ctx sdk.Context, addr ethcmn.Address, amount *big.Int) { + k.CommitStateDB.WithContext(ctx).SubBalance(addr, amount) +} + +// SetNonce calls CommitStateDB.SetNonce using the passed in context +func (k *Keeper) SetNonce(ctx sdk.Context, addr ethcmn.Address, nonce uint64) { + k.CommitStateDB.WithContext(ctx).SetNonce(addr, nonce) +} + +// SetState calls CommitStateDB.SetState using the passed in context +func (k *Keeper) SetState(ctx sdk.Context, addr ethcmn.Address, key, value ethcmn.Hash) { + k.CommitStateDB.WithContext(ctx).SetState(addr, key, value) +} + +// SetCode calls CommitStateDB.SetCode using the passed in context +func (k *Keeper) SetCode(ctx sdk.Context, addr ethcmn.Address, code []byte) { + k.CommitStateDB.WithContext(ctx).SetCode(addr, code) +} + +// AddLog calls CommitStateDB.AddLog using the passed in context +func (k *Keeper) AddLog(ctx sdk.Context, log *ethtypes.Log) { + k.CommitStateDB.WithContext(ctx).AddLog(log) +} + +// AddPreimage calls CommitStateDB.AddPreimage using the passed in context +func (k *Keeper) AddPreimage(ctx sdk.Context, hash ethcmn.Hash, preimage []byte) { + k.CommitStateDB.WithContext(ctx).AddPreimage(hash, preimage) +} + +// AddRefund calls CommitStateDB.AddRefund using the passed in context +func (k *Keeper) AddRefund(ctx sdk.Context, gas uint64) { + k.CommitStateDB.WithContext(ctx).AddRefund(gas) +} + +// SubRefund calls CommitStateDB.SubRefund using the passed in context +func (k *Keeper) SubRefund(ctx sdk.Context, gas uint64) { + k.CommitStateDB.WithContext(ctx).SubRefund(gas) +} + +// ---------------------------------------------------------------------------- +// Getters +// ---------------------------------------------------------------------------- + +// GetBalance calls CommitStateDB.GetBalance using the passed in context +func (k *Keeper) GetBalance(ctx sdk.Context, addr ethcmn.Address) *big.Int { + return k.CommitStateDB.WithContext(ctx).GetBalance(addr) +} + +// GetNonce calls CommitStateDB.GetNonce using the passed in context +func (k *Keeper) GetNonce(ctx sdk.Context, addr ethcmn.Address) uint64 { + return k.CommitStateDB.WithContext(ctx).GetNonce(addr) +} + +// TxIndex calls CommitStateDB.TxIndex using the passed in context +func (k *Keeper) TxIndex(ctx sdk.Context) int { + return k.CommitStateDB.WithContext(ctx).TxIndex() +} + +// BlockHash calls CommitStateDB.BlockHash using the passed in context +func (k *Keeper) BlockHash(ctx sdk.Context) ethcmn.Hash { + return k.CommitStateDB.WithContext(ctx).BlockHash() +} + +// GetCode calls CommitStateDB.GetCode using the passed in context +func (k *Keeper) GetCode(ctx sdk.Context, addr ethcmn.Address) []byte { + return k.CommitStateDB.WithContext(ctx).GetCode(addr) +} + +// GetCodeSize calls CommitStateDB.GetCodeSize using the passed in context +func (k *Keeper) GetCodeSize(ctx sdk.Context, addr ethcmn.Address) int { + return k.CommitStateDB.WithContext(ctx).GetCodeSize(addr) +} + +// GetCodeHash calls CommitStateDB.GetCodeHash using the passed in context +func (k *Keeper) GetCodeHash(ctx sdk.Context, addr ethcmn.Address) ethcmn.Hash { + return k.CommitStateDB.WithContext(ctx).GetCodeHash(addr) +} + +// 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.CommitStateDB.WithContext(ctx).GetState(addr, hash) +} + +// 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.CommitStateDB.WithContext(ctx).GetCommittedState(addr, hash) +} + +// GetLogs calls CommitStateDB.GetLogs using the passed in context +func (k *Keeper) GetLogs(ctx sdk.Context, hash ethcmn.Hash) ([]*ethtypes.Log, error) { + return k.CommitStateDB.WithContext(ctx).GetLogs(hash) +} + +// AllLogs calls CommitStateDB.AllLogs using the passed in context +func (k *Keeper) AllLogs(ctx sdk.Context) []*ethtypes.Log { + return k.CommitStateDB.WithContext(ctx).AllLogs() +} + +// GetRefund calls CommitStateDB.GetRefund using the passed in context +func (k *Keeper) GetRefund(ctx sdk.Context) uint64 { + return k.CommitStateDB.WithContext(ctx).GetRefund() +} + +// Preimages calls CommitStateDB.Preimages using the passed in context +func (k *Keeper) Preimages(ctx sdk.Context) map[ethcmn.Hash][]byte { + return k.CommitStateDB.WithContext(ctx).Preimages() +} + +// HasSuicided calls CommitStateDB.HasSuicided using the passed in context +func (k *Keeper) HasSuicided(ctx sdk.Context, addr ethcmn.Address) bool { + return k.CommitStateDB.WithContext(ctx).HasSuicided(addr) +} + +// StorageTrie calls CommitStateDB.StorageTrie using the passed in context +func (k *Keeper) StorageTrie(ctx sdk.Context, addr ethcmn.Address) ethstate.Trie { + return k.CommitStateDB.WithContext(ctx).StorageTrie(addr) +} + +// ---------------------------------------------------------------------------- +// Persistence +// ---------------------------------------------------------------------------- + +// 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.CommitStateDB.WithContext(ctx).Commit(deleteEmptyObjects) +} + +// Finalise calls CommitStateDB.Finalise using the passed in context +func (k *Keeper) Finalise(ctx sdk.Context, deleteEmptyObjects bool) error { + return k.CommitStateDB.WithContext(ctx).Finalise(deleteEmptyObjects) +} + +// IntermediateRoot calls CommitStateDB.IntermediateRoot using the passed in context +func (k *Keeper) IntermediateRoot(ctx sdk.Context, deleteEmptyObjects bool) error { + _, err := k.CommitStateDB.WithContext(ctx).IntermediateRoot(deleteEmptyObjects) + return err +} + +// ---------------------------------------------------------------------------- +// Snapshotting +// ---------------------------------------------------------------------------- + +// Snapshot calls CommitStateDB.Snapshot using the passed in context +func (k *Keeper) Snapshot(ctx sdk.Context) int { + return k.CommitStateDB.WithContext(ctx).Snapshot() +} + +// RevertToSnapshot calls CommitStateDB.RevertToSnapshot using the passed in context +func (k *Keeper) RevertToSnapshot(ctx sdk.Context, revID int) { + k.CommitStateDB.WithContext(ctx).RevertToSnapshot(revID) +} + +// ---------------------------------------------------------------------------- +// Auxiliary +// ---------------------------------------------------------------------------- + +// Database calls CommitStateDB.Database using the passed in context +func (k *Keeper) Database(ctx sdk.Context) ethstate.Database { + return k.CommitStateDB.WithContext(ctx).Database() +} + +// Empty calls CommitStateDB.Empty using the passed in context +func (k *Keeper) Empty(ctx sdk.Context, addr ethcmn.Address) bool { + return k.CommitStateDB.WithContext(ctx).Empty(addr) +} + +// Exist calls CommitStateDB.Exist using the passed in context +func (k *Keeper) Exist(ctx sdk.Context, addr ethcmn.Address) bool { + return k.CommitStateDB.WithContext(ctx).Exist(addr) +} + +// Error calls CommitStateDB.Error using the passed in context +func (k *Keeper) Error(ctx sdk.Context) error { + return k.CommitStateDB.WithContext(ctx).Error() +} + +// Suicide calls CommitStateDB.Suicide using the passed in context +func (k *Keeper) Suicide(ctx sdk.Context, addr ethcmn.Address) bool { + return k.CommitStateDB.WithContext(ctx).Suicide(addr) +} + +// Reset calls CommitStateDB.Reset using the passed in context +func (k *Keeper) Reset(ctx sdk.Context, root ethcmn.Hash) error { + return k.CommitStateDB.WithContext(ctx).Reset(root) +} + +// Prepare calls CommitStateDB.Prepare using the passed in context +func (k *Keeper) Prepare(ctx sdk.Context, thash, bhash ethcmn.Hash, txi int) { + k.CommitStateDB.WithContext(ctx).Prepare(thash, bhash, txi) +} + +// CreateAccount calls CommitStateDB.CreateAccount using the passed in context +func (k *Keeper) CreateAccount(ctx sdk.Context, addr ethcmn.Address) { + k.CommitStateDB.WithContext(ctx).CreateAccount(addr) +} + +// Copy calls CommitStateDB.Copy using the passed in context +func (k *Keeper) Copy(ctx sdk.Context) ethvm.StateDB { + return k.CommitStateDB.WithContext(ctx).Copy() +} + +// 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.CommitStateDB.WithContext(ctx).ForEachStorage(addr, cb) +} + +// GetOrNewStateObject calls CommitStateDB.GetOrNetStateObject using the passed in context +func (k *Keeper) GetOrNewStateObject(ctx sdk.Context, addr ethcmn.Address) types.StateObject { + return k.CommitStateDB.WithContext(ctx).GetOrNewStateObject(addr) +} From 7c78c79d5f99f9b2692ca305b7ac480472b33acb Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 20 Apr 2020 17:11:17 -0400 Subject: [PATCH 03/14] x/evm: retrieve storage from address --- x/evm/genesis.go | 22 ++++++++++++++++++---- x/evm/genesis_test.go | 15 +++++++++++++++ x/evm/handler.go | 11 +++++++---- x/evm/handler_test.go | 2 +- x/evm/keeper/keeper.go | 27 +++++++++++++-------------- x/evm/keeper/statedb.go | 16 +--------------- 6 files changed, 55 insertions(+), 38 deletions(-) create mode 100644 x/evm/genesis_test.go diff --git a/x/evm/genesis.go b/x/evm/genesis.go index cc4491c9e..411c78b60 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -12,8 +12,13 @@ import ( // InitGenesis initializes genesis state based on exported genesis func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorUpdate { - for _, record := range data.Accounts { - k.CreateGenesisAccount(ctx, record) + for _, account := range data.Accounts { + csdb := k.CommitStateDB.WithContext(ctx) + csdb.SetBalance(account.Address, account.Balance) + csdb.SetCode(account.Address, account.Code) + for _, key := range account.Storage { + csdb.SetState(account.Address, key, account.Storage[key]) + } } return []abci.ValidatorUpdate{} } @@ -24,6 +29,7 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta accounts := ak.GetAllAccounts(ctx) + var err error for _, account := range accounts { ethAccount, ok := account.(emint.Account) if !ok { @@ -32,15 +38,23 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta addr := common.BytesToAddress(ethAccount.GetAddress().Bytes()) + var storage emint.Storage + err = k.CommitStateDB.ForEachStorage(addr, func(key, value common.Hash) bool { + storage[key] = value + return false + }) + if err != nil { + panic(err) + } + genAccount := types.GenesisAccount{ Address: addr, Balance: k.GetBalance(ctx, addr), Code: k.GetCode(ctx, addr), - // Storage: k.GetStorage(ctx, addr), TODO: + Storage: storage } ethGenAccounts = append(ethGenAccounts, genAccount) - } return GenesisState{Accounts: ethGenAccounts} diff --git a/x/evm/genesis_test.go b/x/evm/genesis_test.go new file mode 100644 index 000000000..1a82bcac8 --- /dev/null +++ b/x/evm/genesis_test.go @@ -0,0 +1,15 @@ +package evm_test + +import ( + "github.com/cosmos/ethermint/x/evm" + "github.com/cosmos/ethermint/x/evm/types" +) + +func (suite *EvmTestSuite) TestExportImport() { + var genState types.GenesisState + suite.Require().NotPanics(func() { + genState = evm.ExportGenesis(suite.ctx, suite.app.EvmKeeper, suite.app.AccountKeeper) + }) + + _ = evm.InitGenesis(suite.ctx, suite.app.EvmKeeper, genState) +} diff --git a/x/evm/handler.go b/x/evm/handler.go index ec86327aa..8457b7422 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -76,10 +76,7 @@ func HandleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) sdk k.Bloom.Or(k.Bloom, returnData.Bloom) // update transaction logs in KVStore - err = k.SetTransactionLogs(ctx, txHash[:], returnData.Logs) - if err != nil { - return sdk.ResultFromError(err) - } + k.SetTransactionLogs(ctx, txHash[:], returnData.Logs) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( @@ -145,6 +142,12 @@ func HandleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) sdk.R return sdk.ResultFromError(err) } + // update block bloom filter + k.Bloom.Or(k.Bloom, returnData.Bloom) + + // update transaction logs in KVStore + k.SetTransactionLogs(ctx, txHash[:], returnData.Logs) + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeEthermint, diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index c8c2bce9d..7ad704582 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -86,7 +86,7 @@ func (suite *EvmTestSuite) TestHandler_Logs() { suite.Require().Equal(len(resultData.Logs[0].Topics), 2) hash := []byte{1} - err = suite.app.EvmKeeper.SetTransactionLogs(suite.ctx, resultData.Logs, hash) + suite.app.EvmKeeper.SetTransactionLogs(suite.ctx, hash, resultData.Logs) suite.Require().NoError(err, "failed to set logs") logs, err := suite.app.EvmKeeper.GetTransactionLogs(suite.ctx, hash) diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 4ea660a8c..11cdfe312 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -7,10 +7,11 @@ import ( "fmt" "github.com/cosmos/cosmos-sdk/codec" - ethcmn "github.com/ethereum/go-ethereum/common" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ethermint/x/evm/types" + + ethcmn "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "math/big" @@ -90,33 +91,31 @@ func (k *Keeper) SetBlockBloomMapping(ctx sdk.Context, bloom ethtypes.Bloom, hei func (k *Keeper) GetBlockBloomMapping(ctx sdk.Context, height int64) (ethtypes.Bloom, error) { store := ctx.KVStore(k.blockKey) bz := sdk.Uint64ToBigEndian(uint64(height)) - if len(bz) == 0 { + bloom := store.Get(types.BloomKey(bz)) + if len(bloom) == 0 { return ethtypes.BytesToBloom([]byte{}), fmt.Errorf("block with height %d not found", height) } - bloom := store.Get(types.BloomKey(bz)) return ethtypes.BytesToBloom(bloom), nil } // SetTransactionLogs sets the transaction's logs in the KVStore -func (k *Keeper) SetTransactionLogs(ctx sdk.Context, hash []byte, logs []*ethtypes.Log) error { +func (k *Keeper) SetTransactionLogs(ctx sdk.Context, hash []byte, logs []*ethtypes.Log) { store := ctx.KVStore(k.blockKey) - encLogs, err := types.EncodeLogs(logs) - if err != nil { - return err - } - store.Set(types.LogsKey(hash), encLogs) - return nil + bz := k.cdc.MustMarshalBinaryLengthPrefixed(logs) + store.Set(types.LogsKey(hash), bz) } // GetTransactionLogs gets the logs for a transaction from the KVStore func (k *Keeper) GetTransactionLogs(ctx sdk.Context, hash []byte) ([]*ethtypes.Log, error) { store := ctx.KVStore(k.blockKey) - encLogs := store.Get(types.LogsKey(hash)) - if len(encLogs) == 0 { + bz := store.Get(types.LogsKey(hash)) + if len(bz) == 0 { return nil, errors.New("cannot get transaction logs") } - return types.DecodeLogs(encLogs) + var logs []*ethtypes.Log + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, logs) + return logs, nil } diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index a0fea45a7..061a21428 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -5,27 +5,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ethermint/x/evm/types" + ethcmn "github.com/ethereum/go-ethereum/common" ethstate "github.com/ethereum/go-ethereum/core/state" ethtypes "github.com/ethereum/go-ethereum/core/types" ethvm "github.com/ethereum/go-ethereum/core/vm" ) -// ---------------------------------------------------------------------------- -// Genesis -// ---------------------------------------------------------------------------- - -// CreateGenesisAccount initializes an account and its balance, code, and storage -func (k *Keeper) CreateGenesisAccount(ctx sdk.Context, account types.GenesisAccount) { - csdb := k.CommitStateDB.WithContext(ctx) - csdb.SetBalance(account.Address, account.Balance) - csdb.SetCode(account.Address, account.Code) - for _, key := range account.Storage { - csdb.SetState(account.Address, key, account.Storage[key]) - } - -} - // ---------------------------------------------------------------------------- // Setters // ---------------------------------------------------------------------------- From 58048af8f1e981de8651e92175ed7571823821ee Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 20 Apr 2020 17:15:12 -0400 Subject: [PATCH 04/14] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6994ac11e..7dc786ed1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (app/ante) Moved `AnteHandler` implementation to `app/ante` * (keys) Marked `ExportEthKeyCommand` as **UNSAFE** * (x/evm) Moved `BeginBlock` and `EndBlock` to `x/evm/abci.go` +* (`x/evm`) [\#255](https://github.com/ChainSafe/ethermint/pull/255) Add `ExportGenesis` functionality. ### Features From de24c146d9ab190debbd4452dfb612307897ddc3 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 20 Apr 2020 17:19:31 -0400 Subject: [PATCH 05/14] fixes --- x/evm/genesis.go | 2 +- x/evm/keeper/keeper.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/evm/genesis.go b/x/evm/genesis.go index 411c78b60..e7b0b30ea 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -51,7 +51,7 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta Address: addr, Balance: k.GetBalance(ctx, addr), Code: k.GetCode(ctx, addr), - Storage: storage + Storage: storage, } ethGenAccounts = append(ethGenAccounts, genAccount) diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 11cdfe312..9231db26f 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -116,6 +116,6 @@ func (k *Keeper) GetTransactionLogs(ctx sdk.Context, hash []byte) ([]*ethtypes.L } var logs []*ethtypes.Log - k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, logs) + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &logs) return logs, nil } From ded3b377af25e69ad7f6caefa9546b9648fb288b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 21 Apr 2020 16:13:13 -0400 Subject: [PATCH 06/14] add check for nil logs --- x/evm/keeper/keeper.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 9231db26f..e5f6ede64 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -102,7 +102,9 @@ func (k *Keeper) GetBlockBloomMapping(ctx sdk.Context, height int64) (ethtypes.B // SetTransactionLogs sets the transaction's logs in the KVStore func (k *Keeper) SetTransactionLogs(ctx sdk.Context, hash []byte, logs []*ethtypes.Log) { store := ctx.KVStore(k.blockKey) - + if logs == nil || len(logs) == 0 { + panic("cannot set empty or nil logs") + } bz := k.cdc.MustMarshalBinaryLengthPrefixed(logs) store.Set(types.LogsKey(hash), bz) } From a4d77b025e0b4f8258a22b802939e9437df50394 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Thu, 23 Apr 2020 19:04:21 -0400 Subject: [PATCH 07/14] update validation func --- x/evm/module.go | 8 ++--- x/evm/types/genesis.go | 28 ++++++++++-------- x/evm/types/genesis_test.go | 59 +++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 x/evm/types/genesis_test.go diff --git a/x/evm/module.go b/x/evm/module.go index 64e512b6d..a04282f89 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -41,13 +41,13 @@ func (AppModuleBasic) DefaultGenesis() json.RawMessage { // ValidateGenesis is the validation check of the Genesis func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { - var data types.GenesisState - err := types.ModuleCdc.UnmarshalJSON(bz, &data) + var genesisState types.GenesisState + err := types.ModuleCdc.UnmarshalJSON(bz, &genesisState) if err != nil { return err } - // Once json successfully marshalled, passes along to genesis.go - return types.ValidateGenesis(data) + + return genesisState.Validate() } // RegisterRESTRoutes Registers rest routes diff --git a/x/evm/types/genesis.go b/x/evm/types/genesis.go index d3da70684..7a974fb54 100644 --- a/x/evm/types/genesis.go +++ b/x/evm/types/genesis.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "errors" "math/big" @@ -8,6 +9,8 @@ import ( ethcmn "github.com/ethereum/go-ethereum/common" ) +var zeroAddrBytes = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + type ( // GenesisState defines the application's genesis state. It contains all the // information required and accounts to initialize the blockchain. @@ -24,22 +27,23 @@ type ( } ) -// ValidateGenesis validates evm genesis config -func ValidateGenesis(data GenesisState) error { - for _, acct := range data.Accounts { - if len(acct.Address.Bytes()) == 0 { +// DefaultGenesisState sets default evm genesis config +func DefaultGenesisState() GenesisState { + return GenesisState{ + Accounts: []GenesisAccount{}, + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + for _, acc := range gs.Accounts { + if bytes.Equal(acc.Address.Bytes(), zeroAddrBytes) { return errors.New("invalid GenesisAccount: address cannot be empty") } - if acct.Balance == nil { + if acc.Balance == nil { return errors.New("invalid GenesisAccount: balance cannot be empty") } } return nil } - -// DefaultGenesisState sets default evm genesis config -func DefaultGenesisState() GenesisState { - return GenesisState{ - Accounts: []GenesisAccount{}, - } -} diff --git a/x/evm/types/genesis_test.go b/x/evm/types/genesis_test.go new file mode 100644 index 000000000..e1dfa0a3c --- /dev/null +++ b/x/evm/types/genesis_test.go @@ -0,0 +1,59 @@ +package types + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/require" + + ethcmn "github.com/ethereum/go-ethereum/common" +) + +func TestValidateGenesis(t *testing.T) { + + testCases := []struct { + name string + genState GenesisState + expPass bool + }{ + { + name: "default", + genState: DefaultGenesisState(), + expPass: true, + }, + { + name: "empty account address bytes", + genState: GenesisState{ + Accounts: []GenesisAccount{ + { + Address: ethcmn.Address{}, + Balance: big.NewInt(1), + }, + }, + }, + expPass: false, + }, + { + name: "nil account balance", + genState: GenesisState{ + Accounts: []GenesisAccount{ + { + Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}), + Balance: nil, + }, + }, + }, + expPass: false, + }, + } + + for _, tc := range testCases { + tc := tc + err := tc.genState.Validate() + if tc.expPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + } + } +} From 986c50391d86cbf02fb1d9d70d5256fdaceedf83 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 24 Apr 2020 15:24:17 -0400 Subject: [PATCH 08/14] fixes --- x/evm/genesis.go | 2 +- x/evm/handler_test.go | 1 - x/evm/keeper/keeper.go | 6 ++---- x/evm/module.go | 8 ++++---- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/x/evm/genesis.go b/x/evm/genesis.go index e7b0b30ea..a8485f7e9 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -31,7 +31,7 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta var err error for _, account := range accounts { - ethAccount, ok := account.(emint.Account) + ethAccount, ok := account.(emint.EthAccount) if !ok { continue } diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index 5e23f1cb4..5b209b858 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -233,7 +233,6 @@ func (suite *EvmTestSuite) TestHandlerLogs() { hash := []byte{1} suite.app.EvmKeeper.SetTransactionLogs(suite.ctx, hash, resultData.Logs) - suite.Require().NoError(err, "failed to set logs") logs, err := suite.app.EvmKeeper.GetTransactionLogs(suite.ctx, hash) suite.Require().NoError(err, "failed to get logs") diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 1f35f2608..ecc46128e 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -92,13 +92,11 @@ func (k Keeper) SetBlockBloomMapping(ctx sdk.Context, bloom ethtypes.Bloom, heig } // SetTransactionLogs sets the transaction's logs in the KVStore -func (k *Keeper) SetTransactionLogs(ctx sdk.Context, hash []byte, logs []*ethtypes.Log) { +func (k *Keeper) SetTransactionLogs(ctx sdk.Context, hash []byte, logs []*ethtypes.Log) error { store := ctx.KVStore(k.blockKey) - if logs == nil || len(logs) == 0 { - panic("cannot set empty or nil logs") - } bz := k.cdc.MustMarshalBinaryLengthPrefixed(logs) store.Set(types.LogsKey(hash), bz) + return nil } // GetTransactionLogs gets the logs for a transaction from the KVStore diff --git a/x/evm/module.go b/x/evm/module.go index 3e5624dac..5208c5f9b 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -40,9 +40,9 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis is the validation check of the Genesis -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { var genesisState types.GenesisState - err := types.ModuleCdc.UnmarshalJSON(bz, &genesisState) + err := cdc.UnmarshalJSON(bz, &genesisState) if err != nil { return err } @@ -129,7 +129,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j } // ExportGenesis exports the genesis state to be used by daemon -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { gs := ExportGenesis(ctx, am.keeper, am.ak) - return types.ModuleCdc.MustMarshalJSON(gs) + return cdc.MustMarshalJSON(gs) } From 1d016585122c5dca6ebdf29e4ad63899ce048c88 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 1 May 2020 12:06:57 -0400 Subject: [PATCH 09/14] fix non-determinism --- x/evm/alias.go | 7 +++++-- x/evm/genesis.go | 12 ++++++------ x/evm/keeper/keeper.go | 7 +++++-- x/evm/types/genesis.go | 26 +++++++++++++++++++++----- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/x/evm/alias.go b/x/evm/alias.go index dc5e2822a..42e273a2e 100644 --- a/x/evm/alias.go +++ b/x/evm/alias.go @@ -27,8 +27,9 @@ const ( // nolint var ( - NewKeeper = keeper.NewKeeper - TxDecoder = types.TxDecoder + NewKeeper = keeper.NewKeeper + TxDecoder = types.TxDecoder + NewGenesisStorage = types.NewGenesisStorage ) //nolint @@ -36,4 +37,6 @@ type ( Keeper = keeper.Keeper QueryResAccount = types.QueryResAccount GenesisState = types.GenesisState + GenesisAccount = types.GenesisAccount + GenesisStorage = types.GenesisStorage ) diff --git a/x/evm/genesis.go b/x/evm/genesis.go index a8485f7e9..46783cbed 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -16,8 +16,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU csdb := k.CommitStateDB.WithContext(ctx) csdb.SetBalance(account.Address, account.Balance) csdb.SetCode(account.Address, account.Code) - for _, key := range account.Storage { - csdb.SetState(account.Address, key, account.Storage[key]) + for _, storage := range account.Storage { + csdb.SetState(account.Address, storage.Key, storage.Value) } } return []abci.ValidatorUpdate{} @@ -25,7 +25,7 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU // ExportGenesis exports genesis state func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisState { - var ethGenAccounts []types.GenesisAccount + var ethGenAccounts []GenesisAccount accounts := ak.GetAllAccounts(ctx) @@ -38,16 +38,16 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta addr := common.BytesToAddress(ethAccount.GetAddress().Bytes()) - var storage emint.Storage + var storage []GenesisStorage err = k.CommitStateDB.ForEachStorage(addr, func(key, value common.Hash) bool { - storage[key] = value + storage = append(storage, NewGenesisStorage(key, value)) return false }) if err != nil { panic(err) } - genAccount := types.GenesisAccount{ + genAccount := GenesisAccount{ Address: addr, Balance: k.GetBalance(ctx, addr), Code: k.GetCode(ctx, addr), diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 3e9831cb0..9a6ac1f1c 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -27,8 +27,11 @@ type Keeper struct { // Web3 API blockKey sdk.StoreKey CommitStateDB *types.CommitStateDB - TxCount int - Bloom *big.Int + // Transaction counter in a block. Used on StateSB's Prepare function. + // It is reset to 0 every block on BeginBlock so there's no point in storing the counter + // on the KVStore or adding it as a field on the EVM genesis state. + TxCount int + Bloom *big.Int } // NewKeeper generates new evm module keeper diff --git a/x/evm/types/genesis.go b/x/evm/types/genesis.go index 7a974fb54..dd6234cc3 100644 --- a/x/evm/types/genesis.go +++ b/x/evm/types/genesis.go @@ -5,7 +5,6 @@ import ( "errors" "math/big" - "github.com/cosmos/ethermint/types" ethcmn "github.com/ethereum/go-ethereum/common" ) @@ -18,15 +17,32 @@ type ( Accounts []GenesisAccount `json:"accounts"` } + // GenesisStorage represents the GenesisAccount Storage map as single key value + // pairs. This is to prevent non determinism at genesis initialization or export. + GenesisStorage struct { + Key ethcmn.Hash `json:"key"` + Value ethcmn.Hash `json:"value"` + } + // GenesisAccount defines an account to be initialized in the genesis state. + // Its main difference between with Geth's GenesisAccount is that it uses a custom + // storage type and that it doesn't contain the private key field. GenesisAccount struct { - Address ethcmn.Address `json:"address"` - Balance *big.Int `json:"balance"` - Code []byte `json:"code,omitempty"` - Storage types.Storage `json:"storage,omitempty"` + Address ethcmn.Address `json:"address"` + Balance *big.Int `json:"balance"` + Code []byte `json:"code,omitempty"` + Storage []GenesisStorage `json:"storage,omitempty"` } ) +// NewGenesisStorage creates a new GenesisStorage instance +func NewGenesisStorage(key, value ethcmn.Hash) GenesisStorage { + return GenesisStorage{ + Key: key, + Value: value, + } +} + // DefaultGenesisState sets default evm genesis config func DefaultGenesisState() GenesisState { return GenesisState{ From df00d0ad43a53c3ad59b76f744650c8498e968c8 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 1 May 2020 16:26:14 -0400 Subject: [PATCH 10/14] stop storage iteration --- x/evm/types/statedb.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/x/evm/types/statedb.go b/x/evm/types/statedb.go index a9575fb90..082551763 100644 --- a/x/evm/types/statedb.go +++ b/x/evm/types/statedb.go @@ -722,11 +722,18 @@ func (csdb *CommitStateDB) ForEachStorage(addr ethcmn.Address, cb func(key, valu value := iter.Value() if value, dirty := so.dirtyStorage[key]; dirty { - cb(key, value) + // check if iteration stops + if cb(key, value) { + break + } + continue } - cb(key, ethcmn.BytesToHash(value)) + // check if iteration stops + if cb(key, ethcmn.BytesToHash(value)) { + break + } } return nil From 279cfdbbf4576778fa246bdd3d01f2b3ede00514 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Sat, 2 May 2020 14:21:16 -0400 Subject: [PATCH 11/14] remove error return value --- x/evm/keeper/keeper.go | 3 +-- x/evm/types/genesis.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 9a6ac1f1c..1ddcdab6c 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -102,11 +102,10 @@ func (k Keeper) SetBlockBloomMapping(ctx sdk.Context, bloom ethtypes.Bloom, heig } // SetTransactionLogs sets the transaction's logs in the KVStore -func (k *Keeper) SetTransactionLogs(ctx sdk.Context, hash []byte, logs []*ethtypes.Log) error { +func (k *Keeper) SetTransactionLogs(ctx sdk.Context, hash []byte, logs []*ethtypes.Log) { store := ctx.KVStore(k.blockKey) bz := k.cdc.MustMarshalBinaryLengthPrefixed(logs) store.Set(types.LogsKey(hash), bz) - return nil } // GetTransactionLogs gets the logs for a transaction from the KVStore diff --git a/x/evm/types/genesis.go b/x/evm/types/genesis.go index dd6234cc3..066aab6b7 100644 --- a/x/evm/types/genesis.go +++ b/x/evm/types/genesis.go @@ -43,7 +43,7 @@ func NewGenesisStorage(key, value ethcmn.Hash) GenesisStorage { } } -// DefaultGenesisState sets default evm genesis config +// DefaultGenesisState sets default evm genesis state with empty accounts. func DefaultGenesisState() GenesisState { return GenesisState{ Accounts: []GenesisAccount{}, From 4d23bc082d4c84bbe17842e9a197d8e0e39e7f0e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 18 May 2020 11:45:28 -0400 Subject: [PATCH 12/14] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8781607f..ffad07ea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,7 +53,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (`app/ante`) Moved `AnteHandler` implementation to `app/ante` * (keys) Marked `ExportEthKeyCommand` as **UNSAFE** * (x/evm) Moved `BeginBlock` and `EndBlock` to `x/evm/abci.go` -* (`x/evm`) [\#255](https://github.com/ChainSafe/ethermint/pull/255) Add `ExportGenesis` functionality. +* (`x/evm`) [\#255](https://github.com/ChainSafe/ethermint/pull/255) Add missing `GenesisState` fields and support `ExportGenesis` functionality. * [\#272](https://github.com/ChainSafe/ethermint/pull/272) Add `Logger` for evm module. ### Features From 0b17d77dc920ffdf1006ef96113d12d4f5fd7400 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 18 May 2020 11:58:49 -0400 Subject: [PATCH 13/14] fix test --- x/evm/keeper/keeper_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index e296653ea..c1b0c51ef 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -53,8 +53,7 @@ func (suite *KeeperTestSuite) TestTransactionLogs() { } expLogs := []*ethtypes.Log{log} - err := suite.app.EvmKeeper.SetTransactionLogs(suite.ctx, expLogs, hash) - suite.Require().NoError(err) + suite.app.EvmKeeper.SetTransactionLogs(suite.ctx, hash, expLogs) suite.app.EvmKeeper.AddLog(suite.ctx, expLogs[0]) logs, err := suite.app.EvmKeeper.GetTransactionLogs(suite.ctx, hash) From 148867e64b0ba37afda15a4d0367f568adb33148 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 18 May 2020 12:52:10 -0400 Subject: [PATCH 14/14] lint --- x/evm/genesis.go | 2 +- x/evm/handler.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x/evm/genesis.go b/x/evm/genesis.go index 46783cbed..9adb18253 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -25,8 +25,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU // ExportGenesis exports genesis state func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisState { + // nolint: prealloc var ethGenAccounts []GenesisAccount - accounts := ak.GetAllAccounts(ctx) var err error diff --git a/x/evm/handler.go b/x/evm/handler.go index 4c440bd36..d2c1f12c7 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -74,7 +74,7 @@ func handleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*s k.Bloom.Or(k.Bloom, executionResult.Bloom) // update transaction logs in KVStore - k.SetTransactionLogs(ctx, txHash[:], executionResult.Logs) + k.SetTransactionLogs(ctx, txHash, executionResult.Logs) // log successful execution k.Logger(ctx).Info(executionResult.Result.Log) @@ -147,7 +147,7 @@ func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk k.Bloom.Or(k.Bloom, executionResult.Bloom) // update transaction logs in KVStore - k.SetTransactionLogs(ctx, txHash[:], executionResult.Logs) + k.SetTransactionLogs(ctx, txHash, executionResult.Logs) // log successful execution k.Logger(ctx).Info(executionResult.Result.Log)