Merge PR #1142: Export validators to genesis

* Validator export skeleton
* Update export command, add tests, update CHANGELOG
* Rename exportAppState to exportAppStateAndTMValidators
This commit is contained in:
Christopher Goes 2018-06-06 18:38:13 +02:00 committed by GitHub
parent 5f409ce832
commit 3fbee11ccc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 105 additions and 22 deletions

View File

@ -2,6 +2,12 @@
BREAKING CHANGES BREAKING CHANGES
FEATURES
IMPROVEMENTS
* export command now writes current validator set for Tendermint
FIXES
* [lcd] Switch to bech32 for addresses on all human readable inputs and outputs * [lcd] Switch to bech32 for addresses on all human readable inputs and outputs
## 0.18.0 ## 0.18.0

View File

@ -5,6 +5,7 @@ import (
"os" "os"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
@ -153,7 +154,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
} }
// export the state of gaia for a genesis file // export the state of gaia for a genesis file
func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) { func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
ctx := app.NewContext(true, abci.Header{}) ctx := app.NewContext(true, abci.Header{})
// iterate to get the accounts // iterate to get the accounts
@ -169,5 +170,10 @@ func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
Accounts: accounts, Accounts: accounts,
StakeData: stake.WriteGenesis(ctx, app.stakeKeeper), StakeData: stake.WriteGenesis(ctx, app.stakeKeeper),
} }
return wire.MarshalJSONIndent(app.cdc, genState) appState, err = wire.MarshalJSONIndent(app.cdc, genState)
if err != nil {
return nil, nil, err
}
validators = stake.WriteValidators(ctx, app.stakeKeeper)
return appState, validators, nil
} }

View File

@ -430,6 +430,42 @@ func TestStakeMsgs(t *testing.T) {
require.False(t, found) require.False(t, found)
} }
func TestExportValidators(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42steak")
require.Nil(t, err)
bondCoin, err := sdk.ParseCoin("10steak")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := &auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
err = setGenesis(gapp, acc1, acc2)
require.Nil(t, err)
// Create Validator
description := stake.NewDescription("foo_moniker", "", "", "")
createValidatorMsg := stake.NewMsgCreateValidator(
addr1, priv1.PubKey(), bondCoin, description,
)
SignCheckDeliver(t, gapp, createValidatorMsg, []int64{0}, true, priv1)
gapp.Commit()
// Export validator set
_, validators, err := gapp.ExportAppStateAndValidators()
require.Nil(t, err)
require.Equal(t, 1, len(validators)) // 1 validator
require.Equal(t, priv1.PubKey(), validators[0].PubKey)
require.Equal(t, int64(10), validators[0].Power)
}
//____________________________________________________________________________________ //____________________________________________________________________________________
func CheckBalance(t *testing.T, gapp *GaiaApp, addr sdk.Address, balExpected string) { func CheckBalance(t *testing.T, gapp *GaiaApp, addr sdk.Address, balExpected string) {

View File

@ -6,6 +6,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli" "github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
@ -26,7 +27,7 @@ func main() {
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(),
server.ConstructAppCreator(newApp, "gaia"), server.ConstructAppCreator(newApp, "gaia"),
server.ConstructAppExporter(exportAppState, "gaia")) server.ConstructAppExporter(exportAppStateAndTMValidators, "gaia"))
// prepare and add flags // prepare and add flags
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome) executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
@ -37,7 +38,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewGaiaApp(logger, db) return app.NewGaiaApp(logger, db)
} }
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) { func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
gapp := app.NewGaiaApp(logger, db) gapp := app.NewGaiaApp(logger, db)
return gapp.ExportAppStateJSON() return gapp.ExportAppStateAndValidators()
} }

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
@ -155,7 +156,7 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain)
} }
// Custom logic for state export // Custom logic for state export
func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) { func (app *BasecoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
ctx := app.NewContext(true, abci.Header{}) ctx := app.NewContext(true, abci.Header{})
// iterate to get the accounts // iterate to get the accounts
@ -173,5 +174,10 @@ func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro
genState := types.GenesisState{ genState := types.GenesisState{
Accounts: accounts, Accounts: accounts,
} }
return wire.MarshalJSONIndent(app.cdc, genState) appState, err = wire.MarshalJSONIndent(app.cdc, genState)
if err != nil {
return nil, nil, err
}
validators = stake.WriteValidators(ctx, app.stakeKeeper)
return appState, validators, err
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli" "github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
@ -27,7 +28,7 @@ func main() {
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit,
server.ConstructAppCreator(newApp, "basecoin"), server.ConstructAppCreator(newApp, "basecoin"),
server.ConstructAppExporter(exportAppState, "basecoin")) server.ConstructAppExporter(exportAppStateAndTMValidators, "basecoin"))
// prepare and add flags // prepare and add flags
rootDir := os.ExpandEnv("$HOME/.basecoind") rootDir := os.ExpandEnv("$HOME/.basecoind")
@ -39,7 +40,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewBasecoinApp(logger, db) return app.NewBasecoinApp(logger, db)
} }
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) { func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
bapp := app.NewBasecoinApp(logger, db) bapp := app.NewBasecoinApp(logger, db)
return bapp.ExportAppStateJSON() return bapp.ExportAppStateAndValidators()
} }

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
@ -154,7 +155,7 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep
} }
// Custom logic for state export // Custom logic for state export
func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) { func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
ctx := app.NewContext(true, abci.Header{}) ctx := app.NewContext(true, abci.Header{})
// iterate to get the accounts // iterate to get the accounts
@ -174,5 +175,9 @@ func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper), POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper), CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper),
} }
return wire.MarshalJSONIndent(app.cdc, genState) appState, err = wire.MarshalJSONIndent(app.cdc, genState)
if err != nil {
return nil, nil, err
}
return appState, validators, nil
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli" "github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
@ -46,9 +47,9 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewDemocoinApp(logger, db) return app.NewDemocoinApp(logger, db)
} }
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) { func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
dapp := app.NewDemocoinApp(logger, db) dapp := app.NewDemocoinApp(logger, db)
return dapp.ExportAppStateJSON() return dapp.ExportAppStateAndValidators()
} }
func main() { func main() {
@ -63,7 +64,7 @@ func main() {
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit, server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
server.ConstructAppCreator(newApp, "democoin"), server.ConstructAppCreator(newApp, "democoin"),
server.ConstructAppExporter(exportAppState, "democoin")) server.ConstructAppExporter(exportAppStateAndTMValidators, "democoin"))
// prepare and add flags // prepare and add flags
rootDir := os.ExpandEnv("$HOME/.democoind") rootDir := os.ExpandEnv("$HOME/.democoind")

View File

@ -5,6 +5,7 @@ import (
"path/filepath" "path/filepath"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
) )
@ -13,8 +14,8 @@ import (
// and other flags (?) to start // and other flags (?) to start
type AppCreator func(string, log.Logger) (abci.Application, error) type AppCreator func(string, log.Logger) (abci.Application, error)
// AppExporter dumps all app state to JSON-serializable structure // AppExporter dumps all app state to JSON-serializable structure and returns the current validator set
type AppExporter func(home string, log log.Logger) (json.RawMessage, error) type AppExporter func(home string, log log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error)
// ConstructAppCreator returns an application generation function // ConstructAppCreator returns an application generation function
func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name string) AppCreator { func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name string) AppCreator {
@ -30,12 +31,12 @@ func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name s
} }
// ConstructAppExporter returns an application export function // ConstructAppExporter returns an application export function
func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, error), name string) AppExporter { func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error), name string) AppExporter {
return func(rootDir string, logger log.Logger) (json.RawMessage, error) { return func(rootDir string, logger log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error) {
dataDir := filepath.Join(rootDir, "data") dataDir := filepath.Join(rootDir, "data")
db, err := dbm.NewGoLevelDB(name, dataDir) db, err := dbm.NewGoLevelDB(name, dataDir)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
return appFn(logger, db) return appFn(logger, db)
} }

View File

@ -18,7 +18,7 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
Short: "Export state to JSON", Short: "Export state to JSON",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
home := viper.GetString("home") home := viper.GetString("home")
appState, err := appExporter(home, ctx.Logger) appState, validators, err := appExporter(home, ctx.Logger)
if err != nil { if err != nil {
return errors.Errorf("Error exporting state: %v\n", err) return errors.Errorf("Error exporting state: %v\n", err)
} }
@ -27,6 +27,7 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
return err return err
} }
doc.AppStateJSON = appState doc.AppStateJSON = appState
doc.Validators = validators
encoded, err := wire.MarshalJSONIndent(cdc, doc) encoded, err := wire.MarshalJSONIndent(cdc, doc)
if err != nil { if err != nil {
return err return err

View File

@ -32,6 +32,7 @@ func BondStatusToString(b BondStatus) string {
// validator for a delegated proof of stake system // validator for a delegated proof of stake system
type Validator interface { type Validator interface {
GetMoniker() string // moniker of the validator
GetStatus() BondStatus // status of the validator GetStatus() BondStatus // status of the validator
GetOwner() Address // owner address to receive/return validators coins GetOwner() Address // owner address to receive/return validators coins
GetPubKey() crypto.PubKey // validation pubkey GetPubKey() crypto.PubKey // validation pubkey

View File

@ -1,6 +1,10 @@
package stake package stake
import sdk "github.com/cosmos/cosmos-sdk/types" import (
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// GenesisState - all staking state that must be provided at genesis // GenesisState - all staking state that must be provided at genesis
type GenesisState struct { type GenesisState struct {
@ -63,3 +67,16 @@ func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState {
bonds, bonds,
} }
} }
// WriteValidators - output current validator set
func WriteValidators(ctx sdk.Context, k Keeper) (vals []tmtypes.GenesisValidator) {
k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) {
vals = append(vals, tmtypes.GenesisValidator{
PubKey: validator.GetPubKey(),
Power: validator.GetPower().Evaluate(),
Name: validator.GetMoniker(),
})
return false
})
return
}

View File

@ -251,6 +251,7 @@ func (v Validator) DelegatorShareExRate(pool Pool) sdk.Rat {
var _ sdk.Validator = Validator{} var _ sdk.Validator = Validator{}
// nolint - for sdk.Validator // nolint - for sdk.Validator
func (v Validator) GetMoniker() string { return v.Description.Moniker }
func (v Validator) GetStatus() sdk.BondStatus { return v.Status() } func (v Validator) GetStatus() sdk.BondStatus { return v.Status() }
func (v Validator) GetOwner() sdk.Address { return v.Owner } func (v Validator) GetOwner() sdk.Address { return v.Owner }
func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey }