diff --git a/Cargo.lock b/Cargo.lock index 59bed09c1..36d63c0b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -960,7 +960,7 @@ dependencies = [ [[package]] name = "ckb-ics-axon" version = "0.1.0" -source = "git+https://github.com/synapseweb3/ckb-ics.git?rev=cda7d4e#cda7d4ebbd89002fa983e43e79be722e83181304" +source = "git+https://github.com/synapseweb3/ckb-ics.git?rev=aa894e3#aa894e3766333e002c7164f23f28f817d6b90023" dependencies = [ "bytes", "ethereum-types", diff --git a/crates/relayer/Cargo.toml b/crates/relayer/Cargo.toml index 0f33e3935..8f33d8467 100644 --- a/crates/relayer/Cargo.toml +++ b/crates/relayer/Cargo.toml @@ -99,7 +99,7 @@ jsonrpc-core = "18.0" strum = { version = "0.24.1", features = ["derive"] } lazy_static = "1.4.0" -ckb-ics-axon = { git = "https://github.com/synapseweb3/ckb-ics.git", rev = "cda7d4e" } +ckb-ics-axon = { git = "https://github.com/synapseweb3/ckb-ics.git", rev = "aa894e3" } cstr_core = "0.2.6" rlp = "0.5.2" diff --git a/crates/relayer/src/chain/axon.rs b/crates/relayer/src/chain/axon.rs index 8dc6a3a87..94ad6029d 100644 --- a/crates/relayer/src/chain/axon.rs +++ b/crates/relayer/src/chain/axon.rs @@ -27,7 +27,10 @@ use ethers::{ types::{BlockNumber, TransactionRequest, TxHash, U64}, utils::rlp, }; -use ibc_proto::google::protobuf::Any; +use ibc_proto::{ + google::protobuf::Any, + ibc::apps::fee::v1::{QueryIncentivizedPacketRequest, QueryIncentivizedPacketResponse}, +}; use ibc_relayer_types::{ applications::ics31_icq::response::CrossChainQueryResponse, clients::ics07_axon::{ @@ -47,7 +50,7 @@ use ibc_relayer_types::{ msgs::{conn_open_ack, conn_open_confirm, conn_open_init, conn_open_try}, }, ics04_channel::{ - channel::{ChannelEnd, IdentifiedChannelEnd}, + channel::{ChannelEnd, IdentifiedChannelEnd, Order}, msgs::{ acknowledgement, chan_close_confirm, chan_close_init, chan_open_ack, chan_open_confirm, chan_open_init, chan_open_try, recv_packet, timeout, @@ -610,29 +613,57 @@ impl ChainEndpoint for AxonChain { .call(), ) .map_err(convert_err)?; - Ok((vec![has_receipt as u8], None)) + if has_receipt { + Ok((vec![1u8], None)) + } else { + Ok((vec![], None)) + } } fn query_unreceived_packets( &self, request: QueryUnreceivedPacketsRequest, ) -> Result, Error> { + let (channel, _) = self.query_channel( + QueryChannelRequest { + port_id: request.port_id.clone(), + channel_id: request.channel_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + )?; let mut sequences: Vec = vec![]; - for seq in request.packet_commitment_sequences { - let has_receipt = self - .rt - .block_on( - self.contract - .has_packet_receipt( - request.port_id.to_string(), - request.channel_id.to_string(), - seq.into(), - ) - .call(), - ) - .map_err(convert_err)?; - if !has_receipt { - sequences.push(seq); + if channel.ordering == Order::Ordered { + let (max_recv_seq, _) = self.query_next_sequence_receive( + QueryNextSequenceReceiveRequest { + port_id: request.port_id, + channel_id: request.channel_id, + height: QueryHeight::Latest, + }, + IncludeProof::No, + )?; + sequences = request + .packet_commitment_sequences + .into_iter() + .filter(|seq| *seq >= max_recv_seq) + .collect(); + } else if channel.ordering == Order::Unordered { + for seq in request.packet_commitment_sequences { + let has_receipt = self + .rt + .block_on( + self.contract + .has_packet_receipt( + request.port_id.to_string(), + request.channel_id.to_string(), + seq.into(), + ) + .call(), + ) + .map_err(convert_err)?; + if !has_receipt { + sequences.push(seq); + } } } Ok(sequences) @@ -643,10 +674,6 @@ impl ChainEndpoint for AxonChain { request: QueryPacketAcknowledgementRequest, _include_proof: IncludeProof, ) -> Result<(Vec, Option), Error> { - if matches!(request.height, QueryHeight::Specific(_)) { - // TODO: no implemention for specific acknowledgement query - warn!("search packet acknoledgement at specific height will fallback to latest"); - } let (commitment, _) = self .rt .block_on( @@ -750,14 +777,20 @@ impl ChainEndpoint for AxonChain { &self, _request: QueryHostConsensusStateRequest, ) -> Result { - todo!() + // TODO + warn!("axon query_host_consensus_state() not support"); + Ok(AxonConsensusState {}) } fn query_incentivized_packet( &self, - _request: ibc_proto::ibc::apps::fee::v1::QueryIncentivizedPacketRequest, - ) -> Result { - todo!() + _request: QueryIncentivizedPacketRequest, + ) -> Result { + // TODO + warn!("axon query_incentivized_packet() not support"); + Ok(QueryIncentivizedPacketResponse { + incentivized_packet: None, + }) } fn build_client_state( diff --git a/crates/relayer/src/chain/ckb4ibc.rs b/crates/relayer/src/chain/ckb4ibc.rs index e16ac9f21..bda999ffe 100644 --- a/crates/relayer/src/chain/ckb4ibc.rs +++ b/crates/relayer/src/chain/ckb4ibc.rs @@ -22,6 +22,7 @@ use crate::misbehaviour::MisbehaviourEvidence; use ckb_ics_axon::handler::{IbcChannel, IbcConnections, IbcPacket, PacketStatus}; use ckb_ics_axon::message::Envelope; +use ckb_ics_axon::object::Ordering; use ckb_ics_axon::{ChannelArgs, PacketArgs}; use ckb_jsonrpc_types::{JsonBytes, Status, TransactionView}; use ckb_sdk::constants::TYPE_ID_CODE_HASH; @@ -62,6 +63,7 @@ use ibc_relayer_types::proofs::Proofs; use ibc_relayer_types::signer::Signer; use ibc_relayer_types::timestamp::Timestamp; use ibc_relayer_types::Height; +use rlp::Encodable; use semver::Version; use std::sync::RwLock; use tendermint_rpc::endpoint::broadcast::tx_sync::Response; @@ -270,8 +272,8 @@ impl Ckb4IbcChain { fn fetch_channel_cell_and_extract( &self, - channel_id: ChannelId, - port_id: PortId, + channel_id: &ChannelId, + port_id: &PortId, is_open: bool, ) -> Result<(ChannelEnd, IbcChannel), Error> { let channel_code_hash = self.get_converter()?.get_channel_code_hash(); @@ -281,8 +283,8 @@ impl Ckb4IbcChain { let channel_args = ChannelArgs { client_id, open: is_open, - channel_id: get_channel_number(&channel_id)?, - port_id: convert_port_id_to_array(&port_id)?, + channel_id: get_channel_number(channel_id)?, + port_id: convert_port_id_to_array(port_id)?, }; let script = Script::new_builder() .code_hash(channel_code_hash) @@ -949,15 +951,13 @@ impl ChainEndpoint for Ckb4IbcChain { request: QueryChannelRequest, _include_proof: IncludeProof, ) -> Result<(ChannelEnd, Option), Error> { - if let Ok((channel, _)) = self.fetch_channel_cell_and_extract( - request.channel_id.clone(), - request.port_id.clone(), - false, - ) { + if let Ok((channel, _)) = + self.fetch_channel_cell_and_extract(&request.channel_id, &request.port_id, false) + { Ok((channel, None)) } else { let (channel, _) = - self.fetch_channel_cell_and_extract(request.channel_id, request.port_id, true)?; + self.fetch_channel_cell_and_extract(&request.channel_id, &request.port_id, true)?; Ok((channel, None)) } } @@ -1002,20 +1002,8 @@ impl ChainEndpoint for Ckb4IbcChain { if ibc_packet.status != PacketStatus::Send { Ok((vec![], None)) } else { - Ok(( - PacketArgs { - channel_id: get_channel_number(&request.channel_id)?, - port_id: ibc_packet - .packet - .source_port_id - .as_bytes() - .try_into() - .unwrap(), - sequence: ibc_packet.packet.sequence, - } - .get_search_args(false), - None, - )) + let commitment = keccak256(&ibc_packet.rlp_bytes()).to_vec(); + Ok((commitment, None)) } } @@ -1023,6 +1011,7 @@ impl ChainEndpoint for Ckb4IbcChain { &self, request: QueryPacketCommitmentsRequest, ) -> Result<(Vec, Height), Error> { + // get all packets' commitment without pagination let sequences = self .fetch_packet_cells_and_extract(&request.channel_id, &request.port_id, None)? .into_iter() @@ -1036,54 +1025,93 @@ impl ChainEndpoint for Ckb4IbcChain { request: QueryPacketReceiptRequest, _include_proof: IncludeProof, ) -> Result<(Vec, Option), Error> { - let (ibc_packet, _) = self.fetch_packet_cell_and_extract( - &request.channel_id, - &request.port_id, - request.sequence, - )?; - if ibc_packet.status != PacketStatus::Recv { - Ok((vec![], None)) + let generate_receipt = |channel: IbcChannel| { + if channel.order == Ordering::Unordered { + Ok((vec![1u8], None)) + } else { + Ok((vec![], None)) + } + }; + let (_, channel) = + self.fetch_channel_cell_and_extract(&request.channel_id, &request.port_id, true)?; + if channel.sequence.next_sequence_recvs as u64 > request.sequence.into() { + generate_receipt(channel) } else { - Ok(( - PacketArgs { - channel_id: get_channel_number(&request.channel_id)?, - port_id: ibc_packet - .packet - .source_port_id - .as_bytes() - .try_into() - .unwrap(), - sequence: ibc_packet.packet.sequence, - } - .get_search_args(false), - None, - )) + let (ibc_packet, _) = self.fetch_packet_cell_and_extract( + &request.channel_id, + &request.port_id, + request.sequence, + )?; + if ibc_packet.status != PacketStatus::Recv { + Ok((vec![], None)) + } else { + generate_receipt(channel) + } } } fn query_unreceived_packets( &self, - _request: QueryUnreceivedPacketsRequest, + request: QueryUnreceivedPacketsRequest, ) -> Result, Error> { - // TODO: fix it when Ckb4Ibc contract refactorred - Ok(vec![]) + let (_, channel) = + self.fetch_channel_cell_and_extract(&request.channel_id, &request.port_id, true)?; + let sequences = request + .packet_commitment_sequences + .into_iter() + .filter(|sequence| { + if (channel.sequence.next_sequence_recvs as u64) < (*sequence).into() { + return false; + } + let Ok((packet, _)) = self.fetch_packet_cell_and_extract( + &request.channel_id, + &request.port_id, + *sequence, + ) else { + return true; + }; + if packet.status != PacketStatus::Recv { + return true; + } + false + }) + .collect(); + Ok(sequences) } - // FIXME: acknowledgement is NOT tx_hash fn query_packet_acknowledgement( &self, request: QueryPacketAcknowledgementRequest, _include_proof: IncludeProof, ) -> Result<(Vec, Option), Error> { - let (ibc_packet, _) = self.fetch_packet_cell_and_extract( + let result = self.fetch_packet_cell_and_extract( &request.channel_id, &request.port_id, request.sequence, - )?; - if ibc_packet.status != PacketStatus::WriteAck { - Ok((vec![], None)) + ); + if let Ok((ibc_packet, _)) = result { + if ibc_packet.status != PacketStatus::WriteAck || ibc_packet.status != PacketStatus::Ack + { + Ok((vec![], None)) + } else { + // no matter the `data` is empty or not, we recognize the acknowledge is committed + // if the `WriteAck` cell exists + let ack_commitment = keccak256(&ibc_packet.packet.data).to_vec(); + Ok((ack_commitment, None)) + } } else { - Ok((ibc_packet.tx_hash.unwrap().as_bytes().to_vec(), None)) + // check the sequence status in channel if the packet cell under required sequence not found + let (_, channel) = + self.fetch_channel_cell_and_extract(&request.channel_id, &request.port_id, true)?; + if channel.sequence.next_sequence_recvs as u64 > request.sequence.into() { + // since the previous `WriteAck` cells are consumed and hard to fetch from CKB, we + // just use mock acknowledgement in return which in Hermes runtime is not sensitive + // with its real content but just used as Yes or No option + let ack_commitment = keccak256(b"unfetchable acknowledgement").to_vec(); + Ok((ack_commitment, None)) + } else { + Ok((vec![], None)) + } } } @@ -1091,37 +1119,57 @@ impl ChainEndpoint for Ckb4IbcChain { &self, request: QueryPacketAcknowledgementsRequest, ) -> Result<(Vec, Height), Error> { - let port_id = request.port_id; - let channel_id = request.channel_id; - let result = request + let sequences = request .packet_commitment_sequences .into_iter() - .flat_map(|seq| self.fetch_packet_cell_and_extract(&channel_id, &port_id, seq)) - .filter(|(packet, _)| packet.status == PacketStatus::WriteAck) - .map(|(p, _)| Sequence::from(p.packet.sequence as u64)) - .collect::>(); - Ok((result, Height::default())) + .filter(|sequence| { + let Ok((acknowledgement, _)) = self.query_packet_acknowledgement( + QueryPacketAcknowledgementRequest { + port_id: request.port_id.clone(), + channel_id: request.channel_id.clone(), + sequence: *sequence, + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) else { + return false; + }; + if acknowledgement.is_empty() { + return false; + } + true + }) + .collect(); + Ok((sequences, Height::default())) } fn query_unreceived_acknowledgements( &self, request: QueryUnreceivedAcksRequest, ) -> Result, Error> { - let port_id = request.port_id; - let channel_id = request.channel_id; - let mut data = self.packet_input_data.borrow_mut(); - let result = request + let (_, channel) = + self.fetch_channel_cell_and_extract(&request.channel_id, &request.port_id, true)?; + let sequences = request .packet_ack_sequences .into_iter() - .flat_map(|seq| self.fetch_packet_cell_and_extract(&channel_id, &port_id, seq)) - .filter(|(packet, _)| packet.status == PacketStatus::Send) - .map(|(p, cell_input)| { - let seq = Sequence::from(p.packet.sequence as u64); - data.insert((channel_id.clone(), port_id.clone(), seq), cell_input); - seq + .filter(|sequence| { + if channel.sequence.next_sequence_acks as u64 > (*sequence).into() { + return false; + } + let Ok((packet, _)) = self.fetch_packet_cell_and_extract( + &request.channel_id, + &request.port_id, + *sequence, + ) else { + return true; + }; + if packet.status != PacketStatus::Ack { + return true; + } + false }) - .collect::>(); - Ok(result) + .collect(); + Ok(sequences) } fn query_next_sequence_receive( @@ -1130,7 +1178,7 @@ impl ChainEndpoint for Ckb4IbcChain { _include_proof: IncludeProof, ) -> Result<(Sequence, Option), Error> { let (_, ibc_channel) = - self.fetch_channel_cell_and_extract(request.channel_id, request.port_id, true)?; + self.fetch_channel_cell_and_extract(&request.channel_id, &request.port_id, true)?; let sequence = (ibc_channel.sequence.next_sequence_recvs as u64).into(); Ok((sequence, None)) } diff --git a/tools/ckb4ibc-test/Cargo.toml b/tools/ckb4ibc-test/Cargo.toml index 4fe7b2d16..741a57846 100644 --- a/tools/ckb4ibc-test/Cargo.toml +++ b/tools/ckb4ibc-test/Cargo.toml @@ -27,7 +27,7 @@ jsonrpc-core = "18.0" futures = "0.3.27" serde_json = { version = "1", default-features = false } serde = { version = "1.0", default-features = false } -ckb-ics-axon = { git = "https://github.com/synapseweb3/ckb-ics.git", rev = "cda7d4e" } +ckb-ics-axon = { git = "https://github.com/synapseweb3/ckb-ics.git", rev = "aa894e3" } rlp = "0.5.2" secp256k1 = "0.24" ckb-hash = "0.106" diff --git a/tools/ckb4ibc-test/contracts/ics-channel b/tools/ckb4ibc-test/contracts/ics-channel index 60d71d54f..cdbf89289 100644 Binary files a/tools/ckb4ibc-test/contracts/ics-channel and b/tools/ckb4ibc-test/contracts/ics-channel differ diff --git a/tools/ckb4ibc-test/contracts/ics-connection b/tools/ckb4ibc-test/contracts/ics-connection index aa3b65ba2..70d7171b6 100644 Binary files a/tools/ckb4ibc-test/contracts/ics-connection and b/tools/ckb4ibc-test/contracts/ics-connection differ diff --git a/tools/ckb4ibc-test/contracts/ics-packet b/tools/ckb4ibc-test/contracts/ics-packet index b212e880c..098f3e063 100644 Binary files a/tools/ckb4ibc-test/contracts/ics-packet and b/tools/ckb4ibc-test/contracts/ics-packet differ diff --git a/tools/ckb4ibc-test/contracts/version b/tools/ckb4ibc-test/contracts/version index 387f8d919..d85572714 100644 --- a/tools/ckb4ibc-test/contracts/version +++ b/tools/ckb4ibc-test/contracts/version @@ -2,6 +2,6 @@ all-contracts-in-debug-mode -commit: 7e1ab522262489513c11122ddd32b0d4a7823c70 +commit: 8dc3c92 - +