Fix state export/import, add to CI (#2690)
* Update slashing import/export * More slashing.WriteGenesis * Add test import/export to CI * Store equality comparison. * Fix validator bond intra-tx counter * Set timeslices for unbonding validators * WriteGenesis => ExportGenesis * Delete validators from unbonding queue when re-bonded * Hook for validator deletion, fix staking genesis tests
This commit is contained in:
parent
8f690b5b6c
commit
94f45311a0
|
@ -137,6 +137,24 @@ jobs:
|
|||
export PATH="$GOBIN:$PATH"
|
||||
make test_sim_gaia_fast
|
||||
|
||||
test_sim_gaia_import_export:
|
||||
<<: *defaults
|
||||
parallelism: 1
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- checkout
|
||||
- run:
|
||||
name: dependencies
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_vendor_deps
|
||||
- run:
|
||||
name: Test Gaia import/export simulation
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make test_sim_gaia_import_export
|
||||
|
||||
test_sim_gaia_multi_seed:
|
||||
<<: *defaults
|
||||
parallelism: 1
|
||||
|
@ -259,6 +277,9 @@ workflows:
|
|||
- test_sim_gaia_fast:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_sim_gaia_import_export:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_sim_gaia_multi_seed:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
|
|
12
Makefile
12
Makefile
|
@ -171,6 +171,15 @@ test_sim_gaia_fast:
|
|||
@echo "Running quick Gaia simulation. This may take several minutes..."
|
||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=500 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=10 -v -timeout 24h
|
||||
|
||||
test_sim_gaia_import_export:
|
||||
@echo "Running Gaia import/export simulation. This may take several minutes..."
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=4 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=11 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=12 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=13 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=414 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=4142 -v -timeout 24h
|
||||
|
||||
test_sim_gaia_multi_seed:
|
||||
@echo "Running multi-seed Gaia simulation. This may take awhile!"
|
||||
@bash scripts/multisim.sh 25
|
||||
|
@ -250,4 +259,5 @@ localnet-stop:
|
|||
check_tools check_dev_tools get_tools get_dev_tools get_vendor_deps draw_deps test test_cli test_unit \
|
||||
test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
|
||||
build-linux build-docker-gaiadnode localnet-start localnet-stop \
|
||||
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast test_sim_gaia_multi_seed update_tools update_dev_tools
|
||||
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast \
|
||||
test_sim_gaia_multi_seed test_sim_gaia_import_export update_tools update_dev_tools
|
||||
|
|
|
@ -28,7 +28,7 @@ FEATURES
|
|||
* Gaia
|
||||
|
||||
* SDK
|
||||
* (#1336) Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes.
|
||||
- \#1336 Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes.
|
||||
|
||||
* Tendermint
|
||||
|
||||
|
@ -65,7 +65,8 @@ BUG FIXES
|
|||
* Gaia CLI (`gaiacli`)
|
||||
|
||||
* Gaia
|
||||
- \#2670 [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators`
|
||||
- \#2670 [x/stake] fixed incorrent `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators`
|
||||
- \#2648 [gaiad] Fix `gaiad export` / `gaiad import` consistency, test in CI
|
||||
- \#2691 Fix local testnet creation by using a single canonical genesis time
|
||||
|
||||
* SDK
|
||||
|
|
|
@ -210,9 +210,6 @@ func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.R
|
|||
tags := gov.EndBlocker(ctx, app.govKeeper)
|
||||
validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper)
|
||||
|
||||
// Add these new validators to the addr -> pubkey map.
|
||||
app.slashingKeeper.AddValidators(ctx, validatorUpdates)
|
||||
|
||||
return abci.ResponseEndBlock{
|
||||
ValidatorUpdates: validatorUpdates,
|
||||
Tags: tags,
|
||||
|
@ -231,6 +228,10 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
}
|
||||
|
||||
// sort by account number to maintain consistency
|
||||
sort.Slice(genesisState.Accounts, func(i, j int) bool {
|
||||
return genesisState.Accounts[i].AccountNumber < genesisState.Accounts[j].AccountNumber
|
||||
})
|
||||
// load the accounts
|
||||
for _, gacc := range genesisState.Accounts {
|
||||
acc := gacc.ToAccount()
|
||||
|
@ -244,7 +245,8 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
panic(err) // TODO find a way to do this w/o panics
|
||||
}
|
||||
|
||||
// load the address to pubkey map
|
||||
// initialize module-specific stores
|
||||
auth.InitGenesis(ctx, app.feeCollectionKeeper, genesisState.AuthData)
|
||||
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData)
|
||||
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
||||
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)
|
||||
|
@ -270,7 +272,6 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
|
||||
validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
}
|
||||
app.slashingKeeper.AddValidators(ctx, validators)
|
||||
|
||||
// sanity check
|
||||
if len(req.Validators) > 0 {
|
||||
|
@ -306,11 +307,12 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val
|
|||
app.accountKeeper.IterateAccounts(ctx, appendAccount)
|
||||
genState := NewGenesisState(
|
||||
accounts,
|
||||
stake.WriteGenesis(ctx, app.stakeKeeper),
|
||||
mint.WriteGenesis(ctx, app.mintKeeper),
|
||||
distr.WriteGenesis(ctx, app.distrKeeper),
|
||||
gov.WriteGenesis(ctx, app.govKeeper),
|
||||
slashing.GenesisState{}, // TODO create write methods
|
||||
auth.ExportGenesis(ctx, app.feeCollectionKeeper),
|
||||
stake.ExportGenesis(ctx, app.stakeKeeper),
|
||||
mint.ExportGenesis(ctx, app.mintKeeper),
|
||||
distr.ExportGenesis(ctx, app.distrKeeper),
|
||||
gov.ExportGenesis(ctx, app.govKeeper),
|
||||
slashing.ExportGenesis(ctx, app.slashingKeeper),
|
||||
)
|
||||
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
||||
if err != nil {
|
||||
|
@ -337,12 +339,15 @@ var _ sdk.StakingHooks = Hooks{}
|
|||
// nolint
|
||||
func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
h.dh.OnValidatorCreated(ctx, valAddr)
|
||||
h.sh.OnValidatorCreated(ctx, valAddr)
|
||||
}
|
||||
func (h Hooks) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
h.dh.OnValidatorModified(ctx, valAddr)
|
||||
h.sh.OnValidatorModified(ctx, valAddr)
|
||||
}
|
||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
h.dh.OnValidatorRemoved(ctx, valAddr)
|
||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnValidatorRemoved(ctx, consAddr, valAddr)
|
||||
h.sh.OnValidatorRemoved(ctx, consAddr, valAddr)
|
||||
}
|
||||
func (h Hooks) OnValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnValidatorBonded(ctx, consAddr, valAddr)
|
||||
|
@ -358,10 +363,13 @@ func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddre
|
|||
}
|
||||
func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnDelegationCreated(ctx, delAddr, valAddr)
|
||||
h.sh.OnDelegationCreated(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h Hooks) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnDelegationSharesModified(ctx, delAddr, valAddr)
|
||||
h.sh.OnDelegationSharesModified(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h Hooks) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnDelegationRemoved(ctx, delAddr, valAddr)
|
||||
h.sh.OnDelegationRemoved(ctx, delAddr, valAddr)
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ var (
|
|||
// State to Unmarshal
|
||||
type GenesisState struct {
|
||||
Accounts []GenesisAccount `json:"accounts"`
|
||||
AuthData auth.GenesisState `json:"auth"`
|
||||
StakeData stake.GenesisState `json:"stake"`
|
||||
MintData mint.GenesisState `json:"mint"`
|
||||
DistrData distr.GenesisState `json:"distr"`
|
||||
|
@ -40,11 +41,12 @@ type GenesisState struct {
|
|||
GenTxs []json.RawMessage `json:"gentxs"`
|
||||
}
|
||||
|
||||
func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mintData mint.GenesisState,
|
||||
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState, stakeData stake.GenesisState, mintData mint.GenesisState,
|
||||
distrData distr.GenesisState, govData gov.GenesisState, slashingData slashing.GenesisState) GenesisState {
|
||||
|
||||
return GenesisState{
|
||||
Accounts: accounts,
|
||||
AuthData: authData,
|
||||
StakeData: stakeData,
|
||||
MintData: mintData,
|
||||
DistrData: distrData,
|
||||
|
@ -53,31 +55,39 @@ func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mi
|
|||
}
|
||||
}
|
||||
|
||||
// GenesisAccount doesn't need pubkey or sequence
|
||||
// nolint
|
||||
type GenesisAccount struct {
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
Sequence int64 `json:"sequence_number"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
}
|
||||
|
||||
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
||||
return GenesisAccount{
|
||||
Address: acc.Address,
|
||||
Coins: acc.Coins,
|
||||
Address: acc.Address,
|
||||
Coins: acc.Coins,
|
||||
AccountNumber: acc.AccountNumber,
|
||||
Sequence: acc.Sequence,
|
||||
}
|
||||
}
|
||||
|
||||
func NewGenesisAccountI(acc auth.Account) GenesisAccount {
|
||||
return GenesisAccount{
|
||||
Address: acc.GetAddress(),
|
||||
Coins: acc.GetCoins(),
|
||||
Address: acc.GetAddress(),
|
||||
Coins: acc.GetCoins(),
|
||||
AccountNumber: acc.GetAccountNumber(),
|
||||
Sequence: acc.GetSequence(),
|
||||
}
|
||||
}
|
||||
|
||||
// convert GenesisAccount to auth.BaseAccount
|
||||
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
|
||||
return &auth.BaseAccount{
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins.Sort(),
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins.Sort(),
|
||||
AccountNumber: ga.AccountNumber,
|
||||
Sequence: ga.Sequence,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
|
@ -266,6 +267,103 @@ func TestFullGaiaSimulation(t *testing.T) {
|
|||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestGaiaImportExport(t *testing.T) {
|
||||
if !enabled {
|
||||
t.Skip("Skipping Gaia import/export simulation")
|
||||
}
|
||||
|
||||
// Setup Gaia application
|
||||
var logger log.Logger
|
||||
if verbose {
|
||||
logger = log.TestingLogger()
|
||||
} else {
|
||||
logger = log.NewNopLogger()
|
||||
}
|
||||
var db dbm.DB
|
||||
dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim")
|
||||
db, _ = dbm.NewGoLevelDB("Simulation", dir)
|
||||
defer func() {
|
||||
db.Close()
|
||||
os.RemoveAll(dir)
|
||||
}()
|
||||
app := NewGaiaApp(logger, db, nil)
|
||||
require.Equal(t, "GaiaApp", app.Name())
|
||||
|
||||
// Run randomized simulation
|
||||
err := simulation.SimulateFromSeed(
|
||||
t, app.BaseApp, appStateFn, seed,
|
||||
testAndRunTxs(app),
|
||||
[]simulation.RandSetup{},
|
||||
invariants(app),
|
||||
numBlocks,
|
||||
blockSize,
|
||||
commit,
|
||||
)
|
||||
if commit {
|
||||
// for memdb:
|
||||
// fmt.Println("Database Size", db.Stats()["database.size"])
|
||||
fmt.Println("GoLevelDB Stats")
|
||||
fmt.Println(db.Stats()["leveldb.stats"])
|
||||
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
|
||||
}
|
||||
require.Nil(t, err)
|
||||
|
||||
fmt.Printf("Exporting genesis...\n")
|
||||
|
||||
appState, _, err := app.ExportAppStateAndValidators()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Importing genesis...\n")
|
||||
|
||||
newDir, _ := ioutil.TempDir("", "goleveldb-gaia-sim-2")
|
||||
newDB, _ := dbm.NewGoLevelDB("Simulation-2", dir)
|
||||
defer func() {
|
||||
newDB.Close()
|
||||
os.RemoveAll(newDir)
|
||||
}()
|
||||
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil)
|
||||
require.Equal(t, "GaiaApp", newApp.Name())
|
||||
request := abci.RequestInitChain{
|
||||
AppStateBytes: appState,
|
||||
}
|
||||
newApp.InitChain(request)
|
||||
newApp.Commit()
|
||||
|
||||
fmt.Printf("Comparing stores...\n")
|
||||
ctxA := app.NewContext(true, abci.Header{})
|
||||
ctxB := newApp.NewContext(true, abci.Header{})
|
||||
type StoreKeysPrefixes struct {
|
||||
A sdk.StoreKey
|
||||
B sdk.StoreKey
|
||||
Prefixes [][]byte
|
||||
}
|
||||
storeKeysPrefixes := []StoreKeysPrefixes{
|
||||
{app.keyMain, newApp.keyMain, [][]byte{}},
|
||||
{app.keyAccount, newApp.keyAccount, [][]byte{}},
|
||||
{app.keyStake, newApp.keyStake, [][]byte{stake.UnbondingQueueKey, stake.RedelegationQueueKey, stake.ValidatorQueueKey}}, // ordering may change but it doesn't matter
|
||||
{app.keySlashing, newApp.keySlashing, [][]byte{}},
|
||||
{app.keyMint, newApp.keyMint, [][]byte{}},
|
||||
{app.keyDistr, newApp.keyDistr, [][]byte{}},
|
||||
{app.keyFeeCollection, newApp.keyFeeCollection, [][]byte{}},
|
||||
{app.keyParams, newApp.keyParams, [][]byte{}},
|
||||
{app.keyGov, newApp.keyGov, [][]byte{}},
|
||||
}
|
||||
for _, storeKeysPrefix := range storeKeysPrefixes {
|
||||
storeKeyA := storeKeysPrefix.A
|
||||
storeKeyB := storeKeysPrefix.B
|
||||
prefixes := storeKeysPrefix.Prefixes
|
||||
storeA := ctxA.KVStore(storeKeyA)
|
||||
storeB := ctxB.KVStore(storeKeyB)
|
||||
kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB, prefixes)
|
||||
fmt.Printf("Compared %d key/value pairs between %s and %s\n", count, storeKeyA, storeKeyB)
|
||||
require.True(t, equal, "unequal stores: %s / %s:\nstore A %s (%X) => %s (%X)\nstore B %s (%X) => %s (%X)",
|
||||
storeKeyA, storeKeyB, kvA.Key, kvA.Key, kvA.Value, kvA.Value, kvB.Key, kvB.Key, kvB.Value, kvB.Value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO: Make another test for the fuzzer itself, which just has noOp txs
|
||||
// and doesn't depend on gaia
|
||||
func TestAppStateDeterminism(t *testing.T) {
|
||||
|
|
|
@ -113,6 +113,6 @@ func genAppStateFromConfig(
|
|||
return
|
||||
}
|
||||
|
||||
err = WriteGenesisFile(genFile, initCfg.ChainID, nil, appState)
|
||||
err = ExportGenesisFile(genFile, initCfg.ChainID, nil, appState)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
viper.GetBool(flagOverwrite)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = WriteGenesisFile(genFile, chainID, nil, appState); err != nil {
|
||||
if err = ExportGenesisFile(genFile, chainID, nil, appState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -298,7 +298,7 @@ func collectGenFiles(
|
|||
genFile := config.GenesisFile()
|
||||
|
||||
// overwrite each validator's genesis file to have a canonical genesis time
|
||||
err = WriteGenesisFileWithTime(genFile, chainID, nil, appState, genTime)
|
||||
err = ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ import (
|
|||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// WriteGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// ExportGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// error is returned if building or writing the configuration to file fails.
|
||||
func WriteGenesisFile(
|
||||
func ExportGenesisFile(
|
||||
genFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage,
|
||||
) error {
|
||||
|
||||
|
@ -36,9 +36,9 @@ func WriteGenesisFile(
|
|||
return genDoc.SaveAs(genFile)
|
||||
}
|
||||
|
||||
// WriteGenesisFileWithTime creates and writes the genesis configuration to disk.
|
||||
// ExportGenesisFileWithTime creates and writes the genesis configuration to disk.
|
||||
// An error is returned if building or writing the configuration to file fails.
|
||||
func WriteGenesisFileWithTime(
|
||||
func ExportGenesisFileWithTime(
|
||||
genFile, chainID string, validators []types.GenesisValidator,
|
||||
appState json.RawMessage, genTime time.Time,
|
||||
) error {
|
||||
|
|
|
@ -7,7 +7,7 @@ The staking module allow for the following hooks to be registered with staking e
|
|||
type StakingHooks interface {
|
||||
OnValidatorCreated(ctx Context, address ValAddress) // Must be called when a validator is created
|
||||
OnValidatorModified(ctx Context, address ValAddress) // Must be called when a validator's state changes
|
||||
OnValidatorRemoved(ctx Context, address ValAddress) // Must be called when a validator is deleted
|
||||
OnValidatorRemoved(ctx Context, address ConsAddress, operator ValAddress) // Must be called when a validator is deleted
|
||||
|
||||
OnValidatorBonded(ctx Context, address ConsAddress) // called when a validator is bonded
|
||||
OnValidatorBeginUnbonding(ctx Context, address ConsAddress, operator ValAddress) // called when a validator begins unbonding
|
||||
|
|
|
@ -108,7 +108,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||
return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID,
|
||||
return gaiaInit.ExportGenesisFile(config.GenesisFile(), chainID,
|
||||
[]tmtypes.GenesisValidator{validator}, appStateJSON)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -186,8 +186,8 @@ func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage,
|
|||
|
||||
genState := types.GenesisState{
|
||||
Accounts: accounts,
|
||||
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
|
||||
CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper),
|
||||
POWGenesis: pow.ExportGenesis(ctx, app.powKeeper),
|
||||
CoolGenesis: cool.ExportGenesis(ctx, app.coolKeeper),
|
||||
}
|
||||
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
||||
if err != nil {
|
||||
|
|
|
@ -115,7 +115,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||
return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID,
|
||||
return gaiaInit.ExportGenesisFile(config.GenesisFile(), chainID,
|
||||
[]tmtypes.GenesisValidator{validator}, appStateJSON)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, data Genesis) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// WriteGenesis - output the genesis trend
|
||||
func WriteGenesis(ctx sdk.Context, k Keeper) Genesis {
|
||||
// ExportGenesis - output the genesis trend
|
||||
func ExportGenesis(ctx sdk.Context, k Keeper) Genesis {
|
||||
trend := k.GetTrend(ctx)
|
||||
return Genesis{trend}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ func TestCoolKeeper(t *testing.T) {
|
|||
err := InitGenesis(ctx, keeper, Genesis{"icy"})
|
||||
require.Nil(t, err)
|
||||
|
||||
genesis := WriteGenesis(ctx, keeper)
|
||||
genesis := ExportGenesis(ctx, keeper)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, genesis, Genesis{"icy"})
|
||||
|
||||
|
|
|
@ -43,8 +43,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, genesis Genesis) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// WriteGenesis for the PoW module
|
||||
func WriteGenesis(ctx sdk.Context, k Keeper) Genesis {
|
||||
// ExportGenesis for the PoW module
|
||||
func ExportGenesis(ctx sdk.Context, k Keeper) Genesis {
|
||||
difficulty, err := k.GetLastDifficulty(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
@ -41,7 +41,7 @@ func TestPowKeeperGetSet(t *testing.T) {
|
|||
err := InitGenesis(ctx, keeper, Genesis{uint64(1), uint64(0)})
|
||||
require.Nil(t, err)
|
||||
|
||||
genesis := WriteGenesis(ctx, keeper)
|
||||
genesis := ExportGenesis(ctx, keeper)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, genesis, Genesis{uint64(1), uint64(0)})
|
||||
|
||||
|
|
|
@ -115,9 +115,9 @@ type DelegationSet interface {
|
|||
|
||||
// event hooks for staking validator object
|
||||
type StakingHooks interface {
|
||||
OnValidatorCreated(ctx Context, valAddr ValAddress) // Must be called when a validator is created
|
||||
OnValidatorModified(ctx Context, valAddr ValAddress) // Must be called when a validator's state changes
|
||||
OnValidatorRemoved(ctx Context, valAddr ValAddress) // Must be called when a validator is deleted
|
||||
OnValidatorCreated(ctx Context, valAddr ValAddress) // Must be called when a validator is created
|
||||
OnValidatorModified(ctx Context, valAddr ValAddress) // Must be called when a validator's state changes
|
||||
OnValidatorRemoved(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is deleted
|
||||
|
||||
OnValidatorBonded(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is bonded
|
||||
OnValidatorBeginUnbonding(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator begins unbonding
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
|
@ -176,6 +177,43 @@ func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator {
|
|||
return kvs.ReverseIterator(prefix, PrefixEndBytes(prefix))
|
||||
}
|
||||
|
||||
// Compare two KVstores, return either the first key/value pair
|
||||
// at which they differ and whether or not they are equal, skipping
|
||||
// value comparison for a set of provided prefixes
|
||||
func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvA cmn.KVPair, kvB cmn.KVPair, count int64, equal bool) {
|
||||
iterA := a.Iterator(nil, nil)
|
||||
iterB := b.Iterator(nil, nil)
|
||||
count = int64(0)
|
||||
for {
|
||||
if !iterA.Valid() && !iterB.Valid() {
|
||||
break
|
||||
}
|
||||
var kvA, kvB cmn.KVPair
|
||||
if iterA.Valid() {
|
||||
kvA = cmn.KVPair{Key: iterA.Key(), Value: iterA.Value()}
|
||||
iterA.Next()
|
||||
}
|
||||
if iterB.Valid() {
|
||||
kvB = cmn.KVPair{Key: iterB.Key(), Value: iterB.Value()}
|
||||
iterB.Next()
|
||||
}
|
||||
compareValue := true
|
||||
for _, prefix := range prefixesToSkip {
|
||||
if bytes.Equal(kvA.Key[:len(prefix)], prefix) {
|
||||
compareValue = false
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(kvA.Key, kvB.Key) {
|
||||
return kvA, kvB, count, false
|
||||
}
|
||||
if compareValue && !bytes.Equal(kvA.Value, kvB.Value) {
|
||||
return kvA, kvB, count, false
|
||||
}
|
||||
count++
|
||||
}
|
||||
return cmn.KVPair{}, cmn.KVPair{}, count, true
|
||||
}
|
||||
|
||||
// CacheKVStore cache-wraps a KVStore. After calling .Write() on
|
||||
// the CacheKVStore, all previously created CacheKVStores on the
|
||||
// object expire.
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// GenesisState - all auth state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
CollectedFees sdk.Coins `json:"collected_fees"` // collected fees
|
||||
}
|
||||
|
||||
// Create a new genesis state
|
||||
func NewGenesisState(collectedFees sdk.Coins) GenesisState {
|
||||
return GenesisState{
|
||||
CollectedFees: collectedFees,
|
||||
}
|
||||
}
|
||||
|
||||
// Return a default genesis state
|
||||
func DefaultGenesisState() GenesisState {
|
||||
return NewGenesisState(sdk.Coins{})
|
||||
}
|
||||
|
||||
// Init store state from genesis data
|
||||
func InitGenesis(ctx sdk.Context, keeper FeeCollectionKeeper, data GenesisState) {
|
||||
keeper.setCollectedFees(ctx, data.CollectedFees)
|
||||
}
|
||||
|
||||
// ExportGenesis returns a GenesisState for a given context and keeper
|
||||
func ExportGenesis(ctx sdk.Context, keeper FeeCollectionKeeper) GenesisState {
|
||||
collectedFees := keeper.GetCollectedFees(ctx)
|
||||
return NewGenesisState(collectedFees)
|
||||
}
|
|
@ -21,11 +21,12 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
|
|||
for _, dw := range data.DelegatorWithdrawInfos {
|
||||
keeper.SetDelegatorWithdrawAddr(ctx, dw.DelegatorAddr, dw.WithdrawAddr)
|
||||
}
|
||||
keeper.SetPreviousProposerConsAddr(ctx, data.PreviousProposer)
|
||||
}
|
||||
|
||||
// WriteGenesis returns a GenesisState for a given context and keeper. The
|
||||
// ExportGenesis returns a GenesisState for a given context and keeper. The
|
||||
// GenesisState will contain the pool, and validator/delegator distribution info's
|
||||
func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
||||
func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
||||
feePool := keeper.GetFeePool(ctx)
|
||||
communityTax := keeper.GetCommunityTax(ctx)
|
||||
baseProposerRewards := keeper.GetBaseProposerReward(ctx)
|
||||
|
@ -33,6 +34,7 @@ func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
|||
vdis := keeper.GetAllValidatorDistInfos(ctx)
|
||||
ddis := keeper.GetAllDelegationDistInfos(ctx)
|
||||
dwis := keeper.GetAllDelegatorWithdrawInfos(ctx)
|
||||
pp := keeper.GetPreviousProposerConsAddr(ctx)
|
||||
return NewGenesisState(feePool, communityTax, baseProposerRewards,
|
||||
bonusProposerRewards, vdis, ddis, dwis)
|
||||
bonusProposerRewards, vdis, ddis, dwis, pp)
|
||||
}
|
||||
|
|
|
@ -36,12 +36,12 @@ func (k Keeper) GetAllDelegationDistInfos(ctx sdk.Context) (ddis []types.Delegat
|
|||
// Get the set of all delegator-withdraw addresses with no limits, used during genesis dump
|
||||
func (k Keeper) GetAllDelegatorWithdrawInfos(ctx sdk.Context) (dwis []types.DelegatorWithdrawInfo) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, DelegationDistInfoKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, DelegatorWithdrawInfoKey)
|
||||
defer iterator.Close()
|
||||
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
dw := types.DelegatorWithdrawInfo{
|
||||
DelegatorAddr: sdk.AccAddress(iterator.Key()),
|
||||
DelegatorAddr: GetDelegatorWithdrawInfoAddress(iterator.Key()),
|
||||
WithdrawAddr: sdk.AccAddress(iterator.Value()),
|
||||
}
|
||||
dwis = append(dwis, dw)
|
||||
|
|
|
@ -103,7 +103,7 @@ func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
|
|||
func (h Hooks) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
h.k.onValidatorModified(ctx, valAddr)
|
||||
}
|
||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||
h.k.onValidatorRemoved(ctx, valAddr)
|
||||
}
|
||||
func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
|
|
|
@ -44,3 +44,12 @@ func GetDelegationDistInfosKey(delAddr sdk.AccAddress) []byte {
|
|||
func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte {
|
||||
return append(DelegatorWithdrawInfoKey, delAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// gets an address from a delegator's withdraw info key
|
||||
func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) {
|
||||
addr := key[1:]
|
||||
if len(addr) != sdk.AddrLen {
|
||||
panic("unexpected key length")
|
||||
}
|
||||
return sdk.AccAddress(addr)
|
||||
}
|
||||
|
|
|
@ -18,10 +18,11 @@ type GenesisState struct {
|
|||
ValidatorDistInfos []ValidatorDistInfo `json:"validator_dist_infos"`
|
||||
DelegationDistInfos []DelegationDistInfo `json:"delegator_dist_infos"`
|
||||
DelegatorWithdrawInfos []DelegatorWithdrawInfo `json:"delegator_withdraw_infos"`
|
||||
PreviousProposer sdk.ConsAddress `json:"previous_proposer"`
|
||||
}
|
||||
|
||||
func NewGenesisState(feePool FeePool, communityTax, baseProposerReward, bonusProposerReward sdk.Dec,
|
||||
vdis []ValidatorDistInfo, ddis []DelegationDistInfo, dwis []DelegatorWithdrawInfo) GenesisState {
|
||||
vdis []ValidatorDistInfo, ddis []DelegationDistInfo, dwis []DelegatorWithdrawInfo, pp sdk.ConsAddress) GenesisState {
|
||||
|
||||
return GenesisState{
|
||||
FeePool: feePool,
|
||||
|
@ -31,6 +32,7 @@ func NewGenesisState(feePool FeePool, communityTax, baseProposerReward, bonusPro
|
|||
ValidatorDistInfos: vdis,
|
||||
DelegationDistInfos: ddis,
|
||||
DelegatorWithdrawInfos: dwis,
|
||||
PreviousProposer: pp,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,10 +8,25 @@ import (
|
|||
|
||||
// GenesisState - all staking state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
StartingProposalID uint64 `json:"starting_proposalID"`
|
||||
DepositParams DepositParams `json:"deposit_params"`
|
||||
VotingParams VotingParams `json:"voting_params"`
|
||||
TallyParams TallyParams `json:"tally_params"`
|
||||
StartingProposalID uint64 `json:"starting_proposal_id"`
|
||||
Deposits []DepositWithMetadata `json:"deposits"`
|
||||
Votes []VoteWithMetadata `json:"votes"`
|
||||
Proposals []Proposal `json:"proposals"`
|
||||
DepositParams DepositParams `json:"deposit_params"`
|
||||
VotingParams VotingParams `json:"voting_params"`
|
||||
TallyParams TallyParams `json:"tally_params"`
|
||||
}
|
||||
|
||||
// DepositWithMetadata (just for genesis)
|
||||
type DepositWithMetadata struct {
|
||||
ProposalID uint64 `json:"proposal_id"`
|
||||
Deposit Deposit `json:"deposit"`
|
||||
}
|
||||
|
||||
// VoteWithMetadata (just for genesis)
|
||||
type VoteWithMetadata struct {
|
||||
ProposalID uint64 `json:"proposal_id"`
|
||||
Vote Vote `json:"vote"`
|
||||
}
|
||||
|
||||
func NewGenesisState(startingProposalID uint64, dp DepositParams, vp VotingParams, tp TallyParams) GenesisState {
|
||||
|
@ -52,17 +67,47 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
|||
k.setDepositParams(ctx, data.DepositParams)
|
||||
k.setVotingParams(ctx, data.VotingParams)
|
||||
k.setTallyParams(ctx, data.TallyParams)
|
||||
for _, deposit := range data.Deposits {
|
||||
k.setDeposit(ctx, deposit.ProposalID, deposit.Deposit.Depositer, deposit.Deposit)
|
||||
}
|
||||
for _, vote := range data.Votes {
|
||||
k.setVote(ctx, vote.ProposalID, vote.Vote.Voter, vote.Vote)
|
||||
}
|
||||
for _, proposal := range data.Proposals {
|
||||
k.SetProposal(ctx, proposal)
|
||||
}
|
||||
}
|
||||
|
||||
// WriteGenesis - output genesis parameters
|
||||
func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState {
|
||||
startingProposalID, _ := k.getNewProposalID(ctx)
|
||||
// ExportGenesis - output genesis parameters
|
||||
func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
|
||||
startingProposalID, _ := k.peekCurrentProposalID(ctx)
|
||||
depositParams := k.GetDepositParams(ctx)
|
||||
votingParams := k.GetVotingParams(ctx)
|
||||
tallyParams := k.GetTallyParams(ctx)
|
||||
var deposits []DepositWithMetadata
|
||||
var votes []VoteWithMetadata
|
||||
proposals := k.GetProposalsFiltered(ctx, nil, nil, StatusNil, 0)
|
||||
for _, proposal := range proposals {
|
||||
proposalID := proposal.GetProposalID()
|
||||
depositsIterator := k.GetDeposits(ctx, proposalID)
|
||||
for ; depositsIterator.Valid(); depositsIterator.Next() {
|
||||
var deposit Deposit
|
||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), &deposit)
|
||||
deposits = append(deposits, DepositWithMetadata{proposalID, deposit})
|
||||
}
|
||||
votesIterator := k.GetVotes(ctx, proposalID)
|
||||
for ; votesIterator.Valid(); votesIterator.Next() {
|
||||
var vote Vote
|
||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(votesIterator.Value(), &vote)
|
||||
votes = append(votes, VoteWithMetadata{proposalID, vote})
|
||||
}
|
||||
}
|
||||
|
||||
return GenesisState{
|
||||
StartingProposalID: startingProposalID,
|
||||
Deposits: deposits,
|
||||
Votes: votes,
|
||||
Proposals: proposals,
|
||||
DepositParams: depositParams,
|
||||
VotingParams: votingParams,
|
||||
TallyParams: tallyParams,
|
||||
|
|
|
@ -107,8 +107,8 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
|
|||
var proposalID uint64
|
||||
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID)
|
||||
inactiveProposal := keeper.GetProposal(ctx, proposalID)
|
||||
keeper.RefundDeposits(ctx, proposalID)
|
||||
keeper.DeleteProposal(ctx, proposalID)
|
||||
keeper.DeleteDeposits(ctx, proposalID) // delete any associated deposits (burned)
|
||||
|
||||
resTags = resTags.AppendTag(tags.Action, tags.ActionProposalDropped)
|
||||
resTags = resTags.AppendTag(tags.ProposalID, []byte(string(proposalID)))
|
||||
|
|
|
@ -31,9 +31,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) {
|
|||
keeper.SetParams(ctx, data.Params)
|
||||
}
|
||||
|
||||
// WriteGenesis returns a GenesisState for a given context and keeper. The
|
||||
// ExportGenesis returns a GenesisState for a given context and keeper. The
|
||||
// GenesisState will contain the pool, and validator/delegator distribution info's
|
||||
func WriteGenesis(ctx sdk.Context, keeper Keeper) GenesisState {
|
||||
func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState {
|
||||
|
||||
minter := keeper.GetMinter(ctx)
|
||||
params := keeper.GetParams(ctx)
|
||||
|
|
|
@ -7,13 +7,25 @@ import (
|
|||
|
||||
// GenesisState - all slashing state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
Params Params
|
||||
Params Params
|
||||
SigningInfos map[string]ValidatorSigningInfo
|
||||
MissedBlocks map[string][]MissedBlock
|
||||
SlashingPeriods []ValidatorSlashingPeriod
|
||||
}
|
||||
|
||||
// MissedBlock
|
||||
type MissedBlock struct {
|
||||
Index int64 `json:"index"`
|
||||
Missed bool `json:"missed"`
|
||||
}
|
||||
|
||||
// HubDefaultGenesisState - default GenesisState used by Cosmos Hub
|
||||
func DefaultGenesisState() GenesisState {
|
||||
return GenesisState{
|
||||
Params: DefaultParams(),
|
||||
Params: DefaultParams(),
|
||||
SigningInfos: make(map[string]ValidatorSigningInfo),
|
||||
MissedBlocks: make(map[string][]MissedBlock),
|
||||
SlashingPeriods: []ValidatorSlashingPeriod{},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,5 +36,64 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState, sdata types.
|
|||
keeper.addPubkey(ctx, validator.GetConsPubKey())
|
||||
}
|
||||
|
||||
for addr, info := range data.SigningInfos {
|
||||
address, err := sdk.ConsAddressFromBech32(addr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
keeper.setValidatorSigningInfo(ctx, address, info)
|
||||
}
|
||||
|
||||
for addr, array := range data.MissedBlocks {
|
||||
address, err := sdk.ConsAddressFromBech32(addr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, missed := range array {
|
||||
keeper.setValidatorMissedBlockBitArray(ctx, address, missed.Index, missed.Missed)
|
||||
}
|
||||
}
|
||||
|
||||
for _, slashingPeriod := range data.SlashingPeriods {
|
||||
keeper.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod)
|
||||
}
|
||||
|
||||
keeper.paramspace.SetParamSet(ctx, &data.Params)
|
||||
}
|
||||
|
||||
// ExportGenesis writes the current store values
|
||||
// to a genesis file, which can be imported again
|
||||
// with InitGenesis
|
||||
func ExportGenesis(ctx sdk.Context, keeper Keeper) (data GenesisState) {
|
||||
var params Params
|
||||
keeper.paramspace.GetParamSet(ctx, ¶ms)
|
||||
|
||||
signingInfos := make(map[string]ValidatorSigningInfo)
|
||||
missedBlocks := make(map[string][]MissedBlock)
|
||||
keeper.iterateValidatorSigningInfos(ctx, func(address sdk.ConsAddress, info ValidatorSigningInfo) (stop bool) {
|
||||
bechAddr := address.String()
|
||||
signingInfos[bechAddr] = info
|
||||
array := []MissedBlock{}
|
||||
|
||||
keeper.iterateValidatorMissedBlockBitArray(ctx, address, func(index int64, missed bool) (stop bool) {
|
||||
array = append(array, MissedBlock{index, missed})
|
||||
return false
|
||||
})
|
||||
missedBlocks[bechAddr] = array
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
slashingPeriods := []ValidatorSlashingPeriod{}
|
||||
keeper.iterateValidatorSlashingPeriods(ctx, func(slashingPeriod ValidatorSlashingPeriod) (stop bool) {
|
||||
slashingPeriods = append(slashingPeriods, slashingPeriod)
|
||||
return false
|
||||
})
|
||||
|
||||
return GenesisState{
|
||||
Params: params,
|
||||
SigningInfos: signingInfos,
|
||||
MissedBlocks: missedBlocks,
|
||||
SlashingPeriods: slashingPeriods,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package slashing
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
|
@ -36,6 +38,17 @@ func (k Keeper) onValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddre
|
|||
k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod)
|
||||
}
|
||||
|
||||
// When a validator is created, add the address-pubkey relation.
|
||||
func (k Keeper) onValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
validator := k.validatorSet.Validator(ctx, valAddr)
|
||||
k.addPubkey(ctx, validator.GetConsPubKey())
|
||||
}
|
||||
|
||||
// When a validator is removed, delete the address-pubkey relation.
|
||||
func (k Keeper) onValidatorRemoved(ctx sdk.Context, address sdk.ConsAddress) {
|
||||
k.deleteAddrPubkeyRelation(ctx, crypto.Address(address))
|
||||
}
|
||||
|
||||
//_________________________________________________________________________________________
|
||||
|
||||
// Wrapper struct
|
||||
|
@ -60,12 +73,20 @@ func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddre
|
|||
h.k.onValidatorBeginUnbonding(ctx, consAddr, valAddr)
|
||||
}
|
||||
|
||||
// Implements sdk.ValidatorHooks
|
||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, _ sdk.ValAddress) {
|
||||
h.k.onValidatorRemoved(ctx, consAddr)
|
||||
}
|
||||
|
||||
// Implements sdk.ValidatorHooks
|
||||
func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
h.k.onValidatorCreated(ctx, valAddr)
|
||||
}
|
||||
|
||||
// nolint - unused hooks
|
||||
func (h Hooks) OnValidatorPowerDidChange(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||
}
|
||||
func (h Hooks) OnValidatorCreated(_ sdk.Context, _ sdk.ValAddress) {}
|
||||
func (h Hooks) OnValidatorModified(_ sdk.Context, _ sdk.ValAddress) {}
|
||||
func (h Hooks) OnValidatorRemoved(_ sdk.Context, _ sdk.ValAddress) {}
|
||||
func (h Hooks) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
|
||||
func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
|
||||
func (h Hooks) OnDelegationRemoved(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
|
||||
|
|
|
@ -4,13 +4,10 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
stake "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
)
|
||||
|
||||
|
@ -174,19 +171,6 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
|
|||
k.setValidatorSigningInfo(ctx, consAddr, signInfo)
|
||||
}
|
||||
|
||||
// AddValidators adds the validators to the keepers validator addr to pubkey mapping.
|
||||
func (k Keeper) AddValidators(ctx sdk.Context, vals []abci.ValidatorUpdate) {
|
||||
for i := 0; i < len(vals); i++ {
|
||||
val := vals[i]
|
||||
pubkey, err := tmtypes.PB2TM.PubKey(val.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
k.addPubkey(ctx, pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make a method to remove the pubkey from the map when a validator is unbonded.
|
||||
func (k Keeper) addPubkey(ctx sdk.Context, pubkey crypto.PubKey) {
|
||||
addr := pubkey.Address()
|
||||
k.setAddrPubkeyRelation(ctx, addr, pubkey)
|
||||
|
|
|
@ -34,8 +34,7 @@ func TestHandleDoubleSign(t *testing.T) {
|
|||
operatorAddr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||
got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(operatorAddr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
stake.EndBlocker(ctx, sk)
|
||||
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(operatorAddr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, operatorAddr).GetPower()))
|
||||
|
||||
|
@ -75,9 +74,8 @@ func TestSlashingPeriodCap(t *testing.T) {
|
|||
valConsPubKey, valConsAddr := pks[0], pks[0].Address()
|
||||
got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(operatorAddr, valConsPubKey, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
stake.EndBlocker(ctx, sk)
|
||||
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(operatorAddr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, operatorAddr).GetPower()))
|
||||
|
||||
|
@ -141,8 +139,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
|||
slh := NewHandler(keeper)
|
||||
got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
stake.EndBlocker(ctx, sk)
|
||||
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
|
||||
// will exist since the validator has been bonded
|
||||
|
@ -298,8 +295,7 @@ func TestHandleNewValidator(t *testing.T) {
|
|||
// Validator created
|
||||
got := sh(ctx, NewTestMsgCreateValidator(addr, val, sdk.NewInt(amt)))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
stake.EndBlocker(ctx, sk)
|
||||
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}})
|
||||
require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower())
|
||||
|
||||
|
@ -333,8 +329,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
|||
sh := stake.NewHandler(sk)
|
||||
got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
// 1000 first blocks OK
|
||||
height := int64(0)
|
||||
|
@ -386,8 +381,7 @@ func TestValidatorDippingInAndOut(t *testing.T) {
|
|||
sh := stake.NewHandler(sk)
|
||||
got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
stake.EndBlocker(ctx, sk)
|
||||
|
||||
// 100 first blocks OK
|
||||
height := int64(0)
|
||||
|
@ -400,9 +394,8 @@ func TestValidatorDippingInAndOut(t *testing.T) {
|
|||
newAmt := int64(101)
|
||||
got = sh(ctx, NewTestMsgCreateValidator(addrs[1], pks[1], sdk.NewInt(newAmt)))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates = stake.EndBlocker(ctx, sk)
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
require.Equal(t, 2, len(validatorUpdates))
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
validator, _ := sk.GetValidator(ctx, addr)
|
||||
require.Equal(t, sdk.Unbonding, validator.Status)
|
||||
|
||||
|
|
|
@ -20,6 +20,15 @@ func GetValidatorSigningInfoKey(v sdk.ConsAddress) []byte {
|
|||
return append(ValidatorSigningInfoKey, v.Bytes()...)
|
||||
}
|
||||
|
||||
// extract the address from a validator signing info key
|
||||
func GetValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) {
|
||||
addr := key[1:]
|
||||
if len(addr) != sdk.AddrLen {
|
||||
panic("unexpected key length")
|
||||
}
|
||||
return sdk.ConsAddress(addr)
|
||||
}
|
||||
|
||||
// stored by *Tendermint* address (not operator address)
|
||||
func GetValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte {
|
||||
return append(ValidatorMissedBlockBitArrayKey, v.Bytes()...)
|
||||
|
|
|
@ -20,6 +20,21 @@ func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress
|
|||
return
|
||||
}
|
||||
|
||||
// Stored by *validator* address (not operator address)
|
||||
func (k Keeper) iterateValidatorSigningInfos(ctx sdk.Context, handler func(address sdk.ConsAddress, info ValidatorSigningInfo) (stop bool)) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iter := sdk.KVStorePrefixIterator(store, ValidatorSigningInfoKey)
|
||||
defer iter.Close()
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
address := GetValidatorSigningInfoAddress(iter.Key())
|
||||
var info ValidatorSigningInfo
|
||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &info)
|
||||
if handler(address, info) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stored by *validator* address (not operator address)
|
||||
func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress, info ValidatorSigningInfo) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
@ -40,6 +55,24 @@ func (k Keeper) getValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.Con
|
|||
return
|
||||
}
|
||||
|
||||
// Stored by *validator* address (not operator address)
|
||||
func (k Keeper) iterateValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, handler func(index int64, missed bool) (stop bool)) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
index := int64(0)
|
||||
// Array may be sparse
|
||||
for ; index < k.SignedBlocksWindow(ctx); index++ {
|
||||
var missed bool
|
||||
bz := store.Get(GetValidatorMissedBlockBitArrayKey(address, index))
|
||||
if bz == nil {
|
||||
continue
|
||||
}
|
||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &missed)
|
||||
if handler(index, missed) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stored by *validator* address (not operator address)
|
||||
func (k Keeper) setValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64, missed bool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
|
|
@ -51,6 +51,21 @@ func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk
|
|||
return
|
||||
}
|
||||
|
||||
// Iterate over all slashing periods in the store, calling on each
|
||||
// decode slashing period a provided handler function
|
||||
// Stop if the provided handler function returns true
|
||||
func (k Keeper) iterateValidatorSlashingPeriods(ctx sdk.Context, handler func(slashingPeriod ValidatorSlashingPeriod) (stop bool)) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iter := sdk.KVStorePrefixIterator(store, ValidatorSlashingPeriodKey)
|
||||
defer iter.Close()
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
slashingPeriod := k.unmarshalSlashingPeriodKeyValue(iter.Key(), iter.Value())
|
||||
if handler(slashingPeriod) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stored by validator Tendermint address (not operator address)
|
||||
// This function sets a validator slashing period for a particular validator,
|
||||
// start height, end height, and current slashed-so-far total, or updates
|
||||
|
|
|
@ -91,7 +91,7 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s
|
|||
sk.SetHooks(keeper.Hooks())
|
||||
|
||||
require.NotPanics(t, func() {
|
||||
InitGenesis(ctx, keeper, GenesisState{defaults}, genesis)
|
||||
InitGenesis(ctx, keeper, GenesisState{defaults, nil, nil, nil}, genesis)
|
||||
})
|
||||
|
||||
return ctx, ck, sk, paramstore, keeper
|
||||
|
|
|
@ -19,8 +19,7 @@ func TestBeginBlocker(t *testing.T) {
|
|||
// bond the validator
|
||||
got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(addr, pk, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
stake.EndBlocker(ctx, sk)
|
||||
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@ package stake
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// InitGenesis sets the pool and parameters for the provided keeper and
|
||||
|
@ -26,22 +26,33 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
|
|||
|
||||
keeper.SetPool(ctx, data.Pool)
|
||||
keeper.SetParams(ctx, data.Params)
|
||||
keeper.SetIntraTxCounter(ctx, data.IntraTxCounter)
|
||||
keeper.SetLastTotalPower(ctx, data.LastTotalPower)
|
||||
|
||||
// We only need to set this if we're starting from a list of validators, not a state export
|
||||
setBondIntraTxCounter := true
|
||||
for _, validator := range data.Validators {
|
||||
if validator.BondIntraTxCounter != 0 {
|
||||
setBondIntraTxCounter = false
|
||||
}
|
||||
}
|
||||
|
||||
for i, validator := range data.Validators {
|
||||
validator.BondIntraTxCounter = int16(i) // set the intra-tx counter to the order the validators are presented
|
||||
// set the intra-tx counter to the order the validators are presented, if necessary
|
||||
if setBondIntraTxCounter {
|
||||
validator.BondIntraTxCounter = int16(i)
|
||||
}
|
||||
keeper.SetValidator(ctx, validator)
|
||||
|
||||
if validator.Tokens.IsZero() {
|
||||
return res, errors.Errorf("genesis validator cannot have zero pool shares, validator: %v", validator)
|
||||
}
|
||||
if validator.DelegatorShares.IsZero() {
|
||||
return res, errors.Errorf("genesis validator cannot have zero delegator shares, validator: %v", validator)
|
||||
}
|
||||
|
||||
// Manually set indices for the first time
|
||||
keeper.SetValidatorByConsAddr(ctx, validator)
|
||||
keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool)
|
||||
keeper.OnValidatorCreated(ctx, validator.OperatorAddr)
|
||||
|
||||
// Set timeslice if necessary
|
||||
if validator.Status == sdk.Unbonding {
|
||||
keeper.InsertValidatorQueue(ctx, validator)
|
||||
}
|
||||
}
|
||||
|
||||
for _, delegation := range data.Bonds {
|
||||
|
@ -49,24 +60,56 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
|
|||
keeper.OnDelegationCreated(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
|
||||
}
|
||||
|
||||
sort.SliceStable(data.UnbondingDelegations[:], func(i, j int) bool {
|
||||
return data.UnbondingDelegations[i].CreationHeight < data.UnbondingDelegations[j].CreationHeight
|
||||
})
|
||||
for _, ubd := range data.UnbondingDelegations {
|
||||
keeper.SetUnbondingDelegation(ctx, ubd)
|
||||
keeper.InsertUnbondingQueue(ctx, ubd)
|
||||
}
|
||||
|
||||
sort.SliceStable(data.Redelegations[:], func(i, j int) bool {
|
||||
return data.Redelegations[i].CreationHeight < data.Redelegations[j].CreationHeight
|
||||
})
|
||||
for _, red := range data.Redelegations {
|
||||
keeper.SetRedelegation(ctx, red)
|
||||
keeper.InsertRedelegationQueue(ctx, red)
|
||||
}
|
||||
|
||||
res = keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
// WriteGenesis returns a GenesisState for a given context and keeper. The
|
||||
// ExportGenesis returns a GenesisState for a given context and keeper. The
|
||||
// GenesisState will contain the pool, params, validators, and bonds found in
|
||||
// the keeper.
|
||||
func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
||||
func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
|
||||
pool := keeper.GetPool(ctx)
|
||||
params := keeper.GetParams(ctx)
|
||||
intraTxCounter := keeper.GetIntraTxCounter(ctx)
|
||||
lastTotalPower := keeper.GetLastTotalPower(ctx)
|
||||
validators := keeper.GetAllValidators(ctx)
|
||||
bonds := keeper.GetAllDelegations(ctx)
|
||||
var unbondingDelegations []types.UnbondingDelegation
|
||||
keeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) (stop bool) {
|
||||
unbondingDelegations = append(unbondingDelegations, ubd)
|
||||
return false
|
||||
})
|
||||
var redelegations []types.Redelegation
|
||||
keeper.IterateRedelegations(ctx, func(_ int64, red types.Redelegation) (stop bool) {
|
||||
redelegations = append(redelegations, red)
|
||||
return false
|
||||
})
|
||||
|
||||
return types.GenesisState{
|
||||
Pool: pool,
|
||||
Params: params,
|
||||
Validators: validators,
|
||||
Bonds: bonds,
|
||||
Pool: pool,
|
||||
Params: params,
|
||||
IntraTxCounter: intraTxCounter,
|
||||
LastTotalPower: lastTotalPower,
|
||||
Validators: validators,
|
||||
Bonds: bonds,
|
||||
UnbondingDelegations: unbondingDelegations,
|
||||
Redelegations: redelegations,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,11 +161,8 @@ func validateGenesisStateValidators(validators []types.Validator) (err error) {
|
|||
if val.Jailed && val.Status == sdk.Bonded {
|
||||
return fmt.Errorf("validator is bonded and jailed in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress())
|
||||
}
|
||||
if val.Tokens.IsZero() {
|
||||
return fmt.Errorf("genesis validator cannot have zero pool shares, validator: %v", val)
|
||||
}
|
||||
if val.DelegatorShares.IsZero() {
|
||||
return fmt.Errorf("genesis validator cannot have zero delegator shares, validator: %v", val)
|
||||
if val.DelegatorShares.IsZero() && val.Status != sdk.Unbonding {
|
||||
return fmt.Errorf("bonded/unbonded genesis validator cannot have zero delegator shares, validator: %v", val)
|
||||
}
|
||||
addrMap[strKey] = true
|
||||
}
|
||||
|
|
|
@ -22,29 +22,28 @@ func TestInitGenesis(t *testing.T) {
|
|||
pool.BondedTokens = sdk.NewDec(2)
|
||||
|
||||
params := keeper.GetParams(ctx)
|
||||
validators := make([]Validator, 2)
|
||||
var delegations []Delegation
|
||||
|
||||
validators := []Validator{
|
||||
NewValidator(sdk.ValAddress(keep.Addrs[0]), keep.PKs[0], Description{Moniker: "hoop"}),
|
||||
NewValidator(sdk.ValAddress(keep.Addrs[1]), keep.PKs[1], Description{Moniker: "bloop"}),
|
||||
}
|
||||
genesisState := types.NewGenesisState(pool, params, validators, delegations)
|
||||
_, err := InitGenesis(ctx, keeper, genesisState)
|
||||
require.Error(t, err)
|
||||
|
||||
// initialize the validators
|
||||
validators[0].OperatorAddr = sdk.ValAddress(keep.Addrs[0])
|
||||
validators[0].ConsPubKey = keep.PKs[0]
|
||||
validators[0].Description = Description{Moniker: "hoop"}
|
||||
validators[0].Status = sdk.Bonded
|
||||
validators[0].Tokens = sdk.OneDec()
|
||||
validators[0].DelegatorShares = sdk.OneDec()
|
||||
validators[1].OperatorAddr = sdk.ValAddress(keep.Addrs[1])
|
||||
validators[1].ConsPubKey = keep.PKs[1]
|
||||
validators[1].Description = Description{Moniker: "bloop"}
|
||||
validators[1].Status = sdk.Bonded
|
||||
validators[1].Tokens = sdk.OneDec()
|
||||
validators[1].DelegatorShares = sdk.OneDec()
|
||||
|
||||
genesisState = types.NewGenesisState(pool, params, validators, delegations)
|
||||
genesisState := types.NewGenesisState(pool, params, validators, delegations)
|
||||
vals, err := InitGenesis(ctx, keeper, genesisState)
|
||||
require.NoError(t, err)
|
||||
|
||||
actualGenesis := WriteGenesis(ctx, keeper)
|
||||
actualGenesis := ExportGenesis(ctx, keeper)
|
||||
require.Equal(t, genesisState.Pool, actualGenesis.Pool)
|
||||
require.Equal(t, genesisState.Params, actualGenesis.Params)
|
||||
require.Equal(t, genesisState.Bonds, actualGenesis.Bonds)
|
||||
|
@ -126,10 +125,6 @@ func TestValidateGenesis(t *testing.T) {
|
|||
(*data).Validators = genValidators1
|
||||
(*data).Validators = append((*data).Validators, genValidators1[0])
|
||||
}, true},
|
||||
{"no pool shares", func(data *types.GenesisState) {
|
||||
(*data).Validators = genValidators1
|
||||
(*data).Validators[0].Tokens = sdk.ZeroDec()
|
||||
}, true},
|
||||
{"no delegator shares", func(data *types.GenesisState) {
|
||||
(*data).Validators = genValidators1
|
||||
(*data).Validators[0].DelegatorShares = sdk.ZeroDec()
|
||||
|
|
|
@ -283,6 +283,21 @@ func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) {
|
|||
store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{})
|
||||
}
|
||||
|
||||
// iterate through all redelegations
|
||||
func (k Keeper) IterateRedelegations(ctx sdk.Context, fn func(index int64, red types.Redelegation) (stop bool)) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
iterator := sdk.KVStorePrefixIterator(store, RedelegationKey)
|
||||
defer iterator.Close()
|
||||
|
||||
for i := int64(0); iterator.Valid(); iterator.Next() {
|
||||
red := types.MustUnmarshalRED(k.cdc, iterator.Key(), iterator.Value())
|
||||
if stop := fn(i, red); stop {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// remove a redelegation object and associated index
|
||||
func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
|
|
@ -17,9 +17,9 @@ func (k Keeper) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
|
|||
}
|
||||
}
|
||||
|
||||
func (k Keeper) OnValidatorRemoved(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
func (k Keeper) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||
if k.hooks != nil {
|
||||
k.hooks.OnValidatorRemoved(ctx, valAddr)
|
||||
k.hooks.OnValidatorRemoved(ctx, consAddr, valAddr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -191,11 +191,13 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.
|
|||
validator, pool = validator.UpdateStatus(pool, sdk.Bonded)
|
||||
k.SetPool(ctx, pool)
|
||||
|
||||
// save the now bonded validator record to the three referenced stores
|
||||
// save the now bonded validator record to the two referenced stores
|
||||
k.SetValidator(ctx, validator)
|
||||
|
||||
k.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
|
||||
// delete from queue if present
|
||||
k.DeleteValidatorQueue(ctx, validator)
|
||||
|
||||
// call the bond hook if present
|
||||
if k.hooks != nil {
|
||||
k.hooks.OnValidatorBonded(ctx, validator.ConsAddress(), validator.OperatorAddr)
|
||||
|
@ -224,9 +226,8 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat
|
|||
validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
||||
validator.UnbondingHeight = ctx.BlockHeader().Height
|
||||
|
||||
// save the now unbonded validator record
|
||||
// save the now unbonded validator record and power index
|
||||
k.SetValidator(ctx, validator)
|
||||
|
||||
k.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||
|
||||
// Adds to unbonding validator queue
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"fmt"
|
||||
"time"
|
||||
|
@ -201,6 +202,11 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) {
|
|||
store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address())))
|
||||
store.Delete(GetValidatorsByPowerIndexKey(validator, pool))
|
||||
|
||||
// call hook if present
|
||||
if k.hooks != nil {
|
||||
k.hooks.OnValidatorRemoved(ctx, validator.ConsAddress(), validator.OperatorAddr)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//___________________________________________________________________________
|
||||
|
@ -320,6 +326,12 @@ func (k Keeper) SetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time,
|
|||
store.Set(GetValidatorQueueTimeKey(timestamp), bz)
|
||||
}
|
||||
|
||||
// Deletes a specific validator queue timeslice.
|
||||
func (k Keeper) DeleteValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Delete(GetValidatorQueueTimeKey(timestamp))
|
||||
}
|
||||
|
||||
// Insert an validator address to the appropriate timeslice in the validator queue
|
||||
func (k Keeper) InsertValidatorQueue(ctx sdk.Context, val types.Validator) {
|
||||
timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime)
|
||||
|
@ -331,6 +343,22 @@ func (k Keeper) InsertValidatorQueue(ctx sdk.Context, val types.Validator) {
|
|||
}
|
||||
}
|
||||
|
||||
// Delete a validator address from the validator queue
|
||||
func (k Keeper) DeleteValidatorQueue(ctx sdk.Context, val types.Validator) {
|
||||
timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime)
|
||||
newTimeSlice := []sdk.ValAddress{}
|
||||
for _, addr := range timeSlice {
|
||||
if !bytes.Equal(addr, val.OperatorAddr) {
|
||||
newTimeSlice = append(newTimeSlice, addr)
|
||||
}
|
||||
}
|
||||
if len(newTimeSlice) == 0 {
|
||||
k.DeleteValidatorQueueTimeSlice(ctx, val.UnbondingMinTime)
|
||||
} else {
|
||||
k.SetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime, newTimeSlice)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns all the validator queue timeslices from time 0 until endTime
|
||||
func (k Keeper) ValidatorQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
@ -358,9 +386,12 @@ func (k Keeper) UnbondAllMatureValidatorQueue(ctx sdk.Context) {
|
|||
k.cdc.MustUnmarshalBinaryLengthPrefixed(validatorTimesliceIterator.Value(), ×lice)
|
||||
for _, valAddr := range timeslice {
|
||||
val, found := k.GetValidator(ctx, valAddr)
|
||||
if !found || val.GetStatus() != sdk.Unbonding {
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
if val.GetStatus() != sdk.Unbonding {
|
||||
panic("unexpected validator in unbonding queue, status was not unbonding")
|
||||
}
|
||||
k.unbondingToUnbonded(ctx, val)
|
||||
if val.GetDelegatorShares().IsZero() {
|
||||
k.RemoveValidator(ctx, val.OperatorAddr)
|
||||
|
|
|
@ -57,6 +57,9 @@ var (
|
|||
GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey
|
||||
GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey
|
||||
TestingUpdateValidator = keeper.TestingUpdateValidator
|
||||
UnbondingQueueKey = keeper.UnbondingQueueKey
|
||||
RedelegationQueueKey = keeper.RedelegationQueueKey
|
||||
ValidatorQueueKey = keeper.ValidatorQueueKey
|
||||
|
||||
DefaultParamspace = keeper.DefaultParamspace
|
||||
KeyUnbondingTime = types.KeyUnbondingTime
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// GenesisState - all staking state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
Pool Pool `json:"pool"`
|
||||
Params Params `json:"params"`
|
||||
Validators []Validator `json:"validators"`
|
||||
Bonds []Delegation `json:"bonds"`
|
||||
Pool Pool `json:"pool"`
|
||||
Params Params `json:"params"`
|
||||
IntraTxCounter int16 `json:"intra_tx_counter"`
|
||||
LastTotalPower sdk.Int `json:"last_total_power"`
|
||||
Validators []Validator `json:"validators"`
|
||||
Bonds []Delegation `json:"bonds"`
|
||||
UnbondingDelegations []UnbondingDelegation `json:"unbonding_delegations"`
|
||||
Redelegations []Redelegation `json:"redelegations"`
|
||||
}
|
||||
|
||||
func NewGenesisState(pool Pool, params Params, validators []Validator, bonds []Delegation) GenesisState {
|
||||
|
|
Loading…
Reference in New Issue