app: fix export genesis (#619)

* v0.3.1 changes

* fix export genesis

* changelog

* evm: fix genesis format mismatch (#623)

* evm: fix genesis format mismatch

* genesis tests

* fix test

* changelog

* nolint
This commit is contained in:
Federico Kunze 2020-11-27 19:42:04 +01:00 committed by GitHub
parent 34a6011627
commit 048a8bdc12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 222 additions and 136 deletions

View File

@ -37,6 +37,13 @@ Ref: https://keepachangelog.com/en/1.0.0/
## Unreleased ## Unreleased
### Bug Fixes
* (evm) [\#621](https://github.com/cosmos/ethermint/issues/621) EVM `GenesisAccount` fields now share the same format as the auth module `Account`.
* (app) [\#617](https://github.com/cosmos/ethermint/issues/617) Fix genesis export functionality.
## [v0.3.1] - 2020-11-24
### Improvements ### Improvements
* (deps) [\#615](https://github.com/cosmos/ethermint/pull/615) Bump Cosmos SDK version to [v0.39.2](https://github.com/cosmos/cosmos-sdk/tag/v0.39.2) * (deps) [\#615](https://github.com/cosmos/ethermint/pull/615) Bump Cosmos SDK version to [v0.39.2](https://github.com/cosmos/cosmos-sdk/tag/v0.39.2)

View File

@ -111,14 +111,16 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application
func exportAppStateAndTMValidators( func exportAppStateAndTMValidators(
logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string, logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string,
) (json.RawMessage, []tmtypes.GenesisValidator, error) { ) (json.RawMessage, []tmtypes.GenesisValidator, error) {
var ethermintApp *app.EthermintApp
ethermintApp := app.NewEthermintApp(logger, db, traceStore, true, map[int64]bool{}, 0)
if height != -1 { if height != -1 {
err := ethermintApp.LoadHeight(height) ethermintApp = app.NewEthermintApp(logger, db, traceStore, false, map[int64]bool{}, 0)
if err != nil {
if err := ethermintApp.LoadHeight(height); err != nil {
return nil, nil, err return nil, nil, err
} }
} else {
ethermintApp = app.NewEthermintApp(logger, db, traceStore, true, map[int64]bool{}, 0)
} }
return ethermintApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) return ethermintApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)

View File

@ -1,29 +1,61 @@
package evm package evm
import ( import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
emint "github.com/cosmos/ethermint/types" ethcmn "github.com/ethereum/go-ethereum/common"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types" "github.com/cosmos/ethermint/x/evm/types"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
) )
// InitGenesis initializes genesis state based on exported genesis // InitGenesis initializes genesis state based on exported genesis
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorUpdate { func InitGenesis(ctx sdk.Context, k Keeper, accountKeeper types.AccountKeeper, data GenesisState) []abci.ValidatorUpdate { // nolint: interfacer
evmDenom := data.Params.EvmDenom
for _, account := range data.Accounts { for _, account := range data.Accounts {
// FIXME: this will override bank InitGenesis balance! address := ethcmn.HexToAddress(account.Address)
k.SetBalance(ctx, account.Address, account.Balance) accAddress := sdk.AccAddress(address.Bytes())
k.SetCode(ctx, account.Address, account.Code)
// check that the EVM balance the matches the account balance
acc := accountKeeper.GetAccount(ctx, accAddress)
if acc == nil {
panic(fmt.Errorf("account not found for address %s", account.Address))
}
_, ok := acc.(*ethermint.EthAccount)
if !ok {
panic(
fmt.Errorf("account %s must be an %T type, got %T",
account.Address, &ethermint.EthAccount{}, acc,
),
)
}
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.SetCode(ctx, address, account.Code)
for _, storage := range account.Storage { for _, storage := range account.Storage {
k.SetState(ctx, account.Address, storage.Key, storage.Value) k.SetState(ctx, address, storage.Key, storage.Value)
} }
} }
var err error var err error
for _, txLog := range data.TxsLogs { for _, txLog := range data.TxsLogs {
err = k.SetLogs(ctx, txLog.Hash, txLog.Logs) if err = k.SetLogs(ctx, txLog.Hash, txLog.Logs); err != nil {
if err != nil {
panic(err) panic(err)
} }
} }
@ -54,8 +86,7 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta
accounts := ak.GetAllAccounts(ctx) accounts := ak.GetAllAccounts(ctx)
for _, account := range accounts { for _, account := range accounts {
ethAccount, ok := account.(*ethermint.EthAccount)
ethAccount, ok := account.(*emint.EthAccount)
if !ok { if !ok {
continue continue
} }
@ -67,9 +98,12 @@ 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, Address: addr.String(),
Balance: k.GetBalance(ctx, addr), Balance: balance,
Code: k.GetCode(ctx, addr), Code: k.GetCode(ctx, addr),
Storage: storage, Storage: storage,
} }

File diff suppressed because one or more lines are too long

View File

@ -200,7 +200,8 @@ func queryAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error)
} }
func queryExportAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { func queryExportAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) {
addr := ethcmn.HexToAddress(path[1]) hexAddress := path[1]
addr := ethcmn.HexToAddress(hexAddress)
var storage types.Storage var storage types.Storage
err := keeper.ForEachStorage(ctx, addr, func(key, value ethcmn.Hash) bool { err := keeper.ForEachStorage(ctx, addr, func(key, value ethcmn.Hash) bool {
@ -211,9 +212,12 @@ 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: addr, Address: hexAddress,
Balance: keeper.GetBalance(ctx, addr), Balance: balance,
Code: keeper.GetCode(ctx, addr), Code: keeper.GetCode(ctx, addr),
Storage: storage, Storage: storage,
} }

View File

@ -124,7 +124,7 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState types.GenesisState var genesisState types.GenesisState
types.ModuleCdc.MustUnmarshalJSON(data, &genesisState) types.ModuleCdc.MustUnmarshalJSON(data, &genesisState)
return InitGenesis(ctx, am.keeper, genesisState) return InitGenesis(ctx, am.keeper, am.ak, genesisState)
} }
// ExportGenesis exports the genesis state to be used by daemon // ExportGenesis exports the genesis state to be used by daemon

View File

@ -1,38 +0,0 @@
package evm_test
import (
"encoding/json"
"github.com/cosmos/ethermint/x/evm"
"github.com/ethereum/go-ethereum/common"
)
var testJSON = `{
"accounts": [
{
"address": "0x00cabdd44664b73cfc3194b9d32eb6c351ef7652",
"balance": 34
},
{
"address": "0x2cc7fdf9fde6746731d7f11979609d455c2c197a",
"balance": 0,
"code": "0x60806040"
}
],
"params": {
"evm_denom": "aphoton"
}
}`
func (suite *EvmTestSuite) TestInitGenesis() {
am := evm.NewAppModule(suite.app.EvmKeeper, suite.app.AccountKeeper)
in := json.RawMessage([]byte(testJSON))
_ = am.InitGenesis(suite.ctx, in)
testAddr := common.HexToAddress("0x2cc7fdf9fde6746731d7f11979609d455c2c197a")
res := suite.app.EvmKeeper.CommitStateDB.WithContext(suite.ctx).GetCode(testAddr)
expectedCode := common.FromHex("0x60806040")
suite.Require().Equal(expectedCode, res)
}

View File

@ -1,10 +1,10 @@
package types package types
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"math/big"
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"
@ -23,22 +23,22 @@ type (
// 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.
GenesisAccount struct { GenesisAccount struct {
Address ethcmn.Address `json:"address"` Address string `json:"address"`
Balance *big.Int `json:"balance"` 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"`
} }
) )
// Validate performs a basic validation of a GenesisAccount fields. // Validate performs a basic validation of a GenesisAccount fields.
func (ga GenesisAccount) Validate() error { func (ga GenesisAccount) Validate() error {
if bytes.Equal(ga.Address.Bytes(), ethcmn.Address{}.Bytes()) { if ga.Address == (ethcmn.Address{}.String()) {
return fmt.Errorf("address cannot be the zero address %s", ga.Address.String()) return fmt.Errorf("address cannot be the zero address %s", ga.Address)
} }
if ga.Balance == nil { if ga.Balance.IsNil() {
return errors.New("balance cannot be nil") return errors.New("balance cannot be nil")
} }
if ga.Balance.Sign() == -1 { if ga.Balance.IsNegative() {
return errors.New("balance cannot be negative") return errors.New("balance cannot be negative")
} }
if ga.Code != nil && len(ga.Code) == 0 { if ga.Code != nil && len(ga.Code) == 0 {
@ -65,14 +65,15 @@ func (gs GenesisState) Validate() error {
seenAccounts := make(map[string]bool) seenAccounts := make(map[string]bool)
seenTxs := make(map[string]bool) seenTxs := make(map[string]bool)
for _, acc := range gs.Accounts { for _, acc := range gs.Accounts {
if seenAccounts[acc.Address.String()] { if seenAccounts[acc.Address] {
return fmt.Errorf("duplicated genesis account %s", acc.Address.String()) return fmt.Errorf("duplicated genesis account %s", acc.Address)
} }
if err := acc.Validate(); err != nil { if err := acc.Validate(); err != nil {
return fmt.Errorf("invalid genesis account %s: %w", acc.Address.String(), err) return fmt.Errorf("invalid genesis account %s: %w", acc.Address, err)
} }
seenAccounts[acc.Address.String()] = true seenAccounts[acc.Address] = true
} }
for _, tx := range gs.TxsLogs { for _, tx := range gs.TxsLogs {
if seenTxs[tx.Hash.String()] { if seenTxs[tx.Hash.String()] {
return fmt.Errorf("duplicated logs from transaction %s", tx.Hash.String()) return fmt.Errorf("duplicated logs from transaction %s", tx.Hash.String())

View File

@ -1,7 +1,6 @@
package types package types
import ( import (
"math/big"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -10,9 +9,13 @@ 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"
) )
var address = ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5})
func TestValidateGenesisAccount(t *testing.T) { func TestValidateGenesisAccount(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
@ -22,8 +25,8 @@ func TestValidateGenesisAccount(t *testing.T) {
{ {
"valid genesis account", "valid genesis account",
GenesisAccount{ GenesisAccount{
Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}), Address: address.String(),
Balance: big.NewInt(1), 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})),
@ -34,32 +37,32 @@ func TestValidateGenesisAccount(t *testing.T) {
{ {
"empty account address bytes", "empty account address bytes",
GenesisAccount{ GenesisAccount{
Address: ethcmn.Address{}, Address: ethcmn.Address{}.String(),
Balance: big.NewInt(1), Balance: sdk.NewInt(1),
}, },
false, false,
}, },
{ {
"nil account balance", "nil account balance",
GenesisAccount{ GenesisAccount{
Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}), Address: address.String(),
Balance: nil, Balance: sdk.Int{},
}, },
false, false,
}, },
{ {
"nil account balance", "nil account balance",
GenesisAccount{ GenesisAccount{
Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}), Address: address.String(),
Balance: big.NewInt(-1), Balance: sdk.NewInt(-1),
}, },
false, false,
}, },
{ {
"empty code bytes", "empty code bytes",
GenesisAccount{ GenesisAccount{
Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}), Address: address.String(),
Balance: big.NewInt(1), Balance: sdk.NewInt(1),
Code: []byte{}, Code: []byte{},
}, },
false, false,
@ -97,8 +100,8 @@ func TestValidateGenesis(t *testing.T) {
genState: GenesisState{ genState: GenesisState{
Accounts: []GenesisAccount{ Accounts: []GenesisAccount{
{ {
Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}), Address: address.String(),
Balance: big.NewInt(1), 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})},
@ -138,7 +141,7 @@ func TestValidateGenesis(t *testing.T) {
genState: GenesisState{ genState: GenesisState{
Accounts: []GenesisAccount{ Accounts: []GenesisAccount{
{ {
Address: ethcmn.Address{}, Address: ethcmn.Address{}.String(),
}, },
}, },
}, },
@ -149,16 +152,16 @@ func TestValidateGenesis(t *testing.T) {
genState: GenesisState{ genState: GenesisState{
Accounts: []GenesisAccount{ Accounts: []GenesisAccount{
{ {
Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}), Address: address.String(),
Balance: big.NewInt(1), 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})),
}, },
}, },
{ {
Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}), Address: address.String(),
Balance: big.NewInt(1), 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})),
@ -173,8 +176,8 @@ func TestValidateGenesis(t *testing.T) {
genState: GenesisState{ genState: GenesisState{
Accounts: []GenesisAccount{ Accounts: []GenesisAccount{
{ {
Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}), Address: address.String(),
Balance: big.NewInt(1), 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})},
@ -223,8 +226,8 @@ func TestValidateGenesis(t *testing.T) {
genState: GenesisState{ genState: GenesisState{
Accounts: []GenesisAccount{ Accounts: []GenesisAccount{
{ {
Address: ethcmn.BytesToAddress([]byte{1, 2, 3, 4, 5}), Address: address.String(),
Balance: big.NewInt(1), 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})},