evm: balance and nonce invariants (#661)

* evm: balance and nonce invariants

* nonce invariant

* changelog

* use iterator on export
This commit is contained in:
Federico Kunze 2020-12-15 15:43:06 -03:00 committed by GitHub
parent 6001baed80
commit a1386eec09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 263 additions and 80 deletions

View File

@ -37,13 +37,19 @@ Ref: https://keepachangelog.com/en/1.0.0/
## Unreleased ## Unreleased
### API Breaking
* (evm) [\#661](https://github.com/cosmos/ethermint/pull/661) `Balance` field has been removed from the evm module's `GenesisState`.
### Improvements ### Improvements
* (evm) [\#661](https://github.com/cosmos/ethermint/pull/661) Add invariant check for account balance and account nonce.
* (deps) [\#654](https://github.com/cosmos/ethermint/pull/654) Bump go-ethereum version to [v1.9.25](https://github.com/ethereum/go-ethereum/releases/tag/v1.9.25) * (deps) [\#654](https://github.com/cosmos/ethermint/pull/654) Bump go-ethereum version to [v1.9.25](https://github.com/ethereum/go-ethereum/releases/tag/v1.9.25)
* (evm) [\#627](https://github.com/cosmos/ethermint/issues/627) Add extra EIPs parameter to apply custom EVM jump tables. * (evm) [\#627](https://github.com/cosmos/ethermint/issues/627) Add extra EIPs parameter to apply custom EVM jump tables.
### Bug Fixes ### Bug Fixes
* (evm) [\#661](https://github.com/cosmos/ethermint/pull/661) Set nonce to the EVM account on genesis initialization.
* (evm) [\#621](https://github.com/cosmos/ethermint/issues/621) EVM `GenesisAccount` fields now share the same format as the auth module `Account`. * (evm) [\#621](https://github.com/cosmos/ethermint/issues/621) EVM `GenesisAccount` fields now share the same format as the auth module `Account`.
* (evm) [\#618](https://github.com/cosmos/ethermint/issues/618) Add missing EVM `Context` `GetHash` field that retrieves a the header hash from a given block height. * (evm) [\#618](https://github.com/cosmos/ethermint/issues/618) Add missing EVM `Context` `GetHash` field that retrieves a the header hash from a given block height.
* (app) [\#617](https://github.com/cosmos/ethermint/issues/617) Fix genesis export functionality. * (app) [\#617](https://github.com/cosmos/ethermint/issues/617) Fix genesis export functionality.

View File

@ -280,7 +280,7 @@ func NewEthermintApp(
app.mm.SetOrderInitGenesis( app.mm.SetOrderInitGenesis(
auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName, auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName,
slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName, slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName,
crisis.ModuleName, genutil.ModuleName, evidence.ModuleName, evm.ModuleName, evm.ModuleName, crisis.ModuleName, genutil.ModuleName, evidence.ModuleName,
faucet.ModuleName, faucet.ModuleName,
) )

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
ethcmn "github.com/ethereum/go-ethereum/common" ethcmn "github.com/ethereum/go-ethereum/common"
@ -20,7 +21,6 @@ func InitGenesis(ctx sdk.Context, k Keeper, accountKeeper types.AccountKeeper, d
for _, account := range data.Accounts { for _, account := range data.Accounts {
address := ethcmn.HexToAddress(account.Address) address := ethcmn.HexToAddress(account.Address)
accAddress := sdk.AccAddress(address.Bytes()) accAddress := sdk.AccAddress(address.Bytes())
// check that the EVM balance the matches the account balance // check that the EVM balance the matches the account balance
acc := accountKeeper.GetAccount(ctx, accAddress) acc := accountKeeper.GetAccount(ctx, accAddress)
if acc == nil { if acc == nil {
@ -37,17 +37,11 @@ func InitGenesis(ctx sdk.Context, k Keeper, accountKeeper types.AccountKeeper, d
} }
evmBalance := acc.GetCoins().AmountOf(evmDenom) evmBalance := acc.GetCoins().AmountOf(evmDenom)
if !evmBalance.Equal(account.Balance) {
panic(
fmt.Errorf(
"balance mismatch for account %s, expected %s%s, got %s%s",
account.Address, evmBalance, evmDenom, account.Balance, evmDenom,
),
)
}
k.SetBalance(ctx, address, account.Balance.BigInt()) k.SetNonce(ctx, address, acc.GetSequence())
k.SetBalance(ctx, address, evmBalance.BigInt())
k.SetCode(ctx, address, account.Code) k.SetCode(ctx, address, account.Code)
for _, storage := range account.Storage { for _, storage := range account.Storage {
k.SetState(ctx, address, storage.Key, storage.Value) k.SetState(ctx, address, storage.Key, storage.Value)
} }
@ -83,12 +77,11 @@ func InitGenesis(ctx sdk.Context, k Keeper, accountKeeper types.AccountKeeper, d
func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisState { func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisState {
// nolint: prealloc // nolint: prealloc
var ethGenAccounts []types.GenesisAccount var ethGenAccounts []types.GenesisAccount
accounts := ak.GetAllAccounts(ctx) ak.IterateAccounts(ctx, func(account authexported.Account) bool {
for _, account := range accounts {
ethAccount, ok := account.(*ethermint.EthAccount) ethAccount, ok := account.(*ethermint.EthAccount)
if !ok { if !ok {
continue // ignore non EthAccounts
return false
} }
addr := ethAccount.EthAddress() addr := ethAccount.EthAddress()
@ -98,18 +91,15 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta
panic(err) panic(err)
} }
balanceInt := k.GetBalance(ctx, addr)
balance := sdk.NewIntFromBigInt(balanceInt)
genAccount := types.GenesisAccount{ genAccount := types.GenesisAccount{
Address: addr.String(), Address: addr.String(),
Balance: balance,
Code: k.GetCode(ctx, addr), Code: k.GetCode(ctx, addr),
Storage: storage, Storage: storage,
} }
ethGenAccounts = append(ethGenAccounts, genAccount) ethGenAccounts = append(ethGenAccounts, genAccount)
} return false
})
config, _ := k.GetChainConfig(ctx) config, _ := k.GetChainConfig(ctx)

View File

@ -54,7 +54,6 @@ func (suite *EvmTestSuite) TestInitGenesis() {
Accounts: []types.GenesisAccount{ Accounts: []types.GenesisAccount{
{ {
Address: address.String(), Address: address.String(),
Balance: sdk.OneInt(),
Storage: types.Storage{ Storage: types.Storage{
{Key: common.BytesToHash([]byte("key")), Value: common.BytesToHash([]byte("value"))}, {Key: common.BytesToHash([]byte("key")), Value: common.BytesToHash([]byte("value"))},
}, },
@ -87,25 +86,6 @@ func (suite *EvmTestSuite) TestInitGenesis() {
Accounts: []types.GenesisAccount{ Accounts: []types.GenesisAccount{
{ {
Address: address.String(), Address: address.String(),
Balance: sdk.OneInt(),
},
},
},
true,
},
{
"balance mismatch",
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes())
suite.Require().NotNil(acc)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
},
types.GenesisState{
Params: types.DefaultParams(),
Accounts: []types.GenesisAccount{
{
Address: address.String(),
Balance: sdk.OneInt(),
}, },
}, },
}, },

100
x/evm/keeper/invariants.go Normal file
View File

@ -0,0 +1,100 @@
package keeper
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
)
const (
balanceInvariant = "balance"
nonceInvariant = "nonce"
)
// RegisterInvariants registers the evm module invariants
func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
ir.RegisterRoute(types.ModuleName, balanceInvariant, k.BalanceInvariant())
ir.RegisterRoute(types.ModuleName, nonceInvariant, k.NonceInvariant())
}
// BalanceInvariant checks that all auth module's EthAccounts in the application have the same balance
// as the EVM one.
func (k Keeper) BalanceInvariant() sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var (
msg string
count int
)
k.accountKeeper.IterateAccounts(ctx, func(account authexported.Account) bool {
ethAccount, ok := account.(*ethermint.EthAccount)
if !ok {
// ignore non EthAccounts
return false
}
evmDenom := k.GetParams(ctx).EvmDenom
accountBalance := ethAccount.GetCoins().AmountOf(evmDenom)
evmBalance := k.GetBalance(ctx, ethAccount.EthAddress())
if evmBalance.Cmp(accountBalance.BigInt()) != 0 {
count++
msg += fmt.Sprintf(
"\tbalance mismatch for address %s: account balance %s, evm balance %s\n",
account.GetAddress(), accountBalance.String(), evmBalance.String(),
)
}
return false
})
broken := count != 0
return sdk.FormatInvariant(
types.ModuleName, balanceInvariant,
fmt.Sprintf("account balances mismatches found %d\n%s", count, msg),
), broken
}
}
// NonceInvariant checks that all auth module's EthAccounts in the application have the same nonce
// sequence as the EVM.
func (k Keeper) NonceInvariant() sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var (
msg string
count int
)
k.accountKeeper.IterateAccounts(ctx, func(account authexported.Account) bool {
ethAccount, ok := account.(*ethermint.EthAccount)
if !ok {
// ignore non EthAccounts
return false
}
evmNonce := k.GetNonce(ctx, ethAccount.EthAddress())
if evmNonce != ethAccount.Sequence {
count++
msg += fmt.Sprintf(
"\nonce mismatch for address %s: account nonce %d, evm nonce %d\n",
account.GetAddress(), ethAccount.Sequence, evmNonce,
)
}
return false
})
broken := count != 0
return sdk.FormatInvariant(
types.ModuleName, nonceInvariant,
fmt.Sprintf("account nonces mismatches found %d\n%s", count, msg),
), broken
}
}

View File

@ -0,0 +1,139 @@
package keeper_test
import (
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
ethermint "github.com/cosmos/ethermint/types"
ethcmn "github.com/ethereum/go-ethereum/common"
)
func (suite *KeeperTestSuite) TestBalanceInvariant() {
privkey, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
address := ethcmn.HexToAddress(privkey.PubKey().Address().String())
testCases := []struct {
name string
malleate func()
expBroken bool
}{
{
"balance mismatch",
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes())
suite.Require().NotNil(acc)
err := acc.SetCoins(sdk.NewCoins(ethermint.NewPhotonCoinInt64(1)))
suite.Require().NoError(err)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
suite.app.EvmKeeper.SetBalance(suite.ctx, address, big.NewInt(1000))
},
true,
},
{
"balance ok",
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes())
suite.Require().NotNil(acc)
err := acc.SetCoins(sdk.NewCoins(ethermint.NewPhotonCoinInt64(1)))
suite.Require().NoError(err)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
suite.app.EvmKeeper.SetBalance(suite.ctx, address, big.NewInt(1))
},
false,
},
{
"invalid account type",
func() {
acc := authtypes.NewBaseAccountWithAddress(address.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, &acc)
},
false,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset values
tc.malleate()
_, broken := suite.app.EvmKeeper.BalanceInvariant()(suite.ctx)
if tc.expBroken {
suite.Require().True(broken)
} else {
suite.Require().False(broken)
}
})
}
}
func (suite *KeeperTestSuite) TestNonceInvariant() {
privkey, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
address := ethcmn.HexToAddress(privkey.PubKey().Address().String())
testCases := []struct {
name string
malleate func()
expBroken bool
}{
{
"nonce mismatch",
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes())
suite.Require().NotNil(acc)
err := acc.SetSequence(1)
suite.Require().NoError(err)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
suite.app.EvmKeeper.SetNonce(suite.ctx, address, 100)
},
true,
},
{
"nonce ok",
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes())
suite.Require().NotNil(acc)
err := acc.SetSequence(1)
suite.Require().NoError(err)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
suite.app.EvmKeeper.SetNonce(suite.ctx, address, 1)
},
false,
},
{
"invalid account type",
func() {
acc := authtypes.NewBaseAccountWithAddress(address.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, &acc)
},
false,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset values
tc.malleate()
_, broken := suite.app.EvmKeeper.NonceInvariant()(suite.ctx)
if tc.expBroken {
suite.Require().True(broken)
} else {
suite.Require().False(broken)
}
})
}
}

View File

@ -30,6 +30,8 @@ type Keeper struct {
// - storing block height -> bloom filter map. Needed for the Web3 API. // - storing block height -> bloom filter map. Needed for the Web3 API.
// - storing block hash -> block height map. Needed for the Web3 API. // - storing block hash -> block height map. Needed for the Web3 API.
storeKey sdk.StoreKey storeKey sdk.StoreKey
// Account Keeper for fetching accounts
accountKeeper types.AccountKeeper
// Ethermint concrete implementation on the EVM StateDB interface // Ethermint concrete implementation on the EVM StateDB interface
CommitStateDB *types.CommitStateDB CommitStateDB *types.CommitStateDB
// Transaction counter in a block. Used on StateSB's Prepare function. // Transaction counter in a block. Used on StateSB's Prepare function.
@ -52,6 +54,7 @@ func NewKeeper(
return Keeper{ return Keeper{
cdc: cdc, cdc: cdc,
storeKey: storeKey, storeKey: storeKey,
accountKeeper: ak,
CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, paramSpace, ak), CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, paramSpace, ak),
TxCount: 0, TxCount: 0,
Bloom: big.NewInt(0), Bloom: big.NewInt(0),

View File

@ -197,12 +197,8 @@ func queryExportAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte,
return nil, err return nil, err
} }
balanceInt := keeper.GetBalance(ctx, addr)
balance := sdk.NewIntFromBigInt(balanceInt)
res := types.GenesisAccount{ res := types.GenesisAccount{
Address: hexAddress, Address: hexAddress,
Balance: balance,
Code: keeper.GetCode(ctx, addr), Code: keeper.GetCode(ctx, addr),
Storage: storage, Storage: storage,
} }

View File

@ -88,7 +88,9 @@ func (AppModule) Name() string {
} }
// RegisterInvariants interface for registering invariants // RegisterInvariants interface for registering invariants
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
keeper.RegisterInvariants(ir, am.keeper)
}
// Route specifies path for transactions // Route specifies path for transactions
func (am AppModule) Route() string { func (am AppModule) Route() string {

View File

@ -9,6 +9,7 @@ import (
type AccountKeeper interface { type AccountKeeper interface {
NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authexported.Account NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authexported.Account
GetAllAccounts(ctx sdk.Context) (accounts []authexported.Account) GetAllAccounts(ctx sdk.Context) (accounts []authexported.Account)
IterateAccounts(ctx sdk.Context, cb func(account authexported.Account) bool)
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account
SetAccount(ctx sdk.Context, account authexported.Account) SetAccount(ctx sdk.Context, account authexported.Account)
RemoveAccount(ctx sdk.Context, account authexported.Account) RemoveAccount(ctx sdk.Context, account authexported.Account)

View File

@ -4,8 +4,6 @@ import (
"errors" "errors"
"fmt" "fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
ethcmn "github.com/ethereum/go-ethereum/common" ethcmn "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
) )
@ -22,9 +20,9 @@ type (
// GenesisAccount defines an account to be initialized in the genesis state. // 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 // 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. // storage type and that it doesn't contain the private key field.
// NOTE: balance is omitted as it is imported from the auth account balance.
GenesisAccount struct { GenesisAccount struct {
Address string `json:"address"` Address string `json:"address"`
Balance sdk.Int `json:"balance"`
Code hexutil.Bytes `json:"code,omitempty"` Code hexutil.Bytes `json:"code,omitempty"`
Storage Storage `json:"storage,omitempty"` Storage Storage `json:"storage,omitempty"`
} }
@ -35,12 +33,6 @@ func (ga GenesisAccount) Validate() error {
if ga.Address == (ethcmn.Address{}.String()) { if ga.Address == (ethcmn.Address{}.String()) {
return fmt.Errorf("address cannot be the zero address %s", ga.Address) return fmt.Errorf("address cannot be the zero address %s", ga.Address)
} }
if ga.Balance.IsNil() {
return errors.New("balance cannot be nil")
}
if ga.Balance.IsNegative() {
return errors.New("balance cannot be negative")
}
if ga.Code != nil && len(ga.Code) == 0 { if ga.Code != nil && len(ga.Code) == 0 {
return errors.New("code bytes cannot be empty") return errors.New("code bytes cannot be empty")
} }

View File

@ -9,8 +9,6 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types" ethtypes "github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto" ethcrypto "github.com/ethereum/go-ethereum/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/ethermint/crypto/ethsecp256k1" "github.com/cosmos/ethermint/crypto/ethsecp256k1"
) )
@ -26,7 +24,6 @@ func TestValidateGenesisAccount(t *testing.T) {
"valid genesis account", "valid genesis account",
GenesisAccount{ GenesisAccount{
Address: address.String(), Address: address.String(),
Balance: sdk.NewInt(1),
Code: []byte{1, 2, 3}, Code: []byte{1, 2, 3},
Storage: Storage{ Storage: Storage{
NewState(ethcmn.BytesToHash([]byte{1, 2, 3}), ethcmn.BytesToHash([]byte{1, 2, 3})), NewState(ethcmn.BytesToHash([]byte{1, 2, 3}), ethcmn.BytesToHash([]byte{1, 2, 3})),
@ -38,23 +35,6 @@ func TestValidateGenesisAccount(t *testing.T) {
"empty account address bytes", "empty account address bytes",
GenesisAccount{ GenesisAccount{
Address: ethcmn.Address{}.String(), Address: ethcmn.Address{}.String(),
Balance: sdk.NewInt(1),
},
false,
},
{
"nil account balance",
GenesisAccount{
Address: address.String(),
Balance: sdk.Int{},
},
false,
},
{
"nil account balance",
GenesisAccount{
Address: address.String(),
Balance: sdk.NewInt(-1),
}, },
false, false,
}, },
@ -62,7 +42,6 @@ func TestValidateGenesisAccount(t *testing.T) {
"empty code bytes", "empty code bytes",
GenesisAccount{ GenesisAccount{
Address: address.String(), Address: address.String(),
Balance: sdk.NewInt(1),
Code: []byte{}, Code: []byte{},
}, },
false, false,
@ -101,7 +80,6 @@ func TestValidateGenesis(t *testing.T) {
Accounts: []GenesisAccount{ Accounts: []GenesisAccount{
{ {
Address: address.String(), Address: address.String(),
Balance: sdk.NewInt(1),
Code: []byte{1, 2, 3}, Code: []byte{1, 2, 3},
Storage: Storage{ Storage: Storage{
{Key: ethcmn.BytesToHash([]byte{1, 2, 3})}, {Key: ethcmn.BytesToHash([]byte{1, 2, 3})},
@ -153,7 +131,6 @@ func TestValidateGenesis(t *testing.T) {
Accounts: []GenesisAccount{ Accounts: []GenesisAccount{
{ {
Address: address.String(), Address: address.String(),
Balance: sdk.NewInt(1),
Code: []byte{1, 2, 3}, Code: []byte{1, 2, 3},
Storage: Storage{ Storage: Storage{
NewState(ethcmn.BytesToHash([]byte{1, 2, 3}), ethcmn.BytesToHash([]byte{1, 2, 3})), NewState(ethcmn.BytesToHash([]byte{1, 2, 3}), ethcmn.BytesToHash([]byte{1, 2, 3})),
@ -161,7 +138,6 @@ func TestValidateGenesis(t *testing.T) {
}, },
{ {
Address: address.String(), Address: address.String(),
Balance: sdk.NewInt(1),
Code: []byte{1, 2, 3}, Code: []byte{1, 2, 3},
Storage: Storage{ Storage: Storage{
NewState(ethcmn.BytesToHash([]byte{1, 2, 3}), ethcmn.BytesToHash([]byte{1, 2, 3})), NewState(ethcmn.BytesToHash([]byte{1, 2, 3}), ethcmn.BytesToHash([]byte{1, 2, 3})),
@ -177,7 +153,6 @@ func TestValidateGenesis(t *testing.T) {
Accounts: []GenesisAccount{ Accounts: []GenesisAccount{
{ {
Address: address.String(), Address: address.String(),
Balance: sdk.NewInt(1),
Code: []byte{1, 2, 3}, Code: []byte{1, 2, 3},
Storage: Storage{ Storage: Storage{
{Key: ethcmn.BytesToHash([]byte{1, 2, 3})}, {Key: ethcmn.BytesToHash([]byte{1, 2, 3})},
@ -227,7 +202,6 @@ func TestValidateGenesis(t *testing.T) {
Accounts: []GenesisAccount{ Accounts: []GenesisAccount{
{ {
Address: address.String(), Address: address.String(),
Balance: sdk.NewInt(1),
Code: []byte{1, 2, 3}, Code: []byte{1, 2, 3},
Storage: Storage{ Storage: Storage{
{Key: ethcmn.BytesToHash([]byte{1, 2, 3})}, {Key: ethcmn.BytesToHash([]byte{1, 2, 3})},