diff --git a/sz-poc-offsite-2025/evm/lightnode/Cargo.toml b/sz-poc-offsite-2025/evm/lightnode/Cargo.toml index 57dd20a..8c31a76 100644 --- a/sz-poc-offsite-2025/evm/lightnode/Cargo.toml +++ b/sz-poc-offsite-2025/evm/lightnode/Cargo.toml @@ -15,3 +15,4 @@ crypto-bigint = { version = "0.5.5", features = ["serde"] } risc0-zkvm = { version = "2" } indexmap = { version = "1.9.3" } url = { version = "2" } +hex = { version = "0.4" } diff --git a/sz-poc-offsite-2025/evm/lightnode/src/lib.rs b/sz-poc-offsite-2025/evm/lightnode/src/lib.rs index b1635bc..8c33d70 100644 --- a/sz-poc-offsite-2025/evm/lightnode/src/lib.rs +++ b/sz-poc-offsite-2025/evm/lightnode/src/lib.rs @@ -1,13 +1,13 @@ use std::ops::Range; use executor_http_client::{BasicAuthCredentials, ExecutorHttpClient}; -use nomos::CryptarchiaInfo; +use nomos::{CryptarchiaInfo, HeaderId}; use reqwest::{RequestBuilder, Url}; use serde::{Deserialize, Serialize}; use tracing::{error, info}; -pub const CRYPTARCHIA_INFO: &str = "/cryptarchia/info"; -pub const STORAGE_BLOCK: &str = "/storage/block"; +pub const CRYPTARCHIA_INFO: &str = "cryptarchia/info"; +pub const STORAGE_BLOCK: &str = "storage/block"; mod nomos; @@ -32,22 +32,70 @@ impl NomosClient { } } - pub async fn get_cryptarchia_info(&self) -> Result { + pub async fn get_cryptarchia_info(&self) -> Result { let url = self.base_url.join(CRYPTARCHIA_INFO).expect("Invalid URL"); + info!("Requesting cryptarchia info from {}", url); + let request = self.reqwest_client.get(url).basic_auth( - self.basic_auth.username.clone(), - self.basic_auth.password.clone(), + &self.basic_auth.username, + self.basic_auth.password.as_deref(), ); info!("Sending request with creds {:?}", self.basic_auth); - let response = request.send().await?; + let response = request.send().await.map_err(|e| { + error!("Failed to send request: {}", e); + "Failed to send request".to_string() + })?; + if !response.status().is_success() { error!("Failed to get cryptarchia info: {}", response.status()); + return Err("Failed to get cryptarchia info".to_string()); } - let info = response.json::().await?; + let info = response.json::().await.map_err(|e| { + error!("Failed to parse response: {}", e); + "Failed to parse response".to_string() + })?; Ok(info) } + + pub async fn get_block(&self, id: HeaderId) -> Result { + let url = self.base_url.join(STORAGE_BLOCK).expect("Invalid URL"); + + info!("Requesting block with HeaderId {}", id); + + let request = self + .reqwest_client + .post(url) + .header("Content-Type", "application/json") + .basic_auth( + &self.basic_auth.username, + self.basic_auth.password.as_deref(), + ) + .body(serde_json::to_string(&id).unwrap()); + + let response = request.send().await.map_err(|e| { + error!("Failed to send request: {}", e); + "Failed to send request".to_string() + })?; + + if !response.status().is_success() { + error!("Failed to get block: {}", response.status()); + return Err("Failed to get block".to_string()); + } + + let json: serde_json::Value = response.json().await.map_err(|e| { + error!("Failed to parse JSON: {}", e); + "Failed to parse JSON".to_string() + })?; + + info!( + "Block (raw): {}", + serde_json::to_string_pretty(&json).unwrap() + ); + + Ok(json) + } } diff --git a/sz-poc-offsite-2025/evm/lightnode/src/main.rs b/sz-poc-offsite-2025/evm/lightnode/src/main.rs index 1a44268..19b674f 100644 --- a/sz-poc-offsite-2025/evm/lightnode/src/main.rs +++ b/sz-poc-offsite-2025/evm/lightnode/src/main.rs @@ -37,5 +37,8 @@ async fn main() -> Result<(), Box> { let info = consensus.get_cryptarchia_info().await?; println!("Cryptarchia Info: {:?}", info); + let block = consensus.get_block(info.tip).await?; + println!("Block: {:?}", block); + Ok(()) } diff --git a/sz-poc-offsite-2025/evm/lightnode/src/nomos.rs b/sz-poc-offsite-2025/evm/lightnode/src/nomos.rs new file mode 100644 index 0000000..781d1b4 --- /dev/null +++ b/sz-poc-offsite-2025/evm/lightnode/src/nomos.rs @@ -0,0 +1,52 @@ +use serde::{Deserialize, Deserializer, Serialize}; + +use hex::FromHex; + +// tip "4f573735fb987453f7467688ea4e034b9161e3ca200526faf5c8ce6db09da180" +// slot 5085 +// height 1245 + +#[derive(Serialize, Deserialize, Debug)] +pub struct CryptarchiaInfo { + pub tip: HeaderId, + pub slot: u64, + pub height: u64, +} + +#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash, PartialOrd, Ord)] +pub struct HeaderId([u8; 32]); + +impl<'de> Deserialize<'de> for HeaderId { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let hex_str = String::deserialize(deserializer)?; + + let bytes = <[u8; 32]>::from_hex(hex_str) + .map_err(|e| serde::de::Error::custom(format!("Invalid hex string: {}", e)))?; + + Ok(HeaderId(bytes)) + } +} + +impl Serialize for HeaderId { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let hex_str = hex::encode(self.0); + serializer.serialize_str(&hex_str) + } +} + +use std::fmt; + +impl fmt::Display for HeaderId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for byte in &self.0 { + write!(f, "{:02x}", byte)?; + } + Ok(()) + } +}