1use crate::{chain::quantus_subxt, error::QuantusError, log_error, log_print, log_verbose};
3use clap::Subcommand;
4use colored::Colorize;
5use std::str::FromStr;
6use subxt::utils::H256;
7
8#[derive(Subcommand, Debug)]
10pub enum PreimageCommands {
11 #[command(name = "status")]
13 Status {
14 #[arg(long)]
16 hash: String,
17 },
18 #[command(name = "get")]
20 Get {
21 #[arg(long)]
23 hash: String,
24 #[arg(long)]
26 len: u32,
27 },
28 #[command(name = "list")]
30 List,
31 #[command(name = "request")]
33 Request {
34 #[arg(long)]
36 hash: String,
37 #[arg(long)]
39 from: String,
40 },
41 #[command(name = "note")]
43 Note {
44 #[arg(long)]
46 content: String,
47 #[arg(long)]
49 from: String,
50 },
51 #[command(name = "create")]
53 Create {
54 #[arg(long)]
56 wasm_file: std::path::PathBuf,
57 #[arg(long)]
59 from: String,
60 #[arg(long)]
62 password: Option<String>,
63 #[arg(long)]
65 password_file: Option<String>,
66 },
67}
68
69pub async fn handle_preimage_command(
71 command: PreimageCommands,
72 node_url: &str,
73 execution_mode: crate::cli::common::ExecutionMode,
74) -> crate::error::Result<()> {
75 let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?;
76
77 match command {
78 PreimageCommands::Status { hash } => {
79 check_preimage_status(&quantus_client, &hash).await?;
80 },
81 PreimageCommands::Get { hash, len } => {
82 get_preimage_content(&quantus_client, &hash, len).await?;
83 },
84 PreimageCommands::List => {
85 list_preimages(&quantus_client).await?;
86 },
87 PreimageCommands::Request { hash, from } => {
88 request_preimage(&quantus_client, &hash, &from, execution_mode).await?;
89 },
90 PreimageCommands::Note { content, from } => {
91 note_preimage(&quantus_client, &content, &from, execution_mode).await?;
92 },
93 PreimageCommands::Create { wasm_file, from, password, password_file } => {
94 create_preimage(
95 &quantus_client,
96 wasm_file,
97 &from,
98 password,
99 password_file,
100 execution_mode,
101 )
102 .await?;
103 },
104 }
105
106 Ok(())
107}
108
109async fn check_preimage_status(
111 quantus_client: &crate::chain::client::QuantusClient,
112 hash_str: &str,
113) -> crate::error::Result<()> {
114 let preimage_hash = parse_hash(hash_str)?;
115
116 log_print!("🔍 Checking preimage status for hash: {}", hash_str.bright_cyan());
117
118 let latest_block_hash = quantus_client.get_latest_block().await?;
119 let storage_at = quantus_client.client().storage().at(latest_block_hash);
120
121 let status_addr = quantus_subxt::api::storage().preimage().status_for(preimage_hash);
123 let status_result = storage_at.fetch(&status_addr).await;
124
125 let request_status_addr =
127 quantus_subxt::api::storage().preimage().request_status_for(preimage_hash);
128 let request_status_result = storage_at.fetch(&request_status_addr).await;
129
130 log_print!("📊 Preimage Status Results:");
131 log_print!(" 🔗 Hash: {}", hash_str.bright_yellow());
132
133 match status_result {
134 Ok(Some(status)) => {
135 log_print!(" 📋 StatusFor (Old): {:?}", status);
136 },
137 Ok(None) => {
138 log_print!(" 📋 StatusFor (Old): Not found");
139 },
140 Err(e) => {
141 log_print!(" 📋 StatusFor (Old): Error - {:?}", e);
142 },
143 }
144
145 match request_status_result {
146 Ok(Some(request_status)) => {
147 log_print!(" 📋 RequestStatusFor (New): {:?}", request_status);
148 },
149 Ok(None) => {
150 log_print!(" 📋 RequestStatusFor (New): Not found");
151 },
152 Err(e) => {
153 log_print!(" 📋 RequestStatusFor (New): Error - {:?}", e);
154 },
155 }
156
157 let preimage_addr =
160 quantus_subxt::api::storage().preimage().preimage_for((preimage_hash, 0u32));
161 let preimage_result = storage_at.fetch(&preimage_addr).await;
162
163 match preimage_result {
164 Ok(Some(_)) => {
165 log_print!(" 📦 PreimageFor: Content exists (length 0)");
166 },
167 Ok(None) => {
168 log_print!(" 📦 PreimageFor: No content found (length 0)");
169 },
170 Err(e) => {
171 log_print!(" 📦 PreimageFor: Error - {:?}", e);
172 },
173 }
174
175 Ok(())
176}
177
178async fn get_preimage_content(
180 quantus_client: &crate::chain::client::QuantusClient,
181 hash_str: &str,
182 len: u32,
183) -> crate::error::Result<()> {
184 let preimage_hash = parse_hash(hash_str)?;
185
186 log_print!("📦 Getting preimage content for hash: {}", hash_str.bright_cyan());
187 log_print!(" 📏 Length: {} bytes", len);
188
189 let latest_block_hash = quantus_client.get_latest_block().await?;
190 let storage_at = quantus_client.client().storage().at(latest_block_hash);
191
192 let preimage_addr = quantus_subxt::api::storage().preimage().preimage_for((preimage_hash, len));
193 let preimage_result = storage_at.fetch(&preimage_addr).await;
194
195 match preimage_result {
196 Ok(Some(bounded_vec)) => {
197 log_print!("✅ Preimage content found!");
198 log_print!(" 📏 Actual length: {} bytes", bounded_vec.0.len());
199
200 let content: Vec<u8> = bounded_vec.0;
202
203 let preview_len = std::cmp::min(100, content.len());
205 let preview = &content[..preview_len];
206 log_print!(" 🔍 Preview (first {} bytes):", preview_len);
207 log_print!(" {}", hex::encode(preview).bright_green());
208
209 if content.len() > preview_len {
210 log_print!(" ... ({} more bytes)", content.len() - preview_len);
211 }
212
213 log_verbose!(" 🔧 Attempting to decode as call data...");
215 log_print!(" 📝 Raw content preview (first 100 bytes):");
216 log_print!(
217 " {}",
218 hex::encode(&content[..std::cmp::min(100, content.len())]).bright_green()
219 );
220 },
221 Ok(None) => {
222 log_error!("❌ Preimage content not found for hash {} with length {}", hash_str, len);
223 },
224 Err(e) => {
225 log_error!("❌ Error fetching preimage content: {:?}", e);
226 },
227 }
228
229 Ok(())
230}
231
232async fn list_preimages(
234 quantus_client: &crate::chain::client::QuantusClient,
235) -> crate::error::Result<()> {
236 log_print!("📋 Listing all preimages...");
237
238 let latest_block_hash = quantus_client.get_latest_block().await?;
239 let storage_at = quantus_client.client().storage().at(latest_block_hash);
240
241 let mut preimage_count = 0;
242 let mut unrequested_count = 0;
243 let mut requested_count = 0;
244
245 let preimage_for_addr = quantus_subxt::api::storage().preimage().preimage_for_iter();
247 let mut image_stream = storage_at.iter(preimage_for_addr).await.map_err(|e| {
248 QuantusError::Generic(format!("Failed to iterate preimage contents: {:?}", e))
249 })?;
250
251 while let Some(result) = image_stream.next().await {
252 match result {
253 Ok(entry) => {
254 let key = entry.key_bytes;
255 if key.len() >= 36 {
256 let len_le = &key[key.len() - 4..];
257 let len = u32::from_le_bytes([len_le[0], len_le[1], len_le[2], len_le[3]]);
258 let hash = sp_core::H256::from_slice(&key[key.len() - 36..key.len() - 4]);
259
260 let status = storage_at
261 .fetch(&quantus_subxt::api::storage().preimage().request_status_for(hash))
262 .await
263 .ok()
264 .flatten();
265
266 preimage_count += 1;
267 match status {
268 Some(quantus_subxt::api::runtime_types::pallet_preimage::RequestStatus::Unrequested { ticket: _, len: status_len }) => {
269 unrequested_count += 1;
270 log_print!(" 🔗 {} (Unrequested, {} bytes)", hash, status_len);
271 },
272 Some(quantus_subxt::api::runtime_types::pallet_preimage::RequestStatus::Requested { maybe_ticket: _, count, maybe_len }) => {
273 requested_count += 1;
274 let len_str = match maybe_len { Some(l) => format!("{} bytes", l), None => format!("{} bytes (from key)", len) };
275 log_print!(" 🔗 {} (Requested, count: {}, {})", hash, count, len_str);
276 },
277 None => {
278 log_print!(" 🔗 {} (Unknown status, {} bytes)", hash, len);
279 },
280 }
281 }
282 },
283 Err(e) => log_verbose!("⚠️ Error reading preimage content entry: {:?}", e),
284 }
285 }
286
287 log_print!("");
288 log_print!("📊 Preimage Summary:");
289 log_print!(" 📋 Total preimages: {}", preimage_count);
290 log_print!(" 📝 Unrequested: {}", unrequested_count);
291 log_print!(" 📋 Requested: {}", requested_count);
292
293 if preimage_count == 0 {
294 log_print!(" 💡 No preimages found on chain");
295 }
296
297 Ok(())
298}
299
300async fn request_preimage(
302 quantus_client: &crate::chain::client::QuantusClient,
303 hash_str: &str,
304 from_str: &str,
305 execution_mode: crate::cli::common::ExecutionMode,
306) -> crate::error::Result<()> {
307 let preimage_hash = parse_hash(hash_str)?;
308
309 log_print!("🚀 Requesting preimage for hash: {}", hash_str.bright_cyan());
310 log_print!(" 👤 From: {}", from_str.bright_yellow());
311
312 let keypair = crate::wallet::load_keypair_from_wallet(from_str, None, None)?;
314
315 let request_call = quantus_subxt::api::tx().preimage().request_preimage(preimage_hash);
317
318 let tx_hash = crate::cli::common::submit_transaction(
320 quantus_client,
321 &keypair,
322 request_call,
323 None,
324 execution_mode,
325 )
326 .await?;
327 log_print!("✅ Preimage request transaction submitted: {:?}", tx_hash);
328
329 log_print!("⏳ Waiting for preimage request confirmation...");
331 log_print!("✅ Preimage request confirmed!");
332
333 Ok(())
334}
335
336async fn note_preimage(
338 quantus_client: &crate::chain::client::QuantusClient,
339 content_str: &str,
340 from_str: &str,
341 execution_mode: crate::cli::common::ExecutionMode,
342) -> crate::error::Result<()> {
343 let content = hex::decode(content_str.trim_start_matches("0x"))
344 .map_err(|e| QuantusError::Generic(format!("Invalid hex content: {}", e)))?;
345
346 log_print!("📝 Noting preimage for content length: {} bytes", content.len());
347 log_print!(" 👤 From: {}", from_str.bright_yellow());
348
349 let keypair = crate::wallet::load_keypair_from_wallet(from_str, None, None)?;
351
352 let note_call = quantus_subxt::api::tx().preimage().note_preimage(content);
354
355 let tx_hash = crate::cli::common::submit_transaction(
357 quantus_client,
358 &keypair,
359 note_call,
360 None,
361 execution_mode,
362 )
363 .await?;
364 log_print!("✅ Preimage note transaction submitted: {:?}", tx_hash);
365
366 log_print!("⏳ Waiting for preimage note confirmation...");
368 log_print!("✅ Preimage note confirmed!");
369
370 Ok(())
371}
372
373async fn create_preimage(
375 quantus_client: &crate::chain::client::QuantusClient,
376 wasm_file: std::path::PathBuf,
377 from_str: &str,
378 password: Option<String>,
379 password_file: Option<String>,
380 execution_mode: crate::cli::common::ExecutionMode,
381) -> crate::error::Result<()> {
382 use qp_poseidon::PoseidonHasher;
383
384 log_print!("📦 Creating preimage from WASM file: {}", wasm_file.display());
385 log_print!(" 👤 From: {}", from_str.bright_yellow());
386
387 if !wasm_file.exists() {
388 return Err(QuantusError::Generic(format!("WASM file not found: {}", wasm_file.display())));
389 }
390
391 let wasm_code = std::fs::read(&wasm_file)
393 .map_err(|e| QuantusError::Generic(format!("Failed to read WASM file: {}", e)))?;
394
395 log_print!("📊 WASM file size: {} bytes", wasm_code.len());
396
397 let keypair = crate::wallet::load_keypair_from_wallet(from_str, password, password_file)?;
399
400 let set_code_payload = quantus_subxt::api::tx().system().set_code(wasm_code.clone());
402 let metadata = quantus_client.client().metadata();
403 let encoded_call = <_ as subxt::tx::Payload>::encode_call_data(&set_code_payload, &metadata)
404 .map_err(|e| QuantusError::Generic(format!("Failed to encode call data: {:?}", e)))?;
405
406 log_verbose!("📝 Encoded call size: {} bytes", encoded_call.len());
407
408 let preimage_hash: sp_core::H256 =
410 <PoseidonHasher as sp_runtime::traits::Hash>::hash(&encoded_call);
411
412 log_print!("🔗 Preimage hash: {:?}", preimage_hash);
413
414 type PreimageBytes = quantus_subxt::api::preimage::calls::types::note_preimage::Bytes;
416 let bounded_bytes: PreimageBytes = encoded_call.clone();
417
418 log_print!("📝 Submitting preimage...");
419 let note_preimage_tx = quantus_subxt::api::tx().preimage().note_preimage(bounded_bytes);
420 let preimage_tx_hash = crate::cli::common::submit_transaction(
421 quantus_client,
422 &keypair,
423 note_preimage_tx,
424 None,
425 execution_mode,
426 )
427 .await?;
428 log_print!("✅ Preimage transaction submitted: {:?}", preimage_tx_hash);
429
430 log_print!("⏳ Waiting for preimage transaction confirmation...");
432 log_print!("✅ Preimage transaction confirmed!");
433
434 log_print!("🎯 Preimage created successfully!");
435 log_print!(" 🔗 Hash: {:?}", preimage_hash);
436 log_print!(" 📏 Size: {} bytes", encoded_call.len());
437
438 Ok(())
439}
440
441fn parse_hash(hash_str: &str) -> crate::error::Result<H256> {
443 let hash_str = hash_str.trim_start_matches("0x");
444 H256::from_str(hash_str).map_err(|e| {
445 QuantusError::Generic(format!("Invalid hash format: {}. Expected 64 hex characters", e))
446 })
447}