Skip to content

Commit

Permalink
Robert/docs slashing (#8329)
Browse files Browse the repository at this point in the history
* update slashing docs

* x/slashing docs general audit & cleanup

* Update x/slashing/spec/02_state.md

Co-authored-by: Amaury <amaury.martiny@protonmail.com>

* Update x/slashing/spec/05_hooks.md

Co-authored-by: Alessio Treglia <alessio@tendermint.com>

* use code insertion widget

* review update

* Update x/slashing/spec/05_hooks.md

Co-authored-by: Alessio Treglia <alessio@tendermint.com>

* update link and location for fee distribution spec

Co-authored-by: Amaury <amaury.martiny@protonmail.com>
Co-authored-by: Alessio Treglia <alessio@tendermint.com>
  • Loading branch information
3 people authored Jan 15, 2021
1 parent df95ca8 commit d39c42c
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 82 deletions.
2 changes: 1 addition & 1 deletion docs/migrations/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Some important information concerning all legacy REST endpoints:

## Migrating to New REST Endpoints

Thanks to the Protocol Buffers migration in v0.40 we are able to take advantage of a vast number of gRPC tools and solutions. For most of the legacy REST endpoints, Cosmos SDK v0.40 provides new REST endpoints generated from [gRPC `Query` services](../building-modules/query-services.md) using [grpc-gateway](https://grpc-ecosystem.github.io/grpc-gateway/). We usually call them _gGPC-gateway REST endpoints_.
Thanks to the Protocol Buffers migration in v0.40, we are able to take advantage of a vast number of gRPC tools and solutions. For most of the legacy REST endpoints, Cosmos SDK v0.40 provides new REST endpoints generated from [gRPC `Query` services](../building-modules/query-services.md) using [grpc-gateway](https://grpc-ecosystem.github.io/grpc-gateway/). We usually call them _gGPC-gateway REST endpoints_.

Some modules expose legacy `POST` endpoints to generate unsigned transactions for their `Msg`s. These `POST` endpoints have been removed. We recommend to use [service `Msg`s](../building-modules/msg-services.md) directly, and use Protobuf to do client-side transaction generation. A guide can be found [here](../run-node/txs.md).

Expand Down
2 changes: 1 addition & 1 deletion docs/run-node/interact-node.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func queryState() error {

// Create a connection to the gRPC server.
grpcConn := grpc.Dial(
"127.0.0.1:9090", // Or your gRPC server address.
"127.0.0.1:9090", // your gRPC server address.
grpc.WithInsecure(), // The SDK doesn't support any transport security mechanism.
)
defer grpcConn.Close()
Expand Down
19 changes: 9 additions & 10 deletions docs/run-node/txs.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ will run the following steps:

- generate a transaction with one `Msg` (`x/bank`'s `MsgSend`), and print the generated transaction to the console.
- ask the user for confirmation to send the transaction from the `$MY_VALIDATOR_ADDRESS` account.
- fetch `$MY_VALIDATOR_ADDRESS` in the keyring. This is possible because we have [set up the CLI's keyring](./keyring.md) in a previous step.
- fetch `$MY_VALIDATOR_ADDRESS` from the keyring. This is possible because we have [set up the CLI's keyring](./keyring.md) in a previous step.
- sign the generated transaction with the keyring's account.
- broadcast the signed transaction to the network. This is possible because the CLI connects to the node's Tendermint RPC endpoint.

Expand Down Expand Up @@ -52,22 +52,21 @@ Some useful flags to consider in the `tx sign` command:
#### Signing with Multiple Signers

::: warning
Please note that signing a transaction with multiple signers or with a multisig account, where at least one signer uses `SIGN_MODE_DIRECT`, is not possible as of yet. You may follow [this Github issue](https://github.com/cosmos/cosmos-sdk/issues/8141) for more info.
Please note that signing a transaction with multiple signers or with a multisig account, where at least one signer uses `SIGN_MODE_DIRECT`, is not yet possible. You may follow [this Github issue](https://github.com/cosmos/cosmos-sdk/issues/8141) for more info.
:::

Signing with multiple signers is done with the `tx multisign` command. This command assumes that all signers use `SIGN_MODE_LEGACY_AMINO_JSON`. The flow is similar to the `tx sign` command flow, but instead of signing an unsigned transaction file, each signer signs the file signed by previous signer(s). The `tx multisign` command will append signatures to the existing transactions. It is important that signers sign the transaction **in the same order** as given by the transaction, which is retrievable using the `GetSigners()` method.

For example, starting with the `unsigned_tx.json`, and assuming the transaction has 4 signers, we would run:

```bash
# Let signer 1 sign the unsigned tx.
# Let signer1 sign the unsigned tx.
simd tx multisignsign unsigned_tx.json signer_key_1 --chain-id my-test-chain --keyring-backend test > partial_tx_1.json
# Signer 2 appends their signature.
# Now signer1 will send the partial_tx_1.json to the signer2.
# Signer2 appends their signature:
simd tx multisignsign partial_tx_1.json signer_key_2 --chain-id my-test-chain --keyring-backend test > partial_tx_2.json
# Signer 3 appends their signature.
# Signer2 sends the partial_tx_2.json file to signer3, and signer3 can append his signature:
simd tx multisignsign partial_tx_2.json signer_key_3 --chain-id my-test-chain --keyring-backend test > partial_tx_3.json
# Signer 4 appends their signature. The final output is the fully signed tx.
simd tx multisignsign partial_tx_3.json signer_key_4 --chain-id my-test-chain --keyring-backend test > signed_tx.json
```

### Broadcasting a Transaction
Expand Down Expand Up @@ -154,7 +153,7 @@ At this point, `TxBuilder`'s underlying transaction is ready to be signed.

### Signing a Transaction

We chose our encoding config to use Protobuf, which will use `SIGN_MODE_DIRECT` by default. As per [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/docs/architecture/adr-020-protobuf-transaction-encoding.md), each signer needs to sign the `SignerInfo`s of all other signers. This means that we need to perform two steps sequentially:
We set encoding config to use Protobuf, which will use `SIGN_MODE_DIRECT` by default. As per [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/docs/architecture/adr-020-protobuf-transaction-encoding.md), each signer needs to sign the `SignerInfo`s of all other signers. This means that we need to perform two steps sequentially:

- for each signer, populate the signer's `SignerInfo` inside `TxBuilder`,
- once all `SignerInfo`s are populated, for each signer, sign the `SignDoc` (the payload to be signed).
Expand Down Expand Up @@ -254,7 +253,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/tx"
)

func sendTx() error {
func sendTx(ctx context.Context) error {
// --snip--

// Create a connection to the gRPC server.
Expand All @@ -269,7 +268,7 @@ func sendTx() error {
txClient := tx.NewServiceClient(grpcConn)
// We then call the BroadcastTx method on this client.
grpcRes, err := txClient.BroadcastTx(
context.Background(),
ctx,
&tx.BroadcastTxRequest{
Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC,
TxBytes: txBytes, // Proto-binary of the signed transaction, see previous step.
Expand Down
3 changes: 0 additions & 3 deletions docs/spec/_proposals/README.md

This file was deleted.

File renamed without changes.
File renamed without changes.
15 changes: 9 additions & 6 deletions proto/cosmos/slashing/v1beta1/slashing.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,20 @@ message ValidatorSigningInfo {
option (gogoproto.goproto_stringer) = false;

string address = 1;
// height at which validator was first a candidate OR was unjailed
// Height at which validator was first a candidate OR was unjailed
int64 start_height = 2 [(gogoproto.moretags) = "yaml:\"start_height\""];
// index offset into signed block bit array
// 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`.
int64 index_offset = 3 [(gogoproto.moretags) = "yaml:\"index_offset\""];
// timestamp validator cannot be unjailed until
// Timestamp until which the validator is jailed due to liveness downtime.
google.protobuf.Timestamp jailed_until = 4
[(gogoproto.moretags) = "yaml:\"jailed_until\"", (gogoproto.stdtime) = true, (gogoproto.nullable) = false];
// whether or not a validator has been tombstoned (killed out of validator
// set)
// Whether or not a validator has been tombstoned (killed out of validator set). It is set
// once the validator commits an equivocation or for any other configured misbehiavor.
bool tombstoned = 5;
// missed blocks counter (to avoid scanning the array every time)
// A counter kept to avoid unnecessary array reads.
// Note that `Sum(MissedBlocksBitArray)` always equals `MissedBlocksCounter`.
int64 missed_blocks_counter = 6 [(gogoproto.moretags) = "yaml:\"missed_blocks_counter\""];
}

Expand Down
53 changes: 15 additions & 38 deletions x/slashing/spec/02_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,33 @@ Every block includes a set of precommits by the validators for the previous bloc
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 `LastCommitInfo`
Proposers are incentivized to include precommits from all validators in the Tendermint `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)).
power included in the `LastCommitInfo` and +2/3 (see [fee distribution](https://github.com/cosmos/cosmos-sdk/blob/master/docs/spec/fee_distribution)).

```
type LastCommitInfo struct {
Round int32
Votes []VoteInfo
}
```

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's liveness activity is tracked through `ValidatorSigningInfo`.
It is indexed in the store as follows:

- ValidatorSigningInfo: ` 0x01 | ConsAddress -> amino(valSigningInfo)`
- MissedBlocksBitArray: ` 0x02 | ConsAddress | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)`
- ValidatorSigningInfo: ` 0x01 | ConsAddress -> ProtocolBuffer(ValSigningInfo)`
- MissedBlocksBitArray: ` 0x02 | ConsAddress | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)` (varint is a number encoding format)

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
validator based on the validator's consensus address.

The second mapping (`MissedBlocksBitArray`) 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).
Expand All @@ -40,35 +48,4 @@ bonded validator. The `SignedBlocksWindow` parameter defines the size

The information stored for tracking validator liveness is as follows:

```protobuf
// ValidatorSigningInfo defines a validator's signing info for monitoring their
// liveness activity.
message ValidatorSigningInfo {
string address = 1;
// height at which validator was first a candidate OR was unjailed
int64 start_height = 2;
// index offset into signed block bit array
int64 index_offset = 3;
// timestamp validator cannot be unjailed until
google.protobuf.Timestamp jailed_until = 4;
// whether or not a validator has been tombstoned (killed out of validator
// set)
bool tombstoned = 5;
// missed blocks counter (to avoid scanning the array every time)
int64 missed_blocks_counter = 6;
}
```

Where:

- **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.
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/slashing/v1beta1/slashing.proto#L11-L33
9 changes: 6 additions & 3 deletions x/slashing/spec/03_messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ message MsgUnjail {
}
```

And below is its corresponding handler:
Below is a pseudocode of the `MsgSrv/Unjail` RPC:

```
handleMsgUnjail(tx MsgUnjail)
unjail(tx MsgUnjail)
validator = getValidator(tx.ValidatorAddr)
if validator == nil
fail with "No validator found"
if getSelfDelegation(validator) == 0
fail with "validator must self delegate before unjailing"
if !validator.Jailed
fail with "Validator not jailed, cannot unjail"
Expand All @@ -43,6 +46,6 @@ handleMsgUnjail(tx MsgUnjail)
return
```

If the validator has enough stake to be in the top `n = MaximumBondedValidators`, they will be automatically rebonded,
If the validator has enough stake to be in the top `n = MaximumBondedValidators`, it will be automatically rebonded,
and all delegators still delegated to the validator will be rebonded and begin to again collect
provisions and rewards.
13 changes: 12 additions & 1 deletion x/slashing/spec/05_hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,18 @@ order: 5

# Hooks

In this section we describe the "hooks" - slashing module code that runs when other events happen.
This section contains a description of the module's `hooks`. Hooks are operations that are executed automatically when events are raised.

## Staking hooks

The slashing module implements the `StakingHooks` defined in `x/staking` and are used as record-keeping of validators information. During the app initialization, these hooks should be registered in the staking module struct.

The following hooks impact the slashing state:

+ `AfterValidatorBonded` creates a `ValidatorSigningInfo` instance as described in the following section.
+ `AfterValidatorCreated` stores a validator's consensus key.
+ `AfterValidatorRemoved` removes a validator's consensus key.


## Validator Bonded

Expand Down
30 changes: 22 additions & 8 deletions x/slashing/spec/06_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,19 @@ order: 6

The slashing module emits the following events/tags:

## BeginBlocker
## MsgServer

### MsgUnjail

| Type | Attribute Key | Attribute Value |
| ------- | ------------- | --------------- |
| message | module | slashing |
| message | sender | {validatorAddress} |


## Keeper

## BeginBlocker: HandleValidatorSignature

| Type | Attribute Key | Attribute Value |
| ----- | ------------- | --------------------------- |
Expand All @@ -23,12 +35,14 @@ The slashing module emits the following events/tags:
| liveness | missed_blocks | {missedBlocksCounter} |
| liveness | height | {blockHeight} |

## Handlers

### MsgUnjail
### Slash

| Type | Attribute Key | Attribute Value |
| ------- | ------------- | --------------- |
| message | module | slashing |
| message | action | unjail |
| message | sender | {senderAddress} |
+ same as `"slash"` event from `HandleValidatorSignature`, but without the `jailed` attribute.

### Jail


| Type | Attribute Key | Attribute Value |
| ----- | ------------- | ------------------ |
| slash | jailed | {validatorAddress} |
10 changes: 6 additions & 4 deletions x/slashing/spec/07_tombstone.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,17 @@ Currently, in the jail period implementation, once a validator unjails, all of
their delegators who are delegated to them (haven't unbonded / redelegated away),
stay with them. Given that consensus safety faults are so egregious
(way more so than liveness faults), it is probably prudent to have delegators not
"auto-rebond" to the validator. Thus, we propose setting the "jail time" for a
"auto-rebond" to the validator.

### Proposal: infinite jail

We propose setting the "jail time" for a
validator who commits a consensus safety fault, to `infinite` (i.e. a tombstone state).
This essentially kicks the validator out of the validator set and does not allow
them to re-enter the validator set. All of their delegators (including the operator themselves)
have to either unbond or redelegate away. The validator operator can create a new
validator if they would like, with a new operator key and consensus key, but they
have to "re-earn" their delegations back. To put the validator in the tombstone
state, we set `DoubleSignJailEndTime` to `time.Unix(253402300800)`, the maximum
time supported by Amino.
have to "re-earn" their delegations back.

Implementing the tombstone system and getting rid of the slashing period tracking
will make the `slashing` module way simpler, especially because we can remove all
Expand Down
14 changes: 7 additions & 7 deletions x/slashing/spec/08_params.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ order: 8

The slashing module contains the following parameters:

| Key | Type | Example |
| ----------------------- | ---------------- | ---------------------- |
| SignedBlocksWindow | string (int64) | "100" |
| MinSignedPerWindow | string (dec) | "0.500000000000000000" |
| DowntimeJailDuration | string (time ns) | "600000000000" |
| SlashFractionDoubleSign | string (dec) | "0.050000000000000000" |
| SlashFractionDowntime | string (dec) | "0.010000000000000000" |
| Key | Type | Example |
| ----------------------- | -------------- | ---------------------- |
| SignedBlocksWindow | string (int64) | "100" |
| MinSignedPerWindow | string (dec) | "0.500000000000000000" |
| DowntimeJailDuration | string (ns) | "600000000000" |
| SlashFractionDoubleSign | string (dec) | "0.050000000000000000" |
| SlashFractionDowntime | string (dec) | "0.010000000000000000" |

0 comments on commit d39c42c

Please sign in to comment.