Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow state exporting from any directory (backport #3608) #3613

Merged
merged 2 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Bug Fixes

* [#3608](https://github.com/osmosis-labs/osmosis/pull/3608) Make it possible to state export from any directory.

## v12.3.0

* [#3325](https://github.com/osmosis-labs/osmosis/pull/3325) Use mainline iavl v0.19.4 instead of our iavl fork
Expand Down
159 changes: 4 additions & 155 deletions app/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ package app

import (
"encoding/json"
"log"
"fmt"

tmproto "github.com/tendermint/tendermint/proto/tendermint/types"

servertypes "github.com/cosmos/cosmos-sdk/server/types"
sdk "github.com/cosmos/cosmos-sdk/types"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

// ExportAppStateAndValidators exports the state of the application for a genesis
Expand All @@ -25,8 +23,7 @@ func (app *OsmosisApp) ExportAppStateAndValidators(
// Tendermint will start InitChain.
height := app.LastBlockHeight() + 1
if forZeroHeight {
height = 0
app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs)
return servertypes.ExportedApp{}, fmt.Errorf("forZeroHeight not supported")
}

genState := app.mm.ExportGenesis(ctx, app.AppCodec(), modulesToExport)
Expand All @@ -44,154 +41,6 @@ func (app *OsmosisApp) ExportAppStateAndValidators(
}, err
}

// prepare for fresh start at zero height
// NOTE zero height genesis is a temporary feature which will be deprecated
//
// in favour of export at a block height
func (app *OsmosisApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) {
applyAllowedAddrs := false

// check if there is a allowed address list
if len(jailAllowedAddrs) > 0 {
applyAllowedAddrs = true
}

allowedAddrsMap := make(map[string]bool)

for _, addr := range jailAllowedAddrs {
_, err := sdk.ValAddressFromBech32(addr)
if err != nil {
log.Fatal(err)
}
allowedAddrsMap[addr] = true
}

/* Just to be safe, assert the invariants on current state. */
app.CrisisKeeper.AssertInvariants(ctx)

/* Handle fee distribution state. */

// withdraw all validator commission
app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
_, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator())
return false
})

// withdraw all delegator rewards
dels := app.StakingKeeper.GetAllDelegations(ctx)
for _, delegation := range dels {
valAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress)
if err != nil {
panic(err)
}

delAddr, err := sdk.AccAddressFromBech32(delegation.DelegatorAddress)
if err != nil {
panic(err)
}
_, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr)
}

// clear validator slash events
app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx)

// clear validator historical rewards
app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx)

// set context height to zero
height := ctx.BlockHeight()
ctx = ctx.WithBlockHeight(0)

// reinitialize all validators
app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
// donate any unwithdrawn outstanding reward fraction tokens to the community pool
scraps := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator())
feePool := app.DistrKeeper.GetFeePool(ctx)
feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
app.DistrKeeper.SetFeePool(ctx, feePool)

app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator())
return false
})

// reinitialize all delegations
for _, del := range dels {
valAddr, err := sdk.ValAddressFromBech32(del.ValidatorAddress)
if err != nil {
panic(err)
}
delAddr, err := sdk.AccAddressFromBech32(del.DelegatorAddress)
if err != nil {
panic(err)
}
app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr)
app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr)
}

// reset context height
ctx = ctx.WithBlockHeight(height)

/* Handle staking state. */

// iterate through redelegations, reset creation height
app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) {
for i := range red.Entries {
red.Entries[i].CreationHeight = 0
}
app.StakingKeeper.SetRedelegation(ctx, red)
return false
})

// iterate through unbonding delegations, reset creation height
app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) {
for i := range ubd.Entries {
ubd.Entries[i].CreationHeight = 0
}
app.StakingKeeper.SetUnbondingDelegation(ctx, ubd)
return false
})

// Iterate through validators by power descending, reset bond heights, and
// update bond intra-tx counters.
store := ctx.KVStore(app.GetKey(stakingtypes.StoreKey))
iter := sdk.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey)
counter := int16(0)

for ; iter.Valid(); iter.Next() {
addr := sdk.ValAddress(iter.Key()[1:])
validator, found := app.StakingKeeper.GetValidator(ctx, addr)
if !found {
panic("expected validator, not found")
}

validator.UnbondingHeight = 0
if applyAllowedAddrs && !allowedAddrsMap[addr.String()] {
validator.Jailed = true
}

app.StakingKeeper.SetValidator(ctx, validator)
counter++
}

err := iter.Close()
if err != nil {
log.Fatal(err)
}

_, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
if err != nil {
log.Fatal(err)
}

/* Handle slashing state. */

// reset start height on signing infos
app.SlashingKeeper.IterateValidatorSigningInfos(
ctx,
func(addr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) {
info.StartHeight = 0
app.SlashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
return false
},
)
func (app *OsmosisApp) ExportState(ctx sdk.Context) map[string]json.RawMessage {
return app.mm.ExportGenesis(ctx, app.AppCodec(), []string{})
}
9 changes: 4 additions & 5 deletions cmd/osmosisd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,14 @@ func createOsmosisAppAndExport(
) (servertypes.ExportedApp, error) {
encCfg := osmosis.MakeEncodingConfig() // Ideally, we would reuse the one created by NewRootCmd.
encCfg.Marshaler = codec.NewProtoCodec(encCfg.InterfaceRegistry)
var app *osmosis.OsmosisApp
if height != -1 {
app = osmosis.NewOsmosisApp(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), appOpts, osmosis.GetWasmEnabledProposals(), osmosis.EmptyWasmOpts)
loadLatest := height == -1
homeDir := cast.ToString(appOpts.Get(flags.FlagHome))
app := osmosis.NewOsmosisApp(logger, db, traceStore, loadLatest, map[int64]bool{}, homeDir, 0, appOpts, osmosis.GetWasmEnabledProposals(), osmosis.EmptyWasmOpts)

if !loadLatest {
if err := app.LoadHeight(height); err != nil {
return servertypes.ExportedApp{}, err
}
} else {
app = osmosis.NewOsmosisApp(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), appOpts, osmosis.GetWasmEnabledProposals(), osmosis.EmptyWasmOpts)
}

return app.ExportAppStateAndValidators(forZeroHeight, jailWhiteList, modulesToExport)
Expand Down