Skip to content

Commit

Permalink
feat: Added query for provider parameters (backport #1605) (#1612)
Browse files Browse the repository at this point in the history
* feat: Added query for provider parameters (#1605)

Added query for provider parameters

(cherry picked from commit f5afcb7)

# Conflicts:
#	x/ccv/provider/types/query.pb.go

* Updated proto-gen files

* fix gofumped warning

* Fix broken md-link

---------

Co-authored-by: bernd-m <43466467+bermuell@users.noreply.github.com>
Co-authored-by: Bernd Mueller <bernd@informal.systems>
  • Loading branch information
3 people committed Jan 31, 2024
1 parent 6c38bd9 commit 50b28ff
Show file tree
Hide file tree
Showing 9 changed files with 764 additions and 316 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Added query for current values of all provider parameters
([\#1605](https://github.com/cosmos/interchain-security/pull/1605))
76 changes: 38 additions & 38 deletions docs/docs/adrs/adr-005-cryptographic-equivocation-verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ Accepted

## Context

Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks).
Every proposal needs to go through a (two weeks) voting period before it can be approved.
Currently, we use a governance proposal to slash validators for equivocation (double signing and light client attacks).
Every proposal needs to go through a (two weeks) voting period before it can be approved.
Given a three-week unbonding period, this means that an equivocation proposal needs to be submitted within one week since the infraction occurred.

This ADR proposes a system to slash validators automatically for equivocation, immediately upon the provider chain's receipt of the evidence. Another thing to note is that we intend to introduce this system in stages, since even the partial ability to slash and/or tombstone is a strict improvement in security.
Expand All @@ -27,7 +27,7 @@ The feature is implemented in two parts, each with its dedicated endpoint. One e

In a nutshell, the light client is a process that solely verifies a specific state machine's
consensus without executing the transactions. The light clients get new headers by querying
multiple nodes, called primary and witness nodes.
multiple nodes, called primary and witness nodes.

Light clients download new headers committed on chain from a primary. Headers can be verified in two ways: sequentially,
where the block height of headers is serial, or using skipping. This second verification method allows light clients to download headers
Expand All @@ -41,7 +41,7 @@ and both headers are successfully verified, it indicates a light client attack.
Note that in this case, either the primary or the witness or both are malicious.

The types of light client attacks are defined by analyzing the differences between the conflicting headers.
There are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack.
There are three types of light client attacks: lunatic attack, equivocation attack, and amnesia attack.
For details, see the [CometBFT specification](https://github.com/cometbft/cometbft/blob/main/spec/light-client/attacks/notes-on-evidence-handling.md#evidence-handling).

When a light client agent detects two conflicting headers, it will initially verify their traces (see [cometBFT detector](https://github.com/cometbft/cometbft/blob/v0.34.28/light/detector.go#L28)) using its primary and witness nodes.
Expand All @@ -61,22 +61,22 @@ light client, halting any further trust in or updating of its states.

### Double Signing Attack

A double signing attack, also known as equivocation,
occurs when a validator votes for two different blocks in the same round of the CometBFT consensus.
This consensus mechanism operates with multiple voting rounds at each block height,
and it strictly prohibits sending two votes of the same type during a round
A double signing attack, also known as equivocation,
occurs when a validator votes for two different blocks in the same round of the CometBFT consensus.
This consensus mechanism operates with multiple voting rounds at each block height,
and it strictly prohibits sending two votes of the same type during a round
(see [CometBFT State Machine Overview](https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/consensus.md#state-machine-overview)).

When a node observes two votes from the same peer, it will use these two votes to create
a [`DuplicateVoteEvidence`](https://github.com/cometbft/cometbft/blob/v0.34.28/types/evidence.go#L35)
evidence and gossip it to the other nodes in the network
(see [CometBFT equivocation detection](https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#detection)).
Each node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block.
During the evidence verification process, the signatures of the conflicting votes must be verified successfully.
When a node observes two votes from the same peer, it will use these two votes to create
a [`DuplicateVoteEvidence`](https://github.com/cometbft/cometbft/blob/v0.34.28/types/evidence.go#L35)
evidence and gossip it to the other nodes in the network
(see [CometBFT equivocation detection](https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#detection)).
Each node will then verify the evidence according to the CometBFT rules that define a valid double signing infraction, and based on this verification, they will decide whether to add the evidence to a block.
During the evidence verification process, the signatures of the conflicting votes must be verified successfully.
Note that this is achieved using the public key of the misbehaving validator, along with the chain ID of the chain where the infraction occurred (see [CometBFT equivocation verification](https://github.com/cometbft/cometbft/blob/v0.34.28/spec/consensus/evidence.md#verification)).

Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer.
The application will, in turn, punish the malicious validator through jailing, tombstoning and slashing
Once a double signing evidence is committed to a block, the consensus layer will report the equivocation to the evidence module of the Cosmos SDK application layer.
The application will, in turn, punish the malicious validator through jailing, tombstoning and slashing
(see [handleEquivocationEvidence](https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/keeper/infraction.go#L263)).


Expand All @@ -87,37 +87,37 @@ The application will, in turn, punish the malicious validator through jailing, t
In the first part of the feature, we introduce a new endpoint: `HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmtypes.Misbehaviour)`.
The main idea is to leverage the current IBC misbehaviour handling and update it to solely jail and slash the validators that
performed a light client attack. Note that in this context, we assume that chains connected via a light client
share the same validator set, as is the case with Replicated Security.
share the same validator set, as is the case with Replicated Security.

This endpoint reuses the IBC client libraries to verify that the misbehaviour headers would have fooled the light client.
Additionally, it’s crucial that the endpoint logic results in the slashing and jailing of validators under the same conditions
as a light client agent detector. Therefore, the endpoint ensures that the two conditions are met:
the headers in the misbehaviour message have the same block height, and
the light client isn’t expired.

After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module.
After having successfully verified a misbehaviour, the endpoint executes the jailing and slashing of the malicious validators similarly as in the evidence module.

### Double Signing Attack

In the second part of the feature, we introduce a new endpoint `HandleConsumerDoubleVoting(
ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey)`.
Simply put, the handling logic verifies a double signing evidence against a provided
ctx sdk.Context, evidence *tmtypes.DuplicateVoteEvidence, chainID string, pubkey cryptotypes.PubKey)`.
Simply put, the handling logic verifies a double signing evidence against a provided
public key and chain ID and, if successful, executes the jailing of the malicious validator who double voted.
We define a new
`MsgSubmitConsumerDoubleVoting` message to report a double voting evidence observed
on a consumer chain to the endpoint of the provider chain. This message contains two fields:
a double signing evidence
`duplicate_vote_evidence` and a light client header for the infraction block height,
referred to as `infraction_block_header`.

We define a new
`MsgSubmitConsumerDoubleVoting` message to report a double voting evidence observed
on a consumer chain to the endpoint of the provider chain. This message contains two fields:
a double signing evidence
`duplicate_vote_evidence` and a light client header for the infraction block height,
referred to as `infraction_block_header`.
The latter provides the malicious validator's public key and the chain ID required to verify the signature of the votes contained in the evidence.

Note that double signing evidence is not verified using the same conditions as in the implementation CometBFT (see
[`verify(evidence types.Evidence)`](https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/verify.go#L19) method). Specifically, we do not check that the evidence hasn't expired.
More details can be found in the ["Current limitations"](#current-limitations) section below.
Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time
(see [DoubleSignJailEndTime](https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/types/params.go#L11)
[`verify(evidence types.Evidence)`](https://github.com/cometbft/cometbft/blob/v0.34.28/evidence/verify.go#L19) method). Specifically, we do not check that the evidence hasn't expired.
More details can be found in the ["Current limitations"](#current-limitations) section below.

Upon a successful equivocation verification, the misbehaving validator is jailed for the maximum time
(see [DoubleSignJailEndTime](https://github.com/cosmos/cosmos-sdk/blob/v0.45.16-ics-lsm/x/evidence/types/params.go#L11)
in the SDK evidence module).


Expand All @@ -131,21 +131,21 @@ To explain the technical reasons behind this limitation, let's recap the initial
which is used to slash the misbehaving validator. In the context of untrusted consumer chains, all their states, including vscIDs,
could be corrupted and therefore cannot be used for slashing purposes.

- For the same reasons explained above, the age of a consumer double signing evidence can't be verified,
- For the same reasons explained above, the age of a consumer double signing evidence can't be verified,
either using its infraction height or its unsigned timestamp. Note that changes the jailing behaviour, potentially leading to a validator's jailing based on some "old" evidence from a consumer, which wouldn't occur if the consumer were a standalone chain.

- In the first stage of this feature, validators are jailed indefinitely without being tombstoned.
The underlying reason is that a malicious validator could take advantage of getting tombstoned
to avoid being slashed on the provider ([see comment](https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641)).
The underlying reason is that a malicious validator could take advantage of getting tombstoned
to avoid being slashed on the provider ([see comment](https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641)).

- Currently, the endpoint can only handle _equivocation_ light client attacks. This is because the _lunatic_ attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see [comment](https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684)). In addition, "amnesia" attacks are ignored, similar to CometBFT (see [ADR-056](https://github.com/cometbft/cometbft/blob/main/docs/architecture/tendermint-core/adr-056-light-client-amnesia-attacks.md#decision)).
- Currently, the endpoint can only handle _equivocation_ light client attacks. This is because the _lunatic_ attacks require the endpoint to possess the ability to dissociate which header is conflicted or trusted upon receiving a misbehavior message. Without this information, it's not possible to extract the Byzantine validators from the conflicting headers (see [comment](https://github.com/cosmos/interchain-security/pull/826#discussion_r1268668684)). In addition, "amnesia" attacks are ignored, similar to CometBFT (see [ADR-056](https://github.com/cometbft/cometbft/blob/main/docs/references/architecture/tendermint-core/adr-056-light-client-amnesia-attacks.md#decision)).


## Consequences

### Positive

- It is now possible for the provider chain to jail validators who committed
- It is now possible for the provider chain to jail validators who committed
light client or double signing attacks on a consumer chain.

### Negative
Expand Down
16 changes: 15 additions & 1 deletion proto/interchain_security/ccv/provider/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,14 @@ service Query {
returns (QueryAllPairsValConAddrByConsumerChainIDResponse) {
option (google.api.http).get =
"/interchain_security/ccv/provider/consumer_chain_id";
}
}

// QueryParams returns all current values of provider parameters
rpc QueryParams(QueryParamsRequest)
returns (QueryParamsResponse) {
option (google.api.http).get =
"/interchain_security/ccv/provider/params";
}
}

message QueryConsumerGenesisRequest { string chain_id = 1; }
Expand Down Expand Up @@ -235,3 +242,10 @@ message PairValConAddrProviderAndConsumer {
string consumer_address = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ];
tendermint.crypto.PublicKey consumer_key = 3;
}

message QueryParamsRequest {}

message QueryParamsResponse {
Params params = 1 [(gogoproto.nullable) = false];
}

36 changes: 35 additions & 1 deletion x/ccv/provider/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func NewQueryCmd() *cobra.Command {
cmd.AddCommand(CmdRegisteredConsumerRewardDenoms())
cmd.AddCommand(CmdProposedConsumerChains())
cmd.AddCommand(CmdAllPairsValConAddrByConsumerChainID())

cmd.AddCommand(CmdProviderParameters())
return cmd
}

Expand Down Expand Up @@ -412,3 +412,37 @@ func CmdAllPairsValConAddrByConsumerChainID() *cobra.Command {

return cmd
}

// Command to query provider parameters
func CmdProviderParameters() *cobra.Command {
cmd := &cobra.Command{
Use: "params",
Short: "Query provider parameters information",
Long: strings.TrimSpace(
fmt.Sprintf(`Query parameter values of provider.
Example:
$ %s query provider params
`, version.AppName),
),
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

res, err := queryClient.QueryParams(cmd.Context(),
&types.QueryParamsRequest{})
if err != nil {
return err
}

return clientCtx.PrintProto(&res.Params)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
8 changes: 8 additions & 0 deletions x/ccv/provider/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,11 @@ func (k Keeper) QueryAllPairsValConAddrByConsumerChainID(goCtx context.Context,
PairValConAddr: pairValConAddrs,
}, nil
}

// QueryParams returns all parameters and current values of provider
func (k Keeper) QueryParams(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
params := k.GetParams(ctx)

return &types.QueryParamsResponse{Params: params}, nil
}
Loading

0 comments on commit 50b28ff

Please sign in to comment.