Skip to content

Commit 8cb7267

Browse files
rphmeierpepyakin
authored andcommitted
shim: implement block query
1 parent bf50d7a commit 8cb7267

File tree

6 files changed

+137
-8
lines changed

6 files changed

+137
-8
lines changed

sugondat/shim/src/cli.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,82 @@ pub mod query {
151151
pub enum Commands {
152152
/// Submits the given blob into a namespace.
153153
Submit(submit::Params),
154+
/// Queries information about a block and header.
155+
Block(block::Params),
156+
}
157+
158+
pub mod block {
159+
//! CLI definition for the `query block` subcommand.
160+
161+
use clap::Args;
162+
163+
use super::SugondatRpcParams;
164+
165+
/// A reference to a block to query.
166+
#[derive(Debug, Clone)]
167+
pub enum BlockRef {
168+
/// The current best finalized block known by the node.
169+
Best,
170+
/// The number of the block to query.
171+
Number(u64),
172+
/// The hex-encoded hash of the block to query, prefixed with "0x".
173+
Hash([u8; 32]),
174+
}
175+
176+
impl std::fmt::Display for BlockRef {
177+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
178+
match *self {
179+
BlockRef::Best => write!(f, "best"),
180+
BlockRef::Number(n) => write!(f, "{}", n),
181+
BlockRef::Hash(h) => write!(f, "0x{}", hex::encode(&h[..])),
182+
}
183+
}
184+
}
185+
186+
impl std::str::FromStr for BlockRef {
187+
type Err = String;
188+
189+
fn from_str(input: &str) -> Result<Self, Self::Err> {
190+
if input == "best" {
191+
return Ok(BlockRef::Best);
192+
}
193+
194+
if let Some(s) = input.strip_prefix("0x") {
195+
let bytes = hex::decode(s)
196+
.map_err(|_| "Invalid parameter: not hex encoded".to_owned())?;
197+
198+
let mut hash = [0u8; 32];
199+
if bytes.len() != 32 {
200+
return Err("Invalid parameter: hash not 32 bytes".to_owned());
201+
}
202+
203+
hash.copy_from_slice(&bytes[..]);
204+
return Ok(BlockRef::Hash(hash));
205+
}
206+
207+
if let Ok(n) = input.parse::<u64>() {
208+
Ok(BlockRef::Number(n))
209+
} else {
210+
Err(format!("parse error. see `--help`"))
211+
}
212+
}
213+
}
214+
215+
#[derive(Debug, Args)]
216+
pub struct Params {
217+
#[clap(flatten)]
218+
pub rpc: SugondatRpcParams,
219+
220+
/// The block to query information about.
221+
///
222+
/// Possible values: ["best", number, hash]
223+
///
224+
/// "best" is the highest finalized block.
225+
///
226+
/// Hashes must be 32 bytes, hex-encoded, and prefixed with "0x".
227+
#[arg(default_value_t = BlockRef::Best, value_name = "BLOCK_REF")]
228+
pub block: BlockRef,
229+
}
154230
}
155231

156232
pub mod submit {

sugondat/shim/src/cmd/query/block.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use super::connect_rpc;
2+
use crate::cli::query::block::{BlockRef, Params};
3+
4+
pub async fn run(params: Params) -> anyhow::Result<()> {
5+
let Params { rpc, block } = params;
6+
7+
let client = connect_rpc(rpc).await?;
8+
9+
let maybe_hash = match block {
10+
BlockRef::Best => None,
11+
BlockRef::Hash(h) => Some(h),
12+
BlockRef::Number(n) => Some(
13+
client
14+
.block_hash(n)
15+
.await?
16+
.ok_or_else(|| anyhow::anyhow!("No block with number {}", n))?
17+
.0,
18+
),
19+
};
20+
21+
let block = client.get_block_at(maybe_hash).await?;
22+
23+
println!("Block: #{}", block.number);
24+
println!(" Hash: 0x{}", hex::encode(&block.hash[..]));
25+
println!(" Parent Hash: 0x{}", hex::encode(&block.parent_hash[..]));
26+
println!(" Blobs Root: 0x{}", hex::encode(&block.tree_root.root[..]));
27+
println!(" Min Namespace: {}", block.tree_root.min_ns);
28+
println!(" Max Namespace: {}", block.tree_root.max_ns);
29+
println!(" Timestamp: {}", block.timestamp);
30+
println!(
31+
" Blob Count: {} ({} bytes)",
32+
block.blobs.len(),
33+
block.blobs.iter().map(|b| b.data.len()).sum::<usize>(),
34+
);
35+
for (i, blob) in block.blobs.into_iter().enumerate() {
36+
println!(" Blob #{}", i + 1);
37+
println!(" Extrinsic Index: {}", blob.extrinsic_index);
38+
println!(" Namespace: {}", &blob.namespace);
39+
println!(" Size: {}", blob.data.len());
40+
}
41+
42+
Ok(())
43+
}

sugondat/shim/src/cmd/query/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ use crate::{
33
sugondat_rpc,
44
};
55

6+
mod block;
67
mod submit;
78

89
pub async fn run(params: Params) -> anyhow::Result<()> {
910
match params.command {
1011
Commands::Submit(params) => submit::run(params).await?,
12+
Commands::Block(params) => block::run(params).await?,
1113
}
1214
Ok(())
1315
}

sugondat/shim/src/dock/rollkit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl RollkitRPCServer for RollkitDock {
3434
);
3535
let namespace = parse_namespace(&namespace).map_err(|_| err::bad_namespace())?;
3636
let block_hash = self.client.wait_finalized_height(height).await;
37-
let block = self.client.get_block_at(block_hash).await.unwrap();
37+
let block = self.client.get_block_at(Some(block_hash)).await.unwrap();
3838
let mut blobs = vec![];
3939
for blob in block.blobs {
4040
if blob.namespace == namespace {

sugondat/shim/src/dock/sovereign.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl SovereignRPCServer for SovereignDock {
3434
) -> Result<Block, ErrorObjectOwned> {
3535
info!("get_block({})", height);
3636
let block_hash = self.client.wait_finalized_height(height).await;
37-
let block = self.client.get_block_at(block_hash).await.unwrap();
37+
let block = self.client.get_block_at(Some(block_hash)).await.unwrap();
3838
let proof = make_namespace_proof(&block, namespace);
3939
let blobs = block
4040
.blobs

sugondat/shim/src/sugondat_rpc/mod.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::sync::Arc;
22

33
use crate::key::Keypair;
44
use anyhow::Context;
5-
use subxt::{rpc_params, utils::H256};
5+
use subxt::{config::Header as _, rpc_params, utils::H256};
66
use sugondat_nmt::Namespace;
77
use sugondat_subxt::{
88
sugondat::runtime_types::pallet_sugondat_blobs::namespace_param::UnvalidatedNamespace, Header,
@@ -103,15 +103,19 @@ impl Client {
103103
}
104104

105105
/// Returns the header and the body of the block with the given hash, automatically retrying
106-
/// until it succeeds.
106+
/// until it succeeds. `None` indicates the best block.
107107
async fn get_header_and_extrinsics(
108108
&self,
109-
block_hash: [u8; 32],
109+
block_hash: Option<[u8; 32]>,
110110
) -> anyhow::Result<(Header, Vec<sugondat_subxt::ExtrinsicDetails>)> {
111-
let block_hash = H256::from(block_hash);
111+
let block_hash = block_hash.map(H256::from);
112112
loop {
113113
let conn = self.connector.ensure_connected().await;
114-
let err = match conn.subxt.blocks().at(block_hash).await {
114+
let res = match block_hash {
115+
Some(h) => conn.subxt.blocks().at(h).await,
116+
None => conn.subxt.blocks().at_latest().await,
117+
};
118+
let err = match res {
115119
Ok(it) => {
116120
let header = it.header();
117121
let body = match it.extrinsics().await {
@@ -135,15 +139,18 @@ impl Client {
135139

136140
/// Returns the data of the block identified by the given block hash. If the block is not found
137141
/// returns an error.
142+
///
143+
/// `None` indicates that the best block should be used.
138144
#[tracing::instrument(level = Level::DEBUG, skip(self))]
139-
pub async fn get_block_at(&self, block_hash: [u8; 32]) -> anyhow::Result<Block> {
145+
pub async fn get_block_at(&self, block_hash: Option<[u8; 32]>) -> anyhow::Result<Block> {
140146
let (header, extrinsics) = self.get_header_and_extrinsics(block_hash).await?;
141147
let tree_root = tree_root(&header).ok_or_else(err::no_tree_root)?;
142148
let timestamp = extract_timestamp(&extrinsics)?;
143149
let blobs = extract_blobs(extrinsics);
144150
tracing::debug!(?blobs, "found {} blobs in block", blobs.len());
145151
Ok(Block {
146152
number: header.number as u64,
153+
hash: header.hash().0,
147154
parent_hash: header.parent_hash.0,
148155
tree_root,
149156
timestamp,
@@ -328,6 +335,7 @@ mod err {
328335
/// Represents a sugondat block.
329336
pub struct Block {
330337
pub number: u64,
338+
pub hash: [u8; 32],
331339
pub parent_hash: [u8; 32],
332340
pub tree_root: sugondat_nmt::TreeRoot,
333341
pub timestamp: u64,

0 commit comments

Comments
 (0)