diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 36b9f97f2..3a3d666e0 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -4,6 +4,8 @@ v Before smashing the submit button please review the checkboxes.
v If a checkbox is n/a - please still include it but + a little note why
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
+- Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/cosmos-sdk/blob/develop/CONTRIBUTING.md#pr-targeting))
+
- [ ] Linked to github-issue with discussion and accepted design OR link to spec that describes this work.
- [ ] Wrote tests
- [ ] Updated relevant documentation (`docs/`)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18b9d5348..479f5913a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# Changelog
+## 0.24.2
+
+*August 22nd, 2018*
+
+BUG FIXES
+
+* Tendermint
+ - Fix unbounded consensus WAL growth
+
## 0.24.1
*August 21st, 2018*
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7b7ad81fd..3a7dca210 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -133,6 +133,17 @@ Libraries need not follow the model strictly, but would be wise to.
The SDK utilizes [semantic versioning](https://semver.org/).
+### PR Targeting
+
+Ensure that you base and target your PR on the correct branch:
+ - `release/vxx.yy.zz` for a merge into a release candidate
+ - `master` for a merge of a release
+ - `develop` in the usual case
+
+All feature additions should be targeted against `develop`. Bug fixes for an outstanding release candidate
+should be targeted against the release candidate branch. Release candidate branches themselves should be the
+only pull requests targeted directly against master.
+
### Development Procedure:
- the latest state of development is on `develop`
- `develop` must never fail `make test` or `make test_cli`
diff --git a/Gopkg.lock b/Gopkg.lock
index 73a2ff60f..81591a0ae 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -165,13 +165,12 @@
[[projects]]
branch = "master"
- digest = "1:a361611b8c8c75a1091f00027767f7779b29cb37c456a71b8f2604c88057ab40"
+ digest = "1:12247a2e99a060cc692f6680e5272c8adf0b8f572e6bce0d7095e624c958a240"
name = "github.com/hashicorp/hcl"
packages = [
".",
"hcl/ast",
"hcl/parser",
- "hcl/printer",
"hcl/scanner",
"hcl/strconv",
"hcl/token",
@@ -424,7 +423,7 @@
version = "v0.9.2"
[[projects]]
- digest = "1:26146cdb2811ce481e72138439b9b1aa17a64d54364f96bb92f97a9ef8ba4f01"
+ digest = "1:4f15e95fe3888cc75dd34f407d6394cbc7fd3ff24920851b92b295f6a8b556e6"
name = "github.com/tendermint/tendermint"
packages = [
"abci/client",
@@ -487,8 +486,8 @@
"version",
]
pruneopts = "UT"
- revision = "013b9cef642f875634c614019ab13b17570778ad"
- version = "v0.23.0"
+ revision = "81df19e68ab1519399fccf0cab81cb75bf9d782e"
+ version = "v0.23.1-rc0"
[[projects]]
digest = "1:bf6d9a827ea3cad964c2f863302e4f6823170d0b5ed16f72cf1184a7c615067e"
diff --git a/Gopkg.toml b/Gopkg.toml
index acc3e282a..4368699b6 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -57,7 +57,7 @@
[[override]]
name = "github.com/tendermint/tendermint"
- version = "=v0.23.0"
+ version = "=v0.23.1-rc0"
[[constraint]]
name = "github.com/bartekn/go-bip39"
diff --git a/Makefile b/Makefile
index de5f6956f..66d566309 100644
--- a/Makefile
+++ b/Makefile
@@ -152,7 +152,7 @@ test_sim_gaia_nondeterminism:
test_sim_gaia_fast:
@echo "Running quick Gaia simulation. This may take several minutes..."
- @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=200 -timeout 24h
+ @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=50 -v -timeout 24h
test_sim_gaia_slow:
@echo "Running full Gaia simulation. This may take awhile!"
diff --git a/PENDING.md b/PENDING.md
index 213453e4a..6d70d9f8a 100644
--- a/PENDING.md
+++ b/PENDING.md
@@ -16,8 +16,9 @@ BREAKING CHANGES
* Gaia
* Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013)
* [x/stake] \#1901 Validator type's Owner field renamed to Operator; Validator's GetOwner() renamed accordingly to comply with the SDK's Validator interface.
+ * [docs] [#2001](https://github.com/cosmos/cosmos-sdk/pull/2001) Update slashing spec for slashing period
* [x/stake, x/slashing] [#1305](https://github.com/cosmos/cosmos-sdk/issues/1305) - Rename "revoked" to "jailed"
-
+
* SDK
* [core] \#1807 Switch from use of rational to decimal
* [types] \#1901 Validator interface's GetOwner() renamed to GetOperator()
diff --git a/docs/spec/slashing/README.md b/docs/spec/slashing/README.md
new file mode 100644
index 000000000..dee91eb33
--- /dev/null
+++ b/docs/spec/slashing/README.md
@@ -0,0 +1,33 @@
+# Slashing module specification
+
+## Abstract
+
+This section specifies the slashing module of the Cosmos SDK, which implements functionality
+first outlined in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper) in June 2016.
+
+The slashing module enables Cosmos SDK-based blockchains to disincentivize any attributable action
+by a protocol-recognized actor with value at stake by penalizing them ("slashing").
+
+Penalties may include, but are not limited to:
+- Burning some amount of their stake
+- Removing their ability to vote on future blocks for a period of time.
+
+This module will be used by the Cosmos Hub, the first hub in the Cosmos ecosystem.
+
+## Contents
+
+1. **[Overview](overview.md)**
+1. **[State](state.md)**
+ 1. [SigningInfo](state.md#signing-info)
+ 1. [SlashingPeriod](state.md#slashing-period)
+1. **[Transactions](transactions.md)**
+ 1. [Unjail](transactions.md#unjail)
+1. **[Hooks](hooks.md)**
+ 1. [Validator Bonded](hooks.md#validator-bonded)
+ 1. [Validator Unbonded](hooks.md#validator-unbonded)
+ 1. [Validator Slashed](hooks.md#validator-slashed)
+1. **[Begin Block](begin-block.md)**
+ 1. [Evidence handling](begin-block.md#evidence-handling)
+ 1. [Uptime tracking](begin-block.md#uptime-tracking)
+1. **[Future Improvements](future-improvements.md)**
+ 1. [State cleanup](future-improvements.md#state-cleanup)
diff --git a/docs/spec/slashing/end_block.md b/docs/spec/slashing/begin-block.md
similarity index 86%
rename from docs/spec/slashing/end_block.md
rename to docs/spec/slashing/begin-block.md
index 3eec27372..375e19185 100644
--- a/docs/spec/slashing/end_block.md
+++ b/docs/spec/slashing/begin-block.md
@@ -1,12 +1,13 @@
-# End-Block
+# Begin-Block
-## Slashing
+## Evidence handling
Tendermint blocks can include
[Evidence](https://github.com/tendermint/tendermint/blob/develop/docs/spec/blockchain/blockchain.md#evidence), which indicates that a validator
-committed malicious behaviour. The relevant information is forwarded to the
+committed malicious behavior. The relevant information is forwarded to the
application as [ABCI
-Evidence](https://github.com/tendermint/tendermint/blob/develop/abci/types/types.proto#L259), so the validator an be accordingly punished.
+Evidence](https://github.com/tendermint/tendermint/blob/develop/abci/types/types.proto#L259) in `abci.RequestBeginBlock`
+so that the validator an be accordingly punished.
For some `evidence` to be valid, it must satisfy:
@@ -75,7 +76,9 @@ This ensures that offending validators are punished the same amount whether they
act as a single validator with X stake or as N validators with collectively X
stake.
-## Automatic Unbonding
+The amount slashed for all double signature infractions committed within a single slashing period is capped as described in [state-machine.md](state-machine.md).
+
+## Uptime tracking
At the beginning of each block, we update the signing info for each validator and check if they should be automatically unbonded:
@@ -113,3 +116,5 @@ for val in block.Validators:
SigningInfo.Set(val.Address, signInfo)
```
+
+The amount slashed for downtime slashes is *not* capped by the slashing period in which they are committed, although they do reset it (since the validator is unbonded).
diff --git a/docs/spec/slashing/future-improvements.md b/docs/spec/slashing/future-improvements.md
new file mode 100644
index 000000000..84be139e8
--- /dev/null
+++ b/docs/spec/slashing/future-improvements.md
@@ -0,0 +1,4 @@
+## State Cleanup
+
+Once no evidence for a given slashing period can possibly be valid (the end time plus the unbonding period is less than the current time),
+old slashing periods should be cleaned up. This will be implemented post-launch.
diff --git a/docs/spec/slashing/hooks.md b/docs/spec/slashing/hooks.md
new file mode 100644
index 000000000..36dde61f9
--- /dev/null
+++ b/docs/spec/slashing/hooks.md
@@ -0,0 +1,58 @@
+## Hooks
+
+In this section we describe the "hooks" - slashing module code that runs when other events happen.
+
+### Validator Bonded
+
+Upon successful bonding of a validator (a given validator entering the "bonded" state,
+which may happen on delegation, on unjailing, etc), we create a new `SlashingPeriod` structure for the
+now-bonded validator, which `StartHeight` of the current block, `EndHeight` of `0` (sentinel value for not-yet-ended),
+and `SlashedSoFar` of `0`:
+
+```
+onValidatorBonded(address sdk.ValAddress)
+
+ slashingPeriod = SlashingPeriod{
+ ValidatorAddr : address,
+ StartHeight : CurrentHeight,
+ EndHeight : 0,
+ SlashedSoFar : 0,
+ }
+ setSlashingPeriod(slashingPeriod)
+
+ return
+```
+
+### Validator Unbonded
+
+When a validator is unbonded, we update the in-progress `SlashingPeriod` with the current block as the `EndHeight`:
+
+```
+onValidatorUnbonded(address sdk.ValAddress)
+
+ slashingPeriod = getSlashingPeriod(address, CurrentHeight)
+ slashingPeriod.EndHeight = CurrentHeight
+ setSlashingPeriod(slashingPeriod)
+
+ return
+```
+
+### Validator Slashed
+
+When a validator is slashed, we look up the appropriate `SlashingPeriod` based on the validator
+address and the time of infraction, cap the fraction slashed as `max(SlashFraction, SlashedSoFar)`
+(which may be `0`), and update the `SlashingPeriod` with the increased `SlashedSoFar`:
+
+```
+beforeValidatorSlashed(address sdk.ValAddress, fraction sdk.Rat, infractionHeight int64)
+
+ slashingPeriod = getSlashingPeriod(address, infractionHeight)
+ totalToSlash = max(slashingPeriod.SlashedSoFar, fraction)
+ slashingPeriod.SlashedSoFar = totalToSlash
+ setSlashingPeriod(slashingPeriod)
+
+ remainderToSlash = slashingPeriod.SlashedSoFar - totalToSlash
+ fraction = remainderToSlash
+
+ continue with slashing
+```
diff --git a/docs/spec/slashing/overview.md b/docs/spec/slashing/overview.md
new file mode 100644
index 000000000..aa42f6193
--- /dev/null
+++ b/docs/spec/slashing/overview.md
@@ -0,0 +1,68 @@
+## Conceptual overview
+
+### States
+
+At any given time, there are any number of validators registered in the state machine.
+Each block, the top `n = MaximumBondedValidators` validators who are not jailed become *bonded*, meaning that they may propose and vote on blocks.
+Validators who are *bonded* are *at stake*, meaning that part or all of their stake and their delegators' stake is at risk if they commit a protocol fault.
+
+### Slashing period
+
+In order to mitigate the impact of initially likely categories of non-malicious protocol faults, the Cosmos Hub implements for each validator
+a *slashing period*, in which the amount by which a validator can be slashed is capped at the punishment for the worst violation. For example,
+if you misconfigure your HSM and double-sign a bunch of old blocks, you'll only be punished for the first double-sign (and then immediately jailed,
+so that you have a chance to reconfigure your setup). This will still be quite expensive and desirable to avoid, but slashing periods somewhat blunt
+the economic impact of unintentional misconfiguration.
+
+Unlike the unbonding period, the slashing period doesn't have a fixed length. A new slashing period starts whenever a validator is bonded and ends
+whenever the validator is unbonded (which will happen if the validator is jailed). The amount of tokens slashed relative to validator power for infractions
+committed within the slashing period, whenever they are discovered, is capped at the punishment for the worst infraction
+(which for the Cosmos Hub at launch will be double-signing a block).
+
+#### ASCII timelines
+
+*Code*
+
+*[* : timeline start
+*]* : timeline end
+*<* : slashing period start
+*>* : slashing period end
+*Cn* : infraction `n` committed
+*Dn* : infraction `n` discovered
+*Vb* : validator bonded
+*Vu* : validator unbonded
+
+*Single infraction*
+
+<----------------->
+[----------C1----D1,Vu-----]
+
+A single infraction is committed then later discovered, at which point the validator is unbonded and slashed at the full amount for the infraction.
+
+*Multiple infractions*
+
+<--------------------------->
+[----------C1--C2---C3---D1,D2,D3Vu-----]
+
+Multiple infractions are committed within a single slashing period then later discovered, at which point the validator is unbonded and slashed for only the worst infraction.
+
+*Multiple infractions after rebonding*
+
+
+<---------------------------> <------------->
+[----------C1--C2---C3---D1,D2,D3Vu---Vb---C4----D4,Vu--]
+
+Multiple infractions are committed within a single slashing period then later discovered, at which point the validator is unbonded and slashed for only the worst infraction.
+The validator then unjails themself and rebonds, then commits a fourth infraction - which is discovered and punished at the full amount, since a new slashing period started
+when they unjailed and rebonded.
+
+### Safety note
+
+Slashing is capped fractionally per period, but the amount of total bonded stake associated with any given validator can change (by an unbounded amount) over that period.
+
+For example, with MaxFractionSlashedPerPeriod = `0.5`, if a validator is initially slashed at `0.4` near the start of a period when they have 100 stake bonded,
+then later slashed at `0.4` when they have `1000` stake bonded, the total amount slashed is just `40 + 100 = 140` (since the latter slash is capped at `0.1`) -
+whereas if they had `1000` stake bonded initially, the first offense would have been slashed for `400` stake and the total amount slashed would have been `400 + 100 = 500`.
+
+This means that any slashing events which utilize the slashing period (are capped-per-period) **must also** jail the validator when the infraction is discovered.
+Otherwise it would be possible for a validator to slash themselves intentionally at a low bond, then increase their bond but no longer be at stake since they would have already hit the `SlashedSoFar` cap.
diff --git a/docs/spec/slashing/state.md b/docs/spec/slashing/state.md
index 8bbb22c76..ae426db7b 100644
--- a/docs/spec/slashing/state.md
+++ b/docs/spec/slashing/state.md
@@ -1,6 +1,6 @@
-## State
+# State
-### Signing Info
+## Signing Info
Every block includes a set of precommits by the validators for the previous block,
known as the LastCommit. A LastCommit is valid so long as it contains precommits from +2/3 of voting power.
@@ -36,10 +36,11 @@ The information stored for tracking validator liveness is as follows:
```go
type ValidatorSigningInfo struct {
- StartHeight int64
- IndexOffset int64
- JailedUntil int64
- SignedBlocksCounter int64
+ StartHeight int64 // Height at which the validator became able to sign blocks
+ IndexOffset int64 // Offset into the signed block bit array
+ JailedUntilHeight int64 // Block height until which the validator is jailed,
+ // or sentinel value of 0 for not jailed
+ SignedBlocksCounter int64 // Running counter of signed blocks
}
```
@@ -49,3 +50,31 @@ Where:
* `IndexOffset` is incremented each time the candidate was a bonded validator in a block (and may have signed a precommit or not).
* `JailedUntil` is set whenever the candidate is jailed due to downtime
* `SignedBlocksCounter` is a counter kept to avoid unnecessary array reads. `SignedBlocksBitArray.Sum() == SignedBlocksCounter` always.
+
+## Slashing Period
+
+A slashing period is a start and end block height associated with a particular validator,
+within which only the "worst infraction counts" (see the [Overview](overview.md)): the total
+amount of slashing for infractions committed within the period (and discovered whenever) is
+capped at the penalty for the worst offense.
+
+This period starts when a validator is first bonded and ends when a validator is slashed & jailed
+for any reason. When the validator rejoins the validator set (perhaps through unjailing themselves,
+and perhaps also changing signing keys), they enter into a new period.
+
+Slashing periods are indexed in the store as follows:
+
+- SlashingPeriod: ` 0x03 | ValTendermintAddr | StartHeight -> amino(slashingPeriod) `
+
+This allows us to look up slashing period by a validator's address, the only lookup necessary,
+and iterate over start height to efficiently retrieve the most recent slashing period(s)
+or those beginning after a given height.
+
+```go
+type SlashingPeriod struct {
+ ValidatorAddr sdk.ValAddress // Tendermint address of the validator
+ StartHeight int64 // Block height at which slashing period begin
+ EndHeight int64 // Block height at which slashing period ended
+ SlashedSoFar sdk.Rat // Fraction slashed so far, cumulative
+}
+```
diff --git a/docs/spec/slashing/transactions.md b/docs/spec/slashing/transactions.md
index cdf495e4d..be33ee096 100644
--- a/docs/spec/slashing/transactions.md
+++ b/docs/spec/slashing/transactions.md
@@ -1,19 +1,40 @@
+## Transactions
-### TxProveLive
+In this section we describe the processing of transactions for the `slashing` module.
-If a validator was automatically unbonded due to liveness issues and wishes to
-assert it is still online, it can send `TxProveLive`:
+### Unjail
-```golang
-type TxProveLive struct {
- PubKey crypto.PubKey
+If a validator was automatically unbonded due to downtime and wishes to come back online &
+possibly rejoin the bonded set, it must send `TxUnjail`:
+
+```
+type TxUnjail struct {
+ ValidatorAddr sdk.AccAddress
}
+
+handleMsgUnjail(tx TxUnjail)
+
+ validator = getValidator(tx.ValidatorAddr)
+ if validator == nil
+ fail with "No validator found"
+
+ if !validator.Jailed
+ fail with "Validator not jailed, cannot unjail"
+
+ info = getValidatorSigningInfo(operator)
+ if block time < info.JailedUntil
+ fail with "Validator still jailed, cannot unjail until period has expired"
+
+ // Update the start height so the validator won't be immediately unbonded again
+ info.StartHeight = BlockHeight
+ setValidatorSigningInfo(info)
+
+ validator.Jailed = false
+ setValidator(validator)
+
+ return
```
-All delegators in the temporary unbonding pool which have not
-transacted to move will be bonded back to the now-live validator and begin to
-once again collect provisions and rewards.
-
-```
-TODO: pseudo-code
-```
+If the validator has enough stake to be in the top `n = MaximumBondedValidators`, they will be automatically rebonded,
+and all delegators still delegated to the validator will be rebonded and begin to again collect
+provisions and rewards.
diff --git a/version/version.go b/version/version.go
index 707868ae0..8bfea9577 100644
--- a/version/version.go
+++ b/version/version.go
@@ -3,9 +3,9 @@ package version
const Maj = "0"
const Min = "24"
-const Fix = "1"
+const Fix = "2"
-const Version = "0.24.1"
+const Version = "0.24.2"
// GitCommit set by build flags
var GitCommit = ""