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