Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix export segfault #2128

Merged
merged 1 commit into from
Aug 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
26 changes: 26 additions & 0 deletions server/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 {
Expand All @@ -43,3 +60,12 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
},
}
}

func isEmptyState(home string) (bool, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ValarDragon is this sanity check enough or is there a more direct method we can perform via some attempted state lookup?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine to me since we ensure all file writes persist to disk. I think we can merge this, and then write an issue to query state directly later. (#postlaunch concern)

files, err := ioutil.ReadDir(path.Join(home, "data"))
if err != nil {
return false, err
}

return len(files) == 0, nil
}
53 changes: 53 additions & 0 deletions server/export_test.go
Original file line number Diff line number Diff line change
@@ -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")
}
8 changes: 7 additions & 1 deletion server/mock/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down