From c57182e98d5c15036f5220a41275912966892052 Mon Sep 17 00:00:00 2001 From: Rano | Ranadeep Date: Wed, 10 Apr 2024 22:48:22 +0200 Subject: [PATCH] imp(rpc): dynamic value retrieval with or without proofs (#123) * impl ProvableContext * update match block * return Option directly * update comment * code opt * rm TODO comment * fill remaining branches * change order * traits to retrieve value with or without proofs * methods to retrieve value with or without proofs * update rpc query methods * add comment about inefficiency * update comment * use dyn_connection_end * add ref to doc strings * grammar on comments * update the comment with non-membership case * comments on infallible panics * rename to state_map * rm code duplicates * rename dyn_ to query_ * result over panic * update query calls with RpcResult returns * my first use of GAT * rm unused imports * update after GAT refactor * explain StorageValue trait * fix: consensus state query in test_create_client_on_sov * fix: broken docstring * nit * ignore example code in doc string --------- Co-authored-by: Farhad Shabani --- mocks/src/tests/client.rs | 2 +- modules/sov-ibc/src/rpc/context.rs | 320 ++++++++++++++++- modules/sov-ibc/src/rpc/helpers.rs | 82 ++++- modules/sov-ibc/src/rpc/methods.rs | 558 ++++++++++++++++++----------- 4 files changed, 734 insertions(+), 228 deletions(-) diff --git a/mocks/src/tests/client.rs b/mocks/src/tests/client.rs index 021b6fdb..b1d5002a 100644 --- a/mocks/src/tests/client.rs +++ b/mocks/src/tests/client.rs @@ -64,7 +64,7 @@ async fn test_create_client_on_sov() { revision_number: client_state.latest_height().revision_number(), revision_height: client_state.latest_height().revision_height(), }), - Some(client_state.latest_height()), + Some(client_state.latest_height().increment()), // increment as the proof is available as of the next height )) .await { diff --git a/modules/sov-ibc/src/rpc/context.rs b/modules/sov-ibc/src/rpc/context.rs index ea593d36..8d802662 100644 --- a/modules/sov-ibc/src/rpc/context.rs +++ b/modules/sov-ibc/src/rpc/context.rs @@ -1,30 +1,334 @@ +use borsh::BorshSerialize; use ibc_client_tendermint::types::client_type as tm_client_type; -use ibc_core::channel::types::channel::IdentifiedChannelEnd; +use ibc_core::channel::types::channel::{ChannelEnd, IdentifiedChannelEnd}; +use ibc_core::channel::types::commitment::{AcknowledgementCommitment, PacketCommitment}; use ibc_core::channel::types::error::ChannelError; -use ibc_core::channel::types::packet::PacketState; +use ibc_core::channel::types::packet::{PacketState, Receipt}; use ibc_core::client::context::ClientValidationContext; use ibc_core::client::types::Height; use ibc_core::connection::types::error::ConnectionError; -use ibc_core::connection::types::IdentifiedConnectionEnd; +use ibc_core::connection::types::{ConnectionEnd, IdentifiedConnectionEnd}; use ibc_core::handler::types::error::ContextError; use ibc_core::host::types::identifiers::{ChannelId, ClientId, ConnectionId, PortId, Sequence}; use ibc_core::host::types::path::{ - AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, CommitmentPath, Path, - ReceiptPath, + AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, CommitmentPath, + ConnectionPath, Path, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, UpgradeClientPath, }; use ibc_core::host::{ClientStateRef, ConsensusStateRef, ValidationContext}; use ibc_query::core::context::{ProvableContext, QueryContext}; +use jsonrpsee::core::RpcResult; +use sov_celestia_client::client_state::ClientState as HostClientState; +use sov_celestia_client::consensus_state::ConsensusState as HostConsensusState; use sov_modules_api::Spec; use crate::context::IbcContext; +use crate::helpers::StorageValue; + +impl<'a, S> IbcContext<'a, S> +where + S: Spec, +{ + pub fn query_client_state( + &self, + client_id: &ClientId, + ) -> RpcResult>> + where + SV: StorageValue, + { + SV::value_at_key( + client_id, + &self.ibc.client_state_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_client_consensus_state( + &self, + client_id: &ClientId, + revision_number: u64, + revision_height: u64, + ) -> RpcResult>> + where + SV: StorageValue, + { + let client_consensus_state_path = + &ClientConsensusStatePath::new(client_id.clone(), revision_number, revision_height); + + SV::value_at_key( + client_consensus_state_path, + &self.ibc.consensus_state_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_upgraded_client_state( + &self, + height: u64, + ) -> RpcResult> + where + SV: StorageValue, + { + let upgrade_client_path = &UpgradeClientPath::UpgradedClientState(height); + + SV::value_at_key( + upgrade_client_path, + &self.ibc.upgraded_client_state_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_upgraded_consensus_state( + &self, + height: u64, + ) -> RpcResult> + where + SV: StorageValue, + { + let upgrade_client_consensus_path = + &UpgradeClientPath::UpgradedClientConsensusState(height); + + SV::value_at_key( + upgrade_client_consensus_path, + &self.ibc.upgraded_consensus_state_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_connection_end( + &self, + connection_id: &ConnectionId, + ) -> RpcResult> + where + SV: StorageValue, + { + let connection_path = &ConnectionPath::new(connection_id); + + SV::value_at_key( + connection_path, + &self.ibc.connection_end_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_client_connections( + &self, + client_id: &ClientId, + ) -> RpcResult>> + where + SV: StorageValue, + { + let client_connection_path = &ClientConnectionPath::new(client_id.clone()); + + SV::value_at_key( + client_connection_path, + &self.ibc.client_connections_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_channel_end( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> RpcResult> + where + SV: StorageValue, + { + let channel_end_path = &ChannelEndPath::new(port_id, channel_id); + + SV::value_at_key( + channel_end_path, + &self.ibc.channel_end_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_send_sequence( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> RpcResult> + where + SV: StorageValue, + { + let seq_send_path = &SeqSendPath::new(port_id, channel_id); + + SV::value_at_key( + seq_send_path, + &self.ibc.send_sequence_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_recv_sequence( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> RpcResult> + where + SV: StorageValue, + { + let seq_recv_path = &SeqRecvPath::new(port_id, channel_id); + + SV::value_at_key( + seq_recv_path, + &self.ibc.recv_sequence_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_ack_sequence( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> RpcResult> + where + SV: StorageValue, + { + let seq_ack_path = &SeqAckPath::new(port_id, channel_id); + + SV::value_at_key( + seq_ack_path, + &self.ibc.ack_sequence_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_packet_commitment( + &self, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + ) -> RpcResult> + where + SV: StorageValue, + { + let commitment_path = &CommitmentPath::new(port_id, channel_id, sequence); + + SV::value_at_key( + commitment_path, + &self.ibc.packet_commitment_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_packet_receipt( + &self, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + ) -> RpcResult> + where + SV: StorageValue, + { + let receipt_path = &ReceiptPath::new(port_id, channel_id, sequence); + + SV::value_at_key( + receipt_path, + &self.ibc.packet_receipt_map, + *self.working_set.borrow_mut(), + ) + } + + pub fn query_packet_acknowledgement( + &self, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + ) -> RpcResult> + where + SV: StorageValue, + { + let ack_path = &AckPath::new(port_id, channel_id, sequence); + + SV::value_at_key( + ack_path, + &self.ibc.packet_ack_map, + *self.working_set.borrow_mut(), + ) + } +} impl<'a, S> ProvableContext for IbcContext<'a, S> where S: Spec, { - /// TODO: Should figure out how can access the proof from the context - fn get_proof(&self, _height: Height, _path: &Path) -> Option> { - Some(vec![]) + // NOTE: This is not efficient if used with a separate `get` call which returns only values. + // Because `get_with_proof` will retrieve proof along with the value anyway. + // Currently there is no way of retrieving only the proof. + fn get_proof(&self, height: Height, path: &Path) -> Option> { + let mut archival_working_set = self + .working_set + .borrow() + .get_archival_at(height.revision_height()); + + match path { + Path::ClientState(client_state_path) => self + .ibc + .client_state_map + .get_with_proof(&client_state_path.0, &mut archival_working_set), + Path::ClientConsensusState(client_consensus_state_path) => self + .ibc + .consensus_state_map + .get_with_proof(client_consensus_state_path, &mut archival_working_set), + Path::Connection(connection_path) => self + .ibc + .connection_end_map + .get_with_proof(connection_path, &mut archival_working_set), + Path::ClientConnection(client_connection_path) => self + .ibc + .client_connections_map + .get_with_proof(client_connection_path, &mut archival_working_set), + Path::ChannelEnd(channel_end_path) => self + .ibc + .channel_end_map + .get_with_proof(channel_end_path, &mut archival_working_set), + Path::SeqSend(seq_send_path) => self + .ibc + .send_sequence_map + .get_with_proof(seq_send_path, &mut archival_working_set), + Path::SeqRecv(seq_recv_path) => self + .ibc + .recv_sequence_map + .get_with_proof(seq_recv_path, &mut archival_working_set), + Path::Commitment(commitment_path) => self + .ibc + .packet_commitment_map + .get_with_proof(commitment_path, &mut archival_working_set), + Path::Ack(ack_path) => self + .ibc + .packet_ack_map + .get_with_proof(ack_path, &mut archival_working_set), + Path::Receipt(receipt_path) => self + .ibc + .packet_receipt_map + .get_with_proof(receipt_path, &mut archival_working_set), + // not required in ibc-core; but still implemented + Path::NextClientSequence(_) => self + .ibc + .client_counter + .get_with_proof(&mut archival_working_set), + Path::NextConnectionSequence(_) => self + .ibc + .connection_counter + .get_with_proof(&mut archival_working_set), + Path::NextChannelSequence(_) => self + .ibc + .channel_counter + .get_with_proof(&mut archival_working_set), + Path::UpgradeClient(upgrade_client_path) => self + .ibc + .upgraded_client_state_map + .get_with_proof(upgrade_client_path, &mut archival_working_set), + Path::SeqAck(seq_ack_path) => self + .ibc + .ack_sequence_map + .get_with_proof(seq_ack_path, &mut archival_working_set), + // not required, also not implemented; so `None` is returned + Path::ClientUpdateTime(_) | Path::ClientUpdateHeight(_) | Path::Ports(_) => None?, + } + .try_to_vec() + .ok() } } diff --git a/modules/sov-ibc/src/rpc/helpers.rs b/modules/sov-ibc/src/rpc/helpers.rs index b7384cf8..1158f0c7 100644 --- a/modules/sov-ibc/src/rpc/helpers.rs +++ b/modules/sov-ibc/src/rpc/helpers.rs @@ -1,11 +1,13 @@ use std::cell::RefCell; use std::rc::Rc; +use borsh::BorshSerialize; use ibc_core::client::types::Height; use ibc_core::host::ValidationContext; use jsonrpsee::core::RpcResult; use jsonrpsee::types::ErrorObjectOwned; -use sov_modules_api::{Spec, WorkingSet}; +use sov_modules_api::{Spec, StateMap, WorkingSet}; +use sov_state::storage::{StateCodec, StateItemCodec}; use crate::context::IbcContext; use crate::Ibc; @@ -40,3 +42,81 @@ pub fn to_jsonrpsee_error(err: impl ToString) -> ErrorObjectOwned { None::, ) } + +/// Trait for proof agnostic storage value retrieval. +/// +/// This trait is introduced to avoid duplication in the query methods +/// that fetch values with and without proofs - +/// [`WithProof`] and [`WithoutProof`] respectively. +/// +/// This trait allows to have a single query methods for both cases, e.g.: +/// ```ignore +/// let (client_state, proof) = ibc_ctx.query_client_state::(client_id)?; +/// let client_state = ibc_ctx.query_client_state::(client_id)?; +/// ``` +/// Although the [`WithProof`] case is only required for user-facing +/// query services, such as RPC, we generalized it to avoid code duplication. +pub trait StorageValue { + type Output; + fn value_at_key( + key: &K, + state_map: &StateMap, + working_set: &mut WorkingSet, + ) -> RpcResult> + where + S: Spec, + C: StateCodec, + ::ValueCodec: StateItemCodec, + ::KeyCodec: StateItemCodec; +} + +/// Implementation of [`StorageValue`] for values without proofs. +pub struct WithoutProof; + +impl StorageValue for WithoutProof { + type Output = Option; + + fn value_at_key( + key: &K, + state_map: &StateMap, + working_set: &mut WorkingSet, + ) -> RpcResult> + where + S: Spec, + C: StateCodec, + ::ValueCodec: StateItemCodec, + ::KeyCodec: StateItemCodec, + { + Ok(state_map.get(key, working_set)) + } +} + +/// Implementation of [`StorageValue`] for values with proofs. +pub struct WithProof; + +impl StorageValue for WithProof { + type Output = (Option, Vec); + + fn value_at_key( + key: &K, + state_map: &StateMap, + working_set: &mut WorkingSet, + ) -> RpcResult> + where + S: Spec, + C: StateCodec, + ::ValueCodec: StateItemCodec, + ::KeyCodec: StateItemCodec, + { + let result = state_map.get_with_proof(key, working_set); + + Ok(( + result + .value + .map(|bytes| state_map.codec().value_codec().try_decode(bytes.value())) + .transpose() + .map_err(|e| to_jsonrpsee_error(format!("{e:?}")))?, + result.proof.try_to_vec().map_err(to_jsonrpsee_error)?, + )) + } +} diff --git a/modules/sov-ibc/src/rpc/methods.rs b/modules/sov-ibc/src/rpc/methods.rs index d95f2691..cadcd524 100644 --- a/modules/sov-ibc/src/rpc/methods.rs +++ b/modules/sov-ibc/src/rpc/methods.rs @@ -2,55 +2,47 @@ use std::cell::RefCell; use std::rc::Rc; -use borsh::BorshSerialize; -use ibc_core::channel::types::commitment::PacketCommitment; -use ibc_core::host::types::path::{ClientConsensusStatePath, CommitmentPath, UpgradeClientPath}; +use ibc_core::client::context::client_state::ClientStateCommon; use ibc_core::host::ValidationContext; use ibc_query::core::channel::{ - query_channel, query_channel_client_state, query_channel_consensus_state, query_channels, - query_connection_channels, query_next_sequence_receive, query_packet_acknowledgement, - query_packet_acknowledgements, query_packet_commitments, query_packet_receipt, - query_unreceived_acks, query_unreceived_packets, QueryChannelClientStateRequest, - QueryChannelClientStateResponse, QueryChannelConsensusStateRequest, - QueryChannelConsensusStateResponse, QueryChannelRequest, QueryChannelResponse, - QueryChannelsRequest, QueryChannelsResponse, QueryConnectionChannelsRequest, - QueryConnectionChannelsResponse, QueryNextSequenceReceiveRequest, - QueryNextSequenceReceiveResponse, QueryPacketAcknowledgementRequest, - QueryPacketAcknowledgementResponse, QueryPacketAcknowledgementsRequest, - QueryPacketAcknowledgementsResponse, QueryPacketCommitmentRequest, - QueryPacketCommitmentResponse, QueryPacketCommitmentsRequest, QueryPacketCommitmentsResponse, - QueryPacketReceiptRequest, QueryPacketReceiptResponse, QueryUnreceivedAcksRequest, - QueryUnreceivedAcksResponse, QueryUnreceivedPacketsRequest, QueryUnreceivedPacketsResponse, + query_channel_consensus_state, query_channels, query_connection_channels, + query_packet_acknowledgements, query_packet_commitments, query_unreceived_acks, + query_unreceived_packets, QueryChannelClientStateRequest, QueryChannelClientStateResponse, + QueryChannelConsensusStateRequest, QueryChannelConsensusStateResponse, QueryChannelRequest, + QueryChannelResponse, QueryChannelsRequest, QueryChannelsResponse, + QueryConnectionChannelsRequest, QueryConnectionChannelsResponse, + QueryNextSequenceReceiveRequest, QueryNextSequenceReceiveResponse, + QueryPacketAcknowledgementRequest, QueryPacketAcknowledgementResponse, + QueryPacketAcknowledgementsRequest, QueryPacketAcknowledgementsResponse, + QueryPacketCommitmentRequest, QueryPacketCommitmentResponse, QueryPacketCommitmentsRequest, + QueryPacketCommitmentsResponse, QueryPacketReceiptRequest, QueryPacketReceiptResponse, + QueryUnreceivedAcksRequest, QueryUnreceivedAcksResponse, QueryUnreceivedPacketsRequest, + QueryUnreceivedPacketsResponse, }; use ibc_query::core::client::{ query_client_states, query_client_status, query_consensus_state_heights, - query_consensus_states, QueryClientStateRequest, QueryClientStateResponse, - QueryClientStatesRequest, QueryClientStatesResponse, QueryClientStatusRequest, - QueryClientStatusResponse, QueryConsensusStateHeightsRequest, + query_consensus_states, IdentifiedClientState, QueryClientStateRequest, + QueryClientStateResponse, QueryClientStatesRequest, QueryClientStatesResponse, + QueryClientStatusRequest, QueryClientStatusResponse, QueryConsensusStateHeightsRequest, QueryConsensusStateHeightsResponse, QueryConsensusStateRequest, QueryConsensusStateResponse, QueryConsensusStatesRequest, QueryConsensusStatesResponse, QueryUpgradedClientStateRequest, QueryUpgradedClientStateResponse, QueryUpgradedConsensusStateRequest, QueryUpgradedConsensusStateResponse, }; use ibc_query::core::connection::{ - query_client_connections, query_connection, query_connection_client_state, - query_connection_consensus_state, query_connection_params, query_connections, - QueryClientConnectionsRequest, QueryClientConnectionsResponse, - QueryConnectionClientStateRequest, QueryConnectionClientStateResponse, - QueryConnectionConsensusStateRequest, QueryConnectionConsensusStateResponse, - QueryConnectionParamsRequest, QueryConnectionParamsResponse, QueryConnectionRequest, - QueryConnectionResponse, QueryConnectionsRequest, QueryConnectionsResponse, + query_connection_params, query_connections, QueryClientConnectionsRequest, + QueryClientConnectionsResponse, QueryConnectionClientStateRequest, + QueryConnectionClientStateResponse, QueryConnectionConsensusStateRequest, + QueryConnectionConsensusStateResponse, QueryConnectionParamsRequest, + QueryConnectionParamsResponse, QueryConnectionRequest, QueryConnectionResponse, + QueryConnectionsRequest, QueryConnectionsResponse, }; use jsonrpsee::core::RpcResult; -use sov_celestia_client::client_state::ClientState as HostClientState; -use sov_celestia_client::consensus_state::ConsensusState as HostConsensusState; use sov_modules_api::macros::rpc_gen; -use sov_modules_api::{ProvenStateAccessor, Spec, WorkingSet}; -use sov_state::storage::{SlotKey, StateCodec, StateItemCodec}; +use sov_modules_api::{Spec, WorkingSet}; -use crate::clients::{AnyClientState, AnyConsensusState}; use crate::context::IbcContext; -use crate::helpers::to_jsonrpsee_error; +use crate::helpers::{to_jsonrpsee_error, WithProof, WithoutProof}; use crate::Ibc; /// Structure returned by the `client_state` rpc method. @@ -63,33 +55,20 @@ impl Ibc { working_set: &mut WorkingSet, ) -> RpcResult { let proof_height = self.determine_query_height(request.query_height, working_set)?; - let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); - let value_with_proof = self - .client_state_map - .get_with_proof(&request.client_id, &mut archival_working_set); - - let storage_value = value_with_proof.value.ok_or_else(|| { - to_jsonrpsee_error(format!( - "Client state not found for client {:?}", - request.client_id - )) - })?; - - let client_state: AnyClientState = self - .client_state_map - .codec() - .try_decode(storage_value.value()) - .map_err(to_jsonrpsee_error)?; - - let proof = value_with_proof - .proof - .try_to_vec() - .map_err(to_jsonrpsee_error)?; + let (client_state, proof) = ibc_ctx.query_client_state::(&request.client_id)?; Ok(QueryClientStateResponse::new( - client_state.into(), + client_state + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Client state not found for client {:?}", + request.client_id + )) + })? + .into(), proof, proof_height, )) @@ -115,54 +94,31 @@ impl Ibc { request: QueryConsensusStateRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let prefix = self.consensus_state_map.prefix(); - - let codec = self.consensus_state_map.codec(); + let proof_height = self.determine_query_height(request.query_height, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); - let consensus_height = match request.consensus_height { - Some(height) => height, - None => { - return Err(to_jsonrpsee_error( - "Consensus height is required for querying consensus state", - )) - } - }; + let consensus_height = request.consensus_height.ok_or_else(|| { + to_jsonrpsee_error("Consensus height is required for querying consensus state") + })?; - let path = ClientConsensusStatePath::new( - request.client_id.clone(), + let (consensus_state, proof) = ibc_ctx.query_client_consensus_state::( + &request.client_id, consensus_height.revision_number(), consensus_height.revision_height(), - ); - - let key = SlotKey::new(prefix, &path, codec.key_codec()); - - let value_with_proof = working_set.get_with_proof(key); - - let storage_value = value_with_proof.value.ok_or_else(|| { - to_jsonrpsee_error(format!( - "Consensus state not found for client {:?}", - request.client_id - )) - })?; - - let consensus_state: AnyConsensusState = codec - .try_decode(storage_value.value()) - .map_err(to_jsonrpsee_error)?; - - let proof = value_with_proof - .proof - .try_to_vec() - .map_err(to_jsonrpsee_error)?; - - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; + )?; let proof_height = ibc_ctx.host_height().map_err(to_jsonrpsee_error)?; Ok(QueryConsensusStateResponse::new( - consensus_state.into(), + consensus_state + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Consensus state not found for client {:?} at height {:?}", + request.client_id, consensus_height + )) + })? + .into(), proof, proof_height, )) @@ -217,35 +173,20 @@ impl Ibc { working_set: &mut WorkingSet, ) -> RpcResult { let proof_height = self.determine_query_height(request.query_height, working_set)?; - - let upgrade_client_path = - UpgradeClientPath::UpgradedClientState(proof_height.revision_height()); - let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); - let value_with_proof = self - .upgraded_client_state_map - .get_with_proof(&upgrade_client_path, &mut archival_working_set); - - let storage_value = value_with_proof.value.ok_or_else(|| { - to_jsonrpsee_error(format!( - "upgraded client state not found at: {proof_height:?}", - )) - })?; - - let upgraded_client_state: HostClientState = self - .upgraded_client_state_map - .codec() - .try_decode(storage_value.value()) - .map_err(to_jsonrpsee_error)?; - - let proof = value_with_proof - .proof - .try_to_vec() - .map_err(to_jsonrpsee_error)?; + let (upgraded_client_state, proof) = + ibc_ctx.query_upgraded_client_state::(proof_height.revision_height())?; Ok(QueryUpgradedClientStateResponse::new( - upgraded_client_state.into(), + upgraded_client_state + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Upgraded client state not found at height {proof_height:?}" + )) + })? + .into(), proof, proof_height, )) @@ -258,35 +199,20 @@ impl Ibc { working_set: &mut WorkingSet, ) -> RpcResult { let proof_height = self.determine_query_height(request.query_height, working_set)?; - - let upgrade_consensus_path = - UpgradeClientPath::UpgradedClientConsensusState(proof_height.revision_height()); - let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); - let value_with_proof = self - .upgraded_consensus_state_map - .get_with_proof(&upgrade_consensus_path, &mut archival_working_set); - - let storage_value = value_with_proof.value.ok_or_else(|| { - to_jsonrpsee_error(format!( - "upgraded consensus state not found at: {proof_height:?}", - )) - })?; - - let upgraded_consensus_state: HostConsensusState = self - .upgraded_consensus_state_map - .codec() - .try_decode(storage_value.value()) - .map_err(to_jsonrpsee_error)?; - - let proof = value_with_proof - .proof - .try_to_vec() - .map_err(to_jsonrpsee_error)?; + let (upgraded_consensus_state, proof) = + ibc_ctx.query_upgraded_consensus_state::(proof_height.revision_height())?; Ok(QueryUpgradedConsensusStateResponse::new( - upgraded_consensus_state.into(), + upgraded_consensus_state + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Upgraded consensus state not found at height {proof_height:?}" + )) + })? + .into(), proof, proof_height, )) @@ -298,12 +224,23 @@ impl Ibc { request: QueryConnectionRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; + let proof_height = self.determine_query_height(request.query_height, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); - query_connection(&ibc_ctx, &request).map_err(to_jsonrpsee_error) + let (connection_end, proof) = + ibc_ctx.query_connection_end::(&request.connection_id)?; + + Ok(QueryConnectionResponse::new( + connection_end.ok_or_else(|| { + to_jsonrpsee_error(format!( + "Connection not found for connection id {:?}", + request.connection_id + )) + })?, + proof, + proof_height, + )) } #[rpc_method(name = "connections")] @@ -326,12 +263,23 @@ impl Ibc { request: QueryClientConnectionsRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; + let proof_height = self.determine_query_height(None, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); - query_client_connections(&ibc_ctx, &request).map_err(to_jsonrpsee_error) + let (client_connections, proof) = + ibc_ctx.query_client_connections::(&request.client_id)?; + + Ok(QueryClientConnectionsResponse::new( + client_connections.ok_or_else(|| { + to_jsonrpsee_error(format!( + "Client connections not found for client id {:?}", + request.client_id + )) + })?, + proof, + proof_height, + )) } #[rpc_method(name = "connectionClientState")] @@ -340,12 +288,37 @@ impl Ibc { request: QueryConnectionClientStateRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; - - query_connection_client_state(&ibc_ctx, &request).map_err(to_jsonrpsee_error) + let proof_height = self.determine_query_height(request.query_height, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); + + let connection_end = ibc_ctx + .query_connection_end::(&request.connection_id)? + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Connection not found for connection id {:?}", + request.connection_id + )) + })?; + + let (client_state, proof) = + ibc_ctx.query_client_state::(connection_end.client_id())?; + + Ok(QueryConnectionClientStateResponse::new( + IdentifiedClientState::new( + connection_end.client_id().clone(), + client_state + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Client state not found for connection {:?}", + request.connection_id + )) + })? + .into(), + ), + proof, + proof_height, + )) } #[rpc_method(name = "connectionConsensusState")] @@ -354,12 +327,38 @@ impl Ibc { request: QueryConnectionConsensusStateRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; - - query_connection_consensus_state(&ibc_ctx, &request).map_err(to_jsonrpsee_error) + let proof_height = self.determine_query_height(request.query_height, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); + + let connection_end = ibc_ctx + .query_connection_end::(&request.connection_id)? + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Connection not found for connection id {:?}", + request.connection_id + )) + })?; + + let (consensus_state, proof) = ibc_ctx.query_client_consensus_state::( + connection_end.client_id(), + request.height.revision_number(), + request.height.revision_height(), + )?; + + Ok(QueryConnectionConsensusStateResponse::new( + consensus_state + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Consensus state not found for connection {:?}", + request.connection_id + )) + })? + .into(), + connection_end.client_id().clone(), + proof, + proof_height, + )) } #[rpc_method(name = "connectionParams")] @@ -382,12 +381,23 @@ impl Ibc { request: QueryChannelRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; + let proof_height = self.determine_query_height(request.query_height, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); + + let (channel_end, proof) = + ibc_ctx.query_channel_end::(&request.port_id, &request.channel_id)?; - query_channel(&ibc_ctx, &request).map_err(to_jsonrpsee_error) + Ok(QueryChannelResponse::new( + channel_end.ok_or_else(|| { + to_jsonrpsee_error(format!( + "Channel not found for port id {:?} and channel id {:?}", + request.port_id, request.channel_id + )) + })?, + proof, + proof_height, + )) } #[rpc_method(name = "channels")] @@ -424,12 +434,53 @@ impl Ibc { request: QueryChannelClientStateRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; + let proof_height = self.determine_query_height(request.query_height, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); + + let channel_end = ibc_ctx + .query_channel_end::(&request.port_id, &request.channel_id)? + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Channel not found for port id {:?} and channel id {:?}", + request.port_id, request.channel_id + )) + })?; + + let connection_id = channel_end.connection_hops().first().ok_or_else(|| { + to_jsonrpsee_error(format!( + "ConnectionId not found for channel {:?}", + request.channel_id + )) + })?; - query_channel_client_state(&ibc_ctx, &request).map_err(to_jsonrpsee_error) + let connection_end = ibc_ctx + .query_connection_end::(connection_id)? + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "ConnectionEnd not found for channel {:?}", + request.channel_id + )) + })?; + + let (client_state, proof) = + ibc_ctx.query_client_state::(connection_end.client_id())?; + + Ok(QueryChannelClientStateResponse::new( + IdentifiedClientState::new( + connection_end.client_id().clone(), + client_state + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Client state not found for channel {:?}", + request.channel_id + )) + })? + .into(), + ), + proof, + proof_height, + )) } #[rpc_method(name = "channelConsensusState")] @@ -438,10 +489,51 @@ impl Ibc { request: QueryChannelConsensusStateRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; + let proof_height = self.determine_query_height(request.query_height, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); + + let channel_end = ibc_ctx + .query_channel_end::(&request.port_id, &request.channel_id)? + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Channel not found for port id {:?} and channel id {:?}", + request.port_id, request.channel_id + )) + })?; + + let connection_id = channel_end.connection_hops().first().ok_or_else(|| { + to_jsonrpsee_error(format!( + "ConnectionId not found for channel {:?}", + request.channel_id + )) + })?; + + let connection_end = ibc_ctx + .query_connection_end::(connection_id)? + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "ConnectionEnd not found for channel {:?}", + request.channel_id + )) + })?; + + let client_state = ibc_ctx + .query_client_state::(connection_end.client_id())? + .ok_or_else(|| { + to_jsonrpsee_error(format!( + "Client state not found for channel {:?}", + request.channel_id + )) + })?; + + let client_latest_height = client_state.latest_height(); + + let (consensus_state, proof) = ibc_ctx.query_client_consensus_state::( + connection_end.client_id(), + client_latest_height.revision_number(), + client_latest_height.revision_height(), + )?; query_channel_consensus_state(&ibc_ctx, &request).map_err(to_jsonrpsee_error) } @@ -452,30 +544,23 @@ impl Ibc { request: QueryPacketCommitmentRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let commitment_path = - CommitmentPath::new(&request.port_id, &request.channel_id, request.sequence); - let proof_height = self.determine_query_height(request.query_height, working_set)?; - let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); - let value_with_proof = self - .packet_commitment_map - .get_with_proof(&commitment_path, &mut archival_working_set); - - let proof = value_with_proof - .proof - .try_to_vec() - .map_err(to_jsonrpsee_error)?; - - let storage_value = value_with_proof.value.ok_or_else(|| { - to_jsonrpsee_error(format!( - "Packet commitment not found for path {commitment_path:?}" - )) - })?; + let (commitment, proof) = ibc_ctx.query_packet_commitment::( + &request.port_id, + &request.channel_id, + request.sequence, + )?; Ok(QueryPacketCommitmentResponse::new( - PacketCommitment::from(storage_value.value().to_vec()), + commitment.ok_or_else(|| { + to_jsonrpsee_error(format!( + "Packet commitment not found for port id {:?}, channel id {:?} and sequence {:?}", + request.port_id, request.channel_id, request.sequence + )) + })?, proof, proof_height, )) @@ -501,12 +586,24 @@ impl Ibc { request: QueryPacketReceiptRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; - - query_packet_receipt(&ibc_ctx, &request).map_err(to_jsonrpsee_error) + let proof_height = self.determine_query_height(request.query_height, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); + + let (receipt, proof) = ibc_ctx.query_packet_receipt::( + &request.port_id, + &request.channel_id, + request.sequence, + )?; + + // packet_receipt_map models a set using constant unit value. + // when the key (doesn't) exists in the map, + // the receipt is (not) present and returns a (non) membership proof + Ok(QueryPacketReceiptResponse::new( + receipt.is_some(), + proof, + proof_height, + )) } #[rpc_method(name = "packetAcknowledgement")] @@ -515,12 +612,26 @@ impl Ibc { request: QueryPacketAcknowledgementRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; - - query_packet_acknowledgement(&ibc_ctx, &request).map_err(to_jsonrpsee_error) + let proof_height = self.determine_query_height(request.query_height, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); + + let (acknowledgement, proof) = ibc_ctx.query_packet_acknowledgement::( + &request.port_id, + &request.channel_id, + request.sequence, + )?; + + Ok(QueryPacketAcknowledgementResponse::new( + acknowledgement.ok_or_else(|| { + to_jsonrpsee_error(format!( + "Packet acknowledgement not found for port id {:?}, channel id {:?} and sequence {:?}", + request.port_id, request.channel_id, request.sequence + )) + })?, + proof, + proof_height, + )) } #[rpc_method(name = "packetAcknowledgements")] @@ -571,11 +682,22 @@ impl Ibc { request: QueryNextSequenceReceiveRequest, working_set: &mut WorkingSet, ) -> RpcResult { - let ibc_ctx = IbcContext { - ibc: self, - working_set: Rc::new(RefCell::new(working_set)), - }; + let proof_height = self.determine_query_height(request.query_height, working_set)?; + let mut archival_working_set = working_set.get_archival_at(proof_height.revision_height()); + let ibc_ctx = IbcContext::new(self, Rc::new(RefCell::new(&mut archival_working_set))); - query_next_sequence_receive(&ibc_ctx, &request).map_err(to_jsonrpsee_error) + let (sequence, proof) = + ibc_ctx.query_recv_sequence::(&request.port_id, &request.channel_id)?; + + Ok(QueryNextSequenceReceiveResponse::new( + sequence.ok_or_else(|| { + to_jsonrpsee_error(format!( + "Next sequence receive not found for port id {:?} and channel id {:?}", + request.port_id, request.channel_id + )) + })?, + proof, + proof_height, + )) } }