From 50002b0e0999c3eb1017b992359ae56505a25c24 Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 16:43:43 -0800 Subject: [PATCH 01/11] ibc: implement channel query --- .../ibc/src/component/rpc/consensus_query.rs | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/consensus_query.rs b/crates/core/component/ibc/src/component/rpc/consensus_query.rs index c4d60f5e08..99939331cd 100644 --- a/crates/core/component/ibc/src/component/rpc/consensus_query.rs +++ b/crates/core/component/ibc/src/component/rpc/consensus_query.rs @@ -1,7 +1,9 @@ +use crate::prefix::MerklePrefixExt; +use crate::IBC_COMMITMENT_PREFIX; use async_trait::async_trait; use ibc_proto::ibc::core::channel::v1::query_server::Query as ConsensusQuery; use ibc_proto::ibc::core::channel::v1::{ - PacketState, QueryChannelClientStateRequest, QueryChannelClientStateResponse, + Channel, PacketState, QueryChannelClientStateRequest, QueryChannelClientStateResponse, QueryChannelConsensusStateRequest, QueryChannelConsensusStateResponse, QueryChannelRequest, QueryChannelResponse, QueryChannelsRequest, QueryChannelsResponse, QueryConnectionChannelsRequest, QueryConnectionChannelsResponse, @@ -13,12 +15,14 @@ use ibc_proto::ibc::core::channel::v1::{ QueryPacketReceiptRequest, QueryPacketReceiptResponse, QueryUnreceivedAcksRequest, QueryUnreceivedAcksResponse, QueryUnreceivedPacketsRequest, QueryUnreceivedPacketsResponse, }; - use ibc_proto::ibc::core::client::v1::Height; +use ibc_types::path::ChannelEndPath; +use ibc_types::DomainType; use ibc_types::core::channel::{ChannelId, IdentifiedChannelEnd, PortId}; use ibc_types::core::connection::ConnectionId; +use prost::Message; use std::str::FromStr; @@ -31,9 +35,45 @@ impl ConsensusQuery for IbcQuery { /// Channel queries an IBC Channel. async fn channel( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + let channel_id = ChannelId::from_str(request.get_ref().channel_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid channel id: {e}")))?; + let port_id = PortId::from_str(request.get_ref().port_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid port id: {e}")))?; + + let (channel, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string(ChannelEndPath::new(&port_id, &channel_id).to_string()) + .as_bytes() + .to_vec(), + ) + .await + .map(|res| { + let channel = res + .0 + .map(|chan_bytes| Channel::decode(chan_bytes.as_ref())) + .transpose(); + + (channel, res.1) + }) + .map_err(|e| tonic::Status::aborted(format!("couldn't get channel: {e}")))?; + + let channel = + channel.map_err(|e| tonic::Status::aborted(format!("couldn't decode channel: {e}")))?; + + let res = QueryChannelResponse { + channel, + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + }; + + Ok(tonic::Response::new(res)) } /// Channels queries all the IBC channels of a chain. async fn channels( From cdbab108eb05833e281cf92195a45b975fbebc7f Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 16:58:21 -0800 Subject: [PATCH 02/11] ibc: implement channel_client_state query --- .../ibc/src/component/rpc/consensus_query.rs | 82 +++++++++++++++++-- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/consensus_query.rs b/crates/core/component/ibc/src/component/rpc/consensus_query.rs index 99939331cd..b21d5b7d58 100644 --- a/crates/core/component/ibc/src/component/rpc/consensus_query.rs +++ b/crates/core/component/ibc/src/component/rpc/consensus_query.rs @@ -15,8 +15,8 @@ use ibc_proto::ibc::core::channel::v1::{ QueryPacketReceiptRequest, QueryPacketReceiptResponse, QueryUnreceivedAcksRequest, QueryUnreceivedAcksResponse, QueryUnreceivedPacketsRequest, QueryUnreceivedPacketsResponse, }; -use ibc_proto::ibc::core::client::v1::Height; -use ibc_types::path::ChannelEndPath; +use ibc_proto::ibc::core::client::v1::{Height, IdentifiedClientState}; +use ibc_types::path::{ChannelEndPath, ClientStatePath}; use ibc_types::DomainType; use ibc_types::core::channel::{ChannelId, IdentifiedChannelEnd, PortId}; @@ -26,7 +26,7 @@ use prost::Message; use std::str::FromStr; -use crate::component::ChannelStateReadExt; +use crate::component::{ChannelStateReadExt, ConnectionStateReadExt}; use super::IbcQuery; @@ -178,9 +178,81 @@ impl ConsensusQuery for IbcQuery { /// with the provided channel identifiers. async fn channel_client_state( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + + // 1. get the channel + let channel_id = ChannelId::from_str(request.get_ref().channel_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid channel id: {e}")))?; + let port_id = PortId::from_str(request.get_ref().port_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid port id: {e}")))?; + + let channel = snapshot + .get_channel(&channel_id, &port_id) + .await + .map_err(|e| { + tonic::Status::aborted(format!( + "couldn't get channel {channel_id} for port {port_id}: {e}" + )) + })? + .ok_or("unable to get channel") + .map_err(|e| { + tonic::Status::aborted(format!( + "couldn't get channel {channel_id} for port {port_id}: {e}" + )) + })?; + + // 2. get the connection for the channel + let connection_id = channel + .connection_hops + .first() + .ok_or("channel has no connection hops") + .map_err(|e| { + tonic::Status::aborted(format!( + "couldn't get connection for channel {channel_id} for port {port_id}: {e}" + )) + })?; + + let connection = snapshot.get_connection(&connection_id).await.map_err(|e| { + tonic::Status::aborted(format!( + "couldn't get connection {connection_id} for channel {channel_id} for port {port_id}: {e}" + )) + })?.ok_or("unable to get connection").map_err(|e| { + tonic::Status::aborted(format!( + "couldn't get connection {connection_id} for channel {channel_id} for port {port_id}: {e}" + )) + })?; + + // 3. get the client state for the connection + let (client_state, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string(ClientStatePath::new(&connection.client_id).to_string()) + .as_bytes() + .to_vec(), + ) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get client state: {e}")))?; + + let client_state_any = client_state + .map(|cs_bytes| ibc_proto::google::protobuf::Any::decode(cs_bytes.as_ref())) + .transpose() + .map_err(|e| tonic::Status::aborted(format!("couldn't decode client state: {e}")))?; + + let identified_client_state = IdentifiedClientState { + client_id: connection.client_id.clone().to_string(), + client_state: client_state_any, + }; + + Ok(tonic::Response::new(QueryChannelClientStateResponse { + identified_client_state: Some(identified_client_state), + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + })) } /// ChannelConsensusState queries for the consensus state for the channel /// associated with the provided channel identifiers. From ae1a35309e4fb46d25410af8b274bf8f91e760ca Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 17:18:11 -0800 Subject: [PATCH 03/11] ibc: implement channel_consensus_state query --- .../ibc/src/component/rpc/consensus_query.rs | 84 ++++++++++++++++++- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/consensus_query.rs b/crates/core/component/ibc/src/component/rpc/consensus_query.rs index b21d5b7d58..e4f3ff752f 100644 --- a/crates/core/component/ibc/src/component/rpc/consensus_query.rs +++ b/crates/core/component/ibc/src/component/rpc/consensus_query.rs @@ -16,7 +16,7 @@ use ibc_proto::ibc::core::channel::v1::{ QueryUnreceivedAcksResponse, QueryUnreceivedPacketsRequest, QueryUnreceivedPacketsResponse, }; use ibc_proto::ibc::core::client::v1::{Height, IdentifiedClientState}; -use ibc_types::path::{ChannelEndPath, ClientStatePath}; +use ibc_types::path::{ChannelEndPath, ClientConsensusStatePath, ClientStatePath}; use ibc_types::DomainType; use ibc_types::core::channel::{ChannelId, IdentifiedChannelEnd, PortId}; @@ -258,10 +258,88 @@ impl ConsensusQuery for IbcQuery { /// associated with the provided channel identifiers. async fn channel_consensus_state( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + let consensus_state_height = ibc_types::core::client::Height { + revision_number: request.get_ref().revision_number, + revision_height: request.get_ref().revision_height, + }; + + // 1. get the channel + let channel_id = ChannelId::from_str(request.get_ref().channel_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid channel id: {e}")))?; + let port_id = PortId::from_str(request.get_ref().port_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid port id: {e}")))?; + + let channel = snapshot + .get_channel(&channel_id, &port_id) + .await + .map_err(|e| { + tonic::Status::aborted(format!( + "couldn't get channel {channel_id} for port {port_id}: {e}" + )) + })? + .ok_or("unable to get channel") + .map_err(|e| { + tonic::Status::aborted(format!( + "couldn't get channel {channel_id} for port {port_id}: {e}" + )) + })?; + + // 2. get the connection for the channel + let connection_id = channel + .connection_hops + .first() + .ok_or("channel has no connection hops") + .map_err(|e| { + tonic::Status::aborted(format!( + "couldn't get connection for channel {channel_id} for port {port_id}: {e}" + )) + })?; + + let connection = snapshot.get_connection(&connection_id).await.map_err(|e| { + tonic::Status::aborted(format!( + "couldn't get connection {connection_id} for channel {channel_id} for port {port_id}: {e}" + )) + })?.ok_or("unable to get connection").map_err(|e| { + tonic::Status::aborted(format!( + "couldn't get connection {connection_id} for channel {channel_id} for port {port_id}: {e}" + )) + })?; + + // 3. get the consensus state for the connection + let (consensus_state, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string( + ClientConsensusStatePath::new( + &connection.client_id, + &consensus_state_height, + ) + .to_string(), + ) + .as_bytes() + .to_vec(), + ) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get client state: {e}")))?; + + let consensus_state_any = consensus_state + .map(|cs_bytes| ibc_proto::google::protobuf::Any::decode(cs_bytes.as_ref())) + .transpose() + .map_err(|e| tonic::Status::aborted(format!("couldn't decode client state: {e}")))?; + + Ok(tonic::Response::new(QueryChannelConsensusStateResponse { + consensus_state: consensus_state_any, + client_id: connection.client_id.clone().to_string(), + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + })) } /// PacketCommitment queries a stored packet commitment hash. async fn packet_commitment( From 3b7c455c576acb38a1079cd90ff4f685c9b3347a Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 17:35:14 -0800 Subject: [PATCH 04/11] ibc: implement packet_commitment query --- .../ibc/src/component/rpc/consensus_query.rs | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/consensus_query.rs b/crates/core/component/ibc/src/component/rpc/consensus_query.rs index e4f3ff752f..1ab898932f 100644 --- a/crates/core/component/ibc/src/component/rpc/consensus_query.rs +++ b/crates/core/component/ibc/src/component/rpc/consensus_query.rs @@ -16,13 +16,14 @@ use ibc_proto::ibc::core::channel::v1::{ QueryUnreceivedAcksResponse, QueryUnreceivedPacketsRequest, QueryUnreceivedPacketsResponse, }; use ibc_proto::ibc::core::client::v1::{Height, IdentifiedClientState}; -use ibc_types::path::{ChannelEndPath, ClientConsensusStatePath, ClientStatePath}; +use ibc_types::path::{ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath}; use ibc_types::DomainType; use ibc_types::core::channel::{ChannelId, IdentifiedChannelEnd, PortId}; use ibc_types::core::connection::ConnectionId; use prost::Message; +use sha2::digest::generic_array::functional::MappedSequence; use std::str::FromStr; @@ -344,9 +345,43 @@ impl ConsensusQuery for IbcQuery { /// PacketCommitment queries a stored packet commitment hash. async fn packet_commitment( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + + let port_id = PortId::from_str(&request.get_ref().port_id) + .map_err(|e| tonic::Status::aborted(format!("invalid port id: {e}")))?; + let channel_id = ChannelId::from_str(&request.get_ref().channel_id) + .map_err(|e| tonic::Status::aborted(format!("invalid channel id: {e}")))?; + + let (commitment, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string( + CommitmentPath::new( + &port_id, + &channel_id, + request.get_ref().sequence.into(), + ) + .to_string(), + ) + .as_bytes() + .to_vec(), + ) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get packet commitment: {e}")))?; + + let commitment = + commitment.ok_or_else(|| tonic::Status::aborted("commitment not found"))?; + + Ok(tonic::Response::new(QueryPacketCommitmentResponse { + commitment, + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + })) } /// PacketCommitments returns all the packet commitments hashes associated /// with a channel. From 9044a7321fafd4f383a7513be3dc28a50484427f Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 17:51:32 -0800 Subject: [PATCH 05/11] ibc: implement packet_receipt query --- .../ibc/src/component/rpc/consensus_query.rs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/consensus_query.rs b/crates/core/component/ibc/src/component/rpc/consensus_query.rs index 1ab898932f..b2c0468e70 100644 --- a/crates/core/component/ibc/src/component/rpc/consensus_query.rs +++ b/crates/core/component/ibc/src/component/rpc/consensus_query.rs @@ -16,7 +16,9 @@ use ibc_proto::ibc::core::channel::v1::{ QueryUnreceivedAcksResponse, QueryUnreceivedPacketsRequest, QueryUnreceivedPacketsResponse, }; use ibc_proto::ibc::core::client::v1::{Height, IdentifiedClientState}; -use ibc_types::path::{ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath}; +use ibc_types::path::{ + ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ReceiptPath, +}; use ibc_types::DomainType; use ibc_types::core::channel::{ChannelId, IdentifiedChannelEnd, PortId}; @@ -449,9 +451,36 @@ impl ConsensusQuery for IbcQuery { /// queried chain async fn packet_receipt( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + + let port_id = PortId::from_str(&request.get_ref().port_id) + .map_err(|e| tonic::Status::aborted(format!("invalid port id: {e}")))?; + let channel_id = ChannelId::from_str(&request.get_ref().channel_id) + .map_err(|e| tonic::Status::aborted(format!("invalid channel id: {e}")))?; + + let (receipt, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string( + ReceiptPath::new(&port_id, &channel_id, request.get_ref().sequence.into()) + .to_string(), + ) + .as_bytes() + .to_vec(), + ) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get packet commitment: {e}")))?; + + Ok(tonic::Response::new(QueryPacketReceiptResponse { + received: receipt.is_some(), + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + })) } /// PacketAcknowledgement queries a stored packet acknowledgement hash. async fn packet_acknowledgement( From 889f6aa85ca55584622b233285058e55214f49af Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 17:58:11 -0800 Subject: [PATCH 06/11] ibc: implement packet_acknowledgement query --- .../ibc/src/component/rpc/consensus_query.rs | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/consensus_query.rs b/crates/core/component/ibc/src/component/rpc/consensus_query.rs index b2c0468e70..7ff41f7d3d 100644 --- a/crates/core/component/ibc/src/component/rpc/consensus_query.rs +++ b/crates/core/component/ibc/src/component/rpc/consensus_query.rs @@ -17,7 +17,7 @@ use ibc_proto::ibc::core::channel::v1::{ }; use ibc_proto::ibc::core::client::v1::{Height, IdentifiedClientState}; use ibc_types::path::{ - ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ReceiptPath, + AckPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ReceiptPath, }; use ibc_types::DomainType; @@ -485,10 +485,41 @@ impl ConsensusQuery for IbcQuery { /// PacketAcknowledgement queries a stored packet acknowledgement hash. async fn packet_acknowledgement( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + let channel_id = ChannelId::from_str(request.get_ref().channel_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid channel id: {e}")))?; + let port_id = PortId::from_str(request.get_ref().port_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid port id: {e}")))?; + + let (acknowledgement, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string( + AckPath::new(&port_id, &channel_id, request.get_ref().sequence.into()) + .to_string(), + ) + .as_bytes() + .to_vec(), + ) + .await + .map_err(|e| { + tonic::Status::aborted(format!("couldn't get packet acknowledgement: {e}")) + })?; + + let acknowledgement = + acknowledgement.ok_or_else(|| tonic::Status::aborted("acknowledgement not found"))?; + + Ok(tonic::Response::new(QueryPacketAcknowledgementResponse { + acknowledgement, + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + })) } /// PacketAcknowledgements returns all the packet acknowledgements associated /// with a channel. From c9e8d3a455b44f77b0dc8c65e5a84e93c14b3256 Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 18:03:26 -0800 Subject: [PATCH 07/11] ibc: implement next_sequence_receive query --- .../ibc/src/component/rpc/consensus_query.rs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/consensus_query.rs b/crates/core/component/ibc/src/component/rpc/consensus_query.rs index 7ff41f7d3d..3c0beb3616 100644 --- a/crates/core/component/ibc/src/component/rpc/consensus_query.rs +++ b/crates/core/component/ibc/src/component/rpc/consensus_query.rs @@ -17,7 +17,8 @@ use ibc_proto::ibc::core::channel::v1::{ }; use ibc_proto::ibc::core::client::v1::{Height, IdentifiedClientState}; use ibc_types::path::{ - AckPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ReceiptPath, + AckPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, + ReceiptPath, SeqRecvPath, }; use ibc_types::DomainType; @@ -682,9 +683,37 @@ impl ConsensusQuery for IbcQuery { /// NextSequenceReceive returns the next receive sequence for a given channel. async fn next_sequence_receive( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + + let channel_id = ChannelId::from_str(request.get_ref().channel_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid channel id: {e}")))?; + let port_id = PortId::from_str(request.get_ref().port_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid port id: {e}")))?; + + let (next_recv_sequence, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string(SeqRecvPath::new(&port_id, &channel_id).to_string()) + .as_bytes() + .to_vec(), + ) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get channel: {e}")))?; + + let next_recv_sequence = next_recv_sequence + .map(|seq_bytes| u64::from_be_bytes(seq_bytes.try_into().expect("invalid sequence"))) + .ok_or_else(|| tonic::Status::aborted("next receive sequence not found"))?; + + Ok(tonic::Response::new(QueryNextSequenceReceiveResponse { + next_sequence_receive: next_recv_sequence, + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + })) } /// NextSequenceSend returns the next send sequence for a given channel. From 4d77f792614cf48fa24456341a2dcae664f60a4b Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 18:05:05 -0800 Subject: [PATCH 08/11] ibc: implement next_sequence_send query --- .../ibc/src/component/rpc/consensus_query.rs | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/consensus_query.rs b/crates/core/component/ibc/src/component/rpc/consensus_query.rs index 3c0beb3616..bc22c31b53 100644 --- a/crates/core/component/ibc/src/component/rpc/consensus_query.rs +++ b/crates/core/component/ibc/src/component/rpc/consensus_query.rs @@ -18,7 +18,7 @@ use ibc_proto::ibc::core::channel::v1::{ use ibc_proto::ibc::core::client::v1::{Height, IdentifiedClientState}; use ibc_types::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, - ReceiptPath, SeqRecvPath, + ReceiptPath, SeqRecvPath, SeqSendPath, }; use ibc_types::DomainType; @@ -26,7 +26,6 @@ use ibc_types::core::channel::{ChannelId, IdentifiedChannelEnd, PortId}; use ibc_types::core::connection::ConnectionId; use prost::Message; -use sha2::digest::generic_array::functional::MappedSequence; use std::str::FromStr; @@ -719,8 +718,36 @@ impl ConsensusQuery for IbcQuery { /// NextSequenceSend returns the next send sequence for a given channel. async fn next_sequence_send( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + + let channel_id = ChannelId::from_str(request.get_ref().channel_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid channel id: {e}")))?; + let port_id = PortId::from_str(request.get_ref().port_id.as_str()) + .map_err(|e| tonic::Status::aborted(format!("invalid port id: {e}")))?; + + let (next_send_sequence, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string(SeqSendPath::new(&port_id, &channel_id).to_string()) + .as_bytes() + .to_vec(), + ) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get channel: {e}")))?; + + let next_send_sequence = next_send_sequence + .map(|seq_bytes| u64::from_be_bytes(seq_bytes.try_into().expect("invalid sequence"))) + .ok_or_else(|| tonic::Status::aborted("next receive sequence not found"))?; + + Ok(tonic::Response::new(QueryNextSequenceSendResponse { + next_sequence_send: next_send_sequence, + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + })) } } From f2113ac765fe74d386b3eb06910abeb254bc632a Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 18:21:14 -0800 Subject: [PATCH 09/11] ibc: implement client_connections query --- .../ibc/src/component/rpc/connection_query.rs | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/connection_query.rs b/crates/core/component/ibc/src/component/rpc/connection_query.rs index 5ccb633761..2d2cdb6ba2 100644 --- a/crates/core/component/ibc/src/component/rpc/connection_query.rs +++ b/crates/core/component/ibc/src/component/rpc/connection_query.rs @@ -10,8 +10,9 @@ use ibc_proto::ibc::core::connection::v1::{ QueryConnectionsResponse, }; -use ibc_types::core::connection::{ConnectionId, IdentifiedConnectionEnd}; -use ibc_types::path::ConnectionPath; +use ibc_types::core::client::ClientId; +use ibc_types::core::connection::{ClientPaths, ConnectionId, IdentifiedConnectionEnd}; +use ibc_types::path::{ClientConnectionPath, ConnectionPath}; use ibc_types::DomainType; use prost::Message; use std::str::FromStr; @@ -131,9 +132,40 @@ impl ConnectionQuery for IbcQuery { /// state. async fn client_connections( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + let client_id = &ClientId::from_str(&request.get_ref().client_id) + .map_err(|e| tonic::Status::aborted(format!("invalid client id: {e}")))?; + + let (client_connections, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string(ClientConnectionPath::new(client_id).to_string()) + .as_bytes() + .to_vec(), + ) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get client connections: {e}")))?; + + let connection_paths: Vec = client_connections + .map(|client_connections| ClientPaths::decode(client_connections.as_ref())) + .transpose() + .map_err(|e| { + tonic::Status::aborted(format!("couldn't decode client connections: {e}")) + })? + .map(|client_paths| client_paths.paths) + .map(|paths| paths.into_iter().map(|path| path.to_string()).collect()) + .unwrap_or_default(); + + Ok(tonic::Response::new(QueryClientConnectionsResponse { + connection_paths, + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + })) } /// ConnectionClientState queries the client state associated with the /// connection. From 1da0f6a70bcb627a028755d991d02b2f41eb9c77 Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 18:29:24 -0800 Subject: [PATCH 10/11] ibc: implement connection_client_state query --- .../ibc/src/component/rpc/connection_query.rs | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/connection_query.rs b/crates/core/component/ibc/src/component/rpc/connection_query.rs index 2d2cdb6ba2..64c0d04d95 100644 --- a/crates/core/component/ibc/src/component/rpc/connection_query.rs +++ b/crates/core/component/ibc/src/component/rpc/connection_query.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; -use ibc_proto::ibc::core::client::v1::Height; +use ibc_proto::ibc::core::client::v1::{Height, IdentifiedClientState}; use ibc_proto::ibc::core::connection::v1::query_server::Query as ConnectionQuery; use ibc_proto::ibc::core::connection::v1::{ ConnectionEnd, QueryClientConnectionsRequest, QueryClientConnectionsResponse, @@ -12,7 +12,7 @@ use ibc_proto::ibc::core::connection::v1::{ use ibc_types::core::client::ClientId; use ibc_types::core::connection::{ClientPaths, ConnectionId, IdentifiedConnectionEnd}; -use ibc_types::path::{ClientConnectionPath, ConnectionPath}; +use ibc_types::path::{ClientConnectionPath, ClientStatePath, ConnectionPath}; use ibc_types::DomainType; use prost::Message; use std::str::FromStr; @@ -171,10 +171,49 @@ impl ConnectionQuery for IbcQuery { /// connection. async fn connection_client_state( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + let connection_id = &ConnectionId::from_str(&request.get_ref().connection_id) + .map_err(|e| tonic::Status::aborted(format!("invalid connection id: {e}")))?; + + let client_id = snapshot + .get_connection(connection_id) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get connection: {e}")))? + .ok_or("unable to get connection") + .map_err(|e| tonic::Status::aborted(format!("couldn't get connection: {e}")))? + .client_id; + + let (client_state, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string(ClientStatePath::new(&client_id).to_string()) + .as_bytes() + .to_vec(), + ) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get client state: {e}")))?; + + let client_state_any = client_state + .map(|cs_bytes| ibc_proto::google::protobuf::Any::decode(cs_bytes.as_ref())) + .transpose() + .map_err(|e| tonic::Status::aborted(format!("couldn't decode client state: {e}")))?; + + let identified_client_state = IdentifiedClientState { + client_id: client_id.clone().to_string(), + client_state: client_state_any, + }; + + Ok(tonic::Response::new(QueryConnectionClientStateResponse { + identified_client_state: Some(identified_client_state), + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + })) } /// ConnectionConsensusState queries the consensus state associated with the /// connection. From 9735d8bcf25b440388bb5de12fcd15b2d71f0d59 Mon Sep 17 00:00:00 2001 From: Ava Howell Date: Wed, 3 Jan 2024 18:33:31 -0800 Subject: [PATCH 11/11] ibc: implement connection_consensus_state query --- .../ibc/src/component/rpc/connection_query.rs | 53 +++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/crates/core/component/ibc/src/component/rpc/connection_query.rs b/crates/core/component/ibc/src/component/rpc/connection_query.rs index 64c0d04d95..73fcb76d10 100644 --- a/crates/core/component/ibc/src/component/rpc/connection_query.rs +++ b/crates/core/component/ibc/src/component/rpc/connection_query.rs @@ -1,5 +1,6 @@ use async_trait::async_trait; +use ibc_proto::ibc::core::client; use ibc_proto::ibc::core::client::v1::{Height, IdentifiedClientState}; use ibc_proto::ibc::core::connection::v1::query_server::Query as ConnectionQuery; use ibc_proto::ibc::core::connection::v1::{ @@ -12,7 +13,9 @@ use ibc_proto::ibc::core::connection::v1::{ use ibc_types::core::client::ClientId; use ibc_types::core::connection::{ClientPaths, ConnectionId, IdentifiedConnectionEnd}; -use ibc_types::path::{ClientConnectionPath, ClientStatePath, ConnectionPath}; +use ibc_types::path::{ + ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, ConnectionPath, +}; use ibc_types::DomainType; use prost::Message; use std::str::FromStr; @@ -219,9 +222,53 @@ impl ConnectionQuery for IbcQuery { /// connection. async fn connection_consensus_state( &self, - _request: tonic::Request, + request: tonic::Request, ) -> std::result::Result, tonic::Status> { - Err(tonic::Status::unimplemented("not implemented")) + let snapshot = self.0.latest_snapshot(); + let consensus_state_height = ibc_types::core::client::Height { + revision_number: request.get_ref().revision_number, + revision_height: request.get_ref().revision_height, + }; + let connection_id = &ConnectionId::from_str(&request.get_ref().connection_id) + .map_err(|e| tonic::Status::aborted(format!("invalid connection id: {e}")))?; + + let client_id = snapshot + .get_connection(connection_id) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get connection: {e}")))? + .ok_or("unable to get connection") + .map_err(|e| tonic::Status::aborted(format!("couldn't get connection: {e}")))? + .client_id; + + let (consensus_state, proof) = snapshot + .get_with_proof( + IBC_COMMITMENT_PREFIX + .apply_string( + ClientConsensusStatePath::new(&client_id, &consensus_state_height) + .to_string(), + ) + .as_bytes() + .to_vec(), + ) + .await + .map_err(|e| tonic::Status::aborted(format!("couldn't get client state: {e}")))?; + + let consensus_state_any = consensus_state + .map(|cs_bytes| ibc_proto::google::protobuf::Any::decode(cs_bytes.as_ref())) + .transpose() + .map_err(|e| tonic::Status::aborted(format!("couldn't decode client state: {e}")))?; + + Ok(tonic::Response::new( + QueryConnectionConsensusStateResponse { + consensus_state: consensus_state_any, + client_id: client_id.to_string(), + proof: proof.encode_to_vec(), + proof_height: Some(Height { + revision_number: 0, + revision_height: snapshot.version(), + }), + }, + )) } }