From 766c3b034fbdaf4b4fb1bae3e4b6e6a9abf0a1dd Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 5 Nov 2018 13:37:07 +0100 Subject: [PATCH 01/33] Update PENDING.md --- PENDING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PENDING.md b/PENDING.md index 11c13ea75f00..f64cc092b91c 100644 --- a/PENDING.md +++ b/PENDING.md @@ -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 @@ -63,6 +63,7 @@ BUG FIXES * Gaia - \#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 * SDK - \#2625 [x/gov] fix AppendTag function usage error From f20e961cd69020f4ab73d24981a300a80a6f8ef9 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 5 Nov 2018 14:04:32 +0100 Subject: [PATCH 02/33] Update slashing import/export --- cmd/gaia/app/app.go | 2 +- x/slashing/genesis.go | 43 +++++++++++++++++++++++++++++++++-- x/slashing/signing_info.go | 16 +++++++++++++ x/slashing/slashing_period.go | 15 ++++++++++++ x/slashing/test_common.go | 2 +- 5 files changed, 74 insertions(+), 4 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 1927d235d10d..d81dbadd6be5 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -310,7 +310,7 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val mint.WriteGenesis(ctx, app.mintKeeper), distr.WriteGenesis(ctx, app.distrKeeper), gov.WriteGenesis(ctx, app.govKeeper), - slashing.GenesisState{}, // TODO create write methods + slashing.WriteGenesis(ctx, app.slashingKeeper), ) appState, err = codec.MarshalJSONIndent(app.cdc, genState) if err != nil { diff --git a/x/slashing/genesis.go b/x/slashing/genesis.go index 10af155d6824..79b95c2827cf 100644 --- a/x/slashing/genesis.go +++ b/x/slashing/genesis.go @@ -7,13 +7,17 @@ import ( // GenesisState - all slashing state that must be provided at genesis type GenesisState struct { - Params Params + Params Params + SigningInfos map[string]ValidatorSigningInfo + SlashingPeriods []ValidatorSlashingPeriod } // HubDefaultGenesisState - default GenesisState used by Cosmos Hub func DefaultGenesisState() GenesisState { return GenesisState{ - Params: DefaultParams(), + Params: DefaultParams(), + SigningInfos: make(map[string]ValidatorSigningInfo), + SlashingPeriods: []ValidatorSlashingPeriod{}, } } @@ -24,5 +28,40 @@ 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 _, slashingPeriod := range data.SlashingPeriods { + keeper.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) + } + keeper.paramspace.SetParamSet(ctx, &data.Params) } + +func WriteGenesis(ctx sdk.Context, keeper Keeper) (data GenesisState) { + var params Params + keeper.paramspace.GetParamSet(ctx, ¶ms) + + signingInfos := make(map[string]ValidatorSigningInfo) + keeper.iterateValidatorSigningInfos(ctx, func(address sdk.ConsAddress, info ValidatorSigningInfo) (stop bool) { + signingInfos[address.String()] = info + return false + }) + + slashingPeriods := []ValidatorSlashingPeriod{} + keeper.iterateValidatorSlashingPeriods(ctx, func(slashingPeriod ValidatorSlashingPeriod) (stop bool) { + slashingPeriods = append(slashingPeriods, slashingPeriod) + return false + }) + + return GenesisState{ + Params: params, + SigningInfos: signingInfos, + SlashingPeriods: slashingPeriods, + } +} diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index 6479be928544..b0e496bf6b06 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -20,6 +20,22 @@ 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() { + var address sdk.ConsAddress + copy(address, iter.Key()[1:sdk.AddrLen+1]) + 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) diff --git a/x/slashing/slashing_period.go b/x/slashing/slashing_period.go index 026d141a2b7c..8e6a9ec32ba1 100644 --- a/x/slashing/slashing_period.go +++ b/x/slashing/slashing_period.go @@ -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, ValidatorSigningInfoKey) + 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 diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 2f1113aa136f..152652f76963 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -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}, genesis) }) return ctx, ck, sk, paramstore, keeper From 85a6d88c5ccc81e54c8a6b22c0b00b0bbfc031ef Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 5 Nov 2018 14:29:41 +0100 Subject: [PATCH 03/33] More slashing.WriteGenesis --- x/slashing/genesis.go | 31 ++++++++++++++++++++++++++++++- x/slashing/signing_info.go | 18 ++++++++++++++++++ x/slashing/test_common.go | 2 +- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/x/slashing/genesis.go b/x/slashing/genesis.go index 79b95c2827cf..00b84ada59de 100644 --- a/x/slashing/genesis.go +++ b/x/slashing/genesis.go @@ -9,6 +9,7 @@ import ( type GenesisState struct { Params Params SigningInfos map[string]ValidatorSigningInfo + MissedBlocks map[string][]bool SlashingPeriods []ValidatorSlashingPeriod } @@ -17,6 +18,7 @@ func DefaultGenesisState() GenesisState { return GenesisState{ Params: DefaultParams(), SigningInfos: make(map[string]ValidatorSigningInfo), + MissedBlocks: make(map[string][]bool), SlashingPeriods: []ValidatorSlashingPeriod{}, } } @@ -36,6 +38,16 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState, sdata types. keeper.setValidatorSigningInfo(ctx, address, info) } + for addr, array := range data.MissedBlocks { + address, err := sdk.ConsAddressFromBech32(addr) + if err != nil { + panic(err) + } + for index, missed := range array { + keeper.setValidatorMissedBlockBitArray(ctx, address, int64(index), missed) + } + } + for _, slashingPeriod := range data.SlashingPeriods { keeper.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) } @@ -43,13 +55,29 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState, sdata types. keeper.paramspace.SetParamSet(ctx, &data.Params) } +// WriteGenesis writes the current store values +// to a genesis file, which can be imported again +// with InitGenesis func WriteGenesis(ctx sdk.Context, keeper Keeper) (data GenesisState) { var params Params keeper.paramspace.GetParamSet(ctx, ¶ms) signingInfos := make(map[string]ValidatorSigningInfo) + missedBlocks := make(map[string][]bool) keeper.iterateValidatorSigningInfos(ctx, func(address sdk.ConsAddress, info ValidatorSigningInfo) (stop bool) { - signingInfos[address.String()] = info + bechAddr := address.String() + signingInfos[bechAddr] = info + array := make([]bool, 0) + + keeper.iterateValidatorMissedBlockBitArray(ctx, address, func(index int64, missed bool) (stop bool) { + if index != int64(len(array)) { + panic("invalid index") + } + array = append(array, missed) + return false + }) + missedBlocks[bechAddr] = array + return false }) @@ -62,6 +90,7 @@ func WriteGenesis(ctx sdk.Context, keeper Keeper) (data GenesisState) { return GenesisState{ Params: params, SigningInfos: signingInfos, + MissedBlocks: missedBlocks, SlashingPeriods: slashingPeriods, } } diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index b0e496bf6b06..4a0c0a14f0fb 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -56,6 +56,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) + for { + var missed bool + bz := store.Get(GetValidatorMissedBlockBitArrayKey(address, index)) + if bz == nil { + break + } + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &missed) + if handler(index, missed) { + break + } + index++ + } +} + // 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) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 152652f76963..239ae13d62a1 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -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, nil, nil}, genesis) + InitGenesis(ctx, keeper, GenesisState{defaults, nil, nil, nil}, genesis) }) return ctx, ck, sk, paramstore, keeper From 7c88bb667c98144f9d938c2cde31a0cdc8420372 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 5 Nov 2018 14:36:06 +0100 Subject: [PATCH 04/33] Add test import/export to CI --- .circleci/config.yml | 21 +++++++++++++++++++++ Makefile | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 879df07f02a9..708b5887d6bc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 diff --git a/Makefile b/Makefile index af4ea71c9887..4ee5ea7c7363 100644 --- a/Makefile +++ b/Makefile @@ -171,6 +171,10 @@ 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=10 -v -timeout 24h + test_sim_gaia_multi_seed: @echo "Running multi-seed Gaia simulation. This may take awhile!" @bash scripts/multisim.sh 25 From 0545e188ab02ab3923f0fe5112c0825dcf8ec7ed Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 5 Nov 2018 14:55:57 +0100 Subject: [PATCH 05/33] Efficacious import/export --- cmd/gaia/app/sim_test.go | 69 +++++++++++++++++++++++++++++++++++ x/slashing/slashing_period.go | 2 +- x/stake/genesis.go | 16 ++++---- 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 0216616a88ac..7c21b4e2f846 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -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,74 @@ 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) + + fmt.Printf("Comparing stores...\n") + // TODO compare me + +} + // TODO: Make another test for the fuzzer itself, which just has noOp txs // and doesn't depend on gaia func TestAppStateDeterminism(t *testing.T) { diff --git a/x/slashing/slashing_period.go b/x/slashing/slashing_period.go index 8e6a9ec32ba1..4caf5d7c9d36 100644 --- a/x/slashing/slashing_period.go +++ b/x/slashing/slashing_period.go @@ -56,7 +56,7 @@ func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk // 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, ValidatorSigningInfoKey) + iter := sdk.KVStorePrefixIterator(store, ValidatorSlashingPeriodKey) defer iter.Close() for ; iter.Valid(); iter.Next() { slashingPeriod := k.unmarshalSlashingPeriodKeyValue(iter.Key(), iter.Value()) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 63b038613de5..61bc6377642e 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -31,11 +31,11 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ validator.BondIntraTxCounter = int16(i) // set the intra-tx counter to the order the validators are presented keeper.SetValidator(ctx, validator) - if validator.Tokens.IsZero() { - return res, errors.Errorf("genesis validator cannot have zero pool shares, validator: %v", validator) + if validator.Tokens.IsZero() && validator.Status != sdk.Unbonding { + return res, errors.Errorf("bonded/unbonded 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) + if validator.DelegatorShares.IsZero() && validator.Status != sdk.Unbonding { + return res, errors.Errorf("bonded/unbonded genesis validator cannot have zero delegator shares, validator: %v", validator) } // Manually set indices for the first time @@ -118,11 +118,11 @@ 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.Tokens.IsZero() && val.Status != sdk.Unbonding { + return fmt.Errorf("bonded/unbonded 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 } From 40fa0fd57aad323215dc1a868b4dbcedfcac9f89 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 5 Nov 2018 15:21:43 +0100 Subject: [PATCH 06/33] Store equality comparision in progress --- cmd/gaia/app/sim_test.go | 13 ++++++++++++- types/store.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 7c21b4e2f846..752212a01307 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -331,7 +331,18 @@ func TestGaiaImportExport(t *testing.T) { newApp.InitChain(request) fmt.Printf("Comparing stores...\n") - // TODO compare me + ctxA := app.NewContext(true, abci.Header{}) + ctxB := newApp.NewContext(true, abci.Header{}) + storeKeysA := []sdk.StoreKey{app.keyMain, app.keyAccount} + storeKeysB := []sdk.StoreKey{newApp.keyMain, newApp.keyAccount} + for index, storeKeyA := range storeKeysA { + storeKeyB := storeKeysB[index] + storeA := ctxA.KVStore(storeKeyA) + storeB := ctxB.KVStore(storeKeyB) + kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB) + 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 %v => %v\nstore B %v => %v", storeKeyA, storeKeyB, kvA.Key, kvA.Value, kvB.Key, kvB.Value) + } } diff --git a/types/store.go b/types/store.go index 7bab93b97e60..1e097a3f2f9e 100644 --- a/types/store.go +++ b/types/store.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "fmt" "io" @@ -176,6 +177,33 @@ 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 +func DiffKVStores(a KVStore, b KVStore) (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()} + } + if iterB.Valid() { + kvB = cmn.KVPair{Key: iterB.Key(), Value: iterB.Value()} + } + if !bytes.Equal(kvA.Key, kvB.Key) || !bytes.Equal(kvA.Value, kvB.Value) { + return kvA, kvB, count, false + } + iterA.Next() + iterB.Next() + 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. From ca6c0fc6a1d3f8aee2ab1671fa37ee50357414c8 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 5 Nov 2018 16:03:32 +0100 Subject: [PATCH 07/33] Account stores match --- cmd/gaia/app/app.go | 4 ++++ cmd/gaia/app/genesis.go | 25 +++++++++++++++-------- cmd/gaia/app/sim_test.go | 10 ++++++--- x/auth/{mapper.go => keeper.go} | 0 x/auth/{mapper_test.go => keeper_test.go} | 0 5 files changed, 27 insertions(+), 12 deletions(-) rename x/auth/{mapper.go => keeper.go} (100%) rename x/auth/{mapper_test.go => keeper_test.go} (100%) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index d81dbadd6be5..0d4a4578927c 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -231,6 +231,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() diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index cfbbe5cc2edd..e431f5edd427 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -53,31 +53,38 @@ func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mi } } -// GenesisAccount doesn't need pubkey or sequence 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, } } diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 752212a01307..0b6c080571aa 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -329,19 +329,23 @@ func TestGaiaImportExport(t *testing.T) { AppStateBytes: appState, } newApp.InitChain(request) + newApp.Commit() fmt.Printf("Comparing stores...\n") ctxA := app.NewContext(true, abci.Header{}) ctxB := newApp.NewContext(true, abci.Header{}) - storeKeysA := []sdk.StoreKey{app.keyMain, app.keyAccount} - storeKeysB := []sdk.StoreKey{newApp.keyMain, newApp.keyAccount} + storeKeysA := []sdk.StoreKey{app.keyMain, app.keyAccount, app.keyStake, app.keySlashing, + app.keyMint, app.keyDistr, app.keyGov, app.keyFeeCollection, app.keyParams} + storeKeysB := []sdk.StoreKey{newApp.keyMain, newApp.keyAccount, newApp.keyStake, newApp.keySlashing, + newApp.keyMint, newApp.keyDistr, newApp.keyGov, newApp.keyFeeCollection, newApp.keyParams} + require.Equal(t, len(storeKeysA), len(storeKeysB)) for index, storeKeyA := range storeKeysA { storeKeyB := storeKeysB[index] storeA := ctxA.KVStore(storeKeyA) storeB := ctxB.KVStore(storeKeyB) kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB) 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 %v => %v\nstore B %v => %v", storeKeyA, storeKeyB, kvA.Key, kvA.Value, kvB.Key, kvB.Value) + require.True(t, equal, "unequal stores: %s / %s:\nstore A %s => %s\nstore B %s => %s", storeKeyA, storeKeyB, kvA.Key, kvA.Value, kvB.Key, kvB.Value) } } diff --git a/x/auth/mapper.go b/x/auth/keeper.go similarity index 100% rename from x/auth/mapper.go rename to x/auth/keeper.go diff --git a/x/auth/mapper_test.go b/x/auth/keeper_test.go similarity index 100% rename from x/auth/mapper_test.go rename to x/auth/keeper_test.go From 5ac2359ea87fc51d1c102693f3a6d9f607b551f7 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 5 Nov 2018 16:27:33 +0100 Subject: [PATCH 08/33] Onto debugging x/stake store --- Makefile | 2 +- cmd/gaia/app/sim_test.go | 3 ++- x/stake/genesis.go | 18 +++++++++++++----- x/stake/types/genesis.go | 14 ++++++++++---- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 4ee5ea7c7363..5f438c782179 100644 --- a/Makefile +++ b/Makefile @@ -173,7 +173,7 @@ test_sim_gaia_fast: 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=10 -v -timeout 24h + @go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=11 -v -timeout 24h test_sim_gaia_multi_seed: @echo "Running multi-seed Gaia simulation. This may take awhile!" diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 0b6c080571aa..7ff95c70cb46 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -345,7 +345,8 @@ func TestGaiaImportExport(t *testing.T) { storeB := ctxB.KVStore(storeKeyB) kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB) 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 => %s\nstore B %s => %s", storeKeyA, storeKeyB, kvA.Key, kvA.Value, kvB.Key, kvB.Value) + 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) } } diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 61bc6377642e..69c2c254fbd6 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -26,9 +26,13 @@ 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) for i, validator := range data.Validators { - validator.BondIntraTxCounter = int16(i) // set the intra-tx counter to the order the validators are presented + if validator.BondIntraTxCounter == 0 { + validator.BondIntraTxCounter = int16(i) // set the intra-tx counter to the order the validators are presented + } keeper.SetValidator(ctx, validator) if validator.Tokens.IsZero() && validator.Status != sdk.Unbonding { @@ -59,14 +63,18 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ func WriteGenesis(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) return types.GenesisState{ - Pool: pool, - Params: params, - Validators: validators, - Bonds: bonds, + Pool: pool, + Params: params, + IntraTxCounter: intraTxCounter, + LastTotalPower: lastTotalPower, + Validators: validators, + Bonds: bonds, } } diff --git a/x/stake/types/genesis.go b/x/stake/types/genesis.go index d08c6b899341..147f00f49212 100644 --- a/x/stake/types/genesis.go +++ b/x/stake/types/genesis.go @@ -1,11 +1,17 @@ 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"` } func NewGenesisState(pool Pool, params Params, validators []Validator, bonds []Delegation) GenesisState { From 145435fc9fc132cb444adc8477e278d007fc2077 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 5 Nov 2018 16:52:34 +0100 Subject: [PATCH 09/33] 'make format' --- cmd/gaia/app/genesis.go | 1 + cmd/gaia/app/genesis_test.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index e431f5edd427..6c07440d10e4 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -53,6 +53,7 @@ func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mi } } +// nolint type GenesisAccount struct { Address sdk.AccAddress `json:"address"` Coins sdk.Coins `json:"coins"` diff --git a/cmd/gaia/app/genesis_test.go b/cmd/gaia/app/genesis_test.go index 6c331856c345..9841fa3f889e 100644 --- a/cmd/gaia/app/genesis_test.go +++ b/cmd/gaia/app/genesis_test.go @@ -92,7 +92,7 @@ func makeMsg(name string, pk crypto.PubKey) auth.StdTx { desc := stake.NewDescription(name, "", "", "") comm := stakeTypes.CommissionMsg{} msg := stake.NewMsgCreateValidator(sdk.ValAddress(pk.Address()), pk, sdk.NewInt64Coin(bondDenom, - 50), desc, comm) + 50), desc, comm) return auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, nil, "") } From 54b91297c5869308e96800ec9d5588f5d8353171 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 6 Nov 2018 15:54:37 +0100 Subject: [PATCH 10/33] Fix validator bond intra-tx counter --- x/stake/genesis.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 69c2c254fbd6..a4cde236e3b7 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -29,9 +29,18 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ 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 { - if validator.BondIntraTxCounter == 0 { - 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) From 41088c42343cf8719fca79b667b12403907b808d Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 6 Nov 2018 15:56:10 +0100 Subject: [PATCH 11/33] Set timeslices for unbonding validators --- x/stake/genesis.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index a4cde236e3b7..d0a943eaeede 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -55,6 +55,11 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ 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 { From 84e5514ef2e1dc196acda2d7ca90d1199580b74f Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 6 Nov 2018 16:12:22 +0100 Subject: [PATCH 12/33] Fix missed blocks --- x/slashing/genesis.go | 25 +++++++++++++++---------- x/slashing/signing_info.go | 9 +++++---- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/x/slashing/genesis.go b/x/slashing/genesis.go index 00b84ada59de..c764db8793f3 100644 --- a/x/slashing/genesis.go +++ b/x/slashing/genesis.go @@ -1,6 +1,8 @@ package slashing import ( + // "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -9,16 +11,22 @@ import ( type GenesisState struct { Params Params SigningInfos map[string]ValidatorSigningInfo - MissedBlocks map[string][]bool + 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(), SigningInfos: make(map[string]ValidatorSigningInfo), - MissedBlocks: make(map[string][]bool), + MissedBlocks: make(map[string][]MissedBlock), SlashingPeriods: []ValidatorSlashingPeriod{}, } } @@ -43,8 +51,8 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState, sdata types. if err != nil { panic(err) } - for index, missed := range array { - keeper.setValidatorMissedBlockBitArray(ctx, address, int64(index), missed) + for _, missed := range array { + keeper.setValidatorMissedBlockBitArray(ctx, address, missed.Index, missed.Missed) } } @@ -63,17 +71,14 @@ func WriteGenesis(ctx sdk.Context, keeper Keeper) (data GenesisState) { keeper.paramspace.GetParamSet(ctx, ¶ms) signingInfos := make(map[string]ValidatorSigningInfo) - missedBlocks := make(map[string][]bool) + missedBlocks := make(map[string][]MissedBlock) keeper.iterateValidatorSigningInfos(ctx, func(address sdk.ConsAddress, info ValidatorSigningInfo) (stop bool) { bechAddr := address.String() signingInfos[bechAddr] = info - array := make([]bool, 0) + array := []MissedBlock{} keeper.iterateValidatorMissedBlockBitArray(ctx, address, func(index int64, missed bool) (stop bool) { - if index != int64(len(array)) { - panic("invalid index") - } - array = append(array, missed) + array = append(array, MissedBlock{index, missed}) return false }) missedBlocks[bechAddr] = array diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index 4a0c0a14f0fb..6f9def7db4d9 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -27,7 +27,8 @@ func (k Keeper) iterateValidatorSigningInfos(ctx sdk.Context, handler func(addre defer iter.Close() for ; iter.Valid(); iter.Next() { var address sdk.ConsAddress - copy(address, iter.Key()[1:sdk.AddrLen+1]) + address = make([]byte, sdk.AddrLen) + copy(address[:], iter.Key()[1:sdk.AddrLen+1]) var info ValidatorSigningInfo k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &info) if handler(address, info) { @@ -60,17 +61,17 @@ func (k Keeper) getValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.Con 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) - for { + // Array may be sparse + for ; index < k.SignedBlocksWindow(ctx); index++ { var missed bool bz := store.Get(GetValidatorMissedBlockBitArrayKey(address, index)) if bz == nil { - break + continue } k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &missed) if handler(index, missed) { break } - index++ } } From c7c21ada25dfd06ea9a7eb3d8b6f449485d1c74d Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 6 Nov 2018 16:19:30 +0100 Subject: [PATCH 13/33] Fix distribution import/export --- x/distribution/genesis.go | 4 +++- x/distribution/keeper/genesis.go | 4 ++-- x/distribution/types/genesis.go | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/x/distribution/genesis.go b/x/distribution/genesis.go index 4ee5651a6757..6386e6da0b17 100644 --- a/x/distribution/genesis.go +++ b/x/distribution/genesis.go @@ -21,6 +21,7 @@ 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 @@ -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) } diff --git a/x/distribution/keeper/genesis.go b/x/distribution/keeper/genesis.go index 804ea5242220..8767ab6d0418 100644 --- a/x/distribution/keeper/genesis.go +++ b/x/distribution/keeper/genesis.go @@ -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: sdk.AccAddress(iterator.Key()[1:]), WithdrawAddr: sdk.AccAddress(iterator.Value()), } dwis = append(dwis, dw) diff --git a/x/distribution/types/genesis.go b/x/distribution/types/genesis.go index 528295e5c2db..0577af4d33b4 100644 --- a/x/distribution/types/genesis.go +++ b/x/distribution/types/genesis.go @@ -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, } } From ed6866a5c0d85e9262d226bea4590752d53c3626 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 6 Nov 2018 16:47:42 +0100 Subject: [PATCH 14/33] x/gov fixes in progress --- x/gov/genesis.go | 51 ++++++++++++++++++++++++++++++++++++++++++++---- x/gov/handler.go | 4 +++- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 58273c8e849b..6d7db2803b33 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -8,10 +8,23 @@ import ( // GenesisState - all staking state that must be provided at genesis type GenesisState struct { - StartingProposalID int64 `json:"starting_proposalID"` - DepositProcedure DepositProcedure `json:"deposit_period"` - VotingProcedure VotingProcedure `json:"voting_period"` - TallyingProcedure TallyingProcedure `json:"tallying_procedure"` + StartingProposalID int64 `json:"starting_proposal_id"` + Deposits []DepositWithMetadata `json:"deposits"` + Votes []VoteWithMetadata `json:"votes"` + Proposals []Proposal `json:"proposals"` + DepositProcedure DepositProcedure `json:"deposit_period"` + VotingProcedure VotingProcedure `json:"voting_period"` + TallyingProcedure TallyingProcedure `json:"tallying_procedure"` +} + +type DepositWithMetadata struct { + ProposalID int64 `json:"proposal_id"` + Deposit Deposit `json:"deposit"` +} + +type VoteWithMetadata struct { + ProposalID int64 `json:"proposal_id"` + Vote Vote `json:"vote"` } func NewGenesisState(startingProposalID int64, dp DepositProcedure, vp VotingProcedure, tp TallyingProcedure) GenesisState { @@ -52,6 +65,15 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { k.setDepositProcedure(ctx, data.DepositProcedure) k.setVotingProcedure(ctx, data.VotingProcedure) k.setTallyingProcedure(ctx, data.TallyingProcedure) + 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 @@ -60,9 +82,30 @@ func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState { depositProcedure := k.GetDepositProcedure(ctx) votingProcedure := k.GetVotingProcedure(ctx) tallyingProcedure := k.GetTallyingProcedure(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, DepositProcedure: depositProcedure, VotingProcedure: votingProcedure, TallyingProcedure: tallyingProcedure, diff --git a/x/gov/handler.go b/x/gov/handler.go index dc1dbfb10e40..fe21cdef6484 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -109,10 +109,12 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { continue } - proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(inactiveProposal.GetProposalID()) + proposalID := inactiveProposal.GetProposalID() + proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(proposalID) keeper.DeleteProposal(ctx, inactiveProposal) resTags = resTags.AppendTag(tags.Action, tags.ActionProposalDropped) resTags = resTags.AppendTag(tags.ProposalID, proposalIDBytes) + keeper.DeleteDeposits(ctx, proposalID) // delete any associated deposits (burned) logger.Info( fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %v steak (had only %v steak); deleted", From 4eaffaf4b408c89d546a310961e1f5d6bc26fde5 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 6 Nov 2018 17:09:52 +0100 Subject: [PATCH 15/33] Fee collection keeper import/export --- cmd/gaia/app/app.go | 2 ++ cmd/gaia/app/genesis.go | 4 +++- cmd/gaia/app/sim_test.go | 4 ++-- x/auth/genesis.go | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 x/auth/genesis.go diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 0d4a4578927c..9fba3aee9675 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -249,6 +249,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci } // load the address to pubkey map + 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) @@ -310,6 +311,7 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val app.accountKeeper.IterateAccounts(ctx, appendAccount) genState := NewGenesisState( accounts, + auth.WriteGenesis(ctx, app.feeCollectionKeeper), stake.WriteGenesis(ctx, app.stakeKeeper), mint.WriteGenesis(ctx, app.mintKeeper), distr.WriteGenesis(ctx, app.distrKeeper), diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 6c07440d10e4..38256e4150f0 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -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, diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 7ff95c70cb46..23a4475bcdcb 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -335,9 +335,9 @@ func TestGaiaImportExport(t *testing.T) { ctxA := app.NewContext(true, abci.Header{}) ctxB := newApp.NewContext(true, abci.Header{}) storeKeysA := []sdk.StoreKey{app.keyMain, app.keyAccount, app.keyStake, app.keySlashing, - app.keyMint, app.keyDistr, app.keyGov, app.keyFeeCollection, app.keyParams} + app.keyMint, app.keyDistr, app.keyFeeCollection, app.keyParams, app.keyGov} storeKeysB := []sdk.StoreKey{newApp.keyMain, newApp.keyAccount, newApp.keyStake, newApp.keySlashing, - newApp.keyMint, newApp.keyDistr, newApp.keyGov, newApp.keyFeeCollection, newApp.keyParams} + newApp.keyMint, newApp.keyDistr, newApp.keyFeeCollection, newApp.keyParams, newApp.keyGov} require.Equal(t, len(storeKeysA), len(storeKeysB)) for index, storeKeyA := range storeKeysA { storeKeyB := storeKeysB[index] diff --git a/x/auth/genesis.go b/x/auth/genesis.go new file mode 100644 index 000000000000..edd7f1c61393 --- /dev/null +++ b/x/auth/genesis.go @@ -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) +} + +// WriteGenesis returns a GenesisState for a given context and keeper +func WriteGenesis(ctx sdk.Context, keeper FeeCollectionKeeper) GenesisState { + collectedFees := keeper.GetCollectedFees(ctx) + return NewGenesisState(collectedFees) +} From 76cb7632eaf7aa92d23e9b34748f28473a7732a0 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 6 Nov 2018 17:20:43 +0100 Subject: [PATCH 16/33] Switch seed to realize more discrepancies --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5f438c782179..3a9bee753893 100644 --- a/Makefile +++ b/Makefile @@ -173,7 +173,7 @@ test_sim_gaia_fast: 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=11 -v -timeout 24h + @go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=12 -v -timeout 24h test_sim_gaia_multi_seed: @echo "Running multi-seed Gaia simulation. This may take awhile!" From 0ecc4302927a71b1596209eb2bdf586ee7311962 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 6 Nov 2018 17:58:00 +0100 Subject: [PATCH 17/33] x/stake import/export contd... --- x/stake/genesis.go | 41 ++++++++++++++++++++++++++++++------ x/stake/keeper/delegation.go | 15 +++++++++++++ x/stake/types/genesis.go | 14 ++++++------ 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index d0a943eaeede..050d163a98a0 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -2,6 +2,7 @@ package stake import ( "fmt" + "sort" abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" @@ -67,6 +68,22 @@ 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 } @@ -81,14 +98,26 @@ func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { 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, - IntraTxCounter: intraTxCounter, - LastTotalPower: lastTotalPower, - Validators: validators, - Bonds: bonds, + Pool: pool, + Params: params, + IntraTxCounter: intraTxCounter, + LastTotalPower: lastTotalPower, + Validators: validators, + Bonds: bonds, + UnbondingDelegations: unbondingDelegations, + Redelegations: redelegations, } } diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index fbb62dcbff9a..d535419e136f 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -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) diff --git a/x/stake/types/genesis.go b/x/stake/types/genesis.go index 147f00f49212..f1673a376a4a 100644 --- a/x/stake/types/genesis.go +++ b/x/stake/types/genesis.go @@ -6,12 +6,14 @@ import ( // GenesisState - all staking state that must be provided at genesis type GenesisState struct { - 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"` + 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 { From 80601a65b2d386b91a9774c06ed32ade98164f55 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 6 Nov 2018 20:51:30 +0100 Subject: [PATCH 18/33] Linter fix --- x/gov/genesis.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 6d7db2803b33..267526ab1686 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -17,11 +17,13 @@ type GenesisState struct { TallyingProcedure TallyingProcedure `json:"tallying_procedure"` } +// DepositWithMetadata (just for genesis) type DepositWithMetadata struct { ProposalID int64 `json:"proposal_id"` Deposit Deposit `json:"deposit"` } +// VoteWithMetadata (just for genesis) type VoteWithMetadata struct { ProposalID int64 `json:"proposal_id"` Vote Vote `json:"vote"` From 699f8135395ac1ccdedc7a3579ebe94c08469c7a Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Tue, 6 Nov 2018 16:42:35 -0800 Subject: [PATCH 19/33] Fix dependancy issue --- Gopkg.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gopkg.toml b/Gopkg.toml index a66574ea62f8..62e9eaeb038e 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -36,7 +36,7 @@ [[override]] name = "github.com/tendermint/tendermint" - revision = "ebee4377b15f2958b08994485375dd2ee8a649ac" # TODO replace w/ 0.26.1 + version = "v0.26.1" # TODO replace w/ 0.26.1 ## deps without releases: @@ -84,4 +84,3 @@ [prune] go-tests = true unused-packages = true - From b3547382a91b37e2076a8f227dbb0e766a842744 Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Tue, 6 Nov 2018 16:52:58 -0800 Subject: [PATCH 20/33] Update lockfile --- Gopkg.lock | 8 ++++---- Gopkg.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index f9be7bd97a9e..0e9681ed39eb 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -165,13 +165,12 @@ version = "v1.2.0" [[projects]] - digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10" + digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8" name = "github.com/hashicorp/hcl" packages = [ ".", "hcl/ast", "hcl/parser", - "hcl/printer", "hcl/scanner", "hcl/strconv", "hcl/token", @@ -435,7 +434,7 @@ version = "v0.11.1" [[projects]] - digest = "1:92d7d1678577fd1a6f3348168cef87880bbc710ef5f4e9a1216f45c56567d734" + digest = "1:395820b381043b9d2204e181ddf0f9147397c4a7b8f5dc3162de4cfcddf4589a" name = "github.com/tendermint/tendermint" packages = [ "abci/client", @@ -501,7 +500,8 @@ "version", ] pruneopts = "UT" - revision = "ebee4377b15f2958b08994485375dd2ee8a649ac" + revision = "03e42d2e3866f01a00625f608e3bbfaeb30690de" + version = "v0.26.1-rc0" [[projects]] digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666" diff --git a/Gopkg.toml b/Gopkg.toml index 62e9eaeb038e..5726008858c4 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -36,7 +36,7 @@ [[override]] name = "github.com/tendermint/tendermint" - version = "v0.26.1" # TODO replace w/ 0.26.1 + version = "v0.26.1-rc0" # TODO replace w/ 0.26.1 ## deps without releases: From f50853680f508fa10ab1728824120fd479ea5ea1 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 7 Nov 2018 16:01:47 +0100 Subject: [PATCH 21/33] Peek, don't update proposal ID --- x/gov/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 039659e0749d..2b1a03858349 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -80,7 +80,7 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { // WriteGenesis - output genesis parameters func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState { - startingProposalID, _ := k.getNewProposalID(ctx) + startingProposalID, _ := k.peekCurrentProposalID(ctx) depositParams := k.GetDepositParams(ctx) votingParams := k.GetVotingParams(ctx) tallyParams := k.GetTallyParams(ctx) From 0dcce00a874bba47ba5449e2337144923d1473cd Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 7 Nov 2018 16:04:21 +0100 Subject: [PATCH 22/33] Failing case (works on seeds 12, 13 now) --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3a9bee753893..8194324798bb 100644 --- a/Makefile +++ b/Makefile @@ -173,7 +173,7 @@ test_sim_gaia_fast: 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=12 -v -timeout 24h + @go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=11 -v -timeout 24h test_sim_gaia_multi_seed: @echo "Running multi-seed Gaia simulation. This may take awhile!" @@ -254,4 +254,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 From 5365ba13d1af4067f826b746e8554d8dc775a4c7 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 7 Nov 2018 16:07:38 +0100 Subject: [PATCH 23/33] WriteGenesis => ExportGenesis --- cmd/gaia/app/app.go | 12 ++++++------ cmd/gaia/init/collect.go | 2 +- cmd/gaia/init/init.go | 2 +- cmd/gaia/init/testnet.go | 2 +- cmd/gaia/init/utils.go | 8 ++++---- examples/basecoin/cmd/basecoind/main.go | 2 +- examples/democoin/app/app.go | 4 ++-- examples/democoin/cmd/democoind/main.go | 2 +- examples/democoin/x/cool/keeper.go | 4 ++-- examples/democoin/x/cool/keeper_test.go | 2 +- examples/democoin/x/pow/keeper.go | 4 ++-- examples/democoin/x/pow/keeper_test.go | 2 +- x/auth/genesis.go | 4 ++-- x/distribution/genesis.go | 4 ++-- x/gov/genesis.go | 4 ++-- x/mint/genesis.go | 4 ++-- x/slashing/genesis.go | 4 ++-- x/stake/genesis.go | 4 ++-- x/stake/genesis_test.go | 2 +- 19 files changed, 36 insertions(+), 36 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 9fba3aee9675..e97b9dff75e6 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -311,12 +311,12 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val app.accountKeeper.IterateAccounts(ctx, appendAccount) genState := NewGenesisState( accounts, - auth.WriteGenesis(ctx, app.feeCollectionKeeper), - stake.WriteGenesis(ctx, app.stakeKeeper), - mint.WriteGenesis(ctx, app.mintKeeper), - distr.WriteGenesis(ctx, app.distrKeeper), - gov.WriteGenesis(ctx, app.govKeeper), - slashing.WriteGenesis(ctx, app.slashingKeeper), + 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 { diff --git a/cmd/gaia/init/collect.go b/cmd/gaia/init/collect.go index 97d9743a06c7..cdfc1688c511 100644 --- a/cmd/gaia/init/collect.go +++ b/cmd/gaia/init/collect.go @@ -113,6 +113,6 @@ func genAppStateFromConfig( return } - err = WriteGenesisFile(genFile, initCfg.ChainID, nil, appState) + err = ExportGenesisFile(genFile, initCfg.ChainID, nil, appState) return } diff --git a/cmd/gaia/init/init.go b/cmd/gaia/init/init.go index f2a815a5c30a..a297caee2300 100644 --- a/cmd/gaia/init/init.go +++ b/cmd/gaia/init/init.go @@ -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 } diff --git a/cmd/gaia/init/testnet.go b/cmd/gaia/init/testnet.go index 42d8332d27fb..8bada583e22f 100644 --- a/cmd/gaia/init/testnet.go +++ b/cmd/gaia/init/testnet.go @@ -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 } diff --git a/cmd/gaia/init/utils.go b/cmd/gaia/init/utils.go index 1738433705e7..58edc9b2a589 100644 --- a/cmd/gaia/init/utils.go +++ b/cmd/gaia/init/utils.go @@ -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 { diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 4f40a145094e..f07fbd3ff2b6 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -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) }, } diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 12f5d8d2947c..e8ddd066d7cd 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -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 { diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 2f48a64f34c9..d095b4c79066 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -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) }, } diff --git a/examples/democoin/x/cool/keeper.go b/examples/democoin/x/cool/keeper.go index f805ca880b40..9f46b0209e8d 100644 --- a/examples/democoin/x/cool/keeper.go +++ b/examples/democoin/x/cool/keeper.go @@ -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} } diff --git a/examples/democoin/x/cool/keeper_test.go b/examples/democoin/x/cool/keeper_test.go index 1eb40dfb295c..904681382c2a 100644 --- a/examples/democoin/x/cool/keeper_test.go +++ b/examples/democoin/x/cool/keeper_test.go @@ -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"}) diff --git a/examples/democoin/x/pow/keeper.go b/examples/democoin/x/pow/keeper.go index 38a0d93c6a0a..6c3bfc4eb866 100644 --- a/examples/democoin/x/pow/keeper.go +++ b/examples/democoin/x/pow/keeper.go @@ -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) diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index 86ccbc8c0130..c8d5406f9cfb 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -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)}) diff --git a/x/auth/genesis.go b/x/auth/genesis.go index edd7f1c61393..abc4fc3aea8f 100644 --- a/x/auth/genesis.go +++ b/x/auth/genesis.go @@ -26,8 +26,8 @@ func InitGenesis(ctx sdk.Context, keeper FeeCollectionKeeper, data GenesisState) keeper.setCollectedFees(ctx, data.CollectedFees) } -// WriteGenesis returns a GenesisState for a given context and keeper -func WriteGenesis(ctx sdk.Context, keeper FeeCollectionKeeper) GenesisState { +// 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) } diff --git a/x/distribution/genesis.go b/x/distribution/genesis.go index 6386e6da0b17..34680891629b 100644 --- a/x/distribution/genesis.go +++ b/x/distribution/genesis.go @@ -24,9 +24,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) { 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) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 2b1a03858349..1243bf559018 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -78,8 +78,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { } } -// WriteGenesis - output genesis parameters -func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState { +// ExportGenesis - output genesis parameters +func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState { startingProposalID, _ := k.peekCurrentProposalID(ctx) depositParams := k.GetDepositParams(ctx) votingParams := k.GetVotingParams(ctx) diff --git a/x/mint/genesis.go b/x/mint/genesis.go index 5617685730b0..ce375d71e576 100644 --- a/x/mint/genesis.go +++ b/x/mint/genesis.go @@ -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) diff --git a/x/slashing/genesis.go b/x/slashing/genesis.go index c764db8793f3..ccc6234d4b65 100644 --- a/x/slashing/genesis.go +++ b/x/slashing/genesis.go @@ -63,10 +63,10 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState, sdata types. keeper.paramspace.SetParamSet(ctx, &data.Params) } -// WriteGenesis writes the current store values +// ExportGenesis writes the current store values // to a genesis file, which can be imported again // with InitGenesis -func WriteGenesis(ctx sdk.Context, keeper Keeper) (data GenesisState) { +func ExportGenesis(ctx sdk.Context, keeper Keeper) (data GenesisState) { var params Params keeper.paramspace.GetParamSet(ctx, ¶ms) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 050d163a98a0..e641f915fe90 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -88,10 +88,10 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ 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) diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index 7ee16a453825..9ad3ac8e9fff 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -44,7 +44,7 @@ func TestInitGenesis(t *testing.T) { 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) From 257ace93ebcbfa83c96586e2ade02133f95badcb Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 7 Nov 2018 16:14:43 +0100 Subject: [PATCH 24/33] Address remaining @jaekwon comments --- x/distribution/keeper/genesis.go | 2 +- x/distribution/keeper/key.go | 9 +++++++++ x/slashing/keys.go | 9 +++++++++ x/slashing/signing_info.go | 4 +--- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/x/distribution/keeper/genesis.go b/x/distribution/keeper/genesis.go index 8767ab6d0418..8e5a37abe2f4 100644 --- a/x/distribution/keeper/genesis.go +++ b/x/distribution/keeper/genesis.go @@ -41,7 +41,7 @@ func (k Keeper) GetAllDelegatorWithdrawInfos(ctx sdk.Context) (dwis []types.Dele for ; iterator.Valid(); iterator.Next() { dw := types.DelegatorWithdrawInfo{ - DelegatorAddr: sdk.AccAddress(iterator.Key()[1:]), + DelegatorAddr: GetDelegatorWithdrawInfoAddress(iterator.Key()), WithdrawAddr: sdk.AccAddress(iterator.Value()), } dwis = append(dwis, dw) diff --git a/x/distribution/keeper/key.go b/x/distribution/keeper/key.go index 466d83c2416f..443d13079e3c 100644 --- a/x/distribution/keeper/key.go +++ b/x/distribution/keeper/key.go @@ -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) +} diff --git a/x/slashing/keys.go b/x/slashing/keys.go index 8f4fecc6c8b9..750e8825f12b 100644 --- a/x/slashing/keys.go +++ b/x/slashing/keys.go @@ -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()...) diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index 6f9def7db4d9..77c437174b9c 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -26,9 +26,7 @@ func (k Keeper) iterateValidatorSigningInfos(ctx sdk.Context, handler func(addre iter := sdk.KVStorePrefixIterator(store, ValidatorSigningInfoKey) defer iter.Close() for ; iter.Valid(); iter.Next() { - var address sdk.ConsAddress - address = make([]byte, sdk.AddrLen) - copy(address[:], iter.Key()[1:sdk.AddrLen+1]) + address := GetValidatorSigningInfoAddress(iter.Key()) var info ValidatorSigningInfo k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &info) if handler(address, info) { From 252d961291a3ac80848548453a38841c2ebafb2e Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 7 Nov 2018 16:56:27 +0100 Subject: [PATCH 25/33] Works but still need to debug stake, test gov --- cmd/gaia/app/sim_test.go | 29 +++++++++++++++++++++-------- types/store.go | 18 ++++++++++++++---- x/stake/genesis.go | 11 ----------- x/stake/stake.go | 3 +++ 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 1e40b0210c68..60befcc385aa 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -334,16 +334,29 @@ func TestGaiaImportExport(t *testing.T) { fmt.Printf("Comparing stores...\n") ctxA := app.NewContext(true, abci.Header{}) ctxB := newApp.NewContext(true, abci.Header{}) - storeKeysA := []sdk.StoreKey{app.keyMain, app.keyAccount, app.keyStake, app.keySlashing, - app.keyMint, app.keyDistr, app.keyFeeCollection, app.keyParams, app.keyGov} - storeKeysB := []sdk.StoreKey{newApp.keyMain, newApp.keyAccount, newApp.keyStake, newApp.keySlashing, - newApp.keyMint, newApp.keyDistr, newApp.keyFeeCollection, newApp.keyParams, newApp.keyGov} - require.Equal(t, len(storeKeysA), len(storeKeysB)) - for index, storeKeyA := range storeKeysA { - storeKeyB := storeKeysB[index] + 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) + 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) diff --git a/types/store.go b/types/store.go index 52f54efb561f..abc9877a08b2 100644 --- a/types/store.go +++ b/types/store.go @@ -179,7 +179,7 @@ func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator { // Compare two KVstores, return either the first key/value pair // at which they differ and whether or not they are equal -func DiffKVStores(a KVStore, b KVStore) (kvA cmn.KVPair, kvB cmn.KVPair, count int64, equal bool) { +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) @@ -190,15 +190,25 @@ func DiffKVStores(a KVStore, b KVStore) (kvA cmn.KVPair, kvB cmn.KVPair, count i 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() } - if !bytes.Equal(kvA.Key, kvB.Key) || !bytes.Equal(kvA.Value, kvB.Value) { + compareValue := true + for _, prefix := range prefixesToSkip { + if bytes.Equal(kvA.Key[:len(prefix)], prefix) { + compareValue = false + } + } + // TODO + if compareValue && !bytes.Equal(kvA.Key, kvB.Key) { + return kvA, kvB, count, false + } + if compareValue && !bytes.Equal(kvA.Value, kvB.Value) { return kvA, kvB, count, false } - iterA.Next() - iterB.Next() count++ } return cmn.KVPair{}, cmn.KVPair{}, count, true diff --git a/x/stake/genesis.go b/x/stake/genesis.go index e641f915fe90..d44055ea849b 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -9,7 +9,6 @@ import ( 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 @@ -45,13 +44,6 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ } keeper.SetValidator(ctx, validator) - if validator.Tokens.IsZero() && validator.Status != sdk.Unbonding { - return res, errors.Errorf("bonded/unbonded genesis validator cannot have zero pool shares, validator: %v", validator) - } - if validator.DelegatorShares.IsZero() && validator.Status != sdk.Unbonding { - return res, errors.Errorf("bonded/unbonded 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) @@ -169,9 +161,6 @@ 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() && val.Status != sdk.Unbonding { - return fmt.Errorf("bonded/unbonded genesis validator cannot have zero pool 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) } diff --git a/x/stake/stake.go b/x/stake/stake.go index 9d761772281b..87087e59c095 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -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 From ba21c55d8679be8a36cdc98a7e528c99c32c138b Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 7 Nov 2018 17:29:38 +0100 Subject: [PATCH 26/33] Delete validators from unbonding queue when re-bonded --- types/store.go | 6 +++--- x/stake/keeper/val_state_change.go | 3 +++ x/stake/keeper/validator.go | 13 +++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/types/store.go b/types/store.go index abc9877a08b2..8654594a9440 100644 --- a/types/store.go +++ b/types/store.go @@ -178,7 +178,8 @@ func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator { } // Compare two KVstores, return either the first key/value pair -// at which they differ and whether or not they are equal +// at which they differ and whether or not they are equal, skipping +// value comparision 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) @@ -202,8 +203,7 @@ func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvA cmn.KVPair compareValue = false } } - // TODO - if compareValue && !bytes.Equal(kvA.Key, kvB.Key) { + if !bytes.Equal(kvA.Key, kvB.Key) { return kvA, kvB, count, false } if compareValue && !bytes.Equal(kvA.Value, kvB.Value) { diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 307270c16fb1..09b2bdec5b50 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -185,6 +185,9 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. k.DeleteValidatorByPowerIndex(ctx, validator, pool) + // delete from queue if present + k.DeleteValidatorQueue(ctx, validator) + validator.BondHeight = ctx.BlockHeight() // set the status diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 4646480ac651..c2ab508e2469 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -1,6 +1,7 @@ package keeper import ( + "bytes" "container/list" "fmt" "time" @@ -331,6 +332,18 @@ 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 := make([]sdk.ValAddress, len(timeSlice)) + for _, addr := range timeSlice { + if !bytes.Equal(addr, val.OperatorAddr) { + newTimeSlice = append(newTimeSlice, addr) + } + } + 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) From 6e0948e00a104609e8bf082c0721de31066e1fdc Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 7 Nov 2018 17:39:00 +0100 Subject: [PATCH 27/33] Failing again --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 8194324798bb..bc9b001e8be8 100644 --- a/Makefile +++ b/Makefile @@ -174,6 +174,7 @@ test_sim_gaia_fast: 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=11 -v -timeout 24h + @go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=414 -v -timeout 24h test_sim_gaia_multi_seed: @echo "Running multi-seed Gaia simulation. This may take awhile!" From 9a4bde00c585b674e7adaf4cebf383e45b51f7fc Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 7 Nov 2018 18:56:35 +0100 Subject: [PATCH 28/33] Hook for validator deletion, fix staking genesis tests --- types/store.go | 2 +- x/slashing/hooks.go | 16 ++++++++++++++-- x/slashing/keeper.go | 1 - x/stake/genesis_test.go | 21 ++++++++------------- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/types/store.go b/types/store.go index 8654594a9440..4b6e79a7670f 100644 --- a/types/store.go +++ b/types/store.go @@ -179,7 +179,7 @@ func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator { // Compare two KVstores, return either the first key/value pair // at which they differ and whether or not they are equal, skipping -// value comparision for a set of provided prefixes +// 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) diff --git a/x/slashing/hooks.go b/x/slashing/hooks.go index 10c16d1993e2..7e2c2d5f27fc 100644 --- a/x/slashing/hooks.go +++ b/x/slashing/hooks.go @@ -3,6 +3,8 @@ package slashing import ( "time" + "github.com/tendermint/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -29,13 +31,18 @@ func (k Keeper) onValidatorBonded(ctx sdk.Context, address sdk.ConsAddress, _ sd k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) } -// Mark the slashing period as having ended when a validator begins unbonding +// Mark the slashing period as having ended when a validator begins unbonding, func (k Keeper) onValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress, _ sdk.ValAddress) { slashingPeriod := k.getValidatorSlashingPeriodForHeight(ctx, address, ctx.BlockHeight()) slashingPeriod.EndHeight = ctx.BlockHeight() k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) } +// 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 +67,17 @@ 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, _ sdk.ValAddress) { + // TODO + h.k.onValidatorRemoved(ctx, sdk.ConsAddress{}) +} + // 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) {} diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 4a52ddcb616b..ac9b67d736b9 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -186,7 +186,6 @@ func (k Keeper) AddValidators(ctx sdk.Context, vals []abci.ValidatorUpdate) { } } -// 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) diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index 9ad3ac8e9fff..3f7295a7a033 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -22,25 +22,24 @@ 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) @@ -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() From 9c7cfe712636df077392fff43bda1d4e532354f7 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 8 Nov 2018 13:24:59 +0100 Subject: [PATCH 29/33] Swap to use hooks for add/remove pubkey --- cmd/gaia/app/app.go | 10 ++++++---- x/slashing/hooks.go | 12 +++++++++++- x/slashing/keeper.go | 15 --------------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index e97b9dff75e6..24439c796c84 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -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, @@ -275,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 { @@ -343,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) + h.sh.OnValidatorRemoved(ctx, valAddr) } func (h Hooks) OnValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { h.dh.OnValidatorBonded(ctx, consAddr, valAddr) @@ -364,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) } diff --git a/x/slashing/hooks.go b/x/slashing/hooks.go index 7e2c2d5f27fc..2985c7402894 100644 --- a/x/slashing/hooks.go +++ b/x/slashing/hooks.go @@ -38,6 +38,12 @@ 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)) @@ -73,10 +79,14 @@ func (h Hooks) OnValidatorRemoved(ctx sdk.Context, _ sdk.ValAddress) { h.k.onValidatorRemoved(ctx, sdk.ConsAddress{}) } +// 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) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index ac9b67d736b9..fe1531f22818 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -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,18 +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) - } -} - func (k Keeper) addPubkey(ctx sdk.Context, pubkey crypto.PubKey) { addr := pubkey.Address() k.setAddrPubkeyRelation(ctx, addr, pubkey) From 306a6bd22643f2983ef1d7c7a5248d89e320a3e4 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 8 Nov 2018 13:30:39 +0100 Subject: [PATCH 30/33] Cleanup, fails again --- Makefile | 2 ++ cmd/gaia/app/app.go | 2 +- x/slashing/genesis.go | 2 -- x/slashing/hooks.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index bc9b001e8be8..de35e01835a9 100644 --- a/Makefile +++ b/Makefile @@ -173,8 +173,10 @@ test_sim_gaia_fast: 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=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!" diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 24439c796c84..89fcbd26805b 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -245,7 +245,7 @@ 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) diff --git a/x/slashing/genesis.go b/x/slashing/genesis.go index ccc6234d4b65..614bf41eb371 100644 --- a/x/slashing/genesis.go +++ b/x/slashing/genesis.go @@ -1,8 +1,6 @@ package slashing import ( - // "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" ) diff --git a/x/slashing/hooks.go b/x/slashing/hooks.go index 2985c7402894..7c3367d98a59 100644 --- a/x/slashing/hooks.go +++ b/x/slashing/hooks.go @@ -31,7 +31,7 @@ func (k Keeper) onValidatorBonded(ctx sdk.Context, address sdk.ConsAddress, _ sd k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) } -// Mark the slashing period as having ended when a validator begins unbonding, +// Mark the slashing period as having ended when a validator begins unbonding func (k Keeper) onValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress, _ sdk.ValAddress) { slashingPeriod := k.getValidatorSlashingPeriodForHeight(ctx, address, ctx.BlockHeight()) slashingPeriod.EndHeight = ctx.BlockHeight() From 2b18c7fcadaf47df548efca53111e7c8baad4e0c Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 8 Nov 2018 13:31:44 +0100 Subject: [PATCH 31/33] More testing seeds --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index de35e01835a9..aaa2fbcf3e48 100644 --- a/Makefile +++ b/Makefile @@ -175,6 +175,8 @@ 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 From 1814284e28b8975a5b742885fa943599fcd82f04 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 8 Nov 2018 16:21:45 +0100 Subject: [PATCH 32/33] Bug fixes! --- x/stake/keeper/val_state_change.go | 12 +++++------- x/stake/keeper/validator.go | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 09b2bdec5b50..3f98f08c5601 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -185,20 +185,19 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. k.DeleteValidatorByPowerIndex(ctx, validator, pool) - // delete from queue if present - k.DeleteValidatorQueue(ctx, validator) - validator.BondHeight = ctx.BlockHeight() // set the status 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) @@ -227,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 diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index c2ab508e2469..0eaedc4bbf1a 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -321,6 +321,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) @@ -335,13 +341,17 @@ 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 := make([]sdk.ValAddress, len(timeSlice)) + newTimeSlice := []sdk.ValAddress{} for _, addr := range timeSlice { if !bytes.Equal(addr, val.OperatorAddr) { newTimeSlice = append(newTimeSlice, addr) } } - k.SetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime, newTimeSlice) + 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 @@ -371,9 +381,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) From 1567057eb713d324f4c58b5de7673cb21189f8e5 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 8 Nov 2018 16:39:51 +0100 Subject: [PATCH 33/33] Fixup hooks --- cmd/gaia/app/app.go | 6 +++--- docs/spec/staking/hooks.md | 2 +- types/stake.go | 6 +++--- x/distribution/keeper/hooks.go | 2 +- x/slashing/hooks.go | 5 ++--- x/slashing/keeper_test.go | 21 +++++++-------------- x/slashing/tick_test.go | 3 +-- x/stake/keeper/hooks.go | 4 ++-- x/stake/keeper/validator.go | 5 +++++ 9 files changed, 25 insertions(+), 29 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 89fcbd26805b..918bfc67d114 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -345,9 +345,9 @@ 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) - h.sh.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) diff --git a/docs/spec/staking/hooks.md b/docs/spec/staking/hooks.md index 7d24e32e6446..3644155a67ad 100644 --- a/docs/spec/staking/hooks.md +++ b/docs/spec/staking/hooks.md @@ -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 diff --git a/types/stake.go b/types/stake.go index 7b10b17f87d5..38f1c0c9baab 100644 --- a/types/stake.go +++ b/types/stake.go @@ -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 diff --git a/x/distribution/keeper/hooks.go b/x/distribution/keeper/hooks.go index cdebaf93c4bd..a4f4353fa711 100644 --- a/x/distribution/keeper/hooks.go +++ b/x/distribution/keeper/hooks.go @@ -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) { diff --git a/x/slashing/hooks.go b/x/slashing/hooks.go index 7c3367d98a59..e09f6c566e0a 100644 --- a/x/slashing/hooks.go +++ b/x/slashing/hooks.go @@ -74,9 +74,8 @@ func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddre } // Implements sdk.ValidatorHooks -func (h Hooks) OnValidatorRemoved(ctx sdk.Context, _ sdk.ValAddress) { - // TODO - h.k.onValidatorRemoved(ctx, sdk.ConsAddress{}) +func (h Hooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, _ sdk.ValAddress) { + h.k.onValidatorRemoved(ctx, consAddr) } // Implements sdk.ValidatorHooks diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index caf1cf3da6b6..94251ded31f5 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -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) diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index a2a2d9f0fe0e..c6590c94e751 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -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())) diff --git a/x/stake/keeper/hooks.go b/x/stake/keeper/hooks.go index 4a8496ddd2a1..74e830490647 100644 --- a/x/stake/keeper/hooks.go +++ b/x/stake/keeper/hooks.go @@ -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) } } diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 0eaedc4bbf1a..c7919537cf9c 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -202,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) + } + } //___________________________________________________________________________