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

Fix simulation bugs; Incorprates #2676 from Sunny #2677

Merged
merged 26 commits into from
Nov 5, 2018
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4e44ddf
Print out initial update on every block
cwgoes Oct 28, 2018
38ceea1
Randomize simulation parameters
cwgoes Oct 28, 2018
4e48217
Randomize initial liveness weightings
cwgoes Oct 28, 2018
46e6b40
Randomize genesis parameters
cwgoes Oct 28, 2018
3884b13
Update PENDING.md
cwgoes Oct 28, 2018
991573e
Avoid dividing-by-zero
cwgoes Oct 28, 2018
f5918db
More simulation seeds, more blocks in CI version
cwgoes Oct 29, 2018
e2aa3e9
Update cmd/gaia/app/sim_test.go
zmanian Oct 29, 2018
01c235d
Update cmd/gaia/app/sim_test.go
zmanian Oct 29, 2018
f13f602
Update cmd/gaia/app/sim_test.go
zmanian Oct 29, 2018
1868ee3
Merge remote-tracking branch 'origin/develop' into cwgoes/simulation-…
rigelrozanski Oct 31, 2018
a84cf4f
Merge tag 'v0.25.0' into develop
cwgoes Nov 1, 2018
fb0f4a4
Merge branch 'develop' into cwgoes/simulation-transubstantiated
cwgoes Nov 1, 2018
d9907cc
Address comments
cwgoes Nov 1, 2018
f695a66
Minimize variable passing
cwgoes Nov 1, 2018
39165c9
fixed power store invariant
sunnya97 Nov 2, 2018
3cf6687
PENDING
sunnya97 Nov 2, 2018
42eb4e2
IterateValidatorsBonded -> IterateBondedValidatorsByPower
sunnya97 Nov 2, 2018
888c061
WriteValidators uses IterateLastValidators rather than IterateBondedV…
sunnya97 Nov 2, 2018
13d933f
fixed democoin interface
sunnya97 Nov 2, 2018
191a732
fixed comment
sunnya97 Nov 3, 2018
559ebb7
Merge PR #2671: Power Store Invariant
rigelrozanski Nov 3, 2018
7b10ac4
Merge branch 'develop' into cwgoes/simulation-transubstantiated
Nov 3, 2018
4068d8a
Fix simulation bugs; Incorprates #2676 from Sunny
jaekwon Nov 4, 2018
ace50be
Address review feedback; Update PENDING
jaekwon Nov 5, 2018
95cf0c3
Merge branch 'develop' into jae/simulation-transubstantiated
jaekwon Nov 5, 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
5 changes: 5 additions & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ IMPROVEMENTS

* SDK
- #2573 [x/distribution] add accum invariance
- #2556 [x/mock/simulation] Fix debugging output
- #2396 [x/mock/simulation] Change parameters to get more slashes
- #2617 [x/mock/simulation] Randomize all genesis parameters
- #2669 [x/stake] Added invarant check to make sure validator's power aligns with its spot in the power store.
- \#1924 [x/mock/simulation] Use a transition matrix for block size
- \#2660 [x/mock/simulation] Staking transactions get tested far more frequently
- #2610 [x/stake] Block redelegation to and from the same validator
Expand All @@ -57,6 +61,7 @@ BUG FIXES
* Gaia CLI (`gaiacli`)

* Gaia
- #2670 [x/stake] fixed incorrent `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators`

* SDK
- #2625 [x/gov] fix AppendTag function usage error
Expand Down
1 change: 1 addition & 0 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res

ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger).
WithMinimumFees(app.minimumFees)

// Passes the rest of the path as an argument to the querier.
// For example, in the path "custom/gov/proposal/test", the gov querier gets []string{"proposal", "test"} as the path
resBytes, err := querier(ctx, path[2:], req)
Expand Down
14 changes: 8 additions & 6 deletions cmd/gaia/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,38 +109,40 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
app.cdc,
app.keyParams, app.tkeyParams,
)
app.stakeKeeper = stake.NewKeeper(
stakeKeeper := stake.NewKeeper(
app.cdc,
app.keyStake, app.tkeyStake,
app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace),
sunnya97 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we change all passed around Keepers to be pointers? Or just save that for a seperate PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets consider it in the future for a separate PR... I'm not sure. I think for new keepers we do want pointers.

app.RegisterCodespace(stake.DefaultCodespace),
)
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint,
app.paramsKeeper.Subspace(mint.DefaultParamspace),
app.stakeKeeper, app.feeCollectionKeeper,
&stakeKeeper, app.feeCollectionKeeper,
)
app.distrKeeper = distr.NewKeeper(
app.cdc,
app.keyDistr,
app.paramsKeeper.Subspace(distr.DefaultParamspace),
app.bankKeeper, app.stakeKeeper, app.feeCollectionKeeper,
app.bankKeeper, &stakeKeeper, app.feeCollectionKeeper,
app.RegisterCodespace(stake.DefaultCodespace),
)
app.slashingKeeper = slashing.NewKeeper(
app.cdc,
app.keySlashing,
app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
&stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
app.RegisterCodespace(slashing.DefaultCodespace),
)
app.govKeeper = gov.NewKeeper(
app.cdc,
app.keyGov,
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, app.stakeKeeper,
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakeKeeper,
app.RegisterCodespace(gov.DefaultCodespace),
)

// register the staking hooks
app.stakeKeeper = app.stakeKeeper.WithHooks(
// NOTE: stakeKeeper above are passed by reference,
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
// so that it can be modified like below:
app.stakeKeeper = *stakeKeeper.WithHooks(
NewHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()))

// register message routes
Expand Down
78 changes: 65 additions & 13 deletions cmd/gaia/app/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"math/rand"
"os"
"testing"
"time"

"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -50,42 +51,93 @@ func init() {
func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
var genesisAccounts []GenesisAccount

amt := int64(10000)
amount := int64(r.Intn(1e6))
numInitiallyBonded := int64(r.Intn(250))
numAccs := int64(len(accs))
if numInitiallyBonded > numAccs {
numInitiallyBonded = numAccs
}
fmt.Printf("Selected randomly generated parameters for simulated genesis: {amount of steak per account: %v, initially bonded validators: %v}\n", amount, numInitiallyBonded)

// Randomly generate some genesis accounts
for _, acc := range accs {
coins := sdk.Coins{sdk.Coin{"steak", sdk.NewInt(amt)}}
coins := sdk.Coins{sdk.Coin{"steak", sdk.NewInt(amount)}}
genesisAccounts = append(genesisAccounts, GenesisAccount{
Address: acc.Address,
Coins: coins,
})
}

// Default genesis state
govGenesis := gov.DefaultGenesisState()
stakeGenesis := stake.DefaultGenesisState()
slashingGenesis := slashing.DefaultGenesisState()
// Random genesis states
govGenesis := gov.GenesisState{
StartingProposalID: int64(r.Intn(100)),
DepositProcedure: gov.DepositProcedure{
MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", int64(r.Intn(1e3)))},
MaxDepositPeriod: time.Duration(r.Intn(2*172800)) * time.Second,
},
VotingProcedure: gov.VotingProcedure{
VotingPeriod: time.Duration(r.Intn(2*172800)) * time.Second,
},
TallyingProcedure: gov.TallyingProcedure{
Threshold: sdk.NewDecWithPrec(5, 1),
Veto: sdk.NewDecWithPrec(334, 3),
GovernancePenalty: sdk.NewDecWithPrec(1, 2),
},
}
fmt.Printf("Selected randomly generated governance parameters: %+v\n", govGenesis)
stakeGenesis := stake.GenesisState{
Pool: stake.InitialPool(),
Params: stake.Params{
UnbondingTime: time.Duration(r.Intn(60*60*24*3*2)) * time.Second,
MaxValidators: uint16(r.Intn(250)),
BondDenom: "steak",
},
}
fmt.Printf("Selected randomly generated staking parameters: %+v\n", stakeGenesis)
slashingGenesis := slashing.GenesisState{
Params: slashing.Params{
MaxEvidenceAge: stakeGenesis.Params.UnbondingTime,
DoubleSignUnbondDuration: time.Duration(r.Intn(60*60*24)) * time.Second,
SignedBlocksWindow: int64(r.Intn(1000)),
DowntimeUnbondDuration: time.Duration(r.Intn(86400)) * time.Second,
MinSignedPerWindow: sdk.NewDecWithPrec(int64(r.Intn(10)), 1),
SlashFractionDoubleSign: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(50) + 1))),
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(200) + 1))),
},
}
fmt.Printf("Selected randomly generated slashing parameters: %+v\n", slashingGenesis)
mintGenesis := mint.GenesisState{
Minter: mint.Minter{
InflationLastTime: time.Unix(0, 0),
Inflation: sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
},
Params: mint.Params{
MintDenom: "steak",
InflationRateChange: sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
InflationMax: sdk.NewDecWithPrec(20, 2),
InflationMin: sdk.NewDecWithPrec(7, 2),
GoalBonded: sdk.NewDecWithPrec(67, 2),
},
}
fmt.Printf("Selected randomly generated minting parameters: %v\n", mintGenesis)
var validators []stake.Validator
var delegations []stake.Delegation

// XXX Try different numbers of initially bonded validators
numInitiallyBonded := int64(50)
valAddrs := make([]sdk.ValAddress, numInitiallyBonded)
for i := 0; i < int(numInitiallyBonded); i++ {
valAddr := sdk.ValAddress(accs[i].Address)
valAddrs[i] = valAddr

validator := stake.NewValidator(valAddr, accs[i].PubKey, stake.Description{})
validator.Tokens = sdk.NewDec(amt)
validator.DelegatorShares = sdk.NewDec(amt)
delegation := stake.Delegation{accs[i].Address, valAddr, sdk.NewDec(amt), 0}
validator.Tokens = sdk.NewDec(amount)
validator.DelegatorShares = sdk.NewDec(amount)
delegation := stake.Delegation{accs[i].Address, valAddr, sdk.NewDec(amount), 0}
validators = append(validators, validator)
delegations = append(delegations, delegation)
}
stakeGenesis.Pool.LooseTokens = sdk.NewDec(amt*250 + (numInitiallyBonded * amt))
stakeGenesis.Pool.LooseTokens = sdk.NewDec((amount * numAccs) + (numInitiallyBonded * amount))
stakeGenesis.Validators = validators
stakeGenesis.Bonds = delegations
mintGenesis := mint.DefaultGenesisState()

genesis := GenesisState{
Accounts: genesisAccounts,
Expand Down
9 changes: 7 additions & 2 deletions examples/democoin/mock/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,13 @@ func (vs *ValidatorSet) IterateValidators(ctx sdk.Context, fn func(index int64,
}
}

// IterateValidatorsBonded implements sdk.ValidatorSet
func (vs *ValidatorSet) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, Validator sdk.Validator) bool) {
// IterateBondedValidatorsByPower implements sdk.ValidatorSet
func (vs *ValidatorSet) IterateBondedValidatorsByPower(ctx sdk.Context, fn func(index int64, Validator sdk.Validator) bool) {
vs.IterateValidators(ctx, fn)
}

// IterateLastValidators implements sdk.ValidatorSet
func (vs *ValidatorSet) IterateLastValidators(ctx sdk.Context, fn func(index int64, Validator sdk.Validator) bool) {
vs.IterateValidators(ctx, fn)
}

Expand Down
3 changes: 2 additions & 1 deletion scripts/multisim.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/bin/bash

seeds=(1 2 4 7 9 20 32 123 124 582 1893 2989 3012 4728 37827 981928 87821 891823782 989182 89182391)
seeds=(1 2 4 7 9 20 32 123 124 582 1893 2989 3012 4728 37827 981928 87821 891823782 989182 89182391 \
11 22 44 77 99 2020 3232 123123 124124 582582 18931893 29892989 30123012 47284728 37827)
blocks=$1

echo "Running multi-seed simulation with seeds ${seeds[@]}"
Expand Down
6 changes: 5 additions & 1 deletion types/stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ type ValidatorSet interface {
func(index int64, validator Validator) (stop bool))

// iterate through bonded validators by operator address, execute func for each validator
IterateValidatorsBonded(Context,
IterateBondedValidatorsByPower(Context,
func(index int64, validator Validator) (stop bool))

// iterate through the consensus validator set of the last block by operator address, execute func for each validator
IterateLastValidators(Context,
func(index int64, validator Validator) (stop bool))

Validator(Context, ValAddress) Validator // get a particular validator by operator address
Expand Down
7 changes: 5 additions & 2 deletions x/distribution/keeper/hooks.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package keeper

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
)
Expand Down Expand Up @@ -38,11 +40,12 @@ func (k Keeper) onValidatorBonded(ctx sdk.Context, valAddr sdk.ValAddress) {
k.onValidatorModified(ctx, valAddr)
}

// XXX Consider removing this after debugging.
// Sanity check, very useful!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to #2663?

Like maybe these sanity check so be run as an optional thing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not super performance heavy, lets run it always for now.

func (k Keeper) onValidatorPowerDidChange(ctx sdk.Context, valAddr sdk.ValAddress) {
vi := k.GetValidatorDistInfo(ctx, valAddr)
if vi.FeePoolWithdrawalHeight != ctx.BlockHeight() {
panic("expected validator dist info FeePoolWithdrawalHeight to be updated, but was not.")
panic(fmt.Sprintf("expected validator (%v) dist info FeePoolWithdrawalHeight to be updated to %v, but was %v.",
valAddr.String(), ctx.BlockHeight(), vi.FeePoolWithdrawalHeight))
}
}

Expand Down
2 changes: 1 addition & 1 deletion x/distribution/keeper/test_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initCoins int64,
keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), ck, sk, fck, types.DefaultCodespace)

// set the distribution hooks on staking
sk = sk.WithHooks(keeper.Hooks())
sk = *sk.WithHooks(keeper.Hooks())

// set genesis items required for distribution
keeper.SetFeePool(ctx, types.InitialFeePool())
Expand Down
2 changes: 1 addition & 1 deletion x/gov/tally.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
totalVotingPower := sdk.ZeroDec()
currValidators := make(map[string]validatorGovInfo)

keeper.vs.IterateValidatorsBonded(ctx, func(index int64, validator sdk.Validator) (stop bool) {
keeper.vs.IterateBondedValidatorsByPower(ctx, func(index int64, validator sdk.Validator) (stop bool) {
currValidators[validator.GetOperator().String()] = validatorGovInfo{
Address: validator.GetOperator(),
Power: validator.GetPower(),
Expand Down
37 changes: 0 additions & 37 deletions x/mock/simulation/constants.go

This file was deleted.

66 changes: 66 additions & 0 deletions x/mock/simulation/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package simulation

import (
"math/rand"
)

const (
// Minimum time per block
minTimePerBlock int64 = 10000 / 2

// Maximum time per block
maxTimePerBlock int64 = 10000

// TODO Remove in favor of binary search for invariant violation
onOperation bool = false
)

var (
// Currently there are 3 different liveness types, fully online, spotty connection, offline.
defaultLivenessTransitionMatrix, _ = CreateTransitionMatrix([][]int{
{90, 20, 1},
{10, 50, 5},
{0, 10, 1000},
})

// 3 states: rand in range [0, 4*provided blocksize], rand in range [0, 2 * provided blocksize], 0
defaultBlockSizeTransitionMatrix, _ = CreateTransitionMatrix([][]int{
{85, 5, 0},
{15, 92, 1},
{0, 3, 99},
})
)

// Simulation parameters
type Params struct {
PastEvidenceFraction float64
NumKeys int
EvidenceFraction float64
InitialLivenessWeightings []int
LivenessTransitionMatrix TransitionMatrix
BlockSizeTransitionMatrix TransitionMatrix
}

// Return default simulation parameters
func DefaultParams() Params {
return Params{
PastEvidenceFraction: 0.5,
NumKeys: 250,
EvidenceFraction: 0.5,
InitialLivenessWeightings: []int{40, 5, 5},
LivenessTransitionMatrix: defaultLivenessTransitionMatrix,
BlockSizeTransitionMatrix: defaultBlockSizeTransitionMatrix,
}
}

// Return random simulation parameters
func RandomParams(r *rand.Rand) Params {
return Params{
PastEvidenceFraction: r.Float64(),
NumKeys: r.Intn(250),
EvidenceFraction: r.Float64(),
InitialLivenessWeightings: []int{r.Intn(80), r.Intn(10), r.Intn(10)},
LivenessTransitionMatrix: defaultLivenessTransitionMatrix,
BlockSizeTransitionMatrix: defaultBlockSizeTransitionMatrix,
}
}
Loading