forked from cerc-io/laconicd-deprecated
evm: add missing genesis fields and export genesis state logic (#255)
* evm: export genesis state * x/evm: split keeper.go * x/evm: retrieve storage from address * changelog * fixes * add check for nil logs * update validation func * fixes * fix non-determinism * stop storage iteration * remove error return value * update changelog * fix test * lint
This commit is contained in:
@@ -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)
|
||||
|
||||
+36
-16
@@ -1,13 +1,15 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/cosmos/ethermint/types"
|
||||
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.
|
||||
@@ -15,31 +17,49 @@ 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"`
|
||||
}
|
||||
)
|
||||
|
||||
// ValidateGenesis validates evm genesis config
|
||||
func ValidateGenesis(data GenesisState) error {
|
||||
for _, acct := range data.Accounts {
|
||||
if len(acct.Address.Bytes()) == 0 {
|
||||
return errors.New("invalid GenesisAccount: address cannot be empty")
|
||||
}
|
||||
if acct.Balance == nil {
|
||||
return errors.New("invalid GenesisAccount: balance cannot be empty")
|
||||
}
|
||||
// NewGenesisStorage creates a new GenesisStorage instance
|
||||
func NewGenesisStorage(key, value ethcmn.Hash) GenesisStorage {
|
||||
return GenesisStorage{
|
||||
Key: key,
|
||||
Value: value,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultGenesisState sets default evm genesis config
|
||||
// DefaultGenesisState sets default evm genesis state with empty accounts.
|
||||
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 acc.Balance == nil {
|
||||
return errors.New("invalid GenesisAccount: balance cannot be empty")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+29
-15
@@ -1,45 +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 {
|
||||
msg string
|
||||
genstate GenesisState
|
||||
name string
|
||||
genState GenesisState
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
msg: "pass with defaultState ",
|
||||
genstate: DefaultGenesisState(),
|
||||
name: "default",
|
||||
genState: DefaultGenesisState(),
|
||||
expPass: true,
|
||||
},
|
||||
{
|
||||
msg: "empty address",
|
||||
genstate: GenesisState{
|
||||
Accounts: []GenesisAccount{{}},
|
||||
name: "empty account address bytes",
|
||||
genState: GenesisState{
|
||||
Accounts: []GenesisAccount{
|
||||
{
|
||||
Address: ethcmn.Address{},
|
||||
Balance: big.NewInt(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
msg: "empty balance",
|
||||
genstate: GenesisState{
|
||||
Accounts: []GenesisAccount{{Balance: nil}},
|
||||
name: "nil account balance",
|
||||
genState: GenesisState{
|
||||
Accounts: []GenesisAccount{
|
||||
{
|
||||
Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}),
|
||||
Balance: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
|
||||
err := ValidateGenesis(tc.genstate)
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
err := tc.genState.Validate()
|
||||
if tc.expPass {
|
||||
require.NoError(t, err, "test (%d) %s", i, tc.msg)
|
||||
require.NoError(t, err, tc.name)
|
||||
} else {
|
||||
require.Error(t, err, "test (%d): %s", i, tc.msg)
|
||||
require.Error(t, err, tc.name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user