Skip to content

Commit

Permalink
[Master][DFI-928] Mainnet v1.0 migration (#235)
Browse files Browse the repository at this point in the history
* [DFI-929] migration to v1.0 added; MaxSelfStake staking param support added

* [DFI-929] fixed CSDK version

* [DFI-928] BaseMigrate -> Migrate renaming

* [DFI-929] defaults and restrictions modified to match v1.0 release

* [DFI-947] CSDK version bump

* [DFI-929] appState export update to support zero-height genesis export

* [DFI-929] multisig, orderbook mods: PrepareForZeroHeight squash funcs added

* [DFI-929] multisig mod: call queue fix for genesis squash; app export refactoring, debug added

* [DFI-929] ccstorage, vmauth mods: PrepareForZeroHeight added; mainnet export config added

* [DFI-929] mint mod PrepareForZeroHeight support added

* [DFI-929] gov mod PrepareForZeroHeight support added

* [DFI-947] Mainnet v1.0 migration fixes and report generation

* [DFI-947] Debug validator disabled

* [DFI-947] Mainnet v1.0 export report modification to support a newer CSDK version (BankRewards per validator)

* Linter fixes; tests skip due to changed app limitation; simulator fix to support new distr RewardsBank API

* CLItester fix: increased init acc balance as Gov deposit increased)

* CSDK version bump
  • Loading branch information
Mikhail Kornilov authored Nov 5, 2020
1 parent f208a41 commit aa2b01e
Show file tree
Hide file tree
Showing 28 changed files with 1,451 additions and 126 deletions.
19 changes: 0 additions & 19 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
tmOs "github.com/tendermint/tendermint/libs/os"
tmTypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tm-db"
"google.golang.org/grpc"

Expand Down Expand Up @@ -619,21 +618,3 @@ func (app *DnServiceApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a
func (app *DnServiceApp) LoadHeight(height int64) error {
return app.LoadVersion(height, app.keys[bam.MainStoreKey])
}

// Exports genesis and validators.
func (app *DnServiceApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string,
) (appState json.RawMessage, validators []tmTypes.GenesisValidator, err error) {

// as if they could withdraw from the start of the next block.
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})

genState := app.mm.ExportGenesis(ctx)
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
if err != nil {
return nil, nil, err
}

validators = staking.WriteValidators(ctx, app.stakingKeeper)

return appState, validators, nil
}
4 changes: 4 additions & 0 deletions app/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (

// TestBankSXFI_CLI transfers for sxfi token must be disallowed
func TestBankSXFI_CLI(t *testing.T) {
t.Skip("skipped as dist limitations are disabled for the Mainnet")
t.Parallel()

ct := cliTester.New(t, false)
Expand All @@ -56,6 +57,7 @@ func TestBankSXFI_CLI(t *testing.T) {

// TestGovSXFI_CLI gov deposit allowed just for sxfi token
func TestGovSXFI_CLI(t *testing.T) {
t.Skip("test skipped as it is no longer relevant for Mainnet")
t.Parallel()

ct := cliTester.New(t, false)
Expand All @@ -71,6 +73,7 @@ func TestGovSXFI_CLI(t *testing.T) {

// TestStakeSXFI_CLI staking allowed just for sxfi token
func TestStakeSXFI_CLI(t *testing.T) {
t.Skip("skipped as dist limitations are disabled for the Mainnet")
t.Parallel()

ct := cliTester.New(t, false)
Expand Down Expand Up @@ -305,6 +308,7 @@ func TestCurrencies_CLI(t *testing.T) {

// Check that distribution commands in CLI disabled.
func TestDisableRewards_CLI(t *testing.T) {
t.Skip("skipped as dist limitations are disabled for the Mainnet")
t.Parallel()

ct := cliTester.New(t, false)
Expand Down
2 changes: 2 additions & 0 deletions app/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ func GetGenesis(app *DnServiceApp, chainID, monikerID string, nodeAccPrivKey sec
stakingGenesis := staking.GenesisState{}
app.cdc.MustUnmarshalJSON(genesisState[staking.ModuleName], &stakingGenesis)
stakingGenesis.Params.BondDenom = defaults.MainDenom
maxStakingLvl, _ := sdk.NewIntFromString("1000000000000000000000000")
stakingGenesis.Params.MaxSelfDelegationLvl = maxStakingLvl
genesisState[staking.ModuleName] = codec.MustMarshalJSONIndent(app.cdc, stakingGenesis)

// update mint denom
Expand Down
307 changes: 307 additions & 0 deletions app/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
package app

import (
"encoding/json"
"fmt"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/cosmos/cosmos-sdk/x/supply"
abci "github.com/tendermint/tendermint/abci/types"
tmTypes "github.com/tendermint/tendermint/types"

"github.com/dfinance/dnode/x/ccstorage"
"github.com/dfinance/dnode/x/multisig"
"github.com/dfinance/dnode/x/orderbook"
"github.com/dfinance/dnode/x/vmauth"
)

// Exports genesis and validators.
func (app *DnServiceApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string,
) (appState json.RawMessage, validators []tmTypes.GenesisValidator, retErr error) {

var err error

// create a new context
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})

// zero-height squash
if forZeroHeight {
if err := app.prepareGenesisForZeroHeight(ctx, jailWhiteList); err != nil {
retErr = fmt.Errorf("preparing genesis for zero-height: %w", err)
return
}
}

// genesis export
genState := app.mm.ExportGenesis(ctx)
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
if err != nil {
retErr = fmt.Errorf("genState JSON marshal: %w", err)
return
}

validators = staking.WriteValidators(ctx, app.stakingKeeper)

return appState, validators, nil
}

func (app *DnServiceApp) checkInvariants(ctx sdk.Context) error {
for _, invRoute := range app.crisisKeeper.Routes() {
res, stop := invRoute.Invar(ctx)
if stop {
return fmt.Errorf("module %s (%s): %s", invRoute.ModuleName, invRoute.Route, res)
}
}

return nil
}

// prepareGenesisForZeroHeight updates current context to fit zero-height genesis.
// Basically it "squashes" all height-dependent storage objects.
func (app *DnServiceApp) prepareGenesisForZeroHeight(ctx sdk.Context, jailWhiteList []string) error {
// Check invariants before
if err := app.checkInvariants(ctx); err != nil {
return fmt.Errorf("pre invariants check failed: %w", err)
}

// Prepare PrepareForZeroHeight module functions options
optsMap, err := prepareDefaultZeroHeightOptions(jailWhiteList)
if err != nil {
return fmt.Errorf("prepareDefaultZeroHeightOptions: %w", err)
}
//optsMap, err = setDebugZeroHeightOptions(optsMap)
//if err != nil {
// return fmt.Errorf("setDebugZeroHeightOptions: %w", err)
//}
//optsMap, err = setMainnetZeroHeightOptionsV10(optsMap)
//if err != nil {
// return fmt.Errorf("setMainnetZeroHeightOptionsV10: %w", err)
//}

// CCStorage
{
moduleName := ccstorage.ModuleName
opts := optsMap[moduleName].(ccstorage.SquashOptions)
if err := app.ccsKeeper.PrepareForZeroHeight(ctx, opts); err != nil {
return fmt.Errorf("module %s: %w", moduleName, err)
}
}
// Supply
{
moduleName := supply.ModuleName
opts := optsMap[moduleName].(supply.SquashOptions)
if err := app.supplyKeeper.PrepareForZeroHeight(ctx, opts); err != nil {
return fmt.Errorf("module %s: %w", moduleName, err)
}
}
// VMAuth
{
moduleName := vmauth.ModuleName
opts := optsMap[moduleName].(vmauth.SquashOptions)
if err := app.accountKeeper.PrepareForZeroHeight(ctx, opts); err != nil {
return fmt.Errorf("module %s: %w", moduleName, err)
}
}
// Staking
{
moduleName := staking.ModuleName
opts := optsMap[moduleName].(staking.SquashOptions)
if err := app.stakingKeeper.PrepareForZeroHeight(ctx, opts); err != nil {
return fmt.Errorf("module %s: %w", moduleName, err)
}
}
// Distribution
{
moduleName := distribution.ModuleName
opts := optsMap[moduleName].(distribution.SquashOptions)
if err := app.distrKeeper.PrepareForZeroHeight(ctx, opts); err != nil {
return fmt.Errorf("module %s: %w", moduleName, err)
}
}
// Slashing
{
moduleName := slashing.ModuleName
if err := app.slashingKeeper.PrepareForZeroHeight(ctx); err != nil {
return fmt.Errorf("module %s: %w", moduleName, err)
}
}
// Mint
{
moduleName := mint.ModuleName
opts := optsMap[moduleName].(mint.SquashOptions)
if err := app.mintKeeper.PrepareForZeroHeight(ctx, opts); err != nil {
return fmt.Errorf("module %s: %w", moduleName, err)
}
}
// Gov
{
moduleName := gov.ModuleName
opts := optsMap[moduleName].(gov.SquashOptions)
if err := app.govKeeper.PrepareForZeroHeight(ctx, opts); err != nil {
return fmt.Errorf("module %s: %w", moduleName, err)
}
}
// MultiSig
{
moduleName := multisig.ModuleName
if err := app.msKeeper.PrepareForZeroHeight(ctx); err != nil {
return fmt.Errorf("module %s: %w", moduleName, err)
}
}
// OrderBook
{
moduleName := orderbook.ModuleName
if err := app.orderBookKeeper.PrepareForZeroHeight(ctx); err != nil {
return fmt.Errorf("module %s: %w", moduleName, err)
}
}

// Check invariants after
if err := app.checkInvariants(ctx); err != nil {
return fmt.Errorf("post invariants check failed: %w", err)
}

//
if err := app.processMainnetSXFIBalance(ctx); err != nil {
return fmt.Errorf("mainnet v1.0 processing: %w", err)
}

return nil
}

// prepareDefaultZeroHeightOptions returns base (default) options map per module for PrepareForZeroHeight functions.
func prepareDefaultZeroHeightOptions(jailWhiteList []string) (map[string]interface{}, error) {
optsMap := make(map[string]interface{})

// CCStorage
{
moduleName := ccstorage.ModuleName
opts := ccstorage.NewEmptySquashOptions()
optsMap[moduleName] = opts
}
// Supply
{
moduleName := supply.ModuleName
opts := supply.NewEmptySquashOptions()
optsMap[moduleName] = opts
}
// VMAuth
{
moduleName := vmauth.ModuleName
opts := vmauth.NewEmptySquashOptions()
optsMap[moduleName] = opts
}
// Staking
{
moduleName := staking.ModuleName
opts := staking.NewEmptySquashOptions()
if err := opts.SetJailWhitelistSquashOption(jailWhiteList); err != nil {
return nil, fmt.Errorf("module %s: %w", moduleName, err)
}
optsMap[moduleName] = opts
}
// Distribution
{
moduleName := distribution.ModuleName
opts := distribution.NewEmptySquashOptions()
optsMap[moduleName] = opts
}
// Mint
{
moduleName := mint.ModuleName
opts := mint.NewEmptySquashOptions()
optsMap[moduleName] = opts
}
// Gov
{
moduleName := gov.ModuleName
opts := gov.NewEmptySquashOptions()
optsMap[moduleName] = opts
}

return optsMap, nil
}

// setDebugZeroHeightOptions updates options map per module for debug purposes.
// Adds a fake validator jailing all the others.
// This mod is helpful to run exported genesis locally with one up and running validator.
func setDebugZeroHeightOptions(optsMap map[string]interface{}) (map[string]interface{}, error) {
const (
// Values below are hardcoded according to bootstrap init_single_w_genesis.sh script values
fakeValOperatorAddress = "wallet17raernuazufad6q48uc5jdnqmuzsep5a03dc0n"
fakeValMoniker = "fakeVal"
fakeValPubKey = "walletvalconspub1zcjduepqu9mgrhdjfmwwalv86vdsavvvxfy8r4fmt4py8ehep252rs0acs5q93t5nm"
fakeValSelfDelegationAmount = "1000000000000000000000000"
//
stakingDenom = "sxfi"
)

// Supply
{
moduleName := supply.ModuleName
optsObj, found := optsMap[moduleName]
if !found {
return nil, fmt.Errorf("module %s: options not found", moduleName)
}
opts, ok := optsObj.(supply.SquashOptions)
if !ok {
return nil, fmt.Errorf("module %s: options type assert failed: %T", moduleName, optsObj)
}

if err := opts.SetDenomOp(stakingDenom, false, "", fakeValSelfDelegationAmount); err != nil {
return nil, fmt.Errorf("module %s: %w", moduleName, err)
}
optsMap[moduleName] = opts
}
// VMAuth
{
moduleName := vmauth.ModuleName
optsObj, found := optsMap[moduleName]
if !found {
return nil, fmt.Errorf("module %s: options not found", moduleName)
}
opts, ok := optsObj.(vmauth.SquashOptions)
if !ok {
return nil, fmt.Errorf("module %s: options type assert failed: %T", moduleName, optsObj)
}

if err := opts.SetAddAccountOp(fakeValOperatorAddress, fakeValSelfDelegationAmount+stakingDenom); err != nil {
return nil, fmt.Errorf("module %s: %w", moduleName, err)
}
optsMap[moduleName] = opts
}
// Staking
{
moduleName := staking.ModuleName
optsObj, found := optsMap[moduleName]
if !found {
return nil, fmt.Errorf("module %s: options not found", moduleName)
}
opts, ok := optsObj.(staking.SquashOptions)
if !ok {
return nil, fmt.Errorf("module %s: options type assert failed: %T", moduleName, optsObj)
}

accAddr, err := sdk.AccAddressFromBech32(fakeValOperatorAddress)
if err != nil {
return nil, fmt.Errorf("module %s: invalid fakeValOperatorAddress (%s): %w", moduleName, fakeValOperatorAddress, err)
}
valAddr := sdk.ValAddress(accAddr)

if err := opts.SetAddValidatorOp(fakeValOperatorAddress, fakeValMoniker, fakeValPubKey, fakeValSelfDelegationAmount); err != nil {
return nil, fmt.Errorf("module %s: %w", moduleName, err)
}
if err := opts.SetJailWhitelistSquashOption([]string{valAddr.String()}); err != nil {
return nil, fmt.Errorf("module %s: %w", moduleName, err)
}
optsMap[moduleName] = opts
}

return optsMap, nil
}
Loading

0 comments on commit aa2b01e

Please sign in to comment.