From ee8bcbdaa5b507a4fc3bd9258fb32ae0f97d4d46 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 7 Nov 2018 14:10:20 +0100 Subject: [PATCH 01/33] PENDING => CHANGELOG --- CHANGELOG.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ PENDING.md | 27 +------------------------- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16e01163c..914593325 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,60 @@ # Changelog +## 0.26.0 + +BREAKING CHANGES + +* Gaia + * [gaiad init] \#2602 New genesis workflow + +* SDK + * [simulation] \#2665 only argument to simulation.Invariant is now app + +* Tendermint + * Upgrade to version 0.26.0 + +FEATURES + +* Gaia CLI (`gaiacli`) + * [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations + * [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations + * [cli] [\#2524](https://github.com/cosmos/cosmos-sdk/issues/2524) Add support offline mode to `gaiacli tx sign`. Lookups are not performed if the flag `--offline` is on. + * [cli] [\#2558](https://github.com/cosmos/cosmos-sdk/issues/2558) Rename --print-sigs to --validate-signatures. It now performs a complete set of sanity checks and reports to the user. Also added --print-signature-only to print the signature only, not the whole transaction. + +* SDK + * \#1336 Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes. + +IMPROVEMENTS + +* Gaia + * \#2637 [x/gov] Switched inactive and active proposal queues to an iterator based queue + +* 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 + * \#2652 [x/auth] Add benchmark for get and set account + * \#2685 [store] Add general merkle absence proof (also for empty substores) + * \#2708 [store] Disallow setting nil values + +BUG FIXES + +* Gaia + * \#2670 [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators` + * \#2691 Fix local testnet creation by using a single canonical genesis time + +* SDK + * \#2625 [x/gov] fix AppendTag function usage error + * \#2677 [x/stake, x/distribution] various staking/distribution fixes as found by the simulator + * \#2674 [types] Fix coin.IsLT() impl, coins.IsLT() impl, and renamed coins.Is\* to coins.IsAll\* (see \#2686) + * \#2711 [x/stake] Add commission data to `MsgCreateValidator` signature bytes. + + ## 0.25.0 *October 24th, 2018* diff --git a/PENDING.md b/PENDING.md index 8b2044ea2..4d87301f0 100644 --- a/PENDING.md +++ b/PENDING.md @@ -7,28 +7,21 @@ BREAKING CHANGES * Gaia CLI (`gaiacli`) * Gaia - * [gaiad init] \#2602 New genesis workflow * SDK - * [simulation] \#2665 only argument to simulation.Invariant is now app * Tendermint - * Upgrade to version 0.26.0 + FEATURES * Gaia REST API (`gaiacli advanced rest-server`) * Gaia CLI (`gaiacli`) - * [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations - * [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations - * [cli] [\#2524](https://github.com/cosmos/cosmos-sdk/issues/2524) Add support offline mode to `gaiacli tx sign`. Lookups are not performed if the flag `--offline` is on. - * [cli] [\#2558](https://github.com/cosmos/cosmos-sdk/issues/2558) Rename --print-sigs to --validate-signatures. It now performs a complete set of sanity checks and reports to the user. Also added --print-signature-only to print the signature only, not the whole transaction. * Gaia * SDK - * (#1336) Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes. * Tendermint @@ -40,20 +33,8 @@ IMPROVEMENTS * Gaia CLI (`gaiacli`) * Gaia - - #2637 [x/gov] Switched inactive and active proposal queues to an iterator based queue * 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 - - \#2652 [x/auth] Add benchmark for get and set account - - \#2685 [store] Add general merkle absence proof (also for empty substores) - - \#2708 [store] Disallow setting nil values * Tendermint @@ -65,13 +46,7 @@ BUG FIXES * Gaia CLI (`gaiacli`) * Gaia - - \#2670 [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators` - - \#2691 Fix local testnet creation by using a single canonical genesis time * SDK - - \#2625 [x/gov] fix AppendTag function usage error - - \#2677 [x/stake, x/distribution] various staking/distribution fixes as found by the simulator - - \#2674 [types] Fix coin.IsLT() impl, coins.IsLT() impl, and renamed coins.Is\* to coins.IsAll\* (see \#2686) - - \#2711 [x/stake] Add commission data to `MsgCreateValidator` signature bytes. * Tendermint From ccb329b353fde34907f09bde21382f3a9d39ce33 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 7 Nov 2018 14:13:48 +0100 Subject: [PATCH 02/33] Linkify changelog --- CHANGELOG.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 914593325..5dc577c8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,10 @@ BREAKING CHANGES * Gaia - * [gaiad init] \#2602 New genesis workflow + * [gaiad init] [\#2602](https://github.com/cosmos/cosmos-sdk/issues/2602) New genesis workflow * SDK - * [simulation] \#2665 only argument to simulation.Invariant is now app + * [simulation] [\#2665](https://github.com/cosmos/cosmos-sdk/issues/2665) only argument to simulation.Invariant is now app * Tendermint * Upgrade to version 0.26.0 @@ -22,37 +22,37 @@ FEATURES * [cli] [\#2558](https://github.com/cosmos/cosmos-sdk/issues/2558) Rename --print-sigs to --validate-signatures. It now performs a complete set of sanity checks and reports to the user. Also added --print-signature-only to print the signature only, not the whole transaction. * SDK - * \#1336 Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes. + * [\#1336](https://github.com/cosmos/cosmos-sdk/issues/1336) Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes. IMPROVEMENTS * Gaia - * \#2637 [x/gov] Switched inactive and active proposal queues to an iterator based queue + * [\#2637](https://github.com/cosmos/cosmos-sdk/issues/2637) [x/gov] Switched inactive and active proposal queues to an iterator based queue * 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 - * \#2652 [x/auth] Add benchmark for get and set account - * \#2685 [store] Add general merkle absence proof (also for empty substores) - * \#2708 [store] Disallow setting nil values + * [\#2573](https://github.com/cosmos/cosmos-sdk/issues/2573) [x/distribution] add accum invariance + * [\#2556](https://github.com/cosmos/cosmos-sdk/issues/2556) [x/mock/simulation] Fix debugging output + * [\#2396](https://github.com/cosmos/cosmos-sdk/issues/2396) [x/mock/simulation] Change parameters to get more slashes + * [\#2617](https://github.com/cosmos/cosmos-sdk/issues/2617) [x/mock/simulation] Randomize all genesis parameters + * [\#2669](https://github.com/cosmos/cosmos-sdk/issues/2669) [x/stake] Added invarant check to make sure validator's power aligns with its spot in the power store. + * [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) [x/mock/simulation] Use a transition matrix for block size + * [\#2660](https://github.com/cosmos/cosmos-sdk/issues/2660) [x/mock/simulation] Staking transactions get tested far more frequently + * [\#2610](https://github.com/cosmos/cosmos-sdk/issues/2610) [x/stake] Block redelegation to and from the same validator + * [\#2652](https://github.com/cosmos/cosmos-sdk/issues/2652) [x/auth] Add benchmark for get and set account + * [\#2685](https://github.com/cosmos/cosmos-sdk/issues/2685) [store] Add general merkle absence proof (also for empty substores) + * [\#2708](https://github.com/cosmos/cosmos-sdk/issues/2708) [store] Disallow setting nil values BUG FIXES * Gaia - * \#2670 [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators` - * \#2691 Fix local testnet creation by using a single canonical genesis time + * [\#2670](https://github.com/cosmos/cosmos-sdk/issues/2670) [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators` + * [\#2691](https://github.com/cosmos/cosmos-sdk/issues/2691) Fix local testnet creation by using a single canonical genesis time * SDK - * \#2625 [x/gov] fix AppendTag function usage error - * \#2677 [x/stake, x/distribution] various staking/distribution fixes as found by the simulator - * \#2674 [types] Fix coin.IsLT() impl, coins.IsLT() impl, and renamed coins.Is\* to coins.IsAll\* (see \#2686) - * \#2711 [x/stake] Add commission data to `MsgCreateValidator` signature bytes. + * [\#2625](https://github.com/cosmos/cosmos-sdk/issues/2625) [x/gov] fix AppendTag function usage error + * [\#2677](https://github.com/cosmos/cosmos-sdk/issues/2677) [x/stake, x/distribution] various staking/distribution fixes as found by the simulator + * [\#2674](https://github.com/cosmos/cosmos-sdk/issues/2674) [types] Fix coin.IsLT() impl, coins.IsLT() impl, and renamed coins.Is\* to coins.IsAll\* (see [\#2686](https://github.com/cosmos/cosmos-sdk/issues/2686)) + * [\#2711](https://github.com/cosmos/cosmos-sdk/issues/2711) [x/stake] Add commission data to `MsgCreateValidator` signature bytes. ## 0.25.0 From 74b2a90087b21027d745989bbf49c57b20217251 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 7 Nov 2018 10:28:18 -0500 Subject: [PATCH 03/33] whitespacing --- x/mock/simulation/doc.go | 33 +++--- x/mock/simulation/params.go | 7 +- x/mock/simulation/random_simulate_blocks.go | 100 +++++++++++------ x/mock/simulation/transition_matrix.go | 20 ++-- x/mock/simulation/types.go | 116 ++++++++++---------- x/mock/simulation/util.go | 10 +- 6 files changed, 164 insertions(+), 122 deletions(-) diff --git a/x/mock/simulation/doc.go b/x/mock/simulation/doc.go index 8b9a3f693..2febd9e47 100644 --- a/x/mock/simulation/doc.go +++ b/x/mock/simulation/doc.go @@ -2,26 +2,25 @@ Package simulation implements a simulation framework for any state machine built on the SDK which utilizes auth. -It is primarily intended for fuzz testing the integration of modules. -It will test that the provided operations are interoperable, -and that the desired invariants hold. -It can additionally be used to detect what the performance benchmarks in the -system are, by using benchmarking mode and cpu / mem profiling. -If it detects a failure, it provides the entire log of what was ran, +It is primarily intended for fuzz testing the integration of modules. It will +test that the provided operations are interoperable, and that the desired +invariants hold. It can additionally be used to detect what the performance +benchmarks in the system are, by using benchmarking mode and cpu / mem +profiling. If it detects a failure, it provides the entire log of what was +ran, -The simulator takes as input: a random seed, the set of operations to run, -the invariants to test, and additional parameters to configure how long to run, -and misc. parameters that affect simulation speed. +The simulator takes as input: a random seed, the set of operations to run, the +invariants to test, and additional parameters to configure how long to run, and +misc. parameters that affect simulation speed. -It is intended that every module provides a list of Operations which will randomly -create and run a message / tx in a manner that is interesting to fuzz, and verify that -the state transition was executed as expected. -Each module should additionally provide methods to assert that the desired invariants hold. +It is intended that every module provides a list of Operations which will +randomly create and run a message / tx in a manner that is interesting to fuzz, +and verify that the state transition was executed as expected. Each module +should additionally provide methods to assert that the desired invariants hold. Then to perform a randomized simulation, select the set of desired operations, -the weightings for each, the invariants you want to test, and how long to run it for. -Then run simulation.Simulate! -The simulator will handle things like ensuring that validators periodically double signing, -or go offline. +the weightings for each, the invariants you want to test, and how long to run +it for. Then run simulation.Simulate! The simulator will handle things like +ensuring that validators periodically double signing, or go offline. */ package simulation diff --git a/x/mock/simulation/params.go b/x/mock/simulation/params.go index 404a85e54..8499e6c11 100644 --- a/x/mock/simulation/params.go +++ b/x/mock/simulation/params.go @@ -15,15 +15,18 @@ const ( onOperation bool = false ) +// TODO explain transitional matrix usage var ( - // Currently there are 3 different liveness types, fully online, spotty connection, offline. + // 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 + // 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}, diff --git a/x/mock/simulation/random_simulate_blocks.go b/x/mock/simulation/random_simulate_blocks.go index a568997e6..17a26f762 100644 --- a/x/mock/simulation/random_simulate_blocks.go +++ b/x/mock/simulation/random_simulate_blocks.go @@ -31,8 +31,11 @@ func Simulate(t *testing.T, app *baseapp.BaseApp, return SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit) } -func initChain(r *rand.Rand, params Params, accounts []Account, setups []RandSetup, app *baseapp.BaseApp, - appStateFn func(r *rand.Rand, accounts []Account) json.RawMessage) (validators map[string]mockValidator) { +func initChain(r *rand.Rand, params Params, + accounts []Account, setups []RandSetup, app *baseapp.BaseApp, + appStateFn func(r *rand.Rand, accounts []Account) json.RawMessage) ( + validators map[string]mockValidator) { + res := app.InitChain(abci.RequestInitChain{AppStateBytes: appStateFn(r, accounts)}) validators = make(map[string]mockValidator) for _, validator := range res.Validators { @@ -101,6 +104,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, var pastVoteInfos [][]abci.VoteInfo request := RandomRequestBeginBlock(r, params, validators, pastTimes, pastVoteInfos, event, header) + // These are operations which have been queued by previous operations operationQueue := make(map[int][]Operation) timeOperationQueue := []FutureOperation{} @@ -110,7 +114,11 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, blockLogBuilders = make([]*strings.Builder, numBlocks) } displayLogs := logPrinter(testingMode, blockLogBuilders) - blockSimulator := createBlockSimulator(testingMode, tb, t, params, event, invariants, ops, operationQueue, timeOperationQueue, numBlocks, blockSize, displayLogs) + blockSimulator := createBlockSimulator( + testingMode, tb, t, params, event, invariants, + ops, operationQueue, timeOperationQueue, + numBlocks, blockSize, displayLogs) + if !testingMode { b.ResetTimer() } else { @@ -147,8 +155,14 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, // Run queued operations. Ignores blocksize if blocksize is too small logWriter("Queued operations") - numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, accs, logWriter, displayLogs, event) - numQueuedTimeOpsRan := runQueuedTimeOperations(timeOperationQueue, header.Time, tb, r, app, ctx, accs, logWriter, displayLogs, event) + numQueuedOpsRan := runQueuedOperations( + operationQueue, int(header.Height), + tb, r, app, ctx, accs, logWriter, + displayLogs, event) + numQueuedTimeOpsRan := runQueuedTimeOperations( + timeOperationQueue, header.Time, + tb, r, app, ctx, accs, + logWriter, displayLogs, event) if testingMode && onOperation { // Make sure invariants hold at end of queued operations assertAllInvariants(t, app, invariants, "QueuedOperations", displayLogs) @@ -164,7 +178,10 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, res := app.EndBlock(abci.RequestEndBlock{}) header.Height++ - header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second) + header.Time = header.Time.Add( + time.Duration(minTimePerBlock) * time.Second) + header.Time = header.Time.Add( + time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second) header.ProposerAddress = randomProposer(r, validators) logWriter("EndBlock") @@ -198,16 +215,14 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, return nil } -type blockSimFn func( - r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accounts []Account, header abci.Header, logWriter func(string), -) (opCount int) +type blockSimFn func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + accounts []Account, header abci.Header, logWriter func(string)) (opCount int) // Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize // memory overhead func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params Params, - event func(string), invariants []Invariant, - ops []WeightedOperation, operationQueue map[int][]Operation, timeOperationQueue []FutureOperation, + event func(string), invariants []Invariant, ops []WeightedOperation, + operationQueue map[int][]Operation, timeOperationQueue []FutureOperation, totalNumBlocks int, avgBlockSize int, displayLogs func()) blockSimFn { var ( @@ -233,23 +248,29 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) { - fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", header.Height, totalNumBlocks, opCount, blocksize) + + fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", + header.Height, totalNumBlocks, opCount, blocksize) lastBlocksizeState, blocksize = getBlockSize(r, params, lastBlocksizeState, avgBlockSize) + for j := 0; j < blocksize; j++ { logUpdate, futureOps, err := selectOp(r)(r, app, ctx, accounts, event) logWriter(logUpdate) if err != nil { displayLogs() - tb.Fatalf("error on operation %d within block %d, %v", header.Height, opCount, err) + tb.Fatalf("error on operation %d within block %d, %v", + header.Height, opCount, err) } queueOperations(operationQueue, timeOperationQueue, futureOps) if testingMode { if onOperation { - assertAllInvariants(t, app, invariants, fmt.Sprintf("operation: %v", logUpdate), displayLogs) + assertAllInvariants(t, app, invariants, + fmt.Sprintf("operation: %v", logUpdate), displayLogs) } if opCount%50 == 0 { - fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", header.Height, totalNumBlocks, opCount, blocksize) + fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", + header.Height, totalNumBlocks, opCount, blocksize) } } opCount++ @@ -272,10 +293,11 @@ func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B // getBlockSize returns a block size as determined from the transition matrix. // It targets making average block size the provided parameter. The three // states it moves between are: -// "over stuffed" blocks with average size of 2 * avgblocksize, -// normal sized blocks, hitting avgBlocksize on average, -// and empty blocks, with no txs / only txs scheduled from the past. -func getBlockSize(r *rand.Rand, params Params, lastBlockSizeState, avgBlockSize int) (state, blocksize int) { +// - "over stuffed" blocks with average size of 2 * avgblocksize, +// - normal sized blocks, hitting avgBlocksize on average, +// - and empty blocks, with no txs / only txs scheduled from the past. +func getBlockSize(r *rand.Rand, params Params, + lastBlockSizeState, avgBlockSize int) (state, blocksize int) { // TODO: Make default blocksize transition matrix actually make the average // blocksize equal to avgBlockSize. state = params.BlockSizeTransitionMatrix.NextState(r, lastBlockSizeState) @@ -290,7 +312,10 @@ func getBlockSize(r *rand.Rand, params Params, lastBlockSizeState, avgBlockSize } // adds all future operations into the operation queue. -func queueOperations(queuedOperations map[int][]Operation, queuedTimeOperations []FutureOperation, futureOperations []FutureOperation) { +func queueOperations(queuedOperations map[int][]Operation, + queuedTimeOperations []FutureOperation, + futureOperations []FutureOperation) { + if futureOperations == nil { return } @@ -312,8 +337,11 @@ func queueOperations(queuedOperations map[int][]Operation, queuedTimeOperations } // nolint: errcheck -func runQueuedOperations(queueOperations map[int][]Operation, height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accounts []Account, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) { +func runQueuedOperations(queueOperations map[int][]Operation, + height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + accounts []Account, logWriter func(string), + displayLogs func(), event func(string)) (numOpsRan int) { + if queuedOps, ok := queueOperations[height]; ok { numOps := len(queuedOps) for i := 0; i < numOps; i++ { @@ -333,8 +361,10 @@ func runQueuedOperations(queueOperations map[int][]Operation, height int, tb tes return 0 } -func runQueuedTimeOperations(queueOperations []FutureOperation, currentTime time.Time, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accounts []Account, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) { +func runQueuedTimeOperations(queueOperations []FutureOperation, + currentTime time.Time, tb testing.TB, r *rand.Rand, + app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, + logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) { numOpsRan = 0 for len(queueOperations) > 0 && currentTime.After(queueOperations[0].BlockTime) { @@ -379,10 +409,13 @@ func randomProposer(r *rand.Rand, validators map[string]mockValidator) cmn.HexBy return pk.Address() } -// RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction -// nolint: unparam -func RandomRequestBeginBlock(r *rand.Rand, params Params, validators map[string]mockValidator, - pastTimes []time.Time, pastVoteInfos [][]abci.VoteInfo, event func(string), header abci.Header) abci.RequestBeginBlock { +// RandomRequestBeginBlock generates a list of signing validators according to +// the provided list of validators, signing fraction, and evidence fraction +func RandomRequestBeginBlock(r *rand.Rand, params Params, + validators map[string]mockValidator, pastTimes []time.Time, + pastVoteInfos [][]abci.VoteInfo, + event func(string), header abci.Header) abci.RequestBeginBlock { + if len(validators) == 0 { return abci.RequestBeginBlock{Header: header} } @@ -459,7 +492,9 @@ func RandomRequestBeginBlock(r *rand.Rand, params Params, validators map[string] // updateValidators mimicks Tendermint's update logic // nolint: unparam -func updateValidators(tb testing.TB, r *rand.Rand, params Params, current map[string]mockValidator, updates []abci.ValidatorUpdate, event func(string)) map[string]mockValidator { +func updateValidators(tb testing.TB, r *rand.Rand, params Params, + current map[string]mockValidator, updates []abci.ValidatorUpdate, + event func(string)) map[string]mockValidator { for _, update := range updates { str := fmt.Sprintf("%v", update.PubKey) @@ -478,7 +513,10 @@ func updateValidators(tb testing.TB, r *rand.Rand, params Params, current map[st event("endblock/validatorupdates/updated") } else { // Set this new validator - current[str] = mockValidator{update, GetMemberOfInitialState(r, params.InitialLivenessWeightings)} + current[str] = mockValidator{ + update, + GetMemberOfInitialState(r, params.InitialLivenessWeightings), + } event("endblock/validatorupdates/added") } } diff --git a/x/mock/simulation/transition_matrix.go b/x/mock/simulation/transition_matrix.go index 39bdb1e4f..97cd307e5 100644 --- a/x/mock/simulation/transition_matrix.go +++ b/x/mock/simulation/transition_matrix.go @@ -5,12 +5,11 @@ import ( "math/rand" ) -// TransitionMatrix is _almost_ a left stochastic matrix. -// It is technically not one due to not normalizing the column values. -// In the future, if we want to find the steady state distribution, -// it will be quite easy to normalize these values to get a stochastic matrix. -// Floats aren't currently used as the default due to non-determinism across -// architectures +// TransitionMatrix is _almost_ a left stochastic matrix. It is technically +// not one due to not normalizing the column values. In the future, if we want +// to find the steady state distribution, it will be quite easy to normalize +// these values to get a stochastic matrix. Floats aren't currently used as +// the default due to non-determinism across architectures type TransitionMatrix struct { weights [][]int // total in each column @@ -24,7 +23,8 @@ func CreateTransitionMatrix(weights [][]int) (TransitionMatrix, error) { n := len(weights) for i := 0; i < n; i++ { if len(weights[i]) != n { - return TransitionMatrix{}, fmt.Errorf("Transition Matrix: Non-square matrix provided, error on row %d", i) + return TransitionMatrix{}, + fmt.Errorf("Transition Matrix: Non-square matrix provided, error on row %d", i) } } totals := make([]int, n) @@ -36,8 +36,8 @@ func CreateTransitionMatrix(weights [][]int) (TransitionMatrix, error) { return TransitionMatrix{weights, totals, n}, nil } -// NextState returns the next state randomly chosen using r, and the weightings provided -// in the transition matrix. +// NextState returns the next state randomly chosen using r, and the weightings +// provided in the transition matrix. func (t TransitionMatrix) NextState(r *rand.Rand, i int) int { randNum := r.Intn(t.totals[i]) for row := 0; row < t.n; row++ { @@ -51,7 +51,7 @@ func (t TransitionMatrix) NextState(r *rand.Rand, i int) int { } // GetMemberOfInitialState takes an initial array of weights, of size n. -// It returns a weighted random number in [0,n). +// It returns a weighted random number in [0,n]. func GetMemberOfInitialState(r *rand.Rand, weights []int) int { n := len(weights) total := 0 diff --git a/x/mock/simulation/types.go b/x/mock/simulation/types.go index e601f2e1f..198e2a4ff 100644 --- a/x/mock/simulation/types.go +++ b/x/mock/simulation/types.go @@ -10,68 +10,71 @@ import ( "github.com/tendermint/tendermint/crypto" ) -type ( - // Operation runs a state machine transition, - // and ensures the transition happened as expected. - // The operation could be running and testing a fuzzed transaction, - // or doing the same for a message. - // - // For ease of debugging, - // an operation returns a descriptive message "action", - // which details what this fuzzed state machine transition actually did. - // - // Operations can optionally provide a list of "FutureOperations" to run later - // These will be ran at the beginning of the corresponding block. - Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accounts []Account, event func(string), - ) (action string, futureOperations []FutureOperation, err error) +// Operation runs a state machine transition, +// and ensures the transition happened as expected. +// The operation could be running and testing a fuzzed transaction, +// or doing the same for a message. +// +// For ease of debugging, +// an operation returns a descriptive message "action", +// which details what this fuzzed state machine transition actually did. +// +// Operations can optionally provide a list of "FutureOperations" to run later +// These will be ran at the beginning of the corresponding block. +type Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + accounts []Account, event func(string)) ( + action string, futureOperations []FutureOperation, err error) - // RandSetup performs the random setup the mock module needs. - RandSetup func(r *rand.Rand, accounts []Account) +// RandSetup performs the random setup the mock module needs. +type RandSetup func(r *rand.Rand, accounts []Account) - // An Invariant is a function which tests a particular invariant. - // If the invariant has been broken, it should return an error - // containing a descriptive message about what happened. - // The simulator will then halt and print the logs. - Invariant func(app *baseapp.BaseApp) error +// An Invariant is a function which tests a particular invariant. +// If the invariant has been broken, it should return an error +// containing a descriptive message about what happened. +// The simulator will then halt and print the logs. +type Invariant func(app *baseapp.BaseApp) error - // Account contains a privkey, pubkey, address tuple - // eventually more useful data can be placed in here. - // (e.g. number of coins) - Account struct { - PrivKey crypto.PrivKey - PubKey crypto.PubKey - Address sdk.AccAddress - } +// Account contains a privkey, pubkey, address tuple +// eventually more useful data can be placed in here. +// (e.g. number of coins) +type Account struct { + PrivKey crypto.PrivKey + PubKey crypto.PubKey + Address sdk.AccAddress +} - mockValidator struct { - val abci.ValidatorUpdate - livenessState int - } +// are two accounts equal +func (acc Account) Equals(acc2 Account) bool { + return acc.Address.Equals(acc2.Address) +} - // FutureOperation is an operation which will be ran at the - // beginning of the provided BlockHeight. - // If both a BlockHeight and BlockTime are specified, it will use the BlockHeight. - // In the (likely) event that multiple operations are queued at the same - // block height, they will execute in a FIFO pattern. - FutureOperation struct { - BlockHeight int - BlockTime time.Time - Op Operation - } +type mockValidator struct { + val abci.ValidatorUpdate + livenessState int +} - // WeightedOperation is an operation with associated weight. - // This is used to bias the selection operation within the simulator. - WeightedOperation struct { - Weight int - Op Operation - } -) +// FutureOperation is an operation which will be ran at the +// beginning of the provided BlockHeight. +// If both a BlockHeight and BlockTime are specified, it will use the BlockHeight. +// In the (likely) event that multiple operations are queued at the same +// block height, they will execute in a FIFO pattern. +type FutureOperation struct { + BlockHeight int + BlockTime time.Time + Op Operation +} + +// WeightedOperation is an operation with associated weight. +// This is used to bias the selection operation within the simulator. +type WeightedOperation struct { + Weight int + Op Operation +} // TODO remove? not being called anywhere -// PeriodicInvariant returns an Invariant function closure that asserts -// a given invariant if the mock application's last block modulo the given -// period is congruent to the given offset. +// PeriodicInvariant returns an Invariant function closure that asserts a given +// invariant if the mock application's last block modulo the given period is +// congruent to the given offset. func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant { return func(app *baseapp.BaseApp) error { if int(app.LastBlockHeight())%period == offset { @@ -80,8 +83,3 @@ func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant { return nil } } - -// nolint -func (acc Account) Equals(acc2 Account) bool { - return acc.Address.Equals(acc2.Address) -} diff --git a/x/mock/simulation/util.go b/x/mock/simulation/util.go index 62b253a25..bb974b65f 100644 --- a/x/mock/simulation/util.go +++ b/x/mock/simulation/util.go @@ -21,8 +21,8 @@ import ( // shamelessly copied from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang#31832326 // TODO we should probably move this to tendermint/libs/common/random.go -const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" letterIdxBits = 6 // 6 bits to represent a letter index letterIdxMask = 1< 10 { - fileName := fmt.Sprintf("simulation_log_%s.txt", time.Now().Format("2006-01-02 15:04:05")) + + fileName := fmt.Sprintf("simulation_log_%s.txt", + time.Now().Format("2006-01-02 15:04:05")) + fmt.Printf("Too many logs to display, instead writing to %s\n", fileName) f, _ = os.Create(fileName) } From 6a7c4d1c868a8fdb47ddf42b2f607e9a5c3ce1bb Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 7 Nov 2018 10:37:45 -0500 Subject: [PATCH 04/33] rand utile ... --- x/mock/simulation/rand_util.go | 93 +++++++++++++++++++++ x/mock/simulation/random_simulate_blocks.go | 8 +- x/mock/simulation/types.go | 13 --- x/mock/simulation/util.go | 81 ------------------ 4 files changed, 94 insertions(+), 101 deletions(-) create mode 100644 x/mock/simulation/rand_util.go diff --git a/x/mock/simulation/rand_util.go b/x/mock/simulation/rand_util.go new file mode 100644 index 000000000..076995d36 --- /dev/null +++ b/x/mock/simulation/rand_util.go @@ -0,0 +1,93 @@ +package simulation + +import ( + "math/big" + "math/rand" + "time" + + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/mock" +) + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + letterIdxBits = 6 // 6 bits to represent a letter index + letterIdxMask = 1<= 0; { + if remain == 0 { + cache, remain = r.Int63(), letterIdxMax + } + if idx := int(cache & letterIdxMask); idx < len(letterBytes) { + b[i] = letterBytes[idx] + i-- + } + cache >>= letterIdxBits + remain-- + } + return string(b) +} + +// RandomAcc pick a random account from an array +func RandomAcc(r *rand.Rand, accs []Account) Account { + return accs[r.Intn( + len(accs), + )] +} + +// Generate a random amount +func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int { + return sdk.NewInt(int64(r.Intn(int(max.Int64())))) +} + +// RandomDecAmount generates a random decimal amount +func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec { + randInt := big.NewInt(0).Rand(r, max.Int) + return sdk.NewDecFromBigIntWithPrec(randInt, sdk.Precision) +} + +// RandomAccounts generates n random accounts +func RandomAccounts(r *rand.Rand, n int) []Account { + accs := make([]Account, n) + for i := 0; i < n; i++ { + // don't need that much entropy for simulation + privkeySeed := make([]byte, 15) + r.Read(privkeySeed) + useSecp := r.Int63()%2 == 0 + if useSecp { + accs[i].PrivKey = secp256k1.GenPrivKeySecp256k1(privkeySeed) + } else { + accs[i].PrivKey = ed25519.GenPrivKeyFromSecret(privkeySeed) + } + accs[i].PubKey = accs[i].PrivKey.PubKey() + accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address()) + } + return accs +} + +// RandomSetGenesis wraps mock.RandomSetGenesis, but using simulation accounts +func RandomSetGenesis(r *rand.Rand, app *mock.App, accs []Account, denoms []string) { + addrs := make([]sdk.AccAddress, len(accs)) + for i := 0; i < len(accs); i++ { + addrs[i] = accs[i].Address + } + mock.RandomSetGenesis(r, app, addrs, denoms) +} + +// RandTimestamp generates a random timestamp +func RandTimestamp(r *rand.Rand) time.Time { + // json.Marshal breaks for timestamps greater with year greater than 9999 + unixTime := r.Int63n(253373529600) + return time.Unix(unixTime, 0) +} diff --git a/x/mock/simulation/random_simulate_blocks.go b/x/mock/simulation/random_simulate_blocks.go index 17a26f762..9cfe27011 100644 --- a/x/mock/simulation/random_simulate_blocks.go +++ b/x/mock/simulation/random_simulate_blocks.go @@ -50,12 +50,6 @@ func initChain(r *rand.Rand, params Params, return } -func randTimestamp(r *rand.Rand) time.Time { - // json.Marshal breaks for timestamps greater with year greater than 9999 - unixTime := r.Int63n(253373529600) - return time.Unix(unixTime, 0) -} - // SimulateFromSeed tests an application by running the provided // operations, testing the provided invariants, but using the provided seed. func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, @@ -70,7 +64,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, r := rand.New(rand.NewSource(seed)) params := RandomParams(r) // := DefaultParams() fmt.Printf("Randomized simulation params: %+v\n", params) - timestamp := randTimestamp(r) + timestamp := RandTimestamp(r) fmt.Printf("Starting the simulation from time %v, unixtime %v\n", timestamp.UTC().Format(time.UnixDate), timestamp.Unix()) timeDiff := maxTimePerBlock - minTimePerBlock diff --git a/x/mock/simulation/types.go b/x/mock/simulation/types.go index 198e2a4ff..65118547f 100644 --- a/x/mock/simulation/types.go +++ b/x/mock/simulation/types.go @@ -70,16 +70,3 @@ type WeightedOperation struct { Weight int Op Operation } - -// TODO remove? not being called anywhere -// PeriodicInvariant returns an Invariant function closure that asserts a given -// invariant if the mock application's last block modulo the given period is -// congruent to the given offset. -func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant { - return func(app *baseapp.BaseApp) error { - if int(app.LastBlockHeight())%period == offset { - return invariant(app) - } - return nil - } -} diff --git a/x/mock/simulation/util.go b/x/mock/simulation/util.go index bb974b65f..10ed6b3b0 100644 --- a/x/mock/simulation/util.go +++ b/x/mock/simulation/util.go @@ -2,50 +2,15 @@ package simulation import ( "fmt" - "math/big" - "math/rand" "os" "sort" "strings" "testing" "time" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/mock" ) -// shamelessly copied from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang#31832326 -// TODO we should probably move this to tendermint/libs/common/random.go - -const ( - letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - letterIdxBits = 6 // 6 bits to represent a letter index - letterIdxMask = 1<= 0; { - if remain == 0 { - cache, remain = r.Int63(), letterIdxMax - } - if idx := int(cache & letterIdxMask); idx < len(letterBytes) { - b[i] = letterBytes[idx] - i-- - } - cache >>= letterIdxBits - remain-- - } - return string(b) -} - // Pretty-print events as a table func DisplayEvents(events map[string]uint) { var keys []string @@ -59,43 +24,6 @@ func DisplayEvents(events map[string]uint) { } } -// RandomAcc pick a random account from an array -func RandomAcc(r *rand.Rand, accs []Account) Account { - return accs[r.Intn( - len(accs), - )] -} - -// Generate a random amount -func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int { - return sdk.NewInt(int64(r.Intn(int(max.Int64())))) -} - -// RandomDecAmount generates a random decimal amount -func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec { - randInt := big.NewInt(0).Rand(r, max.Int) - return sdk.NewDecFromBigIntWithPrec(randInt, sdk.Precision) -} - -// RandomAccounts generates n random accounts -func RandomAccounts(r *rand.Rand, n int) []Account { - accs := make([]Account, n) - for i := 0; i < n; i++ { - // don't need that much entropy for simulation - privkeySeed := make([]byte, 15) - r.Read(privkeySeed) - useSecp := r.Int63()%2 == 0 - if useSecp { - accs[i].PrivKey = secp256k1.GenPrivKeySecp256k1(privkeySeed) - } else { - accs[i].PrivKey = ed25519.GenPrivKeyFromSecret(privkeySeed) - } - accs[i].PubKey = accs[i].PrivKey.PubKey() - accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address()) - } - return accs -} - // Builds a function to add logs for this particular block func addLogMessage(testingmode bool, blockLogBuilders []*strings.Builder, height int) func(string) { if testingmode { @@ -124,15 +52,6 @@ func assertAllInvariants(t *testing.T, app *baseapp.BaseApp, } } -// RandomSetGenesis wraps mock.RandomSetGenesis, but using simulation accounts -func RandomSetGenesis(r *rand.Rand, app *mock.App, accs []Account, denoms []string) { - addrs := make([]sdk.AccAddress, len(accs)) - for i := 0; i < len(accs); i++ { - addrs[i] = accs[i].Address - } - mock.RandomSetGenesis(r, app, addrs, denoms) -} - // Creates a function to print out the logs func logPrinter(testingmode bool, logs []*strings.Builder) func() { if testingmode { From 78c3430bb34b1b2ea48072083676d2ffaad0829b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 7 Nov 2018 11:00:24 -0500 Subject: [PATCH 05/33] moving stuff around a bit, trying to get rid of types --- x/mock/simulation/account.go | 51 ++++++++++++ x/mock/simulation/invariants.go | 30 +++++++ x/mock/simulation/rand_util.go | 29 ------- ...{random_simulate_blocks.go => simulate.go} | 82 ++++--------------- x/mock/simulation/types.go | 27 ------ x/mock/simulation/validator.go | 78 ++++++++++++++++++ 6 files changed, 175 insertions(+), 122 deletions(-) create mode 100644 x/mock/simulation/account.go create mode 100644 x/mock/simulation/invariants.go rename x/mock/simulation/{random_simulate_blocks.go => simulate.go} (88%) create mode 100644 x/mock/simulation/validator.go diff --git a/x/mock/simulation/account.go b/x/mock/simulation/account.go new file mode 100644 index 000000000..37dfbb2cd --- /dev/null +++ b/x/mock/simulation/account.go @@ -0,0 +1,51 @@ +package simulation + +import ( + "math/rand" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Account contains a privkey, pubkey, address tuple +// eventually more useful data can be placed in here. +// (e.g. number of coins) +type Account struct { + PrivKey crypto.PrivKey + PubKey crypto.PubKey + Address sdk.AccAddress +} + +// are two accounts equal +func (acc Account) Equals(acc2 Account) bool { + return acc.Address.Equals(acc2.Address) +} + +// RandomAcc pick a random account from an array +func RandomAcc(r *rand.Rand, accs []Account) Account { + return accs[r.Intn( + len(accs), + )] +} + +// RandomAccounts generates n random accounts +func RandomAccounts(r *rand.Rand, n int) []Account { + accs := make([]Account, n) + for i := 0; i < n; i++ { + // don't need that much entropy for simulation + privkeySeed := make([]byte, 15) + r.Read(privkeySeed) + useSecp := r.Int63()%2 == 0 + if useSecp { + accs[i].PrivKey = secp256k1.GenPrivKeySecp256k1(privkeySeed) + } else { + accs[i].PrivKey = ed25519.GenPrivKeyFromSecret(privkeySeed) + } + accs[i].PubKey = accs[i].PrivKey.PubKey() + accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address()) + } + return accs +} diff --git a/x/mock/simulation/invariants.go b/x/mock/simulation/invariants.go new file mode 100644 index 000000000..b8f9aad21 --- /dev/null +++ b/x/mock/simulation/invariants.go @@ -0,0 +1,30 @@ +package simulation + +import ( + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/baseapp" +) + +// An Invariant is a function which tests a particular invariant. +// If the invariant has been broken, it should return an error +// containing a descriptive message about what happened. +// The simulator will then halt and print the logs. +type Invariant func(app *baseapp.BaseApp) error + +// assertAllInvariants asserts a list of provided invariants against +// application state +func assertAllInvariants(t *testing.T, app *baseapp.BaseApp, + invariants []Invariant, where string, displayLogs func()) { + + for i := 0; i < len(invariants); i++ { + err := invariants[i](app) + if err != nil { + fmt.Printf("Invariants broken after %s\n", where) + fmt.Println(err.Error()) + displayLogs() + t.Fatal() + } + } +} diff --git a/x/mock/simulation/rand_util.go b/x/mock/simulation/rand_util.go index 076995d36..c40d2a65c 100644 --- a/x/mock/simulation/rand_util.go +++ b/x/mock/simulation/rand_util.go @@ -5,9 +5,6 @@ import ( "math/rand" "time" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/crypto/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/mock" ) @@ -39,13 +36,6 @@ func RandStringOfLength(r *rand.Rand, n int) string { return string(b) } -// RandomAcc pick a random account from an array -func RandomAcc(r *rand.Rand, accs []Account) Account { - return accs[r.Intn( - len(accs), - )] -} - // Generate a random amount func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int { return sdk.NewInt(int64(r.Intn(int(max.Int64())))) @@ -57,25 +47,6 @@ func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec { return sdk.NewDecFromBigIntWithPrec(randInt, sdk.Precision) } -// RandomAccounts generates n random accounts -func RandomAccounts(r *rand.Rand, n int) []Account { - accs := make([]Account, n) - for i := 0; i < n; i++ { - // don't need that much entropy for simulation - privkeySeed := make([]byte, 15) - r.Read(privkeySeed) - useSecp := r.Int63()%2 == 0 - if useSecp { - accs[i].PrivKey = secp256k1.GenPrivKeySecp256k1(privkeySeed) - } else { - accs[i].PrivKey = ed25519.GenPrivKeyFromSecret(privkeySeed) - } - accs[i].PubKey = accs[i].PrivKey.PubKey() - accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address()) - } - return accs -} - // RandomSetGenesis wraps mock.RandomSetGenesis, but using simulation accounts func RandomSetGenesis(r *rand.Rand, app *mock.App, accs []Account, denoms []string) { addrs := make([]sdk.AccAddress, len(accs)) diff --git a/x/mock/simulation/random_simulate_blocks.go b/x/mock/simulation/simulate.go similarity index 88% rename from x/mock/simulation/random_simulate_blocks.go rename to x/mock/simulation/simulate.go index 9cfe27011..7342a91c1 100644 --- a/x/mock/simulation/random_simulate_blocks.go +++ b/x/mock/simulation/simulate.go @@ -14,7 +14,6 @@ import ( "time" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/baseapp" @@ -188,7 +187,8 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, } if header.ProposerAddress == nil { - fmt.Printf("\nSimulation stopped early as all validators have been unbonded, there is nobody left propose a block!\n") + fmt.Printf("\nSimulation stopped early as all validators " + + "have been unbonded, there is nobody left propose a block!\n") stopEarly = true break } @@ -204,11 +204,16 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, DisplayEvents(events) return } - fmt.Printf("\nSimulation complete. Final height (blocks): %d, final time (seconds), : %v, operations ran %d\n", header.Height, header.Time, opCount) + fmt.Printf("\nSimulation complete. Final height (blocks): %d, "+ + "final time (seconds), : %v, operations ran %d\n", + header.Height, header.Time, opCount) + DisplayEvents(events) return nil } +//______________________________________________________________________________ + type blockSimFn func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) @@ -302,7 +307,7 @@ func getBlockSize(r *rand.Rand, params Params, } else { blocksize = 0 } - return + return state, blocksize } // adds all future operations into the operation queue. @@ -313,6 +318,7 @@ func queueOperations(queuedOperations map[int][]Operation, if futureOperations == nil { return } + for _, futureOp := range futureOperations { if futureOp.BlockHeight != 0 { if val, ok := queuedOperations[futureOp.BlockHeight]; ok { @@ -322,7 +328,12 @@ func queueOperations(queuedOperations map[int][]Operation, } } else { // TODO: Replace with proper sorted data structure, so don't have the copy entire slice - index := sort.Search(len(queuedTimeOperations), func(i int) bool { return queuedTimeOperations[i].BlockTime.After(futureOp.BlockTime) }) + index := sort.Search( + len(queuedTimeOperations), + func(i int) bool { + return queuedTimeOperations[i].BlockTime.After(futureOp.BlockTime) + }, + ) queuedTimeOperations = append(queuedTimeOperations, FutureOperation{}) copy(queuedTimeOperations[index+1:], queuedTimeOperations[index:]) queuedTimeOperations[index] = futureOp @@ -377,32 +388,6 @@ func runQueuedTimeOperations(queueOperations []FutureOperation, return numOpsRan } -func getKeys(validators map[string]mockValidator) []string { - keys := make([]string, len(validators)) - i := 0 - for key := range validators { - keys[i] = key - i++ - } - sort.Strings(keys) - return keys -} - -// randomProposer picks a random proposer from the current validator set -func randomProposer(r *rand.Rand, validators map[string]mockValidator) cmn.HexBytes { - keys := getKeys(validators) - if len(keys) == 0 { - return nil - } - key := keys[r.Intn(len(keys))] - proposer := validators[key].val - pk, err := tmtypes.PB2TM.PubKey(proposer.PubKey) - if err != nil { - panic(err) - } - return pk.Address() -} - // RandomRequestBeginBlock generates a list of signing validators according to // the provided list of validators, signing fraction, and evidence fraction func RandomRequestBeginBlock(r *rand.Rand, params Params, @@ -483,38 +468,3 @@ func RandomRequestBeginBlock(r *rand.Rand, params Params, ByzantineValidators: evidence, } } - -// updateValidators mimicks Tendermint's update logic -// nolint: unparam -func updateValidators(tb testing.TB, r *rand.Rand, params Params, - current map[string]mockValidator, updates []abci.ValidatorUpdate, - event func(string)) map[string]mockValidator { - - for _, update := range updates { - str := fmt.Sprintf("%v", update.PubKey) - switch { - case update.Power == 0: - if _, ok := current[str]; !ok { - tb.Fatalf("tried to delete a nonexistent validator") - } - - event("endblock/validatorupdates/kicked") - delete(current, str) - default: - // Does validator already exist? - if mVal, ok := current[str]; ok { - mVal.val = update - event("endblock/validatorupdates/updated") - } else { - // Set this new validator - current[str] = mockValidator{ - update, - GetMemberOfInitialState(r, params.InitialLivenessWeightings), - } - event("endblock/validatorupdates/added") - } - } - } - - return current -} diff --git a/x/mock/simulation/types.go b/x/mock/simulation/types.go index 65118547f..1014042a7 100644 --- a/x/mock/simulation/types.go +++ b/x/mock/simulation/types.go @@ -6,8 +6,6 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto" ) // Operation runs a state machine transition, @@ -28,31 +26,6 @@ type Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, // RandSetup performs the random setup the mock module needs. type RandSetup func(r *rand.Rand, accounts []Account) -// An Invariant is a function which tests a particular invariant. -// If the invariant has been broken, it should return an error -// containing a descriptive message about what happened. -// The simulator will then halt and print the logs. -type Invariant func(app *baseapp.BaseApp) error - -// Account contains a privkey, pubkey, address tuple -// eventually more useful data can be placed in here. -// (e.g. number of coins) -type Account struct { - PrivKey crypto.PrivKey - PubKey crypto.PubKey - Address sdk.AccAddress -} - -// are two accounts equal -func (acc Account) Equals(acc2 Account) bool { - return acc.Address.Equals(acc2.Address) -} - -type mockValidator struct { - val abci.ValidatorUpdate - livenessState int -} - // FutureOperation is an operation which will be ran at the // beginning of the provided BlockHeight. // If both a BlockHeight and BlockTime are specified, it will use the BlockHeight. diff --git a/x/mock/simulation/validator.go b/x/mock/simulation/validator.go new file mode 100644 index 000000000..e758f4da4 --- /dev/null +++ b/x/mock/simulation/validator.go @@ -0,0 +1,78 @@ +package simulation + +import ( + "fmt" + "math/rand" + "sort" + "testing" + + abci "github.com/tendermint/tendermint/abci/types" + cmn "github.com/tendermint/tendermint/libs/common" + tmtypes "github.com/tendermint/tendermint/types" +) + +type mockValidator struct { + val abci.ValidatorUpdate + livenessState int +} + +func getKeys(validators map[string]mockValidator) []string { + keys := make([]string, len(validators)) + i := 0 + for key := range validators { + keys[i] = key + i++ + } + sort.Strings(keys) + return keys +} + +// randomProposer picks a random proposer from the current validator set +func randomProposer(r *rand.Rand, validators map[string]mockValidator) cmn.HexBytes { + keys := getKeys(validators) + if len(keys) == 0 { + return nil + } + key := keys[r.Intn(len(keys))] + proposer := validators[key].val + pk, err := tmtypes.PB2TM.PubKey(proposer.PubKey) + if err != nil { + panic(err) + } + return pk.Address() +} + +// updateValidators mimicks Tendermint's update logic +// nolint: unparam +func updateValidators(tb testing.TB, r *rand.Rand, params Params, + current map[string]mockValidator, updates []abci.ValidatorUpdate, + event func(string)) map[string]mockValidator { + + for _, update := range updates { + str := fmt.Sprintf("%v", update.PubKey) + switch { + case update.Power == 0: + if _, ok := current[str]; !ok { + tb.Fatalf("tried to delete a nonexistent validator") + } + + event("endblock/validatorupdates/kicked") + delete(current, str) + default: + // Does validator already exist? + if mVal, ok := current[str]; ok { + mVal.val = update + event("endblock/validatorupdates/updated") + } else { + // Set this new validator + current[str] = mockValidator{ + update, + GetMemberOfInitialState(r, params.InitialLivenessWeightings), + } + event("endblock/validatorupdates/added") + } + } + } + + return current +} From ea7a5ea1a85e4c477d76184b8c3419fa567fcba1 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 7 Nov 2018 11:57:53 -0500 Subject: [PATCH 06/33] reorganize more --- x/mock/simulation/params.go | 21 +++++++++++++++++++++ x/mock/simulation/simulate.go | 11 ----------- x/mock/simulation/types.go | 25 +++++++++++-------------- x/mock/simulation/util.go | 29 +++++++++++------------------ 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/x/mock/simulation/params.go b/x/mock/simulation/params.go index 8499e6c11..9c4398c88 100644 --- a/x/mock/simulation/params.go +++ b/x/mock/simulation/params.go @@ -44,6 +44,27 @@ type Params struct { BlockSizeTransitionMatrix TransitionMatrix } +// getBlockSize returns a block size as determined from the transition matrix. +// It targets making average block size the provided parameter. The three +// states it moves between are: +// - "over stuffed" blocks with average size of 2 * avgblocksize, +// - normal sized blocks, hitting avgBlocksize on average, +// - and empty blocks, with no txs / only txs scheduled from the past. +func getBlockSize(r *rand.Rand, params Params, + lastBlockSizeState, avgBlockSize int) (state, blocksize int) { + // TODO: Make default blocksize transition matrix actually make the average + // blocksize equal to avgBlockSize. + state = params.BlockSizeTransitionMatrix.NextState(r, lastBlockSizeState) + if state == 0 { + blocksize = r.Intn(avgBlockSize * 4) + } else if state == 1 { + blocksize = r.Intn(avgBlockSize * 2) + } else { + blocksize = 0 + } + return state, blocksize +} + // Return default simulation parameters func DefaultParams() Params { return Params{ diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index 7342a91c1..68e4f8b7b 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -278,17 +278,6 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params } } -func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B) { - testingMode = false - if _t, ok := tb.(*testing.T); ok { - t = _t - testingMode = true - } else { - b = tb.(*testing.B) - } - return -} - // getBlockSize returns a block size as determined from the transition matrix. // It targets making average block size the provided parameter. The three // states it moves between are: diff --git a/x/mock/simulation/types.go b/x/mock/simulation/types.go index 1014042a7..2789ca699 100644 --- a/x/mock/simulation/types.go +++ b/x/mock/simulation/types.go @@ -8,13 +8,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Operation runs a state machine transition, -// and ensures the transition happened as expected. -// The operation could be running and testing a fuzzed transaction, -// or doing the same for a message. +// RandSetup performs the random setup the mock module needs. +type RandSetup func(r *rand.Rand, accounts []Account) + +// Operation runs a state machine transition, and ensures the transition +// happened as expected. The operation could be running and testing a fuzzed +// transaction, or doing the same for a message. // -// For ease of debugging, -// an operation returns a descriptive message "action", +// For ease of debugging, an operation returns a descriptive message "action", // which details what this fuzzed state machine transition actually did. // // Operations can optionally provide a list of "FutureOperations" to run later @@ -23,14 +24,10 @@ type Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, event func(string)) ( action string, futureOperations []FutureOperation, err error) -// RandSetup performs the random setup the mock module needs. -type RandSetup func(r *rand.Rand, accounts []Account) - -// FutureOperation is an operation which will be ran at the -// beginning of the provided BlockHeight. -// If both a BlockHeight and BlockTime are specified, it will use the BlockHeight. -// In the (likely) event that multiple operations are queued at the same -// block height, they will execute in a FIFO pattern. +// FutureOperation is an operation which will be ran at the beginning of the +// provided BlockHeight. If both a BlockHeight and BlockTime are specified, it +// will use the BlockHeight. In the (likely) event that multiple operations +// are queued at the same block height, they will execute in a FIFO pattern. type FutureOperation struct { BlockHeight int BlockTime time.Time diff --git a/x/mock/simulation/util.go b/x/mock/simulation/util.go index 10ed6b3b0..e115cde24 100644 --- a/x/mock/simulation/util.go +++ b/x/mock/simulation/util.go @@ -7,10 +7,19 @@ import ( "strings" "testing" "time" - - "github.com/cosmos/cosmos-sdk/baseapp" ) +func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B) { + testingMode = false + if _t, ok := tb.(*testing.T); ok { + t = _t + testingMode = true + } else { + b = tb.(*testing.B) + } + return +} + // Pretty-print events as a table func DisplayEvents(events map[string]uint) { var keys []string @@ -36,22 +45,6 @@ func addLogMessage(testingmode bool, blockLogBuilders []*strings.Builder, height return func(x string) {} } -// assertAllInvariants asserts a list of provided invariants against -// application state -func assertAllInvariants(t *testing.T, app *baseapp.BaseApp, - invariants []Invariant, where string, displayLogs func()) { - - for i := 0; i < len(invariants); i++ { - err := invariants[i](app) - if err != nil { - fmt.Printf("Invariants broken after %s\n", where) - fmt.Println(err.Error()) - displayLogs() - t.Fatal() - } - } -} - // Creates a function to print out the logs func logPrinter(testingmode bool, logs []*strings.Builder) func() { if testingmode { From 980dd78c624d751a429ba41de6d9bc012dddb717 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 7 Nov 2018 12:00:13 -0500 Subject: [PATCH 07/33] rename ambig naming of queueOperations --- x/mock/simulation/simulate.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index 68e4f8b7b..85eadcaa6 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -331,47 +331,47 @@ func queueOperations(queuedOperations map[int][]Operation, } // nolint: errcheck -func runQueuedOperations(queueOperations map[int][]Operation, +func runQueuedOperations(queueOps map[int][]Operation, height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) { - if queuedOps, ok := queueOperations[height]; ok { - numOps := len(queuedOps) + if queuedOp, ok := queueOps[height]; ok { + numOps := len(queuedOp) for i := 0; i < numOps; i++ { // For now, queued operations cannot queue more operations. // If a need arises for us to support queued messages to queue more messages, this can // be changed. - logUpdate, _, err := queuedOps[i](r, app, ctx, accounts, event) + logUpdate, _, err := queuedOp[i](r, app, ctx, accounts, event) logWriter(logUpdate) if err != nil { displayLogs() tb.FailNow() } } - delete(queueOperations, height) + delete(queueOps, height) return numOps } return 0 } -func runQueuedTimeOperations(queueOperations []FutureOperation, +func runQueuedTimeOperations(queueOps []FutureOperation, currentTime time.Time, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) { numOpsRan = 0 - for len(queueOperations) > 0 && currentTime.After(queueOperations[0].BlockTime) { + for len(queueOps) > 0 && currentTime.After(queueOps[0].BlockTime) { // For now, queued operations cannot queue more operations. // If a need arises for us to support queued messages to queue more messages, this can // be changed. - logUpdate, _, err := queueOperations[0].Op(r, app, ctx, accounts, event) + logUpdate, _, err := queueOps[0].Op(r, app, ctx, accounts, event) logWriter(logUpdate) if err != nil { displayLogs() tb.FailNow() } - queueOperations = queueOperations[1:] + queueOps = queueOps[1:] numOpsRan++ } return numOpsRan From b5a205eb15a047f384e677724195dab69e72af10 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 7 Nov 2018 12:19:58 -0500 Subject: [PATCH 08/33] minimizing indentation --- x/mock/simulation/simulate.go | 151 ++++++++++++++++++++------------- x/mock/simulation/validator.go | 28 +++--- 2 files changed, 103 insertions(+), 76 deletions(-) diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index 85eadcaa6..2a199ad3c 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -64,7 +64,8 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, params := RandomParams(r) // := DefaultParams() fmt.Printf("Randomized simulation params: %+v\n", params) timestamp := RandTimestamp(r) - fmt.Printf("Starting the simulation from time %v, unixtime %v\n", timestamp.UTC().Format(time.UnixDate), timestamp.Unix()) + fmt.Printf("Starting the simulation from time %v, unixtime %v\n", + timestamp.UTC().Format(time.UnixDate), timestamp.Unix()) timeDiff := maxTimePerBlock - minTimePerBlock accs := RandomAccounts(r, params.NumKeys) @@ -76,11 +77,16 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, } validators := initChain(r, params, accs, setups, app, appStateFn) + // Second variable to keep pending validator set (delayed one block since TM 0.24) // Initially this is the same as the initial validator set nextValidators := validators - header := abci.Header{Height: 1, Time: timestamp, ProposerAddress: randomProposer(r, validators)} + header := abci.Header{ + Height: 1, + Time: timestamp, + ProposerAddress: randomProposer(r, validators), + } opCount := 0 // Setup code to catch SIGTERM's @@ -88,7 +94,8 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT) go func() { receivedSignal := <-c - fmt.Printf("\nExiting early due to %s, on block %d, operation %d\n", receivedSignal, header.Height, opCount) + fmt.Printf("\nExiting early due to %s, on block %d, operation %d\n", + receivedSignal, header.Height, opCount) simError = fmt.Errorf("Exited due to %s", receivedSignal) stopEarly = true }() @@ -96,7 +103,8 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, var pastTimes []time.Time var pastVoteInfos [][]abci.VoteInfo - request := RandomRequestBeginBlock(r, params, validators, pastTimes, pastVoteInfos, event, header) + request := RandomRequestBeginBlock(r, params, + validators, pastTimes, pastVoteInfos, event, header) // These are operations which have been queued by previous operations operationQueue := make(map[int][]Operation) @@ -122,11 +130,14 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, stackTrace := string(debug.Stack()) fmt.Println(stackTrace) displayLogs() - simError = fmt.Errorf("Simulation halted due to panic on block %d", header.Height) + simError = fmt.Errorf( + "Simulation halted due to panic on block %d", + header.Height) } }() } + // TODO split up the contents of this for loop into new functions for i := 0; i < numBlocks && !stopEarly; i++ { // Log the header time for future lookup pastTimes = append(pastTimes, header.Time) @@ -194,11 +205,13 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, } // Generate a random RequestBeginBlock with the current validator set for the next block - request = RandomRequestBeginBlock(r, params, validators, pastTimes, pastVoteInfos, event, header) + request = RandomRequestBeginBlock(r, params, validators, + pastTimes, pastVoteInfos, event, header) // Update the validator set, which will be reflected in the application on the next block validators = nextValidators - nextValidators = updateValidators(tb, r, params, validators, res.ValidatorUpdates, event) + nextValidators = updateValidators(tb, r, params, + validators, res.ValidatorUpdates, event) } if stopEarly { DisplayEvents(events) @@ -224,11 +237,9 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params operationQueue map[int][]Operation, timeOperationQueue []FutureOperation, totalNumBlocks int, avgBlockSize int, displayLogs func()) blockSimFn { - var ( - lastBlocksizeState = 0 // state for [4 * uniform distribution] - totalOpWeight = 0 - blocksize int - ) + var lastBlocksizeState = 0 // state for [4 * uniform distribution] + var totalOpWeight = 0 + var blocksize int for i := 0; i < len(ops); i++ { totalOpWeight += ops[i].Weight @@ -286,14 +297,16 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params // - and empty blocks, with no txs / only txs scheduled from the past. func getBlockSize(r *rand.Rand, params Params, lastBlockSizeState, avgBlockSize int) (state, blocksize int) { + // TODO: Make default blocksize transition matrix actually make the average // blocksize equal to avgBlockSize. state = params.BlockSizeTransitionMatrix.NextState(r, lastBlockSizeState) - if state == 0 { + switch state { + case 0: blocksize = r.Intn(avgBlockSize * 4) - } else if state == 1 { + case 1: blocksize = r.Intn(avgBlockSize * 2) - } else { + default: blocksize = 0 } return state, blocksize @@ -336,23 +349,25 @@ func runQueuedOperations(queueOps map[int][]Operation, accounts []Account, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) { - if queuedOp, ok := queueOps[height]; ok { - numOps := len(queuedOp) - for i := 0; i < numOps; i++ { - // For now, queued operations cannot queue more operations. - // If a need arises for us to support queued messages to queue more messages, this can - // be changed. - logUpdate, _, err := queuedOp[i](r, app, ctx, accounts, event) - logWriter(logUpdate) - if err != nil { - displayLogs() - tb.FailNow() - } - } - delete(queueOps, height) - return numOps + queuedOp, ok := queueOps[height] + if !ok { + return 0 } - return 0 + + numOps := len(queuedOp) + for i := 0; i < numOps; i++ { + // For now, queued operations cannot queue more operations. + // If a need arises for us to support queued messages to queue more messages, this can + // be changed. + logUpdate, _, err := queuedOp[i](r, app, ctx, accounts, event) + logWriter(logUpdate) + if err != nil { + displayLogs() + tb.FailNow() + } + } + delete(queueOps, height) + return numOps } func runQueuedTimeOperations(queueOps []FutureOperation, @@ -385,11 +400,13 @@ func RandomRequestBeginBlock(r *rand.Rand, params Params, event func(string), header abci.Header) abci.RequestBeginBlock { if len(validators) == 0 { - return abci.RequestBeginBlock{Header: header} + return abci.RequestBeginBlock{ + Header: header, + } } voteInfos := make([]abci.VoteInfo, len(validators)) - i := 0 - for _, key := range getKeys(validators) { + + for i, key := range getKeys(validators) { mVal := validators[key] mVal.livenessState = params.LivenessTransitionMatrix.NextState(r, mVal.livenessState) signed := true @@ -403,11 +420,13 @@ func RandomRequestBeginBlock(r *rand.Rand, params Params, // offline signed = false } + if signed { event("beginblock/signing/signed") } else { event("beginblock/signing/missed") } + pubkey, err := tmtypes.PB2TM.PubKey(mVal.val.PubKey) if err != nil { panic(err) @@ -419,36 +438,46 @@ func RandomRequestBeginBlock(r *rand.Rand, params Params, }, SignedLastBlock: signed, } - i++ } - // TODO: Determine capacity before allocation - evidence := make([]abci.Evidence, 0) - // Anything but the first block - if len(pastTimes) > 0 { - for r.Float64() < params.EvidenceFraction { - height := header.Height - time := header.Time - vals := voteInfos - if r.Float64() < params.PastEvidenceFraction { - height = int64(r.Intn(int(header.Height) - 1)) - time = pastTimes[height] - vals = pastVoteInfos[height] - } - validator := vals[r.Intn(len(vals))].Validator - var totalVotingPower int64 - for _, val := range vals { - totalVotingPower += val.Validator.Power - } - evidence = append(evidence, abci.Evidence{ - Type: tmtypes.ABCIEvidenceTypeDuplicateVote, - Validator: validator, - Height: height, - Time: time, - TotalVotingPower: totalVotingPower, - }) - event("beginblock/evidence") + + // return if no past times + if len(pastTimes) <= 0 { + return abci.RequestBeginBlock{ + Header: header, + LastCommitInfo: abci.LastCommitInfo{ + Votes: voteInfos, + }, } } + + // TODO: Determine capacity before allocation + evidence := make([]abci.Evidence, 0) + for r.Float64() < params.EvidenceFraction { + height := header.Height + time := header.Time + vals := voteInfos + if r.Float64() < params.PastEvidenceFraction { + height = int64(r.Intn(int(header.Height) - 1)) + time = pastTimes[height] + vals = pastVoteInfos[height] + } + validator := vals[r.Intn(len(vals))].Validator + var totalVotingPower int64 + + for _, val := range vals { + totalVotingPower += val.Validator.Power + } + + evidence = append(evidence, abci.Evidence{ + Type: tmtypes.ABCIEvidenceTypeDuplicateVote, + Validator: validator, + Height: height, + Time: time, + TotalVotingPower: totalVotingPower, + }) + event("beginblock/evidence") + } + return abci.RequestBeginBlock{ Header: header, LastCommitInfo: abci.LastCommitInfo{ diff --git a/x/mock/simulation/validator.go b/x/mock/simulation/validator.go index e758f4da4..3bbe1050c 100644 --- a/x/mock/simulation/validator.go +++ b/x/mock/simulation/validator.go @@ -16,6 +16,7 @@ type mockValidator struct { livenessState int } +// TODO describe usage func getKeys(validators map[string]mockValidator) []string { keys := make([]string, len(validators)) i := 0 @@ -50,27 +51,24 @@ func updateValidators(tb testing.TB, r *rand.Rand, params Params, for _, update := range updates { str := fmt.Sprintf("%v", update.PubKey) - switch { - case update.Power == 0: + if update.Power == 0 { if _, ok := current[str]; !ok { tb.Fatalf("tried to delete a nonexistent validator") } - event("endblock/validatorupdates/kicked") delete(current, str) - default: - // Does validator already exist? - if mVal, ok := current[str]; ok { - mVal.val = update - event("endblock/validatorupdates/updated") - } else { - // Set this new validator - current[str] = mockValidator{ - update, - GetMemberOfInitialState(r, params.InitialLivenessWeightings), - } - event("endblock/validatorupdates/added") + + } else if mVal, ok := current[str]; ok { + // validator already exists + mVal.val = update + event("endblock/validatorupdates/updated") + } else { + // Set this new validator + current[str] = mockValidator{ + update, + GetMemberOfInitialState(r, params.InitialLivenessWeightings), } + event("endblock/validatorupdates/added") } } From 49707543385d253817b12c1b2a6086d853187177 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 7 Nov 2018 14:42:00 -0500 Subject: [PATCH 09/33] fix some duplicate to get passing --- x/mock/simulation/params.go | 8 +++++--- x/mock/simulation/simulate.go | 23 ----------------------- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/x/mock/simulation/params.go b/x/mock/simulation/params.go index 9c4398c88..c46ab236b 100644 --- a/x/mock/simulation/params.go +++ b/x/mock/simulation/params.go @@ -52,14 +52,16 @@ type Params struct { // - and empty blocks, with no txs / only txs scheduled from the past. func getBlockSize(r *rand.Rand, params Params, lastBlockSizeState, avgBlockSize int) (state, blocksize int) { + // TODO: Make default blocksize transition matrix actually make the average // blocksize equal to avgBlockSize. state = params.BlockSizeTransitionMatrix.NextState(r, lastBlockSizeState) - if state == 0 { + switch state { + case 0: blocksize = r.Intn(avgBlockSize * 4) - } else if state == 1 { + case 1: blocksize = r.Intn(avgBlockSize * 2) - } else { + default: blocksize = 0 } return state, blocksize diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index 2a199ad3c..f963e9491 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -289,29 +289,6 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params } } -// getBlockSize returns a block size as determined from the transition matrix. -// It targets making average block size the provided parameter. The three -// states it moves between are: -// - "over stuffed" blocks with average size of 2 * avgblocksize, -// - normal sized blocks, hitting avgBlocksize on average, -// - and empty blocks, with no txs / only txs scheduled from the past. -func getBlockSize(r *rand.Rand, params Params, - lastBlockSizeState, avgBlockSize int) (state, blocksize int) { - - // TODO: Make default blocksize transition matrix actually make the average - // blocksize equal to avgBlockSize. - state = params.BlockSizeTransitionMatrix.NextState(r, lastBlockSizeState) - switch state { - case 0: - blocksize = r.Intn(avgBlockSize * 4) - case 1: - blocksize = r.Intn(avgBlockSize * 2) - default: - blocksize = 0 - } - return state, blocksize -} - // adds all future operations into the operation queue. func queueOperations(queuedOperations map[int][]Operation, queuedTimeOperations []FutureOperation, From 1ee6c3295d7c75d403231a3655f32f1f72d90f4c Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 7 Nov 2018 23:26:02 -0500 Subject: [PATCH 10/33] operations functions --- x/mock/simulation/{types.go => operation.go} | 34 +++++++++++++-- x/mock/simulation/simulate.go | 45 +++++++------------- x/mock/simulation/validator.go | 20 +++++++++ 3 files changed, 67 insertions(+), 32 deletions(-) rename x/mock/simulation/{types.go => operation.go} (66%) diff --git a/x/mock/simulation/types.go b/x/mock/simulation/operation.go similarity index 66% rename from x/mock/simulation/types.go rename to x/mock/simulation/operation.go index 2789ca699..21b606b37 100644 --- a/x/mock/simulation/types.go +++ b/x/mock/simulation/operation.go @@ -8,9 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// RandSetup performs the random setup the mock module needs. -type RandSetup func(r *rand.Rand, accounts []Account) - // Operation runs a state machine transition, and ensures the transition // happened as expected. The operation could be running and testing a fuzzed // transaction, or doing the same for a message. @@ -24,6 +21,9 @@ type Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, event func(string)) ( action string, futureOperations []FutureOperation, err error) +// queue of operations +type OperationQueue map[int][]Operation + // FutureOperation is an operation which will be ran at the beginning of the // provided BlockHeight. If both a BlockHeight and BlockTime are specified, it // will use the BlockHeight. In the (likely) event that multiple operations @@ -40,3 +40,31 @@ type WeightedOperation struct { Weight int Op Operation } + +// WeightedOperations is the group of all weighted operations to simulate. +type WeightedOperations []WeightedOperation + +func (w WeightedOperations) totalWeight() int { + totalOpWeight := 0 + for i := 0; i < len(w); i++ { + totalOpWeight += w[i].Weight + } + return totalOpWeight +} + +type selectOpFn func(r *rand.Rand) Operation + +func (w WeightedOperations) getSelectOpFn() selectOpFn { + totalOpWeight := ops.totalWeight() + return func(r *rand.Rand) Operation { + x := r.Intn(totalOpWeight) + for i := 0; i < len(ops); i++ { + if x <= ops[i].Weight { + return ops[i].Op + } + x -= ops[i].Weight + } + // shouldn't happen + return ops[0].Op + } +} diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index f963e9491..849f4eeae 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -20,6 +20,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// RandSetup performs the random setup the mock module needs. +type RandSetup func(r *rand.Rand, accounts []Account) + // Simulate tests application by sending random messages. func Simulate(t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, accs []Account) json.RawMessage, @@ -27,26 +30,25 @@ func Simulate(t *testing.T, app *baseapp.BaseApp, invariants []Invariant, numBlocks int, blockSize int, commit bool) error { time := time.Now().UnixNano() - return SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit) + return SimulateFromSeed(t, app, appStateFn, time, ops, + setups, invariants, numBlocks, blockSize, commit) } +// initialize the chain for the simulation func initChain(r *rand.Rand, params Params, accounts []Account, setups []RandSetup, app *baseapp.BaseApp, - appStateFn func(r *rand.Rand, accounts []Account) json.RawMessage) ( - validators map[string]mockValidator) { + appStateFn func(r *rand.Rand, accounts []Account) json.RawMessage) mockValidators { - res := app.InitChain(abci.RequestInitChain{AppStateBytes: appStateFn(r, accounts)}) - validators = make(map[string]mockValidator) - for _, validator := range res.Validators { - str := fmt.Sprintf("%v", validator.PubKey) - validators[str] = mockValidator{validator, GetMemberOfInitialState(r, params.InitialLivenessWeightings)} + req := abci.RequestInitChain{ + AppStateBytes: appStateFn(r, accounts), } + res := app.InitChain(req) + validators = newMockValidators(res.Validators) for i := 0; i < len(setups); i++ { setups[i](r, accounts) } - - return + return validators } // SimulateFromSeed tests an application by running the provided @@ -230,31 +232,16 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, type blockSimFn func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) -// Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize -// memory overhead +// Returns a function to simulate blocks. Written like this to avoid constant +// parameters being passed everytime, to minimize memory overhead func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params Params, - event func(string), invariants []Invariant, ops []WeightedOperation, + event func(string), invariants []Invariant, ops WeightedOperations, operationQueue map[int][]Operation, timeOperationQueue []FutureOperation, totalNumBlocks int, avgBlockSize int, displayLogs func()) blockSimFn { var lastBlocksizeState = 0 // state for [4 * uniform distribution] - var totalOpWeight = 0 var blocksize int - - for i := 0; i < len(ops); i++ { - totalOpWeight += ops[i].Weight - } - selectOp := func(r *rand.Rand) Operation { - x := r.Intn(totalOpWeight) - for i := 0; i < len(ops); i++ { - if x <= ops[i].Weight { - return ops[i].Op - } - x -= ops[i].Weight - } - // shouldn't happen - return ops[0].Op - } + selectOp := ops.getSelectOpFn() return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) { diff --git a/x/mock/simulation/validator.go b/x/mock/simulation/validator.go index 3bbe1050c..7a2213bdb 100644 --- a/x/mock/simulation/validator.go +++ b/x/mock/simulation/validator.go @@ -16,6 +16,26 @@ type mockValidator struct { livenessState int } +type mockValidators map[string]mockValidator + +// get mockValidators from abci validators +func newMockValidators(abciVals abci.ValidatorUpdate) mockValidators { + + validators = make(mockValidators) + for _, validator := range abciVals { + str := fmt.Sprintf("%v", validator.PubKey) + liveliness := GetMemberOfInitialState(r, + params.InitialLivenessWeightings) + + validators[str] = mockValidator{ + val: validator, + livenessState: liveliness, + } + } + + return validators +} + // TODO describe usage func getKeys(validators map[string]mockValidator) []string { keys := make([]string, len(validators)) From ff327049ee3f32871d56e2d015c75d59887372f4 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 7 Nov 2018 23:55:48 -0500 Subject: [PATCH 11/33] assertAllInvarients changes, Operation reorg --- x/mock/simulation/invariants.go | 18 +++++----- x/mock/simulation/operation.go | 38 +++++++++++++++++++++ x/mock/simulation/simulate.go | 58 ++++++++------------------------- 3 files changed, 60 insertions(+), 54 deletions(-) diff --git a/x/mock/simulation/invariants.go b/x/mock/simulation/invariants.go index b8f9aad21..23686005d 100644 --- a/x/mock/simulation/invariants.go +++ b/x/mock/simulation/invariants.go @@ -13,16 +13,16 @@ import ( // The simulator will then halt and print the logs. type Invariant func(app *baseapp.BaseApp) error -// assertAllInvariants asserts a list of provided invariants against -// application state -func assertAllInvariants(t *testing.T, app *baseapp.BaseApp, - invariants []Invariant, where string, displayLogs func()) { +// group of Invarient +type Invariants []Invariant - for i := 0; i < len(invariants); i++ { - err := invariants[i](app) - if err != nil { - fmt.Printf("Invariants broken after %s\n", where) - fmt.Println(err.Error()) +// assertAll asserts the all invariants against application state +func (invs Invariants) assertAll(t *testing.T, app *baseapp.BaseApp, + event string, displayLogs func()) { + + for i := 0; i < len(invs); i++ { + if err := invs[i](app); err != nil { + fmt.Printf("Invariants broken after %s\n%s\n", event, err.Error()) displayLogs() t.Fatal() } diff --git a/x/mock/simulation/operation.go b/x/mock/simulation/operation.go index 21b606b37..27757df2d 100644 --- a/x/mock/simulation/operation.go +++ b/x/mock/simulation/operation.go @@ -2,6 +2,7 @@ package simulation import ( "math/rand" + "sort" "time" "github.com/cosmos/cosmos-sdk/baseapp" @@ -24,6 +25,41 @@ type Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, // queue of operations type OperationQueue map[int][]Operation +// adds all future operations into the operation queue. +func queueOperations(queuedOps OperationQueue, + queuedTimeOps []FutureOperation, + futureOps []FutureOperation) { + + if futureOps == nil { + return + } + + for _, futureOp := range futureOps { + if futureOp.BlockHeight != 0 { + if val, ok := queuedOps[futureOp.BlockHeight]; ok { + queuedOps[futureOp.BlockHeight] = append(val, futureOp.Op) + } else { + queuedOps[futureOp.BlockHeight] = []Operation{futureOp.Op} + } + continue + } + + // TODO: Replace with proper sorted data structure, so don't have the + // copy entire slice + index := sort.Search( + len(queuedTimeOps), + func(i int) bool { + return queuedTimeOps[i].BlockTime.After(futureOp.BlockTime) + }, + ) + queuedTimeOps = append(queuedTimeOps, FutureOperation{}) + copy(queuedTimeOps[index+1:], queuedTimeOps[index:]) + queuedTimeOps[index] = futureOp + } +} + +//________________________________________________________________________ + // FutureOperation is an operation which will be ran at the beginning of the // provided BlockHeight. If both a BlockHeight and BlockTime are specified, it // will use the BlockHeight. In the (likely) event that multiple operations @@ -34,6 +70,8 @@ type FutureOperation struct { Op Operation } +//________________________________________________________________________ + // WeightedOperation is an operation with associated weight. // This is used to bias the selection operation within the simulator. type WeightedOperation struct { diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index 849f4eeae..d9b5176f8 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -7,7 +7,6 @@ import ( "os" "os/signal" "runtime/debug" - "sort" "strings" "syscall" "testing" @@ -27,7 +26,7 @@ type RandSetup func(r *rand.Rand, accounts []Account) func Simulate(t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, accs []Account) json.RawMessage, ops []WeightedOperation, setups []RandSetup, - invariants []Invariant, numBlocks int, blockSize int, commit bool) error { + invariants Invariants, numBlocks int, blockSize int, commit bool) error { time := time.Now().UnixNano() return SimulateFromSeed(t, app, appStateFn, time, ops, @@ -55,7 +54,7 @@ func initChain(r *rand.Rand, params Params, // operations, testing the provided invariants, but using the provided seed. func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, accs []Account) json.RawMessage, - seed int64, ops []WeightedOperation, setups []RandSetup, invariants []Invariant, + seed int64, ops WeightedOperations, setups []RandSetup, invariants Invariants, numBlocks int, blockSize int, commit bool) (simError error) { // in case we have to end early, don't os.Exit so that we can run cleanup code. @@ -154,7 +153,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, if testingMode { // Make sure invariants hold at beginning of block - assertAllInvariants(t, app, invariants, "BeginBlock", displayLogs) + invariants.assertAll(t, app, "BeginBlock", displayLogs) } ctx := app.NewContext(false, header) @@ -171,15 +170,15 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, logWriter, displayLogs, event) if testingMode && onOperation { // Make sure invariants hold at end of queued operations - assertAllInvariants(t, app, invariants, "QueuedOperations", displayLogs) + invariants.assertAll(t, app, "QueuedOperations", displayLogs) } logWriter("Standard operations") operations := blockSimulator(r, app, ctx, accs, header, logWriter) opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan if testingMode { - // Make sure invariants hold at end of block - assertAllInvariants(t, app, invariants, "StandardOperations", displayLogs) + // Make sure invariants hold at the operation + invariants.assertAll(t, app, "StandardOperations", displayLogs) } res := app.EndBlock(abci.RequestEndBlock{}) @@ -193,7 +192,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, if testingMode { // Make sure invariants hold at end of block - assertAllInvariants(t, app, invariants, "EndBlock", displayLogs) + invariants.assertAll(t, app, "EndBlock", displayLogs) } if commit { app.Commit() @@ -235,7 +234,7 @@ type blockSimFn func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, // Returns a function to simulate blocks. Written like this to avoid constant // parameters being passed everytime, to minimize memory overhead func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params Params, - event func(string), invariants []Invariant, ops WeightedOperations, + event func(string), invariants Invariants, ops WeightedOperations, operationQueue map[int][]Operation, timeOperationQueue []FutureOperation, totalNumBlocks int, avgBlockSize int, displayLogs func()) blockSimFn { @@ -262,8 +261,8 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params queueOperations(operationQueue, timeOperationQueue, futureOps) if testingMode { if onOperation { - assertAllInvariants(t, app, invariants, - fmt.Sprintf("operation: %v", logUpdate), displayLogs) + eventStr := fmt.Sprintf("operation: %v", logUpdate) + invariants.assertAll(t, app, eventStr, displayLogs) } if opCount%50 == 0 { fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", @@ -276,37 +275,6 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params } } -// adds all future operations into the operation queue. -func queueOperations(queuedOperations map[int][]Operation, - queuedTimeOperations []FutureOperation, - futureOperations []FutureOperation) { - - if futureOperations == nil { - return - } - - for _, futureOp := range futureOperations { - if futureOp.BlockHeight != 0 { - if val, ok := queuedOperations[futureOp.BlockHeight]; ok { - queuedOperations[futureOp.BlockHeight] = append(val, futureOp.Op) - } else { - queuedOperations[futureOp.BlockHeight] = []Operation{futureOp.Op} - } - } else { - // TODO: Replace with proper sorted data structure, so don't have the copy entire slice - index := sort.Search( - len(queuedTimeOperations), - func(i int) bool { - return queuedTimeOperations[i].BlockTime.After(futureOp.BlockTime) - }, - ) - queuedTimeOperations = append(queuedTimeOperations, FutureOperation{}) - copy(queuedTimeOperations[index+1:], queuedTimeOperations[index:]) - queuedTimeOperations[index] = futureOp - } - } -} - // nolint: errcheck func runQueuedOperations(queueOps map[int][]Operation, height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, @@ -318,8 +286,8 @@ func runQueuedOperations(queueOps map[int][]Operation, return 0 } - numOps := len(queuedOp) - for i := 0; i < numOps; i++ { + numOpsRan = len(queuedOp) + for i := 0; i < numOpsRan; i++ { // For now, queued operations cannot queue more operations. // If a need arises for us to support queued messages to queue more messages, this can // be changed. @@ -331,7 +299,7 @@ func runQueuedOperations(queueOps map[int][]Operation, } } delete(queueOps, height) - return numOps + return numOpsRan } func runQueuedTimeOperations(queueOps []FutureOperation, From fee0763b5ef4bc609bcec2a1eecbde3c57a0a4ff Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 8 Nov 2018 00:12:51 -0500 Subject: [PATCH 12/33] mock tendermint --- x/mock/simulation/mock_tendermint.go | 198 +++++++++++++++++++++++++++ x/mock/simulation/simulate.go | 108 ++------------- x/mock/simulation/validator.go | 96 ------------- 3 files changed, 206 insertions(+), 196 deletions(-) create mode 100644 x/mock/simulation/mock_tendermint.go delete mode 100644 x/mock/simulation/validator.go diff --git a/x/mock/simulation/mock_tendermint.go b/x/mock/simulation/mock_tendermint.go new file mode 100644 index 000000000..ee381cbb6 --- /dev/null +++ b/x/mock/simulation/mock_tendermint.go @@ -0,0 +1,198 @@ +package simulation + +import ( + "fmt" + "math/rand" + "sort" + "testing" + "time" + + abci "github.com/tendermint/tendermint/abci/types" + cmn "github.com/tendermint/tendermint/libs/common" + tmtypes "github.com/tendermint/tendermint/types" +) + +type mockValidator struct { + val abci.ValidatorUpdate + livenessState int +} + +type mockValidators map[string]mockValidator + +// get mockValidators from abci validators +func newMockValidators(abciVals abci.ValidatorUpdate) mockValidators { + + validators = make(mockValidators) + for _, validator := range abciVals { + str := fmt.Sprintf("%v", validator.PubKey) + liveliness := GetMemberOfInitialState(r, + params.InitialLivenessWeightings) + + validators[str] = mockValidator{ + val: validator, + livenessState: liveliness, + } + } + + return validators +} + +// TODO describe usage +func (vals mockValidators) getKeys() []string { + keys := make([]string, len(validators)) + i := 0 + for key := range validators { + keys[i] = key + i++ + } + sort.Strings(keys) + return keys +} + +//_________________________________________________________________________________ + +// randomProposer picks a random proposer from the current validator set +func randomProposer(r *rand.Rand, validators map[string]mockValidator) cmn.HexBytes { + keys := validators.getKeys() + if len(keys) == 0 { + return nil + } + key := keys[r.Intn(len(keys))] + proposer := validators[key].val + pk, err := tmtypes.PB2TM.PubKey(proposer.PubKey) + if err != nil { + panic(err) + } + return pk.Address() +} + +// updateValidators mimicks Tendermint's update logic +// nolint: unparam +func updateValidators(tb testing.TB, r *rand.Rand, params Params, + current map[string]mockValidator, updates []abci.ValidatorUpdate, + event func(string)) map[string]mockValidator { + + for _, update := range updates { + str := fmt.Sprintf("%v", update.PubKey) + if update.Power == 0 { + if _, ok := current[str]; !ok { + tb.Fatalf("tried to delete a nonexistent validator") + } + event("endblock/validatorupdates/kicked") + delete(current, str) + + } else if mVal, ok := current[str]; ok { + // validator already exists + mVal.val = update + event("endblock/validatorupdates/updated") + } else { + // Set this new validator + current[str] = mockValidator{ + update, + GetMemberOfInitialState(r, params.InitialLivenessWeightings), + } + event("endblock/validatorupdates/added") + } + } + + return current +} + +// RandomRequestBeginBlock generates a list of signing validators according to +// the provided list of validators, signing fraction, and evidence fraction +func RandomRequestBeginBlock(r *rand.Rand, params Params, + validators mockValidators, pastTimes []time.Time, + pastVoteInfos [][]abci.VoteInfo, + event func(string), header abci.Header) abci.RequestBeginBlock { + + if len(validators) == 0 { + return abci.RequestBeginBlock{ + Header: header, + } + } + + voteInfos := make([]abci.VoteInfo, len(validators)) + for i, key := range validators.getKeys() { + mVal := validators[key] + mVal.livenessState = params.LivenessTransitionMatrix.NextState(r, mVal.livenessState) + signed := true + + if mVal.livenessState == 1 { + // spotty connection, 50% probability of success + // See https://github.com/golang/go/issues/23804#issuecomment-365370418 + // for reasoning behind computing like this + signed = r.Int63()%2 == 0 + } else if mVal.livenessState == 2 { + // offline + signed = false + } + + if signed { + event("beginblock/signing/signed") + } else { + event("beginblock/signing/missed") + } + + pubkey, err := tmtypes.PB2TM.PubKey(mVal.val.PubKey) + if err != nil { + panic(err) + } + voteInfos[i] = abci.VoteInfo{ + Validator: abci.Validator{ + Address: pubkey.Address(), + Power: mVal.val.Power, + }, + SignedLastBlock: signed, + } + } + + // return if no past times + if len(pastTimes) <= 0 { + return abci.RequestBeginBlock{ + Header: header, + LastCommitInfo: abci.LastCommitInfo{ + Votes: voteInfos, + }, + } + } + + // TODO: Determine capacity before allocation + evidence := make([]abci.Evidence, 0) + for r.Float64() < params.EvidenceFraction { + + height := header.Height + time := header.Time + vals := voteInfos + + if r.Float64() < params.PastEvidenceFraction { + height = int64(r.Intn(int(header.Height) - 1)) + time = pastTimes[height] + vals = pastVoteInfos[height] + } + validator := vals[r.Intn(len(vals))].Validator + + var totalVotingPower int64 + for _, val := range vals { + totalVotingPower += val.Validator.Power + } + + evidence = append(evidence, + abci.Evidence{ + Type: tmtypes.ABCIEvidenceTypeDuplicateVote, + Validator: validator, + Height: height, + Time: time, + TotalVotingPower: totalVotingPower, + }, + ) + event("beginblock/evidence") + } + + return abci.RequestBeginBlock{ + Header: header, + LastCommitInfo: abci.LastCommitInfo{ + Votes: voteInfos, + }, + ByzantineValidators: evidence, + } +} diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index d9b5176f8..dc7c12bfe 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -13,7 +13,6 @@ import ( "time" abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" @@ -25,7 +24,7 @@ type RandSetup func(r *rand.Rand, accounts []Account) // Simulate tests application by sending random messages. func Simulate(t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, accs []Account) json.RawMessage, - ops []WeightedOperation, setups []RandSetup, + ops WeightedOperations, setups []RandSetup, invariants Invariants, numBlocks int, blockSize int, commit bool) error { time := time.Now().UnixNano() @@ -60,13 +59,17 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, // in case we have to end early, don't os.Exit so that we can run cleanup code. stopEarly := false testingMode, t, b := getTestingMode(tb) - fmt.Printf("Starting SimulateFromSeed with randomness created with seed %d\n", int(seed)) + fmt.Printf("Starting SimulateFromSeed with randomness "+ + "created with seed %d\n", int(seed)) + r := rand.New(rand.NewSource(seed)) params := RandomParams(r) // := DefaultParams() fmt.Printf("Randomized simulation params: %+v\n", params) + timestamp := RandTimestamp(r) fmt.Printf("Starting the simulation from time %v, unixtime %v\n", timestamp.UTC().Format(time.UnixDate), timestamp.Unix()) + timeDiff := maxTimePerBlock - minTimePerBlock accs := RandomAccounts(r, params.NumKeys) @@ -232,10 +235,10 @@ type blockSimFn func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) // Returns a function to simulate blocks. Written like this to avoid constant -// parameters being passed everytime, to minimize memory overhead +// parameters being passed everytime, to minimize memory overhead. func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params Params, event func(string), invariants Invariants, ops WeightedOperations, - operationQueue map[int][]Operation, timeOperationQueue []FutureOperation, + operationQueue OperationQueue, timeOperationQueue []FutureOperation, totalNumBlocks int, avgBlockSize int, displayLogs func()) blockSimFn { var lastBlocksizeState = 0 // state for [4 * uniform distribution] @@ -323,98 +326,3 @@ func runQueuedTimeOperations(queueOps []FutureOperation, } return numOpsRan } - -// RandomRequestBeginBlock generates a list of signing validators according to -// the provided list of validators, signing fraction, and evidence fraction -func RandomRequestBeginBlock(r *rand.Rand, params Params, - validators map[string]mockValidator, pastTimes []time.Time, - pastVoteInfos [][]abci.VoteInfo, - event func(string), header abci.Header) abci.RequestBeginBlock { - - if len(validators) == 0 { - return abci.RequestBeginBlock{ - Header: header, - } - } - voteInfos := make([]abci.VoteInfo, len(validators)) - - for i, key := range getKeys(validators) { - mVal := validators[key] - mVal.livenessState = params.LivenessTransitionMatrix.NextState(r, mVal.livenessState) - signed := true - - if mVal.livenessState == 1 { - // spotty connection, 50% probability of success - // See https://github.com/golang/go/issues/23804#issuecomment-365370418 - // for reasoning behind computing like this - signed = r.Int63()%2 == 0 - } else if mVal.livenessState == 2 { - // offline - signed = false - } - - if signed { - event("beginblock/signing/signed") - } else { - event("beginblock/signing/missed") - } - - pubkey, err := tmtypes.PB2TM.PubKey(mVal.val.PubKey) - if err != nil { - panic(err) - } - voteInfos[i] = abci.VoteInfo{ - Validator: abci.Validator{ - Address: pubkey.Address(), - Power: mVal.val.Power, - }, - SignedLastBlock: signed, - } - } - - // return if no past times - if len(pastTimes) <= 0 { - return abci.RequestBeginBlock{ - Header: header, - LastCommitInfo: abci.LastCommitInfo{ - Votes: voteInfos, - }, - } - } - - // TODO: Determine capacity before allocation - evidence := make([]abci.Evidence, 0) - for r.Float64() < params.EvidenceFraction { - height := header.Height - time := header.Time - vals := voteInfos - if r.Float64() < params.PastEvidenceFraction { - height = int64(r.Intn(int(header.Height) - 1)) - time = pastTimes[height] - vals = pastVoteInfos[height] - } - validator := vals[r.Intn(len(vals))].Validator - var totalVotingPower int64 - - for _, val := range vals { - totalVotingPower += val.Validator.Power - } - - evidence = append(evidence, abci.Evidence{ - Type: tmtypes.ABCIEvidenceTypeDuplicateVote, - Validator: validator, - Height: height, - Time: time, - TotalVotingPower: totalVotingPower, - }) - event("beginblock/evidence") - } - - return abci.RequestBeginBlock{ - Header: header, - LastCommitInfo: abci.LastCommitInfo{ - Votes: voteInfos, - }, - ByzantineValidators: evidence, - } -} diff --git a/x/mock/simulation/validator.go b/x/mock/simulation/validator.go deleted file mode 100644 index 7a2213bdb..000000000 --- a/x/mock/simulation/validator.go +++ /dev/null @@ -1,96 +0,0 @@ -package simulation - -import ( - "fmt" - "math/rand" - "sort" - "testing" - - abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" - tmtypes "github.com/tendermint/tendermint/types" -) - -type mockValidator struct { - val abci.ValidatorUpdate - livenessState int -} - -type mockValidators map[string]mockValidator - -// get mockValidators from abci validators -func newMockValidators(abciVals abci.ValidatorUpdate) mockValidators { - - validators = make(mockValidators) - for _, validator := range abciVals { - str := fmt.Sprintf("%v", validator.PubKey) - liveliness := GetMemberOfInitialState(r, - params.InitialLivenessWeightings) - - validators[str] = mockValidator{ - val: validator, - livenessState: liveliness, - } - } - - return validators -} - -// TODO describe usage -func getKeys(validators map[string]mockValidator) []string { - keys := make([]string, len(validators)) - i := 0 - for key := range validators { - keys[i] = key - i++ - } - sort.Strings(keys) - return keys -} - -// randomProposer picks a random proposer from the current validator set -func randomProposer(r *rand.Rand, validators map[string]mockValidator) cmn.HexBytes { - keys := getKeys(validators) - if len(keys) == 0 { - return nil - } - key := keys[r.Intn(len(keys))] - proposer := validators[key].val - pk, err := tmtypes.PB2TM.PubKey(proposer.PubKey) - if err != nil { - panic(err) - } - return pk.Address() -} - -// updateValidators mimicks Tendermint's update logic -// nolint: unparam -func updateValidators(tb testing.TB, r *rand.Rand, params Params, - current map[string]mockValidator, updates []abci.ValidatorUpdate, - event func(string)) map[string]mockValidator { - - for _, update := range updates { - str := fmt.Sprintf("%v", update.PubKey) - if update.Power == 0 { - if _, ok := current[str]; !ok { - tb.Fatalf("tried to delete a nonexistent validator") - } - event("endblock/validatorupdates/kicked") - delete(current, str) - - } else if mVal, ok := current[str]; ok { - // validator already exists - mVal.val = update - event("endblock/validatorupdates/updated") - } else { - // Set this new validator - current[str] = mockValidator{ - update, - GetMemberOfInitialState(r, params.InitialLivenessWeightings), - } - event("endblock/validatorupdates/added") - } - } - - return current -} From eb16a01666e79f38c73c3fdde3d16370539aa0b9 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 8 Nov 2018 00:22:16 -0500 Subject: [PATCH 13/33] util cleanup --- x/mock/simulation/mock_tendermint.go | 2 + x/mock/simulation/util.go | 87 +++++++++++++++------------- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/x/mock/simulation/mock_tendermint.go b/x/mock/simulation/mock_tendermint.go index ee381cbb6..a98e89614 100644 --- a/x/mock/simulation/mock_tendermint.go +++ b/x/mock/simulation/mock_tendermint.go @@ -74,6 +74,7 @@ func updateValidators(tb testing.TB, r *rand.Rand, params Params, for _, update := range updates { str := fmt.Sprintf("%v", update.PubKey) + if update.Power == 0 { if _, ok := current[str]; !ok { tb.Fatalf("tried to delete a nonexistent validator") @@ -85,6 +86,7 @@ func updateValidators(tb testing.TB, r *rand.Rand, params Params, // validator already exists mVal.val = update event("endblock/validatorupdates/updated") + } else { // Set this new validator current[str] = mockValidator{ diff --git a/x/mock/simulation/util.go b/x/mock/simulation/util.go index e115cde24..6b2c01052 100644 --- a/x/mock/simulation/util.go +++ b/x/mock/simulation/util.go @@ -34,54 +34,61 @@ func DisplayEvents(events map[string]uint) { } // Builds a function to add logs for this particular block -func addLogMessage(testingmode bool, blockLogBuilders []*strings.Builder, height int) func(string) { - if testingmode { - blockLogBuilders[height] = &strings.Builder{} - return func(x string) { - (*blockLogBuilders[height]).WriteString(x) - (*blockLogBuilders[height]).WriteString("\n") - } +func addLogMessage(testingmode bool, + blockLogBuilders []*strings.Builder, height int) func(string) { + + if !testingmode { + return func(_ string) {} + } + + blockLogBuilders[height] = &strings.Builder{} + return func(x string) { + (*blockLogBuilders[height]).WriteString(x) + (*blockLogBuilders[height]).WriteString("\n") } - return func(x string) {} } // Creates a function to print out the logs func logPrinter(testingmode bool, logs []*strings.Builder) func() { - if testingmode { - return func() { - numLoggers := 0 - for i := 0; i < len(logs); i++ { - // We're passed the last created block - if logs[i] == nil { - numLoggers = i - break - } - } - var f *os.File - if numLoggers > 10 { + if !testingmode { + return func() {} + } - fileName := fmt.Sprintf("simulation_log_%s.txt", - time.Now().Format("2006-01-02 15:04:05")) - - fmt.Printf("Too many logs to display, instead writing to %s\n", fileName) - f, _ = os.Create(fileName) + return func() { + numLoggers := 0 + for i := 0; i < len(logs); i++ { + // We're passed the last created block + if logs[i] == nil { + numLoggers = i + break } - for i := 0; i < numLoggers; i++ { - if f != nil { - _, err := f.WriteString(fmt.Sprintf("Begin block %d\n", i+1)) - if err != nil { - panic("Failed to write logs to file") - } - _, err = f.WriteString((*logs[i]).String()) - if err != nil { - panic("Failed to write logs to file") - } - } else { - fmt.Printf("Begin block %d\n", i+1) - fmt.Println((*logs[i]).String()) - } + } + + var f *os.File + if numLoggers > 10 { + fileName := fmt.Sprintf("simulation_log_%s.txt", + time.Now().Format("2006-01-02 15:04:05")) + fmt.Printf("Too many logs to display, instead writing to %s\n", + fileName) + f, _ = os.Create(fileName) + } + + for i := 0; i < numLoggers; i++ { + if f == nil { + fmt.Printf("Begin block %d\n", i+1) + fmt.Println((*logs[i]).String()) + continue + } + + _, err := f.WriteString(fmt.Sprintf("Begin block %d\n", i+1)) + if err != nil { + panic("Failed to write logs to file") + } + + _, err = f.WriteString((*logs[i]).String()) + if err != nil { + panic("Failed to write logs to file") } } } - return func() {} } From 5f289e5fdd7fa80370e94215c7793909b4f936bc Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 8 Nov 2018 00:54:12 -0500 Subject: [PATCH 14/33] event stats object, more general cleanup --- x/mock/simulation/event_stats.go | 33 +++++++++++++ x/mock/simulation/operation.go | 14 ++++-- x/mock/simulation/simulate.go | 84 ++++++++++++++++---------------- x/mock/simulation/util.go | 14 ------ 4 files changed, 85 insertions(+), 60 deletions(-) create mode 100644 x/mock/simulation/event_stats.go diff --git a/x/mock/simulation/event_stats.go b/x/mock/simulation/event_stats.go new file mode 100644 index 000000000..5276c533b --- /dev/null +++ b/x/mock/simulation/event_stats.go @@ -0,0 +1,33 @@ +package simulation + +import ( + "fmt" + "sort" +) + +type eventStats map[string]uint + +func newEventStats() eventStats { + events := make(map[string]uint) + return events + event := func(what string) { + events[what]++ + } +} + +func (es *eventStats) tally(eventDesc string) { + es[eventDesc]++ +} + +// Pretty-print events as a table +func (es eventStats) Print() { + var keys []string + for key := range es { + keys = append(keys, key) + } + sort.Strings(keys) + fmt.Printf("Event statistics: \n") + for _, key := range keys { + fmt.Printf(" % 60s => %d\n", key, es[key]) + } +} diff --git a/x/mock/simulation/operation.go b/x/mock/simulation/operation.go index 27757df2d..7710cf5c9 100644 --- a/x/mock/simulation/operation.go +++ b/x/mock/simulation/operation.go @@ -18,17 +18,21 @@ import ( // // Operations can optionally provide a list of "FutureOperations" to run later // These will be ran at the beginning of the corresponding block. -type Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accounts []Account, event func(string)) ( - action string, futureOperations []FutureOperation, err error) +type Operation func(r *rand.Rand, app *baseapp.BaseApp, + ctx sdk.Context, accounts []Account, event func(string)) ( + action string, futureOps []FutureOperation, err error) // queue of operations type OperationQueue map[int][]Operation +func newOperationQueue() OperationQueue { + operationQueue := make(OperationQueue) + return operationQueue +} + // adds all future operations into the operation queue. func queueOperations(queuedOps OperationQueue, - queuedTimeOps []FutureOperation, - futureOps []FutureOperation) { + queuedTimeOps []FutureOperation, futureOps []FutureOperation) { if futureOps == nil { return diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index dc7c12bfe..e6749f4e1 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -21,10 +21,12 @@ import ( // RandSetup performs the random setup the mock module needs. type RandSetup func(r *rand.Rand, accounts []Account) +// AppStateFn returns the app state json bytes +type AppStateFn func(r *rand.Rand, accs []Account) json.RawMessage + // Simulate tests application by sending random messages. func Simulate(t *testing.T, app *baseapp.BaseApp, - appStateFn func(r *rand.Rand, accs []Account) json.RawMessage, - ops WeightedOperations, setups []RandSetup, + appStateFn AppStateFn, ops WeightedOperations, setups []RandSetup, invariants Invariants, numBlocks int, blockSize int, commit bool) error { time := time.Now().UnixNano() @@ -33,9 +35,9 @@ func Simulate(t *testing.T, app *baseapp.BaseApp, } // initialize the chain for the simulation -func initChain(r *rand.Rand, params Params, - accounts []Account, setups []RandSetup, app *baseapp.BaseApp, - appStateFn func(r *rand.Rand, accounts []Account) json.RawMessage) mockValidators { +func initChain(r *rand.Rand, params Params, accounts []Account, + setups []RandSetup, app *baseapp.BaseApp, + appStateFn AppStateFn) mockValidators { req := abci.RequestInitChain{ AppStateBytes: appStateFn(r, accounts), @@ -51,9 +53,10 @@ func initChain(r *rand.Rand, params Params, // SimulateFromSeed tests an application by running the provided // operations, testing the provided invariants, but using the provided seed. +// TODO split this monster function up func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, - appStateFn func(r *rand.Rand, accs []Account) json.RawMessage, - seed int64, ops WeightedOperations, setups []RandSetup, invariants Invariants, + appStateFn AppStateFn, seed int64, ops WeightedOperations, + setups []RandSetup, invariants Invariants, numBlocks int, blockSize int, commit bool) (simError error) { // in case we have to end early, don't os.Exit so that we can run cleanup code. @@ -71,20 +74,13 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, timestamp.UTC().Format(time.UnixDate), timestamp.Unix()) timeDiff := maxTimePerBlock - minTimePerBlock - accs := RandomAccounts(r, params.NumKeys) - - // Setup event stats - events := make(map[string]uint) - event := func(what string) { - events[what]++ - } - + eventStats := newEventStats() validators := initChain(r, params, accs, setups, app, appStateFn) - // Second variable to keep pending validator set (delayed one block since TM 0.24) - // Initially this is the same as the initial validator set - nextValidators := validators + // Second variable to keep pending validator set (delayed one block since + // TM 0.24) Initially this is the same as the initial validator set + nextValidators := validators() header := abci.Header{ Height: 1, @@ -108,10 +104,10 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, var pastVoteInfos [][]abci.VoteInfo request := RandomRequestBeginBlock(r, params, - validators, pastTimes, pastVoteInfos, event, header) + validators, pastTimes, pastVoteInfos, eventStats.tally, header) // These are operations which have been queued by previous operations - operationQueue := make(map[int][]Operation) + operationQueue := newOperationQueue() timeOperationQueue := []FutureOperation{} var blockLogBuilders []*strings.Builder @@ -120,7 +116,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, } displayLogs := logPrinter(testingMode, blockLogBuilders) blockSimulator := createBlockSimulator( - testingMode, tb, t, params, event, invariants, + testingMode, tb, t, params, eventStats.tally, invariants, ops, operationQueue, timeOperationQueue, numBlocks, blockSize, displayLogs) @@ -143,6 +139,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, // TODO split up the contents of this for loop into new functions for i := 0; i < numBlocks && !stopEarly; i++ { + // Log the header time for future lookup pastTimes = append(pastTimes, header.Time) pastVoteInfos = append(pastVoteInfos, request.LastCommitInfo.Votes) @@ -155,7 +152,6 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, app.BeginBlock(request) if testingMode { - // Make sure invariants hold at beginning of block invariants.assertAll(t, app, "BeginBlock", displayLogs) } @@ -166,13 +162,14 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, numQueuedOpsRan := runQueuedOperations( operationQueue, int(header.Height), tb, r, app, ctx, accs, logWriter, - displayLogs, event) + displayLogs, eventStats.tally) + numQueuedTimeOpsRan := runQueuedTimeOperations( timeOperationQueue, header.Time, tb, r, app, ctx, accs, - logWriter, displayLogs, event) + logWriter, displayLogs, eventStats.tally) + if testingMode && onOperation { - // Make sure invariants hold at end of queued operations invariants.assertAll(t, app, "QueuedOperations", displayLogs) } @@ -180,7 +177,6 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, operations := blockSimulator(r, app, ctx, accs, header, logWriter) opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan if testingMode { - // Make sure invariants hold at the operation invariants.assertAll(t, app, "StandardOperations", displayLogs) } @@ -194,7 +190,6 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, logWriter("EndBlock") if testingMode { - // Make sure invariants hold at end of block invariants.assertAll(t, app, "EndBlock", displayLogs) } if commit { @@ -208,24 +203,27 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, break } - // Generate a random RequestBeginBlock with the current validator set for the next block + // Generate a random RequestBeginBlock with the current validator set + // for the next block request = RandomRequestBeginBlock(r, params, validators, - pastTimes, pastVoteInfos, event, header) + pastTimes, pastVoteInfos, eventStats.tally, header) - // Update the validator set, which will be reflected in the application on the next block + // Update the validator set, which will be reflected in the application + // on the next block validators = nextValidators nextValidators = updateValidators(tb, r, params, - validators, res.ValidatorUpdates, event) + validators, res.ValidatorUpdates, eventStats.tally) } + if stopEarly { - DisplayEvents(events) - return + eventStats.Print() + return simError } fmt.Printf("\nSimulation complete. Final height (blocks): %d, "+ "final time (seconds), : %v, operations ran %d\n", header.Height, header.Time, opCount) - DisplayEvents(events) + eventStats.Print() return nil } @@ -252,7 +250,8 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params header.Height, totalNumBlocks, opCount, blocksize) lastBlocksizeState, blocksize = getBlockSize(r, params, lastBlocksizeState, avgBlockSize) - for j := 0; j < blocksize; j++ { + for i := 0; i < blocksize; i++ { + logUpdate, futureOps, err := selectOp(r)(r, app, ctx, accounts, event) logWriter(logUpdate) if err != nil { @@ -280,9 +279,9 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params // nolint: errcheck func runQueuedOperations(queueOps map[int][]Operation, - height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, - accounts []Account, logWriter func(string), - displayLogs func(), event func(string)) (numOpsRan int) { + height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, + ctx sdk.Context, accounts []Account, logWriter func(string), + displayLogs func(), tallyEvent func(string)) (numOpsRan int) { queuedOp, ok := queueOps[height] if !ok { @@ -291,10 +290,11 @@ func runQueuedOperations(queueOps map[int][]Operation, numOpsRan = len(queuedOp) for i := 0; i < numOpsRan; i++ { + // For now, queued operations cannot queue more operations. // If a need arises for us to support queued messages to queue more messages, this can // be changed. - logUpdate, _, err := queuedOp[i](r, app, ctx, accounts, event) + logUpdate, _, err := queuedOp[i](r, app, ctx, accounts, tallyEvent) logWriter(logUpdate) if err != nil { displayLogs() @@ -308,19 +308,21 @@ func runQueuedOperations(queueOps map[int][]Operation, func runQueuedTimeOperations(queueOps []FutureOperation, currentTime time.Time, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, - logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) { + logWriter func(string), displayLogs func(), tallyEvent func(string)) (numOpsRan int) { numOpsRan = 0 for len(queueOps) > 0 && currentTime.After(queueOps[0].BlockTime) { + // For now, queued operations cannot queue more operations. // If a need arises for us to support queued messages to queue more messages, this can // be changed. - logUpdate, _, err := queueOps[0].Op(r, app, ctx, accounts, event) + logUpdate, _, err := queueOps[0].Op(r, app, ctx, accounts, tallyEvent) logWriter(logUpdate) if err != nil { displayLogs() tb.FailNow() } + queueOps = queueOps[1:] numOpsRan++ } diff --git a/x/mock/simulation/util.go b/x/mock/simulation/util.go index 6b2c01052..02ef56d2e 100644 --- a/x/mock/simulation/util.go +++ b/x/mock/simulation/util.go @@ -3,7 +3,6 @@ package simulation import ( "fmt" "os" - "sort" "strings" "testing" "time" @@ -20,19 +19,6 @@ func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B return } -// Pretty-print events as a table -func DisplayEvents(events map[string]uint) { - var keys []string - for key := range events { - keys = append(keys, key) - } - sort.Strings(keys) - fmt.Printf("Event statistics: \n") - for _, key := range keys { - fmt.Printf(" % 60s => %d\n", key, events[key]) - } -} - // Builds a function to add logs for this particular block func addLogMessage(testingmode bool, blockLogBuilders []*strings.Builder, height int) func(string) { From a9ef83bc4a0de7b1672ae3ab513007d613f63a72 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 8 Nov 2018 01:57:37 -0500 Subject: [PATCH 15/33] compiling --- x/mock/simulation/event_stats.go | 5 +---- x/mock/simulation/mock_tendermint.go | 15 ++++++++------- x/mock/simulation/operation.go | 8 ++++---- x/mock/simulation/simulate.go | 10 +++++----- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/x/mock/simulation/event_stats.go b/x/mock/simulation/event_stats.go index 5276c533b..f54eef4cc 100644 --- a/x/mock/simulation/event_stats.go +++ b/x/mock/simulation/event_stats.go @@ -10,12 +10,9 @@ type eventStats map[string]uint func newEventStats() eventStats { events := make(map[string]uint) return events - event := func(what string) { - events[what]++ - } } -func (es *eventStats) tally(eventDesc string) { +func (es eventStats) tally(eventDesc string) { es[eventDesc]++ } diff --git a/x/mock/simulation/mock_tendermint.go b/x/mock/simulation/mock_tendermint.go index a98e89614..2ddac2e79 100644 --- a/x/mock/simulation/mock_tendermint.go +++ b/x/mock/simulation/mock_tendermint.go @@ -20,9 +20,10 @@ type mockValidator struct { type mockValidators map[string]mockValidator // get mockValidators from abci validators -func newMockValidators(abciVals abci.ValidatorUpdate) mockValidators { +func newMockValidators(r *rand.Rand, abciVals []abci.ValidatorUpdate, + params Params) mockValidators { - validators = make(mockValidators) + validators := make(mockValidators) for _, validator := range abciVals { str := fmt.Sprintf("%v", validator.PubKey) liveliness := GetMemberOfInitialState(r, @@ -39,9 +40,9 @@ func newMockValidators(abciVals abci.ValidatorUpdate) mockValidators { // TODO describe usage func (vals mockValidators) getKeys() []string { - keys := make([]string, len(validators)) + keys := make([]string, len(vals)) i := 0 - for key := range validators { + for key := range vals { keys[i] = key i++ } @@ -52,13 +53,13 @@ func (vals mockValidators) getKeys() []string { //_________________________________________________________________________________ // randomProposer picks a random proposer from the current validator set -func randomProposer(r *rand.Rand, validators map[string]mockValidator) cmn.HexBytes { - keys := validators.getKeys() +func (vals mockValidators) randomProposer(r *rand.Rand) cmn.HexBytes { + keys := vals.getKeys() if len(keys) == 0 { return nil } key := keys[r.Intn(len(keys))] - proposer := validators[key].val + proposer := vals[key].val pk, err := tmtypes.PB2TM.PubKey(proposer.PubKey) if err != nil { panic(err) diff --git a/x/mock/simulation/operation.go b/x/mock/simulation/operation.go index 7710cf5c9..00237e03e 100644 --- a/x/mock/simulation/operation.go +++ b/x/mock/simulation/operation.go @@ -86,17 +86,17 @@ type WeightedOperation struct { // WeightedOperations is the group of all weighted operations to simulate. type WeightedOperations []WeightedOperation -func (w WeightedOperations) totalWeight() int { +func (ops WeightedOperations) totalWeight() int { totalOpWeight := 0 - for i := 0; i < len(w); i++ { - totalOpWeight += w[i].Weight + for _, op := range ops { + totalOpWeight += op.Weight } return totalOpWeight } type selectOpFn func(r *rand.Rand) Operation -func (w WeightedOperations) getSelectOpFn() selectOpFn { +func (ops WeightedOperations) getSelectOpFn() selectOpFn { totalOpWeight := ops.totalWeight() return func(r *rand.Rand) Operation { x := r.Intn(totalOpWeight) diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index e6749f4e1..ac0e5d3f7 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -43,7 +43,7 @@ func initChain(r *rand.Rand, params Params, accounts []Account, AppStateBytes: appStateFn(r, accounts), } res := app.InitChain(req) - validators = newMockValidators(res.Validators) + validators := newMockValidators(r, res.Validators, params) for i := 0; i < len(setups); i++ { setups[i](r, accounts) @@ -76,16 +76,16 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, timeDiff := maxTimePerBlock - minTimePerBlock accs := RandomAccounts(r, params.NumKeys) eventStats := newEventStats() - validators := initChain(r, params, accs, setups, app, appStateFn) // Second variable to keep pending validator set (delayed one block since // TM 0.24) Initially this is the same as the initial validator set - nextValidators := validators() + validators := initChain(r, params, accs, setups, app, appStateFn) + nextValidators := validators header := abci.Header{ Height: 1, Time: timestamp, - ProposerAddress: randomProposer(r, validators), + ProposerAddress: validators.randomProposer(r), } opCount := 0 @@ -186,7 +186,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, time.Duration(minTimePerBlock) * time.Second) header.Time = header.Time.Add( time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second) - header.ProposerAddress = randomProposer(r, validators) + header.ProposerAddress = validators.randomProposer(r) logWriter("EndBlock") if testingMode { From bbf574cedbcb5a2cf0e734c68ff40b96ae624fbf Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 8 Nov 2018 02:19:08 -0500 Subject: [PATCH 16/33] pending --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index 4d87301f0..3f632a850 100644 --- a/PENDING.md +++ b/PENDING.md @@ -35,6 +35,7 @@ IMPROVEMENTS * Gaia * SDK + - [mock/simulation] [\#2720] major cleanup, introduction of helper objects, reorganization * Tendermint From bfc7944b55382c0749fecf294289e3b65792c4dc Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 8 Nov 2018 10:32:53 -0500 Subject: [PATCH 17/33] val comments --- x/mock/simulation/doc.go | 11 +++++------ x/mock/simulation/params.go | 23 ----------------------- x/mock/simulation/transition_matrix.go | 2 +- x/mock/simulation/util.go | 24 ++++++++++++++++++++++++ 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/x/mock/simulation/doc.go b/x/mock/simulation/doc.go index 2febd9e47..ff292bd38 100644 --- a/x/mock/simulation/doc.go +++ b/x/mock/simulation/doc.go @@ -2,12 +2,11 @@ Package simulation implements a simulation framework for any state machine built on the SDK which utilizes auth. -It is primarily intended for fuzz testing the integration of modules. It will +It is primarily intended for fuzz testing the integration of modules. It will test that the provided operations are interoperable, and that the desired -invariants hold. It can additionally be used to detect what the performance +invariants hold. It can additionally be used to detect what the performance benchmarks in the system are, by using benchmarking mode and cpu / mem -profiling. If it detects a failure, it provides the entire log of what was -ran, +profiling. If it detects a failure, it provides the entire log of what was ran. The simulator takes as input: a random seed, the set of operations to run, the invariants to test, and additional parameters to configure how long to run, and @@ -15,12 +14,12 @@ misc. parameters that affect simulation speed. It is intended that every module provides a list of Operations which will randomly create and run a message / tx in a manner that is interesting to fuzz, -and verify that the state transition was executed as expected. Each module +and verify that the state transition was executed as expected. Each module should additionally provide methods to assert that the desired invariants hold. Then to perform a randomized simulation, select the set of desired operations, the weightings for each, the invariants you want to test, and how long to run -it for. Then run simulation.Simulate! The simulator will handle things like +it for. Then run simulation.Simulate! The simulator will handle things like ensuring that validators periodically double signing, or go offline. */ package simulation diff --git a/x/mock/simulation/params.go b/x/mock/simulation/params.go index c46ab236b..8499e6c11 100644 --- a/x/mock/simulation/params.go +++ b/x/mock/simulation/params.go @@ -44,29 +44,6 @@ type Params struct { BlockSizeTransitionMatrix TransitionMatrix } -// getBlockSize returns a block size as determined from the transition matrix. -// It targets making average block size the provided parameter. The three -// states it moves between are: -// - "over stuffed" blocks with average size of 2 * avgblocksize, -// - normal sized blocks, hitting avgBlocksize on average, -// - and empty blocks, with no txs / only txs scheduled from the past. -func getBlockSize(r *rand.Rand, params Params, - lastBlockSizeState, avgBlockSize int) (state, blocksize int) { - - // TODO: Make default blocksize transition matrix actually make the average - // blocksize equal to avgBlockSize. - state = params.BlockSizeTransitionMatrix.NextState(r, lastBlockSizeState) - switch state { - case 0: - blocksize = r.Intn(avgBlockSize * 4) - case 1: - blocksize = r.Intn(avgBlockSize * 2) - default: - blocksize = 0 - } - return state, blocksize -} - // Return default simulation parameters func DefaultParams() Params { return Params{ diff --git a/x/mock/simulation/transition_matrix.go b/x/mock/simulation/transition_matrix.go index 97cd307e5..f7d713775 100644 --- a/x/mock/simulation/transition_matrix.go +++ b/x/mock/simulation/transition_matrix.go @@ -51,7 +51,7 @@ func (t TransitionMatrix) NextState(r *rand.Rand, i int) int { } // GetMemberOfInitialState takes an initial array of weights, of size n. -// It returns a weighted random number in [0,n]. +// It returns a weighted random number in [0,n). func GetMemberOfInitialState(r *rand.Rand, weights []int) int { n := len(weights) total := 0 diff --git a/x/mock/simulation/util.go b/x/mock/simulation/util.go index 02ef56d2e..f10364aaa 100644 --- a/x/mock/simulation/util.go +++ b/x/mock/simulation/util.go @@ -2,6 +2,7 @@ package simulation import ( "fmt" + "math/rand" "os" "strings" "testing" @@ -78,3 +79,26 @@ func logPrinter(testingmode bool, logs []*strings.Builder) func() { } } } + +// getBlockSize returns a block size as determined from the transition matrix. +// It targets making average block size the provided parameter. The three +// states it moves between are: +// - "over stuffed" blocks with average size of 2 * avgblocksize, +// - normal sized blocks, hitting avgBlocksize on average, +// - and empty blocks, with no txs / only txs scheduled from the past. +func getBlockSize(r *rand.Rand, params Params, + lastBlockSizeState, avgBlockSize int) (state, blocksize int) { + + // TODO: Make default blocksize transition matrix actually make the average + // blocksize equal to avgBlockSize. + state = params.BlockSizeTransitionMatrix.NextState(r, lastBlockSizeState) + switch state { + case 0: + blocksize = r.Intn(avgBlockSize * 4) + case 1: + blocksize = r.Intn(avgBlockSize * 2) + default: + blocksize = 0 + } + return state, blocksize +} From 94f45311a04f2f5e51046d23cf4885c3045262f9 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 9 Nov 2018 01:28:28 +0100 Subject: [PATCH 18/33] Fix state export/import, add to CI (#2690) * Update slashing import/export * More slashing.WriteGenesis * Add test import/export to CI * Store equality comparison. * Fix validator bond intra-tx counter * Set timeslices for unbonding validators * WriteGenesis => ExportGenesis * Delete validators from unbonding queue when re-bonded * Hook for validator deletion, fix staking genesis tests --- .circleci/config.yml | 21 +++++ Makefile | 12 ++- PENDING.md | 5 +- cmd/gaia/app/app.go | 32 +++++--- cmd/gaia/app/genesis.go | 30 ++++--- cmd/gaia/app/sim_test.go | 98 +++++++++++++++++++++++ cmd/gaia/init/collect.go | 2 +- cmd/gaia/init/init.go | 2 +- cmd/gaia/init/testnet.go | 2 +- cmd/gaia/init/utils.go | 8 +- docs/spec/staking/hooks.md | 2 +- examples/basecoin/cmd/basecoind/main.go | 2 +- examples/democoin/app/app.go | 4 +- examples/democoin/cmd/democoind/main.go | 2 +- examples/democoin/x/cool/keeper.go | 4 +- examples/democoin/x/cool/keeper_test.go | 2 +- examples/democoin/x/pow/keeper.go | 4 +- examples/democoin/x/pow/keeper_test.go | 2 +- types/stake.go | 6 +- types/store.go | 38 +++++++++ x/auth/genesis.go | 33 ++++++++ x/auth/{mapper.go => keeper.go} | 0 x/auth/{mapper_test.go => keeper_test.go} | 0 x/distribution/genesis.go | 8 +- x/distribution/keeper/genesis.go | 4 +- x/distribution/keeper/hooks.go | 2 +- x/distribution/keeper/key.go | 9 +++ x/distribution/types/genesis.go | 4 +- x/gov/genesis.go | 59 ++++++++++++-- x/gov/handler.go | 2 +- x/mint/genesis.go | 4 +- x/slashing/genesis.go | 75 ++++++++++++++++- x/slashing/hooks.go | 25 +++++- x/slashing/keeper.go | 16 ---- x/slashing/keeper_test.go | 21 ++--- x/slashing/keys.go | 9 +++ x/slashing/signing_info.go | 33 ++++++++ x/slashing/slashing_period.go | 15 ++++ x/slashing/test_common.go | 2 +- x/slashing/tick_test.go | 3 +- x/stake/genesis.go | 80 +++++++++++++----- x/stake/genesis_test.go | 23 +++--- x/stake/keeper/delegation.go | 15 ++++ x/stake/keeper/hooks.go | 4 +- x/stake/keeper/val_state_change.go | 9 ++- x/stake/keeper/validator.go | 33 +++++++- x/stake/stake.go | 3 + x/stake/types/genesis.go | 16 +++- 48 files changed, 640 insertions(+), 145 deletions(-) create mode 100644 x/auth/genesis.go rename x/auth/{mapper.go => keeper.go} (100%) rename x/auth/{mapper_test.go => keeper_test.go} (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 879df07f0..708b5887d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -137,6 +137,24 @@ jobs: export PATH="$GOBIN:$PATH" make test_sim_gaia_fast + test_sim_gaia_import_export: + <<: *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_import_export + test_sim_gaia_multi_seed: <<: *defaults parallelism: 1 @@ -259,6 +277,9 @@ workflows: - test_sim_gaia_fast: requires: - setup_dependencies + - test_sim_gaia_import_export: + requires: + - setup_dependencies - test_sim_gaia_multi_seed: requires: - setup_dependencies diff --git a/Makefile b/Makefile index af4ea71c9..aaa2fbcf3 100644 --- a/Makefile +++ b/Makefile @@ -171,6 +171,15 @@ test_sim_gaia_fast: @echo "Running quick Gaia simulation. This may take several minutes..." @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=500 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=10 -v -timeout 24h +test_sim_gaia_import_export: + @echo "Running Gaia import/export simulation. This may take several minutes..." + @go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=4 -v -timeout 24h + @go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=11 -v -timeout 24h + @go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=12 -v -timeout 24h + @go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=13 -v -timeout 24h + @go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=414 -v -timeout 24h + @go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=4142 -v -timeout 24h + test_sim_gaia_multi_seed: @echo "Running multi-seed Gaia simulation. This may take awhile!" @bash scripts/multisim.sh 25 @@ -250,4 +259,5 @@ localnet-stop: check_tools check_dev_tools get_tools get_dev_tools get_vendor_deps draw_deps test test_cli test_unit \ test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \ build-linux build-docker-gaiadnode localnet-start localnet-stop \ -format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast test_sim_gaia_multi_seed update_tools update_dev_tools +format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast \ +test_sim_gaia_multi_seed test_sim_gaia_import_export update_tools update_dev_tools diff --git a/PENDING.md b/PENDING.md index 8b2044ea2..1d5752fc2 100644 --- a/PENDING.md +++ b/PENDING.md @@ -28,7 +28,7 @@ FEATURES * Gaia * SDK - * (#1336) Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes. + - \#1336 Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes. * Tendermint @@ -65,7 +65,8 @@ BUG FIXES * Gaia CLI (`gaiacli`) * Gaia - - \#2670 [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators` + - \#2670 [x/stake] fixed incorrent `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators` + - \#2648 [gaiad] Fix `gaiad export` / `gaiad import` consistency, test in CI - \#2691 Fix local testnet creation by using a single canonical genesis time * SDK diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 1927d235d..918bfc67d 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -210,9 +210,6 @@ func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.R tags := gov.EndBlocker(ctx, app.govKeeper) validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper) - // Add these new validators to the addr -> pubkey map. - app.slashingKeeper.AddValidators(ctx, validatorUpdates) - return abci.ResponseEndBlock{ ValidatorUpdates: validatorUpdates, Tags: tags, @@ -231,6 +228,10 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci // return sdk.ErrGenesisParse("").TraceCause(err, "") } + // 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 + }) // load the accounts for _, gacc := range genesisState.Accounts { acc := gacc.ToAccount() @@ -244,7 +245,8 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci panic(err) // TODO find a way to do this w/o panics } - // load the address to pubkey map + // initialize module-specific stores + auth.InitGenesis(ctx, app.feeCollectionKeeper, genesisState.AuthData) slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData) gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData) mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData) @@ -270,7 +272,6 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx) } - app.slashingKeeper.AddValidators(ctx, validators) // sanity check if len(req.Validators) > 0 { @@ -306,11 +307,12 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val app.accountKeeper.IterateAccounts(ctx, appendAccount) genState := NewGenesisState( accounts, - stake.WriteGenesis(ctx, app.stakeKeeper), - mint.WriteGenesis(ctx, app.mintKeeper), - distr.WriteGenesis(ctx, app.distrKeeper), - gov.WriteGenesis(ctx, app.govKeeper), - slashing.GenesisState{}, // TODO create write methods + 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 { @@ -337,12 +339,15 @@ var _ sdk.StakingHooks = Hooks{} // nolint func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { h.dh.OnValidatorCreated(ctx, valAddr) + h.sh.OnValidatorCreated(ctx, valAddr) } func (h Hooks) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) { h.dh.OnValidatorModified(ctx, valAddr) + h.sh.OnValidatorModified(ctx, valAddr) } -func (h Hooks) OnValidatorRemoved(ctx sdk.Context, valAddr sdk.ValAddress) { - h.dh.OnValidatorRemoved(ctx, valAddr) +func (h Hooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { + h.dh.OnValidatorRemoved(ctx, consAddr, valAddr) + h.sh.OnValidatorRemoved(ctx, consAddr, valAddr) } func (h Hooks) OnValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { h.dh.OnValidatorBonded(ctx, consAddr, valAddr) @@ -358,10 +363,13 @@ func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddre } func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { h.dh.OnDelegationCreated(ctx, delAddr, valAddr) + h.sh.OnDelegationCreated(ctx, delAddr, valAddr) } func (h Hooks) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { h.dh.OnDelegationSharesModified(ctx, delAddr, valAddr) + h.sh.OnDelegationSharesModified(ctx, delAddr, valAddr) } func (h Hooks) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { h.dh.OnDelegationRemoved(ctx, delAddr, valAddr) + h.sh.OnDelegationRemoved(ctx, delAddr, valAddr) } diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index cfbbe5cc2..38256e415 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -32,6 +32,7 @@ var ( // State to Unmarshal type GenesisState struct { Accounts []GenesisAccount `json:"accounts"` + AuthData auth.GenesisState `json:"auth"` StakeData stake.GenesisState `json:"stake"` MintData mint.GenesisState `json:"mint"` DistrData distr.GenesisState `json:"distr"` @@ -40,11 +41,12 @@ type GenesisState struct { GenTxs []json.RawMessage `json:"gentxs"` } -func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mintData mint.GenesisState, +func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState, stakeData stake.GenesisState, mintData mint.GenesisState, distrData distr.GenesisState, govData gov.GenesisState, slashingData slashing.GenesisState) GenesisState { return GenesisState{ Accounts: accounts, + AuthData: authData, StakeData: stakeData, MintData: mintData, DistrData: distrData, @@ -53,31 +55,39 @@ func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mi } } -// GenesisAccount doesn't need pubkey or sequence +// nolint type GenesisAccount struct { - Address sdk.AccAddress `json:"address"` - Coins sdk.Coins `json:"coins"` + Address sdk.AccAddress `json:"address"` + Coins sdk.Coins `json:"coins"` + Sequence int64 `json:"sequence_number"` + AccountNumber int64 `json:"account_number"` } func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount { return GenesisAccount{ - Address: acc.Address, - Coins: acc.Coins, + Address: acc.Address, + Coins: acc.Coins, + AccountNumber: acc.AccountNumber, + Sequence: acc.Sequence, } } func NewGenesisAccountI(acc auth.Account) GenesisAccount { return GenesisAccount{ - Address: acc.GetAddress(), - Coins: acc.GetCoins(), + Address: acc.GetAddress(), + Coins: acc.GetCoins(), + AccountNumber: acc.GetAccountNumber(), + Sequence: acc.GetSequence(), } } // convert GenesisAccount to auth.BaseAccount func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { return &auth.BaseAccount{ - Address: ga.Address, - Coins: ga.Coins.Sort(), + Address: ga.Address, + Coins: ga.Coins.Sort(), + AccountNumber: ga.AccountNumber, + Sequence: ga.Sequence, } } diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 431c5bc41..60befcc38 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" @@ -266,6 +267,103 @@ func TestFullGaiaSimulation(t *testing.T) { require.Nil(t, err) } +func TestGaiaImportExport(t *testing.T) { + if !enabled { + t.Skip("Skipping Gaia import/export simulation") + } + + // Setup Gaia application + var logger log.Logger + if verbose { + logger = log.TestingLogger() + } else { + logger = log.NewNopLogger() + } + var db dbm.DB + dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim") + db, _ = dbm.NewGoLevelDB("Simulation", dir) + defer func() { + db.Close() + os.RemoveAll(dir) + }() + app := NewGaiaApp(logger, db, nil) + require.Equal(t, "GaiaApp", app.Name()) + + // Run randomized simulation + err := simulation.SimulateFromSeed( + t, app.BaseApp, appStateFn, seed, + testAndRunTxs(app), + []simulation.RandSetup{}, + invariants(app), + numBlocks, + blockSize, + commit, + ) + if commit { + // for memdb: + // fmt.Println("Database Size", db.Stats()["database.size"]) + fmt.Println("GoLevelDB Stats") + fmt.Println(db.Stats()["leveldb.stats"]) + fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) + } + require.Nil(t, err) + + fmt.Printf("Exporting genesis...\n") + + appState, _, err := app.ExportAppStateAndValidators() + if err != nil { + panic(err) + } + + fmt.Printf("Importing genesis...\n") + + newDir, _ := ioutil.TempDir("", "goleveldb-gaia-sim-2") + newDB, _ := dbm.NewGoLevelDB("Simulation-2", dir) + defer func() { + newDB.Close() + os.RemoveAll(newDir) + }() + newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil) + require.Equal(t, "GaiaApp", newApp.Name()) + request := abci.RequestInitChain{ + AppStateBytes: appState, + } + newApp.InitChain(request) + newApp.Commit() + + fmt.Printf("Comparing stores...\n") + ctxA := app.NewContext(true, abci.Header{}) + ctxB := newApp.NewContext(true, abci.Header{}) + type StoreKeysPrefixes struct { + A sdk.StoreKey + B sdk.StoreKey + Prefixes [][]byte + } + storeKeysPrefixes := []StoreKeysPrefixes{ + {app.keyMain, newApp.keyMain, [][]byte{}}, + {app.keyAccount, newApp.keyAccount, [][]byte{}}, + {app.keyStake, newApp.keyStake, [][]byte{stake.UnbondingQueueKey, stake.RedelegationQueueKey, stake.ValidatorQueueKey}}, // ordering may change but it doesn't matter + {app.keySlashing, newApp.keySlashing, [][]byte{}}, + {app.keyMint, newApp.keyMint, [][]byte{}}, + {app.keyDistr, newApp.keyDistr, [][]byte{}}, + {app.keyFeeCollection, newApp.keyFeeCollection, [][]byte{}}, + {app.keyParams, newApp.keyParams, [][]byte{}}, + {app.keyGov, newApp.keyGov, [][]byte{}}, + } + for _, storeKeysPrefix := range storeKeysPrefixes { + storeKeyA := storeKeysPrefix.A + storeKeyB := storeKeysPrefix.B + prefixes := storeKeysPrefix.Prefixes + storeA := ctxA.KVStore(storeKeyA) + storeB := ctxB.KVStore(storeKeyB) + kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB, prefixes) + fmt.Printf("Compared %d key/value pairs between %s and %s\n", count, storeKeyA, storeKeyB) + require.True(t, equal, "unequal stores: %s / %s:\nstore A %s (%X) => %s (%X)\nstore B %s (%X) => %s (%X)", + storeKeyA, storeKeyB, kvA.Key, kvA.Key, kvA.Value, kvA.Value, kvB.Key, kvB.Key, kvB.Value, kvB.Value) + } + +} + // TODO: Make another test for the fuzzer itself, which just has noOp txs // and doesn't depend on gaia func TestAppStateDeterminism(t *testing.T) { diff --git a/cmd/gaia/init/collect.go b/cmd/gaia/init/collect.go index 97d9743a0..cdfc1688c 100644 --- a/cmd/gaia/init/collect.go +++ b/cmd/gaia/init/collect.go @@ -113,6 +113,6 @@ func genAppStateFromConfig( return } - err = WriteGenesisFile(genFile, initCfg.ChainID, nil, appState) + err = ExportGenesisFile(genFile, initCfg.ChainID, nil, appState) return } diff --git a/cmd/gaia/init/init.go b/cmd/gaia/init/init.go index f2a815a5c..a297caee2 100644 --- a/cmd/gaia/init/init.go +++ b/cmd/gaia/init/init.go @@ -70,7 +70,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob viper.GetBool(flagOverwrite)); err != nil { return err } - if err = WriteGenesisFile(genFile, chainID, nil, appState); err != nil { + if err = ExportGenesisFile(genFile, chainID, nil, appState); err != nil { return err } diff --git a/cmd/gaia/init/testnet.go b/cmd/gaia/init/testnet.go index 42d8332d2..8bada583e 100644 --- a/cmd/gaia/init/testnet.go +++ b/cmd/gaia/init/testnet.go @@ -298,7 +298,7 @@ func collectGenFiles( genFile := config.GenesisFile() // overwrite each validator's genesis file to have a canonical genesis time - err = WriteGenesisFileWithTime(genFile, chainID, nil, appState, genTime) + err = ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime) if err != nil { return err } diff --git a/cmd/gaia/init/utils.go b/cmd/gaia/init/utils.go index 173843370..58edc9b2a 100644 --- a/cmd/gaia/init/utils.go +++ b/cmd/gaia/init/utils.go @@ -17,9 +17,9 @@ import ( "github.com/tendermint/tendermint/types" ) -// WriteGenesisFile creates and writes the genesis configuration to disk. An +// ExportGenesisFile creates and writes the genesis configuration to disk. An // error is returned if building or writing the configuration to file fails. -func WriteGenesisFile( +func ExportGenesisFile( genFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage, ) error { @@ -36,9 +36,9 @@ func WriteGenesisFile( return genDoc.SaveAs(genFile) } -// WriteGenesisFileWithTime creates and writes the genesis configuration to disk. +// ExportGenesisFileWithTime creates and writes the genesis configuration to disk. // An error is returned if building or writing the configuration to file fails. -func WriteGenesisFileWithTime( +func ExportGenesisFileWithTime( genFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage, genTime time.Time, ) error { diff --git a/docs/spec/staking/hooks.md b/docs/spec/staking/hooks.md index 7d24e32e6..3644155a6 100644 --- a/docs/spec/staking/hooks.md +++ b/docs/spec/staking/hooks.md @@ -7,7 +7,7 @@ The staking module allow for the following hooks to be registered with staking e type StakingHooks interface { OnValidatorCreated(ctx Context, address ValAddress) // Must be called when a validator is created OnValidatorModified(ctx Context, address ValAddress) // Must be called when a validator's state changes - OnValidatorRemoved(ctx Context, address ValAddress) // Must be called when a validator is deleted + OnValidatorRemoved(ctx Context, address ConsAddress, operator ValAddress) // Must be called when a validator is deleted OnValidatorBonded(ctx Context, address ConsAddress) // called when a validator is bonded OnValidatorBeginUnbonding(ctx Context, address ConsAddress, operator ValAddress) // called when a validator begins unbonding diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 4f40a1450..f07fbd3ff 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -108,7 +108,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob return err } fmt.Fprintf(os.Stderr, "%s\n", string(out)) - return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID, + return gaiaInit.ExportGenesisFile(config.GenesisFile(), chainID, []tmtypes.GenesisValidator{validator}, appStateJSON) }, } diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 12f5d8d29..e8ddd066d 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -186,8 +186,8 @@ func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage, genState := types.GenesisState{ Accounts: accounts, - POWGenesis: pow.WriteGenesis(ctx, app.powKeeper), - CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper), + POWGenesis: pow.ExportGenesis(ctx, app.powKeeper), + CoolGenesis: cool.ExportGenesis(ctx, app.coolKeeper), } appState, err = codec.MarshalJSONIndent(app.cdc, genState) if err != nil { diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 2f48a64f3..d095b4c79 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -115,7 +115,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob return err } fmt.Fprintf(os.Stderr, "%s\n", string(out)) - return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID, + return gaiaInit.ExportGenesisFile(config.GenesisFile(), chainID, []tmtypes.GenesisValidator{validator}, appStateJSON) }, } diff --git a/examples/democoin/x/cool/keeper.go b/examples/democoin/x/cool/keeper.go index f805ca880..9f46b0209 100644 --- a/examples/democoin/x/cool/keeper.go +++ b/examples/democoin/x/cool/keeper.go @@ -49,8 +49,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, data Genesis) error { return nil } -// WriteGenesis - output the genesis trend -func WriteGenesis(ctx sdk.Context, k Keeper) Genesis { +// ExportGenesis - output the genesis trend +func ExportGenesis(ctx sdk.Context, k Keeper) Genesis { trend := k.GetTrend(ctx) return Genesis{trend} } diff --git a/examples/democoin/x/cool/keeper_test.go b/examples/democoin/x/cool/keeper_test.go index 1eb40dfb2..904681382 100644 --- a/examples/democoin/x/cool/keeper_test.go +++ b/examples/democoin/x/cool/keeper_test.go @@ -37,7 +37,7 @@ func TestCoolKeeper(t *testing.T) { err := InitGenesis(ctx, keeper, Genesis{"icy"}) require.Nil(t, err) - genesis := WriteGenesis(ctx, keeper) + genesis := ExportGenesis(ctx, keeper) require.Nil(t, err) require.Equal(t, genesis, Genesis{"icy"}) diff --git a/examples/democoin/x/pow/keeper.go b/examples/democoin/x/pow/keeper.go index 38a0d93c6..6c3bfc4eb 100644 --- a/examples/democoin/x/pow/keeper.go +++ b/examples/democoin/x/pow/keeper.go @@ -43,8 +43,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, genesis Genesis) error { return nil } -// WriteGenesis for the PoW module -func WriteGenesis(ctx sdk.Context, k Keeper) Genesis { +// ExportGenesis for the PoW module +func ExportGenesis(ctx sdk.Context, k Keeper) Genesis { difficulty, err := k.GetLastDifficulty(ctx) if err != nil { panic(err) diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index 86ccbc8c0..c8d5406f9 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -41,7 +41,7 @@ func TestPowKeeperGetSet(t *testing.T) { err := InitGenesis(ctx, keeper, Genesis{uint64(1), uint64(0)}) require.Nil(t, err) - genesis := WriteGenesis(ctx, keeper) + genesis := ExportGenesis(ctx, keeper) require.Nil(t, err) require.Equal(t, genesis, Genesis{uint64(1), uint64(0)}) diff --git a/types/stake.go b/types/stake.go index 7b10b17f8..38f1c0c9b 100644 --- a/types/stake.go +++ b/types/stake.go @@ -115,9 +115,9 @@ type DelegationSet interface { // event hooks for staking validator object type StakingHooks interface { - OnValidatorCreated(ctx Context, valAddr ValAddress) // Must be called when a validator is created - OnValidatorModified(ctx Context, valAddr ValAddress) // Must be called when a validator's state changes - OnValidatorRemoved(ctx Context, valAddr ValAddress) // Must be called when a validator is deleted + OnValidatorCreated(ctx Context, valAddr ValAddress) // Must be called when a validator is created + OnValidatorModified(ctx Context, valAddr ValAddress) // Must be called when a validator's state changes + OnValidatorRemoved(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is deleted OnValidatorBonded(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is bonded OnValidatorBeginUnbonding(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator begins unbonding diff --git a/types/store.go b/types/store.go index a90dc223d..4b6e79a76 100644 --- a/types/store.go +++ b/types/store.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "fmt" "io" @@ -176,6 +177,43 @@ func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator { return kvs.ReverseIterator(prefix, PrefixEndBytes(prefix)) } +// Compare two KVstores, return either the first key/value pair +// at which they differ and whether or not they are equal, skipping +// value comparison for a set of provided prefixes +func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvA cmn.KVPair, kvB cmn.KVPair, count int64, equal bool) { + iterA := a.Iterator(nil, nil) + iterB := b.Iterator(nil, nil) + count = int64(0) + for { + if !iterA.Valid() && !iterB.Valid() { + break + } + var kvA, kvB cmn.KVPair + if iterA.Valid() { + kvA = cmn.KVPair{Key: iterA.Key(), Value: iterA.Value()} + iterA.Next() + } + if iterB.Valid() { + kvB = cmn.KVPair{Key: iterB.Key(), Value: iterB.Value()} + iterB.Next() + } + compareValue := true + for _, prefix := range prefixesToSkip { + if bytes.Equal(kvA.Key[:len(prefix)], prefix) { + compareValue = false + } + } + if !bytes.Equal(kvA.Key, kvB.Key) { + return kvA, kvB, count, false + } + if compareValue && !bytes.Equal(kvA.Value, kvB.Value) { + return kvA, kvB, count, false + } + count++ + } + return cmn.KVPair{}, cmn.KVPair{}, count, true +} + // CacheKVStore cache-wraps a KVStore. After calling .Write() on // the CacheKVStore, all previously created CacheKVStores on the // object expire. diff --git a/x/auth/genesis.go b/x/auth/genesis.go new file mode 100644 index 000000000..abc4fc3ae --- /dev/null +++ b/x/auth/genesis.go @@ -0,0 +1,33 @@ +package auth + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// GenesisState - all auth state that must be provided at genesis +type GenesisState struct { + CollectedFees sdk.Coins `json:"collected_fees"` // collected fees +} + +// Create a new genesis state +func NewGenesisState(collectedFees sdk.Coins) GenesisState { + return GenesisState{ + CollectedFees: collectedFees, + } +} + +// Return a default genesis state +func DefaultGenesisState() GenesisState { + return NewGenesisState(sdk.Coins{}) +} + +// Init store state from genesis data +func InitGenesis(ctx sdk.Context, keeper FeeCollectionKeeper, data GenesisState) { + keeper.setCollectedFees(ctx, data.CollectedFees) +} + +// ExportGenesis returns a GenesisState for a given context and keeper +func ExportGenesis(ctx sdk.Context, keeper FeeCollectionKeeper) GenesisState { + collectedFees := keeper.GetCollectedFees(ctx) + return NewGenesisState(collectedFees) +} diff --git a/x/auth/mapper.go b/x/auth/keeper.go similarity index 100% rename from x/auth/mapper.go rename to x/auth/keeper.go diff --git a/x/auth/mapper_test.go b/x/auth/keeper_test.go similarity index 100% rename from x/auth/mapper_test.go rename to x/auth/keeper_test.go diff --git a/x/distribution/genesis.go b/x/distribution/genesis.go index 4ee5651a6..346808916 100644 --- a/x/distribution/genesis.go +++ b/x/distribution/genesis.go @@ -21,11 +21,12 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) { for _, dw := range data.DelegatorWithdrawInfos { keeper.SetDelegatorWithdrawAddr(ctx, dw.DelegatorAddr, dw.WithdrawAddr) } + keeper.SetPreviousProposerConsAddr(ctx, data.PreviousProposer) } -// WriteGenesis returns a GenesisState for a given context and keeper. The +// ExportGenesis returns a GenesisState for a given context and keeper. The // GenesisState will contain the pool, and validator/delegator distribution info's -func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { +func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { feePool := keeper.GetFeePool(ctx) communityTax := keeper.GetCommunityTax(ctx) baseProposerRewards := keeper.GetBaseProposerReward(ctx) @@ -33,6 +34,7 @@ func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { vdis := keeper.GetAllValidatorDistInfos(ctx) ddis := keeper.GetAllDelegationDistInfos(ctx) dwis := keeper.GetAllDelegatorWithdrawInfos(ctx) + pp := keeper.GetPreviousProposerConsAddr(ctx) return NewGenesisState(feePool, communityTax, baseProposerRewards, - bonusProposerRewards, vdis, ddis, dwis) + bonusProposerRewards, vdis, ddis, dwis, pp) } diff --git a/x/distribution/keeper/genesis.go b/x/distribution/keeper/genesis.go index 804ea5242..8e5a37abe 100644 --- a/x/distribution/keeper/genesis.go +++ b/x/distribution/keeper/genesis.go @@ -36,12 +36,12 @@ func (k Keeper) GetAllDelegationDistInfos(ctx sdk.Context) (ddis []types.Delegat // Get the set of all delegator-withdraw addresses with no limits, used during genesis dump func (k Keeper) GetAllDelegatorWithdrawInfos(ctx sdk.Context) (dwis []types.DelegatorWithdrawInfo) { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, DelegationDistInfoKey) + iterator := sdk.KVStorePrefixIterator(store, DelegatorWithdrawInfoKey) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { dw := types.DelegatorWithdrawInfo{ - DelegatorAddr: sdk.AccAddress(iterator.Key()), + DelegatorAddr: GetDelegatorWithdrawInfoAddress(iterator.Key()), WithdrawAddr: sdk.AccAddress(iterator.Value()), } dwis = append(dwis, dw) diff --git a/x/distribution/keeper/hooks.go b/x/distribution/keeper/hooks.go index cdebaf93c..a4f4353fa 100644 --- a/x/distribution/keeper/hooks.go +++ b/x/distribution/keeper/hooks.go @@ -103,7 +103,7 @@ func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { func (h Hooks) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) { h.k.onValidatorModified(ctx, valAddr) } -func (h Hooks) OnValidatorRemoved(ctx sdk.Context, valAddr sdk.ValAddress) { +func (h Hooks) OnValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) { h.k.onValidatorRemoved(ctx, valAddr) } func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { diff --git a/x/distribution/keeper/key.go b/x/distribution/keeper/key.go index 466d83c24..443d13079 100644 --- a/x/distribution/keeper/key.go +++ b/x/distribution/keeper/key.go @@ -44,3 +44,12 @@ func GetDelegationDistInfosKey(delAddr sdk.AccAddress) []byte { func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { return append(DelegatorWithdrawInfoKey, delAddr.Bytes()...) } + +// gets an address from a delegator's withdraw info key +func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) { + addr := key[1:] + if len(addr) != sdk.AddrLen { + panic("unexpected key length") + } + return sdk.AccAddress(addr) +} diff --git a/x/distribution/types/genesis.go b/x/distribution/types/genesis.go index 528295e5c..0577af4d3 100644 --- a/x/distribution/types/genesis.go +++ b/x/distribution/types/genesis.go @@ -18,10 +18,11 @@ type GenesisState struct { ValidatorDistInfos []ValidatorDistInfo `json:"validator_dist_infos"` DelegationDistInfos []DelegationDistInfo `json:"delegator_dist_infos"` DelegatorWithdrawInfos []DelegatorWithdrawInfo `json:"delegator_withdraw_infos"` + PreviousProposer sdk.ConsAddress `json:"previous_proposer"` } func NewGenesisState(feePool FeePool, communityTax, baseProposerReward, bonusProposerReward sdk.Dec, - vdis []ValidatorDistInfo, ddis []DelegationDistInfo, dwis []DelegatorWithdrawInfo) GenesisState { + vdis []ValidatorDistInfo, ddis []DelegationDistInfo, dwis []DelegatorWithdrawInfo, pp sdk.ConsAddress) GenesisState { return GenesisState{ FeePool: feePool, @@ -31,6 +32,7 @@ func NewGenesisState(feePool FeePool, communityTax, baseProposerReward, bonusPro ValidatorDistInfos: vdis, DelegationDistInfos: ddis, DelegatorWithdrawInfos: dwis, + PreviousProposer: pp, } } diff --git a/x/gov/genesis.go b/x/gov/genesis.go index db35f68c8..1243bf559 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -8,10 +8,25 @@ import ( // GenesisState - all staking state that must be provided at genesis type GenesisState struct { - StartingProposalID uint64 `json:"starting_proposalID"` - DepositParams DepositParams `json:"deposit_params"` - VotingParams VotingParams `json:"voting_params"` - TallyParams TallyParams `json:"tally_params"` + StartingProposalID uint64 `json:"starting_proposal_id"` + Deposits []DepositWithMetadata `json:"deposits"` + Votes []VoteWithMetadata `json:"votes"` + Proposals []Proposal `json:"proposals"` + DepositParams DepositParams `json:"deposit_params"` + VotingParams VotingParams `json:"voting_params"` + TallyParams TallyParams `json:"tally_params"` +} + +// DepositWithMetadata (just for genesis) +type DepositWithMetadata struct { + ProposalID uint64 `json:"proposal_id"` + Deposit Deposit `json:"deposit"` +} + +// VoteWithMetadata (just for genesis) +type VoteWithMetadata struct { + ProposalID uint64 `json:"proposal_id"` + Vote Vote `json:"vote"` } func NewGenesisState(startingProposalID uint64, dp DepositParams, vp VotingParams, tp TallyParams) GenesisState { @@ -52,17 +67,47 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { k.setDepositParams(ctx, data.DepositParams) k.setVotingParams(ctx, data.VotingParams) k.setTallyParams(ctx, data.TallyParams) + for _, deposit := range data.Deposits { + k.setDeposit(ctx, deposit.ProposalID, deposit.Deposit.Depositer, deposit.Deposit) + } + for _, vote := range data.Votes { + k.setVote(ctx, vote.ProposalID, vote.Vote.Voter, vote.Vote) + } + for _, proposal := range data.Proposals { + k.SetProposal(ctx, proposal) + } } -// WriteGenesis - output genesis parameters -func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState { - startingProposalID, _ := k.getNewProposalID(ctx) +// ExportGenesis - output genesis parameters +func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState { + startingProposalID, _ := k.peekCurrentProposalID(ctx) depositParams := k.GetDepositParams(ctx) votingParams := k.GetVotingParams(ctx) tallyParams := k.GetTallyParams(ctx) + var deposits []DepositWithMetadata + var votes []VoteWithMetadata + proposals := k.GetProposalsFiltered(ctx, nil, nil, StatusNil, 0) + for _, proposal := range proposals { + proposalID := proposal.GetProposalID() + depositsIterator := k.GetDeposits(ctx, proposalID) + for ; depositsIterator.Valid(); depositsIterator.Next() { + var deposit Deposit + k.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), &deposit) + deposits = append(deposits, DepositWithMetadata{proposalID, deposit}) + } + votesIterator := k.GetVotes(ctx, proposalID) + for ; votesIterator.Valid(); votesIterator.Next() { + var vote Vote + k.cdc.MustUnmarshalBinaryLengthPrefixed(votesIterator.Value(), &vote) + votes = append(votes, VoteWithMetadata{proposalID, vote}) + } + } return GenesisState{ StartingProposalID: startingProposalID, + Deposits: deposits, + Votes: votes, + Proposals: proposals, DepositParams: depositParams, VotingParams: votingParams, TallyParams: tallyParams, diff --git a/x/gov/handler.go b/x/gov/handler.go index 279c4cc6e..180f7a21a 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -107,8 +107,8 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { var proposalID uint64 keeper.cdc.MustUnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID) inactiveProposal := keeper.GetProposal(ctx, proposalID) - keeper.RefundDeposits(ctx, proposalID) keeper.DeleteProposal(ctx, proposalID) + keeper.DeleteDeposits(ctx, proposalID) // delete any associated deposits (burned) resTags = resTags.AppendTag(tags.Action, tags.ActionProposalDropped) resTags = resTags.AppendTag(tags.ProposalID, []byte(string(proposalID))) diff --git a/x/mint/genesis.go b/x/mint/genesis.go index 561768573..ce375d71e 100644 --- a/x/mint/genesis.go +++ b/x/mint/genesis.go @@ -31,9 +31,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { keeper.SetParams(ctx, data.Params) } -// WriteGenesis returns a GenesisState for a given context and keeper. The +// ExportGenesis returns a GenesisState for a given context and keeper. The // GenesisState will contain the pool, and validator/delegator distribution info's -func WriteGenesis(ctx sdk.Context, keeper Keeper) GenesisState { +func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { minter := keeper.GetMinter(ctx) params := keeper.GetParams(ctx) diff --git a/x/slashing/genesis.go b/x/slashing/genesis.go index 10af155d6..614bf41eb 100644 --- a/x/slashing/genesis.go +++ b/x/slashing/genesis.go @@ -7,13 +7,25 @@ import ( // GenesisState - all slashing state that must be provided at genesis type GenesisState struct { - Params Params + Params Params + SigningInfos map[string]ValidatorSigningInfo + MissedBlocks map[string][]MissedBlock + SlashingPeriods []ValidatorSlashingPeriod +} + +// MissedBlock +type MissedBlock struct { + Index int64 `json:"index"` + Missed bool `json:"missed"` } // HubDefaultGenesisState - default GenesisState used by Cosmos Hub func DefaultGenesisState() GenesisState { return GenesisState{ - Params: DefaultParams(), + Params: DefaultParams(), + SigningInfos: make(map[string]ValidatorSigningInfo), + MissedBlocks: make(map[string][]MissedBlock), + SlashingPeriods: []ValidatorSlashingPeriod{}, } } @@ -24,5 +36,64 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState, sdata types. keeper.addPubkey(ctx, validator.GetConsPubKey()) } + for addr, info := range data.SigningInfos { + address, err := sdk.ConsAddressFromBech32(addr) + if err != nil { + panic(err) + } + keeper.setValidatorSigningInfo(ctx, address, info) + } + + for addr, array := range data.MissedBlocks { + address, err := sdk.ConsAddressFromBech32(addr) + if err != nil { + panic(err) + } + for _, missed := range array { + keeper.setValidatorMissedBlockBitArray(ctx, address, missed.Index, missed.Missed) + } + } + + for _, slashingPeriod := range data.SlashingPeriods { + keeper.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) + } + keeper.paramspace.SetParamSet(ctx, &data.Params) } + +// ExportGenesis writes the current store values +// to a genesis file, which can be imported again +// with InitGenesis +func ExportGenesis(ctx sdk.Context, keeper Keeper) (data GenesisState) { + var params Params + keeper.paramspace.GetParamSet(ctx, ¶ms) + + signingInfos := make(map[string]ValidatorSigningInfo) + missedBlocks := make(map[string][]MissedBlock) + keeper.iterateValidatorSigningInfos(ctx, func(address sdk.ConsAddress, info ValidatorSigningInfo) (stop bool) { + bechAddr := address.String() + signingInfos[bechAddr] = info + array := []MissedBlock{} + + keeper.iterateValidatorMissedBlockBitArray(ctx, address, func(index int64, missed bool) (stop bool) { + array = append(array, MissedBlock{index, missed}) + return false + }) + missedBlocks[bechAddr] = array + + return false + }) + + slashingPeriods := []ValidatorSlashingPeriod{} + keeper.iterateValidatorSlashingPeriods(ctx, func(slashingPeriod ValidatorSlashingPeriod) (stop bool) { + slashingPeriods = append(slashingPeriods, slashingPeriod) + return false + }) + + return GenesisState{ + Params: params, + SigningInfos: signingInfos, + MissedBlocks: missedBlocks, + SlashingPeriods: slashingPeriods, + } +} diff --git a/x/slashing/hooks.go b/x/slashing/hooks.go index 10c16d199..e09f6c566 100644 --- a/x/slashing/hooks.go +++ b/x/slashing/hooks.go @@ -3,6 +3,8 @@ package slashing import ( "time" + "github.com/tendermint/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -36,6 +38,17 @@ func (k Keeper) onValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddre k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) } +// When a validator is created, add the address-pubkey relation. +func (k Keeper) onValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { + validator := k.validatorSet.Validator(ctx, valAddr) + k.addPubkey(ctx, validator.GetConsPubKey()) +} + +// When a validator is removed, delete the address-pubkey relation. +func (k Keeper) onValidatorRemoved(ctx sdk.Context, address sdk.ConsAddress) { + k.deleteAddrPubkeyRelation(ctx, crypto.Address(address)) +} + //_________________________________________________________________________________________ // Wrapper struct @@ -60,12 +73,20 @@ func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddre h.k.onValidatorBeginUnbonding(ctx, consAddr, valAddr) } +// Implements sdk.ValidatorHooks +func (h Hooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, _ sdk.ValAddress) { + h.k.onValidatorRemoved(ctx, consAddr) +} + +// Implements sdk.ValidatorHooks +func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { + h.k.onValidatorCreated(ctx, valAddr) +} + // nolint - unused hooks func (h Hooks) OnValidatorPowerDidChange(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { } -func (h Hooks) OnValidatorCreated(_ sdk.Context, _ sdk.ValAddress) {} func (h Hooks) OnValidatorModified(_ sdk.Context, _ sdk.ValAddress) {} -func (h Hooks) OnValidatorRemoved(_ sdk.Context, _ sdk.ValAddress) {} func (h Hooks) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} func (h Hooks) OnDelegationRemoved(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {} diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 4a52ddcb6..fe1531f22 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -4,13 +4,10 @@ import ( "fmt" "time" - tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params" stake "github.com/cosmos/cosmos-sdk/x/stake/types" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" ) @@ -174,19 +171,6 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p k.setValidatorSigningInfo(ctx, consAddr, signInfo) } -// AddValidators adds the validators to the keepers validator addr to pubkey mapping. -func (k Keeper) AddValidators(ctx sdk.Context, vals []abci.ValidatorUpdate) { - for i := 0; i < len(vals); i++ { - val := vals[i] - pubkey, err := tmtypes.PB2TM.PubKey(val.PubKey) - if err != nil { - panic(err) - } - k.addPubkey(ctx, pubkey) - } -} - -// TODO: Make a method to remove the pubkey from the map when a validator is unbonded. func (k Keeper) addPubkey(ctx sdk.Context, pubkey crypto.PubKey) { addr := pubkey.Address() k.setAddrPubkeyRelation(ctx, addr, pubkey) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index caf1cf3da..94251ded3 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -34,8 +34,7 @@ func TestHandleDoubleSign(t *testing.T) { operatorAddr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(operatorAddr, val, amt)) require.True(t, got.IsOK()) - validatorUpdates := stake.EndBlocker(ctx, sk) - keeper.AddValidators(ctx, validatorUpdates) + stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(operatorAddr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, operatorAddr).GetPower())) @@ -75,9 +74,8 @@ func TestSlashingPeriodCap(t *testing.T) { valConsPubKey, valConsAddr := pks[0], pks[0].Address() got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(operatorAddr, valConsPubKey, amt)) require.True(t, got.IsOK()) - validatorUpdates := stake.EndBlocker(ctx, sk) + stake.EndBlocker(ctx, sk) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(operatorAddr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, operatorAddr).GetPower())) @@ -141,8 +139,7 @@ func TestHandleAbsentValidator(t *testing.T) { slh := NewHandler(keeper) got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) - validatorUpdates := stake.EndBlocker(ctx, sk) - keeper.AddValidators(ctx, validatorUpdates) + stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) // will exist since the validator has been bonded @@ -298,8 +295,7 @@ func TestHandleNewValidator(t *testing.T) { // Validator created got := sh(ctx, NewTestMsgCreateValidator(addr, val, sdk.NewInt(amt))) require.True(t, got.IsOK()) - validatorUpdates := stake.EndBlocker(ctx, sk) - keeper.AddValidators(ctx, validatorUpdates) + stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}}) require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower()) @@ -333,8 +329,7 @@ func TestHandleAlreadyJailed(t *testing.T) { sh := stake.NewHandler(sk) got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) - validatorUpdates := stake.EndBlocker(ctx, sk) - keeper.AddValidators(ctx, validatorUpdates) + stake.EndBlocker(ctx, sk) // 1000 first blocks OK height := int64(0) @@ -386,8 +381,7 @@ func TestValidatorDippingInAndOut(t *testing.T) { sh := stake.NewHandler(sk) got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) - validatorUpdates := stake.EndBlocker(ctx, sk) - keeper.AddValidators(ctx, validatorUpdates) + stake.EndBlocker(ctx, sk) // 100 first blocks OK height := int64(0) @@ -400,9 +394,8 @@ func TestValidatorDippingInAndOut(t *testing.T) { newAmt := int64(101) got = sh(ctx, NewTestMsgCreateValidator(addrs[1], pks[1], sdk.NewInt(newAmt))) require.True(t, got.IsOK()) - validatorUpdates = stake.EndBlocker(ctx, sk) + validatorUpdates := stake.EndBlocker(ctx, sk) require.Equal(t, 2, len(validatorUpdates)) - keeper.AddValidators(ctx, validatorUpdates) validator, _ := sk.GetValidator(ctx, addr) require.Equal(t, sdk.Unbonding, validator.Status) diff --git a/x/slashing/keys.go b/x/slashing/keys.go index 8f4fecc6c..750e8825f 100644 --- a/x/slashing/keys.go +++ b/x/slashing/keys.go @@ -20,6 +20,15 @@ func GetValidatorSigningInfoKey(v sdk.ConsAddress) []byte { return append(ValidatorSigningInfoKey, v.Bytes()...) } +// extract the address from a validator signing info key +func GetValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) { + addr := key[1:] + if len(addr) != sdk.AddrLen { + panic("unexpected key length") + } + return sdk.ConsAddress(addr) +} + // stored by *Tendermint* address (not operator address) func GetValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte { return append(ValidatorMissedBlockBitArrayKey, v.Bytes()...) diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index 6479be928..77c437174 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -20,6 +20,21 @@ func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress return } +// Stored by *validator* address (not operator address) +func (k Keeper) iterateValidatorSigningInfos(ctx sdk.Context, handler func(address sdk.ConsAddress, info ValidatorSigningInfo) (stop bool)) { + store := ctx.KVStore(k.storeKey) + iter := sdk.KVStorePrefixIterator(store, ValidatorSigningInfoKey) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + address := GetValidatorSigningInfoAddress(iter.Key()) + var info ValidatorSigningInfo + k.cdc.MustUnmarshalBinaryLengthPrefixed(iter.Value(), &info) + if handler(address, info) { + break + } + } +} + // Stored by *validator* address (not operator address) func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress, info ValidatorSigningInfo) { store := ctx.KVStore(k.storeKey) @@ -40,6 +55,24 @@ func (k Keeper) getValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.Con return } +// Stored by *validator* address (not operator address) +func (k Keeper) iterateValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, handler func(index int64, missed bool) (stop bool)) { + store := ctx.KVStore(k.storeKey) + index := int64(0) + // Array may be sparse + for ; index < k.SignedBlocksWindow(ctx); index++ { + var missed bool + bz := store.Get(GetValidatorMissedBlockBitArrayKey(address, index)) + if bz == nil { + continue + } + k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &missed) + if handler(index, missed) { + break + } + } +} + // Stored by *validator* address (not operator address) func (k Keeper) setValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64, missed bool) { store := ctx.KVStore(k.storeKey) diff --git a/x/slashing/slashing_period.go b/x/slashing/slashing_period.go index 026d141a2..4caf5d7c9 100644 --- a/x/slashing/slashing_period.go +++ b/x/slashing/slashing_period.go @@ -51,6 +51,21 @@ func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk return } +// Iterate over all slashing periods in the store, calling on each +// decode slashing period a provided handler function +// Stop if the provided handler function returns true +func (k Keeper) iterateValidatorSlashingPeriods(ctx sdk.Context, handler func(slashingPeriod ValidatorSlashingPeriod) (stop bool)) { + store := ctx.KVStore(k.storeKey) + iter := sdk.KVStorePrefixIterator(store, ValidatorSlashingPeriodKey) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + slashingPeriod := k.unmarshalSlashingPeriodKeyValue(iter.Key(), iter.Value()) + if handler(slashingPeriod) { + break + } + } +} + // Stored by validator Tendermint address (not operator address) // This function sets a validator slashing period for a particular validator, // start height, end height, and current slashed-so-far total, or updates diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 2f1113aa1..239ae13d6 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -91,7 +91,7 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s sk.SetHooks(keeper.Hooks()) require.NotPanics(t, func() { - InitGenesis(ctx, keeper, GenesisState{defaults}, genesis) + InitGenesis(ctx, keeper, GenesisState{defaults, nil, nil, nil}, genesis) }) return ctx, ck, sk, paramstore, keeper diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index a2a2d9f0f..c6590c94e 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -19,8 +19,7 @@ func TestBeginBlocker(t *testing.T) { // bond the validator got := stake.NewHandler(sk)(ctx, NewTestMsgCreateValidator(addr, pk, amt)) require.True(t, got.IsOK()) - validatorUpdates := stake.EndBlocker(ctx, sk) - keeper.AddValidators(ctx, validatorUpdates) + stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 63b038613..d44055ea8 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -2,13 +2,13 @@ package stake import ( "fmt" + "sort" abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" - "github.com/pkg/errors" ) // InitGenesis sets the pool and parameters for the provided keeper and @@ -26,22 +26,33 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ keeper.SetPool(ctx, data.Pool) keeper.SetParams(ctx, data.Params) + keeper.SetIntraTxCounter(ctx, data.IntraTxCounter) + keeper.SetLastTotalPower(ctx, data.LastTotalPower) + + // We only need to set this if we're starting from a list of validators, not a state export + setBondIntraTxCounter := true + for _, validator := range data.Validators { + if validator.BondIntraTxCounter != 0 { + setBondIntraTxCounter = false + } + } for i, validator := range data.Validators { - validator.BondIntraTxCounter = int16(i) // set the intra-tx counter to the order the validators are presented + // set the intra-tx counter to the order the validators are presented, if necessary + if setBondIntraTxCounter { + validator.BondIntraTxCounter = int16(i) + } keeper.SetValidator(ctx, validator) - if validator.Tokens.IsZero() { - return res, errors.Errorf("genesis validator cannot have zero pool shares, validator: %v", validator) - } - if validator.DelegatorShares.IsZero() { - return res, errors.Errorf("genesis validator cannot have zero delegator shares, validator: %v", validator) - } - // Manually set indices for the first time keeper.SetValidatorByConsAddr(ctx, validator) keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool) keeper.OnValidatorCreated(ctx, validator.OperatorAddr) + + // Set timeslice if necessary + if validator.Status == sdk.Unbonding { + keeper.InsertValidatorQueue(ctx, validator) + } } for _, delegation := range data.Bonds { @@ -49,24 +60,56 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ keeper.OnDelegationCreated(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr) } + sort.SliceStable(data.UnbondingDelegations[:], func(i, j int) bool { + return data.UnbondingDelegations[i].CreationHeight < data.UnbondingDelegations[j].CreationHeight + }) + for _, ubd := range data.UnbondingDelegations { + keeper.SetUnbondingDelegation(ctx, ubd) + keeper.InsertUnbondingQueue(ctx, ubd) + } + + sort.SliceStable(data.Redelegations[:], func(i, j int) bool { + return data.Redelegations[i].CreationHeight < data.Redelegations[j].CreationHeight + }) + for _, red := range data.Redelegations { + keeper.SetRedelegation(ctx, red) + keeper.InsertRedelegationQueue(ctx, red) + } + res = keeper.ApplyAndReturnValidatorSetUpdates(ctx) return } -// WriteGenesis returns a GenesisState for a given context and keeper. The +// ExportGenesis returns a GenesisState for a given context and keeper. The // GenesisState will contain the pool, params, validators, and bonds found in // the keeper. -func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { +func ExportGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { pool := keeper.GetPool(ctx) params := keeper.GetParams(ctx) + intraTxCounter := keeper.GetIntraTxCounter(ctx) + lastTotalPower := keeper.GetLastTotalPower(ctx) validators := keeper.GetAllValidators(ctx) bonds := keeper.GetAllDelegations(ctx) + var unbondingDelegations []types.UnbondingDelegation + keeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) (stop bool) { + unbondingDelegations = append(unbondingDelegations, ubd) + return false + }) + var redelegations []types.Redelegation + keeper.IterateRedelegations(ctx, func(_ int64, red types.Redelegation) (stop bool) { + redelegations = append(redelegations, red) + return false + }) return types.GenesisState{ - Pool: pool, - Params: params, - Validators: validators, - Bonds: bonds, + Pool: pool, + Params: params, + IntraTxCounter: intraTxCounter, + LastTotalPower: lastTotalPower, + Validators: validators, + Bonds: bonds, + UnbondingDelegations: unbondingDelegations, + Redelegations: redelegations, } } @@ -118,11 +161,8 @@ func validateGenesisStateValidators(validators []types.Validator) (err error) { if val.Jailed && val.Status == sdk.Bonded { return fmt.Errorf("validator is bonded and jailed in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress()) } - if val.Tokens.IsZero() { - return fmt.Errorf("genesis validator cannot have zero pool shares, validator: %v", val) - } - if val.DelegatorShares.IsZero() { - return fmt.Errorf("genesis validator cannot have zero delegator shares, validator: %v", val) + if val.DelegatorShares.IsZero() && val.Status != sdk.Unbonding { + return fmt.Errorf("bonded/unbonded genesis validator cannot have zero delegator shares, validator: %v", val) } addrMap[strKey] = true } diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index 7ee16a453..3f7295a7a 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -22,29 +22,28 @@ func TestInitGenesis(t *testing.T) { pool.BondedTokens = sdk.NewDec(2) params := keeper.GetParams(ctx) + validators := make([]Validator, 2) var delegations []Delegation - validators := []Validator{ - NewValidator(sdk.ValAddress(keep.Addrs[0]), keep.PKs[0], Description{Moniker: "hoop"}), - NewValidator(sdk.ValAddress(keep.Addrs[1]), keep.PKs[1], Description{Moniker: "bloop"}), - } - genesisState := types.NewGenesisState(pool, params, validators, delegations) - _, err := InitGenesis(ctx, keeper, genesisState) - require.Error(t, err) - // initialize the validators + validators[0].OperatorAddr = sdk.ValAddress(keep.Addrs[0]) + validators[0].ConsPubKey = keep.PKs[0] + validators[0].Description = Description{Moniker: "hoop"} validators[0].Status = sdk.Bonded validators[0].Tokens = sdk.OneDec() validators[0].DelegatorShares = sdk.OneDec() + validators[1].OperatorAddr = sdk.ValAddress(keep.Addrs[1]) + validators[1].ConsPubKey = keep.PKs[1] + validators[1].Description = Description{Moniker: "bloop"} validators[1].Status = sdk.Bonded validators[1].Tokens = sdk.OneDec() validators[1].DelegatorShares = sdk.OneDec() - genesisState = types.NewGenesisState(pool, params, validators, delegations) + genesisState := types.NewGenesisState(pool, params, validators, delegations) vals, err := InitGenesis(ctx, keeper, genesisState) require.NoError(t, err) - actualGenesis := WriteGenesis(ctx, keeper) + actualGenesis := ExportGenesis(ctx, keeper) require.Equal(t, genesisState.Pool, actualGenesis.Pool) require.Equal(t, genesisState.Params, actualGenesis.Params) require.Equal(t, genesisState.Bonds, actualGenesis.Bonds) @@ -126,10 +125,6 @@ func TestValidateGenesis(t *testing.T) { (*data).Validators = genValidators1 (*data).Validators = append((*data).Validators, genValidators1[0]) }, true}, - {"no pool shares", func(data *types.GenesisState) { - (*data).Validators = genValidators1 - (*data).Validators[0].Tokens = sdk.ZeroDec() - }, true}, {"no delegator shares", func(data *types.GenesisState) { (*data).Validators = genValidators1 (*data).Validators[0].DelegatorShares = sdk.ZeroDec() diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index fbb62dcbf..d535419e1 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -283,6 +283,21 @@ func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) } +// iterate through all redelegations +func (k Keeper) IterateRedelegations(ctx sdk.Context, fn func(index int64, red types.Redelegation) (stop bool)) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, RedelegationKey) + defer iterator.Close() + + for i := int64(0); iterator.Valid(); iterator.Next() { + red := types.MustUnmarshalRED(k.cdc, iterator.Key(), iterator.Value()) + if stop := fn(i, red); stop { + break + } + i++ + } +} + // remove a redelegation object and associated index func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) { store := ctx.KVStore(k.storeKey) diff --git a/x/stake/keeper/hooks.go b/x/stake/keeper/hooks.go index 4a8496ddd..74e830490 100644 --- a/x/stake/keeper/hooks.go +++ b/x/stake/keeper/hooks.go @@ -17,9 +17,9 @@ func (k Keeper) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) { } } -func (k Keeper) OnValidatorRemoved(ctx sdk.Context, valAddr sdk.ValAddress) { +func (k Keeper) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { if k.hooks != nil { - k.hooks.OnValidatorRemoved(ctx, valAddr) + k.hooks.OnValidatorRemoved(ctx, consAddr, valAddr) } } diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 307270c16..3f98f08c5 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -191,11 +191,13 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. validator, pool = validator.UpdateStatus(pool, sdk.Bonded) k.SetPool(ctx, pool) - // save the now bonded validator record to the three referenced stores + // save the now bonded validator record to the two referenced stores k.SetValidator(ctx, validator) - k.SetValidatorByPowerIndex(ctx, validator, pool) + // delete from queue if present + k.DeleteValidatorQueue(ctx, validator) + // call the bond hook if present if k.hooks != nil { k.hooks.OnValidatorBonded(ctx, validator.ConsAddress(), validator.OperatorAddr) @@ -224,9 +226,8 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime) validator.UnbondingHeight = ctx.BlockHeader().Height - // save the now unbonded validator record + // save the now unbonded validator record and power index k.SetValidator(ctx, validator) - k.SetValidatorByPowerIndex(ctx, validator, pool) // Adds to unbonding validator queue diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 4646480ac..c7919537c 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -1,6 +1,7 @@ package keeper import ( + "bytes" "container/list" "fmt" "time" @@ -201,6 +202,11 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address()))) store.Delete(GetValidatorsByPowerIndexKey(validator, pool)) + // call hook if present + if k.hooks != nil { + k.hooks.OnValidatorRemoved(ctx, validator.ConsAddress(), validator.OperatorAddr) + } + } //___________________________________________________________________________ @@ -320,6 +326,12 @@ func (k Keeper) SetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time, store.Set(GetValidatorQueueTimeKey(timestamp), bz) } +// Deletes a specific validator queue timeslice. +func (k Keeper) DeleteValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time) { + store := ctx.KVStore(k.storeKey) + store.Delete(GetValidatorQueueTimeKey(timestamp)) +} + // Insert an validator address to the appropriate timeslice in the validator queue func (k Keeper) InsertValidatorQueue(ctx sdk.Context, val types.Validator) { timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime) @@ -331,6 +343,22 @@ func (k Keeper) InsertValidatorQueue(ctx sdk.Context, val types.Validator) { } } +// Delete a validator address from the validator queue +func (k Keeper) DeleteValidatorQueue(ctx sdk.Context, val types.Validator) { + timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime) + newTimeSlice := []sdk.ValAddress{} + for _, addr := range timeSlice { + if !bytes.Equal(addr, val.OperatorAddr) { + newTimeSlice = append(newTimeSlice, addr) + } + } + if len(newTimeSlice) == 0 { + k.DeleteValidatorQueueTimeSlice(ctx, val.UnbondingMinTime) + } else { + k.SetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime, newTimeSlice) + } +} + // Returns all the validator queue timeslices from time 0 until endTime func (k Keeper) ValidatorQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { store := ctx.KVStore(k.storeKey) @@ -358,9 +386,12 @@ func (k Keeper) UnbondAllMatureValidatorQueue(ctx sdk.Context) { k.cdc.MustUnmarshalBinaryLengthPrefixed(validatorTimesliceIterator.Value(), ×lice) for _, valAddr := range timeslice { val, found := k.GetValidator(ctx, valAddr) - if !found || val.GetStatus() != sdk.Unbonding { + if !found { continue } + if val.GetStatus() != sdk.Unbonding { + panic("unexpected validator in unbonding queue, status was not unbonding") + } k.unbondingToUnbonded(ctx, val) if val.GetDelegatorShares().IsZero() { k.RemoveValidator(ctx, val.OperatorAddr) diff --git a/x/stake/stake.go b/x/stake/stake.go index 9d7617722..87087e59c 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -57,6 +57,9 @@ var ( GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey TestingUpdateValidator = keeper.TestingUpdateValidator + UnbondingQueueKey = keeper.UnbondingQueueKey + RedelegationQueueKey = keeper.RedelegationQueueKey + ValidatorQueueKey = keeper.ValidatorQueueKey DefaultParamspace = keeper.DefaultParamspace KeyUnbondingTime = types.KeyUnbondingTime diff --git a/x/stake/types/genesis.go b/x/stake/types/genesis.go index d08c6b899..f1673a376 100644 --- a/x/stake/types/genesis.go +++ b/x/stake/types/genesis.go @@ -1,11 +1,19 @@ package types +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + // GenesisState - all staking state that must be provided at genesis type GenesisState struct { - Pool Pool `json:"pool"` - Params Params `json:"params"` - Validators []Validator `json:"validators"` - Bonds []Delegation `json:"bonds"` + Pool Pool `json:"pool"` + Params Params `json:"params"` + IntraTxCounter int16 `json:"intra_tx_counter"` + LastTotalPower sdk.Int `json:"last_total_power"` + Validators []Validator `json:"validators"` + Bonds []Delegation `json:"bonds"` + UnbondingDelegations []UnbondingDelegation `json:"unbonding_delegations"` + Redelegations []Redelegation `json:"redelegations"` } func NewGenesisState(pool Pool, params Params, validators []Validator, bonds []Delegation) GenesisState { From 02da39789923c948a4b91b34dda275d46381cc90 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 9 Nov 2018 01:41:57 +0100 Subject: [PATCH 19/33] Merge 0.26.0 back to develop (#2718) * PENDING => CHANGELOG * Linkify changelog * Merge PR #2716: Temporarily disable gaia lite insecure mode * TODO: need to update CHANGELOG w/ import-export PR #2690 --- CHANGELOG.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++ PENDING.md | 24 +------------------- client/lcd/root.go | 37 ++++++++++++++++++++++--------- 3 files changed, 83 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16e01163c..8be464b40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,60 @@ # Changelog +## 0.26.0 + +BREAKING CHANGES + +* Gaia + * [gaiad init] [\#2602](https://github.com/cosmos/cosmos-sdk/issues/2602) New genesis workflow + +* SDK + * [simulation] [\#2665](https://github.com/cosmos/cosmos-sdk/issues/2665) only argument to simulation.Invariant is now app + +* Tendermint + * Upgrade to version 0.26.0 + +FEATURES + +* Gaia CLI (`gaiacli`) + * [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations + * [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations + * [cli] [\#2524](https://github.com/cosmos/cosmos-sdk/issues/2524) Add support offline mode to `gaiacli tx sign`. Lookups are not performed if the flag `--offline` is on. + * [cli] [\#2558](https://github.com/cosmos/cosmos-sdk/issues/2558) Rename --print-sigs to --validate-signatures. It now performs a complete set of sanity checks and reports to the user. Also added --print-signature-only to print the signature only, not the whole transaction. + +* SDK + * [\#1336](https://github.com/cosmos/cosmos-sdk/issues/1336) Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes. + +IMPROVEMENTS + +* Gaia + * [\#2637](https://github.com/cosmos/cosmos-sdk/issues/2637) [x/gov] Switched inactive and active proposal queues to an iterator based queue + +* SDK + * [\#2573](https://github.com/cosmos/cosmos-sdk/issues/2573) [x/distribution] add accum invariance + * [\#2556](https://github.com/cosmos/cosmos-sdk/issues/2556) [x/mock/simulation] Fix debugging output + * [\#2396](https://github.com/cosmos/cosmos-sdk/issues/2396) [x/mock/simulation] Change parameters to get more slashes + * [\#2617](https://github.com/cosmos/cosmos-sdk/issues/2617) [x/mock/simulation] Randomize all genesis parameters + * [\#2669](https://github.com/cosmos/cosmos-sdk/issues/2669) [x/stake] Added invarant check to make sure validator's power aligns with its spot in the power store. + * [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) [x/mock/simulation] Use a transition matrix for block size + * [\#2660](https://github.com/cosmos/cosmos-sdk/issues/2660) [x/mock/simulation] Staking transactions get tested far more frequently + * [\#2610](https://github.com/cosmos/cosmos-sdk/issues/2610) [x/stake] Block redelegation to and from the same validator + * [\#2652](https://github.com/cosmos/cosmos-sdk/issues/2652) [x/auth] Add benchmark for get and set account + * [\#2685](https://github.com/cosmos/cosmos-sdk/issues/2685) [store] Add general merkle absence proof (also for empty substores) + * [\#2708](https://github.com/cosmos/cosmos-sdk/issues/2708) [store] Disallow setting nil values + +BUG FIXES + +* Gaia + * [\#2670](https://github.com/cosmos/cosmos-sdk/issues/2670) [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators` + * [\#2691](https://github.com/cosmos/cosmos-sdk/issues/2691) Fix local testnet creation by using a single canonical genesis time + +* SDK + * [\#2625](https://github.com/cosmos/cosmos-sdk/issues/2625) [x/gov] fix AppendTag function usage error + * [\#2677](https://github.com/cosmos/cosmos-sdk/issues/2677) [x/stake, x/distribution] various staking/distribution fixes as found by the simulator + * [\#2674](https://github.com/cosmos/cosmos-sdk/issues/2674) [types] Fix coin.IsLT() impl, coins.IsLT() impl, and renamed coins.Is\* to coins.IsAll\* (see [\#2686](https://github.com/cosmos/cosmos-sdk/issues/2686)) + * [\#2711](https://github.com/cosmos/cosmos-sdk/issues/2711) [x/stake] Add commission data to `MsgCreateValidator` signature bytes. + * Temporarily disable insecure mode for Gaia Lite + ## 0.25.0 *October 24th, 2018* diff --git a/PENDING.md b/PENDING.md index 1d5752fc2..0b56d5333 100644 --- a/PENDING.md +++ b/PENDING.md @@ -7,23 +7,17 @@ BREAKING CHANGES * Gaia CLI (`gaiacli`) * Gaia - * [gaiad init] \#2602 New genesis workflow * SDK - * [simulation] \#2665 only argument to simulation.Invariant is now app * Tendermint - * Upgrade to version 0.26.0 + FEATURES * Gaia REST API (`gaiacli advanced rest-server`) * Gaia CLI (`gaiacli`) - * [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations - * [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations - * [cli] [\#2524](https://github.com/cosmos/cosmos-sdk/issues/2524) Add support offline mode to `gaiacli tx sign`. Lookups are not performed if the flag `--offline` is on. - * [cli] [\#2558](https://github.com/cosmos/cosmos-sdk/issues/2558) Rename --print-sigs to --validate-signatures. It now performs a complete set of sanity checks and reports to the user. Also added --print-signature-only to print the signature only, not the whole transaction. * Gaia @@ -40,20 +34,8 @@ IMPROVEMENTS * Gaia CLI (`gaiacli`) * Gaia - - #2637 [x/gov] Switched inactive and active proposal queues to an iterator based queue * 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 - - \#2652 [x/auth] Add benchmark for get and set account - - \#2685 [store] Add general merkle absence proof (also for empty substores) - - \#2708 [store] Disallow setting nil values * Tendermint @@ -70,9 +52,5 @@ BUG FIXES - \#2691 Fix local testnet creation by using a single canonical genesis time * SDK - - \#2625 [x/gov] fix AppendTag function usage error - - \#2677 [x/stake, x/distribution] various staking/distribution fixes as found by the simulator - - \#2674 [types] Fix coin.IsLT() impl, coins.IsLT() impl, and renamed coins.Is\* to coins.IsAll\* (see \#2686) - - \#2711 [x/stake] Add commission data to `MsgCreateValidator` signature bytes. * Tendermint diff --git a/client/lcd/root.go b/client/lcd/root.go index c6e7917e7..8366b6114 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -2,6 +2,11 @@ package lcd import ( "errors" + "fmt" + "net" + "net/http" + "os" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/keys" @@ -20,9 +25,6 @@ import ( "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/log" tmserver "github.com/tendermint/tendermint/rpc/lib/server" - "net" - "net/http" - "os" ) const ( @@ -46,7 +48,9 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) (err error) { listenAddr := viper.GetString(flagListenAddr) handler := createHandler(cdc) + registerSwaggerUI(handler) + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server") maxOpen := viper.GetInt(flagMaxOpenConnections) sslHosts := viper.GetString(flagSSLHosts) @@ -62,14 +66,20 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command { }) var cleanupFunc func() + + // TODO: re-enable insecure mode once #2715 has been addressed if viper.GetBool(flagInsecure) { - listener, err = tmserver.StartHTTPServer( - listenAddr, handler, logger, - tmserver.Config{MaxOpenConnections: maxOpen}, + fmt.Println( + "Insecure mode is temporarily disabled, please locally generate an " + + "SSL certificate to test. Support will be re-enabled soon!", ) - if err != nil { - return - } + // listener, err = tmserver.StartHTTPServer( + // listenAddr, handler, logger, + // tmserver.Config{MaxOpenConnections: maxOpen}, + // ) + // if err != nil { + // return + // } } else { if certFile != "" { // validateCertKeyFiles() is needed to work around tendermint/tendermint#2460 @@ -77,6 +87,7 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command { if err != nil { return err } + // cert/key pair is provided, read the fingerprint fingerprint, err = fingerprintFromFile(certFile) if err != nil { @@ -88,10 +99,12 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command { if err != nil { return err } + cleanupFunc = func() { os.Remove(certFile) os.Remove(keyFile) } + defer cleanupFunc() } @@ -104,9 +117,12 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command { if err != nil { return } + logger.Info(fingerprint) + logger.Info("REST server started") } - logger.Info("REST server started") + + // logger.Info("REST server started") return nil }, @@ -123,6 +139,7 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command { cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections") cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)") cmd.Flags().Bool(client.FlagIndentResponse, false, "Add indent to JSON response") + viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode)) viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID)) viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode)) From d8b6d1d1062877ec2edd2237bf07b360d5cbc9e5 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Thu, 8 Nov 2018 16:45:44 -0800 Subject: [PATCH 20/33] Update CHANGELOG/PENDING for straggling PR #2690 --- CHANGELOG.md | 2 ++ PENDING.md | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8be464b40..f635b7ea6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ BUG FIXES * Gaia * [\#2670](https://github.com/cosmos/cosmos-sdk/issues/2670) [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators` * [\#2691](https://github.com/cosmos/cosmos-sdk/issues/2691) Fix local testnet creation by using a single canonical genesis time + - [\#2670](https://github.com/cosmos/cosmos-sdk/issues/2670) [x/stake] fixed incorrent `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators` + - [\#2648](https://github.com/cosmos/cosmos-sdk/issues/2648) [gaiad] Fix `gaiad export` / `gaiad import` consistency, test in CI * SDK * [\#2625](https://github.com/cosmos/cosmos-sdk/issues/2625) [x/gov] fix AppendTag function usage error diff --git a/PENDING.md b/PENDING.md index 0b56d5333..4d87301f0 100644 --- a/PENDING.md +++ b/PENDING.md @@ -22,7 +22,6 @@ FEATURES * Gaia * SDK - - \#1336 Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes. * Tendermint @@ -47,9 +46,6 @@ BUG FIXES * Gaia CLI (`gaiacli`) * Gaia - - \#2670 [x/stake] fixed incorrent `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators` - - \#2648 [gaiad] Fix `gaiad export` / `gaiad import` consistency, test in CI - - \#2691 Fix local testnet creation by using a single canonical genesis time * SDK From 4f6f8e09ae19b8cd314dbb9e8d1a15cd30c50179 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Tue, 6 Nov 2018 09:08:26 +0000 Subject: [PATCH 21/33] Add small utility to add account to genesis.json after gaiad init --- cmd/gaia/cmd/gaiad/main.go | 1 + cmd/gaia/init/genesis_accts.go | 65 ++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 cmd/gaia/init/genesis_accts.go diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index ae076571b..ef7b39d11 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -42,6 +42,7 @@ func main() { rootCmd.AddCommand(gaiaInit.CollectGenTxsCmd(ctx, cdc)) rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, server.AppInit{})) rootCmd.AddCommand(gaiaInit.GenTxCmd(ctx, cdc)) + rootCmd.AddCommand(gaiaInit.AddGenesisAccountCmd(ctx, cdc)) server.AddCommands(ctx, cdc, rootCmd, appInit, newApp, exportAppStateAndTMValidators) diff --git a/cmd/gaia/init/genesis_accts.go b/cmd/gaia/init/genesis_accts.go new file mode 100644 index 000000000..af260d9d6 --- /dev/null +++ b/cmd/gaia/init/genesis_accts.go @@ -0,0 +1,65 @@ +package init + +import ( + "fmt" + "github.com/cosmos/cosmos-sdk/cmd/gaia/app" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/server" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/cli" + "github.com/tendermint/tendermint/libs/common" +) + +// AddGenesisAccountCmd returns add-genesis-account cobra Command +func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "add-genesis-account [address] [coin][,[coin]]", + Short: "Add genesis account to genesis.json", + Args: cobra.ExactArgs(2), + RunE: func(_ *cobra.Command, args []string) error { + config := ctx.Config + config.SetRoot(viper.GetString(cli.HomeFlag)) + + addr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + coins, err := sdk.ParseCoins(args[1]) + if err != nil { + return err + } + coins.Sort() + + genFile := config.GenesisFile() + if !common.FileExists(genFile) { + return fmt.Errorf("%s does not exist, run `gaiad init` first", genFile) + } + genDoc, err := loadGenesisDoc(cdc, genFile) + if err != nil { + return err + } + + var appState app.GenesisState + if err = cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil { + return err + } + + acc := auth.NewBaseAccountWithAddress(addr) + acc.Coins = coins + appState.Accounts = append(appState.Accounts, app.NewGenesisAccount(&acc)) + + appStateJSON, err := cdc.MarshalJSON(appState) + if err != nil { + return err + } + + return WriteGenesisFile(genFile, genDoc.ChainID, nil, appStateJSON) + }, + } + + cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory") + return cmd +} From 194691f052aa7acee802c20e99302f391a4638ac Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 9 Nov 2018 10:53:40 +0000 Subject: [PATCH 22/33] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f635b7ea6..45a9eb66c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ FEATURES * [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations * [cli] [\#2524](https://github.com/cosmos/cosmos-sdk/issues/2524) Add support offline mode to `gaiacli tx sign`. Lookups are not performed if the flag `--offline` is on. * [cli] [\#2558](https://github.com/cosmos/cosmos-sdk/issues/2558) Rename --print-sigs to --validate-signatures. It now performs a complete set of sanity checks and reports to the user. Also added --print-signature-only to print the signature only, not the whole transaction. + * [cli] [\#2704](https://github.com/cosmos/cosmos-sdk/pull/2704) New add-genesis-account convenience command to populate genesis.json with genesis accounts. * SDK * [\#1336](https://github.com/cosmos/cosmos-sdk/issues/1336) Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes. From 8a7c4900f44f370f04a564aefc62d53165ca61ef Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 9 Nov 2018 10:59:11 +0000 Subject: [PATCH 23/33] s/WriteGenesisFile/ExportGenesisFile/ --- cmd/gaia/init/genesis_accts.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/gaia/init/genesis_accts.go b/cmd/gaia/init/genesis_accts.go index af260d9d6..3d43712fc 100644 --- a/cmd/gaia/init/genesis_accts.go +++ b/cmd/gaia/init/genesis_accts.go @@ -2,6 +2,7 @@ package init import ( "fmt" + "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server" @@ -56,7 +57,7 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command return err } - return WriteGenesisFile(genFile, genDoc.ChainID, nil, appStateJSON) + return ExportGenesisFile(genFile, genDoc.ChainID, nil, appStateJSON) }, } From 201abfec8c5c777343edb52ed901f0adc9ae9856 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 9 Nov 2018 15:25:14 +0000 Subject: [PATCH 24/33] Add --chain-id to testnet command --- cmd/gaia/init/testnet.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd/gaia/init/testnet.go b/cmd/gaia/init/testnet.go index 8bada583e..8ca274f78 100644 --- a/cmd/gaia/init/testnet.go +++ b/cmd/gaia/init/testnet.go @@ -75,14 +75,20 @@ Example: cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)") + cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") + return cmd } func initTestnet(config *cfg.Config, cdc *codec.Codec) error { + var chainID string outDir := viper.GetString(flagOutputDir) numValidators := viper.GetInt(flagNumValidators) - chainID := "chain-" + cmn.RandStr(6) + chainID = viper.GetString(client.FlagChainID) + if chainID == "" { + chainID = "chain-" + cmn.RandStr(6) + } monikers := make([]string, numValidators) nodeIDs := make([]string, numValidators) From fc56dd011eb42ba6da66a5abdaebf109d588884b Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 9 Nov 2018 15:27:28 +0000 Subject: [PATCH 25/33] Update PENDING.md --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index 4d87301f0..2de586cfb 100644 --- a/PENDING.md +++ b/PENDING.md @@ -31,6 +31,7 @@ IMPROVEMENTS * Gaia REST API (`gaiacli advanced rest-server`) * Gaia CLI (`gaiacli`) + * [\#2749](https://github.com/cosmos/cosmos-sdk/pull/2749) Add --chain-id flag to gaiad testnet * Gaia From b1ba6a44552273605fa77edb84a4ee033751de97 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 9 Nov 2018 10:31:56 -0500 Subject: [PATCH 26/33] add back in PeriodicInvariant --- x/mock/simulation/util.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/x/mock/simulation/util.go b/x/mock/simulation/util.go index f10364aaa..df2b6dae4 100644 --- a/x/mock/simulation/util.go +++ b/x/mock/simulation/util.go @@ -7,6 +7,8 @@ import ( "strings" "testing" "time" + + "github.com/cosmos/cosmos-sdk/baseapp" ) func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B) { @@ -102,3 +104,19 @@ func getBlockSize(r *rand.Rand, params Params, } return state, blocksize } + +// PeriodicInvariant returns an Invariant function closure that asserts a given +// invariant if the mock application's last block modulo the given period is +// congruent to the given offset. +// +// NOTE this function is intended to be used manually used while running +// computationally heavy simulations. +// TODO reference this function in the codebase probably through use of a switch +func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant { + return func(app *baseapp.BaseApp) error { + if int(app.LastBlockHeight())%period == offset { + return invariant(app) + } + return nil + } +} From 61fd142b9e43a364bc05ee28abb92a41b0edefd0 Mon Sep 17 00:00:00 2001 From: Hendrik Hofstadt Date: Sat, 10 Nov 2018 01:08:35 +0100 Subject: [PATCH 27/33] Fix TimeoutCommit (#2743) * Fix TimeoutCommit to 5 seconds instead of whatever it was before which was too short. --- PENDING.md | 3 ++- server/util.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/PENDING.md b/PENDING.md index 2e93ddea5..1c782aa4f 100644 --- a/PENDING.md +++ b/PENDING.md @@ -48,7 +48,8 @@ BUG FIXES * Gaia CLI (`gaiacli`) * Gaia - + * [\#2742](https://github.com/cosmos/cosmos-sdk/issues/2742) Fix time format of TimeoutCommit override + * SDK * Tendermint diff --git a/server/util.go b/server/util.go index 51f10c765..633ad8870 100644 --- a/server/util.go +++ b/server/util.go @@ -7,6 +7,7 @@ import ( "os/signal" "path/filepath" "syscall" + "time" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -92,7 +93,7 @@ func interceptLoadConfig() (conf *cfg.Config, err error) { conf.P2P.RecvRate = 5120000 conf.P2P.SendRate = 5120000 conf.TxIndex.IndexAllTags = true - conf.Consensus.TimeoutCommit = 5000 + conf.Consensus.TimeoutCommit = 5 * time.Second cfg.WriteConfigFile(configFilePath, conf) // Fall through, just so that its parsed into memory. } From e66a39c898384b524e31742303a6d1f8e816929d Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Fri, 9 Nov 2018 16:11:58 -0800 Subject: [PATCH 28/33] Gaia-9000: Update to TM 0.26.1-rc2 (#2753) * Update to tm 0.26.1-rc2 to fix prometheus issue and node disconnect issue. --- Gopkg.lock | 11 ++++++----- Gopkg.toml | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 8dd4be708..04067bdfc 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -165,12 +165,13 @@ version = "v1.2.0" [[projects]] - digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8" + digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10" name = "github.com/hashicorp/hcl" packages = [ ".", "hcl/ast", "hcl/parser", + "hcl/printer", "hcl/scanner", "hcl/strconv", "hcl/token", @@ -298,7 +299,7 @@ "model", ] pruneopts = "UT" - revision = "7e9e6cabbd393fc208072eedef99188d0ce788b6" + revision = "0b1957f9d949dfa3084171a6ec5642b38055276a" [[projects]] branch = "master" @@ -434,7 +435,7 @@ version = "v0.11.1" [[projects]] - digest = "1:395820b381043b9d2204e181ddf0f9147397c4a7b8f5dc3162de4cfcddf4589a" + digest = "1:fc6b632a318f32a77b2bd4c60c6c9276ce82256a4bb0b67b4c8bebac4d367622" name = "github.com/tendermint/tendermint" packages = [ "abci/client", @@ -500,8 +501,8 @@ "version", ] pruneopts = "UT" - revision = "03e42d2e3866f01a00625f608e3bbfaeb30690de" - version = "v0.26.1-rc0" + revision = "58574b7372cc9dd224ef04aaa438578f72e69a77" + version = "v0.26.1-rc2" [[projects]] digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666" diff --git a/Gopkg.toml b/Gopkg.toml index 572600885..1d120f940 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -36,7 +36,7 @@ [[override]] name = "github.com/tendermint/tendermint" - version = "v0.26.1-rc0" # TODO replace w/ 0.26.1 + version = "v0.26.1-rc2" # TODO replace w/ 0.26.1 ## deps without releases: From bb54a0de127e45713f272217f578c0abe53a5b21 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Fri, 9 Nov 2018 19:39:22 -0800 Subject: [PATCH 29/33] Gaia-9000: Update to TM 0.26.1-rc3 -- pex SeedMode fix --- Gopkg.lock | 9 ++++----- Gopkg.toml | 2 +- PENDING.md | 1 + 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 04067bdfc..9289fd24b 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -165,13 +165,12 @@ version = "v1.2.0" [[projects]] - digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10" + digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8" name = "github.com/hashicorp/hcl" packages = [ ".", "hcl/ast", "hcl/parser", - "hcl/printer", "hcl/scanner", "hcl/strconv", "hcl/token", @@ -435,7 +434,7 @@ version = "v0.11.1" [[projects]] - digest = "1:fc6b632a318f32a77b2bd4c60c6c9276ce82256a4bb0b67b4c8bebac4d367622" + digest = "1:5b1373b03f39e6f6061cd91f3829100527ebb5f94240c092bf9e5d314b153501" name = "github.com/tendermint/tendermint" packages = [ "abci/client", @@ -501,8 +500,8 @@ "version", ] pruneopts = "UT" - revision = "58574b7372cc9dd224ef04aaa438578f72e69a77" - version = "v0.26.1-rc2" + revision = "48ab899923c564bbf2fa2f1244c11cb930e28132" + version = "v0.26.1-rc3" [[projects]] digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666" diff --git a/Gopkg.toml b/Gopkg.toml index 1d120f940..466fd373f 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -36,7 +36,7 @@ [[override]] name = "github.com/tendermint/tendermint" - version = "v0.26.1-rc2" # TODO replace w/ 0.26.1 + version = "v0.26.1-rc3" # TODO replace w/ 0.26.1 ## deps without releases: diff --git a/PENDING.md b/PENDING.md index 1c782aa4f..f3eea2002 100644 --- a/PENDING.md +++ b/PENDING.md @@ -53,3 +53,4 @@ BUG FIXES * SDK * Tendermint + * [\#2797](https://github.com/tendermint/tendermint/pull/2797) AddressBook requires addresses to have IDs; Do not crap out immediately after sending pex addrs in seed mode From 811b863677e0944dfad8a6b187cbab9d131c6e95 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Mon, 12 Nov 2018 02:34:50 -0500 Subject: [PATCH 30/33] Use correct Bech32 prefix for show-address command (#2746) * Use consensus address bech32 prefix * Update show-address CLI description --- PENDING.md | 1 + server/tm_cmds.go | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/PENDING.md b/PENDING.md index f3eea2002..1ff6e3ee1 100644 --- a/PENDING.md +++ b/PENDING.md @@ -48,6 +48,7 @@ BUG FIXES * Gaia CLI (`gaiacli`) * Gaia + * [\#2723] Use `cosmosvalcons` Bech32 prefix in `tendermint show-address` * [\#2742](https://github.com/cosmos/cosmos-sdk/issues/2742) Fix time format of TimeoutCommit override * SDK diff --git a/server/tm_cmds.go b/server/tm_cmds.go index 82652bdec..5aeacf92f 100644 --- a/server/tm_cmds.go +++ b/server/tm_cmds.go @@ -63,17 +63,17 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command { func ShowAddressCmd(ctx *Context) *cobra.Command { cmd := &cobra.Command{ Use: "show-address", - Short: "Shows this node's tendermint validator address", + Short: "Shows this node's tendermint validator consensus address", RunE: func(cmd *cobra.Command, args []string) error { cfg := ctx.Config privValidator := pvm.LoadOrGenFilePV(cfg.PrivValidatorFile()) - valAddr := (sdk.ValAddress)(privValidator.Address) + valConsAddr := (sdk.ConsAddress)(privValidator.Address) if viper.GetBool(client.FlagJson) { - return printlnJSON(valAddr) + return printlnJSON(valConsAddr) } - fmt.Println(valAddr.String()) + fmt.Println(valConsAddr.String()) return nil }, } From 2d38a96a6db5d9a90a63b1328012b33e40560b07 Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Mon, 12 Nov 2018 09:44:45 -0800 Subject: [PATCH 31/33] Fix date to be cross platform --- scripts/multisim.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/multisim.sh b/scripts/multisim.sh index ff5784e4b..2376eb3a8 100755 --- a/scripts/multisim.sh +++ b/scripts/multisim.sh @@ -17,7 +17,7 @@ echo "Using temporary log directory: $tmpdir" sim() { seed=$1 echo "Running full Gaia simulation with seed $seed. This may take awhile!" - file="$tmpdir/gaia-simulation-seed-$seed-date-$(date -Iseconds -u).stdout" + file="$tmpdir/gaia-simulation-seed-$seed-date-$(date -u +"%Y-%m-%dT%H:%M:%S+00:00").stdout" echo "Writing stdout to $file..." go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=$blocks \ -SimulationVerbose=true -SimulationCommit=true -SimulationSeed=$seed -v -timeout 24h > $file From 70826495b88df7a9a687bd766e6efe79ff3cc644 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Mon, 12 Nov 2018 18:54:18 +0000 Subject: [PATCH 32/33] Merge PR #2752: Don't hardcode bondable denom --- PENDING.md | 1 + client/lcd/lcd_test.go | 29 +++--- client/lcd/test_helpers.go | 7 +- cmd/gaia/app/genesis.go | 9 +- cmd/gaia/app/sim_test.go | 9 +- cmd/gaia/cli_test/cli_test.go | 91 ++++++++++--------- cmd/gaia/init/gentx.go | 3 +- cmd/gaia/init/testnet.go | 5 +- examples/democoin/x/simplestake/keeper.go | 2 +- .../democoin/x/simplestake/keeper_test.go | 4 +- types/coin_test.go | 8 +- types/utils_test.go | 4 +- x/auth/client/txbuilder/txbuilder_test.go | 5 +- x/gov/endblocker_test.go | 15 +-- x/gov/genesis.go | 3 +- x/gov/keeper_test.go | 9 +- x/gov/msgs_test.go | 19 ++-- x/gov/simulation/msgs.go | 3 +- x/gov/tally_test.go | 25 ++--- x/gov/test_common.go | 3 +- x/mint/params.go | 3 +- x/slashing/app_test.go | 12 ++- x/slashing/test_common.go | 5 +- x/stake/app_test.go | 10 +- x/stake/keeper/delegation_test.go | 4 +- x/stake/querier/queryable_test.go | 4 +- x/stake/simulation/invariants.go | 13 +-- x/stake/test_common.go | 8 +- x/stake/types/msg_test.go | 6 +- x/stake/types/params.go | 5 +- 30 files changed, 178 insertions(+), 146 deletions(-) diff --git a/PENDING.md b/PENDING.md index 1ff6e3ee1..48d5fe0e1 100644 --- a/PENDING.md +++ b/PENDING.md @@ -9,6 +9,7 @@ BREAKING CHANGES * Gaia * SDK + * [\#2752](https://github.com/cosmos/cosmos-sdk/pull/2752) Don't hardcode bondable denom. * Tendermint diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 92167346d..9b042832b 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -31,6 +31,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) func init() { @@ -265,7 +266,7 @@ func TestCoinSend(t *testing.T) { coins := acc.GetCoins() mycoins := coins[0] - require.Equal(t, "steak", mycoins.Denom) + require.Equal(t, stakeTypes.DefaultBondDenom, mycoins.Denom) require.Equal(t, initialBalance[0].Amount.SubRaw(1), mycoins.Amount) // query receiver @@ -273,7 +274,7 @@ func TestCoinSend(t *testing.T) { coins = acc.GetCoins() mycoins = coins[0] - require.Equal(t, "steak", mycoins.Denom) + require.Equal(t, stakeTypes.DefaultBondDenom, mycoins.Denom) require.Equal(t, int64(1), mycoins.Amount.Int64()) // test failure with too little gas @@ -326,7 +327,7 @@ func DisabledTestIBCTransfer(t *testing.T) { coins := acc.GetCoins() mycoins := coins[0] - require.Equal(t, "steak", mycoins.Denom) + require.Equal(t, stakeTypes.DefaultBondDenom, mycoins.Denom) require.Equal(t, initialBalance[0].Amount.SubRaw(1), mycoins.Amount) // TODO: query ibc egress packet state @@ -514,7 +515,7 @@ func TestValidatorQuery(t *testing.T) { } func TestBonding(t *testing.T) { - name, password, denom := "test", "1234567890", "steak" + name, password, denom := "test", "1234567890", stakeTypes.DefaultBondDenom addr, seed := CreateAddr(t, name, password, GetKeyBase(t)) cleanup, valPubKeys, operAddrs, port := InitializeTestLCD(t, 2, []sdk.AccAddress{addr}) @@ -564,7 +565,7 @@ func TestBonding(t *testing.T) { // sender should have not received any coins as the unbonding has only just begun acc = getAccount(t, port, addr) coins = acc.GetCoins() - require.Equal(t, int64(40), coins.AmountOf("steak").Int64()) + require.Equal(t, int64(40), coins.AmountOf(stakeTypes.DefaultBondDenom).Int64()) unbonding := getUndelegation(t, port, addr, operAddrs[0]) require.Equal(t, "30", unbonding.Balance.Amount.String()) @@ -663,11 +664,11 @@ func TestDeposit(t *testing.T) { // query proposal proposal = getProposal(t, port, proposalID) - require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{sdk.NewInt64Coin("steak", 10)})) + require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)})) // query deposit deposit := getDeposit(t, port, proposalID, addr) - require.True(t, deposit.Amount.IsEqual(sdk.Coins{sdk.NewInt64Coin("steak", 10)})) + require.True(t, deposit.Amount.IsEqual(sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)})) } func TestVote(t *testing.T) { @@ -861,7 +862,7 @@ func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.Acc sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) // send - coinbz, err := cdc.MarshalJSON(sdk.NewInt64Coin("steak", 1)) + coinbz, err := cdc.MarshalJSON(sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 1)) if err != nil { panic(err) } @@ -947,7 +948,7 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Acc "account_number":"%d", "sequence":"%d" } - }`, "steak", name, password, chainID, accnum, sequence)) + }`, stakeTypes.DefaultBondDenom, name, password, chainID, accnum, sequence)) res, body := Request(t, port, "POST", fmt.Sprintf("/ibc/testchain/%s/send", receiveAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -1096,7 +1097,7 @@ func doDelegate(t *testing.T, port, seed, name, password string, "account_number":"%d", "sequence":"%d" } - }`, delAddr, valAddr, "steak", amount, name, password, chainID, accnum, sequence)) + }`, delAddr, valAddr, stakeTypes.DefaultBondDenom, amount, name, password, chainID, accnum, sequence)) res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -1339,7 +1340,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA "description": "test", "proposal_type": "Text", "proposer": "%s", - "initial_deposit": [{ "denom": "steak", "amount": "%d" }], + "initial_deposit": [{ "denom": "%s", "amount": "%d" }], "base_req": { "name": "%s", "password": "%s", @@ -1347,7 +1348,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA "account_number":"%d", "sequence":"%d" } - }`, proposerAddr, amount, name, password, chainID, accnum, sequence)) + }`, proposerAddr, stakeTypes.DefaultBondDenom, amount, name, password, chainID, accnum, sequence)) res, body := Request(t, port, "POST", "/gov/proposals", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -1369,7 +1370,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk // deposit on proposal jsonStr := []byte(fmt.Sprintf(`{ "depositer": "%s", - "amount": [{ "denom": "steak", "amount": "%d" }], + "amount": [{ "denom": "%s", "amount": "%d" }], "base_req": { "name": "%s", "password": "%s", @@ -1377,7 +1378,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk "account_number":"%d", "sequence": "%d" } - }`, proposerAddr, amount, name, password, chainID, accnum, sequence)) + }`, proposerAddr, stakeTypes.DefaultBondDenom, amount, name, password, chainID, accnum, sequence)) res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 39c76865c..283550a16 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "github.com/cosmos/cosmos-sdk/x/stake" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/tendermint/tendermint/crypto/secp256k1" "io/ioutil" "net" @@ -227,7 +228,7 @@ func InitializeTestLCD( msg := stake.NewMsgCreateValidator( sdk.ValAddress(operAddr), pubKey, - sdk.NewCoin("steak", sdk.NewInt(int64(delegation))), + sdk.NewCoin(stakeTypes.DefaultBondDenom, sdk.NewInt(int64(delegation))), stake.Description{Moniker: fmt.Sprintf("validator-%d", i+1)}, stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), ) @@ -245,7 +246,7 @@ func InitializeTestLCD( valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr)) accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(operAddr)) - accAuth.Coins = sdk.Coins{sdk.NewInt64Coin("steak", 150)} + accAuth.Coins = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 150)} accs = append(accs, gapp.NewGenesisAccount(&accAuth)) } @@ -259,7 +260,7 @@ func InitializeTestLCD( // add some tokens to init accounts for _, addr := range initAddrs { accAuth := auth.NewBaseAccountWithAddress(addr) - accAuth.Coins = sdk.Coins{sdk.NewInt64Coin("steak", 100)} + accAuth.Coins = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 100)} acc := gapp.NewGenesisAccount(&accAuth) genesisState.Accounts = append(genesisState.Accounts, acc) genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100)) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 38256e415..e3c869ada 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -19,6 +19,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" tmtypes "github.com/tendermint/tendermint/types" ) @@ -26,7 +27,7 @@ var ( // bonded tokens given to genesis validators/accounts freeFermionVal = int64(100) freeFermionsAcc = sdk.NewInt(150) - bondDenom = "steak" + bondDenom = stakeTypes.DefaultBondDenom ) // State to Unmarshal @@ -286,9 +287,11 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount { accAuth := auth.NewBaseAccountWithAddress(addr) - accAuth.Coins = []sdk.Coin{ + coins :=sdk.Coins{ {"fooToken", sdk.NewInt(1000)}, - {"steak", freeFermionsAcc}, + {bondDenom, freeFermionsAcc}, } + coins.Sort() + accAuth.Coins = coins return NewGenesisAccount(&accAuth) } diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 60befcc38..e56344554 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -29,6 +29,7 @@ import ( slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation" stake "github.com/cosmos/cosmos-sdk/x/stake" stakesim "github.com/cosmos/cosmos-sdk/x/stake/simulation" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) var ( @@ -62,7 +63,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage { // Randomly generate some genesis accounts for _, acc := range accs { - coins := sdk.Coins{sdk.Coin{"steak", sdk.NewInt(amount)}} + coins := sdk.Coins{sdk.Coin{stakeTypes.DefaultBondDenom, sdk.NewInt(amount)}} genesisAccounts = append(genesisAccounts, GenesisAccount{ Address: acc.Address, Coins: coins, @@ -73,7 +74,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage { govGenesis := gov.GenesisState{ StartingProposalID: uint64(r.Intn(100)), DepositParams: gov.DepositParams{ - MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", int64(r.Intn(1e3)))}, + MinDeposit: sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, int64(r.Intn(1e3)))}, MaxDepositPeriod: time.Duration(r.Intn(2*172800)) * time.Second, }, VotingParams: gov.VotingParams{ @@ -91,7 +92,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage { Params: stake.Params{ UnbondingTime: time.Duration(r.Intn(60*60*24*3*2)) * time.Second, MaxValidators: uint16(r.Intn(250)), - BondDenom: "steak", + BondDenom: stakeTypes.DefaultBondDenom, }, } fmt.Printf("Selected randomly generated staking parameters: %+v\n", stakeGenesis) @@ -113,7 +114,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage { Inflation: sdk.NewDecWithPrec(int64(r.Intn(99)), 2), }, Params: mint.Params{ - MintDenom: "steak", + MintDenom: stakeTypes.DefaultBondDenom, InflationRateChange: sdk.NewDecWithPrec(int64(r.Intn(99)), 2), InflationMax: sdk.NewDecWithPrec(20, 2), InflationMin: sdk.NewDecWithPrec(7, 2), diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index bc9151200..07cbbab78 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -29,6 +29,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/stake" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) var ( @@ -55,10 +56,10 @@ func TestGaiaCLIMinimumFees(t *testing.T) { barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) success := executeWrite(t, fmt.Sprintf( - "gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) + "gaiacli tx send %v --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass) require.False(t, success) tests.WaitForNextNBlocksTM(2, port) @@ -121,40 +122,40 @@ func TestGaiaCLISend(t *testing.T) { barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) - executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) + executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags)) - require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(10), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) // Test --dry-run - success := executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo --dry-run", flags, barAddr), app.DefaultKeyPass) + success := executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10%s --to=%s --from=foo --dry-run", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass) require.True(t, success) // Check state didn't change fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) // test autosequencing - executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) + executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags)) - require.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(20), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) // test memo - executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo --memo 'testmemo'", flags, barAddr), app.DefaultKeyPass) + executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10%s --to=%s --from=foo --memo 'testmemo'", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags)) - require.Equal(t, int64(30), barAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(30), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(20), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(20), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) } func TestGaiaCLIGasAuto(t *testing.T) { @@ -172,26 +173,26 @@ func TestGaiaCLIGasAuto(t *testing.T) { barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) // Test failure with auto gas disabled and very little gas set by hand - success := executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=10 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) + success := executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=10 --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass) require.False(t, success) tests.WaitForNextNBlocksTM(2, port) // Check state didn't change fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) // Test failure with negative gas - success = executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=-100 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) + success = executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=-100 --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass) require.False(t, success) // Test failure with 0 gas - success = executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=0 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) + success = executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=0 --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass) require.False(t, success) // Enable auto gas - success, stdout, _ := executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli tx send %v --json --gas=simulate --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) + success, stdout, _ := executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli tx send %v --json --gas=simulate --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass) require.True(t, success) // check that gas wanted == gas used cdc := app.MakeCodec() @@ -205,7 +206,7 @@ func TestGaiaCLIGasAuto(t *testing.T) { tests.WaitForNextNBlocksTM(2, port) // Check state has changed accordingly fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) } func TestGaiaCLICreateValidator(t *testing.T) { @@ -223,13 +224,13 @@ func TestGaiaCLICreateValidator(t *testing.T) { barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) barCeshPubKey := sdk.MustBech32ifyConsPub(barPubKey) - executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) + executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10%s --to=%s --from=foo", flags, stakeTypes.DefaultBondDenom, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags)) - require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(10), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) defaultParams := stake.DefaultParams() initialPool := stake.InitialPool() @@ -239,7 +240,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { cvStr := fmt.Sprintf("gaiacli tx create-validator %v", flags) cvStr += fmt.Sprintf(" --from=%s", "bar") cvStr += fmt.Sprintf(" --pubkey=%s", barCeshPubKey) - cvStr += fmt.Sprintf(" --amount=%v", "2steak") + cvStr += fmt.Sprintf(" --amount=%v", fmt.Sprintf("2%s", stakeTypes.DefaultBondDenom)) cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally") cvStr += fmt.Sprintf(" --commission-rate=%v", "0.05") cvStr += fmt.Sprintf(" --commission-max-rate=%v", "0.20") @@ -265,7 +266,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { tests.WaitForNextNBlocksTM(2, port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags)) - require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc) + require.Equal(t, int64(8), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64(), "%v", barAcc) validator := executeGetValidator(t, fmt.Sprintf("gaiacli query validator %s --output=json %v", sdk.ValAddress(barAddr), flags)) require.Equal(t, validator.OperatorAddr, sdk.ValAddress(barAddr)) @@ -283,7 +284,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { /* // this won't be what we expect because we've only started unbonding, haven't completed barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %v %v", barCech, flags)) - require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc) + require.Equal(t, int64(9), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64(), "%v", barAcc) */ validator = executeGetValidator(t, fmt.Sprintf("gaiacli query validator %s --output=json %v", sdk.ValAddress(barAddr), flags)) require.Equal(t, "1.0000000000", validator.Tokens.String()) @@ -315,7 +316,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome)) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) proposalsQuery, _ := tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "") require.Equal(t, "No matching proposals found", proposalsQuery) @@ -323,7 +324,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { // submit a test proposal spStr := fmt.Sprintf("gaiacli tx submit-proposal %v", flags) spStr += fmt.Sprintf(" --from=%s", "foo") - spStr += fmt.Sprintf(" --deposit=%s", "5steak") + spStr += fmt.Sprintf(" --deposit=%s", fmt.Sprintf("5%s", stakeTypes.DefaultBondDenom)) spStr += fmt.Sprintf(" --type=%s", "Text") spStr += fmt.Sprintf(" --title=%s", "Test") spStr += fmt.Sprintf(" --description=%s", "test") @@ -346,7 +347,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { tests.WaitForNextNBlocksTM(2, port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags)) require.Equal(t, uint64(1), proposal1.GetProposalID()) @@ -358,11 +359,11 @@ func TestGaiaCLISubmitProposal(t *testing.T) { deposit := executeGetDeposit(t, fmt.Sprintf("gaiacli query deposit --proposal-id=1 --depositer=%s --output=json %v", fooAddr, flags)) - require.Equal(t, int64(5), deposit.Amount.AmountOf("steak").Int64()) + require.Equal(t, int64(5), deposit.Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64()) depositStr := fmt.Sprintf("gaiacli tx deposit %v", flags) depositStr += fmt.Sprintf(" --from=%s", "foo") - depositStr += fmt.Sprintf(" --deposit=%s", "10steak") + depositStr += fmt.Sprintf(" --deposit=%s", fmt.Sprintf("10%s", stakeTypes.DefaultBondDenom)) depositStr += fmt.Sprintf(" --proposal-id=%s", "1") // Test generate only @@ -382,15 +383,15 @@ func TestGaiaCLISubmitProposal(t *testing.T) { deposits := executeGetDeposits(t, fmt.Sprintf("gaiacli query deposits --proposal-id=1 --output=json %v", flags)) require.Len(t, deposits, 1) - require.Equal(t, int64(15), deposits[0].Amount.AmountOf("steak").Int64()) + require.Equal(t, int64(15), deposits[0].Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64()) deposit = executeGetDeposit(t, fmt.Sprintf("gaiacli query deposit --proposal-id=1 --depositer=%s --output=json %v", fooAddr, flags)) - require.Equal(t, int64(15), deposit.Amount.AmountOf("steak").Int64()) + require.Equal(t, int64(15), deposit.Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64()) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags)) require.Equal(t, uint64(1), proposal1.GetProposalID()) require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus()) @@ -431,7 +432,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { // submit a second test proposal spStr = fmt.Sprintf("gaiacli tx submit-proposal %v", flags) spStr += fmt.Sprintf(" --from=%s", "foo") - spStr += fmt.Sprintf(" --deposit=%s", "5steak") + spStr += fmt.Sprintf(" --deposit=%s", fmt.Sprintf("5%s", stakeTypes.DefaultBondDenom)) spStr += fmt.Sprintf(" --type=%s", "Text") spStr += fmt.Sprintf(" --title=%s", "Apples") spStr += fmt.Sprintf(" --description=%s", "test") @@ -460,8 +461,8 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { // Test generate sendTx with default gas success, stdout, stderr := executeWriteRetStdStreams(t, fmt.Sprintf( - "gaiacli tx send %v --amount=10steak --to=%s --from=foo --generate-only", - flags, barAddr), []string{}...) + "gaiacli tx send %v --amount=10%s --to=%s --from=foo --generate-only", + flags, stakeTypes.DefaultBondDenom, barAddr), []string{}...) require.True(t, success) require.Empty(t, stderr) msg := unmarshalStdTx(t, stdout) @@ -471,8 +472,8 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { // Test generate sendTx with --gas=$amount success, stdout, stderr = executeWriteRetStdStreams(t, fmt.Sprintf( - "gaiacli tx send %v --amount=10steak --to=%s --from=foo --gas=100 --generate-only", - flags, barAddr), []string{}...) + "gaiacli tx send %v --amount=10%s --to=%s --from=foo --gas=100 --generate-only", + flags, stakeTypes.DefaultBondDenom, barAddr), []string{}...) require.True(t, success) require.Empty(t, stderr) msg = unmarshalStdTx(t, stdout) @@ -482,8 +483,8 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { // Test generate sendTx, estimate gas success, stdout, stderr = executeWriteRetStdStreams(t, fmt.Sprintf( - "gaiacli tx send %v --amount=10steak --to=%s --from=foo --gas=simulate --generate-only", - flags, barAddr), []string{}...) + "gaiacli tx send %v --amount=10%s --to=%s --from=foo --gas=simulate --generate-only", + flags, stakeTypes.DefaultBondDenom, barAddr), []string{}...) require.True(t, success) require.NotEmpty(t, stderr) msg = unmarshalStdTx(t, stdout) @@ -522,7 +523,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { // Test broadcast fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf( "gaiacli tx broadcast %v --json %v", flags, signedTxFile.Name())) @@ -536,9 +537,9 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { tests.WaitForNextNBlocksTM(2, port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags)) - require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(10), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) - require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) + require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64()) } func TestGaiaCLIConfig(t *testing.T) { diff --git a/cmd/gaia/init/gentx.go b/cmd/gaia/init/gentx.go index 7ed820375..449eb2b85 100644 --- a/cmd/gaia/init/gentx.go +++ b/cmd/gaia/init/gentx.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/stake/client/cli" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/spf13/cobra" "github.com/spf13/viper" cfg "github.com/tendermint/tendermint/config" @@ -21,7 +22,7 @@ import ( ) const ( - defaultAmount = "100steak" + defaultAmount = "100" + stakeTypes.DefaultBondDenom defaultCommissionRate = "0.1" defaultCommissionMaxRate = "0.2" defaultCommissionMaxChangeRate = "0.01" diff --git a/cmd/gaia/init/testnet.go b/cmd/gaia/init/testnet.go index 8ca274f78..b0676515c 100644 --- a/cmd/gaia/init/testnet.go +++ b/cmd/gaia/init/testnet.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" authtx "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" "github.com/cosmos/cosmos-sdk/x/stake" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/cosmos/cosmos-sdk/server" "github.com/spf13/cobra" @@ -180,14 +181,14 @@ func initTestnet(config *cfg.Config, cdc *codec.Codec) error { Address: addr, Coins: sdk.Coins{ sdk.NewInt64Coin(fmt.Sprintf("%sToken", nodeDirName), 1000), - sdk.NewInt64Coin("steak", 150), + sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 150), }, }) msg := stake.NewMsgCreateValidator( sdk.ValAddress(addr), valPubKeys[i], - sdk.NewInt64Coin("steak", 100), + sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 100), stake.NewDescription(nodeDirName, "", "", ""), stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), ) diff --git a/examples/democoin/x/simplestake/keeper.go b/examples/democoin/x/simplestake/keeper.go index 607f61d83..b757dd66d 100644 --- a/examples/democoin/x/simplestake/keeper.go +++ b/examples/democoin/x/simplestake/keeper.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" ) -const stakingToken = "steak" +const stakingToken = "stake" const moduleName = "simplestake" diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index c3876cf4a..974cf50e9 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -75,10 +75,10 @@ func TestBonding(t *testing.T) { _, _, err := stakeKeeper.unbondWithoutCoins(ctx, addr) require.Equal(t, err, ErrInvalidUnbond(DefaultCodespace)) - _, err = stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewInt64Coin("steak", 10)) + _, err = stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewInt64Coin("stake", 10)) require.Nil(t, err) - power, err := stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewInt64Coin("steak", 10)) + power, err := stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.NewInt64Coin("stake", 10)) require.Nil(t, err) require.Equal(t, int64(20), power) diff --git a/types/coin_test.go b/types/coin_test.go index ac9fcb391..77307f22a 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -49,8 +49,8 @@ func TestSameDenomAsCoin(t *testing.T) { {NewInt64Coin("A", 1), NewInt64Coin("A", 1), true}, {NewInt64Coin("A", 1), NewInt64Coin("a", 1), false}, {NewInt64Coin("a", 1), NewInt64Coin("b", 1), false}, - {NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), true}, - {NewInt64Coin("steak", -11), NewInt64Coin("steak", 10), true}, + {NewInt64Coin("stake", 1), NewInt64Coin("stake", 10), true}, + {NewInt64Coin("stake", -11), NewInt64Coin("stake", 10), true}, } for tcIndex, tc := range cases { @@ -107,8 +107,8 @@ func TestIsEqualCoin(t *testing.T) { {NewInt64Coin("A", 1), NewInt64Coin("A", 1), true}, {NewInt64Coin("A", 1), NewInt64Coin("a", 1), false}, {NewInt64Coin("a", 1), NewInt64Coin("b", 1), false}, - {NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), false}, - {NewInt64Coin("steak", -11), NewInt64Coin("steak", 10), false}, + {NewInt64Coin("stake", 1), NewInt64Coin("stake", 10), false}, + {NewInt64Coin("stake", -11), NewInt64Coin("stake", 10), false}, } for tcIndex, tc := range cases { diff --git a/types/utils_test.go b/types/utils_test.go index dbdd08c0a..f3930d152 100644 --- a/types/utils_test.go +++ b/types/utils_test.go @@ -21,8 +21,8 @@ func TestSortJSON(t *testing.T) { want: "", wantErr: true}, // genesis.json - {unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`, - want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, + {unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"stake","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"stake"},"candidates":null,"bonds":null}}}`, + want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"stake"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"stake","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, wantErr: false}, // from the TXSpec: {unsortedJSON: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`, diff --git a/x/auth/client/txbuilder/txbuilder_test.go b/x/auth/client/txbuilder/txbuilder_test.go index 996d9b8b1..3ad2ad412 100644 --- a/x/auth/client/txbuilder/txbuilder_test.go +++ b/x/auth/client/txbuilder/txbuilder_test.go @@ -10,6 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/tendermint/tendermint/crypto/ed25519" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) var ( @@ -46,7 +47,7 @@ func TestTxBuilderBuild(t *testing.T) { SimulateGas: false, ChainID: "test-chain", Memo: "hello", - Fee: "1steak", + Fee: "1" + stakeTypes.DefaultBondDenom, }, defaultMsg, StdSignMsg{ @@ -55,7 +56,7 @@ func TestTxBuilderBuild(t *testing.T) { Sequence: 1, Memo: "hello", Msgs: defaultMsg, - Fee: auth.NewStdFee(100, sdk.NewCoin("steak", sdk.NewInt(1))), + Fee: auth.NewStdFee(100, sdk.NewCoin(stakeTypes.DefaultBondDenom, sdk.NewInt(1))), }, false, }, diff --git a/x/gov/endblocker_test.go b/x/gov/endblocker_test.go index 535cf036a..47e903758 100644 --- a/x/gov/endblocker_test.go +++ b/x/gov/endblocker_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" abci "github.com/tendermint/tendermint/abci/types" ) @@ -20,7 +21,7 @@ func TestTickExpiredDepositPeriod(t *testing.T) { require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)}) + newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)}) res := govHandler(ctx, newProposalMsg) require.True(t, res.IsOK()) @@ -62,7 +63,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)}) + newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)}) res := govHandler(ctx, newProposalMsg) require.True(t, res.IsOK()) @@ -79,7 +80,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newProposalMsg2 := NewMsgSubmitProposal("Test2", "test2", ProposalTypeText, addrs[1], sdk.Coins{sdk.NewInt64Coin("steak", 5)}) + newProposalMsg2 := NewMsgSubmitProposal("Test2", "test2", ProposalTypeText, addrs[1], sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)}) res = govHandler(ctx, newProposalMsg2) require.True(t, res.IsOK()) @@ -121,7 +122,7 @@ func TestTickPassedDepositPeriod(t *testing.T) { require.False(t, activeQueue.Valid()) activeQueue.Close() - newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)}) + newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)}) res := govHandler(ctx, newProposalMsg) require.True(t, res.IsOK()) @@ -140,7 +141,7 @@ func TestTickPassedDepositPeriod(t *testing.T) { require.False(t, inactiveQueue.Valid()) inactiveQueue.Close() - newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)}) + newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)}) res = govHandler(ctx, newDepositMsg) require.True(t, res.IsOK()) @@ -163,7 +164,7 @@ func TestTickPassedVotingPeriod(t *testing.T) { require.False(t, activeQueue.Valid()) activeQueue.Close() - newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)}) + newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)}) res := govHandler(ctx, newProposalMsg) require.True(t, res.IsOK()) @@ -174,7 +175,7 @@ func TestTickPassedVotingPeriod(t *testing.T) { newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)}) + newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)}) res = govHandler(ctx, newDepositMsg) require.True(t, res.IsOK()) diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 1243bf559..e134a4a78 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -4,6 +4,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) // GenesisState - all staking state that must be provided at genesis @@ -43,7 +44,7 @@ func DefaultGenesisState() GenesisState { return GenesisState{ StartingProposalID: 1, DepositParams: DepositParams{ - MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", 10)}, + MinDeposit: sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)}, MaxDepositPeriod: time.Duration(172800) * time.Second, }, VotingParams: VotingParams{ diff --git a/x/gov/keeper_test.go b/x/gov/keeper_test.go index 2ff1344b7..23199472b 100644 --- a/x/gov/keeper_test.go +++ b/x/gov/keeper_test.go @@ -9,6 +9,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) func TestGetSetProposal(t *testing.T) { @@ -69,14 +70,14 @@ func TestDeposits(t *testing.T) { proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() - fourSteak := sdk.Coins{sdk.NewInt64Coin("steak", 4)} - fiveSteak := sdk.Coins{sdk.NewInt64Coin("steak", 5)} + fourSteak := sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 4)} + fiveSteak := sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 5)} addr0Initial := keeper.ck.GetCoins(ctx, addrs[0]) addr1Initial := keeper.ck.GetCoins(ctx, addrs[1]) - // require.True(t, addr0Initial.IsEqual(sdk.Coins{sdk.NewInt64Coin("steak", 42)})) - require.Equal(t, sdk.Coins{sdk.NewInt64Coin("steak", 42)}, addr0Initial) + // require.True(t, addr0Initial.IsEqual(sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 42)})) + require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 42)}, addr0Initial) require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{})) diff --git a/x/gov/msgs_test.go b/x/gov/msgs_test.go index bdc273dcd..e488d2aba 100644 --- a/x/gov/msgs_test.go +++ b/x/gov/msgs_test.go @@ -7,16 +7,21 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/mock" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) var ( - coinsPos = sdk.Coins{sdk.NewInt64Coin("steak", 1000)} + coinsPos = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 1000)} coinsZero = sdk.Coins{} - coinsNeg = sdk.Coins{sdk.NewInt64Coin("steak", -10000)} + coinsNeg = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, -10000)} coinsPosNotAtoms = sdk.Coins{sdk.NewInt64Coin("foo", 10000)} - coinsMulti = sdk.Coins{sdk.NewInt64Coin("foo", 10000), sdk.NewInt64Coin("steak", 1000)} + coinsMulti = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 1000), sdk.NewInt64Coin("foo", 10000)} ) +func init() { + coinsMulti.Sort() +} + // test ValidateBasic for MsgCreateValidator func TestMsgSubmitProposal(t *testing.T) { _, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{}) @@ -42,9 +47,9 @@ func TestMsgSubmitProposal(t *testing.T) { for i, tc := range tests { msg := NewMsgSubmitProposal(tc.title, tc.description, tc.proposalType, tc.proposerAddr, tc.initialDeposit) if tc.expectPass { - require.Nil(t, msg.ValidateBasic(), "test: %v", i) + require.NoError(t, msg.ValidateBasic(), "test: %v", i) } else { - require.NotNil(t, msg.ValidateBasic(), "test: %v", i) + require.Error(t, msg.ValidateBasic(), "test: %v", i) } } } @@ -68,9 +73,9 @@ func TestMsgDeposit(t *testing.T) { for i, tc := range tests { msg := NewMsgDeposit(tc.depositerAddr, tc.proposalID, tc.depositAmount) if tc.expectPass { - require.Nil(t, msg.ValidateBasic(), "test: %v", i) + require.NoError(t, msg.ValidateBasic(), "test: %v", i) } else { - require.NotNil(t, msg.ValidateBasic(), "test: %v", i) + require.Error(t, msg.ValidateBasic(), "test: %v", i) } } } diff --git a/x/gov/simulation/msgs.go b/x/gov/simulation/msgs.go index 0eadc7feb..d075c86ae 100644 --- a/x/gov/simulation/msgs.go +++ b/x/gov/simulation/msgs.go @@ -11,10 +11,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/mock/simulation" "github.com/cosmos/cosmos-sdk/x/stake" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) const ( - denom = "steak" + denom = stakeTypes.DefaultBondDenom ) // SimulateSubmittingVotingAndSlashingForProposal simulates creating a msg Submit Proposal diff --git a/x/gov/tally_test.go b/x/gov/tally_test.go index 26b32cc93..b2f6aaf32 100644 --- a/x/gov/tally_test.go +++ b/x/gov/tally_test.go @@ -11,6 +11,7 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" "github.com/cosmos/cosmos-sdk/x/stake" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) var ( @@ -25,7 +26,7 @@ func createValidators(t *testing.T, stakeHandler sdk.Handler, ctx sdk.Context, a for i := 0; i < len(addrs); i++ { valCreateMsg := stake.NewMsgCreateValidator( - addrs[i], pubkeys[i], sdk.NewInt64Coin("steak", coinAmt[i]), testDescription, testCommissionMsg, + addrs[i], pubkeys[i], sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, coinAmt[i]), testDescription, testCommissionMsg, ) res := stakeHandler(ctx, valCreateMsg) @@ -289,7 +290,7 @@ func TestTallyDelgatorOverride(t *testing.T) { createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7}) stake.EndBlocker(ctx, sk) - delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30)) + delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 30)) stakeHandler(ctx, delegator1Msg) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) @@ -326,7 +327,7 @@ func TestTallyDelgatorInherit(t *testing.T) { createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7}) stake.EndBlocker(ctx, sk) - delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30)) + delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 30)) stakeHandler(ctx, delegator1Msg) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) @@ -361,9 +362,9 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7}) stake.EndBlocker(ctx, sk) - delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10)) + delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)) stakeHandler(ctx, delegator1Msg) - delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10)) + delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)) stakeHandler(ctx, delegator1Msg2) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) @@ -393,24 +394,24 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { stakeHandler := stake.NewHandler(sk) val1CreateMsg := stake.NewMsgCreateValidator( - sdk.ValAddress(addrs[0]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 25), testDescription, testCommissionMsg, + sdk.ValAddress(addrs[0]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 25), testDescription, testCommissionMsg, ) stakeHandler(ctx, val1CreateMsg) val2CreateMsg := stake.NewMsgCreateValidator( - sdk.ValAddress(addrs[1]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 6), testDescription, testCommissionMsg, + sdk.ValAddress(addrs[1]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 6), testDescription, testCommissionMsg, ) stakeHandler(ctx, val2CreateMsg) val3CreateMsg := stake.NewMsgCreateValidator( - sdk.ValAddress(addrs[2]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 7), testDescription, testCommissionMsg, + sdk.ValAddress(addrs[2]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 7), testDescription, testCommissionMsg, ) stakeHandler(ctx, val3CreateMsg) - delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10)) + delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)) stakeHandler(ctx, delegator1Msg) - delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10)) + delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)) stakeHandler(ctx, delegator1Msg2) stake.EndBlocker(ctx, sk) @@ -447,10 +448,10 @@ func TestTallyJailedValidator(t *testing.T) { createValidators(t, stakeHandler, ctx, valAddrs, []int64{25, 6, 7}) stake.EndBlocker(ctx, sk) - delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10)) + delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)) stakeHandler(ctx, delegator1Msg) - delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10)) + delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)) stakeHandler(ctx, delegator1Msg2) val2, found := sk.GetValidator(ctx, sdk.ValAddress(addrs[1])) diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 82ae30358..4e0ffd51a 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/stake" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) // initialize the mock application for this module @@ -44,7 +45,7 @@ func getMockApp(t *testing.T, numGenAccs int) (*mock.App, Keeper, stake.Keeper, require.NoError(t, mapp.CompleteSetup(keyStake, tkeyStake, keyGov, keyGlobalParams, tkeyGlobalParams)) - genAccs, addrs, pubKeys, privKeys := mock.CreateGenAccounts(numGenAccs, sdk.Coins{sdk.NewInt64Coin("steak", 42)}) + genAccs, addrs, pubKeys, privKeys := mock.CreateGenAccounts(numGenAccs, sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 42)}) mock.SetGenesis(mapp, genAccs) diff --git a/x/mint/params.go b/x/mint/params.go index 05edc8fd9..47c9c8548 100644 --- a/x/mint/params.go +++ b/x/mint/params.go @@ -2,6 +2,7 @@ package mint import ( "fmt" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -18,7 +19,7 @@ type Params struct { // default minting module parameters func DefaultParams() Params { return Params{ - MintDenom: "steak", + MintDenom: stakeTypes.DefaultBondDenom, InflationRateChange: sdk.NewDecWithPrec(13, 2), InflationMax: sdk.NewDecWithPrec(20, 2), InflationMin: sdk.NewDecWithPrec(7, 2), diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 6529609ba..dd96ff51e 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -3,15 +3,17 @@ package slashing import ( "testing" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/stake" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/ed25519" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) var ( @@ -93,8 +95,8 @@ func checkValidatorSigningInfo(t *testing.T, mapp *mock.App, keeper Keeper, func TestSlashingMsgs(t *testing.T) { mapp, stakeKeeper, keeper := getMockApp(t) - genCoin := sdk.NewInt64Coin("steak", 42) - bondCoin := sdk.NewInt64Coin("steak", 10) + genCoin := sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 42) + bondCoin := sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10) acc1 := &auth.BaseAccount{ Address: addr1, diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 239ae13d6..72ee58e1b 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -21,6 +21,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/stake" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) // TODO remove dependencies on staking (should only refer to validator set type from sdk) @@ -120,7 +121,7 @@ func NewTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt DelegatorAddr: sdk.AccAddress(address), ValidatorAddr: address, PubKey: pubKey, - Delegation: sdk.NewCoin("steak", amt), + Delegation: sdk.NewCoin(stakeTypes.DefaultBondDenom, amt), } } @@ -128,6 +129,6 @@ func newTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, delAmoun return stake.MsgDelegate{ DelegatorAddr: delAddr, ValidatorAddr: valAddr, - Delegation: sdk.NewCoin("steak", delAmount), + Delegation: sdk.NewCoin(stakeTypes.DefaultBondDenom, delAmount), } } diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 9a38d2d17..b24018a6c 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -3,13 +3,15 @@ package stake import ( "testing" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/params" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" ) // getMockApp returns an initialized mock application for this module. @@ -100,8 +102,8 @@ func checkDelegation( func TestStakeMsgs(t *testing.T) { mApp, keeper := getMockApp(t) - genCoin := sdk.NewInt64Coin("steak", 42) - bondCoin := sdk.NewInt64Coin("steak", 10) + genCoin := sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 42) + bondCoin := sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10) acc1 := &auth.BaseAccount{ Address: addr1, diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index fcf2f4206..23dcbc1a6 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -139,7 +139,7 @@ func TestUnbondingDelegation(t *testing.T) { ValidatorAddr: addrVals[0], CreationHeight: 0, MinTime: time.Unix(0, 0), - Balance: sdk.NewInt64Coin("steak", 5), + Balance: sdk.NewInt64Coin(types.DefaultBondDenom, 5), } // set and retrieve a record @@ -149,7 +149,7 @@ func TestUnbondingDelegation(t *testing.T) { require.True(t, ubd.Equal(resUnbond)) // modify a records, save, and retrieve - ubd.Balance = sdk.NewInt64Coin("steak", 21) + ubd.Balance = sdk.NewInt64Coin(types.DefaultBondDenom, 21) keeper.SetUnbondingDelegation(ctx, ubd) resUnbonds := keeper.GetUnbondingDelegations(ctx, addrDels[0], 5) diff --git a/x/stake/querier/queryable_test.go b/x/stake/querier/queryable_test.go index 973e2376f..925eae63f 100644 --- a/x/stake/querier/queryable_test.go +++ b/x/stake/querier/queryable_test.go @@ -189,7 +189,7 @@ func TestQueryDelegation(t *testing.T) { pool := keeper.GetPool(ctx) keeper.SetValidatorByPowerIndex(ctx, val1, pool) - keeper.Delegate(ctx, addrAcc2, sdk.NewCoin("steak", sdk.NewInt(20)), val1, true) + keeper.Delegate(ctx, addrAcc2, sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(20)), val1, true) // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -346,7 +346,7 @@ func TestQueryRedelegations(t *testing.T) { keeper.SetValidator(ctx, val1) keeper.SetValidator(ctx, val2) - keeper.Delegate(ctx, addrAcc2, sdk.NewCoin("steak", sdk.NewInt(100)), val1, true) + keeper.Delegate(ctx, addrAcc2, sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(100)), val1, true) keeper.ApplyAndReturnValidatorSetUpdates(ctx) keeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), sdk.NewDec(20)) diff --git a/x/stake/simulation/invariants.go b/x/stake/simulation/invariants.go index 819bc8b37..439f40de3 100644 --- a/x/stake/simulation/invariants.go +++ b/x/stake/simulation/invariants.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/mock/simulation" "github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake/keeper" + stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types" abci "github.com/tendermint/tendermint/abci/types" ) @@ -48,7 +49,7 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper, loose := sdk.ZeroDec() bonded := sdk.ZeroDec() am.IterateAccounts(ctx, func(acc auth.Account) bool { - loose = loose.Add(sdk.NewDecFromInt(acc.GetCoins().AmountOf("steak"))) + loose = loose.Add(sdk.NewDecFromInt(acc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom))) return false }) k.IterateUnbondingDelegations(ctx, func(_ int64, ubd stake.UnbondingDelegation) bool { @@ -70,19 +71,19 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper, feePool := d.GetFeePool(ctx) // add outstanding fees - loose = loose.Add(sdk.NewDecFromInt(f.GetCollectedFees(ctx).AmountOf("steak"))) + loose = loose.Add(sdk.NewDecFromInt(f.GetCollectedFees(ctx).AmountOf(stakeTypes.DefaultBondDenom))) // add community pool - loose = loose.Add(feePool.CommunityPool.AmountOf("steak")) + loose = loose.Add(feePool.CommunityPool.AmountOf(stakeTypes.DefaultBondDenom)) // add validator distribution pool - loose = loose.Add(feePool.ValPool.AmountOf("steak")) + loose = loose.Add(feePool.ValPool.AmountOf(stakeTypes.DefaultBondDenom)) // add validator distribution commission and yet-to-be-withdrawn-by-delegators d.IterateValidatorDistInfos(ctx, func(_ int64, distInfo distribution.ValidatorDistInfo) (stop bool) { - loose = loose.Add(distInfo.DelPool.AmountOf("steak")) - loose = loose.Add(distInfo.ValCommission.AmountOf("steak")) + loose = loose.Add(distInfo.DelPool.AmountOf(stakeTypes.DefaultBondDenom)) + loose = loose.Add(distInfo.ValCommission.AmountOf(stakeTypes.DefaultBondDenom)) return false }, ) diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 49bac0f31..88077d18b 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -28,7 +28,7 @@ var ( func NewTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator { return types.NewMsgCreateValidator( - address, pubKey, sdk.NewCoin("steak", sdk.NewInt(amt)), Description{}, commissionMsg, + address, pubKey, sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(amt)), Description{}, commissionMsg, ) } @@ -38,7 +38,7 @@ func NewTestMsgCreateValidatorWithCommission(address sdk.ValAddress, pubKey cryp commission := NewCommissionMsg(commissionRate, sdk.OneDec(), sdk.ZeroDec()) return types.NewMsgCreateValidator( - address, pubKey, sdk.NewCoin("steak", sdk.NewInt(amt)), Description{}, commission, + address, pubKey, sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(amt)), Description{}, commission, ) } @@ -46,7 +46,7 @@ func NewTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt int6 return MsgDelegate{ DelegatorAddr: delAddr, ValidatorAddr: valAddr, - Delegation: sdk.NewCoin("steak", sdk.NewInt(amt)), + Delegation: sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(amt)), } } @@ -57,6 +57,6 @@ func NewTestMsgCreateValidatorOnBehalfOf(delAddr sdk.AccAddress, valAddr sdk.Val DelegatorAddr: delAddr, ValidatorAddr: valAddr, PubKey: valPubKey, - Delegation: sdk.NewCoin("steak", sdk.NewInt(amt)), + Delegation: sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(amt)), } } diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index 7c1800b8e..7e719f3ee 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -10,9 +10,9 @@ import ( ) var ( - coinPos = sdk.NewInt64Coin("steak", 1000) - coinZero = sdk.NewInt64Coin("steak", 0) - coinNeg = sdk.NewInt64Coin("steak", -10000) + coinPos = sdk.NewInt64Coin(DefaultBondDenom, 1000) + coinZero = sdk.NewInt64Coin(DefaultBondDenom, 0) + coinNeg = sdk.NewInt64Coin(DefaultBondDenom, -10000) ) // test ValidateBasic for MsgCreateValidator diff --git a/x/stake/types/params.go b/x/stake/types/params.go index 699758ace..dcd172982 100644 --- a/x/stake/types/params.go +++ b/x/stake/types/params.go @@ -19,6 +19,9 @@ const ( // if this is 1, the validator set at the end of a block will sign the block after the next. // Constant as this should not change without a hard fork. ValidatorUpdateDelay int64 = 1 + + // Default bondable coin denomination + DefaultBondDenom = "STAKE" ) // nolint - Keys for parameter access @@ -59,7 +62,7 @@ func DefaultParams() Params { return Params{ UnbondingTime: defaultUnbondingTime, MaxValidators: 100, - BondDenom: "steak", + BondDenom: DefaultBondDenom, } } From b7daf23366f34c3efb734e7d444f4a890aa4e491 Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Mon, 12 Nov 2018 10:55:24 -0800 Subject: [PATCH 33/33] R4R: Fix unbonding command flow (#2727) --- PENDING.md | 1 + x/stake/client/cli/tx.go | 18 ++---------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/PENDING.md b/PENDING.md index 48d5fe0e1..25cf75bc6 100644 --- a/PENDING.md +++ b/PENDING.md @@ -5,6 +5,7 @@ BREAKING CHANGES * Gaia REST API (`gaiacli advanced rest-server`) * Gaia CLI (`gaiacli`) + * [cli] [\#2727](https://github.com/cosmos/cosmos-sdk/pull/2727) Fix unbonding command flow * Gaia diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 3b8d8e200..506499929 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/utils" @@ -284,22 +285,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *codec.Codec) *cobra.Command { func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "unbond", - Short: "begin or complete unbonding shares from a validator", - } - - cmd.AddCommand( - client.PostCommands( - GetCmdBeginUnbonding(storeName, cdc), - )...) - - return cmd -} - -// GetCmdBeginUnbonding implements the begin unbonding validator command. -func GetCmdBeginUnbonding(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "begin", - Short: "begin unbonding", + Short: "unbond shares from a validator", RunE: func(cmd *cobra.Command, args []string) error { txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc) cliCtx := context.NewCLIContext().