block.rs
1 // Copyright (C) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the ADL library. 3 4 // The ADL library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 9 // The ADL library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 14 // You should have received a copy of the GNU General Public License 15 // along with the ADL library. If not, see <https://www.gnu.org/licenses/>. 16 17 use super::*; 18 19 use crate::cli::context::Context; 20 use clap::Parser; 21 22 // Query on-chain information related to blocks. 23 #[derive(Parser, Debug)] 24 pub struct AdlBlock { 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 47 impl Command for AdlBlock { 48 type Input = (); 49 type Output = String; 50 51 fn log_span(&self) -> Span { 52 tracing::span!(tracing::Level::INFO, "Adl") 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 // Build custom url to fetch from based on the flags and user's input. 61 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 // Make sure the range is composed of valid numbers. 69 is_valid_numerical_input(&range[0])?; 70 is_valid_numerical_input(&range[1])?; 71 72 // Parse the range values. 73 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 // Make sure the range is not too large. 76 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 }