Merge pull request #901 from cosmos/cwgoes/dump-state-to-json

Dump all state to JSON
This commit is contained in:
Rigel 2018-04-27 20:57:34 -04:00 committed by GitHub
commit 71dccd4db3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 384 additions and 76 deletions

View File

@ -241,6 +241,7 @@ func (app *BaseApp) setDeliverState(header abci.Header) {
}
//______________________________________________________________________________
// ABCI
// Implements ABCI

View File

@ -80,7 +80,7 @@ func createHandler(cdc *wire.Codec) http.Handler {
keys.RegisterRoutes(r)
rpc.RegisterRoutes(ctx, r)
tx.RegisterRoutes(ctx, r, cdc)
auth.RegisterRoutes(ctx, r, cdc, "main")
auth.RegisterRoutes(ctx, r, cdc, "acc")
bank.RegisterRoutes(ctx, r, cdc, kb)
ibc.RegisterRoutes(ctx, r, cdc, kb)
return r

View File

@ -1,6 +1,7 @@
package app
import (
"encoding/json"
"os"
abci "github.com/tendermint/abci/types"
@ -58,8 +59,14 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
keyStake: sdk.NewKVStoreKey("stake"),
}
// add accountMapper/handlers
app.accountMapper = auth.NewAccountMapper(app.cdc, app.keyMain, &auth.BaseAccount{})
// define the accountMapper
app.accountMapper = auth.NewAccountMapper(
app.cdc,
app.keyAccount, // target store
&auth.BaseAccount{}, // prototype
)
// add handlers
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
@ -117,3 +124,23 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
return abci.ResponseInitChain{}
}
// export the state of gaia for a genesis f
func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
ctx := app.NewContext(true, abci.Header{})
// iterate to get the accounts
accounts := []GenesisAccount{}
appendAccount := func(acc sdk.Account) (stop bool) {
account := NewGenesisAccountI(acc)
accounts = append(accounts, account)
return false
}
app.accountMapper.IterateAccounts(ctx, appendAccount)
genState := GenesisState{
Accounts: accounts,
StakeData: stake.WriteGenesis(ctx, app.stakeKeeper),
}
return wire.MarshalJSONIndent(app.cdc, genState)
}

View File

@ -35,6 +35,13 @@ func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
}
}
func NewGenesisAccountI(acc sdk.Account) GenesisAccount {
return GenesisAccount{
Address: acc.GetAddress(),
Coins: acc.GetCoins(),
}
}
// convert GenesisAccount to auth.BaseAccount
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
return &auth.BaseAccount{

View File

@ -44,7 +44,7 @@ func main() {
// add query/post commands (custom to binary)
rootCmd.AddCommand(
client.GetCommands(
authcmd.GetAccountCmd("main", cdc, authcmd.GetAccountDecoder(cdc)),
authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)),
stakecmd.GetCmdQueryCandidate("stake", cdc),
//stakecmd.GetCmdQueryCandidates("stake", cdc),
stakecmd.GetCmdQueryDelegatorBond("stake", cdc),

View File

@ -1,7 +1,7 @@
package main
import (
"path/filepath"
"encoding/json"
"github.com/spf13/cobra"
@ -23,19 +23,20 @@ func main() {
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
}
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), generateApp)
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(),
server.ConstructAppCreator(newApp, "gaia"),
server.ConstructAppExporter(exportAppState, "gaia"))
// prepare and add flags
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
executor.Execute()
}
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
dataDir := filepath.Join(rootDir, "data")
db, err := dbm.NewGoLevelDB("gaia", dataDir)
if err != nil {
return nil, err
}
bapp := app.NewGaiaApp(logger, db)
return bapp, nil
func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewGaiaApp(logger, db)
}
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
gapp := app.NewGaiaApp(logger, db)
return gapp.ExportAppStateJSON()
}

View File

@ -1,6 +1,8 @@
package app
import (
"encoding/json"
abci "github.com/tendermint/abci/types"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
@ -57,7 +59,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
// Define the accountMapper.
app.accountMapper = auth.NewAccountMapper(
cdc,
app.keyMain, // target store
app.keyAccount, // target store
&types.AppAccount{}, // prototype
)
@ -119,3 +121,25 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain)
}
return abci.ResponseInitChain{}
}
// Custom logic for state export
func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
ctx := app.NewContext(true, abci.Header{})
// iterate to get the accounts
accounts := []*types.GenesisAccount{}
appendAccount := func(acc sdk.Account) (stop bool) {
account := &types.GenesisAccount{
Address: acc.GetAddress(),
Coins: acc.GetCoins(),
}
accounts = append(accounts, account)
return false
}
app.accountMapper.IterateAccounts(ctx, appendAccount)
genState := types.GenesisState{
Accounts: accounts,
}
return wire.MarshalJSONIndent(app.cdc, genState)
}

View File

@ -14,11 +14,13 @@ import (
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/version"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli"
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
)
// rootCmd is the entry point for this binary
@ -47,6 +49,11 @@ func main() {
rootCmd.AddCommand(client.LineBreak)
// add query/post commands (custom to binary)
rootCmd.AddCommand(
client.GetCommands(
authcmd.GetAccountCmd("acc", cdc, types.GetAccountDecoder(cdc)),
)...)
rootCmd.AddCommand(
client.PostCommands(
bankcmd.SendTxCmd(cdc),

View File

@ -1,8 +1,8 @@
package main
import (
"encoding/json"
"os"
"path/filepath"
"github.com/spf13/cobra"
@ -25,7 +25,9 @@ func main() {
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
}
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, generateApp)
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit,
server.ConstructAppCreator(newApp, "basecoin"),
server.ConstructAppExporter(exportAppState, "basecoin"))
// prepare and add flags
rootDir := os.ExpandEnv("$HOME/.basecoind")
@ -33,12 +35,11 @@ func main() {
executor.Execute()
}
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
dataDir := filepath.Join(rootDir, "data")
db, err := dbm.NewGoLevelDB("basecoin", dataDir)
if err != nil {
return nil, err
}
bapp := app.NewBasecoinApp(logger, db)
return bapp, nil
func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewBasecoinApp(logger, db)
}
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
bapp := app.NewBasecoinApp(logger, db)
return bapp.ExportAppStateJSON()
}

View File

@ -1,6 +1,8 @@
package app
import (
"encoding/json"
abci "github.com/tendermint/abci/types"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
@ -36,6 +38,13 @@ type DemocoinApp struct {
capKeyIBCStore *sdk.KVStoreKey
capKeyStakingStore *sdk.KVStoreKey
// keepers
coinKeeper bank.Keeper
coolKeeper cool.Keeper
powKeeper pow.Keeper
ibcMapper ibc.Mapper
stakeKeeper simplestake.Keeper
// Manage getting and setting accounts
accountMapper sdk.AccountMapper
}
@ -59,26 +68,26 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
// Define the accountMapper.
app.accountMapper = auth.NewAccountMapper(
cdc,
app.capKeyMainStore, // target store
&types.AppAccount{}, // prototype
app.capKeyAccountStore, // target store
&types.AppAccount{}, // prototype
)
// Add handlers.
coinKeeper := bank.NewKeeper(app.accountMapper)
coolKeeper := cool.NewKeeper(app.capKeyMainStore, coinKeeper, app.RegisterCodespace(cool.DefaultCodespace))
powKeeper := pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), coinKeeper, app.RegisterCodespace(pow.DefaultCodespace))
ibcMapper := ibc.NewMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace))
stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper, app.RegisterCodespace(simplestake.DefaultCodespace))
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.coolKeeper = cool.NewKeeper(app.capKeyMainStore, app.coinKeeper, app.RegisterCodespace(cool.DefaultCodespace))
app.powKeeper = pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), app.coinKeeper, app.RegisterCodespace(pow.DefaultCodespace))
app.ibcMapper = ibc.NewMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace))
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.coinKeeper, app.RegisterCodespace(simplestake.DefaultCodespace))
app.Router().
AddRoute("bank", bank.NewHandler(coinKeeper)).
AddRoute("cool", cool.NewHandler(coolKeeper)).
AddRoute("pow", powKeeper.Handler).
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
AddRoute("cool", cool.NewHandler(app.coolKeeper)).
AddRoute("pow", app.powKeeper.Handler).
AddRoute("sketchy", sketchy.NewHandler()).
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper)).
AddRoute("simplestake", simplestake.NewHandler(stakeKeeper))
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
AddRoute("simplestake", simplestake.NewHandler(app.stakeKeeper))
// Initialize BaseApp.
app.SetInitChainer(app.initChainerFn(coolKeeper, powKeeper))
app.SetInitChainer(app.initChainerFn(app.coolKeeper, app.powKeeper))
app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyPowStore, app.capKeyIBCStore, app.capKeyStakingStore)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.BurnFeeHandler))
err := app.LoadLatestVersion(app.capKeyMainStore)
@ -127,13 +136,13 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep
}
// Application specific genesis handling
err = coolKeeper.InitGenesis(ctx, genesisState.CoolGenesis)
err = cool.InitGenesis(ctx, app.coolKeeper, genesisState.CoolGenesis)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
err = powKeeper.InitGenesis(ctx, genesisState.POWGenesis)
err = pow.InitGenesis(ctx, app.powKeeper, genesisState.POWGenesis)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
@ -142,3 +151,27 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep
return abci.ResponseInitChain{}
}
}
// Custom logic for state export
func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
ctx := app.NewContext(true, abci.Header{})
// iterate to get the accounts
accounts := []*types.GenesisAccount{}
appendAccount := func(acc sdk.Account) (stop bool) {
account := &types.GenesisAccount{
Address: acc.GetAddress(),
Coins: acc.GetCoins(),
}
accounts = append(accounts, account)
return false
}
app.accountMapper.IterateAccounts(ctx, appendAccount)
genState := types.GenesisState{
Accounts: accounts,
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper),
}
return wire.MarshalJSONIndent(app.cdc, genState)
}

View File

@ -54,7 +54,7 @@ func main() {
// start with commands common to basecoin
rootCmd.AddCommand(
client.GetCommands(
authcmd.GetAccountCmd("main", cdc, types.GetAccountDecoder(cdc)),
authcmd.GetAccountCmd("acc", cdc, types.GetAccountDecoder(cdc)),
)...)
rootCmd.AddCommand(
client.PostCommands(

View File

@ -3,7 +3,6 @@ package main
import (
"encoding/json"
"os"
"path/filepath"
"github.com/spf13/cobra"
@ -32,18 +31,24 @@ func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso
key := "cool"
value := json.RawMessage(`{
"trend": "ice-cold"
}`)
appState, err = server.AppendJSON(cdc, appState, key, value)
key = "pow"
value = json.RawMessage(`{
"difficulty": 1,
"count": 0
}`)
appState, err = server.AppendJSON(cdc, appState, key, value)
return
}
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
db, err := dbm.NewGoLevelDB("democoin", filepath.Join(rootDir, "data"))
if err != nil {
return nil, err
}
bapp := app.NewDemocoinApp(logger, db)
return bapp, nil
func newApp(logger log.Logger, db dbm.DB) abci.Application {
return app.NewDemocoinApp(logger, db)
}
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
dapp := app.NewDemocoinApp(logger, db)
return dapp.ExportAppStateJSON()
}
func main() {
@ -56,7 +61,9 @@ func main() {
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
}
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit, generateApp)
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
server.ConstructAppCreator(newApp, "democoin"),
server.ConstructAppExporter(exportAppState, "democoin"))
// prepare and add flags
rootDir := os.ExpandEnv("$HOME/.democoind")

View File

@ -44,7 +44,13 @@ func (k Keeper) CheckTrend(ctx sdk.Context, guessedTrend string) bool {
}
// InitGenesis - store the genesis trend
func (k Keeper) InitGenesis(ctx sdk.Context, data Genesis) error {
func InitGenesis(ctx sdk.Context, k Keeper, data Genesis) error {
k.setTrend(ctx, data.Trend)
return nil
}
// WriteGenesis - output the genesis trend
func WriteGenesis(ctx sdk.Context, k Keeper) Genesis {
trend := k.GetTrend(ctx)
return Genesis{trend}
}

View File

@ -0,0 +1,50 @@
package cool
import (
"testing"
"github.com/stretchr/testify/assert"
abci "github.com/tendermint/abci/types"
dbm "github.com/tendermint/tmlibs/db"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
auth "github.com/cosmos/cosmos-sdk/x/auth"
bank "github.com/cosmos/cosmos-sdk/x/bank"
)
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey) {
db := dbm.NewMemDB()
capKey := sdk.NewKVStoreKey("capkey")
ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db)
ms.LoadLatestVersion()
return ms, capKey
}
func TestCoolKeeper(t *testing.T) {
ms, capKey := setupMultiStore()
cdc := wire.NewCodec()
auth.RegisterBaseAccount(cdc)
am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{})
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
ck := bank.NewKeeper(am)
keeper := NewKeeper(capKey, ck, DefaultCodespace)
err := InitGenesis(ctx, keeper, Genesis{"icy"})
assert.Nil(t, err)
genesis := WriteGenesis(ctx, keeper)
assert.Nil(t, err)
assert.Equal(t, genesis, Genesis{"icy"})
res := keeper.GetTrend(ctx)
assert.Equal(t, res, "icy")
keeper.setTrend(ctx, "fiery")
res = keeper.GetTrend(ctx)
assert.Equal(t, res, "fiery")
}

View File

@ -30,7 +30,7 @@ func TestPowHandler(t *testing.T) {
count := uint64(1)
difficulty := uint64(2)
err := keeper.InitGenesis(ctx, Genesis{uint64(1), uint64(0)})
err := InitGenesis(ctx, keeper, Genesis{uint64(1), uint64(0)})
assert.Nil(t, err)
nonce, proof := mine(addr, count, difficulty)

View File

@ -36,13 +36,29 @@ func NewKeeper(key sdk.StoreKey, config Config, ck bank.Keeper, codespace sdk.Co
return Keeper{key, config, ck, codespace}
}
// Init Genessis for the POW module
func (k Keeper) InitGenesis(ctx sdk.Context, genesis Genesis) error {
// InitGenesis for the POW module
func InitGenesis(ctx sdk.Context, k Keeper, genesis Genesis) error {
k.SetLastDifficulty(ctx, genesis.Difficulty)
k.SetLastCount(ctx, genesis.Count)
return nil
}
// WriteGenesis for the PoW module
func WriteGenesis(ctx sdk.Context, k Keeper) Genesis {
difficulty, err := k.GetLastDifficulty(ctx)
if err != nil {
panic(err)
}
count, err := k.GetLastCount(ctx)
if err != nil {
panic(err)
}
return Genesis{
difficulty,
count,
}
}
var lastDifficultyKey = []byte("lastDifficultyKey")
// get the last mining difficulty

View File

@ -37,9 +37,13 @@ func TestPowKeeperGetSet(t *testing.T) {
ck := bank.NewKeeper(am)
keeper := NewKeeper(capKey, config, ck, DefaultCodespace)
err := keeper.InitGenesis(ctx, Genesis{uint64(1), uint64(0)})
err := InitGenesis(ctx, keeper, Genesis{uint64(1), uint64(0)})
assert.Nil(t, err)
genesis := WriteGenesis(ctx, keeper)
assert.Nil(t, err)
assert.Equal(t, genesis, Genesis{uint64(1), uint64(0)})
res, err := keeper.GetLastDifficulty(ctx)
assert.Nil(t, err)
assert.Equal(t, res, uint64(1))

42
server/constructors.go Normal file
View File

@ -0,0 +1,42 @@
package server
import (
"encoding/json"
"path/filepath"
abci "github.com/tendermint/abci/types"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
)
// AppCreator lets us lazily initialize app, using home dir
// and other flags (?) to start
type AppCreator func(string, log.Logger) (abci.Application, error)
// AppExporter dumps all app state to JSON-serializable structure
type AppExporter func(home string, log log.Logger) (json.RawMessage, error)
// ConstructAppCreator returns an application generation function
func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name string) AppCreator {
return func(rootDir string, logger log.Logger) (abci.Application, error) {
dataDir := filepath.Join(rootDir, "data")
db, err := dbm.NewGoLevelDB(name, dataDir)
if err != nil {
return nil, err
}
app := appFn(logger, db)
return app, nil
}
}
// ConstructAppExporter returns an application export function
func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, error), name string) AppExporter {
return func(rootDir string, logger log.Logger) (json.RawMessage, error) {
dataDir := filepath.Join(rootDir, "data")
db, err := dbm.NewGoLevelDB(name, dataDir)
if err != nil {
return nil, err
}
return appFn(logger, db)
}
}

28
server/export.go Normal file
View File

@ -0,0 +1,28 @@
package server
import (
"fmt"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/wire"
)
// ExportCmd dumps app state to JSON
func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Command {
return &cobra.Command{
Use: "export",
Short: "Export state to JSON",
RunE: func(cmd *cobra.Command, args []string) error {
home := viper.GetString("home")
appState, err := appExporter(home, ctx.Logger)
if err != nil {
return errors.Errorf("Error exporting state: %v\n", err)
}
fmt.Println(string(appState))
return nil
},
}
}

View File

@ -6,14 +6,12 @@ import (
"github.com/spf13/viper"
"github.com/tendermint/abci/server"
abci "github.com/tendermint/abci/types"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
"github.com/tendermint/tendermint/node"
"github.com/tendermint/tendermint/proxy"
pvm "github.com/tendermint/tendermint/types/priv_validator"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log"
)
const (
@ -21,10 +19,6 @@ const (
flagAddress = "address"
)
// AppCreator lets us lazily initialize app, using home dir
// and other flags (?) to start
type AppCreator func(string, log.Logger) (abci.Application, error)
// StartCmd runs the service passed in, either
// stand-alone, or in-process with tendermint
func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command {

View File

@ -68,7 +68,7 @@ func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error
func AddCommands(
ctx *Context, cdc *wire.Codec,
rootCmd *cobra.Command, appInit AppInit,
appCreator AppCreator) {
appCreator AppCreator, appExport AppExporter) {
rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level")
@ -78,6 +78,8 @@ func AddCommands(
UnsafeResetAllCmd(ctx),
ShowNodeIDCmd(ctx),
ShowValidatorCmd(ctx),
ExportCmd(ctx, cdc, appExport),
UnsafeResetAllCmd(ctx),
version.VersionCmd,
)
}

View File

@ -48,6 +48,7 @@ type AccountMapper interface {
NewAccountWithAddress(ctx Context, addr Address) Account
GetAccount(ctx Context, addr Address) Account
SetAccount(ctx Context, acc Account)
IterateAccounts(ctx Context, process func(Account) (stop bool))
}
// AccountDecoder unmarshals account bytes

View File

@ -1,10 +0,0 @@
package types
import (
"encoding/json"
)
// Run only once on chain initialization, should write genesis state to store
// or throw an error if some required information was not provided, in which case
// the application will panic.
type InitGenesis func(ctx Context, data json.RawMessage) error

View File

@ -62,6 +62,23 @@ func (am accountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) {
store.Set(addr, bz)
}
// Implements sdk.AccountMapper.
func (am accountMapper) IterateAccounts(ctx sdk.Context, process func(sdk.Account) (stop bool)) {
store := ctx.KVStore(am.key)
iter := store.Iterator(nil, nil)
for {
if !iter.Valid() {
return
}
val := iter.Value()
acc := am.decodeAccount(val)
if process(acc) {
return
}
iter.Next()
}
}
//----------------------------------------
// misc.

View File

@ -55,6 +55,23 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
for _, candidate := range data.Candidates {
k.setCandidate(ctx, candidate)
}
for _, bond := range data.Bonds {
k.setDelegatorBond(ctx, bond)
}
}
// WriteGenesis - output genesis parameters
func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState {
pool := k.GetPool(ctx)
params := k.GetParams(ctx)
candidates := k.GetCandidates(ctx, 32767)
bonds := k.getBonds(ctx, 32767)
return GenesisState{
pool,
params,
candidates,
bonds,
}
}
//_____________________________________________________________________

View File

@ -371,6 +371,30 @@ func (k Keeper) GetDelegatorBond(ctx sdk.Context,
return bond, true
}
// load all bonds
func (k Keeper) getBonds(ctx sdk.Context, maxRetrieve int16) (bonds []DelegatorBond) {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(subspace(DelegatorBondKeyPrefix))
bonds = make([]DelegatorBond, maxRetrieve)
i := 0
for ; ; i++ {
if !iterator.Valid() || i > int(maxRetrieve-1) {
iterator.Close()
break
}
bondBytes := iterator.Value()
var bond DelegatorBond
err := k.cdc.UnmarshalBinary(bondBytes, &bond)
if err != nil {
panic(err)
}
bonds[i] = bond
iterator.Next()
}
return bonds[:i] // trim
}
// load all bonds of a delegator
func (k Keeper) GetDelegatorBonds(ctx sdk.Context, delegator sdk.Address, maxRetrieve int16) (bonds []DelegatorBond) {
store := ctx.KVStore(k.storeKey)

View File

@ -94,7 +94,7 @@ func TestCandidate(t *testing.T) {
assert.False(t, found)
}
// tests GetDelegatorBond, GetDelegatorBonds, SetDelegatorBond, removeDelegatorBond
// tests GetDelegatorBond, GetDelegatorBonds, SetDelegatorBond, removeDelegatorBond, GetBonds
func TestBond(t *testing.T) {
ctx, _, keeper := createTestInput(t, false, 0)
@ -172,6 +172,14 @@ func TestBond(t *testing.T) {
assert.True(t, bondsEqual(bond2to1, resBonds[0]))
assert.True(t, bondsEqual(bond2to2, resBonds[1]))
assert.True(t, bondsEqual(bond2to3, resBonds[2]))
allBonds := keeper.getBonds(ctx, 1000)
require.Equal(t, 6, len(allBonds))
assert.True(t, bondsEqual(bond1to1, allBonds[0]))
assert.True(t, bondsEqual(bond1to2, allBonds[1]))
assert.True(t, bondsEqual(bond1to3, allBonds[2]))
assert.True(t, bondsEqual(bond2to1, allBonds[3]))
assert.True(t, bondsEqual(bond2to2, allBonds[4]))
assert.True(t, bondsEqual(bond2to3, allBonds[5]))
// delete a record
keeper.removeDelegatorBond(ctx, bond2to3)

View File

@ -9,9 +9,10 @@ import (
// GenesisState - all staking state that must be provided at genesis
type GenesisState struct {
Pool Pool `json:"pool"`
Params Params `json:"params"`
Candidates []Candidate `json:"candidates"`
Pool Pool `json:"pool"`
Params Params `json:"params"`
Candidates []Candidate `json:"candidates"`
Bonds []DelegatorBond `json:"bonds"`
}
//_________________________________________________________________________