Skip to content

Commit 186271a

Browse files
committed
Primitive packet trace
Allows to check the current status of the packet
1 parent f69a537 commit 186271a

File tree

6 files changed

+140
-9
lines changed

6 files changed

+140
-9
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contracts/pallet-ibc/rpc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-
2727
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }
2828
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }
2929
tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", rev = "e81f7bf23d63ffbcd242381d1ce5e35da3515ff1", default-features = false }
30+
hex = "0.4.3"
3031

3132
[dependencies.ibc]
3233
path = "../../../ibc/modules"

contracts/pallet-ibc/rpc/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ pub struct PacketInfo {
136136
pub ack: Option<Vec<u8>>,
137137
}
138138

139+
impl Display for PacketInfo {
140+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141+
write!(f, "PacketInfo {{ height: {}, seq: {}, src_chan: {}/{}, dst_chan: {}/{}, data: {}, timeout_height: {}-{}, timeout_timestamp: {}, ack: {} }}",
142+
self.height.unwrap_or(0), self.sequence, self.source_port, self.source_channel, self.destination_port, self.destination_channel,
143+
String::from_utf8(self.data.clone()).unwrap_or_else(|_| hex::encode(&self.data)), self.timeout_height.revision_number, self.timeout_height.revision_height, self.timeout_timestamp, self.ack.clone().map(|ack| String::from_utf8(ack.clone()).unwrap_or_else(|_| hex::encode(&ack))).unwrap_or_default())
144+
}
145+
}
146+
139147
impl TryFrom<RawPacketInfo> for PacketInfo {
140148
type Error = ();
141149

hyperspace/core/src/command.rs

Lines changed: 121 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,18 @@
1313
// limitations under the License.
1414

1515
use crate::{
16-
chain::{AnyConfig, Config, CoreConfig},
16+
chain::{AnyChain, AnyConfig, Config, CoreConfig},
1717
fish, relay, Mode,
1818
};
1919
use anyhow::{anyhow, Result};
2020
use clap::{Args, Parser};
21-
use ibc::core::{ics04_channel::channel::Order, ics24_host::identifier::PortId};
21+
use ibc::core::{
22+
ics04_channel::channel::{ChannelEnd, Order},
23+
ics24_host::identifier::PortId,
24+
};
2225
use metrics::{data::Metrics, handler::MetricsHandler, init_prometheus};
2326
use primitives::{
27+
error::Error,
2428
utils::{create_channel, create_clients, create_connection},
2529
Chain, IbcProvider,
2630
};
@@ -52,9 +56,9 @@ pub enum Subcommand {
5256
#[clap(name = "create-channel", about = "Creates a channel on the specified port")]
5357
CreateChannel(Cmd),
5458
#[clap(name = "query", about = "Query commands")]
55-
Client {
59+
Query {
5660
#[command(subcommand)]
57-
client: QueryCmd,
61+
query: QueryCmd,
5862
#[command(flatten)]
5963
cmd: Cmd,
6064
},
@@ -126,7 +130,7 @@ impl UploadWasmCmd {
126130
}
127131

128132
impl Cmd {
129-
async fn parse_config(&self) -> Result<Config> {
133+
pub async fn parse_config(&self) -> Result<Config> {
130134
use tokio::fs::read_to_string;
131135
let path_a: PathBuf = self.config_a.parse()?;
132136
let path_b: PathBuf = self.config_b.parse()?;
@@ -289,12 +293,124 @@ pub enum QueryCmd {
289293
Packets(QueryPacketsCmd),
290294
}
291295

296+
impl QueryCmd {
297+
pub async fn run(&self, config: Config) -> anyhow::Result<()> {
298+
let chain_a = config.chain_a.into_client().await?;
299+
let chain_b = config.chain_b.into_client().await?;
300+
301+
match self {
302+
QueryCmd::Packets(query) => query.run(chain_a, chain_b).await,
303+
}
304+
}
305+
}
306+
292307
#[derive(Debug, Clone, clap::Subcommand)]
293308
pub enum QueryPacketsCmd {
294309
/// Trace packets
295310
Trace(TracePacketsCmd),
296311
}
297312

313+
impl QueryPacketsCmd {
314+
pub(crate) async fn run(&self, chain_a: AnyChain, chain_b: AnyChain) -> anyhow::Result<()> {
315+
let name_a = chain_a.name();
316+
let name_b = chain_b.name();
317+
let (height_a, _) = chain_a.latest_height_and_timestamp().await?;
318+
let (_height_b, _) = chain_b.latest_height_and_timestamp().await?;
319+
320+
match self {
321+
QueryPacketsCmd::Trace(cmd) => {
322+
let sequence = cmd.sequence;
323+
let set = chain_a.channel_whitelist();
324+
if set.is_empty() {
325+
println!("No channels found on {name_a}");
326+
return Ok(())
327+
}
328+
for (channel_id, port_id) in set {
329+
let channel_response =
330+
chain_a.query_channel_end(height_a, channel_id, port_id.clone()).await?;
331+
let channel_end =
332+
ChannelEnd::try_from(channel_response.channel.ok_or_else(|| {
333+
Error::Custom("ChannelEnd not could not be decoded".to_string())
334+
})?)
335+
.map_err(|e| Error::Custom(e.to_string()))?;
336+
let counterparty_channel_id =
337+
channel_end.counterparty().channel_id.ok_or_else(|| {
338+
Error::Custom("Expected counterparty channel id".to_string())
339+
})?;
340+
let counterparty_port_id = channel_end.counterparty().port_id.clone();
341+
342+
let maybe_received = chain_b
343+
.query_received_packets(
344+
counterparty_channel_id.clone(),
345+
counterparty_port_id.clone(),
346+
vec![sequence],
347+
)
348+
.await?
349+
.pop();
350+
351+
if let Some(received) = maybe_received {
352+
println!("Packet {sequence} was received on {name_b}: {received}");
353+
let unreceived_acks = chain_a
354+
.query_unreceived_acknowledgements(
355+
height_a,
356+
channel_id.clone(),
357+
port_id.clone(),
358+
vec![sequence],
359+
)
360+
.await?;
361+
if unreceived_acks.is_empty() {
362+
println!("Packet {sequence} was acknowledged on {name_b}");
363+
} else {
364+
println!("Packet {sequence} was not acknowledged on {name_b}");
365+
}
366+
continue;
367+
}
368+
let sent_packets = chain_a
369+
.query_send_packets(channel_id.clone(), port_id.clone(), vec![sequence])
370+
.await?;
371+
if sent_packets.is_empty() {
372+
println!("Packet {sequence} not found");
373+
continue;
374+
}
375+
for packet_info in sent_packets {
376+
let seq = packet_info.sequence;
377+
println!("Sent packet {} ({name_a}->{name_b}): {}", seq, packet_info);
378+
let received = chain_b
379+
.query_received_packets(
380+
packet_info.destination_channel.parse()?,
381+
packet_info.destination_port.parse()?,
382+
vec![seq],
383+
)
384+
.await?
385+
.pop();
386+
if received.is_none() {
387+
println!("Packet {seq} ({name_a}->{name_b}) was not received");
388+
continue;
389+
}
390+
391+
println!("Received packet {seq} ({name_a}->{name_b}) {received:?}");
392+
393+
let ack = chain_a
394+
.query_unreceived_acknowledgements(
395+
height_a,
396+
channel_id.clone(),
397+
port_id.clone(),
398+
vec![seq],
399+
)
400+
.await?;
401+
if ack.is_empty() {
402+
println!("Packet {seq} ({name_a}->{name_b}) was acknowledged");
403+
} else {
404+
println!("Packet {seq} ({name_a}->{name_b}) was not acknowledged");
405+
}
406+
}
407+
}
408+
Ok(())
409+
},
410+
}
411+
}
412+
}
413+
298414
#[derive(Debug, Clone, Args)]
299415
pub struct TracePacketsCmd {
300416
pub sequence: u64,

hyperspace/cosmos/src/client.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,15 +253,15 @@ where
253253
pub async fn new(config: CosmosClientConfig) -> Result<Self, Error> {
254254
let (rpc_client, rpc_driver) = WebSocketClient::new(config.websocket_url.clone())
255255
.await
256-
.map_err(|e| Error::RpcError(format!("{:?}", e)))?;
256+
.map_err(|e| Error::RpcError(format!("failed to connect to WS: {:?}", e)))?;
257257
let rpc_http_client = HttpClient::new(config.rpc_url.clone())
258-
.map_err(|e| Error::RpcError(format!("{:?}", e)))?;
258+
.map_err(|e| Error::RpcError(format!("failed to connect to RPC: {:?}", e)))?;
259259
let ws_driver_jh = tokio::spawn(rpc_driver.run());
260260
let grpc_client = tonic::transport::Endpoint::new(config.grpc_url.to_string())
261-
.map_err(|e| Error::RpcError(format!("{:?}", e)))?
261+
.map_err(|e| Error::RpcError(format!("failed to connect to GRPC: {:?}", e)))?
262262
.connect()
263263
.await
264-
.map_err(|e| Error::RpcError(format!("{:?}", e)))?;
264+
.map_err(|e| Error::RpcError(format!("failed to connect to GRPC: {:?}", e)))?;
265265

266266
let chain_id = ChainId::from(config.chain_id);
267267
let light_client =

hyperspace/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,10 @@ async fn main() -> Result<()> {
4242
cmd.save_config(&new_config).await
4343
},
4444
Subcommand::Fish(cmd) => cmd.fish().await,
45+
Subcommand::Query { cmd, query } => {
46+
let config = cmd.parse_config().await?;
47+
query.run(config).await?;
48+
Ok(())
49+
},
4550
}
4651
}

0 commit comments

Comments
 (0)