From 2146450aaa101b9500970969116a02d4fd1f1d0e Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Thu, 23 Aug 2018 02:34:59 -0700 Subject: [PATCH] Fix export segfault Closes #1834 --- PENDING.md | 1 + server/export.go | 26 +++++++++++++++++++++ server/export_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++ server/mock/app.go | 8 ++++++- 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 server/export_test.go diff --git a/PENDING.md b/PENDING.md index 01bdc2158..46e861013 100644 --- a/PENDING.md +++ b/PENDING.md @@ -51,6 +51,7 @@ IMPROVEMENTS * Gaia CLI (`gaiacli`) * [cli] #2060 removed `--select` from `block` command + * [cli] #2128 fixed segfault when exporting directly after `gaiad init` * Gaia * [x/stake] [#2023](https://github.com/cosmos/cosmos-sdk/pull/2023) Terminate iteration loop in `UpdateBondedValidators` and `UpdateBondedValidatorsFull` when the first revoked validator is encountered and perform a sanity check. diff --git a/server/export.go b/server/export.go index fa1c1907a..1d0f760ce 100644 --- a/server/export.go +++ b/server/export.go @@ -9,6 +9,8 @@ import ( "github.com/cosmos/cosmos-sdk/wire" tmtypes "github.com/tendermint/tendermint/types" + "io/ioutil" + "path" ) // ExportCmd dumps app state to JSON. @@ -19,6 +21,21 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co RunE: func(cmd *cobra.Command, args []string) error { home := viper.GetString("home") traceStore := viper.GetString(flagTraceStore) + emptyState, err := isEmptyState(home) + if err != nil { + return err + } + + if emptyState { + fmt.Println("WARNING: State is not initialized. Returning genesis file.") + genesisFile := path.Join(home, "config", "genesis.json") + genesis, err := ioutil.ReadFile(genesisFile) + if err != nil { + return err + } + fmt.Println(string(genesis)) + return nil + } appState, validators, err := appExporter(home, ctx.Logger, traceStore) if err != nil { @@ -43,3 +60,12 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co }, } } + +func isEmptyState(home string) (bool, error) { + files, err := ioutil.ReadDir(path.Join(home, "data")) + if err != nil { + return false, err + } + + return len(files) == 0, nil +} diff --git a/server/export_test.go b/server/export_test.go new file mode 100644 index 000000000..358f72cf6 --- /dev/null +++ b/server/export_test.go @@ -0,0 +1,53 @@ +package server + +import ( + "testing" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/tendermint/tendermint/libs/log" + tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" + "os" + "bytes" + "io" + "github.com/cosmos/cosmos-sdk/server/mock" + ) + +func TestEmptyState(t *testing.T) { + defer setupViper(t)() + logger := log.NewNopLogger() + cfg, err := tcmd.ParseConfig() + require.Nil(t, err) + ctx := NewContext(cfg, logger) + cdc := wire.NewCodec() + appInit := AppInit{ + AppGenTx: mock.AppGenTx, + AppGenState: mock.AppGenStateEmpty, + } + cmd := InitCmd(ctx, cdc, appInit) + err = cmd.RunE(nil, nil) + require.NoError(t, err) + + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + cmd = ExportCmd(ctx, cdc, nil) + err = cmd.RunE(nil, nil) + require.NoError(t, err) + + outC := make(chan string) + go func() { + var buf bytes.Buffer + io.Copy(&buf, r) + outC <- buf.String() + }() + + w.Close() + os.Stdout = old + out := <-outC + require.Contains(t, out, "WARNING: State is not initialized") + require.Contains(t, out, "genesis_time") + require.Contains(t, out, "chain_id") + require.Contains(t, out, "consensus_params") + require.Contains(t, out, "validators") + require.Contains(t, out, "app_hash") +} diff --git a/server/mock/app.go b/server/mock/app.go index 7b22328b0..eb2dfc3cc 100644 --- a/server/mock/app.go +++ b/server/mock/app.go @@ -121,9 +121,15 @@ func AppGenState(_ *wire.Codec, _ []json.RawMessage) (appState json.RawMessage, return } +// AppGenStateEmpty returns an empty transaction state for mocking. +func AppGenStateEmpty(_ *wire.Codec, _ []json.RawMessage) (appState json.RawMessage, err error) { + appState = json.RawMessage(``) + return +} + // Return a validator, not much else func AppGenTx(_ *wire.Codec, pk crypto.PubKey, genTxConfig gc.GenTx) ( - appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { validator = tmtypes.GenesisValidator{ PubKey: pk,