Skip to content

Commit

Permalink
Submit misbehaviour messages using the CCV consumer id (Permissionles…
Browse files Browse the repository at this point in the history
…s ICS)
  • Loading branch information
romac committed Sep 5, 2024
1 parent e26d356 commit e6fa94b
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 32 deletions.
5 changes: 2 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ uuid = "1.10.0"
overflow-checks = true

[patch.crates-io]
ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs", branch = "romac/permissionless-ics" }
# tendermint = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "main" }
# tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "main" }
# tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "main" }
Expand Down
28 changes: 21 additions & 7 deletions crates/relayer-cli/src/commands/evidence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use ibc_relayer::chain::endpoint::ChainEndpoint;
use ibc_relayer::chain::handle::{BaseChainHandle, ChainHandle};
use ibc_relayer::chain::requests::{IncludeProof, PageRequest, QueryHeight};
use ibc_relayer::chain::tracking::TrackedMsgs;
use ibc_relayer::foreign_client::ForeignClient;
use ibc_relayer::foreign_client::{fetch_ccv_consumer_id, ForeignClient};
use ibc_relayer::spawn::spawn_chain_runtime_with_modified_config;
use ibc_relayer_types::applications::ics28_ccv::msgs::ccv_double_voting::MsgSubmitIcsConsumerDoubleVoting;
use ibc_relayer_types::applications::ics28_ccv::msgs::ccv_misbehaviour::MsgSubmitIcsConsumerMisbehaviour;
Expand Down Expand Up @@ -323,6 +323,8 @@ fn submit_duplicate_vote_evidence(
return Ok(ControlFlow::Continue(()));
}

let consumer_id = fetch_ccv_consumer_id(counterparty_chain_handle, counterparty_client_id)?;

let infraction_height = evidence.vote_a.height;

// Get the trusted height in the same way we do for client updates,
Expand Down Expand Up @@ -359,6 +361,7 @@ fn submit_duplicate_vote_evidence(
submitter: signer.clone(),
duplicate_vote_evidence: evidence.clone(),
infraction_block_header,
consumer_id,
}
.to_any();

Expand Down Expand Up @@ -578,13 +581,24 @@ fn submit_light_client_attack_evidence(
counterparty.id(),
);

let msg = MsgSubmitIcsConsumerMisbehaviour {
submitter: signer.clone(),
misbehaviour: misbehaviour.clone(),
match fetch_ccv_consumer_id(counterparty, &counterparty_client_id) {
Ok(consumer_id) => {
msgs.push(
MsgSubmitIcsConsumerMisbehaviour {
submitter: signer.clone(),
misbehaviour: misbehaviour.clone(),
consumer_id,
}
.to_any(),
);
}
Err(e) => {
error!(
"cannot submit CCV light client attack evidence to client `{}` on provider chain `{}`: {e}",
counterparty_client_id, counterparty.id()
);
}
}
.to_any();

msgs.push(msg);
};

// We do not need to submit the misbehaviour if the client is already frozen.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::signer::Signer;
use crate::tx_msg::Msg;

use super::error::Error;
use super::ConsumerId;

pub const ICS_DOUBLE_VOTING_TYPE_URL: &str =
"/interchain_security.ccv.provider.v1.MsgSubmitConsumerDoubleVoting";
Expand All @@ -18,6 +19,7 @@ pub struct MsgSubmitIcsConsumerDoubleVoting {
pub submitter: Signer,
pub duplicate_vote_evidence: DuplicateVoteEvidence,
pub infraction_block_header: Header,
pub consumer_id: ConsumerId,
}

impl Msg for MsgSubmitIcsConsumerDoubleVoting {
Expand Down Expand Up @@ -57,6 +59,7 @@ impl TryFrom<RawIcsDoubleVoting> for MsgSubmitIcsConsumerDoubleVoting {
.map_err(|e| {
Error::invalid_raw_double_voting(format!("cannot convert header: {e}"))
})?,
consumer_id: ConsumerId::new(raw.consumer_id),
})
}
}
Expand All @@ -67,6 +70,7 @@ impl From<MsgSubmitIcsConsumerDoubleVoting> for RawIcsDoubleVoting {
submitter: value.submitter.to_string(),
duplicate_vote_evidence: Some(value.duplicate_vote_evidence.into()),
infraction_block_header: Some(value.infraction_block_header.into()),
consumer_id: value.consumer_id.to_string(),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::signer::Signer;
use crate::tx_msg::Msg;

use super::error::Error;
use super::ConsumerId;

pub const ICS_MISBEHAVIOR_TYPE_URL: &str =
"/interchain_security.ccv.provider.v1.MsgSubmitConsumerMisbehaviour";
Expand All @@ -18,6 +19,7 @@ pub const ICS_MISBEHAVIOR_TYPE_URL: &str =
pub struct MsgSubmitIcsConsumerMisbehaviour {
pub submitter: Signer,
pub misbehaviour: Misbehaviour,
pub consumer_id: ConsumerId,
}

impl Msg for MsgSubmitIcsConsumerMisbehaviour {
Expand Down Expand Up @@ -48,6 +50,7 @@ impl TryFrom<RawIcsMisbehaviour> for MsgSubmitIcsConsumerMisbehaviour {
.map_err(|_e| {
Error::invalid_raw_misbehaviour("cannot convert misbehaviour".into())
})?,
consumer_id: ConsumerId::new(raw.consumer_id),
})
}
}
Expand All @@ -57,6 +60,7 @@ impl From<MsgSubmitIcsConsumerMisbehaviour> for RawIcsMisbehaviour {
RawIcsMisbehaviour {
submitter: value.submitter.to_string(),
misbehaviour: Some(value.misbehaviour.into()),
consumer_id: value.consumer_id.to_string(),
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions crates/relayer-types/src/applications/ics28_ccv/msgs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
pub mod ccv_double_voting;
pub mod ccv_misbehaviour;
pub mod error;

use derive_more::Display;
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display, Serialize, Deserialize)]
pub struct ConsumerId(String);

impl ConsumerId {
pub const fn new(id: String) -> Self {
Self(id)
}

pub fn as_str(&self) -> &str {
&self.0
}
}
60 changes: 57 additions & 3 deletions crates/relayer/src/chain/cosmos.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use alloc::sync::Arc;
use bytes::Buf;
use bytes::Bytes;
use config::CosmosSdkConfig;
use core::{future::Future, str::FromStr, time::Duration};
use futures::future::join_all;
use ibc_relayer_types::applications::ics28_ccv::msgs::ConsumerId;
use num_bigint::BigInt;
use prost::Message;
use std::cmp::Ordering;
Expand Down Expand Up @@ -366,6 +368,7 @@ impl CosmosSdkChain {
}

/// Performs a gRPC query to fetch CCV Consumer chain staking parameters.
/// Assumes we are the consumer chain.
pub fn query_ccv_consumer_chain_params(&self) -> Result<CcvConsumerParams, Error> {
crate::time!(
"query_ccv_consumer_chain_params",
Expand Down Expand Up @@ -399,6 +402,14 @@ impl CosmosSdkChain {
Ok(params)
}

/// Performs a gRPC query to fetch the CCV ConsumerID corresponding
/// to the given ClientID.
///
/// Assumes we are the provider chain.
pub fn query_ccv_consumer_id(&self, client_id: &ClientId) -> Result<ConsumerId, Error> {
self.block_on(query_ccv_consumer_id(&self.config, client_id))
}

/// Performs a gRPC query for Cosmos chain staking parameters.
pub fn query_staking_params(&self) -> Result<StakingParams, Error> {
crate::time!(
Expand Down Expand Up @@ -2533,6 +2544,9 @@ impl ChainEndpoint for CosmosSdkChain {
}

fn query_consumer_chains(&self) -> Result<Vec<(ChainId, ClientId)>, Error> {
use ibc_proto::interchain_security::ccv::provider::v1::ConsumerPhase;
use ibc_proto::interchain_security::ccv::provider::v1::QueryConsumerChainsRequest;

crate::time!(
"query_consumer_chains",
{
Expand All @@ -2546,9 +2560,10 @@ impl ChainEndpoint for CosmosSdkChain {
ibc_proto::interchain_security::ccv::provider::v1::query_client::QueryClient::new,
))?;

let request = tonic::Request::new(
ibc_proto::interchain_security::ccv::provider::v1::QueryConsumerChainsRequest {},
);
let request = tonic::Request::new(QueryConsumerChainsRequest {
phase: ConsumerPhase::Launched as i32,
limit: 100,
});

let response = self
.block_on(client.query_consumer_chains(request))
Expand Down Expand Up @@ -2774,6 +2789,45 @@ fn do_health_check(chain: &CosmosSdkChain) -> Result<(), Error> {
Ok(())
}

/// Performs a gRPC query to fetch the CCV ConsumerID corresponding
/// to the given ClientID.
///
/// Assumes we are the provider chain.
pub async fn query_ccv_consumer_id(
config: &CosmosSdkConfig,
client_id: &ClientId,
) -> Result<ConsumerId, Error> {
use ibc_proto::interchain_security::ccv::provider::v1::query_client::QueryClient;
use ibc_proto::interchain_security::ccv::provider::v1::QueryConsumerIdFromClientIdRequest;

crate::telemetry!(query, &config.id, "query_ccv_consumer_id");
crate::time!(
"query_ccv_consumer_id",
{
"src_chain": &config.id,
}
);

let grpc_addr = Uri::from_str(&config.grpc_addr.to_string())
.map_err(|e| Error::invalid_uri(config.grpc_addr.to_string(), e))?;

let mut client = create_grpc_client(grpc_addr, QueryClient::new)
.await?
.max_decoding_message_size(config.max_grpc_decoding_size.get_bytes() as usize);

let request = tonic::Request::new(QueryConsumerIdFromClientIdRequest {
client_id: client_id.to_string(),
});

let response = client
.query_consumer_id_from_client_id(request)
.await
.map_err(|e| Error::grpc_status(e, "query_ccv_consumer_id".to_owned()))?;

let consumer_id = response.into_inner().consumer_id;
Ok(ConsumerId::new(consumer_id))
}

#[cfg(test)]
mod tests {
use super::calculate_fee;
Expand Down
Loading

0 comments on commit e6fa94b

Please sign in to comment.