leo_lang/cli/commands/query/
block.rs1use super::*;
18
19use crate::cli::context::Context;
20use clap::Parser;
21
22#[derive(Parser, Debug)]
24pub struct LeoBlock {
25 #[clap(help = "Fetch a block by specifying its height or hash", required_unless_present_any = &["latest", "latest_hash", "latest_height", "range"])]
26 pub(crate) id: Option<String>,
27 #[arg(short, long, help = "Get the latest block", default_value = "false", conflicts_with_all(["latest_hash", "latest_height", "range", "transactions", "to_height"]))]
28 pub(crate) latest: bool,
29 #[arg(long, help = "Get the latest block hash", default_value = "false", conflicts_with_all(["latest", "latest_height", "range", "transactions", "to_height"]))]
30 pub(crate) latest_hash: bool,
31 #[arg(long, help = "Get the latest block height", default_value = "false", conflicts_with_all(["latest", "latest_hash", "range", "transactions", "to_height"]))]
32 pub(crate) latest_height: bool,
33 #[arg(short, long, help = "Get up to 50 consecutive blocks", number_of_values = 2, value_names = &["START_HEIGHT", "END_HEIGHT"], conflicts_with_all(["latest", "latest_hash", "latest_height", "transactions", "to_height"]))]
34 pub(crate) range: Option<Vec<String>>,
35 #[arg(
36 short,
37 long,
38 help = "Get all transactions at the specified block height",
39 conflicts_with("to_height"),
40 default_value = "false"
41 )]
42 pub(crate) transactions: bool,
43 #[arg(long, help = "Lookup the block height corresponding to a hash value", default_value = "false")]
44 pub(crate) to_height: bool,
45}
46
47impl Command for LeoBlock {
48 type Input = ();
49 type Output = String;
50
51 fn log_span(&self) -> Span {
52 tracing::span!(tracing::Level::INFO, "Leo")
53 }
54
55 fn prelude(&self, _context: Context) -> Result<Self::Input> {
56 Ok(())
57 }
58
59 fn apply(self, _context: Context, _input: Self::Input) -> Result<Self::Output> {
60 let url = if self.latest_height {
62 "block/height/latest".to_string()
63 } else if self.latest_hash {
64 "block/hash/latest".to_string()
65 } else if self.latest {
66 "block/latest".to_string()
67 } else if let Some(range) = self.range {
68 is_valid_numerical_input(&range[0])?;
70 is_valid_numerical_input(&range[1])?;
71
72 let end = &range[1].parse::<u32>().map_err(|_| UtilError::invalid_bound(&range[1]))?;
74 let start = &range[0].parse::<u32>().map_err(|_| UtilError::invalid_bound(&range[0]))?;
75 if end - start > 50 {
77 return Err(UtilError::invalid_range().into());
78 }
79 format!("blocks?start={}&end={}", range[0], range[1])
80 } else if self.transactions {
81 is_valid_numerical_input(&self.id.clone().unwrap())?;
82 format!("block/{}/transactions", self.id.unwrap()).to_string()
83 } else if self.to_height {
84 let id = self.id.unwrap();
85 is_valid_hash(&id)?;
86 format!("height/{}", id).to_string()
87 } else if let Some(id) = self.id {
88 is_valid_height_or_hash(&id)?;
89 format!("block/{}", id)
90 } else {
91 unreachable!("All cases are covered")
92 };
93
94 Ok(url)
95 }
96}