github.com/Finschia/finschia-sdk@v0.48.1/simapp/export.go (about)

     1  package simapp
     2  
     3  import (
     4  	"encoding/json"
     5  	"log"
     6  
     7  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
     8  
     9  	servertypes "github.com/Finschia/finschia-sdk/server/types"
    10  	sdk "github.com/Finschia/finschia-sdk/types"
    11  	slashingtypes "github.com/Finschia/finschia-sdk/x/slashing/types"
    12  	"github.com/Finschia/finschia-sdk/x/staking"
    13  	stakingtypes "github.com/Finschia/finschia-sdk/x/staking/types"
    14  )
    15  
    16  // ExportAppStateAndValidators exports the state of the application for a genesis
    17  // file.
    18  func (app *SimApp) ExportAppStateAndValidators(
    19  	forZeroHeight bool, jailAllowedAddrs []string,
    20  ) (servertypes.ExportedApp, error) {
    21  	// as if they could withdraw from the start of the next block
    22  	ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
    23  
    24  	// We export at last height + 1, because that's the height at which
    25  	// Tendermint will start InitChain.
    26  	height := app.LastBlockHeight() + 1
    27  	if forZeroHeight {
    28  		height = 0
    29  		app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs)
    30  	}
    31  
    32  	genState := app.mm.ExportGenesis(ctx, app.appCodec)
    33  	appState, err := json.MarshalIndent(genState, "", "  ")
    34  	if err != nil {
    35  		return servertypes.ExportedApp{}, err
    36  	}
    37  
    38  	validators, err := staking.WriteValidators(ctx, app.StakingKeeper)
    39  	return servertypes.ExportedApp{
    40  		AppState:        appState,
    41  		Validators:      validators,
    42  		Height:          height,
    43  		ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
    44  	}, err
    45  }
    46  
    47  // prepare for fresh start at zero height
    48  // NOTE zero height genesis is a temporary feature which will be deprecated
    49  //
    50  //	in favour of export at a block height
    51  func (app *SimApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) {
    52  	applyAllowedAddrs := false
    53  
    54  	// check if there is a allowed address list
    55  	if len(jailAllowedAddrs) > 0 {
    56  		applyAllowedAddrs = true
    57  	}
    58  
    59  	allowedAddrsMap := make(map[string]bool)
    60  
    61  	for _, addr := range jailAllowedAddrs {
    62  		_, err := sdk.ValAddressFromBech32(addr)
    63  		if err != nil {
    64  			log.Fatal(err)
    65  		}
    66  		allowedAddrsMap[addr] = true
    67  	}
    68  
    69  	/* Just to be safe, assert the invariants on current state. */
    70  	app.CrisisKeeper.AssertInvariants(ctx)
    71  
    72  	/* Handle fee distribution state. */
    73  
    74  	// withdraw all validator commission
    75  	app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
    76  		_, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator())
    77  		return false
    78  	})
    79  
    80  	// withdraw all delegator rewards
    81  	dels := app.StakingKeeper.GetAllDelegations(ctx)
    82  	for _, delegation := range dels {
    83  		valAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress)
    84  		if err != nil {
    85  			panic(err)
    86  		}
    87  
    88  		delAddr := sdk.MustAccAddressFromBech32(delegation.DelegatorAddress)
    89  
    90  		_, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr)
    91  	}
    92  
    93  	// clear validator slash events
    94  	app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx)
    95  
    96  	// clear validator historical rewards
    97  	app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx)
    98  
    99  	// set context height to zero
   100  	height := ctx.BlockHeight()
   101  	ctx = ctx.WithBlockHeight(0)
   102  
   103  	// reinitialize all validators
   104  	app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
   105  		// donate any unwithdrawn outstanding reward fraction tokens to the community pool
   106  		scraps := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator())
   107  		feePool := app.DistrKeeper.GetFeePool(ctx)
   108  		feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
   109  		app.DistrKeeper.SetFeePool(ctx, feePool)
   110  
   111  		app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator())
   112  		return false
   113  	})
   114  
   115  	// reinitialize all delegations
   116  	for _, del := range dels {
   117  		valAddr, err := sdk.ValAddressFromBech32(del.ValidatorAddress)
   118  		if err != nil {
   119  			panic(err)
   120  		}
   121  		delAddr := sdk.MustAccAddressFromBech32(del.DelegatorAddress)
   122  		app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr)
   123  		app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr)
   124  	}
   125  
   126  	// reset context height
   127  	ctx = ctx.WithBlockHeight(height)
   128  
   129  	/* Handle staking state. */
   130  
   131  	// iterate through redelegations, reset creation height
   132  	app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) {
   133  		for i := range red.Entries {
   134  			red.Entries[i].CreationHeight = 0
   135  		}
   136  		app.StakingKeeper.SetRedelegation(ctx, red)
   137  		return false
   138  	})
   139  
   140  	// iterate through unbonding delegations, reset creation height
   141  	app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) {
   142  		for i := range ubd.Entries {
   143  			ubd.Entries[i].CreationHeight = 0
   144  		}
   145  		app.StakingKeeper.SetUnbondingDelegation(ctx, ubd)
   146  		return false
   147  	})
   148  
   149  	// Iterate through validators by power descending, reset bond heights, and
   150  	// update bond intra-tx counters.
   151  	store := ctx.KVStore(app.keys[stakingtypes.StoreKey])
   152  	iter := sdk.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey)
   153  	counter := int16(0)
   154  
   155  	for ; iter.Valid(); iter.Next() {
   156  		addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key()))
   157  		validator, found := app.StakingKeeper.GetValidator(ctx, addr)
   158  		if !found {
   159  			panic("expected validator, not found")
   160  		}
   161  
   162  		validator.UnbondingHeight = 0
   163  		if applyAllowedAddrs && !allowedAddrsMap[addr.String()] {
   164  			validator.Jailed = true
   165  		}
   166  
   167  		app.StakingKeeper.SetValidator(ctx, validator)
   168  		counter++
   169  	}
   170  
   171  	iter.Close()
   172  
   173  	_, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
   174  	if err != nil {
   175  		log.Fatal(err)
   176  	}
   177  
   178  	/* Handle slashing state. */
   179  
   180  	// reset start height on signing infos
   181  	app.SlashingKeeper.IterateValidatorSigningInfos(
   182  		ctx,
   183  		func(addr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) {
   184  			info.StartHeight = 0
   185  			app.SlashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
   186  			return false
   187  		},
   188  	)
   189  }