Skip to content

Commit

Permalink
v0.36.0-rc6 🍒 Picks
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored Aug 13, 2019
2 parents 5742d13 + f4b3455 commit 118aa61
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 127 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@

### Bug Fixes

* [\#4891](https://github.com/cosmos/cosmos-sdk/issues/4891) Disable querying with proofs enabled when the query height <= 1.
* (rest) [\#4858](https://github.com/cosmos/cosmos-sdk/issues/4858) Do not return an error in BroadcastTxCommit when the tx broadcasting
was successful. This allows the proper REST response to be returned for a
failed tx during `block` broadcasting mode.
* (store) [\#4880](https://github.com/cosmos/cosmos-sdk/pull/4880) Fix error check in
IAVL `Store#DeleteVersion`.
* (tendermint) [\#4879](https://github.com/cosmos/cosmos-sdk/issues/4879) Don't terminate the process immediately after startup when run in standalone mode.
* (simulation) [\#4861](https://github.com/cosmos/cosmos-sdk/pull/4861) Fix non-determinism simulation
by using CLI flags as input and updating Makefile target.
* [\#4868](https://github.com/cosmos/cosmos-sdk/issues/4868) Context#CacheContext now sets a new EventManager. This prevents unwanted events
Expand Down
7 changes: 4 additions & 3 deletions client/context/broadcast.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ func (ctx CLIContext) BroadcastTx(txBytes []byte) (res sdk.TxResponse, err error
}

// BroadcastTxCommit broadcasts transaction bytes to a Tendermint node and
// waits for a commit.
// waits for a commit. An error is only returned if there is no RPC node
// connection or if broadcasting fails.
//
// NOTE: This should ideally not be used as the request may timeout but the tx
// may still be included in a block. Use BroadcastTxAsync or BroadcastTxSync
Expand All @@ -47,11 +48,11 @@ func (ctx CLIContext) BroadcastTxCommit(txBytes []byte) (sdk.TxResponse, error)
}

if !res.CheckTx.IsOK() {
return sdk.NewResponseFormatBroadcastTxCommit(res), fmt.Errorf(res.CheckTx.Log)
return sdk.NewResponseFormatBroadcastTxCommit(res), nil
}

if !res.DeliverTx.IsOK() {
return sdk.NewResponseFormatBroadcastTxCommit(res), fmt.Errorf(res.DeliverTx.Log)
return sdk.NewResponseFormatBroadcastTxCommit(res), nil
}

return sdk.NewResponseFormatBroadcastTxCommit(res), nil
Expand Down
8 changes: 7 additions & 1 deletion client/context/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,19 @@ func (ctx CLIContext) GetFromName() string {

// query performs a query to a Tendermint node with the provided store name
// and path. It returns the result and height of the query upon success
// or an error if the query fails.
// or an error if the query fails. In addition, it will verify the returned
// proof if TrustNode is disabled. If proof verification fails or the query
// height is invalid, an error will be returned.
func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, height int64, err error) {
node, err := ctx.GetNode()
if err != nil {
return res, height, err
}

if ctx.Height <= 1 && !ctx.TrustNode {
return res, height, errors.New("cannot query with proof when height <= 1; please provide a valid height")
}

opts := rpcclient.ABCIQueryOptions{
Height: ctx.Height,
Prove: !ctx.TrustNode,
Expand Down
45 changes: 29 additions & 16 deletions docs/spec/slashing/01_concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,33 @@

## 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.
At any given time, there are any number of validators registered in the state
machine. Each block, the top `MaxValidators` (defined by `x/staking`) 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.

For each of these validators we keep a `ValidatorSigningInfo` record that contains
information partaining to validator's liveness and other infraction related
attributes.

## Tombstone Caps

In order to mitigate the impact of initially likely categories of non-malicious protocol faults, the Cosmos Hub implements for each validator
a *tombstone* cap, which only allows a validator to be slashed once for a double sign fault. 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 tombstombed). This will still be quite expensive and desirable
to avoid, but tombstone caps somewhat blunt the economic impact of unintentional misconfiguration.
In order to mitigate the impact of initially likely categories of non-malicious
protocol faults, the Cosmos Hub implements for each validator
a *tombstone* cap, which only allows a validator to be slashed once for a double
sign fault. 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 tombstombed). This will still be quite expensive and desirable to avoid, but tombstone caps
somewhat blunt the economic impact of unintentional misconfiguration.

Liveness faults do not have caps, as they can't stack upon each other. Liveness bugs are "detected" as soon as the infraction occurs, and the validators are immediately put in jail, so it is not possible for them to commit multiple liveness faults without unjailing in between.

## ASCII timelines
## Infraction Timelines

To illustrate how the `x/slashing` module handles submitted evidence through
Tendermint consensus, consider the following examples:

*Code*
__Definitions__:

*[* : timeline start
*]* : timeline end
Expand All @@ -26,17 +37,19 @@ Liveness faults do not have caps, as they can't stack upon each other. Liveness
*V<sub>b</sub>* : validator bonded
*V<sub>u</sub>* : validator unbonded

*Single Double Sign Infraction*
### Single Double Sign Infraction

<----------------->
<----------------->
[----------C<sub>1</sub>----D<sub>1</sub>,V<sub>u</sub>-----]

A single infraction is committed then later discovered, at which point the validator is unbonded and slashed at the full amount for the infraction.
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 Double Sign Infractions*
### Multiple Double Sign Infractions

<--------------------------->
<--------------------------->
[----------C<sub>1</sub>--C<sub>2</sub>---C<sub>3</sub>---D<sub>1</sub>,D<sub>2</sub>,D<sub>3</sub>V<sub>u</sub>-----]

Multiple infractions are committed and then later discovered, at which point the validator is jailed and slashed for only one infraction.
Because the validator is also tombstoned, they can not rejoin the validator set.
Multiple infractions are committed and then later discovered, at which point the
validator is jailed and slashed for only one infraction. Because the validator
is also tombstoned, they can not rejoin the validator set.
74 changes: 41 additions & 33 deletions docs/spec/slashing/02_state.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,62 @@
# State

## Signing Info
## Signing Info (Liveness)

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.
Every block includes a set of precommits by the validators for the previous block,
known as the `LastCommitInfo` provided by Tendermint. A `LastCommitInfo` is valid so
long as it contains precommits from +2/3 of total voting power.

Proposers are incentivized to include precommits from all
validators in the LastCommit by receiving additional fees
proportional to the difference between the voting power included in the
LastCommit and +2/3 (see [TODO](https://github.com/cosmos/cosmos-sdk/issues/967)).
Proposers are incentivized to include precommits from all validators in the `LastCommitInfo`
by receiving additional fees proportional to the difference between the voting
power included in the `LastCommitInfo` and +2/3 (see [TODO](https://github.com/cosmos/cosmos-sdk/issues/967)).

Validators are penalized for failing to be included in the LastCommit for some
number of blocks by being automatically unbonded.
Validators are penalized for failing to be included in the `LastCommitInfo` for some
number of blocks by being automatically jailed, potentially slashed, and unbonded.

Information about validator activity is tracked in a `ValidatorSigningInfo`.
Information about validator's liveness activity is tracked through `ValidatorSigningInfo`.
It is indexed in the store as follows:

- SigningInfo: ` 0x01 | ValTendermintAddr -> amino(valSigningInfo)`
- MissedBlocksBitArray: ` 0x02 | ValTendermintAddr | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)`
- ValidatorSigningInfo: ` 0x01 | ConsAddress -> amino(valSigningInfo)`
- MissedBlocksBitArray: ` 0x02 | ConsAddress | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)`

The first map allows us to easily lookup the recent signing info for a
validator, according to the Tendermint validator address. The second map acts as
a bit-array of size `SIGNED_BLOCKS_WINDOW` that tells us if the validator missed the block for a given index in the bit-array.

The index in the bit-array is given as little endian uint64.
The first mapping allows us to easily lookup the recent signing info for a
validator based on the validator's consensus address. The second mapping acts
as a bit-array of size `SignedBlocksWindow` that tells us if the validator missed
the block for a given index in the bit-array. The index in the bit-array is given
as little endian uint64.

The result is a `varint` that takes on `0` or `1`, where `0` indicates the
validator did not miss (did sign) the corresponding block, and `1` indicates they missed the block (did not sign).
validator did not miss (did sign) the corresponding block, and `1` indicates
they missed the block (did not sign).

Note that the MissedBlocksBitArray is not explicitly initialized up-front. Keys are
added as we progress through the first `SIGNED_BLOCKS_WINDOW` blocks for a newly
bonded validator.
Note that the `MissedBlocksBitArray` is not explicitly initialized up-front. Keys
are added as we progress through the first `SignedBlocksWindow` blocks for a newly
bonded validator. The `SignedBlocksWindow` parameter defines the size
(number of blocks) of the sliding window used to track validator liveness.

The information stored for tracking validator liveness is as follows:

```go
type ValidatorSigningInfo struct {
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
Tombstoned bool // Whether a validator is tombstoned or not
MissedBlocksCounter int64 // Running counter of missed blocks
Address sdk.ConsAddress
StartHeight int64
IndexOffset int64
JailedUntil time.Time
Tombstoned bool
MissedBlocksCounter int64
}

```

Where:
* `StartHeight` is set to the height that the candidate became an active validator (with non-zero voting power).
* `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
* `Tombstoned` is set once a validator's first double sign evidence comes in
* `MissedBlocksCounter` is a counter kept to avoid unnecessary array reads. `MissedBlocksBitArray.Sum() == MissedBlocksCounter` always.

- __Address__: The validator's consensus address.
- __StartHeight__: The height that the candidate became an active validator
(with non-zero voting power).
- __IndexOffset__: Index which is incremented each time the validator was a bonded
in a block and may have signed a precommit or not. This in conjunction with the
`SignedBlocksWindow` param determines the index in the `MissedBlocksBitArray`.
- __JailedUntil__: Time for which the validator is jailed until due to liveness downtime.
- __Tombstoned__: Desribes if the validator is tombstoned or not. It is set once the
validator commits an equivocation or for any other configured misbehiavor.
- __MissedBlocksCounter__: A counter kept to avoid unnecessary array reads. Note
that `Sum(MissedBlocksBitArray)` equals `MissedBlocksCounter` always.
Loading

0 comments on commit 118aa61

Please sign in to comment.