types, evm: refactor accounts (#884)

* types,evm: refactor accounts

* fix

* fix panic

* changelog

* fix

* lint, rm dbErr
This commit is contained in:
Federico Kunze Küllmer 2022-01-05 19:18:02 +01:00 committed by GitHub
parent eea80d50c3
commit 4320f46fc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 116 additions and 155 deletions

View File

@ -56,6 +56,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Improvements ### Improvements
* (types) [tharsis#884](https://github.com/tharsis/ethermint/pull/884) Introduce a new `EthAccountI` interface for EVM-compatible account types.
* (types) [tharsis#849](https://github.com/tharsis/ethermint/pull/849) Add `Type` function to distinguish EOAs from Contract accounts. * (types) [tharsis#849](https://github.com/tharsis/ethermint/pull/849) Add `Type` function to distinguish EOAs from Contract accounts.
* (evm) [tharsis#826](https://github.com/tharsis/ethermint/issues/826) Improve allocation of bytes of `tx.To` address. * (evm) [tharsis#826](https://github.com/tharsis/ethermint/issues/826) Improve allocation of bytes of `tx.To` address.
* (evm) [tharsis#827](https://github.com/tharsis/ethermint/issues/827) Speed up creation of event logs by using the slice insertion idiom with indices. * (evm) [tharsis#827](https://github.com/tharsis/ethermint/issues/827) Speed up creation of event logs by using the slice insertion idiom with indices.
@ -64,6 +65,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Bug Fixes ### Bug Fixes
* (evm) [tharsis#884](https://github.com/tharsis/ethermint/pull/884) Support multiple account types on the EVM `StateDB`.
* (rpc) [tharsis#831](https://github.com/tharsis/ethermint/pull/831) Fix BaseFee value when height is specified. * (rpc) [tharsis#831](https://github.com/tharsis/ethermint/pull/831) Fix BaseFee value when height is specified.
* (evm) [tharsis#838](https://github.com/tharsis/ethermint/pull/838) Fix splitting of trace.Memory into 32 chunks. * (evm) [tharsis#838](https://github.com/tharsis/ethermint/pull/838) Fix splitting of trace.Memory into 32 chunks.
* (rpc) [tharsis#860](https://github.com/tharsis/ethermint/pull/860) Fix `eth_getLogs` when specify blockHash without address/topics, and limit the response size. * (rpc) [tharsis#860](https://github.com/tharsis/ethermint/pull/860) Fix `eth_getLogs` when specify blockHash without address/topics, and limit the response size.

View File

@ -115,11 +115,8 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx
// check whether the sender address is EOA // check whether the sender address is EOA
fromAddr := common.BytesToAddress(from) fromAddr := common.BytesToAddress(from)
acct, err := avd.evmKeeper.GetAccount(ctx, fromAddr) acct := avd.evmKeeper.GetAccount(ctx, fromAddr)
if err != nil {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType,
"the sender is not EthAccount: address %s", fromAddr)
}
if acct == nil { if acct == nil {
acc := avd.ak.NewAccountWithAddress(ctx, from) acc := avd.ak.NewAccountWithAddress(ctx, from)
avd.ak.SetAccount(ctx, acc) avd.ak.SetAccount(ctx, acc)

View File

@ -5,6 +5,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
tx "github.com/cosmos/cosmos-sdk/types/tx" tx "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -23,6 +24,7 @@ type EVMKeeper interface {
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool, ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
) (sdk.Coins, error) ) (sdk.Coins, error)
BaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int BaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
} }
type protoTxProvider interface { type protoTxProvider interface {

View File

@ -12,6 +12,7 @@ import (
var ( var (
_ authtypes.AccountI = (*EthAccount)(nil) _ authtypes.AccountI = (*EthAccount)(nil)
_ EthAccountI = (*EthAccount)(nil)
_ authtypes.GenesisAccount = (*EthAccount)(nil) _ authtypes.GenesisAccount = (*EthAccount)(nil)
_ codectypes.UnpackInterfacesMessage = (*EthAccount)(nil) _ codectypes.UnpackInterfacesMessage = (*EthAccount)(nil)
) )
@ -25,6 +26,19 @@ const (
AccountTypeContract AccountTypeContract
) )
// EthAccountI represents the interface of an EVM compatible account
type EthAccountI interface {
authtypes.AccountI
// EthAddress returns the ethereum Address representation of the AccAddress
EthAddress() common.Address
// CodeHash is the keccak256 hash of the contract code (if any)
GetCodeHash() common.Hash
// SetCodeHash sets the code hash to the account fields
SetCodeHash(code common.Hash) error
// Type returns the type of Ethereum Account (EOA or Contract)
Type() int8
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Main Ethermint account // Main Ethermint account
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -48,6 +62,12 @@ func (acc EthAccount) GetCodeHash() common.Hash {
return common.HexToHash(acc.CodeHash) return common.HexToHash(acc.CodeHash)
} }
// SetCodeHash sets the account code hash to the EthAccount fields
func (acc *EthAccount) SetCodeHash(codeHash common.Hash) error {
acc.CodeHash = codeHash.Hex()
return nil
}
// Type returns the type of Ethereum Account (EOA or Contract) // Type returns the type of Ethereum Account (EOA or Contract)
func (acc EthAccount) Type() int8 { func (acc EthAccount) Type() int8 {
if bytes.Equal(emptyCodeHash, common.Hex2Bytes(acc.CodeHash)) { if bytes.Equal(emptyCodeHash, common.Hex2Bytes(acc.CodeHash)) {

View File

@ -1,12 +0,0 @@
package types
// ----------------------------------------------------------------------------
// Code
// ----------------------------------------------------------------------------
// Code is account Code type alias
type Code []byte
func (c Code) String() string {
return string(c)
}

View File

@ -40,20 +40,21 @@ func InitGenesis(
panic(fmt.Errorf("account not found for address %s", account.Address)) panic(fmt.Errorf("account not found for address %s", account.Address))
} }
ethAcct, ok := acc.(*ethermint.EthAccount) ethAcct, ok := acc.(ethermint.EthAccountI)
if !ok { if !ok {
panic( panic(
fmt.Errorf("account %s must be an %T type, got %T", fmt.Errorf("account %s must be an EthAccount interface, got %T",
account.Address, &ethermint.EthAccount{}, acc, account.Address, acc,
), ),
) )
} }
code := common.Hex2Bytes(account.Code) code := common.Hex2Bytes(account.Code)
codeHash := crypto.Keccak256Hash(code) codeHash := crypto.Keccak256Hash(code)
if !bytes.Equal(common.HexToHash(ethAcct.CodeHash).Bytes(), codeHash.Bytes()) { if !bytes.Equal(ethAcct.GetCodeHash().Bytes(), codeHash.Bytes()) {
panic("code don't match codeHash") panic("code don't match codeHash")
} }
k.SetCode(ctx, codeHash.Bytes(), code) k.SetCode(ctx, codeHash.Bytes(), code)
for _, storage := range account.Storage { for _, storage := range account.Storage {
@ -68,7 +69,7 @@ func InitGenesis(
func ExportGenesis(ctx sdk.Context, k *keeper.Keeper, ak types.AccountKeeper) *types.GenesisState { func ExportGenesis(ctx sdk.Context, k *keeper.Keeper, ak types.AccountKeeper) *types.GenesisState {
var ethGenAccounts []types.GenesisAccount var ethGenAccounts []types.GenesisAccount
ak.IterateAccounts(ctx, func(account authtypes.AccountI) bool { ak.IterateAccounts(ctx, func(account authtypes.AccountI) bool {
ethAccount, ok := account.(*ethermint.EthAccount) ethAccount, ok := account.(ethermint.EthAccountI)
if !ok { if !ok {
// ignore non EthAccounts // ignore non EthAccounts
return false return false

View File

@ -48,10 +48,8 @@ func (k Keeper) Account(c context.Context, req *types.QueryAccountRequest) (*typ
addr := common.HexToAddress(req.Address) addr := common.HexToAddress(req.Address)
ctx := sdk.UnwrapSDKContext(c) ctx := sdk.UnwrapSDKContext(c)
acct, err := k.GetAccountOrEmpty(ctx, addr) acct := k.GetAccountOrEmpty(ctx, addr)
if err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
return &types.QueryAccountResponse{ return &types.QueryAccountResponse{
Balance: acct.Balance.String(), Balance: acct.Balance.String(),
CodeHash: common.BytesToHash(acct.CodeHash).Hex(), CodeHash: common.BytesToHash(acct.CodeHash).Hex(),
@ -186,10 +184,7 @@ func (k Keeper) Code(c context.Context, req *types.QueryCodeRequest) (*types.Que
ctx := sdk.UnwrapSDKContext(c) ctx := sdk.UnwrapSDKContext(c)
address := common.HexToAddress(req.Address) address := common.HexToAddress(req.Address)
acct, err := k.GetAccountWithoutBalance(ctx, address) acct := k.GetAccountWithoutBalance(ctx, address)
if err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
var code []byte var code []byte
if acct != nil && acct.IsContract() { if acct != nil && acct.IsContract() {

View File

@ -345,9 +345,7 @@ func (suite *KeeperTestSuite) TestQueryCode() {
} }
func (suite *KeeperTestSuite) TestQueryTxLogs() { func (suite *KeeperTestSuite) TestQueryTxLogs() {
var ( var expLogs []*types.Log
expLogs []*types.Log
)
txHash := common.BytesToHash([]byte("tx_hash")) txHash := common.BytesToHash([]byte("tx_hash"))
txIndex := uint(1) txIndex := uint(1)
logIndex := uint(1) logIndex := uint(1)
@ -593,7 +591,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
rsp, err := suite.queryClient.EstimateGas(sdk.WrapSDKContext(suite.ctx), &req) rsp, err := suite.queryClient.EstimateGas(sdk.WrapSDKContext(suite.ctx), &req)
if tc.expPass { if tc.expPass {
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Require().Equal(tc.expGas, rsp.Gas) suite.Require().Equal(int64(tc.expGas), int64(rsp.Gas))
} else { } else {
suite.Require().Error(err) suite.Require().Error(err)
} }

View File

@ -6,7 +6,6 @@ import (
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
@ -235,38 +234,37 @@ func (k Keeper) Tracer(ctx sdk.Context, msg core.Message, ethCfg *params.ChainCo
// GetAccountWithoutBalance load nonce and codehash without balance, // GetAccountWithoutBalance load nonce and codehash without balance,
// more efficient in cases where balance is not needed. // more efficient in cases where balance is not needed.
func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) (*statedb.Account, error) { func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) *statedb.Account {
cosmosAddr := sdk.AccAddress(addr.Bytes()) cosmosAddr := sdk.AccAddress(addr.Bytes())
acct := k.accountKeeper.GetAccount(ctx, cosmosAddr) acct := k.accountKeeper.GetAccount(ctx, cosmosAddr)
if acct == nil { if acct == nil {
return nil, nil return nil
} }
ethAcct, ok := acct.(*ethermint.EthAccount) codeHash := types.EmptyCodeHash
if !ok { ethAcct, ok := acct.(ethermint.EthAccountI)
return nil, sdkerrors.Wrapf(types.ErrInvalidAccount, "type %T, address %s", acct, addr) if ok {
codeHash = ethAcct.GetCodeHash().Bytes()
} }
return &statedb.Account{ return &statedb.Account{
Nonce: ethAcct.Sequence, Nonce: acct.GetSequence(),
CodeHash: common.FromHex(ethAcct.CodeHash), CodeHash: codeHash,
}, nil }
} }
// GetAccountOrEmpty returns empty account if not exist, returns error if it's not `EthAccount` // GetAccountOrEmpty returns empty account if not exist, returns error if it's not `EthAccount`
func (k *Keeper) GetAccountOrEmpty(ctx sdk.Context, addr common.Address) (statedb.Account, error) { func (k *Keeper) GetAccountOrEmpty(ctx sdk.Context, addr common.Address) statedb.Account {
acct, err := k.GetAccount(ctx, addr) acct := k.GetAccount(ctx, addr)
if err != nil { if acct != nil {
return statedb.Account{}, err return *acct
} }
if acct == nil {
// empty account // empty account
return statedb.Account{ return statedb.Account{
Balance: new(big.Int), Balance: new(big.Int),
CodeHash: types.EmptyCodeHash, CodeHash: types.EmptyCodeHash,
}, nil
} }
return *acct, nil
} }
// GetNonce returns the sequence number of an account, returns 0 if not exists. // GetNonce returns the sequence number of an account, returns 0 if not exists.
@ -277,12 +275,7 @@ func (k *Keeper) GetNonce(ctx sdk.Context, addr common.Address) uint64 {
return 0 return 0
} }
ethAcct, ok := acct.(*ethermint.EthAccount) return acct.GetSequence()
if !ok {
return 0
}
return ethAcct.Sequence
} }
// GetBalance load account's balance of gas token // GetBalance load account's balance of gas token

View File

@ -17,18 +17,18 @@ import (
var _ statedb.Keeper = &Keeper{} var _ statedb.Keeper = &Keeper{}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// statedb.Keeper implementation // StateDB Keeper implementation
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// GetAccount returns nil if account is not exist, returns error if it's not `EthAccount` // GetAccount returns nil if account is not exist, returns error if it's not `EthAccountI`
func (k *Keeper) GetAccount(ctx sdk.Context, addr common.Address) (*statedb.Account, error) { func (k *Keeper) GetAccount(ctx sdk.Context, addr common.Address) *statedb.Account {
acct, err := k.GetAccountWithoutBalance(ctx, addr) acct := k.GetAccountWithoutBalance(ctx, addr)
if acct == nil || err != nil { if acct == nil {
return acct, err return nil
} }
acct.Balance = k.GetBalance(ctx, addr) acct.Balance = k.GetBalance(ctx, addr)
return acct, nil return acct
} }
// GetState loads contract state from database, implements `statedb.Keeper` interface. // GetState loads contract state from database, implements `statedb.Keeper` interface.
@ -109,25 +109,33 @@ func (k *Keeper) SetAccount(ctx sdk.Context, addr common.Address, account stated
if acct == nil { if acct == nil {
acct = k.accountKeeper.NewAccountWithAddress(ctx, cosmosAddr) acct = k.accountKeeper.NewAccountWithAddress(ctx, cosmosAddr)
} }
ethAcct, ok := acct.(*ethermint.EthAccount)
if !ok { if err := acct.SetSequence(account.Nonce); err != nil {
return sdkerrors.Wrapf(types.ErrInvalidAccount, "type %T, address %s", acct, addr) return err
} }
if err := ethAcct.SetSequence(account.Nonce); err != nil {
codeHash := common.BytesToHash(account.CodeHash)
if ethAcct, ok := acct.(ethermint.EthAccountI); ok {
if err := ethAcct.SetCodeHash(codeHash); err != nil {
return err
}
}
k.accountKeeper.SetAccount(ctx, acct)
if err := k.SetBalance(ctx, addr, account.Balance); err != nil {
return err return err
} }
ethAcct.CodeHash = common.BytesToHash(account.CodeHash).Hex()
k.accountKeeper.SetAccount(ctx, ethAcct)
err := k.SetBalance(ctx, addr, account.Balance)
k.Logger(ctx).Debug( k.Logger(ctx).Debug(
"account updated", "account updated",
"ethereum-address", addr.Hex(), "ethereum-address", addr.Hex(),
"nonce", account.Nonce, "nonce", account.Nonce,
"codeHash", common.BytesToHash(account.CodeHash).Hex(), "codeHash", codeHash.Hex(),
"balance", account.Balance, "balance", account.Balance,
) )
return err return nil
} }
// SetState update contract storage, delete if value is empty. // SetState update contract storage, delete if value is empty.
@ -177,7 +185,8 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error {
return nil return nil
} }
ethAcct, ok := acct.(*ethermint.EthAccount) // NOTE: only Ethereum accounts (contracts) can be selfdestructed
ethAcct, ok := acct.(ethermint.EthAccountI)
if !ok { if !ok {
return sdkerrors.Wrapf(types.ErrInvalidAccount, "type %T, address %s", acct, addr) return sdkerrors.Wrapf(types.ErrInvalidAccount, "type %T, address %s", acct, addr)
} }
@ -188,9 +197,9 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error {
} }
// remove code // remove code
codeHash := common.HexToHash(ethAcct.CodeHash).Bytes() codeHashBz := ethAcct.GetCodeHash().Bytes()
if !bytes.Equal(codeHash, types.EmptyCodeHash) { if !bytes.Equal(codeHashBz, types.EmptyCodeHash) {
k.SetCode(ctx, codeHash, nil) k.SetCode(ctx, codeHashBz, nil)
} }
// clear storage // clear storage

View File

@ -235,9 +235,9 @@ func (suite *KeeperTestSuite) TestGetCodeHash() {
func(vm.StateDB) {}, func(vm.StateDB) {},
}, },
{ {
"account not EthAccount type, error", "account not EthAccount type, EmptyCodeHash",
addr, addr,
common.Hash{}, common.BytesToHash(types.EmptyCodeHash),
func(vm.StateDB) {}, func(vm.StateDB) {},
}, },
{ {
@ -469,27 +469,21 @@ func (suite *KeeperTestSuite) TestExist() {
func (suite *KeeperTestSuite) TestEmpty() { func (suite *KeeperTestSuite) TestEmpty() {
suite.SetupTest() suite.SetupTest()
addr := tests.GenerateAddress()
baseAcc := &authtypes.BaseAccount{Address: sdk.AccAddress(addr.Bytes()).String()}
suite.app.AccountKeeper.SetAccount(suite.ctx, baseAcc)
acct, err := suite.app.EvmKeeper.GetAccount(suite.ctx, suite.address)
suite.Require().NoError(err)
fmt.Println("default address", acct)
testCases := []struct { testCases := []struct {
name string name string
address common.Address address common.Address
malleate func(vm.StateDB) malleate func(vm.StateDB)
empty bool empty bool
expErr bool
}{ }{
{"empty, account exists", suite.address, func(vm.StateDB) {}, true, false}, {"empty, account exists", suite.address, func(vm.StateDB) {}, true},
{"error, non ethereum account", addr, func(vm.StateDB) {}, true, true}, {
{"not empty, positive balance", suite.address, func(vmdb vm.StateDB) { "not empty, positive balance",
vmdb.AddBalance(suite.address, big.NewInt(100)) suite.address,
}, false, false}, func(vmdb vm.StateDB) { vmdb.AddBalance(suite.address, big.NewInt(100)) },
{"empty, account doesn't exist", tests.GenerateAddress(), func(vm.StateDB) {}, true, false}, false,
},
{"empty, account doesn't exist", tests.GenerateAddress(), func(vm.StateDB) {}, true},
} }
for _, tc := range testCases { for _, tc := range testCases {
@ -498,11 +492,6 @@ func (suite *KeeperTestSuite) TestEmpty() {
tc.malleate(vmdb) tc.malleate(vmdb)
suite.Require().Equal(tc.empty, vmdb.Empty(tc.address)) suite.Require().Equal(tc.empty, vmdb.Empty(tc.address))
if tc.expErr {
suite.Require().Error(vmdb.Error())
} else {
suite.Require().NoError(vmdb.Error())
}
}) })
} }
} }

View File

@ -235,9 +235,8 @@ func (suite *KeeperTestSuite) TestCheckSenderBalance() {
txData, _ := evmtypes.UnpackTxData(tx.Data) txData, _ := evmtypes.UnpackTxData(tx.Data)
acct, err := suite.app.EvmKeeper.GetAccountOrEmpty(suite.ctx, suite.address) acct := suite.app.EvmKeeper.GetAccountOrEmpty(suite.ctx, suite.address)
suite.Require().NoError(err) err := evmkeeper.CheckSenderBalance(
err = evmkeeper.CheckSenderBalance(
sdk.NewIntFromBigInt(acct.Balance), sdk.NewIntFromBigInt(acct.Balance),
txData, txData,
) )

View File

@ -8,7 +8,7 @@ import (
// Keeper provide underlying storage of StateDB // Keeper provide underlying storage of StateDB
type Keeper interface { type Keeper interface {
// Read methods // Read methods
GetAccount(ctx sdk.Context, addr common.Address) (*Account, error) GetAccount(ctx sdk.Context, addr common.Address) *Account
GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash
GetCode(ctx sdk.Context, codeHash common.Hash) []byte GetCode(ctx sdk.Context, codeHash common.Hash) []byte
// the callback returns false to break early // the callback returns false to break early

View File

@ -1,7 +1,6 @@
package statedb_test package statedb_test
import ( import (
"errors"
"math/big" "math/big"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -29,15 +28,12 @@ func NewMockKeeper() *MockKeeper {
} }
} }
func (k MockKeeper) GetAccount(ctx sdk.Context, addr common.Address) (*statedb.Account, error) { func (k MockKeeper) GetAccount(ctx sdk.Context, addr common.Address) *statedb.Account {
if addr == k.errAddress {
return nil, errors.New("mock db error")
}
acct, ok := k.accounts[addr] acct, ok := k.accounts[addr]
if !ok { if !ok {
return nil, nil return nil
} }
return &acct, nil return &acct
} }
func (k MockKeeper) GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash { func (k MockKeeper) GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash {

View File

@ -31,7 +31,6 @@ var _ vm.StateDB = &StateDB{}
type StateDB struct { type StateDB struct {
keeper Keeper keeper Keeper
ctx sdk.Context ctx sdk.Context
dbErr error
// Journal of state modifications. This is the backbone of // Journal of state modifications. This is the backbone of
// Snapshot and RevertToSnapshot. // Snapshot and RevertToSnapshot.
@ -76,18 +75,6 @@ func (s *StateDB) Context() sdk.Context {
return s.ctx return s.ctx
} }
// setError remembers the first non-nil error it is called with.
func (s *StateDB) setError(err error) {
if s.dbErr == nil {
s.dbErr = err
}
}
// Error returns the database error recorded.
func (s *StateDB) Error() error {
return s.dbErr
}
// AddLog adds a log, called by evm. // AddLog adds a log, called by evm.
func (s *StateDB) AddLog(log *ethtypes.Log) { func (s *StateDB) AddLog(log *ethtypes.Log) {
s.journal.append(addLogChange{}) s.journal.append(addLogChange{})
@ -235,11 +222,7 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
return obj return obj
} }
// If no live objects are available, load it from keeper // If no live objects are available, load it from keeper
account, err := s.keeper.GetAccount(s.ctx, addr) account := s.keeper.GetAccount(s.ctx, addr)
if err != nil {
s.setError(err)
return nil
}
if account == nil { if account == nil {
return nil return nil
} }
@ -468,9 +451,6 @@ func (s *StateDB) RevertToSnapshot(revid int) {
// Commit writes the dirty states to keeper // Commit writes the dirty states to keeper
// the StateDB object should be discarded after committed. // the StateDB object should be discarded after committed.
func (s *StateDB) Commit() error { func (s *StateDB) Commit() error {
if s.dbErr != nil {
return fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr)
}
for _, addr := range s.journal.sortedDirties() { for _, addr := range s.journal.sortedDirties() {
obj := s.stateObjects[addr] obj := s.stateObjects[addr]
if obj.suicided { if obj.suicided {

View File

@ -17,7 +17,6 @@ type StateDBTestSuite struct {
} }
func (suite *StateDBTestSuite) TestAccounts() { func (suite *StateDBTestSuite) TestAccounts() {
addrErr := common.BigToAddress(big.NewInt(1))
addr2 := common.BigToAddress(big.NewInt(2)) addr2 := common.BigToAddress(big.NewInt(2))
testTxConfig := statedb.NewTxConfig( testTxConfig := statedb.NewTxConfig(
common.BigToHash(big.NewInt(10)), // tx hash common.BigToHash(big.NewInt(10)), // tx hash
@ -31,7 +30,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
test func(*statedb.StateDB) test func(*statedb.StateDB)
}{ }{
{ {
"success,empty account", "success, empty account",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
suite.Require().Equal(true, db.Empty(addr2)) suite.Require().Equal(true, db.Empty(addr2))
suite.Require().Equal(big.NewInt(0), db.GetBalance(addr2)) suite.Require().Equal(big.NewInt(0), db.GetBalance(addr2))
@ -40,21 +39,14 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,GetBalance", "success, GetBalance",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
db.AddBalance(addr2, big.NewInt(1)) db.AddBalance(addr2, big.NewInt(1))
suite.Require().Equal(big.NewInt(1), db.GetBalance(addr2)) suite.Require().Equal(big.NewInt(1), db.GetBalance(addr2))
}, },
}, },
{ {
"fail,GetBalance dbErr", "success, change balance",
func(db *statedb.StateDB) {
suite.Require().Equal(big.NewInt(0), db.GetBalance(addrErr))
suite.Require().Error(db.Commit())
},
},
{
"success,change balance",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
db.AddBalance(addr2, big.NewInt(2)) db.AddBalance(addr2, big.NewInt(2))
suite.Require().Equal(big.NewInt(2), db.GetBalance(addr2)) suite.Require().Equal(big.NewInt(2), db.GetBalance(addr2))
@ -69,7 +61,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,SetState", "success, SetState",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
key := common.BigToHash(big.NewInt(1)) key := common.BigToHash(big.NewInt(1))
value := common.BigToHash(big.NewInt(1)) value := common.BigToHash(big.NewInt(1))
@ -81,7 +73,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,SetCode", "success, SetCode",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
code := []byte("hello world") code := []byte("hello world")
codeHash := crypto.Keccak256Hash(code) codeHash := crypto.Keccak256Hash(code)
@ -98,7 +90,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,CreateAccount", "success, CreateAccount",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
// test balance carry over when overwritten // test balance carry over when overwritten
amount := big.NewInt(1) amount := big.NewInt(1)
@ -131,7 +123,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,nested snapshot revert", "success, nested snapshot revert",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
key := common.BigToHash(big.NewInt(1)) key := common.BigToHash(big.NewInt(1))
value1 := common.BigToHash(big.NewInt(1)) value1 := common.BigToHash(big.NewInt(1))
@ -152,7 +144,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,nonce", "success, nonce",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
suite.Require().Equal(uint64(0), db.GetNonce(addr2)) suite.Require().Equal(uint64(0), db.GetNonce(addr2))
db.SetNonce(addr2, 1) db.SetNonce(addr2, 1)
@ -165,7 +157,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,logs", "success, logs",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
data := []byte("hello world") data := []byte("hello world")
db.AddLog(&ethtypes.Log{ db.AddLog(&ethtypes.Log{
@ -203,7 +195,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,refund", "success, refund",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
db.AddRefund(uint64(10)) db.AddRefund(uint64(10))
suite.Require().Equal(uint64(10), db.GetRefund()) suite.Require().Equal(uint64(10), db.GetRefund())
@ -218,7 +210,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,empty", "success, empty",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
suite.Require().False(db.Exist(addr2)) suite.Require().False(db.Exist(addr2))
suite.Require().True(db.Empty(addr2)) suite.Require().True(db.Empty(addr2))
@ -233,7 +225,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,suicide commit", "success, suicide commit",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
code := []byte("hello world") code := []byte("hello world")
db.SetCode(addr2, code) db.SetCode(addr2, code)
@ -253,7 +245,7 @@ func (suite *StateDBTestSuite) TestAccounts() {
}, },
}, },
{ {
"success,suicide revert", "success, suicide revert",
func(db *statedb.StateDB) { func(db *statedb.StateDB) {
code := []byte("hello world") code := []byte("hello world")
db.SetCode(addr2, code) db.SetCode(addr2, code)