From abf790cc28a6cb1a0761ca62f51e3be10c5d549c Mon Sep 17 00:00:00 2001 From: Pia Date: Sun, 15 Sep 2024 17:41:39 +0900 Subject: [PATCH 1/5] chore: some cleanups --- cli/src/interactive.rs | 2 +- hdp/src/cairo_runner/dry_run.rs | 4 +- hdp/src/preprocessor/compile/datalake.rs | 4 +- hdp/src/preprocessor/compile/module.rs | 2 +- hdp/src/preprocessor/module_registry.rs | 9 +- hdp/src/primitives/block/account.rs | 2 +- hdp/src/primitives/chain_id.rs | 6 + .../processed_types/cairo_format/account.rs | 3 +- .../cairo_format/datalake_compute.rs | 5 +- .../cairo_format/felt_vec_unit.rs | 27 ++- .../processed_types/cairo_format/header.rs | 2 +- .../processed_types/cairo_format/module.rs | 2 +- .../processed_types/cairo_format/mpt.rs | 2 +- .../processed_types/cairo_format/receipt.rs | 2 +- .../processed_types/cairo_format/storage.rs | 5 +- .../cairo_format/transaction.rs | 2 +- hdp/src/primitives/processed_types/uint256.rs | 166 +++++++++++++++--- .../datalake_compute/datalake/envelope.rs | 16 +- .../datalake/transactions_in_block.rs | 7 +- .../task/datalake/block_sampled/datalake.rs | 5 +- .../task/datalake/transactions/datalake.rs | 37 ++-- .../task/datalake/transactions/mod.rs | 16 +- 22 files changed, 236 insertions(+), 90 deletions(-) diff --git a/cli/src/interactive.rs b/cli/src/interactive.rs index 2be26667..aed27e98 100644 --- a/cli/src/interactive.rs +++ b/cli/src/interactive.rs @@ -230,7 +230,7 @@ pub async fn run_interactive() -> anyhow::Result<()> { start_index, end_index, increment, - IncludedTypes::from(&included_types), + IncludedTypes::from_bytes(&included_types), ); DatalakeEnvelope::TransactionsInBlock(transactions_datalake) } diff --git a/hdp/src/cairo_runner/dry_run.rs b/hdp/src/cairo_runner/dry_run.rs index 5683f9a1..646bb4e8 100644 --- a/hdp/src/cairo_runner/dry_run.rs +++ b/hdp/src/cairo_runner/dry_run.rs @@ -170,7 +170,7 @@ mod tests { let result = dry_runner.run(input).unwrap(); assert_eq!(result.len(), 1); assert_eq!(result[0].fetch_keys.len(), 3); - assert_eq!(result[0].result, Uint256::from_strs("0x0", "0x0").unwrap()); + assert_eq!(result[0].result, Uint256::ZERO); assert_eq!( result[0].program_hash, felt!("0x04df21eb479ae4416fbdc00abab6fab43bff0b8083be4d1fd8602c8fbfbd2274") @@ -233,7 +233,7 @@ mod tests { println!("Fetch key {}: {:?}", i, key); } - assert_eq!(module.result, Uint256::from_strs("0x0", "0x0").unwrap()); + assert_eq!(module.result, Uint256::ZERO); assert_eq!( module.program_hash, felt!("0xc8580f74b6e6e04d8073602ad0c0d55538b56bf8307fefebb6b65b1bbf2a27") diff --git a/hdp/src/preprocessor/compile/datalake.rs b/hdp/src/preprocessor/compile/datalake.rs index 8369ffae..7cef1a11 100644 --- a/hdp/src/preprocessor/compile/datalake.rs +++ b/hdp/src/preprocessor/compile/datalake.rs @@ -173,7 +173,7 @@ mod tests { start_index: 0, end_index: 10, increment: 1, - included_types: IncludedTypes::from(&[1, 1, 1, 1]), + included_types: IncludedTypes::from_bytes(&[1, 1, 1, 1]), sampled_property: TransactionsCollection::Transactions( TransactionField::GasLimit, ), @@ -187,7 +187,7 @@ mod tests { start_index: 0, end_index: 11, increment: 1, - included_types: IncludedTypes::from(&[1, 1, 1, 1]), + included_types: IncludedTypes::from_bytes(&[1, 1, 1, 1]), sampled_property: TransactionsCollection::TranasactionReceipts( TransactionReceiptField::Success, ), diff --git a/hdp/src/preprocessor/compile/module.rs b/hdp/src/preprocessor/compile/module.rs index bf44a7aa..9742823c 100644 --- a/hdp/src/preprocessor/compile/module.rs +++ b/hdp/src/preprocessor/compile/module.rs @@ -54,7 +54,7 @@ impl Compilable for ModuleVec { // Extract the dry run module result let dry_run_module = dry_run_results.into_iter().next().unwrap(); - let commit_results = vec![dry_run_module.result.to_combined_string().into()]; + let commit_results = vec![dry_run_module.result.into()]; // 3. Categorize fetch keys by chain ID let categorized_keys = categorize_fetch_keys(dry_run_module.fetch_keys); diff --git a/hdp/src/preprocessor/module_registry.rs b/hdp/src/preprocessor/module_registry.rs index bc4cdb36..038fe9be 100644 --- a/hdp/src/preprocessor/module_registry.rs +++ b/hdp/src/preprocessor/module_registry.rs @@ -64,8 +64,10 @@ impl ModuleRegistry { local_class_path: Option, module_inputs: Vec, ) -> Result { - let program_hash = - program_hash.map(|program_hash| FieldElement::from_hex_be(&program_hash).unwrap()); + let program_hash = program_hash.map(|program_hash| { + FieldElement::from_hex_be(&program_hash) + .expect("program hash cannot be converted to FieldElement") + }); let module_inputs: Result, _> = module_inputs .into_iter() .map(|input| ModuleInput::from_str(&input)) @@ -103,7 +105,8 @@ impl ModuleRegistry { }; let program_hash = casm.compiled_class_hash(); - let converted_hash = FieldElement::from_bytes_be(&program_hash.to_bytes_be()).unwrap(); + let converted_hash = FieldElement::from_bytes_be(&program_hash.to_bytes_be()) + .expect("program hash cannot be converted to FieldElement"); info!("program Hash: {:#?}", converted_hash); let module = Module { diff --git a/hdp/src/primitives/block/account.rs b/hdp/src/primitives/block/account.rs index 447bb93e..c8386d53 100644 --- a/hdp/src/primitives/block/account.rs +++ b/hdp/src/primitives/block/account.rs @@ -30,7 +30,7 @@ impl Account { } pub fn rlp_decode(mut rlp: &[u8]) -> Self { - ::decode(&mut rlp).unwrap() + ::decode(&mut rlp).expect("rlp decode failed.") } } diff --git a/hdp/src/primitives/chain_id.rs b/hdp/src/primitives/chain_id.rs index 7f35dfaf..71c93904 100644 --- a/hdp/src/primitives/chain_id.rs +++ b/hdp/src/primitives/chain_id.rs @@ -13,6 +13,12 @@ pub enum ChainId { StarknetSepolia, } +impl Default for ChainId { + fn default() -> Self { + Self::EthereumSepolia + } +} + #[derive(Error, Debug, PartialEq)] #[error("Failed to parse ChainId: {input}")] pub struct ParseChainIdError { diff --git a/hdp/src/primitives/processed_types/cairo_format/account.rs b/hdp/src/primitives/processed_types/cairo_format/account.rs index a568790d..125119e9 100644 --- a/hdp/src/primitives/processed_types/cairo_format/account.rs +++ b/hdp/src/primitives/processed_types/cairo_format/account.rs @@ -14,8 +14,7 @@ impl AsCairoFormat for BaseProcessedAccount { type Output = ProcessedAccount; fn as_cairo_format(&self) -> Self::Output { - let address_chunk_result = - FieldElementVectorUnit::from_bytes(self.address.as_ref()).unwrap(); + let address_chunk_result = FieldElementVectorUnit::from_bytes(self.address.as_ref()); let account_key = &self.account_key; let proofs = self .proofs diff --git a/hdp/src/primitives/processed_types/cairo_format/datalake_compute.rs b/hdp/src/primitives/processed_types/cairo_format/datalake_compute.rs index 1042dc75..b711be25 100644 --- a/hdp/src/primitives/processed_types/cairo_format/datalake_compute.rs +++ b/hdp/src/primitives/processed_types/cairo_format/datalake_compute.rs @@ -10,9 +10,8 @@ impl AsCairoFormat for BaseProcessedDatalakeCompute { type Output = ProcessedDatalakeCompute; fn as_cairo_format(&self) -> Self::Output { - let computational_task_felts = - FieldElementVectorUnit::from_bytes(&self.encoded_task).unwrap(); - let datalake_felts = FieldElementVectorUnit::from_bytes(&self.encoded_datalake).unwrap(); + let computational_task_felts = FieldElementVectorUnit::from_bytes(&self.encoded_task); + let datalake_felts = FieldElementVectorUnit::from_bytes(&self.encoded_datalake); ProcessedDatalakeCompute { task_bytes_len: computational_task_felts.bytes_len, encoded_task: computational_task_felts.felts, diff --git a/hdp/src/primitives/processed_types/cairo_format/felt_vec_unit.rs b/hdp/src/primitives/processed_types/cairo_format/felt_vec_unit.rs index afc4baca..6a19a72b 100644 --- a/hdp/src/primitives/processed_types/cairo_format/felt_vec_unit.rs +++ b/hdp/src/primitives/processed_types/cairo_format/felt_vec_unit.rs @@ -1,4 +1,3 @@ -use anyhow::Result; use serde::Serialize; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; @@ -7,15 +6,25 @@ use starknet_crypto::FieldElement; #[serde_as] #[derive(Serialize, Debug)] pub struct FieldElementVectorUnit { + /// Chunked vector of field elements #[serde_as(as = "Vec")] pub felts: Vec, + /// Length of the original byte array before chunking into field elements pub bytes_len: u64, } impl FieldElementVectorUnit { - pub fn from_bytes(bytes: &[u8]) -> Result { + /// Converts a byte slice into a `FieldElementVectorUnit`. + /// + /// This function takes a slice of bytes and converts it into a `FieldElementVectorUnit`, + /// which consists of a vector of `FieldElement`s and the length of the original byte slice. + /// + /// # Panics + /// + /// This function will panic if the input byte slice is empty. + pub fn from_bytes(bytes: &[u8]) -> Self { if bytes.is_empty() { - return Err(anyhow::anyhow!("Empty hex input")); + panic!("Cannot convert to FieldElementVectorUnit from empty bytes") } let bytes_len = bytes.len() as u64; let felts = bytes @@ -30,7 +39,7 @@ impl FieldElementVectorUnit { }) .collect(); - Ok(Self { felts, bytes_len }) + Self { felts, bytes_len } } } @@ -41,16 +50,16 @@ mod tests { use super::*; #[test] + #[should_panic(expected = "Cannot convert to FieldElementVectorUnit from empty bytes")] fn test_empty_bytes() { let bytes = hex::decode("").unwrap(); - let result = FieldElementVectorUnit::from_bytes(&bytes); - assert!(result.is_err()); + FieldElementVectorUnit::from_bytes(&bytes); } #[test] fn test_single_byte_bytes() { let bytes = hex::decode("0x01").unwrap(); - let result = FieldElementVectorUnit::from_bytes(&bytes).unwrap(); + let result = FieldElementVectorUnit::from_bytes(&bytes); assert_eq!(result.bytes_len, 1); assert_eq!(result.felts.len(), 1); assert_eq!(result.felts[0], FieldElement::from_hex_be("0x1").unwrap()); @@ -59,7 +68,7 @@ mod tests { #[test] fn test_single_chunk_bytes() { let bytes = hex::decode("0x1234567890abcdef").unwrap(); - let result = FieldElementVectorUnit::from_bytes(&bytes).unwrap(); + let result = FieldElementVectorUnit::from_bytes(&bytes); assert_eq!(result.bytes_len, 8); assert_eq!(result.felts.len(), 1); assert_eq!( @@ -71,7 +80,7 @@ mod tests { #[test] fn test_multiple_chunks_bytes() { let bytes = hex::decode("0x1234567890abcdef1122334455667788").unwrap(); - let result = FieldElementVectorUnit::from_bytes(&bytes).unwrap(); + let result = FieldElementVectorUnit::from_bytes(&bytes); assert_eq!(result.bytes_len, 16); assert_eq!(result.felts.len(), 2); assert_eq!( diff --git a/hdp/src/primitives/processed_types/cairo_format/header.rs b/hdp/src/primitives/processed_types/cairo_format/header.rs index 6d04873b..663ad126 100644 --- a/hdp/src/primitives/processed_types/cairo_format/header.rs +++ b/hdp/src/primitives/processed_types/cairo_format/header.rs @@ -13,7 +13,7 @@ impl AsCairoFormat for BaseProcessedHeader { type Output = ProcessedHeader; fn as_cairo_format(&self) -> Self::Output { - let felts_unit = FieldElementVectorUnit::from_bytes(&self.rlp).unwrap(); + let felts_unit = FieldElementVectorUnit::from_bytes(&self.rlp); let proof = self.proof.clone(); ProcessedHeader { rlp: felts_unit.felts, diff --git a/hdp/src/primitives/processed_types/cairo_format/module.rs b/hdp/src/primitives/processed_types/cairo_format/module.rs index fe55b295..ace62357 100644 --- a/hdp/src/primitives/processed_types/cairo_format/module.rs +++ b/hdp/src/primitives/processed_types/cairo_format/module.rs @@ -13,7 +13,7 @@ impl AsCairoFormat for BaseProcessedModule { type Output = ProcessedModule; fn as_cairo_format(&self) -> Self::Output { - let module_task_felts = FieldElementVectorUnit::from_bytes(&self.encoded_task).unwrap(); + let module_task_felts = FieldElementVectorUnit::from_bytes(&self.encoded_task); ProcessedModule { module_class: self.module_class.clone(), encoded_task: module_task_felts.felts, diff --git a/hdp/src/primitives/processed_types/cairo_format/mpt.rs b/hdp/src/primitives/processed_types/cairo_format/mpt.rs index ec2baaaa..707f4112 100644 --- a/hdp/src/primitives/processed_types/cairo_format/mpt.rs +++ b/hdp/src/primitives/processed_types/cairo_format/mpt.rs @@ -13,7 +13,7 @@ impl AsCairoFormat for BaseProcessedMPTProof { let proof_felts: Vec = self .proof .iter() - .map(|proof| FieldElementVectorUnit::from_bytes(proof).unwrap()) + .map(|proof| FieldElementVectorUnit::from_bytes(proof)) .collect(); let proof_bytes_len = proof_felts.iter().map(|f| f.bytes_len).collect(); diff --git a/hdp/src/primitives/processed_types/cairo_format/receipt.rs b/hdp/src/primitives/processed_types/cairo_format/receipt.rs index f5293f1b..dba8fd5d 100644 --- a/hdp/src/primitives/processed_types/cairo_format/receipt.rs +++ b/hdp/src/primitives/processed_types/cairo_format/receipt.rs @@ -15,7 +15,7 @@ impl AsCairoFormat for BaseProcessedReceipt { let proof_felts: Vec = self .proof .iter() - .map(|proof| FieldElementVectorUnit::from_bytes(proof).unwrap()) + .map(|proof| FieldElementVectorUnit::from_bytes(proof)) .collect(); let proof_bytes_len = proof_felts.iter().map(|f| f.bytes_len).collect(); diff --git a/hdp/src/primitives/processed_types/cairo_format/storage.rs b/hdp/src/primitives/processed_types/cairo_format/storage.rs index 4aba0c1c..6817b80b 100644 --- a/hdp/src/primitives/processed_types/cairo_format/storage.rs +++ b/hdp/src/primitives/processed_types/cairo_format/storage.rs @@ -14,9 +14,8 @@ impl AsCairoFormat for BaseProcessedStorage { type Output = ProcessedStorage; fn as_cairo_format(&self) -> Self::Output { - let address_chunk_result = - FieldElementVectorUnit::from_bytes(self.address.as_ref()).unwrap(); - let slot_chunk_result = FieldElementVectorUnit::from_bytes(self.slot.as_ref()).unwrap(); + let address_chunk_result = FieldElementVectorUnit::from_bytes(self.address.as_ref()); + let slot_chunk_result = FieldElementVectorUnit::from_bytes(self.slot.as_ref()); let storage_key = self.storage_key; let proofs = self .proofs diff --git a/hdp/src/primitives/processed_types/cairo_format/transaction.rs b/hdp/src/primitives/processed_types/cairo_format/transaction.rs index 39385a9b..2a32578b 100644 --- a/hdp/src/primitives/processed_types/cairo_format/transaction.rs +++ b/hdp/src/primitives/processed_types/cairo_format/transaction.rs @@ -15,7 +15,7 @@ impl AsCairoFormat for BaseProcessedTransaction { let proof_felts: Vec = self .proof .iter() - .map(|proof| FieldElementVectorUnit::from_bytes(proof).unwrap()) + .map(|proof| FieldElementVectorUnit::from_bytes(proof)) .collect(); let proof_bytes_len = proof_felts.iter().map(|f| f.bytes_len).collect(); diff --git a/hdp/src/primitives/processed_types/uint256.rs b/hdp/src/primitives/processed_types/uint256.rs index 33e51e00..a5fd4676 100644 --- a/hdp/src/primitives/processed_types/uint256.rs +++ b/hdp/src/primitives/processed_types/uint256.rs @@ -1,8 +1,9 @@ //! This module contains the `Uint256` type, which is a 256-bit unsigned integer. //! This is compatible with Cairo `uint256` type. -use alloy::primitives::{hex::FromHex, B256}; +use alloy::primitives::{hex::FromHex, B256, U256}; use anyhow::Result; +use core::fmt::Display; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; @@ -11,27 +12,81 @@ use std::str::FromStr; use crate::primitives::utils::bytes_to_hex_string; +/// [`Uint256`] represents a 256-bit unsigned integer. +/// It is implemented as a struct with two [`FieldElement`] values: `high` and `low`. +/// Each [`FieldElement`] represents 128 bits of the 256-bit integer. #[serde_as] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Eq, Hash)] pub struct Uint256 { #[serde_as(as = "UfeHex")] - pub low: FieldElement, + pub low: FieldElement, // Represents the least significant 128 bits #[serde_as(as = "UfeHex")] - pub high: FieldElement, + pub high: FieldElement, // Represents the most significant 128 bits +} + +impl Default for Uint256 { + /// Returns a `Uint256` with a value of zero. + fn default() -> Self { + Self::ZERO + } } impl Uint256 { - pub fn from_strs(high: &str, low: &str) -> Result { + /// Constant representing zero as a `Uint256`. + pub const ZERO: Self = Self { + high: FieldElement::ZERO, + low: FieldElement::ZERO, + }; + + /// Creates a `Uint256` from two byte slices representing the high and low parts. + /// + /// # Arguments + /// * `high` - A byte slice representing the most significant 128 bits + /// * `low` - A byte slice representing the least significant 128 bits + /// + /// # Returns + /// A `Result` containing the new `Uint256` or an error if conversion fails. + pub fn from_bytes_tuple(high: &[u8], low: &[u8]) -> Result { + Ok(Self { + high: FieldElement::from_byte_slice_be(high)?, + low: FieldElement::from_byte_slice_be(low)?, + }) + } + + /// Creates a `Uint256` from two hexadecimal strings representing the high and low parts. + /// + /// # Arguments + /// * `high` - A string slice representing the most significant 128 bits in hex + /// * `low` - A string slice representing the least significant 128 bits in hex + /// + /// # Returns + /// A `Result` containing the new `Uint256` or an error if conversion fails. + pub fn from_hex_tuple(high: &str, low: &str) -> Result { Ok(Self { high: FieldElement::from_hex_be(high)?, low: FieldElement::from_hex_be(low)?, }) } - pub fn from_felts(high: FieldElement, low: FieldElement) -> Self { + /// Creates a `Uint256` from two [`FieldElement`]s representing the high and low parts. + /// + /// # Arguments + /// * `high` - A `FieldElement` representing the most significant 128 bits + /// * `low` - A `FieldElement` representing the least significant 128 bits + /// + /// # Returns + /// A new `Uint256` instance. + pub fn from_field_element_tuple(high: FieldElement, low: FieldElement) -> Self { Self { high, low } } + /// Creates a `Uint256` from a little-endian hexadecimal string. + /// + /// # Arguments + /// * `hex_str` - A string slice containing the hexadecimal representation + /// + /// # Returns + /// A `Result` containing the new `Uint256` or an error if conversion fails. pub fn from_le_hex_str(hex_str: &str) -> Result { let clean_hex = hex_str.trim_start_matches("0x"); let mut fix_hex: B256 = B256::from_hex(clean_hex)?; @@ -46,6 +101,13 @@ impl Uint256 { }) } + /// Creates a `Uint256` from a big-endian hexadecimal string. + /// + /// # Arguments + /// * `hex_str` - A string slice containing the hexadecimal representation + /// + /// # Returns + /// A `Result` containing the new `Uint256` or an error if conversion fails. pub fn from_be_hex_str(hex_str: &str) -> Result { let clean_hex = hex_str.trim_start_matches("0x"); let padded_hex = format!("{:0>64}", clean_hex); @@ -56,8 +118,28 @@ impl Uint256 { }) } - /// combine_parts_into_big_endian_hex - pub fn to_combined_string(&self) -> B256 { + /// Creates a `Uint256` from a big-endian byte slice. + /// + /// # Arguments + /// * `bytes` - A byte slice containing the 256-bit integer representation + /// + /// # Returns + /// A `Result` containing the new `Uint256` or an error if conversion fails. + pub fn from_be_bytes(bytes: &[u8]) -> Result { + let high_part = bytes[..16].to_vec(); + let low_part = bytes[16..].to_vec(); + + Ok(Self { + high: FieldElement::from_hex_be(&bytes_to_hex_string(&high_part))?, + low: FieldElement::from_hex_be(&bytes_to_hex_string(&low_part))?, + }) + } +} + +impl Display for Uint256 { + /// Formats the `Uint256` as a hexadecimal string. + /// The output is a 0x-prefixed, 64-character hexadecimal string. + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Ensure both parts are exactly 32 hex characters long let high_padded = format!( "{:0>32}", @@ -71,8 +153,35 @@ impl Uint256 { ) .trim_start_matches("0x") .to_string(); + write!(f, "0x{}{}", high_padded, low_padded) + } +} + +impl From for B256 { + /// Converts a `Uint256` to a `B256`. + fn from(value: Uint256) -> B256 { + B256::from_str(&value.to_string()).expect("Invalid value for B256") + } +} + +impl From for Uint256 { + /// Converts a `B256` to a `Uint256`. + fn from(value: B256) -> Self { + Self::from_be_bytes(value.as_slice()).expect("Invalid value for Uint256") + } +} - B256::from_str(&format!("0x{}{}", high_padded, low_padded)).unwrap() +impl From for U256 { + /// Converts a `Uint256` to a `U256`. + fn from(value: Uint256) -> U256 { + U256::from_str(&value.to_string()).expect("Invalid value for U256") + } +} + +impl From for Uint256 { + /// Converts a `U256` to a `Uint256`. + fn from(value: U256) -> Self { + Self::from_be_bytes(&value.to_be_bytes_vec()).expect("Invalid value for Uint256") } } @@ -85,32 +194,35 @@ mod tests { #[test] fn test_combine_parts_into_big_endian_hex() { - let uint256 = Uint256::from_felts( - FieldElement::from_hex_be("0x988c19313bcbfb19fcc4da12e3adb46c").unwrap(), - FieldElement::from_hex_be("0xf6fbdd08af91b1d8df80c6e755159f1").unwrap(), - ); + let result0: B256 = Uint256::from_field_element_tuple( + felt!("0x988c19313bcbfb19fcc4da12e3adb46c"), + felt!("0xf6fbdd08af91b1d8df80c6e755159f1"), + ) + .into(); assert_eq!( - uint256.to_combined_string(), + result0, B256::from_str("0x988c19313bcbfb19fcc4da12e3adb46c0f6fbdd08af91b1d8df80c6e755159f1") .unwrap() ); - let uint256 = Uint256::from_felts( + let result1: B256 = Uint256::from_field_element_tuple( felt!("0x988c19313bcbfb19fcc4da12e3adb46"), felt!("0xf6fbdd08af91b1d8df80c6e755159f1"), - ); + ) + .into(); assert_eq!( - uint256.to_combined_string(), + result1, B256::from_str("0x0988c19313bcbfb19fcc4da12e3adb460f6fbdd08af91b1d8df80c6e755159f1") .unwrap() ); - let uint256 = Uint256::from_felts( + let result2: B256 = Uint256::from_field_element_tuple( felt!("0x988c19313bcbfb19fcc4da12e3adb4"), felt!("0xf6fbdd08af91b1d8df80c6e755159f1"), - ); + ) + .into(); assert_eq!( - uint256.to_combined_string(), + result2, B256::from_str("0x00988c19313bcbfb19fcc4da12e3adb40f6fbdd08af91b1d8df80c6e755159f1") .unwrap() ); @@ -122,12 +234,13 @@ mod tests { let result = Uint256::from_be_hex_str(hex_str).unwrap(); assert_eq!( result, - Uint256::from_felts( + Uint256::from_field_element_tuple( felt!("0x60870c80ce4e1d0c35e34f08b1648e8a"), felt!("0x4fdc7818eea7caedbd316c63a3863562"), ) ); - assert_eq!(result.to_combined_string().to_string(), hex_str); + let result_b256: B256 = result.into(); + assert_eq!(result_b256, B256::from_str(hex_str).unwrap()); } #[test] @@ -136,7 +249,7 @@ mod tests { let result = Uint256::from_le_hex_str(hex_str).unwrap(); assert_eq!( result, - Uint256::from_felts( + Uint256::from_field_element_tuple( felt!("0x1d693b26fded2cc4edb9acbf8133f52d"), felt!("0x2a32ca1db17188d788996d243adbda8d"), ) @@ -145,7 +258,7 @@ mod tests { #[test] fn test_uint256_serde() { - let target = Uint256::from_felts( + let target = Uint256::from_field_element_tuple( felt!("0x1d693b26fded2cc4edb9acbf8133f52d"), felt!("0x2a32ca1db17188d788996d243adbda8d"), ); @@ -154,4 +267,11 @@ mod tests { let expected = json_file.trim(); assert_eq!(string, expected); } + + #[test] + fn test_uint256_default() { + let zero: B256 = Uint256::ZERO.into(); + + assert_eq!(zero, B256::ZERO) + } } diff --git a/hdp/src/primitives/solidity_types/datalake_compute/datalake/envelope.rs b/hdp/src/primitives/solidity_types/datalake_compute/datalake/envelope.rs index bf529c3a..d2f1413c 100644 --- a/hdp/src/primitives/solidity_types/datalake_compute/datalake/envelope.rs +++ b/hdp/src/primitives/solidity_types/datalake_compute/datalake/envelope.rs @@ -180,7 +180,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let transaction_datalake2 = TransactionsInBlockDatalake::new( @@ -190,7 +190,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let datalakes = vec![ @@ -215,7 +215,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let transaction_datalake2 = TransactionsInBlockDatalake::new( @@ -225,7 +225,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); assert_eq!( @@ -247,7 +247,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let transaction_datalake2 = TransactionsInBlockDatalake::new( @@ -257,7 +257,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let datalakes = vec![ @@ -282,7 +282,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let transaction_datalake2 = TransactionsInBlockDatalake::new( @@ -292,7 +292,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); assert_eq!( diff --git a/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs b/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs index 81c91781..0905bedc 100644 --- a/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs +++ b/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs @@ -7,7 +7,7 @@ use crate::primitives::{ }, ChainId, }; -use alloy::primitives::keccak256; +use alloy::primitives::{keccak256, U256}; use alloy::{ dyn_abi::{DynSolType, DynSolValue}, primitives::B256, @@ -29,7 +29,8 @@ impl DatalakeCodecs for TransactionsInBlockDatalake { let start_index: DynSolValue = self.start_index.into(); let end_index: DynSolValue = self.end_index.into(); let increment: DynSolValue = self.increment.into(); - let included_types: DynSolValue = self.included_types.to_uint256().into(); + let converted: U256 = (&self.included_types).into(); + let included_types: DynSolValue = converted.into(); let tuple_value = DynSolValue::Tuple(vec![ datalake_code, @@ -73,7 +74,7 @@ impl DatalakeCodecs for TransactionsInBlockDatalake { let start_index = value[3].as_uint().unwrap().0.to_string().parse::()?; let end_index = value[4].as_uint().unwrap().0.to_string().parse::()?; let increment = value[5].as_uint().unwrap().0.to_string().parse::()?; - let included_types = IncludedTypes::from_uint256(value[6].as_uint().unwrap().0); + let included_types = IncludedTypes::from(value[6].as_uint().unwrap().0); let sampled_property = TransactionsCollection::deserialize(value[7].as_bytes().unwrap())?; Ok(Self { diff --git a/hdp/src/primitives/task/datalake/block_sampled/datalake.rs b/hdp/src/primitives/task/datalake/block_sampled/datalake.rs index 7242e98c..850d249c 100644 --- a/hdp/src/primitives/task/datalake/block_sampled/datalake.rs +++ b/hdp/src/primitives/task/datalake/block_sampled/datalake.rs @@ -5,12 +5,13 @@ use crate::primitives::{task::datalake::envelope::default_increment, ChainId}; use super::collection::BlockSampledCollection; /// [`BlockSampledDatalake`] is a struct that represents a block sampled datalake. -/// It contains the block range, the sampled property, and the increment. +/// It contains chain id, block range, the sampled property, and the increment. /// -/// The block range is inclusive, so the block range is from `block_range_start` to `block_range_end` +/// Inclusive block range: [block_range_start..block_range_end] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct BlockSampledDatalake { + /// Chain id of the datalake pub chain_id: ChainId, /// The start of the block range pub block_range_start: u64, diff --git a/hdp/src/primitives/task/datalake/transactions/datalake.rs b/hdp/src/primitives/task/datalake/transactions/datalake.rs index dee89bd6..b7b0727b 100644 --- a/hdp/src/primitives/task/datalake/transactions/datalake.rs +++ b/hdp/src/primitives/task/datalake/transactions/datalake.rs @@ -114,7 +114,15 @@ impl IncludedTypes { included_types } - pub fn from(included_types: &[u8]) -> Self { + /// Converts a slice of bytes into an [`IncludedTypes`] instance. + /// + /// # Panics + /// + /// This function will panic if: + /// - The input slice is not exactly 4 bytes long. + /// - Any byte in the slice is not 0 or 1. + /// - All bytes in the slice are 0 (i.e., no transaction type is included). + pub fn from_bytes(included_types: &[u8]) -> Self { if included_types.len() != 4 { panic!("Included types must be 4 bytes long"); } @@ -134,19 +142,24 @@ impl IncludedTypes { let inner_bytes = self.to_be_bytes(); inner_bytes[target_type as usize] != 0 } +} - pub fn to_uint256(&self) -> U256 { +impl From<&IncludedTypes> for U256 { + fn from(value: &IncludedTypes) -> U256 { let mut bytes = [0; 32]; - let inner_bytes = self.to_be_bytes(); + let inner_bytes = value.to_be_bytes(); bytes[28..32].copy_from_slice(&inner_bytes); U256::from_be_bytes(bytes) } +} - pub fn from_uint256(value: U256) -> Self { +// Implementation of From for Self +impl From for IncludedTypes { + fn from(value: U256) -> IncludedTypes { let bytes: [u8; 32] = value.to_be_bytes(); let mut inner = [0; 4]; inner.copy_from_slice(&bytes[28..32]); - Self::from_be_bytes(inner) + IncludedTypes::from_be_bytes(inner) } } @@ -163,7 +176,7 @@ impl FromStr for IncludedTypes { panic!("Included types must be 4 bytes long"); } - Ok(IncludedTypes::from(&included_types)) + Ok(IncludedTypes::from_bytes(&included_types)) } } @@ -173,16 +186,16 @@ mod tests { #[test] fn test_included_types() { - let included_types = IncludedTypes::from(&[1, 1, 1, 1]); + let included_types = IncludedTypes::from_bytes(&[1, 1, 1, 1]); assert!(included_types.is_included(TxType::Legacy)); assert!(included_types.is_included(TxType::Eip2930)); assert!(included_types.is_included(TxType::Eip1559)); assert!(included_types.is_included(TxType::Eip4844)); - let uint256 = included_types.to_uint256(); + let uint256: U256 = (&included_types).into(); assert_eq!(uint256, U256::from(0x01010101)); - let included_types = IncludedTypes::from_uint256(uint256); + let included_types = IncludedTypes::from(uint256); assert!(included_types.is_included(TxType::Legacy)); assert!(included_types.is_included(TxType::Eip2930)); assert!(included_types.is_included(TxType::Eip1559)); @@ -191,16 +204,16 @@ mod tests { #[test] fn test_included_types_partial() { - let included_types = IncludedTypes::from(&[1, 0, 1, 0]); + let included_types = IncludedTypes::from_bytes(&[1, 0, 1, 0]); assert!(included_types.is_included(TxType::Legacy)); assert!(!included_types.is_included(TxType::Eip2930)); assert!(included_types.is_included(TxType::Eip1559)); assert!(!included_types.is_included(TxType::Eip4844)); - let uint256 = included_types.to_uint256(); + let uint256: U256 = (&included_types).into(); assert_eq!(uint256, U256::from(0x01000100)); - let included_types = IncludedTypes::from_uint256(uint256); + let included_types = IncludedTypes::from(uint256); assert!(included_types.is_included(TxType::Legacy)); assert!(!included_types.is_included(TxType::Eip2930)); assert!(included_types.is_included(TxType::Eip1559)); diff --git a/hdp/src/primitives/task/datalake/transactions/mod.rs b/hdp/src/primitives/task/datalake/transactions/mod.rs index 3abcef5b..625297bf 100644 --- a/hdp/src/primitives/task/datalake/transactions/mod.rs +++ b/hdp/src/primitives/task/datalake/transactions/mod.rs @@ -33,7 +33,7 @@ mod tests { 1, 10, 2, - IncludedTypes::from(&[1, 1, 1, 1]), + IncludedTypes::from_bytes(&[1, 1, 1, 1]), ); let encoded = transaction_datalake.encode().unwrap(); @@ -51,10 +51,8 @@ mod tests { TransactionsCollection::Transactions(TransactionField::Nonce) ); - assert_eq!( - transaction_datalake.included_types.to_uint256(), - U256::from(0x01010101) - ); + let converted: U256 = (&transaction_datalake.included_types).into(); + assert_eq!(converted, U256::from(0x01010101)); let decoded = TransactionsInBlockDatalake::decode(&encoded).unwrap(); assert_eq!(decoded, transaction_datalake); @@ -72,7 +70,7 @@ mod tests { 1, 10, 2, - IncludedTypes::from(&[1, 0, 0, 1]), + IncludedTypes::from_bytes(&[1, 0, 0, 1]), ); let encoded = transaction_datalake.encode().unwrap(); @@ -90,10 +88,8 @@ mod tests { TransactionsCollection::TranasactionReceipts(TransactionReceiptField::Success) ); - assert_eq!( - transaction_datalake.included_types.to_uint256(), - U256::from(0x01000001) - ); + let converted: U256 = (&transaction_datalake.included_types).into(); + assert_eq!(converted, U256::from(0x01000001)); let decoded = TransactionsInBlockDatalake::decode(&encoded).unwrap(); assert_eq!(decoded, transaction_datalake); From 42d15fb29b7346b99e346c18c40cfa1a13446325 Mon Sep 17 00:00:00 2001 From: Pia Date: Sun, 15 Sep 2024 17:49:21 +0900 Subject: [PATCH 2/5] chore: consume value on from --- .../datalake_compute/datalake/transactions_in_block.rs | 2 +- .../primitives/task/datalake/transactions/datalake.rs | 10 +++++----- hdp/src/primitives/task/datalake/transactions/mod.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs b/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs index 0905bedc..a9eb0482 100644 --- a/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs +++ b/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs @@ -29,7 +29,7 @@ impl DatalakeCodecs for TransactionsInBlockDatalake { let start_index: DynSolValue = self.start_index.into(); let end_index: DynSolValue = self.end_index.into(); let increment: DynSolValue = self.increment.into(); - let converted: U256 = (&self.included_types).into(); + let converted: U256 = self.included_types.into(); let included_types: DynSolValue = converted.into(); let tuple_value = DynSolValue::Tuple(vec![ diff --git a/hdp/src/primitives/task/datalake/transactions/datalake.rs b/hdp/src/primitives/task/datalake/transactions/datalake.rs index b7b0727b..87487128 100644 --- a/hdp/src/primitives/task/datalake/transactions/datalake.rs +++ b/hdp/src/primitives/task/datalake/transactions/datalake.rs @@ -66,7 +66,7 @@ impl TransactionsInBlockDatalake { /// 1: EIP-2930 /// 2: EIP-1559 /// 3: EIP-4844 -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct IncludedTypes { legacy: bool, eip2930: bool, @@ -144,8 +144,8 @@ impl IncludedTypes { } } -impl From<&IncludedTypes> for U256 { - fn from(value: &IncludedTypes) -> U256 { +impl From for U256 { + fn from(value: IncludedTypes) -> U256 { let mut bytes = [0; 32]; let inner_bytes = value.to_be_bytes(); bytes[28..32].copy_from_slice(&inner_bytes); @@ -192,7 +192,7 @@ mod tests { assert!(included_types.is_included(TxType::Eip1559)); assert!(included_types.is_included(TxType::Eip4844)); - let uint256: U256 = (&included_types).into(); + let uint256: U256 = included_types.into(); assert_eq!(uint256, U256::from(0x01010101)); let included_types = IncludedTypes::from(uint256); @@ -210,7 +210,7 @@ mod tests { assert!(included_types.is_included(TxType::Eip1559)); assert!(!included_types.is_included(TxType::Eip4844)); - let uint256: U256 = (&included_types).into(); + let uint256: U256 = included_types.into(); assert_eq!(uint256, U256::from(0x01000100)); let included_types = IncludedTypes::from(uint256); diff --git a/hdp/src/primitives/task/datalake/transactions/mod.rs b/hdp/src/primitives/task/datalake/transactions/mod.rs index 625297bf..f96d1a53 100644 --- a/hdp/src/primitives/task/datalake/transactions/mod.rs +++ b/hdp/src/primitives/task/datalake/transactions/mod.rs @@ -51,7 +51,7 @@ mod tests { TransactionsCollection::Transactions(TransactionField::Nonce) ); - let converted: U256 = (&transaction_datalake.included_types).into(); + let converted: U256 = transaction_datalake.included_types.into(); assert_eq!(converted, U256::from(0x01010101)); let decoded = TransactionsInBlockDatalake::decode(&encoded).unwrap(); @@ -88,7 +88,7 @@ mod tests { TransactionsCollection::TranasactionReceipts(TransactionReceiptField::Success) ); - let converted: U256 = (&transaction_datalake.included_types).into(); + let converted: U256 = transaction_datalake.included_types.into(); assert_eq!(converted, U256::from(0x01000001)); let decoded = TransactionsInBlockDatalake::decode(&encoded).unwrap(); From cbcf5a0bf572a6c198ce39cfef2af0d69d9a75e1 Mon Sep 17 00:00:00 2001 From: Pia Date: Sun, 15 Sep 2024 17:57:42 +0900 Subject: [PATCH 3/5] chore: --- hdp/src/preprocessor/compile/datalake.rs | 4 +-- .../task/datalake/transactions/datalake.rs | 27 ++++++++++++++----- .../task/datalake/transactions/mod.rs | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/hdp/src/preprocessor/compile/datalake.rs b/hdp/src/preprocessor/compile/datalake.rs index 7cef1a11..47f4da05 100644 --- a/hdp/src/preprocessor/compile/datalake.rs +++ b/hdp/src/preprocessor/compile/datalake.rs @@ -173,7 +173,7 @@ mod tests { start_index: 0, end_index: 10, increment: 1, - included_types: IncludedTypes::from_bytes(&[1, 1, 1, 1]), + included_types: IncludedTypes::ALL, sampled_property: TransactionsCollection::Transactions( TransactionField::GasLimit, ), @@ -187,7 +187,7 @@ mod tests { start_index: 0, end_index: 11, increment: 1, - included_types: IncludedTypes::from_bytes(&[1, 1, 1, 1]), + included_types: IncludedTypes::ALL, sampled_property: TransactionsCollection::TranasactionReceipts( TransactionReceiptField::Success, ), diff --git a/hdp/src/primitives/task/datalake/transactions/datalake.rs b/hdp/src/primitives/task/datalake/transactions/datalake.rs index 87487128..84a0b6fd 100644 --- a/hdp/src/primitives/task/datalake/transactions/datalake.rs +++ b/hdp/src/primitives/task/datalake/transactions/datalake.rs @@ -17,22 +17,27 @@ use crate::primitives::{task::datalake::envelope::default_increment, ChainId}; use super::TransactionsCollection; +/// [`TransactionsInBlockDatalake`] is a struct that represents a transactions datalake. +/// It contains chain id, target block, transaction range, sampled property, and other properties. +/// +/// Transaction range: [start_index..end_index] with specified increment #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionsInBlockDatalake { + /// Chain id of the datalake pub chain_id: ChainId, - // target block number + /// Target block number pub target_block: u64, - // start index of transactions range ( default 0 ) + /// Start index of transactions range (default 0) pub start_index: u64, - // end index of transactions range, not included in the range ( default last ) + /// End index of transactions range, not included in the range (default last) pub end_index: u64, - // increment of transactions, Defaults to 1 if not present. + /// Increment of transactions, Defaults to 1 if not present. #[serde(default = "default_increment")] pub increment: u64, - // filter out the specific type of Txs + /// Filter out the specific type of Txs pub included_types: IncludedTypes, - // ex. "tx.to" , "tx.gas_price" or "tx_receipt.success", "tx_receipt.cumulative_gas_used" + /// Sampled property (e.g., "tx.to", "tx.gas_price", "tx_receipt.success", "tx_receipt.cumulative_gas_used") pub sampled_property: TransactionsCollection, } @@ -75,6 +80,14 @@ pub struct IncludedTypes { } impl IncludedTypes { + /// All transaction types(Legacy, EIP-1559, EIP-2930, EIP-4844) are included + pub const ALL: Self = Self { + legacy: true, + eip1559: true, + eip2930: true, + eip4844: true, + }; + pub fn to_be_bytes(&self) -> [u8; 4] { let mut bytes = [0; 4]; if self.legacy { @@ -186,7 +199,7 @@ mod tests { #[test] fn test_included_types() { - let included_types = IncludedTypes::from_bytes(&[1, 1, 1, 1]); + let included_types = IncludedTypes::ALL; assert!(included_types.is_included(TxType::Legacy)); assert!(included_types.is_included(TxType::Eip2930)); assert!(included_types.is_included(TxType::Eip1559)); diff --git a/hdp/src/primitives/task/datalake/transactions/mod.rs b/hdp/src/primitives/task/datalake/transactions/mod.rs index f96d1a53..5589833e 100644 --- a/hdp/src/primitives/task/datalake/transactions/mod.rs +++ b/hdp/src/primitives/task/datalake/transactions/mod.rs @@ -33,7 +33,7 @@ mod tests { 1, 10, 2, - IncludedTypes::from_bytes(&[1, 1, 1, 1]), + IncludedTypes::ALL, ); let encoded = transaction_datalake.encode().unwrap(); From 96fb67fa9f54b72418e6e26d3dac12826aa4e261 Mon Sep 17 00:00:00 2001 From: Pia Date: Sun, 15 Sep 2024 18:36:07 +0900 Subject: [PATCH 4/5] chore: more cleanup --- hdp/src/primitives/block/account.rs | 31 ++++++------------- hdp/src/primitives/block/header.rs | 9 ++---- hdp/src/primitives/chain_id.rs | 6 ---- hdp/src/primitives/processed_types/uint256.rs | 10 +++--- .../solidity_types/datalake_compute/mod.rs | 8 ++--- hdp/src/primitives/solidity_types/module.rs | 8 ++--- .../task/datalake/block_sampled/collection.rs | 2 +- .../task/datalake/block_sampled/rlp_fields.rs | 4 +-- hdp/src/primitives/task/datalake/envelope.rs | 6 ++-- .../task/datalake/transactions/collection.rs | 2 +- .../task/datalake/transactions/datalake.rs | 21 +++++++++++++ .../task/datalake/transactions/mod.rs | 11 ++----- .../task/datalake/transactions/rlp_fields.rs | 4 +-- hdp/src/primitives/task/module.rs | 10 +++++- 14 files changed, 63 insertions(+), 69 deletions(-) diff --git a/hdp/src/primitives/block/account.rs b/hdp/src/primitives/block/account.rs index c8386d53..da369862 100644 --- a/hdp/src/primitives/block/account.rs +++ b/hdp/src/primitives/block/account.rs @@ -49,18 +49,15 @@ impl From<&EIP1186AccountProofResponse> for Account { mod tests { use super::*; use alloy::hex; - use alloy::primitives::U256; - use std::str::FromStr; + use alloy::primitives::{b256, U256}; #[test] fn test_get_account_rlp() { let account = Account::new( U64::from(1), U256::from(0), - B256::from_str("0x1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185") - .unwrap(), - B256::from_str("0xcd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c") - .unwrap(), + b256!("1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185"), + b256!("cd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c"), ); let account_rlp = account.rlp_encode(); assert_eq!( @@ -71,10 +68,8 @@ mod tests { let account = Account::new( U64::from(2), U256::from(0), - B256::from_str("0x1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185") - .unwrap(), - B256::from_str("0xcd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c") - .unwrap(), + b256!("1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185"), + b256!("cd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c"), ); let account_rlp = account.rlp_encode(); assert_eq!( @@ -85,10 +80,8 @@ mod tests { let account = Account::new( U64::from(2), U256::from(0x1), - B256::from_str("0x1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185") - .unwrap(), - B256::from_str("0xcd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c") - .unwrap(), + b256!("1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185"), + b256!("cd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c"), ); let account_rlp = account.rlp_encode(); assert_eq!( @@ -106,14 +99,8 @@ mod tests { Account::new( U64::from(1), U256::from(0), - B256::from_str( - "0x1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185" - ) - .unwrap(), - B256::from_str( - "0xcd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c" - ) - .unwrap() + b256!("1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185"), + b256!("cd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c") ) ); } diff --git a/hdp/src/primitives/block/header.rs b/hdp/src/primitives/block/header.rs index 249ce349..02555db6 100644 --- a/hdp/src/primitives/block/header.rs +++ b/hdp/src/primitives/block/header.rs @@ -378,8 +378,8 @@ impl BlockHeaderFromRpc { } } -impl From<&BlockHeaderFromRpc> for Header { - fn from(value: &BlockHeaderFromRpc) -> Self { +impl From for Header { + fn from(value: BlockHeaderFromRpc) -> Self { Self { parent_hash: B256::from_str(&value.parent_hash).expect("Invalid hex string"), ommers_hash: B256::from_str(&value.sha3_uncles).expect("Invalid hex string"), @@ -400,23 +400,18 @@ impl From<&BlockHeaderFromRpc> for Header { nonce: u64::from_str_radix(&value.nonce[2..], 16).expect("Invalid hex string"), base_fee_per_gas: value .base_fee_per_gas - .clone() .map(|x| u64::from_str_radix(&x[2..], 16).expect("Invalid hex string")), withdrawals_root: value .withdrawals_root - .clone() .map(|x| B256::from_str(&x).expect("Invalid hex string")), blob_gas_used: value .blob_gas_used - .clone() .map(|x| u64::from_str_radix(&x[2..], 16).expect("Invalid hex string")), excess_blob_gas: value .excess_blob_gas - .clone() .map(|x| u64::from_str_radix(&x[2..], 16).expect("Invalid hex string")), parent_beacon_block_root: value .parent_beacon_block_root - .clone() .map(|x| B256::from_str(&x).expect("Invalid hex string")), } } diff --git a/hdp/src/primitives/chain_id.rs b/hdp/src/primitives/chain_id.rs index 71c93904..7f35dfaf 100644 --- a/hdp/src/primitives/chain_id.rs +++ b/hdp/src/primitives/chain_id.rs @@ -13,12 +13,6 @@ pub enum ChainId { StarknetSepolia, } -impl Default for ChainId { - fn default() -> Self { - Self::EthereumSepolia - } -} - #[derive(Error, Debug, PartialEq)] #[error("Failed to parse ChainId: {input}")] pub struct ParseChainIdError { diff --git a/hdp/src/primitives/processed_types/uint256.rs b/hdp/src/primitives/processed_types/uint256.rs index a5fd4676..3099417e 100644 --- a/hdp/src/primitives/processed_types/uint256.rs +++ b/hdp/src/primitives/processed_types/uint256.rs @@ -188,6 +188,7 @@ impl From for Uint256 { #[cfg(test)] mod tests { + use alloy::primitives::b256; use starknet::macros::felt; use super::*; @@ -201,8 +202,7 @@ mod tests { .into(); assert_eq!( result0, - B256::from_str("0x988c19313bcbfb19fcc4da12e3adb46c0f6fbdd08af91b1d8df80c6e755159f1") - .unwrap() + b256!("988c19313bcbfb19fcc4da12e3adb46c0f6fbdd08af91b1d8df80c6e755159f1") ); let result1: B256 = Uint256::from_field_element_tuple( @@ -212,8 +212,7 @@ mod tests { .into(); assert_eq!( result1, - B256::from_str("0x0988c19313bcbfb19fcc4da12e3adb460f6fbdd08af91b1d8df80c6e755159f1") - .unwrap() + b256!("0988c19313bcbfb19fcc4da12e3adb460f6fbdd08af91b1d8df80c6e755159f1") ); let result2: B256 = Uint256::from_field_element_tuple( @@ -223,8 +222,7 @@ mod tests { .into(); assert_eq!( result2, - B256::from_str("0x00988c19313bcbfb19fcc4da12e3adb40f6fbdd08af91b1d8df80c6e755159f1") - .unwrap() + b256!("00988c19313bcbfb19fcc4da12e3adb40f6fbdd08af91b1d8df80c6e755159f1") ); } diff --git a/hdp/src/primitives/solidity_types/datalake_compute/mod.rs b/hdp/src/primitives/solidity_types/datalake_compute/mod.rs index 36fd4ae6..bbefe0f2 100644 --- a/hdp/src/primitives/solidity_types/datalake_compute/mod.rs +++ b/hdp/src/primitives/solidity_types/datalake_compute/mod.rs @@ -106,6 +106,8 @@ impl BatchedDatalakeComputeCodecs for BatchedDatalakeCompute { mod tests { use std::str::FromStr; + use alloy::primitives::b256; + use crate::primitives::{ aggregate_fn::FunctionContext, task::datalake::{ @@ -140,8 +142,7 @@ mod tests { assert_eq!( datalake_compute.commit(), - B256::from_str("0x931644ee9576d1a377d4c5ba642a9f96361663f31d867d36169623f782a887fc") - .unwrap() + b256!("931644ee9576d1a377d4c5ba642a9f96361663f31d867d36169623f782a887fc") ) } @@ -170,8 +171,7 @@ mod tests { assert_eq!( datalake_compute.commit(), - B256::from_str("0xa15da24b3eb2bb5260f59a71c3934b64e2747d8e934563ad532e7f877a061bed") - .unwrap() + b256!("a15da24b3eb2bb5260f59a71c3934b64e2747d8e934563ad532e7f877a061bed") ) } } diff --git a/hdp/src/primitives/solidity_types/module.rs b/hdp/src/primitives/solidity_types/module.rs index 570b8ced..dc54a964 100644 --- a/hdp/src/primitives/solidity_types/module.rs +++ b/hdp/src/primitives/solidity_types/module.rs @@ -34,8 +34,8 @@ impl Module { #[cfg(test)] mod tests { + use alloy::primitives::b256; use starknet_crypto::FieldElement; - use std::str::FromStr; use crate::primitives::task::module::{ModuleInput, Visibility}; @@ -62,8 +62,7 @@ mod tests { let expected_commit = module.commit(); assert_eq!( expected_commit, - B256::from_str("0x879869b6d237b92bfdd3f3f7b76baaa9ebb2a3ad5e8478d12cca258d3def05af") - .unwrap() + b256!("879869b6d237b92bfdd3f3f7b76baaa9ebb2a3ad5e8478d12cca258d3def05af") ); } @@ -88,8 +87,7 @@ mod tests { let expected_commit = module.commit(); assert_eq!( expected_commit, - B256::from_str("0xd81ebd27b719967e1df4edf64c9e3ce87635089e3462306af340a393625d8726") - .unwrap() + b256!("d81ebd27b719967e1df4edf64c9e3ce87635089e3462306af340a393625d8726") ); } } diff --git a/hdp/src/primitives/task/datalake/block_sampled/collection.rs b/hdp/src/primitives/task/datalake/block_sampled/collection.rs index c342eb68..fe3da9e2 100644 --- a/hdp/src/primitives/task/datalake/block_sampled/collection.rs +++ b/hdp/src/primitives/task/datalake/block_sampled/collection.rs @@ -8,7 +8,7 @@ use crate::primitives::task::datalake::{DatalakeCollection, DatalakeField}; use super::rlp_fields::{AccountField, HeaderField}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "String")] pub enum BlockSampledCollection { Header(HeaderField), diff --git a/hdp/src/primitives/task/datalake/block_sampled/rlp_fields.rs b/hdp/src/primitives/task/datalake/block_sampled/rlp_fields.rs index 77d3ffeb..36936f86 100644 --- a/hdp/src/primitives/task/datalake/block_sampled/rlp_fields.rs +++ b/hdp/src/primitives/task/datalake/block_sampled/rlp_fields.rs @@ -13,7 +13,7 @@ use crate::{ primitives::task::datalake::DatalakeField, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "String")] pub enum HeaderField { ParentHash, @@ -238,7 +238,7 @@ impl Display for HeaderField { // == Account Field == -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "String")] pub enum AccountField { Nonce, diff --git a/hdp/src/primitives/task/datalake/envelope.rs b/hdp/src/primitives/task/datalake/envelope.rs index e592162f..00dfe2de 100644 --- a/hdp/src/primitives/task/datalake/envelope.rs +++ b/hdp/src/primitives/task/datalake/envelope.rs @@ -18,10 +18,8 @@ pub enum DatalakeEnvelope { impl DatalakeEnvelope { pub fn get_collection_type(&self) -> Box { match self { - DatalakeEnvelope::BlockSampled(datalake) => Box::new(datalake.sampled_property.clone()), - DatalakeEnvelope::TransactionsInBlock(datalake) => { - Box::new(datalake.sampled_property.clone()) - } + DatalakeEnvelope::BlockSampled(datalake) => Box::new(datalake.sampled_property), + DatalakeEnvelope::TransactionsInBlock(datalake) => Box::new(datalake.sampled_property), } } diff --git a/hdp/src/primitives/task/datalake/transactions/collection.rs b/hdp/src/primitives/task/datalake/transactions/collection.rs index a31444bd..5e3310c8 100644 --- a/hdp/src/primitives/task/datalake/transactions/collection.rs +++ b/hdp/src/primitives/task/datalake/transactions/collection.rs @@ -37,7 +37,7 @@ impl FromStr for TransactionsCollectionType { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "String")] pub enum TransactionsCollection { Transactions(TransactionField), diff --git a/hdp/src/primitives/task/datalake/transactions/datalake.rs b/hdp/src/primitives/task/datalake/transactions/datalake.rs index 84a0b6fd..b64074df 100644 --- a/hdp/src/primitives/task/datalake/transactions/datalake.rs +++ b/hdp/src/primitives/task/datalake/transactions/datalake.rs @@ -5,6 +5,7 @@ //! Example: `TransactionsInBlockDatalake { target_block: 100, sampled_property: "tx.to", increment: 1 }` //! represents all transactions in block 100 with a `tx.to` property sampled with an increment of 1. +use core::fmt::Display; use std::num::ParseIntError; use std::str::FromStr; @@ -157,6 +158,13 @@ impl IncludedTypes { } } +impl Display for IncludedTypes { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let bytes = self.to_be_bytes(); + write!(f, "{},{},{},{}", bytes[0], bytes[1], bytes[2], bytes[3]) + } +} + impl From for U256 { fn from(value: IncludedTypes) -> U256 { let mut bytes = [0; 32]; @@ -232,4 +240,17 @@ mod tests { assert!(included_types.is_included(TxType::Eip1559)); assert!(!included_types.is_included(TxType::Eip4844)); } + + #[test] + fn test_included_types_from_str_to_str() { + let input_str = "1,0,1,0"; + let included_types = IncludedTypes::from_str(input_str).unwrap(); + assert!(included_types.is_included(TxType::Legacy)); + assert!(!included_types.is_included(TxType::Eip2930)); + assert!(included_types.is_included(TxType::Eip1559)); + assert!(!included_types.is_included(TxType::Eip4844)); + + let output_str = included_types.to_string(); + assert_eq!(input_str, output_str); + } } diff --git a/hdp/src/primitives/task/datalake/transactions/mod.rs b/hdp/src/primitives/task/datalake/transactions/mod.rs index 5589833e..9fb5a93e 100644 --- a/hdp/src/primitives/task/datalake/transactions/mod.rs +++ b/hdp/src/primitives/task/datalake/transactions/mod.rs @@ -9,15 +9,12 @@ pub use rlp_fields::*; #[cfg(test)] mod tests { - - use std::str::FromStr; - use crate::primitives::{ solidity_types::traits::DatalakeCodecs, task::datalake::DatalakeCollection, ChainId, }; use alloy::{ hex, - primitives::{B256, U256}, + primitives::{b256, U256}, }; use super::*; @@ -42,8 +39,7 @@ mod tests { assert_eq!( transaction_datalake.commit(), - B256::from_str("0x0a1ad7357827238fdbea5c8f34df65e7313c18388026fad78a75d4b5a6be71b7") - .unwrap() + b256!("0a1ad7357827238fdbea5c8f34df65e7313c18388026fad78a75d4b5a6be71b7") ); assert_eq!( @@ -79,8 +75,7 @@ mod tests { assert_eq!( transaction_datalake.commit(), - B256::from_str("0x991d3d38a26f54aed67f8391bab26c855dedd2fd810931542625b6ad4f7c1e42") - .unwrap() + b256!("991d3d38a26f54aed67f8391bab26c855dedd2fd810931542625b6ad4f7c1e42") ); assert_eq!( diff --git a/hdp/src/primitives/task/datalake/transactions/rlp_fields.rs b/hdp/src/primitives/task/datalake/transactions/rlp_fields.rs index a36c4b73..fe9dddee 100644 --- a/hdp/src/primitives/task/datalake/transactions/rlp_fields.rs +++ b/hdp/src/primitives/task/datalake/transactions/rlp_fields.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::primitives::task::datalake::DatalakeField; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum TransactionField { // ===== Transaction fields ===== Nonce, @@ -207,7 +207,7 @@ impl Display for TransactionField { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum TransactionReceiptField { Success, CumulativeGasUsed, diff --git a/hdp/src/primitives/task/module.rs b/hdp/src/primitives/task/module.rs index e1b014a5..a3276b9d 100644 --- a/hdp/src/primitives/task/module.rs +++ b/hdp/src/primitives/task/module.rs @@ -31,7 +31,8 @@ impl ModuleInput { pub fn new(visibility: Visibility, value: &str) -> Self { Self { visibility, - value: FieldElement::from_hex_be(value).unwrap(), + value: FieldElement::from_hex_be(value) + .expect("invalid hex string value to convert FieldElement"), } } } @@ -62,6 +63,13 @@ impl FromStr for ModuleInput { } } +impl From for ModuleInput { + fn from(s: String) -> Self { + s.parse() + .unwrap_or_else(|_| ModuleInput::new(Visibility::Private, &s)) + } +} + impl Module { pub fn new( program_hash: FieldElement, From 0a6164e493c0e5ea6662fd6f5465843deb17b864 Mon Sep 17 00:00:00 2001 From: Pia Date: Sun, 15 Sep 2024 18:50:23 +0900 Subject: [PATCH 5/5] cargo doc --- cli/src/commands/run_datalake.rs | 2 +- hdp/src/lib.rs | 5 +++++ hdp/src/primitives/block/header.rs | 3 +-- .../datalake_compute/datalake/transactions_in_block.rs | 4 ++-- hdp/src/primitives/solidity_types/traits.rs | 4 ++-- hdp/src/primitives/task/datalake/datalake_type.rs | 4 ++-- hdp/src/provider/error.rs | 6 +++--- hdp/src/provider/indexer.rs | 2 +- hdp/src/provider/starknet/types.rs | 2 +- justfile | 8 ++++++-- 10 files changed, 24 insertions(+), 16 deletions(-) diff --git a/cli/src/commands/run_datalake.rs b/cli/src/commands/run_datalake.rs index 8feedeca..50e68505 100644 --- a/cli/src/commands/run_datalake.rs +++ b/cli/src/commands/run_datalake.rs @@ -17,7 +17,7 @@ pub struct RunDatalakeArgs { pub aggregate_fn_id: AggregationFunction, /// Optional context for applying conditions on the aggregate function "count". /// Format: "{operator}.{value}" (e.g., "eq.100" for equality, "gt.100" for greater-than). - /// Supported operators are in the [`Operator`] enum. + /// Supported operators are in the Operator enum. pub aggregate_fn_ctx: Option, #[command(subcommand)] diff --git a/hdp/src/lib.rs b/hdp/src/lib.rs index 0c64bec9..ac51f953 100644 --- a/hdp/src/lib.rs +++ b/hdp/src/lib.rs @@ -1,3 +1,8 @@ +//! The Data Processor CLI serves as an essential tool for developers working with Cairo programs and zkVM environments. +//! Its primary function is to translate human-readable requests into a format compatible with Cairo programs, +//! enabling commands to be executed over the Cairo VM and generating executable outputs. +//! This transformation is a crucial preprocessing step that prepares data for off-chain computations in zkVM environments. + pub mod cairo_runner; pub mod constant; pub mod hdp_run; diff --git a/hdp/src/primitives/block/header.rs b/hdp/src/primitives/block/header.rs index 02555db6..72b875b6 100644 --- a/hdp/src/primitives/block/header.rs +++ b/hdp/src/primitives/block/header.rs @@ -131,7 +131,6 @@ impl Header { } /// Heavy function that will calculate hash of data and will *not* save the change to metadata. - /// Use [`Header::seal`], [`SealedHeader`] and unlock if you need hash to be persistent. pub fn hash_slow(&self) -> B256 { keccak256(alloy_rlp::encode(self)) } @@ -343,7 +342,7 @@ impl Header { } /// Block header returned from RPC -/// https://ethereum.org/en/developers/docs/apis/json-rpc#eth_getblockbynumber +/// #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct BlockHeaderFromRpc { diff --git a/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs b/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs index a9eb0482..408ad867 100644 --- a/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs +++ b/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs @@ -49,13 +49,13 @@ impl DatalakeCodecs for TransactionsInBlockDatalake { } } - /// Get the commitment hash of the [`TransactionsDatalake`] + /// Get the commitment hash of the [`TransactionsInBlockDatalake`] fn commit(&self) -> B256 { let encoded_datalake = self.encode().expect("Encoding failed"); keccak256(encoded_datalake) } - /// Decode the encoded transactions datalake hex string into a [`TransactionsDatalake`] + /// Decode the encoded transactions datalake hex string into a [`TransactionsInBlockDatalake`] fn decode(encoded: &[u8]) -> Result { let abi_type: DynSolType = "(uint256,uint256, uint256, uint256, uint256, uint256, uint256, bytes)".parse()?; diff --git a/hdp/src/primitives/solidity_types/traits.rs b/hdp/src/primitives/solidity_types/traits.rs index 7aa92f93..176cece3 100644 --- a/hdp/src/primitives/solidity_types/traits.rs +++ b/hdp/src/primitives/solidity_types/traits.rs @@ -22,7 +22,7 @@ pub trait Codecs { Self: Sized; } -/// Codecs for [`DatalakeCompute`] +/// Codecs for datalake task pub trait DatalakeComputeCodecs { fn decode(encoded_datalake: &[u8], encoded_compute: &[u8]) -> Result where @@ -31,7 +31,7 @@ pub trait DatalakeComputeCodecs { fn commit(&self) -> B256; } -/// Codecs for [`BatchedDatalakeCompute`] +/// Codecs for vector of datalake task pub trait BatchedDatalakeComputeCodecs { fn decode(encoded_datalake: &[u8], encoded_compute: &[u8]) -> Result where diff --git a/hdp/src/primitives/task/datalake/datalake_type.rs b/hdp/src/primitives/task/datalake/datalake_type.rs index aa16dfd4..1cd1177e 100644 --- a/hdp/src/primitives/task/datalake/datalake_type.rs +++ b/hdp/src/primitives/task/datalake/datalake_type.rs @@ -2,10 +2,10 @@ use anyhow::{bail, Result}; use serde::{Deserialize, Serialize}; use std::str::FromStr; -/// Identifier for a [`BlockSampledDatalake`] type. +/// Identifier for a BlockSampledDatalake pub const BLOCK_SAMPLED_DATALAKE_TYPE_ID: u8 = 0; -/// Identifier for an [`TransactionsDatalake`] type. +/// Identifier for a TransactionsDatalake pub const TRANSACTIONS_IN_BLOCK_DATALAKE_TYPE_ID: u8 = 1; #[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq)] diff --git a/hdp/src/provider/error.rs b/hdp/src/provider/error.rs index 23678940..d35f84d6 100644 --- a/hdp/src/provider/error.rs +++ b/hdp/src/provider/error.rs @@ -18,11 +18,11 @@ pub enum ProviderError { #[error("MMR not found")] MmrNotFound, - /// Error from the [`Indexer`] + /// Error from the [`IndexerError`] #[error("Failed from indexer")] IndexerError(#[from] IndexerError), - /// Error from [`RpcProvider`] + /// Error from [`RpcProviderError`] #[error("Failed to get proofs: {0}")] EvmRpcProviderError(#[from] RpcProviderError), @@ -34,7 +34,7 @@ pub enum ProviderError { FetchKeyError(String), } -/// Error from [`RpcProvider`] +/// Error from rpc #[derive(Error, Debug)] pub enum RpcProviderError { #[error("Failed to send proofs with mpsc")] diff --git a/hdp/src/provider/indexer.rs b/hdp/src/provider/indexer.rs index 42684725..09519a68 100644 --- a/hdp/src/provider/indexer.rs +++ b/hdp/src/provider/indexer.rs @@ -53,7 +53,7 @@ impl ChainId { /// Indexer client for fetching MMR and headers proof from Herodotus Indexer /// -/// For more information, see: https://rs-indexer.api.herodotus.cloud/swagger +/// For more information, see: /// /// How to use: /// ```rust diff --git a/hdp/src/provider/starknet/types.rs b/hdp/src/provider/starknet/types.rs index 33180733..a827823b 100644 --- a/hdp/src/provider/starknet/types.rs +++ b/hdp/src/provider/starknet/types.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use starknet_types_core::{felt::Felt, hash::StarkHash}; -/// Codebase is from https://github.com/eqlabs/pathfinder/tree/ae81d84b7c4157891069bd02ef810a29b60a94e3 +/// Codebase is from /// Holds the membership/non-membership of a contract and its associated /// contract contract if the contract exists. diff --git a/justfile b/justfile index b698c87f..c1730a61 100644 --- a/justfile +++ b/justfile @@ -13,10 +13,14 @@ clean: clippy: cargo clippy --all-targets --all-features -- -Dwarnings +# Generate documentation for the project +docs: + cargo doc --no-deps + # Execute all unit tests in the workspace test: cargo llvm-cov nextest --features test_utils -# Run the entire CI pipeline including format, clippy, and test checks -run-ci-flow: format clippy test +# Run the entire CI pipeline including format, clippy, docs, and test checks +run-ci-flow: format clippy docs test @echo "CI flow completed"