Skip to content

Commit 01f9698

Browse files
stana-miricgithub-actionsmpoke
authored
feat!: Customizable Slashing and Jailing (#2403)
* Customizable Slashing and Jailing * additional tests * relay test fixes * integration tests fix * migrations * slash with right params * comment fix * docs * Revert "migrations" This reverts commit f1e7c6a. * cr fix * updrade.md update * cr fix * Update testing documentation * update changelog entries --------- Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: mpoke <marius.poke@posteo.de>
1 parent 331c1c9 commit 01f9698

37 files changed

+2258
-532
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- `[x/provider]` Enable the customization of the slashing and jailing conditions
2+
for infractions committed by validators on consumer chains (as per
3+
[ADR 020](https://cosmos.github.io/interchain-security/adrs/adr-020-cutomizable_slashing_and_jailing)).
4+
Every consumer chain can decide the punishment for every type of infraction.
5+
([\#2403](https://github.com/cosmos/interchain-security/pull/2403))
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- `[x/provider]` Enable the customization of the slashing and jailing conditions
2+
for infractions committed by validators on consumer chains (as per
3+
[ADR 020](https://cosmos.github.io/interchain-security/adrs/adr-020-cutomizable_slashing_and_jailing)).
4+
Every consumer chain can decide the punishment for every type of infraction.
5+
([\#2403](https://github.com/cosmos/interchain-security/pull/2403))

UPGRADING.md

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,46 @@
1-
# Upgrading Replicated Security
1+
# Upgrading Interchain Security
22

33
## Unreleased
44

5+
### Provider
6+
7+
Upgrading a provider from v6.2.0 requires state migrations. The following migrators should be added to the upgrade handler of the provider chain:
8+
9+
```golang
10+
// Initializes infraction parameters for each active consumer. During slashing and jailing of validators for misbehavior on the consumer chain, the parameters defined for that specific consumer will be used. Initially, default values are set, which can later be customized for each consumer as needed.
11+
func SetConsumerInfractionParams(ctx sdk.Context, pk providerkeeper.Keeper) error {
12+
infractionParameters := DefaultInfractionParams()
13+
14+
activeConsumerIds := pk.GetAllActiveConsumerIds(ctx)
15+
for _, consumerId := range activeConsumerIds {
16+
if err := pk.SetInfractionParameters(ctx, consumerId, infractionParameters); err != nil {
17+
return err
18+
}
19+
}
20+
21+
return nil
22+
}
23+
24+
func DefaultInfractionParams() providertypes.InfractionParameters {
25+
return providertypes.InfractionParameters{
26+
DoubleSign: &providertypes.SlashJailParameters{
27+
JailDuration: time.Duration(1<<63 - 1), // the largest value a time.Duration can hold 9223372036854775807 (approximately 292 years)
28+
SlashFraction: math.LegacyNewDecWithPrec(5, 2), // 0.05
29+
},
30+
Downtime: &providertypes.SlashJailParameters{
31+
JailDuration: 600 * time.Second,
32+
SlashFraction: math.LegacyNewDec(0), // no slashing for downtime on the consumer
33+
},
34+
}
35+
}
36+
```
37+
38+
## v6.3.x
39+
40+
Upgrading from `v6.2.0` will not require state migration. To upgrade from lower versions, please check the sections below.
41+
42+
## v6.2.x
43+
544
### Consumer
645

746
Upgrading a consumer from v4.4.x to v4.5.x and from v5.x or v6.1.x to v6.2.x requires state migrations. The following migrators should be added to the upgrade handler of the consumer chain:
@@ -22,6 +61,13 @@ func InitializeConsumerId(ctx sdk.Context, consumerKeeper consumerkeeper.Keeper)
2261
}
2362
```
2463

64+
## [v6.1.x](https://github.com/cosmos/interchain-security/releases/tag/v6.1.0)
65+
66+
Upgrading from `v6.0.0` will not require state migration.
67+
68+
69+
## [v6.0.x](https://github.com/cosmos/interchain-security/releases/tag/v6.0.0)
70+
2571
### Provider
2672

2773
Upgrading a provider from v5.1.x requires state migrations. The following migrators should be added to the upgrade handler of the provider chain:
@@ -378,4 +424,4 @@ Upgrading a provider from `v1.1.0-multiden` to `v2.0.0` will require state migra
378424

379425
### Consumer
380426

381-
Upgrading a consumer from `v1.2.0-multiden` to `v2.0.0` will NOT require state migrations.
427+
Upgrading a consumer from `v1.2.0-multiden` to `v2.0.0` will NOT require state migrations.

docs/docs/build/modules/02-provider.md

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -482,8 +482,8 @@ message MsgChangeRewardDenoms {
482482
`MsgCreateConsumer` enables a user to create a consumer chain.
483483

484484
Both the `chain_id` and `metadata` fields are mandatory.
485-
The `initialization_parameters`, `power_shaping_parameters`, and `allowlisted_reward_denoms` fields are optional.
486-
The parameters not provided are set to their zero value.
485+
The `initialization_parameters`, `power_shaping_parameters`, `infraction_parameters` and `allowlisted_reward_denoms` fields are optional.
486+
The parameters not provided are set to their zero value. If `infraction_parameters` are not set, the default values currently configured on the provider are used.
487487

488488
The owner of the created consumer chain is the submitter of the message.
489489
This message cannot be submitted as part of a governance proposal, i.e., the submitter cannot be the gov module account address.
@@ -516,6 +516,9 @@ message MsgCreateConsumer {
516516
517517
// allowlisted reward denoms by the consumer chain
518518
AllowlistedRewardDenoms allowlisted_reward_denoms = 6;
519+
520+
// infraction parameters for slashing and jailing
521+
InfractionParameters infraction_parameters = 7;
519522
}
520523
```
521524

@@ -528,7 +531,7 @@ The others fields are optional. Not providing one of them will leave the existin
528531
Providing one of `metadata`, `initialization_parameters`, `power_shaping_parameters`, or `allowlisted_reward_denoms`
529532
will update all the containing fields.
530533
If one of the containing fields is missing, it will be set to its zero value.
531-
For example, updating the `initialization_parameters` without specifying the `spawn_time`, will set the `spawn_time` to zero.
534+
For example, updating the `initialization_parameters` without specifying the `spawn_time`, will set the `spawn_time` to zero.
532535

533536
If the `initialization_parameters` field is set and `initialization_parameters.spawn_time > 0`, then the consumer chain will be scheduled to launch at `spawn_time`.
534537
Updating the `spawn_time` from a positive value to zero will remove the consumer chain from the list of scheduled to launch chains.
@@ -568,6 +571,9 @@ message MsgUpdateConsumer {
568571
569572
// to update the chain id of the chain (can only be updated if the chain has not yet launched)
570573
string new_chain_id = 8;
574+
575+
// infraction parameters for slashing and jailing
576+
InfractionParameters infraction_parameters = 9;
571577
}
572578
```
573579

@@ -829,6 +835,7 @@ In the `BeginBlock` of the provider module the following actions are performed:
829835
- Remove every stopped consumer chain for which the removal time has passed.
830836
- Replenish the throttling meter if necessary.
831837
- Distribute ICS rewards to the opted in validators.
838+
- Update consumer infraction parameters with the queued infraction parameters that were added to the queue before a time period greater than the unbonding time.
832839

833840
Note that for every consumer chain, the computation of its initial validator set is based on the consumer's [power shaping parameters](../../features/power-shaping.md)
834841
and the [validators that opted in on that consumer](../../features/partial-set-security.md).
@@ -2874,6 +2881,16 @@ grpcurl -plaintext -d '{"consumer_id": "0"}' localhost:9090 interchain_security.
28742881
"minStake": "1000",
28752882
"allowInactiveVals": true
28762883
},
2884+
"infraction_parameters":{
2885+
"double_sign":{
2886+
"slash_fraction":"0.050000000000000000",
2887+
"jail_duration":"9223372036.854775807s"
2888+
},
2889+
"downtime":{
2890+
"slash_fraction":"0.000000000000000000",
2891+
"jail_duration":"600s"
2892+
}
2893+
},
28772894
"clientId": "07-tendermint-28"
28782895
}
28792896
```
@@ -3573,6 +3590,17 @@ Output:
35733590
"minStake": "1000",
35743591
"allowInactiveVals": true
35753592
}
3593+
,
3594+
"infraction_parameters":{
3595+
"double_sign":{
3596+
"slash_fraction":"0.050000000000000000",
3597+
"jail_duration":"9223372036.854775807s"
3598+
},
3599+
"downtime":{
3600+
"slash_fraction":"0.000000000000000000",
3601+
"jail_duration":"600s"
3602+
}
3603+
}
35763604
}
35773605
```
35783606

docs/docs/features/slashing.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ The ICS protocol differentiates between downtime and equivocation infractions.
1414
## Downtime Infractions
1515

1616
Downtime infractions are reported by consumer chains and are acted upon on the provider as soon as they are received.
17-
Instead of slashing, the provider will **_only jail_** offending validator for the duration of time established by the provider chain parameters.
18-
Note that validators are only jailed for downtime on consumer chains that they opted in to validate on,
17+
The provider will jail and slash the offending validator. The jailing duration and slashing fraction are determined by the consumer's downtime infraction parameters on the provider chain.
18+
By default, validators are **_only jailed_** for downtime on consumer chains that they opted in to validate on,
1919
or in the case of Top N chains, where they are automatically opted in by being in the Top N% of the validator set on the provider.
2020

2121
For preventing malicious consumer chains from harming the provider, [slash throttling](../adrs/adr-002-throttle.md) (also known as _jail throttling_) ensures that only a fraction of the provider validator set can be jailed at any given time.
@@ -24,7 +24,7 @@ For preventing malicious consumer chains from harming the provider, [slash throt
2424

2525
Equivocation infractions are reported by external agents (e.g., relayers) that can submit to the provider evidence of light client or double signing attacks observed on a consumer chain.
2626
The evidence is submitted by sending `MsgSubmitConsumerMisbehaviour` or `MsgSubmitConsumerDoubleVoting` messages to the provider.
27-
When valid evidence is received, the malicious validators are slashed, jailed, and tombstoned on the provider.
27+
When valid evidence is received, the malicious validators are slashed, jailed, and tombstoned on the provider. The jailing duration and slashing fraction are determined by the consumer's double sign infraction parameters on the provider chain.
2828
This is enabled through the _cryptographic verification of equivocation_ feature.
2929
For more details, see [ADR-005](../adrs/adr-005-cryptographic-equivocation-verification.md) and [ADR-013](../adrs/adr-013-equivocation-slashing.md).
3030

@@ -597,3 +597,7 @@ The following command demonstrates how to run a Hermes instance in _evidence mod
597597
hermes evidence --chain <CONSUMER-CHAIN-ID>
598598
```
599599
Note that `hermes evidence` takes a `--check-past-blocks` option giving the possibility to look for older evidence (default is 100).
600+
601+
### Infraction parameters
602+
603+
Jailing and slashing for misbehavior on a consumer chain are governed by parameters defined on the provider chain for that specific consumer chain. To create or update these infraction parameters, use the MsgCreateConsumer or MsgUpdateConsumer messages. When creating a consumer chain, if custom infraction parameters are not specified, default values from the provider are applied. For updates, parameters can be modified immediately if the chain is in the pre-launch phase. If the chain has already launched, the update will be scheduled to take effect after the unbonding period expires. This ensures that changes are applied seamlessly based on the chain's lifecycle.

proto/interchain_security/ccv/provider/v1/provider.proto

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,3 +556,22 @@ enum ConsumerPhase {
556556
message AllowlistedRewardDenoms {
557557
repeated string denoms = 1;
558558
}
559+
560+
//
561+
message InfractionParameters {
562+
SlashJailParameters double_sign = 1;
563+
SlashJailParameters downtime = 2;
564+
}
565+
566+
//
567+
message SlashJailParameters {
568+
bytes slash_fraction = 1 [
569+
(cosmos_proto.scalar) = "cosmos.Dec",
570+
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
571+
(gogoproto.nullable) = false,
572+
(amino.dont_omitempty) = true
573+
];
574+
// for permanent jailing use 9223372036854775807 which is the largest value a time.Duration can hold (approximately 292 years)
575+
google.protobuf.Duration jail_duration = 2
576+
[ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ];
577+
}

proto/interchain_security/ccv/provider/v1/query.proto

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ message Chain {
209209
// filled with these validators first, and other validators will be added to the validator set only if there are
210210
// not enough eligible priority validators.
211211
repeated string prioritylist = 15;
212+
// Infraction parameters for slashing and jailing
213+
InfractionParameters infraction_parameters = 16;
212214
}
213215

214216
message QueryValidatorConsumerAddrRequest {
@@ -397,9 +399,10 @@ message QueryConsumerChainResponse {
397399
ConsumerMetadata metadata = 5 [ (gogoproto.nullable) = false ];
398400
ConsumerInitializationParameters init_params = 6;
399401
PowerShapingParameters power_shaping_params = 7;
402+
InfractionParameters infraction_parameters = 8;
400403

401404
// corresponds to the id of the client that is created during launch
402-
string client_id = 8;
405+
string client_id = 9;
403406
}
404407

405408
message QueryConsumerGenesisTimeRequest {

proto/interchain_security/ccv/provider/v1/tx.proto

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,9 @@ message MsgCreateConsumer {
363363

364364
// allowlisted reward denoms of the consumer
365365
AllowlistedRewardDenoms allowlisted_reward_denoms = 6;
366+
367+
// infraction parameters for slashing and jailing
368+
InfractionParameters infraction_parameters = 7;
366369
}
367370

368371
// MsgCreateConsumerResponse defines response type for MsgCreateConsumer
@@ -399,6 +402,9 @@ message MsgUpdateConsumer {
399402
// the chain id CANNOT be updated.
400403
// This field is optional and can remain empty (i.e., `new_chain_id = ""`) or correspond to the chain id the chain already has.
401404
string new_chain_id = 8;
405+
406+
// infraction parameters for slashing and jailing
407+
InfractionParameters infraction_parameters = 9;
402408
}
403409

404410
// MsgUpdateConsumerResponse defines response type for MsgUpdateConsumer messages

scripts/test_doc/test_documentation.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@
6565
| Function | Short Description |
6666
|----------|-------------------|
6767
[TestHandleConsumerMisbehaviour](../../tests/integration/misbehaviour.go#L25) | TestHandleConsumerMisbehaviour tests the handling of consumer misbehavior.<details><summary>Details</summary>* Set up a CCV channel and send an empty VSC packet to ensure that the consumer client revision height is greater than 0.<br>* Construct a Misbehaviour object with two conflicting headers and process the equivocation evidence.<br>* Verify that the provider chain correctly processes this misbehavior.<br>* Ensure that all involved validators are jailed, tombstoned, and slashed according to the expected outcomes.<br>* Assert that their tokens are adjusted based on the slashing fraction.</details> |
68-
[TestGetByzantineValidators](../../tests/integration/misbehaviour.go#L101) | TestGetByzantineValidators checks the GetByzantineValidators function on various instances of misbehaviour.<details><summary>Details</summary>* Set up a provider and consumer chain.<br>* Create a header with a subset of the validators on the consumer chain, then create a second header (in a variety of different ways),<br>and check which validators are considered Byzantine by calling the GetByzantineValidators function.<br>* The test scenarios are:<br>- when one of the headers is empty, the function should return an error<br>- when one of the headers has a corrupted validator set (e.g. by a validator having a different public key), the function should return an error<br>- when the signatures in one of the headers are corrupted, the function should return an error<br>- when the attack is an amnesia attack (i.e. the headers have different block IDs), no validator is considered byzantine<br>- for non-amnesia misbehaviour, all validators that signed both headers are considered byzantine</details> |
69-
[TestCheckMisbehaviour](../../tests/integration/misbehaviour.go#L399) | TestCheckMisbehaviour tests that the CheckMisbehaviour function correctly checks for misbehaviour.<details><summary>Details</summary>* Set up a provider and consumer chain.<br>* Create a valid client header and then create a misbehaviour by creating a second header in a variety of different ways.<br>* Check that the CheckMisbehaviour function correctly checks for misbehaviour by verifying that<br>it returns an error when the misbehaviour is invalid and no error when the misbehaviour is valid.<br>* The test scenarios are:<br> - both headers are identical (returns an error)<br> - the misbehaviour is not for the consumer chain (returns an error)<br> - passing an invalid client id (returns an error)<br> - passing a misbehaviour with different header height (returns an error)<br> - passing a misbehaviour older than the min equivocation evidence height (returns an error)<br> - one header of the misbehaviour has insufficient voting power (returns an error)<br> - passing a valid misbehaviour (no error)<br><br>* Test does not test actually submitting the misbehaviour to the chain or freezing the client.</details> |
68+
[TestGetByzantineValidators](../../tests/integration/misbehaviour.go#L102) | TestGetByzantineValidators checks the GetByzantineValidators function on various instances of misbehaviour.<details><summary>Details</summary>* Set up a provider and consumer chain.<br>* Create a header with a subset of the validators on the consumer chain, then create a second header (in a variety of different ways),<br>and check which validators are considered Byzantine by calling the GetByzantineValidators function.<br>* The test scenarios are:<br>- when one of the headers is empty, the function should return an error<br>- when one of the headers has a corrupted validator set (e.g. by a validator having a different public key), the function should return an error<br>- when the signatures in one of the headers are corrupted, the function should return an error<br>- when the attack is an amnesia attack (i.e. the headers have different block IDs), no validator is considered byzantine<br>- for non-amnesia misbehaviour, all validators that signed both headers are considered byzantine</details> |
69+
[TestCheckMisbehaviour](../../tests/integration/misbehaviour.go#L400) | TestCheckMisbehaviour tests that the CheckMisbehaviour function correctly checks for misbehaviour.<details><summary>Details</summary>* Set up a provider and consumer chain.<br>* Create a valid client header and then create a misbehaviour by creating a second header in a variety of different ways.<br>* Check that the CheckMisbehaviour function correctly checks for misbehaviour by verifying that<br>it returns an error when the misbehaviour is invalid and no error when the misbehaviour is valid.<br>* The test scenarios are:<br> - both headers are identical (returns an error)<br> - the misbehaviour is not for the consumer chain (returns an error)<br> - passing an invalid client id (returns an error)<br> - passing a misbehaviour with different header height (returns an error)<br> - passing a misbehaviour older than the min equivocation evidence height (returns an error)<br> - one header of the misbehaviour has insufficient voting power (returns an error)<br> - passing a valid misbehaviour (no error)<br><br>* Test does not test actually submitting the misbehaviour to the chain or freezing the client.</details> |
7070
</details>
7171

7272
# [normal_operations.go](../../tests/integration/normal_operations.go)

tests/integration/double_vote.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,10 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() {
257257

258258
// verifies that the val gets slashed and has fewer tokens after the slashing
259259
val, _ := s.providerApp.GetTestStakingKeeper().GetValidator(provCtx, provAddr.ToSdkConsAddr().Bytes())
260-
slashFraction, err := s.providerApp.GetTestSlashingKeeper().SlashFractionDoubleSign(provCtx)
260+
infractionParam, err := s.providerApp.GetProviderKeeper().GetInfractionParameters(provCtx, tc.consumerId)
261261
s.Require().NoError(err)
262262
actualTokens := math.LegacyNewDecFromInt(val.GetTokens())
263-
s.Require().True(initialTokens.Sub(initialTokens.Mul(slashFraction)).Equal(actualTokens))
263+
s.Require().True(initialTokens.Sub(initialTokens.Mul(infractionParam.DoubleSign.SlashFraction)).Equal(actualTokens))
264264
} else {
265265
s.Require().Error(err)
266266

@@ -409,8 +409,9 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVotingSlashesUndelegationsAndRele
409409
)
410410
s.Require().NoError(err)
411411

412-
slashFraction, err := s.providerApp.GetTestSlashingKeeper().SlashFractionDoubleSign(s.providerCtx())
412+
infractionParam, err := s.providerApp.GetProviderKeeper().GetInfractionParameters(s.providerCtx(), s.getFirstBundle().ConsumerId)
413413
s.Require().NoError(err)
414+
slashFraction := infractionParam.DoubleSign.SlashFraction
414415

415416
// check undelegations are slashed
416417
ubds, _ = s.providerApp.GetTestStakingKeeper().GetUnbondingDelegation(s.providerCtx(), delAddr, valAddr)

0 commit comments

Comments
 (0)