Add height in exported genesis (#7089)
* Add height in exported genesis * +1 * Add test * Refactor ctx in setupApp * Use amino in export * Use tmjson * Add custom initialVersion (set to 0 for now) * Add comment * Add mount in initChainer * app.LastBlockheight * InitializeAndSeal in InitChain? * Revert create store with initial version * Update to latest iavl * Check height in test * Make it work * Add more tests * Rename interface * Use struct isntead of 6 args * Fix lint * Remove stray fmt * Revert go mod/sum * Install iavl rc3 * Update comments * Add fee in network * Typo * Fix logic in commit * Fix tests * Only set initial version on > 1 * Genesis block num = 1 * Fresh chain, genesis block = 0 * Add comments * Revert Mutable/ImmutableTree * Allow for zero height * Fix restart * Add comments * Add comments, fix test * Fix remaining one test * Add panic test * Update comment * Add test for --height * No cast * Add check that genesis file exists * Remove duplicate imports * Fail early Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Jack Zampolin <jack.zampolin@gmail.com> Co-authored-by: Cory <cjlevinson@gmail.com>
This commit is contained in:
co-authored by
Alexander Bezobchuk
Jack Zampolin
Cory
parent
9e85e81e0e
commit
3b9b58c931
+20
-15
@@ -3,12 +3,12 @@ package server
|
||||
// DONTCOVER
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
tmjson "github.com/tendermint/tendermint/libs/json"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
@@ -35,6 +35,10 @@ func ExportCmd(appExporter types.AppExporter, defaultNodeHome string) *cobra.Com
|
||||
homeDir, _ := cmd.Flags().GetString(flags.FlagHome)
|
||||
config.SetRoot(homeDir)
|
||||
|
||||
if _, err := os.Stat(config.GenesisFile()); os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
db, err := openDB(config.RootDir)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -64,7 +68,7 @@ func ExportCmd(appExporter types.AppExporter, defaultNodeHome string) *cobra.Com
|
||||
forZeroHeight, _ := cmd.Flags().GetBool(FlagForZeroHeight)
|
||||
jailAllowedAddrs, _ := cmd.Flags().GetStringSlice(FlagJailAllowedAddrs)
|
||||
|
||||
appState, validators, cp, err := appExporter(serverCtx.Logger, db, traceWriter, height, forZeroHeight, jailAllowedAddrs)
|
||||
exported, err := appExporter(serverCtx.Logger, db, traceWriter, height, forZeroHeight, jailAllowedAddrs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error exporting state: %v", err)
|
||||
}
|
||||
@@ -74,29 +78,30 @@ func ExportCmd(appExporter types.AppExporter, defaultNodeHome string) *cobra.Com
|
||||
return err
|
||||
}
|
||||
|
||||
doc.AppState = appState
|
||||
doc.Validators = validators
|
||||
doc.AppState = exported.AppState
|
||||
doc.Validators = exported.Validators
|
||||
doc.InitialHeight = exported.Height
|
||||
doc.ConsensusParams = &tmproto.ConsensusParams{
|
||||
Block: tmproto.BlockParams{
|
||||
MaxBytes: cp.Block.MaxBytes,
|
||||
MaxGas: cp.Block.MaxGas,
|
||||
MaxBytes: exported.ConsensusParams.Block.MaxBytes,
|
||||
MaxGas: exported.ConsensusParams.Block.MaxGas,
|
||||
TimeIotaMs: doc.ConsensusParams.Block.TimeIotaMs,
|
||||
},
|
||||
Evidence: tmproto.EvidenceParams{
|
||||
MaxAgeNumBlocks: cp.Evidence.MaxAgeNumBlocks,
|
||||
MaxAgeDuration: cp.Evidence.MaxAgeDuration,
|
||||
MaxNum: cp.Evidence.MaxNum,
|
||||
ProofTrialPeriod: cp.Evidence.ProofTrialPeriod,
|
||||
MaxAgeNumBlocks: exported.ConsensusParams.Evidence.MaxAgeNumBlocks,
|
||||
MaxAgeDuration: exported.ConsensusParams.Evidence.MaxAgeDuration,
|
||||
MaxNum: exported.ConsensusParams.Evidence.MaxNum,
|
||||
ProofTrialPeriod: exported.ConsensusParams.Evidence.ProofTrialPeriod,
|
||||
},
|
||||
Validator: tmproto.ValidatorParams{
|
||||
PubKeyTypes: cp.Validator.PubKeyTypes,
|
||||
PubKeyTypes: exported.ConsensusParams.Validator.PubKeyTypes,
|
||||
},
|
||||
}
|
||||
|
||||
// NOTE: for now we're just using standard JSON marshaling for the root GenesisDoc.
|
||||
// These types are in Tendermint, don't support proto and as far as we know, don't need it.
|
||||
// All of the protobuf/amino state is inside AppState
|
||||
encoded, err := json.MarshalIndent(doc, "", " ")
|
||||
// NOTE: Tendermint uses a custom JSON decoder for GenesisDoc
|
||||
// (except for stuff inside AppState). Inside AppState, we're free
|
||||
// to encode as protobuf or amino.
|
||||
encoded, err := tmjson.Marshal(doc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+133
-36
@@ -1,4 +1,4 @@
|
||||
package server
|
||||
package server_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -10,15 +10,20 @@ import (
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmjson "github.com/tendermint/tendermint/libs/json"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/server/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/types/errors"
|
||||
@@ -29,40 +34,7 @@ func TestExportCmd_ConsensusParams(t *testing.T) {
|
||||
tempDir, clean := testutil.NewTestCaseDir(t)
|
||||
defer clean()
|
||||
|
||||
err := createConfigFolder(tempDir)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating config folder: %s", err)
|
||||
}
|
||||
|
||||
db := dbm.NewMemDB()
|
||||
app := simapp.NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, tempDir, 0, simapp.MakeEncodingConfig())
|
||||
|
||||
serverCtx := NewDefaultContext()
|
||||
serverCtx.Config.RootDir = tempDir
|
||||
|
||||
clientCtx := client.Context{}.WithJSONMarshaler(app.AppCodec())
|
||||
|
||||
genDoc := newDefaultGenesisDoc()
|
||||
err = saveGenesisFile(genDoc, serverCtx.Config.GenesisFile())
|
||||
|
||||
app.InitChain(
|
||||
abci.RequestInitChain{
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
ConsensusParams: simapp.DefaultConsensusParams,
|
||||
AppStateBytes: genDoc.AppState,
|
||||
},
|
||||
)
|
||||
|
||||
app.Commit()
|
||||
|
||||
cmd := ExportCmd(
|
||||
func(logger log.Logger, db dbm.DB, writer io.Writer, i int64, b bool, strings []string) (json.RawMessage, []tmtypes.GenesisValidator, *abci.ConsensusParams, error) {
|
||||
return app.ExportAppStateAndValidators(true, []string{})
|
||||
}, tempDir)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
|
||||
ctx = context.WithValue(ctx, ServerContextKey, serverCtx)
|
||||
_, ctx, genDoc, cmd := setupApp(t, tempDir)
|
||||
|
||||
output := &bytes.Buffer{}
|
||||
cmd.SetOut(output)
|
||||
@@ -70,7 +42,7 @@ func TestExportCmd_ConsensusParams(t *testing.T) {
|
||||
require.NoError(t, cmd.ExecuteContext(ctx))
|
||||
|
||||
var exportedGenDoc tmtypes.GenesisDoc
|
||||
err = json.Unmarshal(output.Bytes(), &exportedGenDoc)
|
||||
err := tmjson.Unmarshal(output.Bytes(), &exportedGenDoc)
|
||||
if err != nil {
|
||||
t.Fatalf("error unmarshaling exported genesis doc: %s", err)
|
||||
}
|
||||
@@ -85,6 +57,131 @@ func TestExportCmd_ConsensusParams(t *testing.T) {
|
||||
require.Equal(t, simapp.DefaultConsensusParams.Validator.PubKeyTypes, exportedGenDoc.ConsensusParams.Validator.PubKeyTypes)
|
||||
}
|
||||
|
||||
func TestExportCmd_HomeDir(t *testing.T) {
|
||||
tempDir, clean := testutil.NewTestCaseDir(t)
|
||||
defer clean()
|
||||
|
||||
_, ctx, _, cmd := setupApp(t, tempDir)
|
||||
|
||||
cmd.SetArgs([]string{fmt.Sprintf("--%s=%s", flags.FlagHome, "foobar")})
|
||||
err := cmd.ExecuteContext(ctx)
|
||||
require.EqualError(t, err, "stat foobar/config/genesis.json: no such file or directory")
|
||||
}
|
||||
|
||||
func TestExportCmd_Height(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
flags []string
|
||||
fastForward int64
|
||||
expHeight int64
|
||||
}{
|
||||
{
|
||||
"should export correct height",
|
||||
[]string{},
|
||||
5, 6,
|
||||
},
|
||||
{
|
||||
"should export correct height with --height",
|
||||
[]string{
|
||||
fmt.Sprintf("--%s=%d", server.FlagHeight, 3),
|
||||
},
|
||||
5, 4,
|
||||
},
|
||||
{
|
||||
"should export height 0 with --for-zero-height",
|
||||
[]string{
|
||||
fmt.Sprintf("--%s=%s", server.FlagForZeroHeight, "true"),
|
||||
},
|
||||
2, 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tempDir, clean := testutil.NewTestCaseDir(t)
|
||||
defer clean()
|
||||
|
||||
app, ctx, _, cmd := setupApp(t, tempDir)
|
||||
|
||||
// Fast forward to block `tc.fastForward`.
|
||||
for i := int64(2); i <= tc.fastForward; i++ {
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: i}})
|
||||
app.Commit()
|
||||
}
|
||||
|
||||
output := &bytes.Buffer{}
|
||||
cmd.SetOut(output)
|
||||
args := append(tc.flags, fmt.Sprintf("--%s=%s", flags.FlagHome, tempDir))
|
||||
cmd.SetArgs(args)
|
||||
require.NoError(t, cmd.ExecuteContext(ctx))
|
||||
|
||||
var exportedGenDoc tmtypes.GenesisDoc
|
||||
err := tmjson.Unmarshal(output.Bytes(), &exportedGenDoc)
|
||||
if err != nil {
|
||||
t.Fatalf("error unmarshaling exported genesis doc: %s", err)
|
||||
}
|
||||
|
||||
require.Equal(t, tc.expHeight, exportedGenDoc.InitialHeight)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func setupApp(t *testing.T, tempDir string) (*simapp.SimApp, context.Context, *tmtypes.GenesisDoc, *cobra.Command) {
|
||||
err := createConfigFolder(tempDir)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating config folder: %s", err)
|
||||
}
|
||||
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
db := dbm.NewMemDB()
|
||||
encCfg := simapp.MakeEncodingConfig()
|
||||
app := simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, tempDir, 0, encCfg)
|
||||
|
||||
serverCtx := server.NewDefaultContext()
|
||||
serverCtx.Config.RootDir = tempDir
|
||||
|
||||
clientCtx := client.Context{}.WithJSONMarshaler(app.AppCodec())
|
||||
|
||||
genDoc := newDefaultGenesisDoc()
|
||||
err = saveGenesisFile(genDoc, serverCtx.Config.GenesisFile())
|
||||
require.NoError(t, err)
|
||||
|
||||
app.InitChain(
|
||||
abci.RequestInitChain{
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
ConsensusParams: simapp.DefaultConsensusParams,
|
||||
AppStateBytes: genDoc.AppState,
|
||||
},
|
||||
)
|
||||
|
||||
app.Commit()
|
||||
|
||||
cmd := server.ExportCmd(
|
||||
func(_ log.Logger, _ dbm.DB, _ io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string) (types.ExportedApp, error) {
|
||||
encCfg := simapp.MakeEncodingConfig()
|
||||
|
||||
var simApp *simapp.SimApp
|
||||
if height != -1 {
|
||||
simApp = simapp.NewSimApp(logger, db, nil, false, map[int64]bool{}, "", 0, encCfg)
|
||||
|
||||
if err := simApp.LoadHeight(height); err != nil {
|
||||
return types.ExportedApp{}, err
|
||||
}
|
||||
} else {
|
||||
simApp = simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, "", 0, encCfg)
|
||||
}
|
||||
|
||||
return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs)
|
||||
}, tempDir)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
|
||||
ctx = context.WithValue(ctx, server.ServerContextKey, serverCtx)
|
||||
|
||||
return app, ctx, genDoc, cmd
|
||||
}
|
||||
|
||||
func createConfigFolder(dir string) error {
|
||||
return os.Mkdir(path.Join(dir, "config"), 0700)
|
||||
}
|
||||
|
||||
@@ -99,6 +99,10 @@ func (ms multiStore) SetInterBlockCache(_ sdk.MultiStorePersistentCache) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (ms multiStore) SetInitialVersion(version int64) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
var _ sdk.KVStore = kvStore{}
|
||||
|
||||
type kvStore struct {
|
||||
|
||||
+14
-1
@@ -42,7 +42,20 @@ type (
|
||||
// application using various configurations.
|
||||
AppCreator func(log.Logger, dbm.DB, io.Writer, AppOptions) Application
|
||||
|
||||
// ExportedApp represents an exported app state, along with
|
||||
// validators, consensus params and latest app height.
|
||||
ExportedApp struct {
|
||||
// AppState is the application state as JSON.
|
||||
AppState json.RawMessage
|
||||
// Validators is the exported validator set.
|
||||
Validators []tmtypes.GenesisValidator
|
||||
// Height is the app's latest block height.
|
||||
Height int64
|
||||
// ConsensusParams are the exported consensus params for ABCI.
|
||||
ConsensusParams *abci.ConsensusParams
|
||||
}
|
||||
|
||||
// AppExporter is a function that dumps all app state to
|
||||
// JSON-serializable structure and returns the current validator set.
|
||||
AppExporter func(log.Logger, dbm.DB, io.Writer, int64, bool, []string) (json.RawMessage, []tmtypes.GenesisValidator, *abci.ConsensusParams, error)
|
||||
AppExporter func(log.Logger, dbm.DB, io.Writer, int64, bool, []string) (ExportedApp, error)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user