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

State export import #348

Merged
merged 25 commits into from
May 5, 2022
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
31 changes: 17 additions & 14 deletions app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ import (
var emptyWasmOpts []wasm.Option = nil

func TestTgradeExport(t *testing.T) {
t.Skip("Alex, export is not implemented")
alpe marked this conversation as resolved.
Show resolved Hide resolved

db := db.NewMemDB()
gapp := NewTgradeApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeEncodingConfig(), EmptyBaseAppOptions{}, emptyWasmOpts)
genesisState := NewDefaultGenesisState()
Expand All @@ -37,7 +35,6 @@ func TestTgradeExport(t *testing.T) {

stateBytes, err := json.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)

// Initialize the chain
gapp.InitChain(
abci.RequestInitChain{
Expand All @@ -62,6 +59,10 @@ func setupWithSingleValidatorGenTX(t *testing.T, genesisState GenesisState) {
// - enough funds on the bank
// - membership in engagement group
marshaler := MakeEncodingConfig().Codec
poeGS := poetypes.GetGenesisStateFromAppState(marshaler, genesisState)
if poeGS.GetSeedContracts() == nil {
panic("not in seed mode")
}

systemAdminAddr := sdk.AccAddress(rand.Bytes(address.Len))
myGenTx, myAddr, _ := poetypes.RandomGenTX(t, 100)
Expand All @@ -79,34 +80,36 @@ func setupWithSingleValidatorGenTX(t *testing.T, genesisState GenesisState) {
marshaler.MustUnmarshalJSON(genesisState[banktypes.ModuleName], &bankGenState)

coins := sdk.Coins{sdk.NewCoin(poetypes.DefaultBondDenom, sdk.NewInt(1000000000))}
bankGenState.Balances = append(bankGenState.Balances, banktypes.Balance{Address: myAddr.String(), Coins: coins.Sort()})
bankGenState.Balances = append(bankGenState.Balances, banktypes.Balance{Address: systemAdminAddr.String(), Coins: coins.Sort()})
bankGenState.Balances = append(bankGenState.Balances, banktypes.Balance{Address: myAddr.String(), Coins: coins})
bankGenState.Supply = bankGenState.Supply.Add(coins...)
bankGenState.Balances = append(bankGenState.Balances, banktypes.Balance{Address: systemAdminAddr.String(), Coins: coins})
bankGenState.Supply = bankGenState.Supply.Add(coins...)

genAddrAndUpdateBalance := func(numAddr int, balance sdk.Coins) []string {
genAddr := make([]string, numAddr)
for i := 0; i < numAddr; i++ {
addr := poetypes.RandomAccAddress().String()
bankGenState.Balances = append(bankGenState.Balances, banktypes.Balance{Address: addr, Coins: balance})
genAddr[i] = addr
bankGenState.Supply = bankGenState.Supply.Add(balance...)
}
return genAddr
}
// add 3 oc members
ocMembers := genAddrAndUpdateBalance(3, coins.Sort())
ocMembers := genAddrAndUpdateBalance(3, coins)

// add 2 ap members
apMembers := genAddrAndUpdateBalance(2, coins.Sort())
apMembers := genAddrAndUpdateBalance(2, coins)

genesisState[banktypes.ModuleName] = marshaler.MustMarshalJSON(&bankGenState)

// add system admin to not fail poe on validation
poeGS := poetypes.GetGenesisStateFromAppState(marshaler, genesisState)
poeGS.BondDenom = poetypes.DefaultBondDenom
poeGS.GenTxs = []json.RawMessage{myGenTx}
poeGS.Engagement = []poetypes.TG4Member{{Address: myAddr.String(), Points: 10}}
poeGS.SystemAdminAddress = systemAdminAddr.String()
poeGS.OversightCommunityMembers = ocMembers
poeGS.ArbiterPoolMembers = apMembers
poeGS.GetSeedContracts().BondDenom = poetypes.DefaultBondDenom
poeGS.GetSeedContracts().GenTxs = []json.RawMessage{myGenTx}
poeGS.GetSeedContracts().Engagement = []poetypes.TG4Member{{Address: myAddr.String(), Points: 10}}
poeGS.GetSeedContracts().SystemAdminAddress = systemAdminAddr.String()
poeGS.GetSeedContracts().OversightCommunityMembers = ocMembers
poeGS.GetSeedContracts().ArbiterPoolMembers = apMembers
genesisState = poetypes.SetGenesisStateInAppState(marshaler, genesisState, poeGS)
}

Expand Down
248 changes: 76 additions & 172 deletions app/export.go
Original file line number Diff line number Diff line change
@@ -1,185 +1,89 @@
package app

import (
"encoding/json"
"time"

servertypes "github.com/cosmos/cosmos-sdk/server/types"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
tmcrypto "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/encoding"
pc "github.com/tendermint/tendermint/proto/tendermint/crypto"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"

"github.com/confio/tgrade/x/poe/contract"
)

// ExportAppStateAndValidators exports the state of the application for a genesis
// file.
func (app *TgradeApp) ExportAppStateAndValidators(
forZeroHeight bool, jailAllowedAddrs []string,
) (servertypes.ExportedApp, error) {
panic("Alex, not implemented")
//// as if they could withdraw from the start of the next block
//ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
//
//// We export at last height + 1, because that's the height at which
//// Tendermint will start InitChain.
//height := app.LastBlockHeight() + 1
//if forZeroHeight {
// height = 0
// app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs)
//}
//
//genState := app.mm.ExportGenesis(ctx, app.appCodec)
//appState, err := json.MarshalIndent(genState, "", " ")
//if err != nil {
// return servertypes.ExportedApp{}, err
//}
//
//validators, err := staking.WriteValidators(ctx, app.stakingKeeper)
//return servertypes.ExportedApp{
// AppState: appState,
// Validators: validators,
// Height: height,
// ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
//}, err
if forZeroHeight {
alpe marked this conversation as resolved.
Show resolved Hide resolved
panic("zero height export not supported")
}
// as if they could withdraw from the start of the next block
ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}).
WithBlockTime(time.Now().UTC()) // todo (Alex): check if there is any way to get the last block time

// We export at last height + 1, because that's the height at which
// Tendermint will start InitChain.
height := app.LastBlockHeight() + 1
genState := app.mm.ExportGenesis(ctx, app.appCodec)
appState, err := json.MarshalIndent(genState, "", " ")
if err != nil {
return servertypes.ExportedApp{}, err
}

validators, err := activeValidatorSet(app, ctx, err)
alpe marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return servertypes.ExportedApp{}, err
}
return servertypes.ExportedApp{
AppState: appState,
Validators: validators,
Height: height,
ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
}, 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 *TgradeApp) 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.OperatorAddress)
// 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.OperatorAddress)
// 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.keys[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++
// }
//
// iter.Close()
//
// _, 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 activeValidatorSet(app *TgradeApp, ctx sdk.Context, err error) ([]tmtypes.GenesisValidator, error) {
var result []tmtypes.GenesisValidator
valset := app.poeKeeper.ValsetContract(ctx)
valset.IterateActiveValidators(ctx, func(c contract.ValidatorInfo) bool {
var opAddr sdk.AccAddress
opAddr, err = sdk.AccAddressFromBech32(c.Operator)
if err != nil {
return true
}
var pk pc.PublicKey
pk, err = contract.ConvertToTendermintPubKey(c.ValidatorPubkey)
if err != nil {
return true
}
var tmPk tmcrypto.PubKey
tmPk, err = encoding.PubKeyFromProto(pk)
if err != nil {
return true
}
var meta *stakingtypes.Validator
meta, err = valset.QueryValidator(ctx, opAddr)
if err != nil {
return true
}
moniker := ""
if meta != nil {
moniker = meta.GetMoniker()
}
result = append(result, tmtypes.GenesisValidator{
Address: tmPk.Address(),
PubKey: tmPk,
Power: int64(c.Power),
Name: moniker,
})
return false
}, nil)
return result, err
}
Loading