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

R4R: Add a flag to export for zero-height start #2827

Merged
merged 73 commits into from
Nov 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
1c08b35
Initial pass
cwgoes Nov 14, 2018
492e9f0
Minor cleanup
cwgoes Nov 14, 2018
93242a2
untested core minting updates
rigelrozanski Nov 15, 2018
d9a53e5
fix initialMinter
rigelrozanski Nov 15, 2018
e61c357
Merge branch 'develop' into cwgoes/runtime-assertable-invariants
cwgoes Nov 15, 2018
dd4bc57
Update PENDING.md
cwgoes Nov 15, 2018
decf163
Add flag
cwgoes Nov 15, 2018
70d64ec
Fix flag, update docs
cwgoes Nov 15, 2018
7feb7aa
Update heights across state, add forZeroHeight handling to app.go
cwgoes Nov 15, 2018
079f7f4
Merge branch 'develop' into cwgoes/runtime-assertable-invariants
cwgoes Nov 15, 2018
f8ea009
Merge branch 'cwgoes/runtime-assertable-invariants' into cwgoes/expor…
cwgoes Nov 15, 2018
7c61478
Assert runtime invariants at application start, move export code
cwgoes Nov 15, 2018
bf2e525
Test fixes; 'make format'
cwgoes Nov 15, 2018
9c96e64
Bugfix height; return validators correctly
cwgoes Nov 15, 2018
481d801
Minor simulation fixes
cwgoes Nov 15, 2018
e6f05b2
Fix import-export tests, which cannot assert invariants
cwgoes Nov 15, 2018
58e026a
Simulation after import, include in CI
cwgoes Nov 15, 2018
e2a21f2
Avoid zero-validator case
cwgoes Nov 15, 2018
9a57abc
Fix height offset
cwgoes Nov 15, 2018
1cc058f
fix existing tests
rigelrozanski Nov 15, 2018
32e652f
working writing test
rigelrozanski Nov 16, 2018
2bd86c2
Merge branch 'develop' into cwgoes/export-for-zero-height
cwgoes Nov 16, 2018
7155483
Remove offset-by-one, must be some other issue
cwgoes Nov 16, 2018
834d472
'make format'
cwgoes Nov 16, 2018
7d6ff98
Add iteration functions
cwgoes Nov 16, 2018
c08f90c
Don't iterate over all accounts
cwgoes Nov 16, 2018
b9b979f
NextProvision test, some fixes
rigelrozanski Nov 16, 2018
f31a7e8
update mechanism to use average block time, PENDING, wip docs
rigelrozanski Nov 16, 2018
3dc8ab1
1 line compile fix
rigelrozanski Nov 16, 2018
5b0f3c9
finish updating docs
rigelrozanski Nov 16, 2018
5f70992
compile fix
rigelrozanski Nov 16, 2018
01a9246
address @cwgoes comments
rigelrozanski Nov 19, 2018
bb8c8ed
uint fixes
rigelrozanski Nov 19, 2018
fa469c2
benchmark using Int
rigelrozanski Nov 20, 2018
e1af6c6
use decimal
rigelrozanski Nov 20, 2018
58d34b7
Merge remote-tracking branch 'origin/develop' into rigel/blockly-mint
rigelrozanski Nov 20, 2018
8581dc4
Merge branch 'develop' into cwgoes/export-for-zero-height
cwgoes Nov 20, 2018
0f0ad9d
Address @rigelrozanski comments
cwgoes Nov 20, 2018
385cb68
Fix testcases
cwgoes Nov 20, 2018
06e7844
Add accum invariant
cwgoes Nov 20, 2018
645e023
minor invar update
rigelrozanski Nov 20, 2018
4d11313
doc update
rigelrozanski Nov 20, 2018
c6ce1e6
Merge branch 'develop' into rigel/blockly-mint
cwgoes Nov 20, 2018
9c74ae1
lint
rigelrozanski Nov 20, 2018
00b6497
Linter fix
cwgoes Nov 20, 2018
8b082e9
defensive checks
rigelrozanski Nov 20, 2018
3f8176b
some debugging output
rigelrozanski Nov 20, 2018
17e3bf5
Rename initGenesis to initFromGenesisState
cwgoes Nov 21, 2018
b8c2d43
Merge branch 'develop' into cwgoes/export-for-zero-height
cwgoes Nov 21, 2018
3cc2495
correct the defensive checks addresses
rigelrozanski Nov 21, 2018
94c888a
delegation share invariance
rigelrozanski Nov 21, 2018
1480510
...
rigelrozanski Nov 21, 2018
eb2bdcc
...
rigelrozanski Nov 21, 2018
f4782fe
del accum invariance
rigelrozanski Nov 21, 2018
d510df1
better invar output
rigelrozanski Nov 21, 2018
fb8aa02
PositiveDelegationInvariant
rigelrozanski Nov 22, 2018
2abab59
resolved Dec bug
rigelrozanski Nov 22, 2018
d41eeb1
PENDING.md
rigelrozanski Nov 22, 2018
b678bcc
Merge branch 'develop' into rigel/blockly-mint
rigelrozanski Nov 22, 2018
fffc100
test cover fix
rigelrozanski Nov 22, 2018
0da12f8
Merge branch 'rigel/blockly-mint' of https://github.com/cosmos/cosmos…
rigelrozanski Nov 22, 2018
ccfbfcf
...
rigelrozanski Nov 22, 2018
7c97582
missing iter.Close(), line length, reduce tab
rigelrozanski Nov 22, 2018
e38af2a
typo
rigelrozanski Nov 22, 2018
faa14f1
Merge branch 'develop' into cwgoes/export-for-zero-height
cwgoes Nov 22, 2018
822944b
Set validator.UnbondingHeight to 0
cwgoes Nov 22, 2018
dbf5a4b
Remove defer() usage
cwgoes Nov 22, 2018
685c55d
Tiny cleanup
cwgoes Nov 22, 2018
7aa1182
Merge branch 'rigel/blockly-mint' into cwgoes/export-for-zero-height
cwgoes Nov 22, 2018
3094324
Turn the ability to withdraw rewards into an invariant
cwgoes Nov 23, 2018
b1a14c1
Fix linter nit
cwgoes Nov 23, 2018
3674cb3
Correctly set height
cwgoes Nov 23, 2018
64fdd49
Merge branch 'develop' into cwgoes/export-for-zero-height
jaekwon Nov 26, 2018
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
21 changes: 21 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,24 @@ jobs:
export PATH="$GOBIN:$PATH"
make test_sim_gaia_import_export

test_sim_gaia_simulation_after_import:
<<: *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_simulation_after_import

test_sim_gaia_multi_seed:
<<: *defaults
parallelism: 1
Expand Down Expand Up @@ -301,6 +319,9 @@ workflows:
- test_sim_gaia_import_export:
requires:
- setup_dependencies
- test_sim_gaia_simulation_after_import:
requires:
- setup_dependencies
- test_sim_gaia_multi_seed:
requires:
- setup_dependencies
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ test_sim_gaia_import_export:
@echo "Running Gaia import/export simulation. This may take several minutes..."
@bash scripts/import-export-sim.sh 50

test_sim_gaia_simulation_after_import:
@echo "Running Gaia simulation-after-import. This may take several minutes..."
@bash scripts/simulation-after-import.sh 50

test_sim_gaia_multi_seed:
@echo "Running multi-seed Gaia simulation. This may take awhile!"
@bash scripts/multisim.sh 25
Expand Down
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ FEATURES
for getting governance parameters.
* [app] \#2663 - Runtime-assertable invariants
* [app] \#2791 Support export at a specific height, with `gaiad export --height=HEIGHT`.
* [app] \#2812 Support export alterations to prepare for restarting at zero-height

* SDK
* [simulator] \#2682 MsgEditValidator now looks at the validator's max rate, thus it now succeeds a significant portion of the time
Expand Down
64 changes: 21 additions & 43 deletions cmd/gaia/app/app.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package app

import (
"encoding/json"
"fmt"
"io"
"os"
Expand All @@ -22,7 +21,6 @@ import (
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
)

const (
Expand Down Expand Up @@ -218,18 +216,8 @@ func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.R
}
}

// custom logic for gaia initialization
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
stateJSON := req.AppStateBytes
// TODO is this now the whole genesis file?

var genesisState GenesisState
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}

// initialize store from a genesis state
func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisState) []abci.ValidatorUpdate {
// 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
Expand Down Expand Up @@ -276,6 +264,22 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci

validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
}
return validators
}

// custom logic for gaia initialization
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
stateJSON := req.AppStateBytes
// TODO is this now the whole genesis file?

var genesisState GenesisState
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}

validators := app.initFromGenesisState(ctx, genesisState)

// sanity check
if len(req.Validators) > 0 {
Expand All @@ -292,40 +296,14 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
}
}

// assert runtime invariants
app.assertRuntimeInvariants()

return abci.ResponseInitChain{
Validators: validators,
}
}

// export the state of gaia for a genesis file
func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
ctx := app.NewContext(true, abci.Header{})

// iterate to get the accounts
accounts := []GenesisAccount{}
appendAccount := func(acc auth.Account) (stop bool) {
account := NewGenesisAccountI(acc)
accounts = append(accounts, account)
return false
}
app.accountKeeper.IterateAccounts(ctx, appendAccount)
genState := NewGenesisState(
accounts,
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 {
return nil, nil, err
}
validators = stake.WriteValidators(ctx, app.stakeKeeper)
return appState, validators, nil
}

// load a particular height
func (app *GaiaApp) LoadHeight(height int64) error {
return app.LoadVersion(height, app.keyMain)
Expand Down
2 changes: 1 addition & 1 deletion cmd/gaia/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ func TestGaiadExport(t *testing.T) {

// Making a new app object with the db, so that initchain hasn't been called
newGapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil)
_, _, err := newGapp.ExportAppStateAndValidators()
_, _, err := newGapp.ExportAppStateAndValidators(false)
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}
156 changes: 156 additions & 0 deletions cmd/gaia/app/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
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/auth"
distr "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"
stake "github.com/cosmos/cosmos-sdk/x/stake"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
)

// export the state of gaia for a genesis file
func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool) (
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()})

if forZeroHeight {
app.prepForZeroHeightGenesis(ctx)
}

// iterate to get the accounts
accounts := []GenesisAccount{}
appendAccount := func(acc auth.Account) (stop bool) {
account := NewGenesisAccountI(acc)
accounts = append(accounts, account)
return false
}
app.accountKeeper.IterateAccounts(ctx, appendAccount)

genState := NewGenesisState(
accounts,
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 {
return nil, nil, err
}
validators = stake.WriteValidators(ctx, app.stakeKeeper)
return appState, validators, nil
}

// prepare for fresh start at zero height
func (app *GaiaApp) prepForZeroHeightGenesis(ctx sdk.Context) {

/* TODO XXX check some invariants */
rigelrozanski marked this conversation as resolved.
Show resolved Hide resolved

height := ctx.BlockHeight()

valAccum := sdk.ZeroDec()
vdiIter := func(_ int64, vdi distr.ValidatorDistInfo) bool {
lastValPower := app.stakeKeeper.GetLastValidatorPower(ctx, vdi.OperatorAddr)
valAccum = valAccum.Add(vdi.GetValAccum(height, sdk.NewDecFromInt(lastValPower)))
return false
}
app.distrKeeper.IterateValidatorDistInfos(ctx, vdiIter)

lastTotalPower := sdk.NewDecFromInt(app.stakeKeeper.GetLastTotalPower(ctx))
totalAccum := app.distrKeeper.GetFeePool(ctx).GetTotalValAccum(height, lastTotalPower)

if !totalAccum.Equal(valAccum) {
panic(fmt.Errorf("validator accum invariance: \n\tfee pool totalAccum: %v"+
"\n\tvalidator accum \t%v\n", totalAccum.String(), valAccum.String()))
}

fmt.Printf("accum invariant ok!\n")

/* END TODO XXX */

/* Handle fee distribution state. */

// withdraw all delegator & validator rewards
vdiIter = func(_ int64, valInfo distr.ValidatorDistInfo) (stop bool) {
err := app.distrKeeper.WithdrawValidatorRewardsAll(ctx, valInfo.OperatorAddr)
if err != nil {
panic(err)
}
return false
}
app.distrKeeper.IterateValidatorDistInfos(ctx, vdiIter)

ddiIter := func(_ int64, distInfo distr.DelegationDistInfo) (stop bool) {
err := app.distrKeeper.WithdrawDelegationReward(
ctx, distInfo.DelegatorAddr, distInfo.ValOperatorAddr)
if err != nil {
panic(err)
}
return false
}
app.distrKeeper.IterateDelegationDistInfos(ctx, ddiIter)

// delete all distribution infos
// these will be recreated in InitGenesis
app.distrKeeper.RemoveValidatorDistInfos(ctx)
app.distrKeeper.RemoveDelegationDistInfos(ctx)

// assert that the fee pool is empty
feePool := app.distrKeeper.GetFeePool(ctx)
if !feePool.TotalValAccum.Accum.IsZero() {
panic("unexpected leftover validator accum")
}
bondDenom := app.stakeKeeper.GetParams(ctx).BondDenom
if !feePool.ValPool.AmountOf(bondDenom).IsZero() {
panic(fmt.Sprintf("unexpected leftover validator pool coins: %v",
feePool.ValPool.AmountOf(bondDenom).String()))
}

// reset fee pool height, save fee pool
feePool.TotalValAccum.UpdateHeight = 0
app.distrKeeper.SetFeePool(ctx, feePool)

/* Handle stake state. */

// iterate through validators by power descending, reset bond height, update bond intra-tx counter
store := ctx.KVStore(app.keyStake)
iter := sdk.KVStoreReversePrefixIterator(store, stake.ValidatorsByPowerIndexKey)
counter := int16(0)
for ; iter.Valid(); iter.Next() {
addr := sdk.ValAddress(iter.Value())
validator, found := app.stakeKeeper.GetValidator(ctx, addr)
if !found {
panic("expected validator, not found")
}
validator.BondHeight = 0
validator.BondIntraTxCounter = counter
validator.UnbondingHeight = 0
app.stakeKeeper.SetValidator(ctx, validator)
counter++
}
iter.Close()

/* Handle slashing state. */

// we have to clear the slashing periods, since they reference heights
app.slashingKeeper.DeleteValidatorSlashingPeriods(ctx)

// reset start height on signing infos
app.slashingKeeper.IterateValidatorSigningInfos(ctx, func(addr sdk.ConsAddress, info slashing.ValidatorSigningInfo) (stop bool) {
info.StartHeight = 0
app.slashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
return false
})
}
Loading