diff --git a/Cargo.toml b/Cargo.toml index a9e94f46..0e7d0cbc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -146,4 +146,16 @@ codegen-units = 1 warnings = "deny" [workspace.lints] -clippy.all = "deny" +clippy.all = { level = "deny", priority = -1 } +clippy.pedantic = { level = "deny", priority = -1 } + +# Reason: documenting every function returning Result is too verbose and doesn't add much value when you have good error types. +clippy.missing-errors-doc = "allow" +# Reason: most of the panics are internal and not part of the public API, so documenting them is not necessary. +clippy.missing-panics-doc = "allow" +# Reason: this isn't always bad and actually works well for our financial and cryptography code. +clippy.similar-names = "allow" +# Reason: this lint is too strict and hard to fix. +clippy.too-many-lines = "allow" +# Reason: std hasher is fine for us in public functions +clippy.implicit-hasher = "allow" diff --git a/bedrock_client/src/lib.rs b/bedrock_client/src/lib.rs index 534a0cf6..227cc47a 100644 --- a/bedrock_client/src/lib.rs +++ b/bedrock_client/src/lib.rs @@ -96,9 +96,14 @@ impl BedrockClient { } fn backoff_strategy(&self) -> impl Iterator { - tokio_retry::strategy::FibonacciBackoff::from_millis( - self.backoff.start_delay.as_millis() as u64 - ) - .take(self.backoff.max_retries) + let start_delay_millis = self + .backoff + .start_delay + .as_millis() + .try_into() + .expect("Start delay must be less than u64::MAX milliseconds"); + + tokio_retry::strategy::FibonacciBackoff::from_millis(start_delay_millis) + .take(self.backoff.max_retries) } } diff --git a/common/src/block.rs b/common/src/block.rs index 0343435b..e5a58aed 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -69,6 +69,7 @@ pub struct HashableBlockData { } impl HashableBlockData { + #[must_use] pub fn into_pending_block( self, signing_key: &nssa::PrivateKey, @@ -93,6 +94,7 @@ impl HashableBlockData { } } + #[must_use] pub fn block_hash(&self) -> BlockHash { OwnHasher::hash(&borsh::to_vec(&self).unwrap()) } diff --git a/common/src/config.rs b/common/src/config.rs index 3850f08c..537c35bd 100644 --- a/common/src/config.rs +++ b/common/src/config.rs @@ -43,7 +43,7 @@ impl FromStr for BasicAuth { Ok(Self { username: username.to_string(), - password: password.map(|p| p.to_string()), + password: password.map(std::string::ToString::to_string), }) } } diff --git a/common/src/rpc_primitives/errors.rs b/common/src/rpc_primitives/errors.rs index 1f799815..1c376a53 100644 --- a/common/src/rpc_primitives/errors.rs +++ b/common/src/rpc_primitives/errors.rs @@ -49,6 +49,7 @@ impl RpcError { /// A generic constructor. /// /// Mostly for completeness, doesn't do anything but filling in the corresponding fields. + #[must_use] pub fn new(code: i64, message: String, data: Option) -> Self { RpcError { code, @@ -82,6 +83,7 @@ impl RpcError { } /// Create a parse error. + #[must_use] pub fn parse_error(e: String) -> Self { RpcError { code: -32_700, @@ -93,12 +95,14 @@ impl RpcError { } } + #[must_use] pub fn serialization_error(e: &str) -> Self { RpcError::new_internal_error(Some(Value::String(e.to_owned())), e) } /// Helper method to define extract `INTERNAL_ERROR` in separate `RpcErrorKind` /// Returns `HANDLER_ERROR` if the error is not internal one + #[must_use] pub fn new_internal_or_handler_error(error_data: Option, error_struct: Value) -> Self { if error_struct["name"] == "INTERNAL_ERROR" { let error_message = match error_struct["info"].get("error_message") { @@ -111,6 +115,7 @@ impl RpcError { } } + #[must_use] pub fn new_internal_error(error_data: Option, info: &str) -> Self { RpcError { code: -32_000, @@ -133,6 +138,7 @@ impl RpcError { } /// Create a method not found error. + #[must_use] pub fn method_not_found(method: String) -> Self { RpcError { code: -32_601, diff --git a/common/src/rpc_primitives/message.rs b/common/src/rpc_primitives/message.rs index 98867448..5092dbc9 100644 --- a/common/src/rpc_primitives/message.rs +++ b/common/src/rpc_primitives/message.rs @@ -32,7 +32,7 @@ impl<'de> serde::Deserialize<'de> for Version { fn deserialize>(deserializer: D) -> Result { struct VersionVisitor; #[allow(clippy::needless_lifetimes)] - impl<'de> Visitor<'de> for VersionVisitor { + impl Visitor<'_> for VersionVisitor { type Value = Version; fn expecting(&self, formatter: &mut Formatter<'_>) -> FmtResult { @@ -62,6 +62,7 @@ pub struct Request { } impl Request { + #[must_use] pub fn from_payload_version_2_0(method: String, payload: serde_json::Value) -> Self { Self { jsonrpc: Version, @@ -75,6 +76,7 @@ impl Request { /// Answer the request with a (positive) reply. /// /// The ID is taken from the request. + #[must_use] pub fn reply(&self, reply: Value) -> Message { Message::Response(Response { jsonrpc: Version, @@ -84,6 +86,7 @@ impl Request { } /// Answer the request with an error. + #[must_use] pub fn error(&self, error: RpcError) -> Message { Message::Response(Response { jsonrpc: Version, @@ -212,6 +215,7 @@ impl Message { /// A constructor for a request. /// /// The ID is auto-set to dontcare. + #[must_use] pub fn request(method: String, params: Value) -> Self { let id = Value::from("dontcare"); Message::Request(Request { @@ -223,6 +227,7 @@ impl Message { } /// Create a top-level error (without an ID). + #[must_use] pub fn error(error: RpcError) -> Self { Message::Response(Response { jsonrpc: Version, @@ -232,6 +237,7 @@ impl Message { } /// A constructor for a notification. + #[must_use] pub fn notification(method: String, params: Value) -> Self { Message::Notification(Notification { jsonrpc: Version, @@ -241,6 +247,7 @@ impl Message { } /// A constructor for a response. + #[must_use] pub fn response(id: Value, result: Result) -> Self { Message::Response(Response { jsonrpc: Version, @@ -250,6 +257,7 @@ impl Message { } /// Returns id or Null if there is no id. + #[must_use] pub fn id(&self) -> Value { match self { Message::Request(req) => req.id.clone(), @@ -276,6 +284,7 @@ impl Broken { /// /// The error message for these things are specified in the RFC, so this just creates an error /// with the right values. + #[must_use] pub fn reply(&self) -> Message { match *self { Broken::Unmatched(_) => Message::error(RpcError::parse_error( @@ -343,7 +352,6 @@ mod tests { /// But since serialization doesn't have to produce the exact same result (order, spaces, …), /// we then serialize and deserialize the thing again and check it matches. #[test] - #[allow(clippy::too_many_lines)] fn message_serde() { // A helper for running one message test fn one(input: &str, expected: &Message) { @@ -491,10 +499,10 @@ mod tests { // Something completely different one(r#"{"x": [1, 2, 3]}"#); - match from_str(r#"{]"#) { + match from_str(r"{]") { Err(Broken::SyntaxError(_)) => (), other => panic!("Something unexpected: {other:?}"), - }; + } } /// Test some non-trivial aspects of the constructors @@ -503,7 +511,7 @@ mod tests { /// Most of it is related to the ids. #[test] #[allow(clippy::panic)] - #[ignore] + #[ignore = "Not a full coverage test"] fn constructors() { let msg1 = Message::request("call".to_owned(), json!([1, 2, 3])); let msg2 = Message::request("call".to_owned(), json!([1, 2, 3])); diff --git a/common/src/rpc_primitives/mod.rs b/common/src/rpc_primitives/mod.rs index be5182e1..5cc74995 100644 --- a/common/src/rpc_primitives/mod.rs +++ b/common/src/rpc_primitives/mod.rs @@ -39,6 +39,7 @@ impl Default for RpcConfig { } impl RpcConfig { + #[must_use] pub fn new(addr: &str) -> Self { RpcConfig { addr: addr.to_owned(), @@ -46,6 +47,7 @@ impl RpcConfig { } } + #[must_use] pub fn with_port(port: u16) -> Self { RpcConfig { addr: format!("0.0.0.0:{port}"), diff --git a/common/src/sequencer_client.rs b/common/src/sequencer_client.rs index f847b865..dc6c8ca7 100644 --- a/common/src/sequencer_client.rs +++ b/common/src/sequencer_client.rs @@ -30,6 +30,14 @@ use crate::{ transaction::NSSATransaction, }; +#[derive(Debug, Clone, Deserialize)] +#[allow(dead_code)] +struct SequencerRpcResponse { + jsonrpc: String, + result: serde_json::Value, + id: u64, +} + #[derive(Clone)] pub struct SequencerClient { pub client: reqwest::Client, @@ -86,14 +94,6 @@ impl SequencerClient { }) .await?; - #[derive(Debug, Clone, Deserialize)] - #[allow(dead_code)] - pub struct SequencerRpcResponse { - pub jsonrpc: String, - pub result: serde_json::Value, - pub id: u64, - } - if let Ok(response) = serde_json::from_value::(response_vall.clone()) { Ok(response.result) diff --git a/common/src/test_utils.rs b/common/src/test_utils.rs index 09651c18..1d166ade 100644 --- a/common/src/test_utils.rs +++ b/common/src/test_utils.rs @@ -8,6 +8,7 @@ use crate::{ // Helpers +#[must_use] pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey { nssa::PrivateKey::try_new([37; 32]).unwrap() } @@ -21,6 +22,7 @@ pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey { /// `prev_hash` - hash of previous block, provide None for genesis /// /// `transactions` - vector of `EncodedTransaction` objects +#[must_use] pub fn produce_dummy_block( id: u64, prev_hash: Option, @@ -36,6 +38,7 @@ pub fn produce_dummy_block( block_data.into_pending_block(&sequencer_sign_key_for_testing(), [0; 32]) } +#[must_use] pub fn produce_dummy_empty_transaction() -> NSSATransaction { let program_id = nssa::program::Program::authenticated_transfer_program().id(); let account_ids = vec![]; @@ -56,12 +59,13 @@ pub fn produce_dummy_empty_transaction() -> NSSATransaction { NSSATransaction::Public(nssa_tx) } +#[must_use] pub fn create_transaction_native_token_transfer( from: AccountId, nonce: u128, to: AccountId, balance_to_move: u128, - signing_key: nssa::PrivateKey, + signing_key: &nssa::PrivateKey, ) -> NSSATransaction { let account_ids = vec![from, to]; let nonces = vec![nonce]; @@ -73,7 +77,7 @@ pub fn create_transaction_native_token_transfer( balance_to_move, ) .unwrap(); - let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]); + let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); let nssa_tx = nssa::PublicTransaction::new(message, witness_set); diff --git a/common/src/transaction.rs b/common/src/transaction.rs index a996250b..74a41ca2 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -13,6 +13,7 @@ pub enum NSSATransaction { } impl NSSATransaction { + #[must_use] pub fn hash(&self) -> HashType { HashType(match self { NSSATransaction::Public(tx) => tx.hash(), @@ -21,6 +22,7 @@ impl NSSATransaction { }) } + #[must_use] pub fn affected_public_account_ids(&self) -> Vec { match self { NSSATransaction::ProgramDeployment(tx) => tx.affected_public_account_ids(), diff --git a/examples/program_deployment/methods/guest/src/bin/hello_world_with_authorization.rs b/examples/program_deployment/methods/guest/src/bin/hello_world_with_authorization.rs index 043da1bf..e327ca47 100644 --- a/examples/program_deployment/methods/guest/src/bin/hello_world_with_authorization.rs +++ b/examples/program_deployment/methods/guest/src/bin/hello_world_with_authorization.rs @@ -36,9 +36,7 @@ fn main() { // Fail if the input account is not authorized // The `is_authorized` field will be correctly populated or verified by the system if // authorization is provided. - if !pre_state.is_authorized { - panic!("Missing required authorization"); - } + assert!(pre_state.is_authorized, "Missing required authorization"); // #### // Construct the post state account values diff --git a/examples/program_deployment/methods/guest/src/bin/hello_world_with_move_function.rs b/examples/program_deployment/methods/guest/src/bin/hello_world_with_move_function.rs index af0d4bf4..e278a732 100644 --- a/examples/program_deployment/methods/guest/src/bin/hello_world_with_move_function.rs +++ b/examples/program_deployment/methods/guest/src/bin/hello_world_with_move_function.rs @@ -1,5 +1,5 @@ use nssa_core::{ - account::{Account, AccountWithMetadata}, + account::{Account, AccountWithMetadata, Data}, program::{ AccountPostState, DEFAULT_PROGRAM_ID, ProgramInput, read_nssa_inputs, write_nssa_outputs, }, @@ -35,12 +35,12 @@ fn build_post_state(post_account: Account) -> AccountPostState { } } -fn write(pre_state: AccountWithMetadata, greeting: Vec) -> AccountPostState { +fn write(pre_state: AccountWithMetadata, greeting: &[u8]) -> AccountPostState { // Construct the post state account values let post_account = { - let mut this = pre_state.account.clone(); + let mut this = pre_state.account; let mut bytes = this.data.into_inner(); - bytes.extend_from_slice(&greeting); + bytes.extend_from_slice(greeting); this.data = bytes .try_into() .expect("Data should fit within the allowed limits"); @@ -50,21 +50,18 @@ fn write(pre_state: AccountWithMetadata, greeting: Vec) -> AccountPostState build_post_state(post_account) } -fn move_data( - from_pre: &AccountWithMetadata, - to_pre: &AccountWithMetadata, -) -> Vec { +fn move_data(from_pre: AccountWithMetadata, to_pre: AccountWithMetadata) -> Vec { // Construct the post state account values let from_data: Vec = from_pre.account.data.clone().into(); let from_post = { - let mut this = from_pre.account.clone(); - this.data = Default::default(); + let mut this = from_pre.account; + this.data = Data::default(); build_post_state(this) }; let to_post = { - let mut this = to_pre.account.clone(); + let mut this = to_pre.account; let mut bytes = this.data.into_inner(); bytes.extend_from_slice(&from_data); this.data = bytes @@ -88,11 +85,11 @@ fn main() { let post_states = match (pre_states.as_slice(), function_id, data.len()) { ([account_pre], WRITE_FUNCTION_ID, _) => { - let post = write(account_pre.clone(), data); + let post = write(account_pre.clone(), &data); vec![post] } ([account_from_pre, account_to_pre], MOVE_DATA_FUNCTION_ID, 0) => { - move_data(account_from_pre, account_to_pre) + move_data(account_from_pre.clone(), account_to_pre.clone()) } _ => panic!("invalid params"), }; diff --git a/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs b/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs index e933598f..01389085 100644 --- a/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs +++ b/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs @@ -29,7 +29,7 @@ fn main() { let ( ProgramInput { pre_states, - instruction: _, + instruction: (), }, instruction_data, ) = read_nssa_inputs::<()>(); diff --git a/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs b/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs index 684fa1e8..679df3bf 100644 --- a/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs +++ b/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs @@ -34,7 +34,7 @@ fn main() { let ( ProgramInput { pre_states, - instruction: _, + instruction: (), }, instruction_data, ) = read_nssa_inputs::<()>(); diff --git a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs index fc116241..85bd19c6 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs @@ -148,5 +148,5 @@ async fn main() { .await .unwrap(); } - }; + } } diff --git a/explorer_service/src/api.rs b/explorer_service/src/api.rs index 1e2bdd5b..6cec377c 100644 --- a/explorer_service/src/api.rs +++ b/explorer_service/src/api.rs @@ -22,7 +22,7 @@ pub async fn get_account(account_id: AccountId) -> Result Result client .get_block_by_id(block_id) .await - .map_err(|e| ServerFnError::ServerError(format!("RPC error: {}", e))) + .map_err(|e| ServerFnError::ServerError(format!("RPC error: {e}"))) } /// Get latest block ID @@ -91,7 +91,7 @@ pub async fn get_latest_block_id() -> Result { client .get_last_finalized_block_id() .await - .map_err(|e| ServerFnError::ServerError(format!("RPC error: {}", e))) + .map_err(|e| ServerFnError::ServerError(format!("RPC error: {e}"))) } /// Get block by hash @@ -102,7 +102,7 @@ pub async fn get_block_by_hash(block_hash: HashType) -> Result Result, limit: u32) -> Result, ServerFnError> { +pub async fn get_blocks(before: Option, limit: u64) -> Result, ServerFnError> { use indexer_service_rpc::RpcClient as _; let client = expect_context::(); client .get_blocks(before, limit) .await - .map_err(|e| ServerFnError::ServerError(format!("RPC error: {}", e))) + .map_err(|e| ServerFnError::ServerError(format!("RPC error: {e}"))) } /// Get transactions by account #[server] pub async fn get_transactions_by_account( account_id: AccountId, - limit: u32, - offset: u32, + offset: u64, + limit: u64, ) -> Result, ServerFnError> { use indexer_service_rpc::RpcClient as _; let client = expect_context::(); client - .get_transactions_by_account(account_id, limit, offset) + .get_transactions_by_account(account_id, offset, limit) .await - .map_err(|e| ServerFnError::ServerError(format!("RPC error: {}", e))) + .map_err(|e| ServerFnError::ServerError(format!("RPC error: {e}"))) } /// Create the RPC client for the indexer service (server-side only) diff --git a/explorer_service/src/components/transaction_preview.rs b/explorer_service/src/components/transaction_preview.rs index 68c1e86e..f4ff2bb4 100644 --- a/explorer_service/src/components/transaction_preview.rs +++ b/explorer_service/src/components/transaction_preview.rs @@ -13,6 +13,10 @@ fn transaction_type_info(tx: &Transaction) -> (&'static str, &'static str) { /// Transaction preview component #[component] +#[expect( + clippy::needless_pass_by_value, + reason = "Leptos component props are passed by value by framework convention" +)] pub fn TransactionPreview(transaction: Transaction) -> impl IntoView { let hash = transaction.hash(); let hash_str = hash.to_string(); diff --git a/explorer_service/src/format_utils.rs b/explorer_service/src/format_utils.rs index 20c1824c..07d7e8ec 100644 --- a/explorer_service/src/format_utils.rs +++ b/explorer_service/src/format_utils.rs @@ -3,7 +3,10 @@ /// Format timestamp to human-readable string pub fn format_timestamp(timestamp: u64) -> String { let seconds = timestamp / 1000; - let datetime = chrono::DateTime::from_timestamp(seconds as i64, 0) - .unwrap_or_else(|| chrono::DateTime::from_timestamp(0, 0).unwrap()); + let datetime = chrono::DateTime::from_timestamp( + i64::try_from(seconds).expect("Timestamp out of range"), + 0, + ) + .unwrap_or_else(|| chrono::DateTime::from_timestamp(0, 0).unwrap()); datetime.format("%Y-%m-%d %H:%M:%S UTC").to_string() } diff --git a/explorer_service/src/lib.rs b/explorer_service/src/lib.rs index e2b2291e..fadc164b 100644 --- a/explorer_service/src/lib.rs +++ b/explorer_service/src/lib.rs @@ -1,3 +1,8 @@ +#![expect( + clippy::must_use_candidate, + reason = "Warns on code generated by leptos macros" +)] + use leptos::prelude::*; use leptos_meta::{Meta, Stylesheet, Title, provide_meta_context}; use leptos_router::{ diff --git a/explorer_service/src/main.rs b/explorer_service/src/main.rs index 6cc4a9a4..357219ef 100644 --- a/explorer_service/src/main.rs +++ b/explorer_service/src/main.rs @@ -8,8 +8,6 @@ async fn main() { use leptos_axum::{LeptosRoutes, generate_route_list}; use leptos_meta::MetaTags; - env_logger::init(); - /// LEZ Block Explorer Server CLI arguments. #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -19,6 +17,8 @@ async fn main() { indexer_rpc_url: url::Url, } + env_logger::init(); + let args = Args::parse(); let conf = get_configuration(None).unwrap(); diff --git a/explorer_service/src/pages/account_page.rs b/explorer_service/src/pages/account_page.rs index 4c0af1ac..5f95d8e0 100644 --- a/explorer_service/src/pages/account_page.rs +++ b/explorer_service/src/pages/account_page.rs @@ -10,11 +10,11 @@ use crate::{api, components::TransactionPreview}; #[component] pub fn AccountPage() -> impl IntoView { let params = use_params_map(); - let (tx_offset, set_tx_offset) = signal(0u32); + let (tx_offset, set_tx_offset) = signal(0u64); let (all_transactions, set_all_transactions) = signal(Vec::new()); let (is_loading, set_is_loading) = signal(false); let (has_more, set_has_more) = signal(true); - let tx_limit = 10u32; + let tx_limit = 10u64; // Parse account ID from URL params let account_id = move || { @@ -35,7 +35,7 @@ pub fn AccountPage() -> impl IntoView { // Load initial transactions let transactions_resource = Resource::new(account_id, move |acc_id_opt| async move { match acc_id_opt { - Some(acc_id) => api::get_transactions_by_account(acc_id, tx_limit, 0).await, + Some(acc_id) => api::get_transactions_by_account(acc_id, 0, tx_limit).await, None => Err(leptos::prelude::ServerFnError::ServerError( "Invalid account ID".to_string(), )), @@ -46,7 +46,9 @@ pub fn AccountPage() -> impl IntoView { Effect::new(move || { if let Some(Ok(txs)) = transactions_resource.get() { set_all_transactions.set(txs.clone()); - set_has_more.set(txs.len() as u32 == tx_limit); + set_has_more.set( + u64::try_from(txs.len()).expect("Transaction count should fit in u64") == tx_limit, + ); } }); @@ -61,14 +63,15 @@ pub fn AccountPage() -> impl IntoView { set_tx_offset.set(current_offset); leptos::task::spawn_local(async move { - match api::get_transactions_by_account(acc_id, tx_limit, current_offset).await { + match api::get_transactions_by_account(acc_id, current_offset, tx_limit).await { Ok(new_txs) => { - let txs_count = new_txs.len() as u32; + let txs_count = + u64::try_from(new_txs.len()).expect("Transaction count should fit in u64"); set_all_transactions.update(|txs| txs.extend(new_txs)); set_has_more.set(txs_count == tx_limit); } Err(e) => { - log::error!("Failed to load more transactions: {}", e); + log::error!("Failed to load more transactions: {e}"); } } set_is_loading.set(false); @@ -123,7 +126,7 @@ pub fn AccountPage() -> impl IntoView {
"Data:" - {format!("{} bytes", data_len)} + {format!("{data_len} bytes")}
@@ -190,7 +193,7 @@ pub fn AccountPage() -> impl IntoView { Err(e) => { view! {
- {format!("Failed to load transactions: {}", e)} + {format!("Failed to load transactions: {e}")}
} .into_any() @@ -208,7 +211,7 @@ pub fn AccountPage() -> impl IntoView { view! {

"Error"

-

{format!("Failed to load account: {}", e)}

+

{format!("Failed to load account: {e}")}

} .into_any() diff --git a/explorer_service/src/pages/block_page.rs b/explorer_service/src/pages/block_page.rs index aee0a7cf..d63d9f8e 100644 --- a/explorer_service/src/pages/block_page.rs +++ b/explorer_service/src/pages/block_page.rs @@ -144,7 +144,7 @@ pub fn BlockPage() -> impl IntoView { view! {

"Error"

-

{format!("Failed to load block: {}", e)}

+

{format!("Failed to load block: {e}")}

} .into_any() diff --git a/explorer_service/src/pages/main_page.rs b/explorer_service/src/pages/main_page.rs index 28d1d1d9..7e26e794 100644 --- a/explorer_service/src/pages/main_page.rs +++ b/explorer_service/src/pages/main_page.rs @@ -1,5 +1,8 @@ use leptos::prelude::*; -use leptos_router::hooks::{use_navigate, use_query_map}; +use leptos_router::{ + NavigateOptions, + hooks::{use_navigate, use_query_map}, +}; use web_sys::SubmitEvent; use crate::{ @@ -7,7 +10,7 @@ use crate::{ components::{AccountPreview, BlockPreview, TransactionPreview}, }; -const RECENT_BLOCKS_LIMIT: u32 = 10; +const RECENT_BLOCKS_LIMIT: u64 = 10; /// Main page component #[component] @@ -33,7 +36,7 @@ pub fn MainPage() -> impl IntoView { match api::search(query).await { Ok(result) => Some(result), Err(e) => { - log::error!("Search error: {}", e); + log::error!("Search error: {e}"); None } } @@ -48,7 +51,7 @@ pub fn MainPage() -> impl IntoView { // Load recent blocks on mount let recent_blocks_resource = Resource::new( || (), - |_| async { api::get_blocks(None, RECENT_BLOCKS_LIMIT).await }, + |()| async { api::get_blocks(None, RECENT_BLOCKS_LIMIT).await }, ); // Update all_blocks when initial load completes @@ -57,8 +60,11 @@ pub fn MainPage() -> impl IntoView { let oldest_id = blocks.last().map(|b| b.header.block_id); set_all_blocks.set(blocks.clone()); set_oldest_loaded_block_id.set(oldest_id); - set_has_more_blocks - .set(blocks.len() as u32 == RECENT_BLOCKS_LIMIT && oldest_id.unwrap_or(0) > 1); + set_has_more_blocks.set( + u64::try_from(blocks.len()).expect("usize should fit in u64") + == RECENT_BLOCKS_LIMIT + && oldest_id.unwrap_or(0) > 1, + ); } }); @@ -75,7 +81,8 @@ pub fn MainPage() -> impl IntoView { leptos::task::spawn_local(async move { match api::get_blocks(before_id, RECENT_BLOCKS_LIMIT).await { Ok(new_blocks) => { - let blocks_count = new_blocks.len() as u32; + let blocks_count = + u64::try_from(new_blocks.len()).expect("usize should fit in u64"); let new_oldest_id = new_blocks.last().map(|b| b.header.block_id); set_all_blocks.update(|blocks| blocks.extend(new_blocks)); set_oldest_loaded_block_id.set(new_oldest_id); @@ -83,7 +90,7 @@ pub fn MainPage() -> impl IntoView { .set(blocks_count == RECENT_BLOCKS_LIMIT && new_oldest_id.unwrap_or(0) > 1); } Err(e) => { - log::error!("Failed to load more blocks: {}", e); + log::error!("Failed to load more blocks: {e}"); } } set_is_loading_blocks.set(false); @@ -95,13 +102,13 @@ pub fn MainPage() -> impl IntoView { ev.prevent_default(); let query = search_query.get(); if query.is_empty() { - navigate("?", Default::default()); + navigate("?", NavigateOptions::default()); return; } navigate( &format!("?q={}", urlencoding::encode(&query)), - Default::default(), + NavigateOptions::default(), ); }; @@ -142,78 +149,78 @@ pub fn MainPage() -> impl IntoView { view! {

"Search Results"

- {if !has_results { - view! {
"No results found"
} - .into_any() - } else { - view! { -
- {if !blocks.is_empty() { - view! { -
-

"Blocks"

-
- {blocks - .into_iter() - .map(|block| { - view! { } - }) - .collect::>()} + {if has_results { + view! { +
+ {if blocks.is_empty() { + ().into_any() + } else { + view! { +
+

"Blocks"

+
+ {blocks + .into_iter() + .map(|block| { + view! { } + }) + .collect::>()} +
-
- } - .into_any() - } else { - ().into_any() - }} + } + .into_any() + }} - {if !transactions.is_empty() { - view! { -
-

"Transactions"

-
- {transactions - .into_iter() - .map(|tx| { - view! { } - }) - .collect::>()} + {if transactions.is_empty() { + ().into_any() + } else { + view! { +
+

"Transactions"

+
+ {transactions + .into_iter() + .map(|tx| { + view! { } + }) + .collect::>()} +
-
- } - .into_any() - } else { - ().into_any() - }} + } + .into_any() + }} - {if !accounts.is_empty() { - view! { -
-

"Accounts"

-
- {accounts - .into_iter() - .map(|(id, account)| { - view! { - - } - }) - .collect::>()} + {if accounts.is_empty() { + ().into_any() + } else { + view! { +
+

"Accounts"

+
+ {accounts + .into_iter() + .map(|(id, account)| { + view! { + + } + }) + .collect::>()} +
-
- } - .into_any() - } else { - ().into_any() - }} + } + .into_any() + }} -
- } - .into_any() - }} +
+ } + .into_any() + } else { + view! {
"No results found"
} + .into_any() + }}
} .into_any() @@ -274,7 +281,7 @@ pub fn MainPage() -> impl IntoView { } } Err(e) => { - view! {
{format!("Error: {}", e)}
} + view! {
{format!("Error: {e}")}
} .into_any() } }) diff --git a/explorer_service/src/pages/transaction_page.rs b/explorer_service/src/pages/transaction_page.rs index 2859719f..266f3f80 100644 --- a/explorer_service/src/pages/transaction_page.rs +++ b/explorer_service/src/pages/transaction_page.rs @@ -105,7 +105,7 @@ pub fn TransactionPage() -> impl IntoView {
"Proof Size:" - {format!("{} bytes", proof_len)} + {format!("{proof_len} bytes")}
"Signatures:" @@ -212,7 +212,7 @@ pub fn TransactionPage() -> impl IntoView {
"Proof Size:" - {format!("{} bytes", proof_len)} + {format!("{proof_len} bytes")}
@@ -284,7 +284,7 @@ pub fn TransactionPage() -> impl IntoView {
"Bytecode Size:" - {format!("{} bytes", bytecode_len)} + {format!("{bytecode_len} bytes")}
@@ -302,7 +302,7 @@ pub fn TransactionPage() -> impl IntoView { view! {

"Error"

-

{format!("Failed to load transaction: {}", e)}

+

{format!("Failed to load transaction: {e}")}

} .into_any() diff --git a/indexer/core/src/block_store.rs b/indexer/core/src/block_store.rs index 681b63c8..f2fb2ce9 100644 --- a/indexer/core/src/block_store.rs +++ b/indexer/core/src/block_store.rs @@ -3,7 +3,7 @@ use std::{path::Path, sync::Arc}; use anyhow::Result; use bedrock_client::HeaderId; use common::{ - block::{BedrockStatus, Block}, + block::{BedrockStatus, Block, BlockId}, transaction::NSSATransaction, }; use nssa::{Account, AccountId, V02State}; @@ -50,7 +50,7 @@ impl IndexerStore { Ok(self.dbio.get_block(id)?) } - pub fn get_block_batch(&self, before: Option, limit: u64) -> Result> { + pub fn get_block_batch(&self, before: Option, limit: u64) -> Result> { Ok(self.dbio.get_block_batch(before, limit)?) } @@ -79,12 +79,14 @@ impl IndexerStore { Ok(self.dbio.get_acc_transactions(acc_id, offset, limit)?) } + #[must_use] pub fn genesis_id(&self) -> u64 { self.dbio .get_meta_first_block_in_db() .expect("Must be set at the DB startup") } + #[must_use] pub fn last_block(&self) -> u64 { self.dbio .get_meta_last_block_in_db() diff --git a/indexer/core/src/config.rs b/indexer/core/src/config.rs index 95e6147c..326a79a3 100644 --- a/indexer/core/src/config.rs +++ b/indexer/core/src/config.rs @@ -43,11 +43,16 @@ pub struct IndexerConfig { impl IndexerConfig { pub fn from_path(config_path: &Path) -> Result { - let file = File::open(config_path) - .with_context(|| format!("Failed to open indexer config at {config_path:?}"))?; + let file = File::open(config_path).with_context(|| { + format!("Failed to open indexer config at {}", config_path.display()) + })?; let reader = BufReader::new(file); - serde_json::from_reader(reader) - .with_context(|| format!("Failed to parse indexer config at {config_path:?}")) + serde_json::from_reader(reader).with_context(|| { + format!( + "Failed to parse indexer config at {}", + config_path.display() + ) + }) } } diff --git a/indexer/core/src/lib.rs b/indexer/core/src/lib.rs index 6d56eb18..38fb5989 100644 --- a/indexer/core/src/lib.rs +++ b/indexer/core/src/lib.rs @@ -98,43 +98,40 @@ impl IndexerCore { }) } - pub async fn subscribe_parse_block_stream(&self) -> impl futures::Stream> { + pub fn subscribe_parse_block_stream(&self) -> impl futures::Stream> { async_stream::stream! { info!("Searching for initial header"); let last_l1_lib_header = self.store.last_observed_l1_lib_header()?; - let mut prev_last_l1_lib_header = match last_l1_lib_header { - Some(last_l1_lib_header) => { - info!("Last l1 lib header found: {last_l1_lib_header}"); - last_l1_lib_header - }, - None => { - info!("Last l1 lib header not found in DB"); - info!("Searching for the start of a channel"); + let mut prev_last_l1_lib_header = if let Some(last_l1_lib_header) = last_l1_lib_header { + info!("Last l1 lib header found: {last_l1_lib_header}"); + last_l1_lib_header + } else { + info!("Last l1 lib header not found in DB"); + info!("Searching for the start of a channel"); - let BackfillData { - block_data: start_buff, - curr_fin_l1_lib_header: last_l1_lib_header, - } = self.search_for_channel_start().await?; + let BackfillData { + block_data: start_buff, + curr_fin_l1_lib_header: last_l1_lib_header, + } = self.search_for_channel_start().await?; - for BackfillBlockData { - l2_blocks: l2_block_vec, - l1_header, - } in start_buff { - let mut l2_blocks_parsed_ids: Vec<_> = l2_block_vec.iter().map(|block| block.header.block_id).collect(); - l2_blocks_parsed_ids.sort(); - info!("Parsed {} L2 blocks with ids {:?}", l2_block_vec.len(), l2_blocks_parsed_ids); + for BackfillBlockData { + l2_blocks: l2_block_vec, + l1_header, + } in start_buff { + let mut l2_blocks_parsed_ids: Vec<_> = l2_block_vec.iter().map(|block| block.header.block_id).collect(); + l2_blocks_parsed_ids.sort_unstable(); + info!("Parsed {} L2 blocks with ids {:?}", l2_block_vec.len(), l2_blocks_parsed_ids); - for l2_block in l2_block_vec { - self.store.put_block(l2_block.clone(), l1_header)?; + for l2_block in l2_block_vec { + self.store.put_block(l2_block.clone(), l1_header)?; - yield Ok(l2_block); - } + yield Ok(l2_block); } + } - last_l1_lib_header - }, + last_l1_lib_header }; info!("Searching for initial header finished"); @@ -157,7 +154,7 @@ impl IndexerCore { l1_header: header, } in buff { let mut l2_blocks_parsed_ids: Vec<_> = l2_block_vec.iter().map(|block| block.header.block_id).collect(); - l2_blocks_parsed_ids.sort(); + l2_blocks_parsed_ids.sort_unstable(); info!("Parsed {} L2 blocks with ids {:?}", l2_block_vec.len(), l2_blocks_parsed_ids); for l2_block in l2_block_vec { @@ -177,14 +174,14 @@ impl IndexerCore { async fn get_next_lib(&self, prev_lib: HeaderId) -> Result { loop { let next_lib = self.get_lib().await?; - if next_lib != prev_lib { - break Ok(next_lib); - } else { + if next_lib == prev_lib { info!( "Wait {:?} to not spam the node", self.config.consensus_info_polling_interval ); tokio::time::sleep(self.config.consensus_info_polling_interval).await; + } else { + break Ok(next_lib); } } } @@ -204,15 +201,13 @@ impl IndexerCore { let mut cycle_header = curr_last_l1_lib_header; loop { - let cycle_block = - if let Some(block) = self.bedrock_client.get_block_by_id(cycle_header).await? { - block - } else { - // First run can reach root easily - // so here we are optimistic about L1 - // failing to get parent. - break; - }; + let Some(cycle_block) = self.bedrock_client.get_block_by_id(cycle_header).await? + else { + // First run can reach root easily + // so here we are optimistic about L1 + // failing to get parent. + break; + }; // It would be better to have id, but block does not have it, so slot will do. info!( @@ -289,10 +284,9 @@ impl IndexerCore { if cycle_block.header().id() == last_fin_l1_lib_header { break; - } else { - // Step back to parent - cycle_header = cycle_block.header().parent(); } + // Step back to parent + cycle_header = cycle_block.header().parent(); // It would be better to have id, but block does not have it, so slot will do. info!( @@ -335,7 +329,7 @@ fn parse_block_owned( }) if channel_id == decoded_channel_id => { borsh::from_slice::(inscription) .inspect_err(|err| { - error!("Failed to deserialize our inscription with err: {err:#?}") + error!("Failed to deserialize our inscription with err: {err:#?}"); }) .ok() } diff --git a/indexer/service/protocol/src/convert.rs b/indexer/service/protocol/src/convert.rs index 1de28aa3..931c340c 100644 --- a/indexer/service/protocol/src/convert.rs +++ b/indexer/service/protocol/src/convert.rs @@ -1,6 +1,12 @@ -//! Conversions between indexer_service_protocol types and nssa/nssa_core types +//! Conversions between `indexer_service_protocol` types and `nssa/nssa_core` types -use crate::*; +use crate::{ + Account, AccountId, BedrockStatus, Block, BlockBody, BlockHeader, Ciphertext, Commitment, + CommitmentSetDigest, Data, EncryptedAccountData, EphemeralPublicKey, HashType, MantleMsgId, + Nullifier, PrivacyPreservingMessage, PrivacyPreservingTransaction, ProgramDeploymentMessage, + ProgramDeploymentTransaction, ProgramId, Proof, PublicKey, PublicMessage, PublicTransaction, + Signature, Transaction, WitnessSet, +}; // ============================================================================ // Account-related conversions diff --git a/indexer/service/protocol/src/lib.rs b/indexer/service/protocol/src/lib.rs index 8fdd3289..3a47e095 100644 --- a/indexer/service/protocol/src/lib.rs +++ b/indexer/service/protocol/src/lib.rs @@ -141,6 +141,7 @@ pub enum Transaction { impl Transaction { /// Get the hash of the transaction + #[must_use] pub fn hash(&self) -> &self::HashType { match self { Transaction::Public(tx) => &tx.hash, @@ -308,7 +309,7 @@ mod base64 { use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub mod arr { - use super::*; + use super::{Deserializer, Serializer}; pub fn serialize(v: &[u8], s: S) -> Result { super::serialize(v, s) diff --git a/indexer/service/rpc/src/lib.rs b/indexer/service/rpc/src/lib.rs index 2a67ac50..be0e45ca 100644 --- a/indexer/service/rpc/src/lib.rs +++ b/indexer/service/rpc/src/lib.rs @@ -44,16 +44,16 @@ pub trait Rpc { #[method(name = "getBlocks")] async fn get_blocks( &self, - before: Option, - limit: u32, + before: Option, + limit: u64, ) -> Result, ErrorObjectOwned>; #[method(name = "getTransactionsByAccount")] async fn get_transactions_by_account( &self, account_id: AccountId, - limit: u32, - offset: u32, + offset: u64, + limit: u64, ) -> Result, ErrorObjectOwned>; // ToDo: expand healthcheck response into some kind of report diff --git a/indexer/service/src/lib.rs b/indexer/service/src/lib.rs index 5741f003..cfbe93a0 100644 --- a/indexer/service/src/lib.rs +++ b/indexer/service/src/lib.rs @@ -23,6 +23,7 @@ impl IndexerHandle { } } + #[must_use] pub fn addr(&self) -> SocketAddr { self.addr } @@ -33,9 +34,14 @@ impl IndexerHandle { .take() .expect("Indexer server handle is set"); - handle.stopped().await + handle.stopped().await; } + #[expect( + clippy::redundant_closure_for_method_calls, + reason = "Clippy suggested path jsonrpsee::jsonrpsee_server::ServerHandle is not accessible" + )] + #[must_use] pub fn is_stopped(&self) -> bool { self.server_handle .as_ref() diff --git a/indexer/service/src/main.rs b/indexer/service/src/main.rs index e4d18feb..e66fe401 100644 --- a/indexer/service/src/main.rs +++ b/indexer/service/src/main.rs @@ -26,10 +26,10 @@ async fn main() -> Result<()> { let indexer_handle = indexer_service::run_server(config, port).await?; tokio::select! { - _ = cancellation_token.cancelled() => { + () = cancellation_token.cancelled() => { info!("Shutting down server..."); } - _ = indexer_handle.stopped() => { + () = indexer_handle.stopped() => { error!("Server stopped unexpectedly"); } } diff --git a/indexer/service/src/mock_service.rs b/indexer/service/src/mock_service.rs index 5f0cfbf2..ac052a18 100644 --- a/indexer/service/src/mock_service.rs +++ b/indexer/service/src/mock_service.rs @@ -1,3 +1,8 @@ +#![expect( + clippy::cast_possible_truncation, + clippy::cast_lossless, + reason = "Mock service uses intentional casts and format patterns for test data generation" +)] use std::collections::HashMap; use indexer_service_protocol::{ @@ -9,7 +14,7 @@ use indexer_service_protocol::{ }; use jsonrpsee::{core::SubscriptionResult, types::ErrorObjectOwned}; -/// A mock implementation of the IndexerService RPC for testing purposes. +/// A mock implementation of the `IndexerService` RPC for testing purposes. pub struct MockIndexerService { blocks: Vec, accounts: HashMap, @@ -17,6 +22,7 @@ pub struct MockIndexerService { } impl MockIndexerService { + #[must_use] pub fn new_with_mock_blocks() -> Self { let mut blocks = Vec::new(); let mut accounts = HashMap::new(); @@ -136,7 +142,7 @@ impl MockIndexerService { block_id, prev_block_hash: prev_hash, hash: block_hash, - timestamp: 1704067200000 + (block_id * 12000), // ~12 seconds per block + timestamp: 1_704_067_200_000 + (block_id * 12_000), // ~12 seconds per block signature: Signature([0u8; 64]), }, body: BlockBody { @@ -197,7 +203,7 @@ impl indexer_service_rpc::RpcServer for MockIndexerService { .ok_or_else(|| { ErrorObjectOwned::owned( -32001, - format!("Block with ID {} not found", block_id), + format!("Block with ID {block_id} not found"), None::<()>, ) }) @@ -227,15 +233,18 @@ impl indexer_service_rpc::RpcServer for MockIndexerService { async fn get_blocks( &self, - before: Option, - limit: u32, + before: Option, + limit: u64, ) -> Result, ErrorObjectOwned> { - let start_id = before.map_or_else(|| self.blocks.len() as u64, |id| id.saturating_sub(1)); + let start_id = before.map_or_else( + || self.blocks.len(), + |id| usize::try_from(id.saturating_sub(1)).expect("u64 should fit in usize"), + ); let result = (1..=start_id) .rev() .take(limit as usize) - .map_while(|block_id| self.blocks.get(block_id as usize - 1).cloned()) + .map_while(|block_id| self.blocks.get(block_id - 1).cloned()) .collect(); Ok(result) @@ -244,8 +253,8 @@ impl indexer_service_rpc::RpcServer for MockIndexerService { async fn get_transactions_by_account( &self, account_id: AccountId, - limit: u32, - offset: u32, + offset: u64, + limit: u64, ) -> Result, ErrorObjectOwned> { let mut account_txs: Vec<_> = self .transactions diff --git a/indexer/service/src/service.rs b/indexer/service/src/service.rs index da3e7cbd..838e1403 100644 --- a/indexer/service/src/service.rs +++ b/indexer/service/src/service.rs @@ -90,19 +90,19 @@ impl indexer_service_rpc::RpcServer for IndexerService { async fn get_blocks( &self, - before: Option, - limit: u32, + before: Option, + limit: u64, ) -> Result, ErrorObjectOwned> { let blocks = self .indexer .store - .get_block_batch(before, limit as u64) + .get_block_batch(before, limit) .map_err(db_error)?; let mut block_res = vec![]; for block in blocks { - block_res.push(block.into()) + block_res.push(block.into()); } Ok(block_res) @@ -111,19 +111,19 @@ impl indexer_service_rpc::RpcServer for IndexerService { async fn get_transactions_by_account( &self, account_id: AccountId, - limit: u32, - offset: u32, + offset: u64, + limit: u64, ) -> Result, ErrorObjectOwned> { let transactions = self .indexer .store - .get_transactions_by_account(account_id.value, offset as u64, limit as u64) + .get_transactions_by_account(account_id.value, offset, limit) .map_err(db_error)?; let mut tx_res = vec![]; for tx in transactions { - tx_res.push(tx.into()) + tx_res.push(tx.into()); } Ok(tx_res) @@ -177,8 +177,8 @@ impl SubscriptionService { } } - bail!(err); - }; + bail!(err) + } Ok(()) } @@ -190,7 +190,7 @@ impl SubscriptionService { let handle = tokio::spawn(async move { let mut subscribers = Vec::new(); - let mut block_stream = pin!(indexer.subscribe_parse_block_stream().await); + let mut block_stream = pin!(indexer.subscribe_parse_block_stream()); loop { tokio::select! { @@ -273,6 +273,7 @@ impl Drop for Subscription { } } +#[must_use] pub fn not_yet_implemented_error() -> ErrorObjectOwned { ErrorObject::owned( ErrorCode::InternalError.code(), @@ -281,6 +282,10 @@ pub fn not_yet_implemented_error() -> ErrorObjectOwned { ) } +#[expect( + clippy::needless_pass_by_value, + reason = "Error is consumed to extract details for error response" +)] fn db_error(err: anyhow::Error) -> ErrorObjectOwned { ErrorObjectOwned::owned( ErrorCode::InternalError.code(), diff --git a/integration_tests/src/config.rs b/integration_tests/src/config.rs index 8dd18a25..062fa442 100644 --- a/integration_tests/src/config.rs +++ b/integration_tests/src/config.rs @@ -38,6 +38,7 @@ pub fn indexer_config( } /// Sequencer config options available for custom changes in integration tests. +#[derive(Debug, Clone, Copy)] pub struct SequencerPartialConfig { pub max_num_tx_in_block: usize, pub max_block_size: ByteSize, @@ -122,6 +123,7 @@ pub struct InitialData { } impl InitialData { + #[must_use] pub fn with_two_public_and_two_private_initialized_accounts() -> Self { let mut public_alice_private_key = PrivateKey::new_os_random(); let mut public_alice_public_key = @@ -231,6 +233,7 @@ impl InitialData { } } +#[derive(Debug, Clone, Copy)] pub enum UrlProtocol { Http, Ws, diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index f0111735..b2263b5e 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -52,6 +52,7 @@ impl TestContext { Self::builder().build().await } + #[must_use] pub fn builder() -> TestContextBuilder { TestContextBuilder::new() } @@ -120,6 +121,10 @@ impl TestContext { // Setting port to 0 to avoid conflicts between parallel tests, actual port will be retrieved after container is up .with_env("PORT", "0"); + #[expect( + clippy::items_after_statements, + reason = "This is more readable is this function used just after its definition" + )] async fn up_and_retrieve_port(compose: &mut DockerCompose) -> Result { compose .up() @@ -181,7 +186,10 @@ impl TestContext { let temp_indexer_dir = tempfile::tempdir().context("Failed to create temp dir for indexer home")?; - debug!("Using temp indexer home at {:?}", temp_indexer_dir.path()); + debug!( + "Using temp indexer home at {}", + temp_indexer_dir.path().display() + ); let indexer_config = config::indexer_config( bedrock_addr, @@ -206,8 +214,8 @@ impl TestContext { tempfile::tempdir().context("Failed to create temp dir for sequencer home")?; debug!( - "Using temp sequencer home at {:?}", - temp_sequencer_dir.path() + "Using temp sequencer home at {}", + temp_sequencer_dir.path().display() ); let config = config::sequencer_config( @@ -260,10 +268,12 @@ impl TestContext { } /// Get reference to the wallet. + #[must_use] pub fn wallet(&self) -> &WalletCore { &self.wallet } + #[must_use] pub fn wallet_password(&self) -> &str { &self.wallet_password } @@ -274,16 +284,19 @@ impl TestContext { } /// Get reference to the sequencer client. + #[must_use] pub fn sequencer_client(&self) -> &SequencerClient { &self.sequencer_client } /// Get reference to the indexer client. + #[must_use] pub fn indexer_client(&self) -> &IndexerClient { &self.indexer_client } /// Get existing public account IDs in the wallet. + #[must_use] pub fn existing_public_accounts(&self) -> Vec { self.wallet .storage() @@ -293,6 +306,7 @@ impl TestContext { } /// Get existing private account IDs in the wallet. + #[must_use] pub fn existing_private_accounts(&self) -> Vec { self.wallet .storage() @@ -386,11 +400,13 @@ impl TestContextBuilder { } } + #[must_use] pub fn with_initial_data(mut self, initial_data: config::InitialData) -> Self { self.initial_data = Some(initial_data); self } + #[must_use] pub fn with_sequencer_partial_config( mut self, sequencer_partial_config: config::SequencerPartialConfig, @@ -419,14 +435,16 @@ impl Drop for BlockingTestContext { if let Some(ctx) = ctx.take() { drop(ctx); } - }) + }); } } +#[must_use] pub fn format_public_account_id(account_id: AccountId) -> String { format!("Public/{account_id}") } +#[must_use] pub fn format_private_account_id(account_id: AccountId) -> String { format!("Private/{account_id}") } diff --git a/integration_tests/tests/account.rs b/integration_tests/tests/account.rs index 36dcca5e..5a700707 100644 --- a/integration_tests/tests/account.rs +++ b/integration_tests/tests/account.rs @@ -45,9 +45,8 @@ async fn new_public_account_with_label() -> Result<()> { let result = execute_subcommand(ctx.wallet_mut(), command).await?; // Extract the account_id from the result - let account_id = match result { - wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id, - _ => panic!("Expected RegisterAccount return value"), + let wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } = result else { + panic!("Expected RegisterAccount return value") }; // Verify the label was stored @@ -78,9 +77,9 @@ async fn new_private_account_with_label() -> Result<()> { let result = execute_subcommand(ctx.wallet_mut(), command).await?; // Extract the account_id from the result - let account_id = match result { - wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id, - _ => panic!("Expected RegisterAccount return value"), + + let wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } = result else { + panic!("Expected RegisterAccount return value") }; // Verify the label was stored @@ -110,9 +109,9 @@ async fn new_public_account_without_label() -> Result<()> { let result = execute_subcommand(ctx.wallet_mut(), command).await?; // Extract the account_id from the result - let account_id = match result { - wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id, - _ => panic!("Expected RegisterAccount return value"), + + let wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } = result else { + panic!("Expected RegisterAccount return value") }; // Verify no label was stored diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index aa8ca180..fb5643c8 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -86,7 +86,7 @@ async fn private_transfer_to_foreign_account() -> Result<()> { assert_eq!(tx.message.new_commitments[0], new_commitment1); assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments.into_iter() { + for commitment in tx.message.new_commitments { assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await); } @@ -198,7 +198,7 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> { assert_eq!(tx.message.new_commitments[0], new_commitment1); assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments.into_iter() { + for commitment in tx.message.new_commitments { assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await); } @@ -353,7 +353,7 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { // Verify commitments are in state assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments.into_iter() { + for commitment in tx.message.new_commitments { assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await); } diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index ed8296ec..75ae2c12 100644 --- a/integration_tests/tests/auth_transfer/public.rs +++ b/integration_tests/tests/auth_transfer/public.rs @@ -112,7 +112,7 @@ async fn failed_transfer_with_insufficient_balance() -> Result<()> { to: Some(format_public_account_id(ctx.existing_public_accounts()[1])), to_npk: None, to_vpk: None, - amount: 1000000, + amount: 1_000_000, }); let failed_send = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await; diff --git a/integration_tests/tests/block_size_limit.rs b/integration_tests/tests/block_size_limit.rs index d8ee64dc..47fabdc0 100644 --- a/integration_tests/tests/block_size_limit.rs +++ b/integration_tests/tests/block_size_limit.rs @@ -38,13 +38,12 @@ async fn reject_oversized_transaction() -> Result<()> { ); let err = result.unwrap_err(); - let err_str = format!("{:?}", err); + let err_str = format!("{err:?}"); // Check if the error contains information about transaction being too large assert!( err_str.contains("TransactionTooLarge") || err_str.contains("too large"), - "Expected TransactionTooLarge error, got: {}", - err_str + "Expected TransactionTooLarge error, got: {err_str}" ); Ok(()) diff --git a/integration_tests/tests/config.rs b/integration_tests/tests/config.rs index ed301616..5443edc9 100644 --- a/integration_tests/tests/config.rs +++ b/integration_tests/tests/config.rs @@ -23,7 +23,7 @@ async fn modify_config_field() -> Result<()> { // Return how it was at the beginning let command = Command::Config(ConfigSubcommand::Set { key: "seq_poll_timeout".to_string(), - value: format!("{:?}", old_seq_poll_timeout), + value: format!("{old_seq_poll_timeout:?}"), }); wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs index ad169790..f12ae600 100644 --- a/integration_tests/tests/indexer.rs +++ b/integration_tests/tests/indexer.rs @@ -12,7 +12,7 @@ use tokio::test; use wallet::cli::{Command, programs::native_token_transfer::AuthTransferSubcommand}; /// Timeout in milliseconds to reliably await for block finalization -const L2_TO_L1_TIMEOUT_MILLIS: u64 = 600000; +const L2_TO_L1_TIMEOUT_MILLIS: u64 = 600_000; #[test] async fn indexer_test_run() -> Result<()> { diff --git a/integration_tests/tests/keys_restoration.rs b/integration_tests/tests/keys_restoration.rs index 1bd207be..8806fdab 100644 --- a/integration_tests/tests/keys_restoration.rs +++ b/integration_tests/tests/keys_restoration.rs @@ -87,7 +87,7 @@ async fn sync_private_account_with_non_zero_chain_index() -> Result<()> { assert_eq!(tx.message.new_commitments[0], new_commitment1); assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments.into_iter() { + for commitment in tx.message.new_commitments { assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await); } diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index 12669f90..9f7dd16b 100644 --- a/integration_tests/tests/tps.rs +++ b/integration_tests/tests/tps.rs @@ -56,16 +56,17 @@ pub async fn tps_test() -> Result<()> { for (i, tx_hash) in tx_hashes.iter().enumerate() { loop { - if now.elapsed().as_millis() > target_time.as_millis() { - panic!("TPS test failed by timeout"); - } + assert!( + now.elapsed().as_millis() <= target_time.as_millis(), + "TPS test failed by timeout" + ); let tx_obj = ctx .sequencer_client() .get_transaction_by_hash(*tx_hash) .await .inspect_err(|err| { - log::warn!("Failed to get transaction by hash {tx_hash} with error: {err:#?}") + log::warn!("Failed to get transaction by hash {tx_hash} with error: {err:#?}"); }); if let Ok(tx_obj) = tx_obj @@ -119,6 +120,10 @@ impl TpsTestManager { } } + #[expect( + clippy::cast_precision_loss, + reason = "This is just for testing purposes, we don't care about precision loss here" + )] pub(crate) fn target_time(&self) -> Duration { let number_transactions = (self.public_keypairs.len() - 1) as u64; Duration::from_secs_f64(number_transactions as f64 / self.target_tps as f64) @@ -165,7 +170,7 @@ impl TpsTestManager { let key_chain = KeyChain::new_os_random(); let account = Account { balance: 100, - nonce: 0xdeadbeef, + nonce: 0xdead_beef, program_owner: Program::authenticated_transfer_program().id(), data: Data::default(), }; @@ -200,7 +205,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { let sender_pre = AccountWithMetadata::new( Account { balance: 100, - nonce: 0xdeadbeef, + nonce: 0xdead_beef, program_owner: program.id(), data: Data::default(), }, @@ -234,7 +239,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { vec![sender_pre, recipient_pre], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ (sender_npk.clone(), sender_ss), (recipient_npk.clone(), recipient_ss), diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index e57e6b13..4355e5f1 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -152,7 +152,7 @@ unsafe extern "C" { fn new_wallet_ffi_with_test_context_config( ctx: &BlockingTestContext, home: &Path, -) -> *mut WalletHandle { +) -> Result<*mut WalletHandle> { let config_path = home.join("wallet_config.json"); let storage_path = home.join("storage.json"); let mut config = ctx.ctx().wallet().config().to_owned(); @@ -163,75 +163,73 @@ fn new_wallet_ffi_with_test_context_config( .write(true) .create(true) .truncate(true) - .open(&config_path) - .unwrap(); + .open(&config_path)?; - let config_with_overrides_serialized = serde_json::to_vec_pretty(&config).unwrap(); + let config_with_overrides_serialized = serde_json::to_vec_pretty(&config)?; - file.write_all(&config_with_overrides_serialized).unwrap(); + file.write_all(&config_with_overrides_serialized)?; - let config_path = CString::new(config_path.to_str().unwrap()).unwrap(); - let storage_path = CString::new(storage_path.to_str().unwrap()).unwrap(); - let password = CString::new(ctx.ctx().wallet_password()).unwrap(); + let config_path = CString::new(config_path.to_str().unwrap())?; + let storage_path = CString::new(storage_path.to_str().unwrap())?; + let password = CString::new(ctx.ctx().wallet_password())?; - unsafe { + Ok(unsafe { wallet_ffi_create_new( config_path.as_ptr(), storage_path.as_ptr(), password.as_ptr(), ) - } + }) } -fn new_wallet_ffi_with_default_config(password: &str) -> *mut WalletHandle { - let tempdir = tempdir().unwrap(); +fn new_wallet_ffi_with_default_config(password: &str) -> Result<*mut WalletHandle> { + let tempdir = tempdir()?; let config_path = tempdir.path().join("wallet_config.json"); let storage_path = tempdir.path().join("storage.json"); - let config_path_c = CString::new(config_path.to_str().unwrap()).unwrap(); - let storage_path_c = CString::new(storage_path.to_str().unwrap()).unwrap(); - let password = CString::new(password).unwrap(); + let config_path_c = CString::new(config_path.to_str().unwrap())?; + let storage_path_c = CString::new(storage_path.to_str().unwrap())?; + let password = CString::new(password)?; - unsafe { + Ok(unsafe { wallet_ffi_create_new( config_path_c.as_ptr(), storage_path_c.as_ptr(), password.as_ptr(), ) - } + }) } -fn new_wallet_rust_with_default_config(password: &str) -> WalletCore { - let tempdir = tempdir().unwrap(); +fn new_wallet_rust_with_default_config(password: &str) -> Result { + let tempdir = tempdir()?; let config_path = tempdir.path().join("wallet_config.json"); let storage_path = tempdir.path().join("storage.json"); WalletCore::new_init_storage( - config_path.to_path_buf(), - storage_path.to_path_buf(), + config_path.clone(), + storage_path.clone(), None, password.to_string(), ) - .unwrap() } -fn load_existing_ffi_wallet(home: &Path) -> *mut WalletHandle { +fn load_existing_ffi_wallet(home: &Path) -> Result<*mut WalletHandle> { let config_path = home.join("wallet_config.json"); let storage_path = home.join("storage.json"); - let config_path = CString::new(config_path.to_str().unwrap()).unwrap(); - let storage_path = CString::new(storage_path.to_str().unwrap()).unwrap(); + let config_path = CString::new(config_path.to_str().unwrap())?; + let storage_path = CString::new(storage_path.to_str().unwrap())?; - unsafe { wallet_ffi_open(config_path.as_ptr(), storage_path.as_ptr()) } + Ok(unsafe { wallet_ffi_open(config_path.as_ptr(), storage_path.as_ptr()) }) } #[test] -fn test_wallet_ffi_create_public_accounts() { +fn test_wallet_ffi_create_public_accounts() -> Result<()> { let password = "password_for_tests"; let n_accounts = 10; // First `n_accounts` public accounts created with Rust wallet let new_public_account_ids_rust = { let mut account_ids = Vec::new(); - let mut wallet_rust = new_wallet_rust_with_default_config(password); + let mut wallet_rust = new_wallet_rust_with_default_config(password)?; for _ in 0..n_accounts { let account_id = wallet_rust.create_new_account_public(None).0; account_ids.push(*account_id.value()); @@ -243,13 +241,10 @@ fn test_wallet_ffi_create_public_accounts() { let new_public_account_ids_ffi = unsafe { let mut account_ids = Vec::new(); - let wallet_ffi_handle = new_wallet_ffi_with_default_config(password); + let wallet_ffi_handle = new_wallet_ffi_with_default_config(password)?; for _ in 0..n_accounts { let mut out_account_id = FfiBytes32::from_bytes([0; 32]); - wallet_ffi_create_account_public( - wallet_ffi_handle, - (&mut out_account_id) as *mut FfiBytes32, - ); + wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut out_account_id); account_ids.push(out_account_id.data); } wallet_ffi_destroy(wallet_ffi_handle); @@ -257,17 +252,19 @@ fn test_wallet_ffi_create_public_accounts() { }; assert_eq!(new_public_account_ids_ffi, new_public_account_ids_rust); + + Ok(()) } #[test] -fn test_wallet_ffi_create_private_accounts() { +fn test_wallet_ffi_create_private_accounts() -> Result<()> { let password = "password_for_tests"; let n_accounts = 10; // First `n_accounts` private accounts created with Rust wallet let new_private_account_ids_rust = { let mut account_ids = Vec::new(); - let mut wallet_rust = new_wallet_rust_with_default_config(password); + let mut wallet_rust = new_wallet_rust_with_default_config(password)?; for _ in 0..n_accounts { let account_id = wallet_rust.create_new_account_private(None).0; account_ids.push(*account_id.value()); @@ -279,56 +276,52 @@ fn test_wallet_ffi_create_private_accounts() { let new_private_account_ids_ffi = unsafe { let mut account_ids = Vec::new(); - let wallet_ffi_handle = new_wallet_ffi_with_default_config(password); + let wallet_ffi_handle = new_wallet_ffi_with_default_config(password)?; for _ in 0..n_accounts { let mut out_account_id = FfiBytes32::from_bytes([0; 32]); - wallet_ffi_create_account_private( - wallet_ffi_handle, - (&mut out_account_id) as *mut FfiBytes32, - ); + wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_account_id); account_ids.push(out_account_id.data); } wallet_ffi_destroy(wallet_ffi_handle); account_ids }; - assert_eq!(new_private_account_ids_ffi, new_private_account_ids_rust) + assert_eq!(new_private_account_ids_ffi, new_private_account_ids_rust); + + Ok(()) } #[test] fn test_wallet_ffi_save_and_load_persistent_storage() -> Result<()> { let ctx = BlockingTestContext::new()?; let mut out_private_account_id = FfiBytes32::from_bytes([0; 32]); - let home = tempfile::tempdir().unwrap(); + let home = tempfile::tempdir()?; // Create a private account with the wallet FFI and save it unsafe { - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); - wallet_ffi_create_account_private( - wallet_ffi_handle, - (&mut out_private_account_id) as *mut FfiBytes32, - ); + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_private_account_id); wallet_ffi_save(wallet_ffi_handle); wallet_ffi_destroy(wallet_ffi_handle); } let private_account_keys = unsafe { - let wallet_ffi_handle = load_existing_ffi_wallet(home.path()); + let wallet_ffi_handle = load_existing_ffi_wallet(home.path())?; let mut private_account = FfiAccount::default(); let result = wallet_ffi_get_account_private( wallet_ffi_handle, - (&out_private_account_id) as *const FfiBytes32, - (&mut private_account) as *mut FfiAccount, + &raw const out_private_account_id, + &raw mut private_account, ); assert_eq!(result, error::WalletFfiError::Success); let mut out_keys = FfiPrivateAccountKeys::default(); let result = wallet_ffi_get_private_account_keys( wallet_ffi_handle, - (&out_private_account_id) as *const FfiBytes32, - (&mut out_keys) as *mut FfiPrivateAccountKeys, + &raw const out_private_account_id, + &raw mut out_keys, ); assert_eq!(result, error::WalletFfiError::Success); @@ -346,17 +339,17 @@ fn test_wallet_ffi_save_and_load_persistent_storage() -> Result<()> { } #[test] -fn test_wallet_ffi_list_accounts() { +fn test_wallet_ffi_list_accounts() -> Result<()> { let password = "password_for_tests"; // Create the wallet FFI let wallet_ffi_handle = unsafe { - let handle = new_wallet_ffi_with_default_config(password); + let handle = new_wallet_ffi_with_default_config(password)?; // Create 5 public accounts and 5 private accounts for _ in 0..5 { let mut out_account_id = FfiBytes32::from_bytes([0; 32]); - wallet_ffi_create_account_public(handle, (&mut out_account_id) as *mut FfiBytes32); - wallet_ffi_create_account_private(handle, (&mut out_account_id) as *mut FfiBytes32); + wallet_ffi_create_account_public(handle, &raw mut out_account_id); + wallet_ffi_create_account_private(handle, &raw mut out_account_id); } handle @@ -364,7 +357,7 @@ fn test_wallet_ffi_list_accounts() { // Create the wallet Rust let wallet_rust = { - let mut wallet = new_wallet_rust_with_default_config(password); + let mut wallet = new_wallet_rust_with_default_config(password)?; // Create 5 public accounts and 5 private accounts for _ in 0..5 { wallet.create_new_account_public(None); @@ -376,7 +369,7 @@ fn test_wallet_ffi_list_accounts() { // Get the account list with FFI method let mut wallet_ffi_account_list = unsafe { let mut out_list = FfiAccountList::default(); - wallet_ffi_list_accounts(wallet_ffi_handle, (&mut out_list) as *mut FfiAccountList); + wallet_ffi_list_accounts(wallet_ffi_handle, &raw mut out_list); out_list }; @@ -400,7 +393,7 @@ fn test_wallet_ffi_list_accounts() { assert_eq!( wallet_rust_account_ids .iter() - .map(|id| id.value()) + .map(nssa::AccountId::value) .collect::>(), wallet_ffi_account_list_slice .iter() @@ -409,7 +402,7 @@ fn test_wallet_ffi_list_accounts() { ); // Assert `is_pub` flag is correct in the FFI result - for entry in wallet_ffi_account_list_slice.iter() { + for entry in wallet_ffi_account_list_slice { let account_id = AccountId::new(entry.account_id.data); let is_pub_default_in_rust_wallet = wallet_rust .storage() @@ -429,27 +422,30 @@ fn test_wallet_ffi_list_accounts() { } unsafe { - wallet_ffi_free_account_list((&mut wallet_ffi_account_list) as *mut FfiAccountList); + wallet_ffi_free_account_list(&raw mut wallet_ffi_account_list); wallet_ffi_destroy(wallet_ffi_handle); } + + Ok(()) } #[test] fn test_wallet_ffi_get_balance_public() -> Result<()> { let ctx = BlockingTestContext::new()?; let account_id: AccountId = ctx.ctx().existing_public_accounts()[0]; - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let balance = unsafe { let mut out_balance: [u8; 16] = [0; 16]; let ffi_account_id = FfiBytes32::from(&account_id); - let _result = wallet_ffi_get_balance( + wallet_ffi_get_balance( wallet_ffi_handle, - (&ffi_account_id) as *const FfiBytes32, + &raw const ffi_account_id, true, - (&mut out_balance) as *mut [u8; 16], - ); + &raw mut out_balance, + ) + .unwrap(); u128::from_le_bytes(out_balance) }; assert_eq!(balance, 10000); @@ -467,17 +463,18 @@ fn test_wallet_ffi_get_balance_public() -> Result<()> { fn test_wallet_ffi_get_account_public() -> Result<()> { let ctx = BlockingTestContext::new()?; let account_id: AccountId = ctx.ctx().existing_public_accounts()[0]; - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let mut out_account = FfiAccount::default(); let account: Account = unsafe { let ffi_account_id = FfiBytes32::from(&account_id); - let _result = wallet_ffi_get_account_public( + wallet_ffi_get_account_public( wallet_ffi_handle, - (&ffi_account_id) as *const FfiBytes32, - (&mut out_account) as *mut FfiAccount, - ); + &raw const ffi_account_id, + &raw mut out_account, + ) + .unwrap(); (&out_account).try_into().unwrap() }; @@ -490,7 +487,7 @@ fn test_wallet_ffi_get_account_public() -> Result<()> { assert_eq!(account.nonce, 0); unsafe { - wallet_ffi_free_account_data((&mut out_account) as *mut FfiAccount); + wallet_ffi_free_account_data(&raw mut out_account); wallet_ffi_destroy(wallet_ffi_handle); } @@ -503,17 +500,18 @@ fn test_wallet_ffi_get_account_public() -> Result<()> { fn test_wallet_ffi_get_account_private() -> Result<()> { let ctx = BlockingTestContext::new()?; let account_id: AccountId = ctx.ctx().existing_private_accounts()[0]; - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let mut out_account = FfiAccount::default(); let account: Account = unsafe { let ffi_account_id = FfiBytes32::from(&account_id); - let _result = wallet_ffi_get_account_private( + wallet_ffi_get_account_private( wallet_ffi_handle, - (&ffi_account_id) as *const FfiBytes32, - (&mut out_account) as *mut FfiAccount, - ); + &raw const ffi_account_id, + &raw mut out_account, + ) + .unwrap(); (&out_account).try_into().unwrap() }; @@ -526,7 +524,7 @@ fn test_wallet_ffi_get_account_private() -> Result<()> { assert_eq!(account.nonce, 0); unsafe { - wallet_ffi_free_account_data((&mut out_account) as *mut FfiAccount); + wallet_ffi_free_account_data(&raw mut out_account); wallet_ffi_destroy(wallet_ffi_handle); } @@ -539,17 +537,18 @@ fn test_wallet_ffi_get_account_private() -> Result<()> { fn test_wallet_ffi_get_public_account_keys() -> Result<()> { let ctx = BlockingTestContext::new()?; let account_id: AccountId = ctx.ctx().existing_public_accounts()[0]; - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let mut out_key = FfiPublicAccountKey::default(); let key: PublicKey = unsafe { let ffi_account_id = FfiBytes32::from(&account_id); - let _result = wallet_ffi_get_public_account_key( + wallet_ffi_get_public_account_key( wallet_ffi_handle, - (&ffi_account_id) as *const FfiBytes32, - (&mut out_key) as *mut FfiPublicAccountKey, - ); + &raw const ffi_account_id, + &raw mut out_key, + ) + .unwrap(); (&out_key).try_into().unwrap() }; @@ -577,17 +576,18 @@ fn test_wallet_ffi_get_public_account_keys() -> Result<()> { fn test_wallet_ffi_get_private_account_keys() -> Result<()> { let ctx = BlockingTestContext::new()?; let account_id: AccountId = ctx.ctx().existing_private_accounts()[0]; - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let mut keys = FfiPrivateAccountKeys::default(); unsafe { let ffi_account_id = FfiBytes32::from(&account_id); - let _result = wallet_ffi_get_private_account_keys( + wallet_ffi_get_private_account_keys( wallet_ffi_handle, - (&ffi_account_id) as *const FfiBytes32, - (&mut keys) as *mut FfiPrivateAccountKeys, - ); + &raw const ffi_account_id, + &raw mut keys, + ) + .unwrap(); }; let key_chain = &ctx @@ -606,7 +606,7 @@ fn test_wallet_ffi_get_private_account_keys() -> Result<()> { assert_eq!(&keys.vpk().unwrap(), expected_vpk); unsafe { - wallet_ffi_free_private_account_keys((&mut keys) as *mut FfiPrivateAccountKeys); + wallet_ffi_free_private_account_keys(&raw mut keys); wallet_ffi_destroy(wallet_ffi_handle); } @@ -616,66 +616,65 @@ fn test_wallet_ffi_get_private_account_keys() -> Result<()> { } #[test] -fn test_wallet_ffi_account_id_to_base58() { +fn test_wallet_ffi_account_id_to_base58() -> Result<()> { let private_key = PrivateKey::new_os_random(); let public_key = PublicKey::new_from_private_key(&private_key); let account_id = AccountId::from(&public_key); let ffi_bytes: FfiBytes32 = (&account_id).into(); - let ptr = unsafe { wallet_ffi_account_id_to_base58((&ffi_bytes) as *const FfiBytes32) }; + let ptr = unsafe { wallet_ffi_account_id_to_base58(&raw const ffi_bytes) }; - let ffi_result = unsafe { CStr::from_ptr(ptr).to_str().unwrap() }; + let ffi_result = unsafe { CStr::from_ptr(ptr).to_str()? }; assert_eq!(account_id.to_string(), ffi_result); unsafe { wallet_ffi_free_string(ptr); } + + Ok(()) } #[test] -fn test_wallet_ffi_base58_to_account_id() { +fn test_wallet_ffi_base58_to_account_id() -> Result<()> { let private_key = PrivateKey::new_os_random(); let public_key = PublicKey::new_from_private_key(&private_key); let account_id = AccountId::from(&public_key); let account_id_str = account_id.to_string(); - let account_id_c_str = CString::new(account_id_str.clone()).unwrap(); + let account_id_c_str = CString::new(account_id_str.clone())?; let account_id: AccountId = unsafe { let mut out_account_id_bytes = FfiBytes32::default(); - wallet_ffi_account_id_from_base58( - account_id_c_str.as_ptr(), - (&mut out_account_id_bytes) as *mut FfiBytes32, - ); + wallet_ffi_account_id_from_base58(account_id_c_str.as_ptr(), &raw mut out_account_id_bytes); out_account_id_bytes.into() }; - let expected_account_id = account_id_str.parse().unwrap(); + let expected_account_id = account_id_str.parse()?; assert_eq!(account_id, expected_account_id); + + Ok(()) } #[test] fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> { - let ctx = BlockingTestContext::new().unwrap(); - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let ctx = BlockingTestContext::new()?; + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; // Create a new uninitialized public account let mut out_account_id = FfiBytes32::from_bytes([0; 32]); unsafe { - wallet_ffi_create_account_public( - wallet_ffi_handle, - (&mut out_account_id) as *mut FfiBytes32, - ); + wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut out_account_id); } // Check its program owner is the default program id let account: Account = unsafe { let mut out_account = FfiAccount::default(); - let _result = wallet_ffi_get_account_public( + wallet_ffi_get_account_public( wallet_ffi_handle, - (&out_account_id) as *const FfiBytes32, - (&mut out_account) as *mut FfiAccount, - ); + &raw const out_account_id, + &raw mut out_account, + ) + .unwrap(); (&out_account).try_into().unwrap() }; assert_eq!(account.program_owner, DEFAULT_PROGRAM_ID); @@ -685,8 +684,8 @@ fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> { unsafe { wallet_ffi_register_public_account( wallet_ffi_handle, - (&out_account_id) as *const FfiBytes32, - (&mut transfer_result) as *mut FfiTransferResult, + &raw const out_account_id, + &raw mut transfer_result, ); } @@ -696,11 +695,12 @@ fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> { // Check that the program owner is now the authenticated transfer program let account: Account = unsafe { let mut out_account = FfiAccount::default(); - let _result = wallet_ffi_get_account_public( + wallet_ffi_get_account_public( wallet_ffi_handle, - (&out_account_id) as *const FfiBytes32, - (&mut out_account) as *mut FfiAccount, - ); + &raw const out_account_id, + &raw mut out_account, + ) + .unwrap(); (&out_account).try_into().unwrap() }; assert_eq!( @@ -709,7 +709,7 @@ fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> { ); unsafe { - wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult); + wallet_ffi_free_transfer_result(&raw mut transfer_result); wallet_ffi_destroy(wallet_ffi_handle); } @@ -718,17 +718,14 @@ fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> { #[test] fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> { - let ctx = BlockingTestContext::new().unwrap(); - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let ctx = BlockingTestContext::new()?; + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; // Create a new uninitialized public account let mut out_account_id = FfiBytes32::from_bytes([0; 32]); unsafe { - wallet_ffi_create_account_private( - wallet_ffi_handle, - (&mut out_account_id) as *mut FfiBytes32, - ); + wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_account_id); } // Check its program owner is the default program id @@ -736,8 +733,8 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> { let mut out_account = FfiAccount::default(); wallet_ffi_get_account_private( wallet_ffi_handle, - (&out_account_id) as *const FfiBytes32, - (&mut out_account) as *mut FfiAccount, + &raw const out_account_id, + &raw mut out_account, ); (&out_account).try_into().unwrap() }; @@ -748,8 +745,8 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> { unsafe { wallet_ffi_register_private_account( wallet_ffi_handle, - (&out_account_id) as *const FfiBytes32, - (&mut transfer_result) as *mut FfiTransferResult, + &raw const out_account_id, + &raw mut transfer_result, ); } @@ -759,18 +756,19 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> { // Sync private account local storage with onchain encrypted state unsafe { let mut current_height = 0; - wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64); + wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height); wallet_ffi_sync_to_block(wallet_ffi_handle, current_height); }; // Check that the program owner is now the authenticated transfer program let account: Account = unsafe { let mut out_account = FfiAccount::default(); - let _result = wallet_ffi_get_account_private( + wallet_ffi_get_account_private( wallet_ffi_handle, - (&out_account_id) as *const FfiBytes32, - (&mut out_account) as *mut FfiAccount, - ); + &raw const out_account_id, + &raw mut out_account, + ) + .unwrap(); (&out_account).try_into().unwrap() }; assert_eq!( @@ -779,7 +777,7 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> { ); unsafe { - wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult); + wallet_ffi_free_transfer_result(&raw mut transfer_result); wallet_ffi_destroy(wallet_ffi_handle); } @@ -788,9 +786,9 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> { #[test] fn test_wallet_ffi_transfer_public() -> Result<()> { - let ctx = BlockingTestContext::new().unwrap(); - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let ctx = BlockingTestContext::new()?; + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let from: FfiBytes32 = (&ctx.ctx().existing_public_accounts()[0]).into(); let to: FfiBytes32 = (&ctx.ctx().existing_public_accounts()[1]).into(); let amount: [u8; 16] = 100u128.to_le_bytes(); @@ -799,10 +797,10 @@ fn test_wallet_ffi_transfer_public() -> Result<()> { unsafe { wallet_ffi_transfer_public( wallet_ffi_handle, - (&from) as *const FfiBytes32, - (&to) as *const FfiBytes32, - (&amount) as *const [u8; 16], - (&mut transfer_result) as *mut FfiTransferResult, + &raw const from, + &raw const to, + &raw const amount, + &raw mut transfer_result, ); } @@ -811,23 +809,20 @@ fn test_wallet_ffi_transfer_public() -> Result<()> { let from_balance = unsafe { let mut out_balance: [u8; 16] = [0; 16]; - let _result = wallet_ffi_get_balance( + wallet_ffi_get_balance( wallet_ffi_handle, - (&from) as *const FfiBytes32, + &raw const from, true, - (&mut out_balance) as *mut [u8; 16], - ); + &raw mut out_balance, + ) + .unwrap(); u128::from_le_bytes(out_balance) }; let to_balance = unsafe { let mut out_balance: [u8; 16] = [0; 16]; - let _result = wallet_ffi_get_balance( - wallet_ffi_handle, - (&to) as *const FfiBytes32, - true, - (&mut out_balance) as *mut [u8; 16], - ); + wallet_ffi_get_balance(wallet_ffi_handle, &raw const to, true, &raw mut out_balance) + .unwrap(); u128::from_le_bytes(out_balance) }; @@ -835,7 +830,7 @@ fn test_wallet_ffi_transfer_public() -> Result<()> { assert_eq!(to_balance, 20100); unsafe { - wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult); + wallet_ffi_free_transfer_result(&raw mut transfer_result); wallet_ffi_destroy(wallet_ffi_handle); } @@ -844,21 +839,18 @@ fn test_wallet_ffi_transfer_public() -> Result<()> { #[test] fn test_wallet_ffi_transfer_shielded() -> Result<()> { - let ctx = BlockingTestContext::new().unwrap(); - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let ctx = BlockingTestContext::new()?; + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let from: FfiBytes32 = (&ctx.ctx().existing_public_accounts()[0]).into(); let (to, to_keys) = unsafe { let mut out_account_id = FfiBytes32::default(); let mut out_keys = FfiPrivateAccountKeys::default(); - wallet_ffi_create_account_private( - wallet_ffi_handle, - (&mut out_account_id) as *mut FfiBytes32, - ); + wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_account_id); wallet_ffi_get_private_account_keys( wallet_ffi_handle, - (&out_account_id) as *const FfiBytes32, - (&mut out_keys) as *mut FfiPrivateAccountKeys, + &raw const out_account_id, + &raw mut out_keys, ); (out_account_id, out_keys) }; @@ -868,10 +860,10 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> { unsafe { wallet_ffi_transfer_shielded( wallet_ffi_handle, - (&from) as *const FfiBytes32, - (&to_keys) as *const FfiPrivateAccountKeys, - (&amount) as *const [u8; 16], - (&mut transfer_result) as *mut FfiTransferResult, + &raw const from, + &raw const to_keys, + &raw const amount, + &raw mut transfer_result, ); } @@ -881,18 +873,19 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> { // Sync private account local storage with onchain encrypted state unsafe { let mut current_height = 0; - wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64); + wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height); wallet_ffi_sync_to_block(wallet_ffi_handle, current_height); }; let from_balance = unsafe { let mut out_balance: [u8; 16] = [0; 16]; - let _result = wallet_ffi_get_balance( + wallet_ffi_get_balance( wallet_ffi_handle, - (&from) as *const FfiBytes32, + &raw const from, true, - (&mut out_balance) as *mut [u8; 16], - ); + &raw mut out_balance, + ) + .unwrap(); u128::from_le_bytes(out_balance) }; @@ -900,9 +893,9 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> { let mut out_balance: [u8; 16] = [0; 16]; let _result = wallet_ffi_get_balance( wallet_ffi_handle, - (&to) as *const FfiBytes32, + &raw const to, false, - (&mut out_balance) as *mut [u8; 16], + &raw mut out_balance, ); u128::from_le_bytes(out_balance) }; @@ -911,7 +904,7 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> { assert_eq!(to_balance, 100); unsafe { - wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult); + wallet_ffi_free_transfer_result(&raw mut transfer_result); wallet_ffi_destroy(wallet_ffi_handle); } @@ -920,9 +913,9 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> { #[test] fn test_wallet_ffi_transfer_deshielded() -> Result<()> { - let ctx = BlockingTestContext::new().unwrap(); - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let ctx = BlockingTestContext::new()?; + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let from: FfiBytes32 = (&ctx.ctx().existing_private_accounts()[0]).into(); let to = FfiBytes32::from_bytes([37; 32]); let amount: [u8; 16] = 100u128.to_le_bytes(); @@ -931,10 +924,10 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> { unsafe { wallet_ffi_transfer_deshielded( wallet_ffi_handle, - (&from) as *const FfiBytes32, - (&to) as *const FfiBytes32, - (&amount) as *const [u8; 16], - (&mut transfer_result) as *mut FfiTransferResult, + &raw const from, + &raw const to, + &raw const amount, + &raw mut transfer_result, ); } @@ -944,7 +937,7 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> { // Sync private account local storage with onchain encrypted state unsafe { let mut current_height = 0; - wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64); + wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height); wallet_ffi_sync_to_block(wallet_ffi_handle, current_height); }; @@ -952,21 +945,17 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> { let mut out_balance: [u8; 16] = [0; 16]; let _result = wallet_ffi_get_balance( wallet_ffi_handle, - (&from) as *const FfiBytes32, + &raw const from, false, - (&mut out_balance) as *mut [u8; 16], + &raw mut out_balance, ); u128::from_le_bytes(out_balance) }; let to_balance = unsafe { let mut out_balance: [u8; 16] = [0; 16]; - let _result = wallet_ffi_get_balance( - wallet_ffi_handle, - (&to) as *const FfiBytes32, - true, - (&mut out_balance) as *mut [u8; 16], - ); + let _result = + wallet_ffi_get_balance(wallet_ffi_handle, &raw const to, true, &raw mut out_balance); u128::from_le_bytes(out_balance) }; @@ -974,7 +963,7 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> { assert_eq!(to_balance, 100); unsafe { - wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult); + wallet_ffi_free_transfer_result(&raw mut transfer_result); wallet_ffi_destroy(wallet_ffi_handle); } @@ -983,22 +972,19 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> { #[test] fn test_wallet_ffi_transfer_private() -> Result<()> { - let ctx = BlockingTestContext::new().unwrap(); - let home = tempfile::tempdir().unwrap(); - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path()); + let ctx = BlockingTestContext::new()?; + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let from: FfiBytes32 = (&ctx.ctx().existing_private_accounts()[0]).into(); let (to, to_keys) = unsafe { let mut out_account_id = FfiBytes32::default(); let mut out_keys = FfiPrivateAccountKeys::default(); - wallet_ffi_create_account_private( - wallet_ffi_handle, - (&mut out_account_id) as *mut FfiBytes32, - ); + wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_account_id); wallet_ffi_get_private_account_keys( wallet_ffi_handle, - (&out_account_id) as *const FfiBytes32, - (&mut out_keys) as *mut FfiPrivateAccountKeys, + &raw const out_account_id, + &raw mut out_keys, ); (out_account_id, out_keys) }; @@ -1009,10 +995,10 @@ fn test_wallet_ffi_transfer_private() -> Result<()> { unsafe { wallet_ffi_transfer_private( wallet_ffi_handle, - (&from) as *const FfiBytes32, - (&to_keys) as *const FfiPrivateAccountKeys, - (&amount) as *const [u8; 16], - (&mut transfer_result) as *mut FfiTransferResult, + &raw const from, + &raw const to_keys, + &raw const amount, + &raw mut transfer_result, ); } @@ -1022,7 +1008,7 @@ fn test_wallet_ffi_transfer_private() -> Result<()> { // Sync private account local storage with onchain encrypted state unsafe { let mut current_height = 0; - wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64); + wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height); wallet_ffi_sync_to_block(wallet_ffi_handle, current_height); }; @@ -1030,9 +1016,9 @@ fn test_wallet_ffi_transfer_private() -> Result<()> { let mut out_balance: [u8; 16] = [0; 16]; let _result = wallet_ffi_get_balance( wallet_ffi_handle, - (&from) as *const FfiBytes32, + &raw const from, false, - (&mut out_balance) as *mut [u8; 16], + &raw mut out_balance, ); u128::from_le_bytes(out_balance) }; @@ -1041,9 +1027,9 @@ fn test_wallet_ffi_transfer_private() -> Result<()> { let mut out_balance: [u8; 16] = [0; 16]; let _result = wallet_ffi_get_balance( wallet_ffi_handle, - (&to) as *const FfiBytes32, + &raw const to, false, - (&mut out_balance) as *mut [u8; 16], + &raw mut out_balance, ); u128::from_le_bytes(out_balance) }; @@ -1052,7 +1038,7 @@ fn test_wallet_ffi_transfer_private() -> Result<()> { assert_eq!(to_balance, 100); unsafe { - wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult); + wallet_ffi_free_transfer_result(&raw mut transfer_result); wallet_ffi_destroy(wallet_ffi_handle); } diff --git a/key_protocol/src/key_management/ephemeral_key_holder.rs b/key_protocol/src/key_management/ephemeral_key_holder.rs index 4aaea58c..a10a5191 100644 --- a/key_protocol/src/key_management/ephemeral_key_holder.rs +++ b/key_protocol/src/key_management/ephemeral_key_holder.rs @@ -12,6 +12,7 @@ pub struct EphemeralKeyHolder { ephemeral_secret_key: EphemeralSecretKey, } +#[must_use] pub fn produce_one_sided_shared_secret_receiver( vpk: &ViewingPublicKey, ) -> (SharedSecretKey, EphemeralPublicKey) { @@ -24,6 +25,7 @@ pub fn produce_one_sided_shared_secret_receiver( } impl EphemeralKeyHolder { + #[must_use] pub fn new(receiver_nullifier_public_key: &NullifierPublicKey) -> Self { let mut nonce_bytes = [0; 16]; OsRng.fill_bytes(&mut nonce_bytes); @@ -36,10 +38,12 @@ impl EphemeralKeyHolder { } } + #[must_use] pub fn generate_ephemeral_public_key(&self) -> EphemeralPublicKey { EphemeralPublicKey::from_scalar(self.ephemeral_secret_key) } + #[must_use] pub fn calculate_shared_secret_sender( &self, receiver_viewing_public_key: &ViewingPublicKey, diff --git a/key_protocol/src/key_management/key_tree/chain_index.rs b/key_protocol/src/key_management/key_tree/chain_index.rs index d5fbf401..80dced3b 100644 --- a/key_protocol/src/key_management/key_tree/chain_index.rs +++ b/key_protocol/src/key_management/key_tree/chain_index.rs @@ -28,7 +28,7 @@ impl FromStr for ChainIndex { let uprooted_substring = s.strip_prefix("/").unwrap(); - let splitted_chain: Vec<&str> = uprooted_substring.split("/").collect(); + let splitted_chain: Vec<&str> = uprooted_substring.split('/').collect(); let mut res = vec![]; for split_ch in splitted_chain { @@ -47,7 +47,7 @@ impl Display for ChainIndex { write!(f, "{cci}/")?; } if let Some(last) = self.0.last() { - write!(f, "{}", last)?; + write!(f, "{last}")?; } Ok(()) } @@ -60,28 +60,33 @@ impl Default for ChainIndex { } impl ChainIndex { + #[must_use] pub fn root() -> Self { ChainIndex::default() } + #[must_use] pub fn chain(&self) -> &[u32] { &self.0 } + #[must_use] pub fn index(&self) -> Option { self.chain().last().copied() } + #[must_use] pub fn next_in_line(&self) -> ChainIndex { let mut chain = self.0.clone(); // ToDo: Add overflow check if let Some(last_p) = chain.last_mut() { - *last_p += 1 + *last_p += 1; } ChainIndex(chain) } + #[must_use] pub fn previous_in_line(&self) -> Option { let mut chain = self.0.clone(); if let Some(last_p) = chain.last_mut() { @@ -91,6 +96,7 @@ impl ChainIndex { Some(ChainIndex(chain)) } + #[must_use] pub fn parent(&self) -> Option { if self.0.is_empty() { None @@ -99,6 +105,7 @@ impl ChainIndex { } } + #[must_use] pub fn nth_child(&self, child_id: u32) -> ChainIndex { let mut chain = self.0.clone(); chain.push(child_id); @@ -106,6 +113,7 @@ impl ChainIndex { ChainIndex(chain) } + #[must_use] pub fn depth(&self) -> u32 { self.0.iter().map(|cci| cci + 1).sum() } @@ -124,7 +132,7 @@ impl ChainIndex { .iter() .permutations(self.0.len()) .unique() - .map(|item| ChainIndex(item.into_iter().cloned().collect())) + .map(|item| ChainIndex(item.into_iter().copied().collect())) } pub fn chain_ids_at_depth(depth: usize) -> impl Iterator { @@ -227,7 +235,7 @@ mod tests { let prev_chain_id = chain_id.previous_in_line().unwrap(); - assert_eq!(prev_chain_id, ChainIndex(vec![1, 7, 2])) + assert_eq!(prev_chain_id, ChainIndex(vec![1, 7, 2])); } #[test] @@ -236,7 +244,7 @@ mod tests { let prev_chain_id = chain_id.previous_in_line(); - assert_eq!(prev_chain_id, None) + assert_eq!(prev_chain_id, None); } #[test] @@ -245,7 +253,7 @@ mod tests { let parent_chain_id = chain_id.parent().unwrap(); - assert_eq!(parent_chain_id, ChainIndex(vec![1, 7])) + assert_eq!(parent_chain_id, ChainIndex(vec![1, 7])); } #[test] @@ -254,7 +262,7 @@ mod tests { let parent_chain_id = chain_id.parent(); - assert_eq!(parent_chain_id, None) + assert_eq!(parent_chain_id, None); } #[test] @@ -263,7 +271,7 @@ mod tests { let parent_chain_id = chain_id.parent().unwrap(); - assert_eq!(parent_chain_id, ChainIndex::root()) + assert_eq!(parent_chain_id, ChainIndex::root()); } #[test] @@ -272,7 +280,7 @@ mod tests { let collapsed = chain_id.collapse_back().unwrap(); - assert_eq!(collapsed, ChainIndex(vec![3])) + assert_eq!(collapsed, ChainIndex(vec![3])); } #[test] @@ -281,7 +289,7 @@ mod tests { let collapsed = chain_id.collapse_back(); - assert_eq!(collapsed, None) + assert_eq!(collapsed, None); } #[test] @@ -290,7 +298,7 @@ mod tests { let collapsed = chain_id.collapse_back(); - assert_eq!(collapsed, None) + assert_eq!(collapsed, None); } #[test] diff --git a/key_protocol/src/key_management/key_tree/keys_public.rs b/key_protocol/src/key_management/key_tree/keys_public.rs index 7c5d6e38..7e041c3f 100644 --- a/key_protocol/src/key_management/key_tree/keys_public.rs +++ b/key_protocol/src/key_management/key_tree/keys_public.rs @@ -16,21 +16,18 @@ impl ChildKeysPublic { fn compute_hash_value(&self, cci: u32) -> [u8; 64] { let mut hash_input = vec![]; - match ((2u32).pow(31)).cmp(&cci) { + if 2u32.pow(31) > cci { // Non-harden - std::cmp::Ordering::Greater => { - hash_input.extend_from_slice(self.cpk.value()); - hash_input.extend_from_slice(&cci.to_le_bytes()); + hash_input.extend_from_slice(self.cpk.value()); + hash_input.extend_from_slice(&cci.to_le_bytes()); - hmac_sha512::HMAC::mac(hash_input, self.ccc) - } + hmac_sha512::HMAC::mac(hash_input, self.ccc) + } else { // Harden - _ => { - hash_input.extend_from_slice(self.csk.value()); - hash_input.extend_from_slice(&(cci).to_le_bytes()); + hash_input.extend_from_slice(self.csk.value()); + hash_input.extend_from_slice(&(cci).to_le_bytes()); - hmac_sha512::HMAC::mac(hash_input, self.ccc) - } + hmac_sha512::HMAC::mac(hash_input, self.ccc) } } } @@ -68,9 +65,10 @@ impl KeyNode for ChildKeysPublic { ) .unwrap(); - if secp256k1::constants::CURVE_ORDER < *csk.value() { - panic!("Secret key cannot exceed curve order"); - } + assert!( + secp256k1::constants::CURVE_ORDER >= *csk.value(), + "Secret key cannot exceed curve order" + ); let ccc = *hash_value .last_chunk::<32>() diff --git a/key_protocol/src/key_management/key_tree/mod.rs b/key_protocol/src/key_management/key_tree/mod.rs index ead60595..bae44fbd 100644 --- a/key_protocol/src/key_management/key_tree/mod.rs +++ b/key_protocol/src/key_management/key_tree/mod.rs @@ -32,6 +32,7 @@ pub type KeyTreePublic = KeyTree; pub type KeyTreePrivate = KeyTree; impl KeyTree { + #[must_use] pub fn new(seed: &SeedHolder) -> Self { let seed_fit: [u8; 64] = seed .seed @@ -63,6 +64,7 @@ impl KeyTree { // ToDo: Add function to create a tree from list of nodes with consistency check. + #[must_use] pub fn find_next_last_child_of_id(&self, parent_id: &ChainIndex) -> Option { if !self.key_map.contains_key(parent_id) { return None; @@ -87,14 +89,14 @@ impl KeyTree { match (&rightmost_ref, &rightmost_ref_next) { (Some(_), Some(_)) => { left_border = right; - right = (right + right_border) / 2; + right = u32::midpoint(right, right_border); } (Some(_), None) => { break Some(right + 1); } (None, None) => { right_border = right; - right = (left_border + right) / 2; + right = u32::midpoint(left_border, right); } (None, Some(_)) => { unreachable!(); @@ -152,6 +154,7 @@ impl KeyTree { self.fill_node(&self.find_next_slot_layered()) } + #[must_use] pub fn get_node(&self, account_id: nssa::AccountId) -> Option<&N> { self.account_id_map .get(&account_id) diff --git a/key_protocol/src/key_management/key_tree/traits.rs b/key_protocol/src/key_management/key_tree/traits.rs index 5770c47d..b57eec64 100644 --- a/key_protocol/src/key_management/key_tree/traits.rs +++ b/key_protocol/src/key_management/key_tree/traits.rs @@ -4,6 +4,7 @@ pub trait KeyNode { fn root(seed: [u8; 64]) -> Self; /// `cci`'s child of node + #[must_use] fn nth_child(&self, cci: u32) -> Self; fn chain_code(&self) -> &[u8; 32]; diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index 6e2891ce..b8e3c261 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -21,6 +21,7 @@ pub struct KeyChain { } impl KeyChain { + #[must_use] pub fn new_os_random() -> Self { // Currently dropping SeedHolder at the end of initialization. // Now entirely sure if we need it in the future. @@ -40,6 +41,7 @@ impl KeyChain { } } + #[must_use] pub fn new_mnemonic(passphrase: String) -> Self { // Currently dropping SeedHolder at the end of initialization. // Not entirely sure if we need it in the future. @@ -59,14 +61,15 @@ impl KeyChain { } } + #[must_use] pub fn calculate_shared_secret_receiver( &self, - ephemeral_public_key_sender: EphemeralPublicKey, + ephemeral_public_key_sender: &EphemeralPublicKey, index: Option, ) -> SharedSecretKey { SharedSecretKey::new( &self.secret_spending_key.generate_viewing_secret_key(index), - &ephemeral_public_key_sender, + ephemeral_public_key_sender, ) } } @@ -106,7 +109,7 @@ mod tests { // Calculate shared secret let _shared_secret = account_id_key_holder - .calculate_shared_secret_receiver(ephemeral_public_key_sender, None); + .calculate_shared_secret_receiver(&ephemeral_public_key_sender, None); } #[test] @@ -184,7 +187,7 @@ mod tests { let key_sender = eph_key_holder.calculate_shared_secret_sender(&keys.viewing_public_key); let key_receiver = keys.calculate_shared_secret_receiver( - eph_key_holder.generate_ephemeral_public_key(), + &eph_key_holder.generate_ephemeral_public_key(), Some(2), ); diff --git a/key_protocol/src/key_management/secret_holders.rs b/key_protocol/src/key_management/secret_holders.rs index d5aac258..0c096be4 100644 --- a/key_protocol/src/key_management/secret_holders.rs +++ b/key_protocol/src/key_management/secret_holders.rs @@ -25,14 +25,15 @@ pub struct SecretSpendingKey(pub(crate) [u8; 32]); pub type ViewingSecretKey = Scalar; #[derive(Serialize, Deserialize, Debug, Clone)] -/// Private key holder. Produces public keys. Can produce account_id. Can produce shared secret for -/// recepient. +/// Private key holder. Produces public keys. Can produce `account_id`. Can produce shared secret +/// for recepient. pub struct PrivateKeyHolder { pub nullifier_secret_key: NullifierSecretKey, pub(crate) viewing_secret_key: ViewingSecretKey, } impl SeedHolder { + #[must_use] pub fn new_os_random() -> Self { let mut enthopy_bytes: [u8; 32] = [0; 32]; OsRng.fill_bytes(&mut enthopy_bytes); @@ -46,6 +47,7 @@ impl SeedHolder { } } + #[must_use] pub fn new_mnemonic(passphrase: String) -> Self { let mnemonic = Mnemonic::from_entropy(&NSSA_ENTROPY_BYTES) .expect("Enthropy must be a multiple of 32 bytes"); @@ -56,6 +58,7 @@ impl SeedHolder { } } + #[must_use] pub fn generate_secret_spending_key_hash(&self) -> HashType { let mut hash = hmac_sha512::HMAC::mac(&self.seed, "NSSA_seed"); @@ -67,22 +70,24 @@ impl SeedHolder { HashType(*hash.first_chunk::<32>().unwrap()) } + #[must_use] pub fn produce_top_secret_key_holder(&self) -> SecretSpendingKey { SecretSpendingKey(self.generate_secret_spending_key_hash().into()) } } impl SecretSpendingKey { + #[must_use] pub fn generate_nullifier_secret_key(&self, index: Option) -> NullifierSecretKey { + const PREFIX: &[u8; 8] = b"LEE/keys"; + const SUFFIX_1: &[u8; 1] = &[1]; + const SUFFIX_2: &[u8; 19] = &[0; 19]; + let index = match index { None => 0u32, _ => index.expect("Expect a valid u32"), }; - const PREFIX: &[u8; 8] = b"LEE/keys"; - const SUFFIX_1: &[u8; 1] = &[1]; - const SUFFIX_2: &[u8; 19] = &[0; 19]; - let mut hasher = sha2::Sha256::new(); hasher.update(PREFIX); hasher.update(self.0); @@ -93,14 +98,16 @@ impl SecretSpendingKey { ::from(hasher.finalize_fixed()) } + #[must_use] pub fn generate_viewing_secret_key(&self, index: Option) -> ViewingSecretKey { + const PREFIX: &[u8; 8] = b"LEE/keys"; + const SUFFIX_1: &[u8; 1] = &[2]; + const SUFFIX_2: &[u8; 19] = &[0; 19]; + let index = match index { None => 0u32, _ => index.expect("Expect a valid u32"), }; - const PREFIX: &[u8; 8] = b"LEE/keys"; - const SUFFIX_1: &[u8; 1] = &[2]; - const SUFFIX_2: &[u8; 19] = &[0; 19]; let mut hasher = sha2::Sha256::new(); hasher.update(PREFIX); @@ -112,6 +119,7 @@ impl SecretSpendingKey { hasher.finalize_fixed().into() } + #[must_use] pub fn produce_private_key_holder(&self, index: Option) -> PrivateKeyHolder { PrivateKeyHolder { nullifier_secret_key: self.generate_nullifier_secret_key(index), @@ -121,10 +129,12 @@ impl SecretSpendingKey { } impl PrivateKeyHolder { + #[must_use] pub fn generate_nullifier_public_key(&self) -> NullifierPublicKey { (&self.nullifier_secret_key).into() } + #[must_use] pub fn generate_viewing_public_key(&self) -> ViewingPublicKey { ViewingPublicKey::from_scalar(self.viewing_secret_key) } diff --git a/key_protocol/src/key_protocol_core/mod.rs b/key_protocol/src/key_protocol_core/mod.rs index 42e4b672..f0ce49fa 100644 --- a/key_protocol/src/key_protocol_core/mod.rs +++ b/key_protocol/src/key_protocol_core/mod.rs @@ -34,7 +34,7 @@ impl NSSAUserData { let expected_account_id = nssa::AccountId::from(&nssa::PublicKey::new_from_private_key(key)); if &expected_account_id != account_id { - println!("{}, {}", expected_account_id, account_id); + println!("{expected_account_id}, {account_id}"); check_res = false; } } @@ -48,7 +48,7 @@ impl NSSAUserData { for (account_id, (key, _)) in accounts_keys_map { let expected_account_id = nssa::AccountId::from(&key.nullifer_public_key); if expected_account_id != *account_id { - println!("{}, {}", expected_account_id, account_id); + println!("{expected_account_id}, {account_id}"); check_res = false; } } @@ -86,7 +86,7 @@ impl NSSAUserData { /// Generated new private key for public transaction signatures /// - /// Returns the account_id of new account + /// Returns the `account_id` of new account pub fn generate_new_public_transaction_private_key( &mut self, parent_cci: Option, @@ -119,7 +119,7 @@ impl NSSAUserData { /// Generated new private key for privacy preserving transactions /// - /// Returns the account_id of new account + /// Returns the `account_id` of new account pub fn generate_new_privacy_preserving_transaction_key_chain( &mut self, parent_cci: Option, diff --git a/mempool/src/lib.rs b/mempool/src/lib.rs index fae52b3e..874a2fa3 100644 --- a/mempool/src/lib.rs +++ b/mempool/src/lib.rs @@ -6,6 +6,7 @@ pub struct MemPool { } impl MemPool { + #[must_use] pub fn new(max_size: usize) -> (Self, MemPoolHandle) { let (sender, receiver) = tokio::sync::mpsc::channel(max_size); @@ -17,6 +18,7 @@ impl MemPool { (mem_pool, sender) } + /// Pop an item from the mempool first checking the front buffer (LIFO) then the channel (FIFO). pub fn pop(&mut self) -> Option { use tokio::sync::mpsc::error::TryRecvError; diff --git a/nssa/build.rs b/nssa/build.rs index 020b838c..ce39df93 100644 --- a/nssa/build.rs +++ b/nssa/build.rs @@ -1,4 +1,4 @@ -use std::{env, fs, path::PathBuf}; +use std::{env, fmt::Write as _, fs, path::PathBuf}; fn main() -> Result<(), Box> { let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); @@ -15,7 +15,7 @@ fn main() -> Result<(), Box> { .collect::>(); if bins.is_empty() { - return Err(format!("No .bin files found in {:?}", program_methods_dir).into()); + return Err(format!("No .bin files found in {}", program_methods_dir.display()).into()); } fs::create_dir_all(&mod_dir)?; @@ -25,14 +25,16 @@ fn main() -> Result<(), Box> { let name = path.file_stem().unwrap().to_string_lossy(); let bytecode = fs::read(&path)?; let image_id: [u32; 8] = risc0_binfmt::compute_image_id(&bytecode)?.into(); - src.push_str(&format!( + write!( + src, "pub const {}_ELF: &[u8] = include_bytes!(r#\"{}\"#);\n\ + #[expect(clippy::unreadable_literal, reason = \"Generated image IDs from risc0 are cryptographic hashes represented as u32 arrays\")]\n\ pub const {}_ID: [u32; 8] = {:?};\n", name.to_uppercase(), path.display(), name.to_uppercase(), image_id - )); + )?; } fs::write(&mod_file, src)?; println!("cargo:warning=Generated module at {}", mod_file.display()); diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index 9de3df5e..59c8a203 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -1,4 +1,7 @@ -use std::{fmt::Display, str::FromStr}; +use std::{ + fmt::{Display, Write as _}, + str::FromStr, +}; use base58::{FromBase58, ToBase58}; use borsh::{BorshDeserialize, BorshSerialize}; @@ -25,12 +28,14 @@ pub struct Account { impl std::fmt::Debug for Account { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let program_owner_hex: String = self + let program_owner_hex = self .program_owner .iter() .flat_map(|n| n.to_le_bytes()) - .map(|b| format!("{b:02x}")) - .collect(); + .fold(String::new(), |mut acc, bytes| { + write!(acc, "{bytes:02x}").expect("writing to string should not fail"); + acc + }); f.debug_struct("Account") .field("program_owner", &program_owner_hex) .field("balance", &self.balance) @@ -82,14 +87,17 @@ impl std::fmt::Debug for AccountId { } impl AccountId { + #[must_use] pub fn new(value: [u8; 32]) -> Self { Self { value } } + #[must_use] pub fn value(&self) -> &[u8; 32] { &self.value } + #[must_use] pub fn into_value(self) -> [u8; 32] { self.value } @@ -172,7 +180,7 @@ mod tests { .to_vec() .try_into() .unwrap(), - nonce: 0xdeadbeef, + nonce: 0xdead_beef, }; let fingerprint = AccountId::new([8; 32]); let new_acc_with_metadata = AccountWithMetadata::new(account.clone(), true, fingerprint); diff --git a/nssa/core/src/account/data.rs b/nssa/core/src/account/data.rs index 91c58516..d244ee47 100644 --- a/nssa/core/src/account/data.rs +++ b/nssa/core/src/account/data.rs @@ -10,10 +10,12 @@ pub const DATA_MAX_LENGTH: ByteSize = ByteSize::kib(100); pub struct Data(Vec); impl Data { + #[must_use] pub fn into_inner(self) -> Vec { self.0 } + /// Reads data from a cursor. #[cfg(feature = "host")] pub fn from_cursor( cursor: &mut std::io::Cursor<&[u8]>, @@ -23,7 +25,9 @@ impl Data { let mut u32_bytes = [0u8; 4]; cursor.read_exact(&mut u32_bytes)?; let data_length = u32::from_le_bytes(u32_bytes); - if data_length as usize > DATA_MAX_LENGTH.as_u64() as usize { + if data_length as usize + > usize::try_from(DATA_MAX_LENGTH.as_u64()).expect("DATA_MAX_LENGTH fits in usize") + { return Err( std::io::Error::new(std::io::ErrorKind::InvalidData, DataTooBigError).into(), ); @@ -49,7 +53,9 @@ impl TryFrom> for Data { type Error = DataTooBigError; fn try_from(value: Vec) -> Result { - if value.len() > DATA_MAX_LENGTH.as_u64() as usize { + if value.len() + > usize::try_from(DATA_MAX_LENGTH.as_u64()).expect("DATA_MAX_LENGTH fits in usize") + { Err(DataTooBigError) } else { Ok(Self(value)) @@ -98,13 +104,17 @@ impl<'de> Deserialize<'de> for Data { A: serde::de::SeqAccess<'de>, { let mut vec = Vec::with_capacity( - seq.size_hint() - .unwrap_or(0) - .min(DATA_MAX_LENGTH.as_u64() as usize), + seq.size_hint().unwrap_or(0).min( + usize::try_from(DATA_MAX_LENGTH.as_u64()) + .expect("DATA_MAX_LENGTH fits in usize"), + ), ); while let Some(value) = seq.next_element()? { - if vec.len() >= DATA_MAX_LENGTH.as_u64() as usize { + if vec.len() + >= usize::try_from(DATA_MAX_LENGTH.as_u64()) + .expect("DATA_MAX_LENGTH fits in usize") + { return Err(serde::de::Error::custom(DataTooBigError)); } vec.push(value); @@ -125,10 +135,15 @@ impl BorshDeserialize for Data { let len = u32::deserialize_reader(reader)?; match len { 0 => Ok(Self::default()), - len if len as usize > DATA_MAX_LENGTH.as_u64() as usize => Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - DataTooBigError, - )), + len if len as usize + > usize::try_from(DATA_MAX_LENGTH.as_u64()) + .expect("DATA_MAX_LENGTH fits in usize") => + { + Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + DataTooBigError, + )) + } len => { let vec_bytes = u8::vec_from_reader(len, reader)? .expect("can't be None in current borsh crate implementation"); @@ -144,21 +159,35 @@ mod tests { #[test] fn test_data_max_length_allowed() { - let max_vec = vec![0u8; DATA_MAX_LENGTH.as_u64() as usize]; + let max_vec = vec![ + 0u8; + usize::try_from(DATA_MAX_LENGTH.as_u64()) + .expect("DATA_MAX_LENGTH fits in usize") + ]; let result = Data::try_from(max_vec); assert!(result.is_ok()); } #[test] fn test_data_too_big_error() { - let big_vec = vec![0u8; DATA_MAX_LENGTH.as_u64() as usize + 1]; + let big_vec = vec![ + 0u8; + usize::try_from(DATA_MAX_LENGTH.as_u64()) + .expect("DATA_MAX_LENGTH fits in usize") + + 1 + ]; let result = Data::try_from(big_vec); assert!(matches!(result, Err(DataTooBigError))); } #[test] fn test_borsh_deserialize_exceeding_limit_error() { - let too_big_data = vec![0u8; DATA_MAX_LENGTH.as_u64() as usize + 1]; + let too_big_data = vec![ + 0u8; + usize::try_from(DATA_MAX_LENGTH.as_u64()) + .expect("DATA_MAX_LENGTH fits in usize") + + 1 + ]; let mut serialized = Vec::new(); <_ as BorshSerialize>::serialize(&too_big_data, &mut serialized).unwrap(); @@ -168,7 +197,12 @@ mod tests { #[test] fn test_json_deserialize_exceeding_limit_error() { - let data = vec![0u8; DATA_MAX_LENGTH.as_u64() as usize + 1]; + let data = vec![ + 0u8; + usize::try_from(DATA_MAX_LENGTH.as_u64()) + .expect("DATA_MAX_LENGTH fits in usize") + + 1 + ]; let json = serde_json::to_string(&data).unwrap(); let result: Result = serde_json::from_str(&json); diff --git a/nssa/core/src/circuit_io.rs b/nssa/core/src/circuit_io.rs index dedcf780..fd65491a 100644 --- a/nssa/core/src/circuit_io.rs +++ b/nssa/core/src/circuit_io.rs @@ -42,6 +42,8 @@ pub struct PrivacyPreservingCircuitOutput { #[cfg(feature = "host")] impl PrivacyPreservingCircuitOutput { + /// Serializes the circuit output to a byte vector. + #[must_use] pub fn to_bytes(&self) -> Vec { bytemuck::cast_slice(&risc0_zkvm::serde::to_vec(&self).unwrap()).to_vec() } @@ -65,9 +67,9 @@ mod tests { AccountWithMetadata::new( Account { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], - balance: 12345678901234567890, + balance: 12_345_678_901_234_567_890, data: b"test data".to_vec().try_into().unwrap(), - nonce: 18446744073709551614, + nonce: 18_446_744_073_709_551_614, }, true, AccountId::new([0; 32]), @@ -75,9 +77,9 @@ mod tests { AccountWithMetadata::new( Account { program_owner: [9, 9, 9, 8, 8, 8, 7, 7], - balance: 123123123456456567112, + balance: 123_123_123_456_456_567_112, data: b"test data".to_vec().try_into().unwrap(), - nonce: 9999999999999999999999, + nonce: 9_999_999_999_999_999_999_999, }, false, AccountId::new([1; 32]), @@ -87,7 +89,7 @@ mod tests { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], balance: 100, data: b"post state data".to_vec().try_into().unwrap(), - nonce: 18446744073709551615, + nonce: 18_446_744_073_709_551_615, }], ciphertexts: vec![Ciphertext(vec![255, 255, 1, 1, 2, 2])], new_commitments: vec![Commitment::new( diff --git a/nssa/core/src/commitment.rs b/nssa/core/src/commitment.rs index 0040db03..58bd838c 100644 --- a/nssa/core/src/commitment.rs +++ b/nssa/core/src/commitment.rs @@ -14,7 +14,12 @@ pub struct Commitment(pub(super) [u8; 32]); #[cfg(any(feature = "host", test))] impl std::fmt::Debug for Commitment { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let hex: String = self.0.iter().map(|b| format!("{b:02x}")).collect(); + use std::fmt::Write as _; + + let hex: String = self.0.iter().fold(String::new(), |mut acc, b| { + write!(acc, "{b:02x}").expect("writing to string should not fail"); + acc + }); write!(f, "Commitment({hex})") } } @@ -45,7 +50,8 @@ pub const DUMMY_COMMITMENT_HASH: [u8; 32] = [ impl Commitment { /// Generates the commitment to a private account owned by user for npk: - /// SHA256(npk || program_owner || balance || nonce || SHA256(data)) + /// SHA256(npk || `program_owner` || balance || nonce || SHA256(data)) + #[must_use] pub fn new(npk: &NullifierPublicKey, account: &Account) -> Self { let mut bytes = Vec::new(); bytes.extend_from_slice(&npk.to_byte_array()); @@ -73,6 +79,7 @@ pub type CommitmentSetDigest = [u8; 32]; pub type MembershipProof = (usize, Vec<[u8; 32]>); /// Computes the resulting digest for the given membership proof and corresponding commitment +#[must_use] pub fn compute_digest_for_path( commitment: &Commitment, proof: &MembershipProof, diff --git a/nssa/core/src/encoding.rs b/nssa/core/src/encoding.rs index 34be3782..6050a234 100644 --- a/nssa/core/src/encoding.rs +++ b/nssa/core/src/encoding.rs @@ -17,6 +17,8 @@ use crate::{ }; impl Account { + /// Serializes the account to bytes. + #[must_use] pub fn to_bytes(&self) -> Vec { let mut bytes = Vec::new(); for word in &self.program_owner { @@ -24,12 +26,13 @@ impl Account { } bytes.extend_from_slice(&self.balance.to_le_bytes()); bytes.extend_from_slice(&self.nonce.to_le_bytes()); - let data_length: u32 = self.data.len() as u32; + let data_length: u32 = u32::try_from(self.data.len()).expect("data length fits in u32"); bytes.extend_from_slice(&data_length.to_le_bytes()); bytes.extend_from_slice(self.data.as_ref()); bytes } + /// Deserializes an account from a cursor. #[cfg(feature = "host")] pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { use crate::account::data::Data; @@ -65,15 +68,18 @@ impl Account { } impl Commitment { + #[must_use] pub fn to_byte_array(&self) -> [u8; 32] { self.0 } #[cfg(feature = "host")] + #[must_use] pub fn from_byte_array(bytes: [u8; 32]) -> Self { Self(bytes) } + /// Deserializes a commitment from a cursor. #[cfg(feature = "host")] pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { let mut bytes = [0u8; 32]; @@ -83,6 +89,7 @@ impl Commitment { } impl NullifierPublicKey { + #[must_use] pub fn to_byte_array(&self) -> [u8; 32] { self.0 } @@ -90,15 +97,18 @@ impl NullifierPublicKey { #[cfg(feature = "host")] impl Nullifier { + #[must_use] pub fn to_byte_array(&self) -> [u8; 32] { self.0 } #[cfg(feature = "host")] + #[must_use] pub fn from_byte_array(bytes: [u8; 32]) -> Self { Self(bytes) } + /// Deserializes a nullifier from a cursor. pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { let mut bytes = [0u8; 32]; cursor.read_exact(&mut bytes)?; @@ -107,9 +117,12 @@ impl Nullifier { } impl Ciphertext { + /// Serializes the ciphertext to bytes. + #[must_use] pub fn to_bytes(&self) -> Vec { let mut bytes = Vec::new(); - let ciphertext_length: u32 = self.0.len() as u32; + let ciphertext_length: u32 = + u32::try_from(self.0.len()).expect("ciphertext length fits in u32"); bytes.extend_from_slice(&ciphertext_length.to_le_bytes()); bytes.extend_from_slice(&self.0); @@ -117,16 +130,19 @@ impl Ciphertext { } #[cfg(feature = "host")] + #[must_use] pub fn into_inner(self) -> Vec { self.0 } #[cfg(feature = "host")] + #[must_use] pub fn from_inner(inner: Vec) -> Self { Self(inner) } #[cfg(feature = "host")] + /// Deserializes ciphertext from a cursor. pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { let mut u32_bytes = [0; 4]; @@ -141,10 +157,13 @@ impl Ciphertext { #[cfg(feature = "host")] impl Secp256k1Point { + /// Converts the point to bytes. + #[must_use] pub fn to_bytes(&self) -> [u8; 33] { self.0.clone().try_into().unwrap() } + /// Deserializes a secp256k1 point from a cursor. pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { let mut value = vec![0; 33]; cursor.read_exact(&mut value)?; @@ -153,6 +172,7 @@ impl Secp256k1Point { } impl AccountId { + #[must_use] pub fn to_bytes(&self) -> [u8; 32] { *self.value() } @@ -166,7 +186,7 @@ mod tests { fn test_enconding() { let account = Account { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], - balance: 123456789012345678901234567890123456, + balance: 123_456_789_012_345_678_901_234_567_890_123_456, nonce: 42, data: b"hola mundo".to_vec().try_into().unwrap(), }; @@ -227,7 +247,7 @@ mod tests { fn test_account_to_bytes_roundtrip() { let account = Account { program_owner: [1, 2, 3, 4, 5, 6, 7, 8], - balance: 123456789012345678901234567890123456, + balance: 123_456_789_012_345_678_901_234_567_890_123_456, nonce: 42, data: b"hola mundo".to_vec().try_into().unwrap(), }; diff --git a/nssa/core/src/encryption/mod.rs b/nssa/core/src/encryption/mod.rs index 8c2ff154..4b07428b 100644 --- a/nssa/core/src/encryption/mod.rs +++ b/nssa/core/src/encryption/mod.rs @@ -28,19 +28,25 @@ pub struct Ciphertext(pub(crate) Vec); #[cfg(any(feature = "host", test))] impl std::fmt::Debug for Ciphertext { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let hex: String = self.0.iter().map(|b| format!("{b:02x}")).collect(); + use std::fmt::Write as _; + + let hex: String = self.0.iter().fold(String::new(), |mut acc, b| { + write!(acc, "{b:02x}").expect("writing to string should not fail"); + acc + }); write!(f, "Ciphertext({hex})") } } impl EncryptionScheme { + #[must_use] pub fn encrypt( account: &Account, shared_secret: &SharedSecretKey, commitment: &Commitment, output_index: u32, ) -> Ciphertext { - let mut buffer = account.to_bytes().to_vec(); + let mut buffer = account.to_bytes().clone(); Self::symmetric_transform(&mut buffer, shared_secret, commitment, output_index); Ciphertext(buffer) } @@ -72,6 +78,7 @@ impl EncryptionScheme { } #[cfg(feature = "host")] + #[must_use] pub fn decrypt( ciphertext: &Ciphertext, shared_secret: &SharedSecretKey, @@ -79,7 +86,7 @@ impl EncryptionScheme { output_index: u32, ) -> Option { use std::io::Cursor; - let mut buffer = ciphertext.0.to_owned(); + let mut buffer = ciphertext.0.clone(); Self::symmetric_transform(&mut buffer, shared_secret, commitment, output_index); let mut cursor = Cursor::new(buffer.as_slice()); @@ -87,12 +94,12 @@ impl EncryptionScheme { .inspect_err(|err| { println!( "Failed to decode {ciphertext:?} \n - with secret {:?} ,\n + with secret {:?} ,\n commitment {commitment:?} ,\n and output_index {output_index} ,\n with error {err:?}", shared_secret.0 - ) + ); }) .ok() } diff --git a/nssa/core/src/encryption/shared_key_derivation.rs b/nssa/core/src/encryption/shared_key_derivation.rs index 6a6636b2..9e37668f 100644 --- a/nssa/core/src/encryption/shared_key_derivation.rs +++ b/nssa/core/src/encryption/shared_key_derivation.rs @@ -1,3 +1,5 @@ +use std::fmt::Write as _; + use borsh::{BorshDeserialize, BorshSerialize}; use k256::{ AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, @@ -15,12 +17,16 @@ pub struct Secp256k1Point(pub Vec); impl std::fmt::Debug for Secp256k1Point { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let hex: String = self.0.iter().map(|b| format!("{b:02x}")).collect(); + let hex: String = self.0.iter().fold(String::new(), |mut acc, b| { + write!(acc, "{b:02x}").expect("writing to string should not fail"); + acc + }); write!(f, "Secp256k1Point({hex})") } } impl Secp256k1Point { + #[must_use] pub fn from_scalar(value: Scalar) -> Secp256k1Point { let x_bytes: FieldBytes = value.into(); let x = k256::Scalar::from_repr(x_bytes).unwrap(); @@ -43,6 +49,8 @@ impl From<&EphemeralSecretKey> for EphemeralPublicKey { } impl SharedSecretKey { + /// Creates a new shared secret key from a scalar and a point. + #[must_use] pub fn new(scalar: &Scalar, point: &Secp256k1Point) -> Self { let scalar = k256::Scalar::from_repr((*scalar).into()).unwrap(); let point: [u8; 33] = point.0.clone().try_into().unwrap(); diff --git a/nssa/core/src/nullifier.rs b/nssa/core/src/nullifier.rs index 95006600..5038138f 100644 --- a/nssa/core/src/nullifier.rs +++ b/nssa/core/src/nullifier.rs @@ -28,10 +28,10 @@ impl AsRef<[u8]> for NullifierPublicKey { impl From<&NullifierSecretKey> for NullifierPublicKey { fn from(value: &NullifierSecretKey) -> Self { - let mut bytes = Vec::new(); const PREFIX: &[u8; 8] = b"LEE/keys"; const SUFFIX_1: &[u8; 1] = &[7]; const SUFFIX_2: &[u8; 23] = &[0; 23]; + let mut bytes = Vec::new(); bytes.extend_from_slice(PREFIX); bytes.extend_from_slice(value); bytes.extend_from_slice(SUFFIX_1); @@ -52,12 +52,19 @@ pub struct Nullifier(pub(super) [u8; 32]); #[cfg(any(feature = "host", test))] impl std::fmt::Debug for Nullifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let hex: String = self.0.iter().map(|b| format!("{b:02x}")).collect(); + use std::fmt::Write as _; + + let hex: String = self.0.iter().fold(String::new(), |mut acc, b| { + write!(acc, "{b:02x}").expect("writing to string should not fail"); + acc + }); write!(f, "Nullifier({hex})") } } impl Nullifier { + /// Computes a nullifier for an account update. + #[must_use] pub fn for_account_update(commitment: &Commitment, nsk: &NullifierSecretKey) -> Self { const UPDATE_PREFIX: &[u8; 32] = b"/NSSA/v0.2/Nullifier/Update/\x00\x00\x00\x00"; let mut bytes = UPDATE_PREFIX.to_vec(); @@ -66,6 +73,8 @@ impl Nullifier { Self(Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap()) } + /// Computes a nullifier for an account initialization. + #[must_use] pub fn for_account_initialization(npk: &NullifierPublicKey) -> Self { const INIT_PREFIX: &[u8; 32] = b"/NSSA/v0.2/Nullifier/Initialize/"; let mut bytes = INIT_PREFIX.to_vec(); diff --git a/nssa/core/src/program.rs b/nssa/core/src/program.rs index a6a04425..1b97b117 100644 --- a/nssa/core/src/program.rs +++ b/nssa/core/src/program.rs @@ -15,7 +15,7 @@ pub struct ProgramInput { pub instruction: T, } -/// A 32-byte seed used to compute a *Program-Derived AccountId* (PDA). +/// A 32-byte seed used to compute a *Program-Derived `AccountId`* (PDA). /// /// Each program can derive up to `2^256` unique account IDs by choosing different /// seeds. PDAs allow programs to control namespaced account identifiers without @@ -24,11 +24,13 @@ pub struct ProgramInput { pub struct PdaSeed([u8; 32]); impl PdaSeed { + #[must_use] pub const fn new(value: [u8; 32]) -> Self { Self(value) } } +#[must_use] pub fn compute_authorized_pdas( caller_program_id: Option, pda_seeds: &[PdaSeed], @@ -90,6 +92,7 @@ impl ChainedCall { } } + #[must_use] pub fn with_pda_seeds(mut self, pda_seeds: Vec) -> Self { self.pda_seeds = pda_seeds; self @@ -110,6 +113,7 @@ pub struct AccountPostState { impl AccountPostState { /// Creates a post state without a claim request. /// The executing program is not requesting ownership of the account. + #[must_use] pub fn new(account: Account) -> Self { Self { account, @@ -120,6 +124,7 @@ impl AccountPostState { /// Creates a post state that requests ownership of the account. /// This indicates that the executing program intends to claim the /// account as its own and is allowed to mutate it. + #[must_use] pub fn new_claimed(account: Account) -> Self { Self { account, @@ -129,6 +134,7 @@ impl AccountPostState { /// Creates a post state that requests ownership of the account /// if the account's program owner is the default program ID. + #[must_use] pub fn new_claimed_if_default(account: Account) -> Self { let claim = account.program_owner == DEFAULT_PROGRAM_ID; Self { account, claim } @@ -136,11 +142,13 @@ impl AccountPostState { /// Returns `true` if this post state requests that the account /// be claimed (owned) by the executing program. + #[must_use] pub fn requires_claim(&self) -> bool { self.claim } /// Returns the underlying account + #[must_use] pub fn account(&self) -> &Account { &self.account } @@ -151,6 +159,7 @@ impl AccountPostState { } /// Consumes the post state and returns the underlying account + #[must_use] pub fn into_account(self) -> Account { self.account } @@ -167,6 +176,8 @@ pub struct ProgramOutput { pub chained_calls: Vec, } +/// Reads the NSSA inputs from the guest environment. +#[must_use] pub fn read_nssa_inputs() -> (ProgramInput, InstructionData) { let pre_states: Vec = env::read(); let instruction_words: InstructionData = env::read(); @@ -215,6 +226,7 @@ pub fn write_nssa_outputs_with_chained_call( /// - `pre_states`: The list of input accounts, each annotated with authorization metadata. /// - `post_states`: The list of resulting accounts after executing the program logic. /// - `executing_program_id`: The identifier of the program that was executed. +#[must_use] pub fn validate_execution( pre_states: &[AccountWithMetadata], post_states: &[AccountPostState], diff --git a/nssa/src/encoding/privacy_preserving_transaction.rs b/nssa/src/encoding/privacy_preserving_transaction.rs index fcb6c943..6fe5c443 100644 --- a/nssa/src/encoding/privacy_preserving_transaction.rs +++ b/nssa/src/encoding/privacy_preserving_transaction.rs @@ -4,6 +4,7 @@ use crate::{ }; impl Message { + #[must_use] pub fn to_bytes(&self) -> Vec { borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } @@ -14,6 +15,7 @@ impl Message { } impl PrivacyPreservingTransaction { + #[must_use] pub fn to_bytes(&self) -> Vec { borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } diff --git a/nssa/src/encoding/program_deployment_transaction.rs b/nssa/src/encoding/program_deployment_transaction.rs index ee66863d..9b1b9406 100644 --- a/nssa/src/encoding/program_deployment_transaction.rs +++ b/nssa/src/encoding/program_deployment_transaction.rs @@ -1,6 +1,7 @@ use crate::{ProgramDeploymentTransaction, error::NssaError}; impl ProgramDeploymentTransaction { + #[must_use] pub fn to_bytes(&self) -> Vec { borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } diff --git a/nssa/src/encoding/public_transaction.rs b/nssa/src/encoding/public_transaction.rs index ea0988c7..2549cf27 100644 --- a/nssa/src/encoding/public_transaction.rs +++ b/nssa/src/encoding/public_transaction.rs @@ -7,6 +7,7 @@ impl Message { } impl PublicTransaction { + #[must_use] pub fn to_bytes(&self) -> Vec { borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } diff --git a/nssa/src/merkle_tree/mod.rs b/nssa/src/merkle_tree/mod.rs index 9c981b62..b15891b7 100644 --- a/nssa/src/merkle_tree/mod.rs +++ b/nssa/src/merkle_tree/mod.rs @@ -64,12 +64,12 @@ impl MerkleTree { let capacity = capacity.next_power_of_two(); let total_depth = capacity.trailing_zeros() as usize; - let nodes = default_values::DEFAULT_VALUES[..(total_depth + 1)] + let nodes = default_values::DEFAULT_VALUES[..=total_depth] .iter() .rev() .enumerate() .flat_map(|(level, default_value)| std::iter::repeat_n(default_value, 1 << level)) - .cloned() + .copied() .collect(); Self { @@ -164,7 +164,7 @@ mod tests { impl MerkleTree { pub fn new(values: &[Value]) -> Self { let mut this = Self::with_capacity(values.len()); - for value in values.iter().cloned() { + for value in values.iter().copied() { this.insert(value); } this @@ -201,7 +201,7 @@ mod tests { hex!("48c73f7821a58a8d2a703e5b39c571c0aa20cf14abcd0af8f2b955bc202998de"); assert_eq!(tree.root(), expected_root); assert_eq!(tree.capacity, 4); - assert_eq!(tree.length, 4) + assert_eq!(tree.length, 4); } #[test] @@ -283,15 +283,15 @@ mod tests { assert_eq!(tree.length, 0); assert_eq!(tree.nodes.len(), 15); for i in 7..15 { - assert_eq!(*tree.get_node(i), default_values::DEFAULT_VALUES[0]) + assert_eq!(*tree.get_node(i), default_values::DEFAULT_VALUES[0]); } for i in 3..7 { - assert_eq!(*tree.get_node(i), default_values::DEFAULT_VALUES[1]) + assert_eq!(*tree.get_node(i), default_values::DEFAULT_VALUES[1]); } for i in 1..3 { - assert_eq!(*tree.get_node(i), default_values::DEFAULT_VALUES[2]) + assert_eq!(*tree.get_node(i), default_values::DEFAULT_VALUES[2]); } - assert_eq!(*tree.get_node(0), default_values::DEFAULT_VALUES[3]) + assert_eq!(*tree.get_node(0), default_values::DEFAULT_VALUES[3]); } #[test] diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 98e0be24..25542aee 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -21,10 +21,12 @@ use crate::{ pub struct Proof(pub(crate) Vec); impl Proof { + #[must_use] pub fn into_inner(self) -> Vec { self.0 } + #[must_use] pub fn from_inner(inner: Vec) -> Self { Self(inner) } @@ -38,6 +40,7 @@ pub struct ProgramWithDependencies { } impl ProgramWithDependencies { + #[must_use] pub fn new(program: Program, dependencies: HashMap) -> Self { Self { program, @@ -74,7 +77,7 @@ pub fn execute_and_prove( let initial_call = ChainedCall { program_id: program.id(), - instruction_data: instruction_data.clone(), + instruction_data, pre_states, pda_seeds: vec![], }; @@ -217,7 +220,7 @@ mod tests { let expected_recipient_post = Account { program_owner: program.id(), balance: balance_to_move, - nonce: 0xdeadbeef, + nonce: 0xdead_beef, data: Data::default(), }; @@ -230,7 +233,7 @@ mod tests { vec![sender, recipient], Program::serialize_instruction(balance_to_move).unwrap(), vec![0, 2], - vec![0xdeadbeef], + vec![0xdead_beef], vec![(recipient_keys.npk(), shared_secret)], vec![], vec![None], @@ -267,7 +270,7 @@ mod tests { let sender_pre = AccountWithMetadata::new( Account { balance: 100, - nonce: 0xdeadbeef, + nonce: 0xdead_beef, program_owner: program.id(), data: Data::default(), }, @@ -302,13 +305,13 @@ mod tests { let expected_private_account_1 = Account { program_owner: program.id(), balance: 100 - balance_to_move, - nonce: 0xdeadbeef1, + nonce: 0xdead_beef1, ..Default::default() }; let expected_private_account_2 = Account { program_owner: program.id(), balance: balance_to_move, - nonce: 0xdeadbeef2, + nonce: 0xdead_beef2, ..Default::default() }; let expected_new_commitments = vec![ @@ -326,7 +329,7 @@ mod tests { vec![sender_pre.clone(), recipient], Program::serialize_instruction(balance_to_move).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ (sender_keys.npk(), shared_secret_1), (recipient_keys.npk(), shared_secret_2), diff --git a/nssa/src/privacy_preserving_transaction/message.rs b/nssa/src/privacy_preserving_transaction/message.rs index 844e746a..a0b9379c 100644 --- a/nssa/src/privacy_preserving_transaction/message.rs +++ b/nssa/src/privacy_preserving_transaction/message.rs @@ -20,8 +20,8 @@ pub struct EncryptedAccountData { impl EncryptedAccountData { fn new( ciphertext: Ciphertext, - npk: NullifierPublicKey, - vpk: ViewingPublicKey, + npk: &NullifierPublicKey, + vpk: &ViewingPublicKey, epk: EphemeralPublicKey, ) -> Self { let view_tag = Self::compute_view_tag(npk, vpk); @@ -33,7 +33,8 @@ impl EncryptedAccountData { } /// Computes the tag as the first byte of SHA256("/NSSA/v0.2/ViewTag/" || Npk || vpk) - pub fn compute_view_tag(npk: NullifierPublicKey, vpk: ViewingPublicKey) -> ViewTag { + #[must_use] + pub fn compute_view_tag(npk: &NullifierPublicKey, vpk: &ViewingPublicKey) -> ViewTag { let mut hasher = Sha256::new(); hasher.update(b"/NSSA/v0.2/ViewTag/"); hasher.update(npk.to_byte_array()); @@ -98,7 +99,7 @@ impl Message { .into_iter() .zip(public_keys) .map(|(ciphertext, (npk, vpk, epk))| { - EncryptedAccountData::new(ciphertext, npk, vpk, epk) + EncryptedAccountData::new(ciphertext, &npk, &vpk, epk) }) .collect(); Ok(Self { @@ -126,6 +127,7 @@ pub mod tests { privacy_preserving_transaction::message::{EncryptedAccountData, Message}, }; + #[must_use] pub fn message_for_tests() -> Message { let account1 = Account::default(); let account2 = Account::default(); @@ -173,7 +175,7 @@ pub mod tests { let epk = EphemeralPublicKey::from_scalar(esk); let ciphertext = EncryptionScheme::encrypt(&account, &shared_secret, &commitment, 2); let encrypted_account_data = - EncryptedAccountData::new(ciphertext.clone(), npk.clone(), vpk.clone(), epk.clone()); + EncryptedAccountData::new(ciphertext.clone(), &npk, &vpk, epk.clone()); let expected_view_tag = { let mut hasher = Sha256::new(); @@ -188,7 +190,7 @@ pub mod tests { assert_eq!(encrypted_account_data.epk, epk); assert_eq!( encrypted_account_data.view_tag, - EncryptedAccountData::compute_view_tag(npk, vpk) + EncryptedAccountData::compute_view_tag(&npk, &vpk) ); assert_eq!(encrypted_account_data.view_tag, expected_view_tag); } diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/nssa/src/privacy_preserving_transaction/transaction.rs index 9e0ca30a..1b89ea19 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/nssa/src/privacy_preserving_transaction/transaction.rs @@ -21,6 +21,7 @@ pub struct PrivacyPreservingTransaction { } impl PrivacyPreservingTransaction { + #[must_use] pub fn new(message: Message, witness_set: WitnessSet) -> Self { Self { message, @@ -119,19 +120,22 @@ impl PrivacyPreservingTransaction { Ok(message .public_account_ids .iter() - .cloned() + .copied() .zip(message.public_post_states.clone()) .collect()) } + #[must_use] pub fn message(&self) -> &Message { &self.message } + #[must_use] pub fn witness_set(&self) -> &WitnessSet { &self.witness_set } + #[must_use] pub fn hash(&self) -> [u8; 32] { let bytes = self.to_bytes(); let mut hasher = sha2::Sha256::new(); @@ -147,6 +151,7 @@ impl PrivacyPreservingTransaction { .collect() } + #[must_use] pub fn affected_public_account_ids(&self) -> Vec { let mut acc_set = self .signer_account_ids() diff --git a/nssa/src/privacy_preserving_transaction/witness_set.rs b/nssa/src/privacy_preserving_transaction/witness_set.rs index 365b61b9..df80c420 100644 --- a/nssa/src/privacy_preserving_transaction/witness_set.rs +++ b/nssa/src/privacy_preserving_transaction/witness_set.rs @@ -12,6 +12,7 @@ pub struct WitnessSet { } impl WitnessSet { + #[must_use] pub fn for_message(message: &Message, proof: Proof, private_keys: &[&PrivateKey]) -> Self { let message_bytes = message.to_bytes(); let signatures_and_public_keys = private_keys @@ -24,11 +25,12 @@ impl WitnessSet { }) .collect(); Self { - proof, signatures_and_public_keys, + proof, } } + #[must_use] pub fn signatures_are_valid_for(&self, message: &Message) -> bool { let message_bytes = message.to_bytes(); for (signature, public_key) in self.signatures_and_public_keys() { @@ -39,18 +41,22 @@ impl WitnessSet { true } + #[must_use] pub fn signatures_and_public_keys(&self) -> &[(Signature, PublicKey)] { &self.signatures_and_public_keys } + #[must_use] pub fn proof(&self) -> &Proof { &self.proof } + #[must_use] pub fn into_raw_parts(self) -> (Vec<(Signature, PublicKey)>, Proof) { (self.signatures_and_public_keys, self.proof) } + #[must_use] pub fn from_raw_parts( signatures_and_public_keys: Vec<(Signature, PublicKey)>, proof: Proof, diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 06c7ad29..29033a50 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -32,10 +32,12 @@ impl Program { Ok(Self { elf: bytecode, id }) } + #[must_use] pub fn id(&self) -> ProgramId { self.id } + #[must_use] pub fn elf(&self) -> &[u8] { &self.elf } @@ -85,18 +87,21 @@ impl Program { Ok(()) } + #[must_use] pub fn authenticated_transfer_program() -> Self { // This unwrap won't panic since the `AUTHENTICATED_TRANSFER_ELF` comes from risc0 build of // `program_methods` Self::new(AUTHENTICATED_TRANSFER_ELF.to_vec()).unwrap() } + #[must_use] pub fn token() -> Self { // This unwrap won't panic since the `TOKEN_ELF` comes from risc0 build of // `program_methods` Self::new(TOKEN_ELF.to_vec()).unwrap() } + #[must_use] pub fn amm() -> Self { Self::new(AMM_ELF.to_vec()).expect("The AMM program must be a valid Risc0 program") } @@ -104,12 +109,14 @@ impl Program { // TODO: Testnet only. Refactor to prevent compilation on mainnet. impl Program { + #[must_use] pub fn pinata() -> Self { // This unwrap won't panic since the `PINATA_ELF` comes from risc0 build of // `program_methods` Self::new(PINATA_ELF.to_vec()).unwrap() } + #[must_use] pub fn pinata_token() -> Self { use crate::program_methods::PINATA_TOKEN_ELF; Self::new(PINATA_TOKEN_ELF.to_vec()).expect("Piñata program must be a valid R0BF file") @@ -130,6 +137,7 @@ mod tests { impl Program { /// A program that changes the nonce of an account + #[must_use] pub fn nonce_changer_program() -> Self { use test_program_methods::{NONCE_CHANGER_ELF, NONCE_CHANGER_ID}; @@ -140,6 +148,7 @@ mod tests { } /// A program that produces more output accounts than the inputs it received + #[must_use] pub fn extra_output_program() -> Self { use test_program_methods::{EXTRA_OUTPUT_ELF, EXTRA_OUTPUT_ID}; @@ -150,6 +159,7 @@ mod tests { } /// A program that produces less output accounts than the inputs it received + #[must_use] pub fn missing_output_program() -> Self { use test_program_methods::{MISSING_OUTPUT_ELF, MISSING_OUTPUT_ID}; @@ -160,6 +170,7 @@ mod tests { } /// A program that changes the program owner of an account to [0, 1, 2, 3, 4, 5, 6, 7] + #[must_use] pub fn program_owner_changer() -> Self { use test_program_methods::{PROGRAM_OWNER_CHANGER_ELF, PROGRAM_OWNER_CHANGER_ID}; @@ -170,6 +181,7 @@ mod tests { } /// A program that transfers balance without caring about authorizations + #[must_use] pub fn simple_balance_transfer() -> Self { use test_program_methods::{SIMPLE_BALANCE_TRANSFER_ELF, SIMPLE_BALANCE_TRANSFER_ID}; @@ -180,6 +192,7 @@ mod tests { } /// A program that modifies the data of an account + #[must_use] pub fn data_changer() -> Self { use test_program_methods::{DATA_CHANGER_ELF, DATA_CHANGER_ID}; @@ -190,6 +203,7 @@ mod tests { } /// A program that mints balance + #[must_use] pub fn minter() -> Self { use test_program_methods::{MINTER_ELF, MINTER_ID}; @@ -200,6 +214,7 @@ mod tests { } /// A program that burns balance + #[must_use] pub fn burner() -> Self { use test_program_methods::{BURNER_ELF, BURNER_ID}; @@ -209,6 +224,7 @@ mod tests { } } + #[must_use] pub fn chain_caller() -> Self { use test_program_methods::{CHAIN_CALLER_ELF, CHAIN_CALLER_ID}; @@ -218,6 +234,7 @@ mod tests { } } + #[must_use] pub fn claimer() -> Self { use test_program_methods::{CLAIMER_ELF, CLAIMER_ID}; @@ -227,6 +244,7 @@ mod tests { } } + #[must_use] pub fn changer_claimer() -> Self { use test_program_methods::{CHANGER_CLAIMER_ELF, CHANGER_CLAIMER_ID}; @@ -236,6 +254,7 @@ mod tests { } } + #[must_use] pub fn noop() -> Self { use test_program_methods::{NOOP_ELF, NOOP_ID}; @@ -245,6 +264,7 @@ mod tests { } } + #[must_use] pub fn malicious_authorization_changer() -> Self { use test_program_methods::{ MALICIOUS_AUTHORIZATION_CHANGER_ELF, MALICIOUS_AUTHORIZATION_CHANGER_ID, @@ -256,6 +276,7 @@ mod tests { } } + #[must_use] pub fn modified_transfer_program() -> Self { use test_program_methods::MODIFIED_TRANSFER_ELF; // This unwrap won't panic since the `MODIFIED_TRANSFER_ELF` comes from risc0 build of @@ -267,11 +288,11 @@ mod tests { #[test] fn test_program_execution() { let program = Program::simple_balance_transfer(); - let balance_to_move: u128 = 11223344556677; + let balance_to_move: u128 = 11_223_344_556_677; let instruction_data = Program::serialize_instruction(balance_to_move).unwrap(); let sender = AccountWithMetadata::new( Account { - balance: 77665544332211, + balance: 77_665_544_332_211, ..Account::default() }, true, @@ -281,7 +302,7 @@ mod tests { AccountWithMetadata::new(Account::default(), false, AccountId::new([1; 32])); let expected_sender_post = Account { - balance: 77665544332211 - balance_to_move, + balance: 77_665_544_332_211 - balance_to_move, ..Account::default() }; let expected_recipient_post = Account { diff --git a/nssa/src/program_deployment_transaction/message.rs b/nssa/src/program_deployment_transaction/message.rs index 41c4e10a..1f8b7500 100644 --- a/nssa/src/program_deployment_transaction/message.rs +++ b/nssa/src/program_deployment_transaction/message.rs @@ -6,10 +6,12 @@ pub struct Message { } impl Message { + #[must_use] pub fn new(bytecode: Vec) -> Self { Self { bytecode } } + #[must_use] pub fn into_bytecode(self) -> Vec { self.bytecode } diff --git a/nssa/src/program_deployment_transaction/transaction.rs b/nssa/src/program_deployment_transaction/transaction.rs index 8e77bfe0..1cdb238a 100644 --- a/nssa/src/program_deployment_transaction/transaction.rs +++ b/nssa/src/program_deployment_transaction/transaction.rs @@ -12,10 +12,12 @@ pub struct ProgramDeploymentTransaction { } impl ProgramDeploymentTransaction { + #[must_use] pub fn new(message: Message) -> Self { Self { message } } + #[must_use] pub fn into_message(self) -> Message { self.message } @@ -33,6 +35,7 @@ impl ProgramDeploymentTransaction { } } + #[must_use] pub fn hash(&self) -> [u8; 32] { let bytes = self.to_bytes(); let mut hasher = sha2::Sha256::new(); @@ -40,6 +43,7 @@ impl ProgramDeploymentTransaction { hasher.finalize_fixed().into() } + #[must_use] pub fn affected_public_account_ids(&self) -> Vec { vec![] } diff --git a/nssa/src/public_transaction/message.rs b/nssa/src/public_transaction/message.rs index 776151cf..15eba285 100644 --- a/nssa/src/public_transaction/message.rs +++ b/nssa/src/public_transaction/message.rs @@ -49,6 +49,7 @@ impl Message { }) } + #[must_use] pub fn new_preserialized( program_id: ProgramId, account_ids: Vec, diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 06c61987..fdd55510 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -22,6 +22,7 @@ pub struct PublicTransaction { } impl PublicTransaction { + #[must_use] pub fn new(message: Message, witness_set: WitnessSet) -> Self { Self { message, @@ -29,10 +30,12 @@ impl PublicTransaction { } } + #[must_use] pub fn message(&self) -> &Message { &self.message } + #[must_use] pub fn witness_set(&self) -> &WitnessSet { &self.witness_set } @@ -45,6 +48,7 @@ impl PublicTransaction { .collect() } + #[must_use] pub fn affected_public_account_ids(&self) -> Vec { let mut acc_set = self .signer_account_ids() @@ -55,6 +59,7 @@ impl PublicTransaction { acc_set.into_iter().collect() } + #[must_use] pub fn hash(&self) -> [u8; 32] { let bytes = self.to_bytes(); let mut hasher = sha2::Sha256::new(); @@ -353,7 +358,7 @@ pub mod tests { let witness_set = WitnessSet::for_message(&message, &[&key1, &key1]); let tx = PublicTransaction::new(message, witness_set); let result = tx.validate_and_produce_public_state_diff(&state); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))) + assert!(matches!(result, Err(NssaError::InvalidInput(_)))); } #[test] @@ -373,7 +378,7 @@ pub mod tests { let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]); let tx = PublicTransaction::new(message, witness_set); let result = tx.validate_and_produce_public_state_diff(&state); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))) + assert!(matches!(result, Err(NssaError::InvalidInput(_)))); } #[test] @@ -394,7 +399,7 @@ pub mod tests { witness_set.signatures_and_public_keys[0].0 = Signature::new_for_tests([1; 64]); let tx = PublicTransaction::new(message, witness_set); let result = tx.validate_and_produce_public_state_diff(&state); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))) + assert!(matches!(result, Err(NssaError::InvalidInput(_)))); } #[test] @@ -414,7 +419,7 @@ pub mod tests { let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]); let tx = PublicTransaction::new(message, witness_set); let result = tx.validate_and_produce_public_state_diff(&state); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))) + assert!(matches!(result, Err(NssaError::InvalidInput(_)))); } #[test] @@ -423,13 +428,13 @@ pub mod tests { let state = state_for_tests(); let nonces = vec![0, 0]; let instruction = 1337; - let unknown_program_id = [0xdeadbeef; 8]; + let unknown_program_id = [0xdead_beef; 8]; let message = Message::try_new(unknown_program_id, vec![addr1, addr2], nonces, instruction).unwrap(); let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]); let tx = PublicTransaction::new(message, witness_set); let result = tx.validate_and_produce_public_state_diff(&state); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))) + assert!(matches!(result, Err(NssaError::InvalidInput(_)))); } } diff --git a/nssa/src/public_transaction/witness_set.rs b/nssa/src/public_transaction/witness_set.rs index 9b9cd290..db139d86 100644 --- a/nssa/src/public_transaction/witness_set.rs +++ b/nssa/src/public_transaction/witness_set.rs @@ -8,6 +8,7 @@ pub struct WitnessSet { } impl WitnessSet { + #[must_use] pub fn for_message(message: &Message, private_keys: &[&PrivateKey]) -> Self { let message_bytes = message.to_bytes(); let signatures_and_public_keys = private_keys @@ -24,6 +25,7 @@ impl WitnessSet { } } + #[must_use] pub fn is_valid_for(&self, message: &Message) -> bool { let message_bytes = message.to_bytes(); for (signature, public_key) in self.signatures_and_public_keys() { @@ -34,14 +36,17 @@ impl WitnessSet { true } + #[must_use] pub fn signatures_and_public_keys(&self) -> &[(Signature, PublicKey)] { &self.signatures_and_public_keys } + #[must_use] pub fn into_raw_parts(self) -> Vec<(Signature, PublicKey)> { self.signatures_and_public_keys } + #[must_use] pub fn from_raw_parts(signatures_and_public_keys: Vec<(Signature, PublicKey)>) -> Self { Self { signatures_and_public_keys, diff --git a/nssa/src/signature/bip340_test_vectors.rs b/nssa/src/signature/bip340_test_vectors.rs index 0e91bcb4..ae473b9c 100644 --- a/nssa/src/signature/bip340_test_vectors.rs +++ b/nssa/src/signature/bip340_test_vectors.rs @@ -14,7 +14,7 @@ pub struct TestVector { } /// Test vectors from -/// https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv +/// // pub fn test_vectors() -> Vec { vec![ diff --git a/nssa/src/signature/mod.rs b/nssa/src/signature/mod.rs index 24094c5d..7e2928ea 100644 --- a/nssa/src/signature/mod.rs +++ b/nssa/src/signature/mod.rs @@ -18,6 +18,7 @@ impl std::fmt::Debug for Signature { } impl Signature { + #[must_use] pub fn new(key: &PrivateKey, message: &[u8]) -> Self { let mut aux_random = [0u8; 32]; OsRng.fill_bytes(&mut aux_random); @@ -39,6 +40,7 @@ impl Signature { Self { value } } + #[must_use] pub fn is_valid_for(&self, bytes: &[u8], public_key: &PublicKey) -> bool { let pk = secp256k1::XOnlyPublicKey::from_byte_array(*public_key.value()).unwrap(); let secp = secp256k1::Secp256k1::new(); diff --git a/nssa/src/signature/private_key.rs b/nssa/src/signature/private_key.rs index 667fc306..03121a90 100644 --- a/nssa/src/signature/private_key.rs +++ b/nssa/src/signature/private_key.rs @@ -9,14 +9,14 @@ use crate::error::NssaError; pub struct PrivateKey([u8; 32]); impl PrivateKey { + #[must_use] pub fn new_os_random() -> Self { let mut rng = OsRng; loop { - match Self::try_new(rng.r#gen()) { - Ok(key) => break key, - Err(_) => continue, - }; + if let Ok(key) = Self::try_new(rng.r#gen()) { + break key; + } } } @@ -32,6 +32,7 @@ impl PrivateKey { } } + #[must_use] pub fn value(&self) -> &[u8; 32] { &self.0 } diff --git a/nssa/src/signature/public_key.rs b/nssa/src/signature/public_key.rs index 83fbf0cb..d916db23 100644 --- a/nssa/src/signature/public_key.rs +++ b/nssa/src/signature/public_key.rs @@ -29,6 +29,7 @@ impl BorshDeserialize for PublicKey { } impl PublicKey { + #[must_use] pub fn new_from_private_key(key: &PrivateKey) -> Self { let value = { let secret_key = secp256k1::SecretKey::from_byte_array(*key.value()).unwrap(); @@ -47,6 +48,7 @@ impl PublicKey { Ok(Self(value)) } + #[must_use] pub fn value(&self) -> &[u8; 32] { &self.0 } diff --git a/nssa/src/state.rs b/nssa/src/state.rs index c8599d97..2c99556f 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -52,8 +52,8 @@ impl CommitmentSet { } /// Initializes an empty `CommitmentSet` with a given capacity. - /// If the capacity is not a power_of_two, then capacity is taken - /// to be the next power_of_two. + /// If the capacity is not a `power_of_two`, then capacity is taken + /// to be the next `power_of_two`. pub(crate) fn with_capacity(capacity: usize) -> CommitmentSet { Self { merkle_tree: MerkleTree::with_capacity(capacity), @@ -114,6 +114,7 @@ pub struct V02State { } impl V02State { + #[must_use] pub fn new_with_genesis_accounts( initial_data: &[(AccountId, u128)], initial_commitments: &[nssa_core::Commitment], @@ -159,7 +160,7 @@ impl V02State { ) -> Result<(), NssaError> { let state_diff = tx.validate_and_produce_public_state_diff(self)?; - for (account_id, post) in state_diff.into_iter() { + for (account_id, post) in state_diff { let current_account = self.get_account_by_id_mut(account_id); *current_account = post; @@ -195,7 +196,7 @@ impl V02State { self.private_state.1.extend(new_nullifiers); // 4. Update public accounts - for (account_id, post) in public_state_diff.into_iter() { + for (account_id, post) in public_state_diff { let current_account = self.get_account_by_id_mut(account_id); *current_account = post; } @@ -222,6 +223,7 @@ impl V02State { self.public_state.entry(account_id).or_default() } + #[must_use] pub fn get_account_by_id(&self, account_id: AccountId) -> Account { self.public_state .get(&account_id) @@ -229,6 +231,7 @@ impl V02State { .unwrap_or(Account::default()) } + #[must_use] pub fn get_proof_for_commitment(&self, commitment: &Commitment) -> Option { self.private_state.0.get_proof_for(commitment) } @@ -237,6 +240,7 @@ impl V02State { &self.programs } + #[must_use] pub fn commitment_set_digest(&self) -> CommitmentSetDigest { self.private_state.0.digest() } @@ -245,7 +249,7 @@ impl V02State { &self, new_commitments: &[Commitment], ) -> Result<(), NssaError> { - for commitment in new_commitments.iter() { + for commitment in new_commitments { if self.private_state.0.contains(commitment) { return Err(NssaError::InvalidInput( "Commitment already seen".to_string(), @@ -259,7 +263,7 @@ impl V02State { &self, new_nullifiers: &[(Nullifier, CommitmentSetDigest)], ) -> Result<(), NssaError> { - for (nullifier, digest) in new_nullifiers.iter() { + for (nullifier, digest) in new_nullifiers { if self.private_state.1.contains(nullifier) { return Err(NssaError::InvalidInput( "Nullifier already seen".to_string(), @@ -284,7 +288,7 @@ impl V02State { account_id, Account { program_owner: Program::pinata().id(), - balance: 1500000, + balance: 1_500_000, // Difficulty: 3 data: vec![3; 33].try_into().expect("should fit"), nonce: 0, @@ -339,7 +343,7 @@ pub mod tests { fn transfer_transaction( from: AccountId, - from_key: PrivateKey, + from_key: &PrivateKey, nonce: u128, to: AccountId, balance: u128, @@ -349,7 +353,7 @@ pub mod tests { let program_id = Program::authenticated_transfer_program().id(); let message = public_transaction::Message::try_new(program_id, account_ids, nonces, balance).unwrap(); - let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]); + let witness_set = public_transaction::WitnessSet::for_message(&message, &[from_key]); PublicTransaction::new(message, witness_set) } @@ -454,7 +458,7 @@ pub mod tests { assert_eq!(state.get_account_by_id(to), Account::default()); let balance_to_move = 5; - let tx = transfer_transaction(from, key, 0, to, balance_to_move); + let tx = transfer_transaction(from, &key, 0, to, balance_to_move); state.transition_from_public_transaction(&tx).unwrap(); assert_eq!(state.get_account_by_id(from).balance, 95); @@ -475,7 +479,7 @@ pub mod tests { let balance_to_move = 101; assert!(state.get_account_by_id(from).balance < balance_to_move); - let tx = transfer_transaction(from, from_key, 0, to, balance_to_move); + let tx = transfer_transaction(from, &from_key, 0, to, balance_to_move); let result = state.transition_from_public_transaction(&tx); assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_)))); @@ -499,7 +503,7 @@ pub mod tests { assert_ne!(state.get_account_by_id(to), Account::default()); let balance_to_move = 8; - let tx = transfer_transaction(from, from_key, 0, to, balance_to_move); + let tx = transfer_transaction(from, &from_key, 0, to, balance_to_move); state.transition_from_public_transaction(&tx).unwrap(); assert_eq!(state.get_account_by_id(from).balance, 192); @@ -519,10 +523,10 @@ pub mod tests { let account_id3 = AccountId::new([3; 32]); let balance_to_move = 5; - let tx = transfer_transaction(account_id1, key1, 0, account_id2, balance_to_move); + let tx = transfer_transaction(account_id1, &key1, 0, account_id2, balance_to_move); state.transition_from_public_transaction(&tx).unwrap(); let balance_to_move = 3; - let tx = transfer_transaction(account_id2, key2, 0, account_id3, balance_to_move); + let tx = transfer_transaction(account_id2, &key2, 0, account_id3, balance_to_move); state.transition_from_public_transaction(&tx).unwrap(); assert_eq!(state.get_account_by_id(account_id1).balance, 95); @@ -539,6 +543,7 @@ pub mod tests { } /// Include test programs in the builtin programs map + #[must_use] pub fn with_test_programs(mut self) -> Self { self.insert_program(Program::nonce_changer_program()); self.insert_program(Program::extra_output_program()); @@ -555,6 +560,7 @@ pub mod tests { self } + #[must_use] pub fn with_non_default_accounts_but_default_program_owners(mut self) -> Self { let account_with_default_values_except_balance = Account { balance: 100, @@ -583,6 +589,7 @@ pub mod tests { self } + #[must_use] pub fn with_account_owned_by_burner_program(mut self) -> Self { let account = Account { program_owner: Program::burner().id(), @@ -593,6 +600,7 @@ pub mod tests { self } + #[must_use] pub fn with_private_account(mut self, keys: &TestPrivateKeys, account: &Account) -> Self { let commitment = Commitment::new(&keys.npk(), account); self.private_state.0.extend(&[commitment]); @@ -916,7 +924,7 @@ pub mod tests { vec![sender, recipient], Program::serialize_instruction(balance_to_move).unwrap(), vec![0, 2], - vec![0xdeadbeef], + vec![0xdead_beef], vec![(recipient_keys.npk(), shared_secret)], vec![], vec![None], @@ -1084,7 +1092,7 @@ pub mod tests { let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100, - nonce: 0xdeadbeef, + nonce: 0xdead_beef, data: Data::default(), }; let recipient_keys = test_private_account_keys_2(); @@ -1099,7 +1107,7 @@ pub mod tests { &sender_private_account, &recipient_keys, balance_to_move, - [0xcafecafe, 0xfecafeca], + [0xcafe_cafe, 0xfeca_feca], &state, ); @@ -1107,7 +1115,7 @@ pub mod tests { &sender_keys.npk(), &Account { program_owner: Program::authenticated_transfer_program().id(), - nonce: 0xcafecafe, + nonce: 0xcafe_cafe, balance: sender_private_account.balance - balance_to_move, data: Data::default(), }, @@ -1121,7 +1129,7 @@ pub mod tests { &recipient_keys.npk(), &Account { program_owner: Program::authenticated_transfer_program().id(), - nonce: 0xfecafeca, + nonce: 0xfeca_feca, balance: balance_to_move, ..Account::default() }, @@ -1150,7 +1158,7 @@ pub mod tests { let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100, - nonce: 0xdeadbeef, + nonce: 0xdead_beef, data: Data::default(), }; let recipient_keys = test_public_account_keys_1(); @@ -1174,7 +1182,7 @@ pub mod tests { &sender_private_account, &recipient_keys.account_id(), balance_to_move, - 0xcafecafe, + 0xcafe_cafe, &state, ); @@ -1182,7 +1190,7 @@ pub mod tests { &sender_keys.npk(), &Account { program_owner: Program::authenticated_transfer_program().id(), - nonce: 0xcafecafe, + nonce: 0xcafe_cafe, balance: sender_private_account.balance - balance_to_move, data: Data::default(), }, @@ -1333,7 +1341,12 @@ pub mod tests { ); let large_data: Vec = - vec![0; nssa_core::account::data::DATA_MAX_LENGTH.as_u64() as usize + 1]; + vec![ + 0; + usize::try_from(nssa_core::account::data::DATA_MAX_LENGTH.as_u64()) + .expect("DATA_MAX_LENGTH fits in usize") + + 1 + ]; let result = execute_and_prove( vec![public_account], @@ -1343,7 +1356,7 @@ pub mod tests { vec![], vec![], vec![], - &program.to_owned().into(), + &program.clone().into(), ); assert!(matches!(result, Err(NssaError::ProgramProveFailed(_)))); @@ -1531,7 +1544,7 @@ pub mod tests { AccountWithMetadata::new(Account::default(), false, &recipient_keys.npk()); // Setting only one nonce for an execution with two private accounts. - let private_account_nonces = [0xdeadbeef1]; + let private_account_nonces = [0xdead_beef1]; let result = execute_and_prove( vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), @@ -1580,7 +1593,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], private_account_keys.to_vec(), vec![sender_keys.nsk], vec![Some((0, vec![]))], @@ -1613,7 +1626,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1655,7 +1668,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1713,7 +1726,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], private_account_keys.to_vec(), private_account_nsks.to_vec(), private_account_membership_proofs.to_vec(), @@ -1751,7 +1764,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1799,7 +1812,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1846,7 +1859,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1882,7 +1895,7 @@ pub mod tests { let private_account_2 = AccountWithMetadata::new( Account { // Non default nonce - nonce: 0xdeadbeef, + nonce: 0xdead_beef, ..Account::default() }, false, @@ -1893,7 +1906,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -1938,7 +1951,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -2006,7 +2019,7 @@ pub mod tests { // Setting three new private account nonces for a circuit execution with only two private // accounts. - let private_account_nonces = [0xdeadbeef1, 0xdeadbeef2, 0xdeadbeef3]; + let private_account_nonces = [0xdead_beef1, 0xdead_beef2, 0xdead_beef3]; let result = execute_and_prove( vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), @@ -2067,7 +2080,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), vec![1, 2], - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], private_account_keys.to_vec(), vec![sender_keys.nsk], vec![Some((0, vec![]))], @@ -2103,7 +2116,7 @@ pub mod tests { vec![private_account_1, private_account_2], Program::serialize_instruction(10u128).unwrap(), visibility_mask.to_vec(), - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ ( sender_keys.npk(), @@ -2128,7 +2141,7 @@ pub mod tests { let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100, - nonce: 0xdeadbeef, + nonce: 0xdead_beef, data: Data::default(), }; let recipient_keys = test_private_account_keys_2(); @@ -2143,7 +2156,7 @@ pub mod tests { &sender_private_account, &recipient_keys, balance_to_move, - [0xcafecafe, 0xfecafeca], + [0xcafe_cafe, 0xfeca_feca], &state, ); @@ -2154,7 +2167,7 @@ pub mod tests { let sender_private_account = Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100 - balance_to_move, - nonce: 0xcafecafe, + nonce: 0xcafe_cafe, data: Data::default(), }; @@ -2199,7 +2212,7 @@ pub mod tests { vec![private_account_1.clone(), private_account_1], Program::serialize_instruction(100u128).unwrap(), visibility_mask.to_vec(), - vec![0xdeadbeef1, 0xdeadbeef2], + vec![0xdead_beef1, 0xdead_beef2], vec![ (sender_keys.npk(), shared_secret), (sender_keys.npk(), shared_secret), @@ -2308,7 +2321,8 @@ pub mod tests { let instruction: (u128, ProgramId, u32, Option) = ( amount, Program::authenticated_transfer_program().id(), - MAX_NUMBER_CHAINED_CALLS as u32 + 1, + u32::try_from(MAX_NUMBER_CHAINED_CALLS).expect("MAX_NUMBER_CHAINED_CALLS fits in u32") + + 1, None, ); @@ -3829,18 +3843,18 @@ pub mod tests { dependencies.insert(auth_transfers.id(), auth_transfers); let program_with_deps = ProgramWithDependencies::new(chain_caller, dependencies); - let from_new_nonce = 0xdeadbeef1; - let to_new_nonce = 0xdeadbeef2; + let from_new_nonce = 0xdead_beef1; + let to_new_nonce = 0xdead_beef2; let from_expected_post = Account { - balance: initial_balance - number_of_calls as u128 * amount, + balance: initial_balance - u128::from(number_of_calls) * amount, nonce: from_new_nonce, ..from_account.account.clone() }; let from_expected_commitment = Commitment::new(&from_keys.npk(), &from_expected_post); let to_expected_post = Account { - balance: number_of_calls as u128 * amount, + balance: u128::from(number_of_calls) * amount, nonce: to_new_nonce, ..to_account.account.clone() }; @@ -3948,7 +3962,7 @@ pub mod tests { state.transition_from_public_transaction(&tx).unwrap(); // Submit a solution to the pinata program to claim the prize - let solution: u128 = 989106; + let solution: u128 = 989_106; let message = public_transaction::Message::try_new( pinata_token.id(), vec![ @@ -3994,7 +4008,7 @@ pub mod tests { let result = state.transition_from_public_transaction(&tx); - assert!(matches!(result, Err(NssaError::InvalidProgramBehavior))) + assert!(matches!(result, Err(NssaError::InvalidProgramBehavior))); } /// This test ensures that even if a malicious program tries to perform overflow of balances @@ -4083,7 +4097,7 @@ pub mod tests { // Balance to initialize the account with (0 for a new account) let balance: u128 = 0; - let nonce = 0xdeadbeef1; + let nonce = 0xdead_beef1; // Execute and prove the circuit with the authorized account but no commitment proof let (output, proof) = execute_and_prove( @@ -4136,7 +4150,7 @@ pub mod tests { let epk = EphemeralPublicKey::from_scalar(esk); let balance: u128 = 0; - let nonce = 0xdeadbeef1; + let nonce = 0xdead_beef1; // Step 2: Execute claimer program to claim the account with authentication let (output, proof) = execute_and_prove( @@ -4184,7 +4198,7 @@ pub mod tests { let esk2 = [4; 32]; let shared_secret2 = SharedSecretKey::new(&esk2, &private_keys.vpk()); - let nonce2 = 0xdeadbeef2; + let nonce2 = 0xdead_beef2; // Step 3: Try to execute noop program with authentication but without initialization let res = execute_and_prove( @@ -4341,7 +4355,7 @@ pub mod tests { dependencies.insert(auth_transfers.id(), auth_transfers); let program_with_deps = ProgramWithDependencies::new(malicious_program, dependencies); - let recipient_new_nonce = 0xdeadbeef1; + let recipient_new_nonce = 0xdead_beef1; // Act - execute the malicious program - this should fail during proving let result = execute_and_prove( diff --git a/program_methods/guest/src/bin/authenticated_transfer.rs b/program_methods/guest/src/bin/authenticated_transfer.rs index 8a13173a..43f06c56 100644 --- a/program_methods/guest/src/bin/authenticated_transfer.rs +++ b/program_methods/guest/src/bin/authenticated_transfer.rs @@ -7,18 +7,17 @@ use nssa_core::{ /// Initializes a default account under the ownership of this program. fn initialize_account(pre_state: AccountWithMetadata) -> AccountPostState { - let account_to_claim = AccountPostState::new_claimed(pre_state.account.clone()); + let account_to_claim = AccountPostState::new_claimed(pre_state.account); let is_authorized = pre_state.is_authorized; // Continue only if the account to claim has default values - if account_to_claim.account() != &Account::default() { - panic!("Account must be uninitialized"); - } + assert!( + account_to_claim.account() == &Account::default(), + "Account must be uninitialized" + ); // Continue only if the owner authorized this operation - if !is_authorized { - panic!("Account must be authorized"); - } + assert!(is_authorized, "Account must be authorized"); account_to_claim } @@ -30,26 +29,25 @@ fn transfer( balance_to_move: u128, ) -> Vec { // Continue only if the sender has authorized this operation - if !sender.is_authorized { - panic!("Sender must be authorized"); - } + assert!(sender.is_authorized, "Sender must be authorized"); // Continue only if the sender has enough balance - if sender.account.balance < balance_to_move { - panic!("Sender has insufficient balance"); - } + assert!( + sender.account.balance >= balance_to_move, + "Sender has insufficient balance" + ); // Create accounts post states, with updated balances let sender_post = { // Modify sender's balance - let mut sender_post_account = sender.account.clone(); + let mut sender_post_account = sender.account; sender_post_account.balance -= balance_to_move; AccountPostState::new(sender_post_account) }; let recipient_post = { // Modify recipient's balance - let mut recipient_post_account = recipient.account.clone(); + let mut recipient_post_account = recipient.account; recipient_post_account.balance += balance_to_move; // Claim recipient account if it has default program owner diff --git a/program_methods/guest/src/bin/pinata.rs b/program_methods/guest/src/bin/pinata.rs index 0dc3c108..70d76db2 100644 --- a/program_methods/guest/src/bin/pinata.rs +++ b/program_methods/guest/src/bin/pinata.rs @@ -52,9 +52,8 @@ fn main() { instruction_words, ) = read_nssa_inputs::(); - let [pinata, winner] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([pinata, winner]) = <[_; 2]>::try_from(pre_states) else { + return; }; let data = Challenge::new(&pinata.account.data); diff --git a/program_methods/guest/src/bin/pinata_token.rs b/program_methods/guest/src/bin/pinata_token.rs index 188597cb..e0b269a4 100644 --- a/program_methods/guest/src/bin/pinata_token.rs +++ b/program_methods/guest/src/bin/pinata_token.rs @@ -59,13 +59,15 @@ fn main() { instruction_words, ) = read_nssa_inputs::(); - let [ - pinata_definition, - pinata_token_holding, - winner_token_holding, - ] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok( + [ + pinata_definition, + pinata_token_holding, + winner_token_holding, + ], + ) = <[_; 3]>::try_from(pre_states) + else { + return; }; let data = Challenge::new(&pinata_definition.account.data); diff --git a/program_methods/guest/src/bin/privacy_preserving_circuit.rs b/program_methods/guest/src/bin/privacy_preserving_circuit.rs index 4bbd895f..51dd4c4c 100644 --- a/program_methods/guest/src/bin/privacy_preserving_circuit.rs +++ b/program_methods/guest/src/bin/privacy_preserving_circuit.rs @@ -113,7 +113,7 @@ impl ExecutionState { ); execution_state.validate_and_sync_states( chained_call.program_id, - authorized_pdas, + &authorized_pdas, program_output.pre_states, program_output.post_states, ); @@ -153,7 +153,7 @@ impl ExecutionState { fn validate_and_sync_states( &mut self, program_id: ProgramId, - authorized_pdas: HashSet, + authorized_pdas: &HashSet, pre_states: Vec, post_states: Vec, ) { @@ -173,12 +173,12 @@ impl ExecutionState { .pre_states .iter() .find(|acc| acc.account_id == pre_account_id) - .map(|acc| acc.is_authorized) - .unwrap_or_else(|| { - panic!( + .map_or_else( + || panic!( "Pre state must exist in execution state for account {pre_account_id:?}", - ) - }); + ), + |acc| acc.is_authorized + ); let is_authorized = previous_is_authorized || authorized_pdas.contains(&pre_account_id); @@ -379,18 +379,8 @@ fn compute_nullifier_and_set_digest( npk: &NullifierPublicKey, nsk: &NullifierSecretKey, ) -> (Nullifier, CommitmentSetDigest) { - membership_proof_opt - .as_ref() - .map(|membership_proof| { - // Compute commitment set digest associated with provided auth path - let commitment_pre = Commitment::new(npk, pre_account); - let set_digest = compute_digest_for_path(&commitment_pre, membership_proof); - - // Compute update nullifier - let nullifier = Nullifier::for_account_update(&commitment_pre, nsk); - (nullifier, set_digest) - }) - .unwrap_or_else(|| { + membership_proof_opt.as_ref().map_or_else( + || { assert_eq!( *pre_account, Account::default(), @@ -400,5 +390,15 @@ fn compute_nullifier_and_set_digest( // Compute initialization nullifier let nullifier = Nullifier::for_account_initialization(npk); (nullifier, DUMMY_COMMITMENT_HASH) - }) + }, + |membership_proof| { + // Compute commitment set digest associated with provided auth path + let commitment_pre = Commitment::new(npk, pre_account); + let set_digest = compute_digest_for_path(&commitment_pre, membership_proof); + + // Compute update nullifier + let nullifier = Nullifier::for_account_update(&commitment_pre, nsk); + (nullifier, set_digest) + }, + ) } diff --git a/programs/amm/core/src/lib.rs b/programs/amm/core/src/lib.rs index f9d20dd3..128460a2 100644 --- a/programs/amm/core/src/lib.rs +++ b/programs/amm/core/src/lib.rs @@ -89,7 +89,7 @@ pub struct PoolDefinition { pub fees: u128, /// A pool becomes inactive (active = false) /// once all of its liquidity has been removed (e.g., reserves are emptied and - /// liquidity_pool_supply = 0) + /// `liquidity_pool_supply` = 0) pub active: bool, } @@ -113,6 +113,7 @@ impl From<&PoolDefinition> for Data { } } +#[must_use] pub fn compute_pool_pda( amm_program_id: ProgramId, definition_token_a_id: AccountId, @@ -124,6 +125,7 @@ pub fn compute_pool_pda( )) } +#[must_use] pub fn compute_pool_pda_seed( definition_token_a_id: AccountId, definition_token_b_id: AccountId, @@ -151,6 +153,7 @@ pub fn compute_pool_pda_seed( ) } +#[must_use] pub fn compute_vault_pda( amm_program_id: ProgramId, pool_id: AccountId, @@ -162,6 +165,7 @@ pub fn compute_vault_pda( )) } +#[must_use] pub fn compute_vault_pda_seed(pool_id: AccountId, definition_token_id: AccountId) -> PdaSeed { use risc0_zkvm::sha::{Impl, Sha256}; @@ -177,10 +181,12 @@ pub fn compute_vault_pda_seed(pool_id: AccountId, definition_token_id: AccountId ) } +#[must_use] pub fn compute_liquidity_token_pda(amm_program_id: ProgramId, pool_id: AccountId) -> AccountId { AccountId::from((&amm_program_id, &compute_liquidity_token_pda_seed(pool_id))) } +#[must_use] pub fn compute_liquidity_token_pda_seed(pool_id: AccountId) -> PdaSeed { use risc0_zkvm::sha::{Impl, Sha256}; diff --git a/programs/amm/src/add.rs b/programs/amm/src/add.rs index 28b4661c..0a926b3b 100644 --- a/programs/amm/src/add.rs +++ b/programs/amm/src/add.rs @@ -7,6 +7,7 @@ use nssa_core::{ }; #[expect(clippy::too_many_arguments, reason = "TODO: Fix later")] +#[must_use] pub fn add_liquidity( pool: AccountWithMetadata, vault_a: AccountWithMetadata, @@ -123,7 +124,7 @@ pub fn add_liquidity( ); // 5. Update pool account - let mut pool_post = pool.account.clone(); + let mut pool_post = pool.account; let pool_post_definition = PoolDefinition { liquidity_pool_supply: pool_def_data.liquidity_pool_supply + delta_lp, reserve_a: pool_def_data.reserve_a + actual_amount_a, @@ -166,12 +167,12 @@ pub fn add_liquidity( let post_states = vec![ AccountPostState::new(pool_post), - AccountPostState::new(vault_a.account.clone()), - AccountPostState::new(vault_b.account.clone()), - AccountPostState::new(pool_definition_lp.account.clone()), - AccountPostState::new(user_holding_a.account.clone()), - AccountPostState::new(user_holding_b.account.clone()), - AccountPostState::new(user_holding_lp.account.clone()), + AccountPostState::new(vault_a.account), + AccountPostState::new(vault_b.account), + AccountPostState::new(pool_definition_lp.account), + AccountPostState::new(user_holding_a.account), + AccountPostState::new(user_holding_b.account), + AccountPostState::new(user_holding_lp.account), ]; (post_states, chained_calls) diff --git a/programs/amm/src/new_definition.rs b/programs/amm/src/new_definition.rs index af54adce..b3642349 100644 --- a/programs/amm/src/new_definition.rs +++ b/programs/amm/src/new_definition.rs @@ -10,6 +10,7 @@ use nssa_core::{ }; #[expect(clippy::too_many_arguments, reason = "TODO: Fix later")] +#[must_use] pub fn new_definition( pool: AccountWithMetadata, vault_a: AccountWithMetadata, @@ -79,8 +80,20 @@ pub fn new_definition( // LP Token minting calculation let initial_lp = (token_a_amount.get() * token_b_amount.get()).isqrt(); + // Chain call for liquidity token (TokenLP definition -> User LP Holding) + let instruction = if pool.account == Account::default() { + token_core::Instruction::NewFungibleDefinition { + name: String::from("LP Token"), + total_supply: initial_lp, + } + } else { + token_core::Instruction::Mint { + amount_to_mint: initial_lp, + } + }; + // Update pool account - let mut pool_post = pool.account.clone(); + let mut pool_post = pool.account; let pool_post_definition = PoolDefinition { definition_token_a_id, definition_token_b_id, @@ -95,11 +108,7 @@ pub fn new_definition( }; pool_post.data = Data::from(&pool_post_definition); - let pool_post: AccountPostState = if pool.account == Account::default() { - AccountPostState::new_claimed(pool_post.clone()) - } else { - AccountPostState::new(pool_post.clone()) - }; + let pool_post = AccountPostState::new_claimed_if_default(pool_post); let token_program_id = user_holding_a.account.program_owner; @@ -120,18 +129,6 @@ pub fn new_definition( }, ); - // Chain call for liquidity token (TokenLP definition -> User LP Holding) - let instruction = if pool.account == Account::default() { - token_core::Instruction::NewFungibleDefinition { - name: String::from("LP Token"), - total_supply: initial_lp, - } - } else { - token_core::Instruction::Mint { - amount_to_mint: initial_lp, - } - }; - let mut pool_lp_auth = pool_definition_lp.clone(); pool_lp_auth.is_authorized = true; @@ -145,13 +142,13 @@ pub fn new_definition( let chained_calls = vec![call_token_lp, call_token_b, call_token_a]; let post_states = vec![ - pool_post.clone(), - AccountPostState::new(vault_a.account.clone()), - AccountPostState::new(vault_b.account.clone()), - AccountPostState::new(pool_definition_lp.account.clone()), - AccountPostState::new(user_holding_a.account.clone()), - AccountPostState::new(user_holding_b.account.clone()), - AccountPostState::new(user_holding_lp.account.clone()), + pool_post, + AccountPostState::new(vault_a.account), + AccountPostState::new(vault_b.account), + AccountPostState::new(pool_definition_lp.account), + AccountPostState::new(user_holding_a.account), + AccountPostState::new(user_holding_b.account), + AccountPostState::new(user_holding_lp.account), ]; (post_states.clone(), chained_calls) diff --git a/programs/amm/src/remove.rs b/programs/amm/src/remove.rs index 370b3609..d8c7ced5 100644 --- a/programs/amm/src/remove.rs +++ b/programs/amm/src/remove.rs @@ -7,6 +7,7 @@ use nssa_core::{ }; #[expect(clippy::too_many_arguments, reason = "TODO: Fix later")] +#[must_use] pub fn remove_liquidity( pool: AccountWithMetadata, vault_a: AccountWithMetadata, @@ -101,7 +102,7 @@ pub fn remove_liquidity( let active: bool = pool_def_data.liquidity_pool_supply - delta_lp != 0; // 5. Update pool account - let mut pool_post = pool.account.clone(); + let mut pool_post = pool.account; let pool_post_definition = PoolDefinition { liquidity_pool_supply: pool_def_data.liquidity_pool_supply - delta_lp, reserve_a: pool_def_data.reserve_a - withdraw_amount_a, @@ -153,13 +154,13 @@ pub fn remove_liquidity( let chained_calls = vec![call_token_lp, call_token_b, call_token_a]; let post_states = vec![ - AccountPostState::new(pool_post.clone()), - AccountPostState::new(vault_a.account.clone()), - AccountPostState::new(vault_b.account.clone()), - AccountPostState::new(pool_definition_lp.account.clone()), - AccountPostState::new(user_holding_a.account.clone()), - AccountPostState::new(user_holding_b.account.clone()), - AccountPostState::new(user_holding_lp.account.clone()), + AccountPostState::new(pool_post), + AccountPostState::new(vault_a.account), + AccountPostState::new(vault_b.account), + AccountPostState::new(pool_definition_lp.account), + AccountPostState::new(user_holding_a.account), + AccountPostState::new(user_holding_b.account), + AccountPostState::new(user_holding_lp.account), ]; (post_states, chained_calls) diff --git a/programs/amm/src/swap.rs b/programs/amm/src/swap.rs index aa02ac24..cb64f5eb 100644 --- a/programs/amm/src/swap.rs +++ b/programs/amm/src/swap.rs @@ -5,6 +5,7 @@ use nssa_core::{ }; #[expect(clippy::too_many_arguments, reason = "TODO: Fix later")] +#[must_use] pub fn swap( pool: AccountWithMetadata, vault_a: AccountWithMetadata, @@ -95,7 +96,7 @@ pub fn swap( }; // Update pool account - let mut pool_post = pool.account.clone(); + let mut pool_post = pool.account; let pool_post_definition = PoolDefinition { reserve_a: pool_def_data.reserve_a + deposit_a - withdraw_a, reserve_b: pool_def_data.reserve_b + deposit_b - withdraw_b, @@ -105,11 +106,11 @@ pub fn swap( pool_post.data = Data::from(&pool_post_definition); let post_states = vec![ - AccountPostState::new(pool_post.clone()), - AccountPostState::new(vault_a.account.clone()), - AccountPostState::new(vault_b.account.clone()), - AccountPostState::new(user_holding_a.account.clone()), - AccountPostState::new(user_holding_b.account.clone()), + AccountPostState::new(pool_post), + AccountPostState::new(vault_a.account), + AccountPostState::new(vault_b.account), + AccountPostState::new(user_holding_a.account), + AccountPostState::new(user_holding_b.account), ]; (post_states, chained_calls) @@ -151,7 +152,7 @@ fn swap_logic( }, )); - let mut vault_withdraw = vault_withdraw.clone(); + let mut vault_withdraw = vault_withdraw; vault_withdraw.is_authorized = true; let pda_seed = compute_vault_pda_seed( diff --git a/programs/token/core/src/lib.rs b/programs/token/core/src/lib.rs index 140ae38f..f96e10e2 100644 --- a/programs/token/core/src/lib.rs +++ b/programs/token/core/src/lib.rs @@ -127,6 +127,7 @@ pub enum TokenHolding { } impl TokenHolding { + #[must_use] pub fn zeroized_clone_from(other: &Self) -> Self { match other { TokenHolding::Fungible { definition_id, .. } => TokenHolding::Fungible { @@ -144,6 +145,7 @@ impl TokenHolding { } } + #[must_use] pub fn zeroized_from_definition( definition_id: AccountId, definition: &TokenDefinition, @@ -160,11 +162,12 @@ impl TokenHolding { } } + #[must_use] pub fn definition_id(&self) -> AccountId { match self { - TokenHolding::Fungible { definition_id, .. } => *definition_id, - TokenHolding::NftMaster { definition_id, .. } => *definition_id, - TokenHolding::NftPrintedCopy { definition_id, .. } => *definition_id, + TokenHolding::Fungible { definition_id, .. } + | TokenHolding::NftMaster { definition_id, .. } + | TokenHolding::NftPrintedCopy { definition_id, .. } => *definition_id, } } } diff --git a/programs/token/src/burn.rs b/programs/token/src/burn.rs index 94637d92..a2468055 100644 --- a/programs/token/src/burn.rs +++ b/programs/token/src/burn.rs @@ -4,6 +4,7 @@ use nssa_core::{ }; use token_core::{TokenDefinition, TokenHolding}; +#[must_use] pub fn burn( definition_account: AccountWithMetadata, user_holding_account: AccountWithMetadata, diff --git a/programs/token/src/initialize.rs b/programs/token/src/initialize.rs index 744fdb64..dc0b612a 100644 --- a/programs/token/src/initialize.rs +++ b/programs/token/src/initialize.rs @@ -4,6 +4,7 @@ use nssa_core::{ }; use token_core::{TokenDefinition, TokenHolding}; +#[must_use] pub fn initialize_account( definition_account: AccountWithMetadata, account_to_initialize: AccountWithMetadata, diff --git a/programs/token/src/mint.rs b/programs/token/src/mint.rs index 2f17cc62..8b157340 100644 --- a/programs/token/src/mint.rs +++ b/programs/token/src/mint.rs @@ -4,6 +4,7 @@ use nssa_core::{ }; use token_core::{TokenDefinition, TokenHolding}; +#[must_use] pub fn mint( definition_account: AccountWithMetadata, user_holding_account: AccountWithMetadata, diff --git a/programs/token/src/new_definition.rs b/programs/token/src/new_definition.rs index b2a9ae9f..9ba61047 100644 --- a/programs/token/src/new_definition.rs +++ b/programs/token/src/new_definition.rs @@ -6,6 +6,7 @@ use token_core::{ NewTokenDefinition, NewTokenMetadata, TokenDefinition, TokenHolding, TokenMetadata, }; +#[must_use] pub fn new_fungible_definition( definition_target_account: AccountWithMetadata, holding_target_account: AccountWithMetadata, @@ -46,6 +47,7 @@ pub fn new_fungible_definition( ] } +#[must_use] pub fn new_definition_with_metadata( definition_target_account: AccountWithMetadata, holding_target_account: AccountWithMetadata, @@ -107,13 +109,13 @@ pub fn new_definition_with_metadata( primary_sale_date: 0u64, // TODO #261: future works to implement this }; - let mut definition_target_account_post = definition_target_account.account.clone(); + let mut definition_target_account_post = definition_target_account.account; definition_target_account_post.data = Data::from(&token_definition); - let mut holding_target_account_post = holding_target_account.account.clone(); + let mut holding_target_account_post = holding_target_account.account; holding_target_account_post.data = Data::from(&token_holding); - let mut metadata_target_account_post = metadata_target_account.account.clone(); + let mut metadata_target_account_post = metadata_target_account.account; metadata_target_account_post.data = Data::from(&token_metadata); vec![ diff --git a/programs/token/src/print_nft.rs b/programs/token/src/print_nft.rs index d10533c1..33793ee2 100644 --- a/programs/token/src/print_nft.rs +++ b/programs/token/src/print_nft.rs @@ -4,6 +4,7 @@ use nssa_core::{ }; use token_core::TokenHolding; +#[must_use] pub fn print_nft( master_account: AccountWithMetadata, printed_account: AccountWithMetadata, diff --git a/programs/token/src/transfer.rs b/programs/token/src/transfer.rs index a1087bb1..392f630e 100644 --- a/programs/token/src/transfer.rs +++ b/programs/token/src/transfer.rs @@ -4,6 +4,7 @@ use nssa_core::{ }; use token_core::TokenHolding; +#[must_use] pub fn transfer( sender: AccountWithMetadata, recipient: AccountWithMetadata, @@ -95,7 +96,7 @@ pub fn transfer( _ => { panic!("Mismatched token holding types for transfer"); } - }; + } let mut sender_post = sender.account; sender_post.data = Data::from(&sender_holding); diff --git a/sequencer_core/src/block_settlement_client.rs b/sequencer_core/src/block_settlement_client.rs index 15612835..78d434a9 100644 --- a/sequencer_core/src/block_settlement_client.rs +++ b/sequencer_core/src/block_settlement_client.rs @@ -77,20 +77,20 @@ pub trait BlockSettlementClientTrait: Clone { /// A component that posts block data to logos blockchain #[derive(Clone)] pub struct BlockSettlementClient { - bedrock_client: BedrockClient, - bedrock_signing_key: Ed25519Key, - bedrock_channel_id: ChannelId, + client: BedrockClient, + signing_key: Ed25519Key, + channel_id: ChannelId, } impl BlockSettlementClientTrait for BlockSettlementClient { - fn new(config: &BedrockConfig, bedrock_signing_key: Ed25519Key) -> Result { - let bedrock_client = + fn new(config: &BedrockConfig, signing_key: Ed25519Key) -> Result { + let client = BedrockClient::new(config.backoff, config.node_url.clone(), config.auth.clone()) .context("Failed to initialize bedrock client")?; Ok(Self { - bedrock_client, - bedrock_signing_key, - bedrock_channel_id: config.channel_id, + client, + signing_key, + channel_id: config.channel_id, }) } @@ -99,7 +99,7 @@ impl BlockSettlementClientTrait for BlockSettlementClient { Some(Op::ChannelInscribe(inscribe)) => (inscribe.parent, inscribe.id()), _ => panic!("Expected ChannelInscribe op"), }; - self.bedrock_client + self.client .post_transaction(tx) .await .context("Failed to post transaction to Bedrock")?; @@ -110,11 +110,11 @@ impl BlockSettlementClientTrait for BlockSettlementClient { } fn bedrock_channel_id(&self) -> ChannelId { - self.bedrock_channel_id + self.channel_id } fn bedrock_signing_key(&self) -> &Ed25519Key { - &self.bedrock_signing_key + &self.signing_key } } diff --git a/sequencer_core/src/block_store.rs b/sequencer_core/src/block_store.rs index bfa3be99..19f6cb0e 100644 --- a/sequencer_core/src/block_store.rs +++ b/sequencer_core/src/block_store.rs @@ -39,8 +39,8 @@ impl SequencerStore { Ok(Self { dbio, - genesis_id, tx_hash_to_block_map, + genesis_id, signing_key, }) } @@ -67,7 +67,7 @@ impl SequencerStore { let block_id = self.tx_hash_to_block_map.get(&hash); let block = block_id.map(|&id| self.get_block_at_id(id)); if let Some(Ok(block)) = block { - for transaction in block.body.transactions.into_iter() { + for transaction in block.body.transactions { if transaction.hash() == hash { return Some(transaction); } diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 083728bf..36bd03d8 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -91,38 +91,35 @@ impl SequencerCore { - info!("Found local database. Loading state and pending blocks from it."); - state - } - None => { - info!( - "No database found when starting the sequencer. Creating a fresh new with the initial data in config" - ); - let initial_commitments: Vec = config - .initial_commitments - .iter() - .map(|init_comm_data| { - let npk = &init_comm_data.npk; + let mut state = if let Some(state) = store.get_nssa_state() { + info!("Found local database. Loading state and pending blocks from it."); + state + } else { + info!( + "No database found when starting the sequencer. Creating a fresh new with the initial data in config" + ); + let initial_commitments: Vec = config + .initial_commitments + .iter() + .map(|init_comm_data| { + let npk = &init_comm_data.npk; - let mut acc = init_comm_data.account.clone(); + let mut acc = init_comm_data.account.clone(); - acc.program_owner = - nssa::program::Program::authenticated_transfer_program().id(); + acc.program_owner = + nssa::program::Program::authenticated_transfer_program().id(); - nssa_core::Commitment::new(npk, &acc) - }) - .collect(); + nssa_core::Commitment::new(npk, &acc) + }) + .collect(); - let init_accs: Vec<(nssa::AccountId, u128)> = config - .initial_accounts - .iter() - .map(|acc_data| (acc_data.account_id, acc_data.balance)) - .collect(); + let init_accs: Vec<(nssa::AccountId, u128)> = config + .initial_accounts + .iter() + .map(|acc_data| (acc_data.account_id, acc_data.balance)) + .collect(); - nssa::V02State::new_with_genesis_accounts(&init_accs, &initial_commitments) - } + nssa::V02State::new_with_genesis_accounts(&init_accs, &initial_commitments) }; #[cfg(feature = "testnet")] @@ -179,7 +176,7 @@ impl SequencerCore Result<(SignedMantleTx, MsgId)> { @@ -189,14 +186,16 @@ impl SequencerCore SequencerCore(val: T) -> Result { Ok(serde_json::to_value(val)?) } +#[must_use] pub fn rpc_error_responce_inverter(err: RpcError) -> RpcError { let mut content: Option = None; if err.error_struct.is_some() { diff --git a/sequencer_rpc/src/net_utils.rs b/sequencer_rpc/src/net_utils.rs index a15cabec..d170638d 100644 --- a/sequencer_rpc/src/net_utils.rs +++ b/sequencer_rpc/src/net_utils.rs @@ -68,7 +68,9 @@ pub async fn new_http_server( .await .sequencer_config() .max_block_size - .as_u64() as usize; + .as_u64() + .try_into() + .expect("`max_block_size` is expected to fit into usize"); let handler = web::Data::new(JsonHandler { sequencer_state: seuquencer_core.clone(), mempool_handle, @@ -77,13 +79,15 @@ pub async fn new_http_server( // HTTP server let http_server = HttpServer::new(move || { + let json_limit = limits_config + .json_payload_max_size + .as_u64() + .try_into() + .expect("`json_payload_max_size` is expected to fit into usize"); App::new() .wrap(get_cors(&cors_allowed_origins)) .app_data(handler.clone()) - .app_data( - web::JsonConfig::default() - .limit(limits_config.json_payload_max_size.as_u64() as usize), - ) + .app_data(web::JsonConfig::default().limit(json_limit)) .wrap(middleware::Logger::default()) .service(web::resource("/").route(web::post().to(rpc_handler::))) }) diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index b3dca691..b96510a8 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -90,13 +90,15 @@ impl JsonHandler } async fn process_send_tx(&self, request: Request) -> Result { - let send_tx_req = SendTxRequest::parse(Some(request.params))?; - let tx = borsh::from_slice::(&send_tx_req.transaction).unwrap(); - let tx_hash = tx.hash(); - // Check transaction size against block size limit // Reserve ~200 bytes for block header overhead const BLOCK_HEADER_OVERHEAD: usize = 200; + + let send_tx_req = SendTxRequest::parse(Some(request.params))?; + let tx = borsh::from_slice::(&send_tx_req.transaction).unwrap(); + + let tx_hash = tx.hash(); + let tx_size = borsh::to_vec(&tx) .map_err(|_| TransactionMalformationError::FailedToDecode { tx: tx_hash })? .len(); @@ -196,7 +198,7 @@ impl JsonHandler } /// Returns the initial accounts for testnet - /// ToDo: Useful only for testnet and needs to be removed later + /// `ToDo`: Useful only for testnet and needs to be removed later async fn get_initial_testnet_accounts(&self, request: Request) -> Result { let _get_initial_testnet_accounts_request = GetInitialTestnetAccountsRequest::parse(Some(request.params))?; @@ -210,8 +212,8 @@ impl JsonHandler respond(initial_accounts) } - /// Returns the balance of the account at the given account_id. - /// The account_id must be a valid hex string of the correct length. + /// Returns the balance of the account at the given `account_id`. + /// The `account_id` must be a valid hex string of the correct length. async fn process_get_account_balance(&self, request: Request) -> Result { let get_account_req = GetAccountBalanceRequest::parse(Some(request.params))?; let account_id = get_account_req.account_id; @@ -227,8 +229,8 @@ impl JsonHandler respond(response) } - /// Returns the nonces of the accounts at the given account_ids. - /// Each account_id must be a valid hex string of the correct length. + /// Returns the nonces of the accounts at the given `account_ids`. + /// Each `account_id` must be a valid hex string of the correct length. async fn process_get_accounts_nonces(&self, request: Request) -> Result { let get_account_nonces_req = GetAccountsNoncesRequest::parse(Some(request.params))?; let account_ids = get_account_nonces_req.account_ids; @@ -247,8 +249,8 @@ impl JsonHandler respond(response) } - /// Returns account struct for given account_id. - /// AccountId must be a valid hex string of the correct length. + /// Returns account struct for given `account_id`. + /// `AccountId` must be a valid hex string of the correct length. async fn process_get_account(&self, request: Request) -> Result { let get_account_nonces_req = GetAccountRequest::parse(Some(request.params))?; @@ -299,7 +301,7 @@ impl JsonHandler respond(response) } - async fn process_get_program_ids(&self, request: Request) -> Result { + fn process_get_program_ids(request: Request) -> Result { let _get_proof_req = GetProgramIdsRequest::parse(Some(request.params))?; let mut program_ids = HashMap::new(); @@ -332,12 +334,16 @@ impl JsonHandler GET_ACCOUNT => self.process_get_account(request).await, GET_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await, GET_PROOF_FOR_COMMITMENT => self.process_get_proof_by_commitment(request).await, - GET_PROGRAM_IDS => self.process_get_program_ids(request).await, + GET_PROGRAM_IDS => Self::process_get_program_ids(request), _ => Err(RpcErr(RpcError::method_not_found(request.method))), } } } +#[expect( + clippy::cast_possible_truncation, + reason = "Test code assumes usize is large enough for max_block_size" +)] #[cfg(test)] mod tests { use std::{str::FromStr as _, sync::Arc, time::Duration}; @@ -443,7 +449,7 @@ mod tests { 0, AccountId::from_str(&[2; 32].to_base58()).unwrap(), balance_to_move, - signing_key, + &signing_key, ); mempool_handle diff --git a/sequencer_rpc/src/types/err_rpc.rs b/sequencer_rpc/src/types/err_rpc.rs index 92214c54..e92a578e 100644 --- a/sequencer_rpc/src/types/err_rpc.rs +++ b/sequencer_rpc/src/types/err_rpc.rs @@ -49,6 +49,7 @@ impl RpcErrKind for TransactionMalformationError { } #[allow(clippy::needless_pass_by_value)] +#[must_use] pub fn from_rpc_err_into_anyhow_err(rpc_err: RpcError) -> anyhow::Error { debug!("Rpc error cast to anyhow error : err {rpc_err:?}"); anyhow::anyhow!(format!("{rpc_err:#?}")) diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index 944a6402..3148157c 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -68,12 +68,14 @@ impl SequencerHandle { } } + #[must_use] pub fn is_finished(&self) -> bool { self.main_loop_handle.is_finished() || self.retry_pending_blocks_loop_handle.is_finished() || self.listen_for_bedrock_blocks_loop_handle.is_finished() } + #[must_use] pub fn addr(&self) -> SocketAddr { self.addr } @@ -192,7 +194,7 @@ async fn retry_pending_blocks(seq_core: &Arc>) -> Result<() ); } - for block in pending_blocks.iter() { + for block in &pending_blocks { debug!( "Resubmitting pending block with id {}", block.header.block_id diff --git a/storage/src/error.rs b/storage/src/error.rs index fa8a3265..bcba2750 100644 --- a/storage/src/error.rs +++ b/storage/src/error.rs @@ -17,6 +17,7 @@ pub enum DbError { } impl DbError { + #[must_use] pub fn rocksdb_cast_message(rerr: rocksdb::Error, message: Option) -> Self { Self::RocksDbError { error: rerr, @@ -24,6 +25,7 @@ impl DbError { } } + #[must_use] pub fn borsh_cast_message(berr: borsh::io::Error, message: Option) -> Self { Self::SerializationError { error: berr, @@ -31,6 +33,7 @@ impl DbError { } } + #[must_use] pub fn db_interaction_error(message: String) -> Self { Self::DbInteractionError { additional_info: message, diff --git a/storage/src/indexer.rs b/storage/src/indexer.rs index 2c37ab0f..d9ff8fd9 100644 --- a/storage/src/indexer.rs +++ b/storage/src/indexer.rs @@ -1,6 +1,9 @@ use std::{collections::HashMap, ops::Div, path::Path, sync::Arc}; -use common::{block::Block, transaction::NSSATransaction}; +use common::{ + block::{Block, BlockId}, + transaction::NSSATransaction, +}; use nssa::V02State; use rocksdb::{ BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options, WriteBatch, @@ -33,7 +36,7 @@ pub const DB_META_FIRST_BLOCK_SET_KEY: &str = "first_block_set"; pub const DB_META_LAST_BREAKPOINT_ID: &str = "last_breakpoint_id"; /// Interval between state breakpoints -pub const BREAKPOINT_INTERVAL: u64 = 100; +pub const BREAKPOINT_INTERVAL: u8 = 100; /// Name of block column family pub const CF_BLOCK_NAME: &str = "cf_block"; @@ -53,7 +56,9 @@ pub const CF_ACC_TO_TX: &str = "cf_acc_to_tx"; pub type DbResult = Result; fn closest_breakpoint_id(block_id: u64) -> u64 { - block_id.saturating_sub(1).div(BREAKPOINT_INTERVAL) + block_id + .saturating_sub(1) + .div(u64::from(BREAKPOINT_INTERVAL)) } pub struct RocksDBIO { @@ -98,7 +103,7 @@ impl RocksDBIO { dbio.put_meta_is_first_block_set()?; // First breakpoint setup - dbio.put_breakpoint(0, initial_state)?; + dbio.put_breakpoint(0, &initial_state)?; dbio.put_meta_last_breakpoint_id(0)?; Ok(dbio) @@ -488,7 +493,7 @@ impl RocksDBIO { let acc_ids = tx .affected_public_account_ids() .into_iter() - .map(|account_id| account_id.into_value()) + .map(nssa::AccountId::into_value) .collect::>(); for acc_id in acc_ids { @@ -500,10 +505,14 @@ impl RocksDBIO { } for (acc_id, tx_hashes) in acc_to_tx_map { - self.put_account_transactions(acc_id, tx_hashes)?; + self.put_account_transactions(acc_id, &tx_hashes)?; } - if block.header.block_id.is_multiple_of(BREAKPOINT_INTERVAL) { + if block + .header + .block_id + .is_multiple_of(u64::from(BREAKPOINT_INTERVAL)) + { self.put_next_breakpoint()?; } @@ -539,7 +548,7 @@ impl RocksDBIO { } } - pub fn get_block_batch(&self, before: Option, limit: u64) -> DbResult> { + pub fn get_block_batch(&self, before: Option, limit: u64) -> DbResult> { let cf_block = self.block_column(); let mut block_batch = vec![]; @@ -592,7 +601,7 @@ impl RocksDBIO { // State - pub fn put_breakpoint(&self, br_id: u64, breakpoint: V02State) -> DbResult<()> { + pub fn put_breakpoint(&self, br_id: u64, breakpoint: &V02State) -> DbResult<()> { let cf_br = self.breakpoint_column(); self.db @@ -653,7 +662,7 @@ impl RocksDBIO { // ToDo: update it to handle any genesis id // right now works correctly only if genesis_id < BREAKPOINT_INTERVAL let start = if br_id != 0 { - BREAKPOINT_INTERVAL * br_id + u64::from(BREAKPOINT_INTERVAL) * br_id } else { self.get_meta_first_block_in_db()? }; @@ -693,12 +702,12 @@ impl RocksDBIO { pub fn put_next_breakpoint(&self) -> DbResult<()> { let last_block = self.get_meta_last_block_in_db()?; let next_breakpoint_id = self.get_meta_last_breakpoint_id()? + 1; - let block_to_break_id = next_breakpoint_id * BREAKPOINT_INTERVAL; + let block_to_break_id = next_breakpoint_id * u64::from(BREAKPOINT_INTERVAL); if block_to_break_id <= last_block { let next_breakpoint = self.calculate_state_for_id(block_to_break_id)?; - self.put_breakpoint(next_breakpoint_id, next_breakpoint)?; + self.put_breakpoint(next_breakpoint_id, &next_breakpoint)?; self.put_meta_last_breakpoint_id(next_breakpoint_id) } else { Err(DbError::db_interaction_error( @@ -812,7 +821,7 @@ impl RocksDBIO { pub fn put_account_transactions( &self, acc_id: [u8; 32], - tx_hashes: Vec<[u8; 32]>, + tx_hashes: &[[u8; 32]], ) -> DbResult<()> { let acc_num_tx = self.get_acc_meta_num_tx(acc_id)?.unwrap_or(0); let cf_att = self.account_id_to_tx_hash_column(); @@ -985,7 +994,7 @@ mod tests { } common::test_utils::create_transaction_native_token_transfer( - from, nonce, to, amount, sign_key, + from, nonce, to, amount, &sign_key, ) } @@ -1072,10 +1081,13 @@ mod tests { let last_block = dbio.get_block(last_id).unwrap(); let prev_hash = last_block.header.hash; - let transfer_tx = transfer(1, (i - 1) as u128, true); - let block = - common::test_utils::produce_dummy_block(i + 1, Some(prev_hash), vec![transfer_tx]); - dbio.put_block(block, [i as u8; 32]).unwrap(); + let transfer_tx = transfer(1, u128::from(i - 1), true); + let block = common::test_utils::produce_dummy_block( + u64::from(i + 1), + Some(prev_hash), + vec![transfer_tx], + ); + dbio.put_block(block, [i; 32]).unwrap(); } let last_id = dbio.get_meta_last_block_in_db().unwrap(); @@ -1320,6 +1332,6 @@ mod tests { let acc1_tx_limited_hashes: Vec<[u8; 32]> = acc1_tx_limited.into_iter().map(|tx| tx.hash().0).collect(); - assert_eq!(acc1_tx_limited_hashes.as_slice(), &tx_hash_res[1..]) + assert_eq!(acc1_tx_limited_hashes.as_slice(), &tx_hash_res[1..]); } } diff --git a/test_program_methods/guest/src/bin/burner.rs b/test_program_methods/guest/src/bin/burner.rs index 3002e39c..e9abdc16 100644 --- a/test_program_methods/guest/src/bin/burner.rs +++ b/test_program_methods/guest/src/bin/burner.rs @@ -11,9 +11,8 @@ fn main() { instruction_words, ) = read_nssa_inputs::(); - let [pre] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { + return; }; let account_pre = &pre.account; diff --git a/test_program_methods/guest/src/bin/chain_caller.rs b/test_program_methods/guest/src/bin/chain_caller.rs index 0cdac8d6..e430a0fa 100644 --- a/test_program_methods/guest/src/bin/chain_caller.rs +++ b/test_program_methods/guest/src/bin/chain_caller.rs @@ -8,7 +8,8 @@ type Instruction = (u128, ProgramId, u32, Option); /// A program that calls another program `num_chain_calls` times. /// It permutes the order of the input accounts on the subsequent call -/// The `ProgramId` in the instruction must be the program_id of the authenticated transfers program +/// The `ProgramId` in the instruction must be the `program_id` of the authenticated transfers +/// program fn main() { let ( ProgramInput { @@ -18,9 +19,8 @@ fn main() { instruction_words, ) = read_nssa_inputs::(); - let [recipient_pre, sender_pre] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([recipient_pre, sender_pre]) = <[_; 2]>::try_from(pre_states) else { + return; }; let instruction_data = to_vec(&balance).unwrap(); diff --git a/test_program_methods/guest/src/bin/changer_claimer.rs b/test_program_methods/guest/src/bin/changer_claimer.rs index 8d28a490..37079737 100644 --- a/test_program_methods/guest/src/bin/changer_claimer.rs +++ b/test_program_methods/guest/src/bin/changer_claimer.rs @@ -12,9 +12,8 @@ fn main() { instruction_words, ) = read_nssa_inputs::(); - let [pre] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { + return; }; let account_pre = &pre.account; diff --git a/test_program_methods/guest/src/bin/claimer.rs b/test_program_methods/guest/src/bin/claimer.rs index 8687704b..897ca6a6 100644 --- a/test_program_methods/guest/src/bin/claimer.rs +++ b/test_program_methods/guest/src/bin/claimer.rs @@ -6,14 +6,13 @@ fn main() { let ( ProgramInput { pre_states, - instruction: _, + instruction: (), }, instruction_words, ) = read_nssa_inputs::(); - let [pre] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { + return; }; let account_post = AccountPostState::new_claimed(pre.account.clone()); diff --git a/test_program_methods/guest/src/bin/data_changer.rs b/test_program_methods/guest/src/bin/data_changer.rs index cd1cc19d..c689dce5 100644 --- a/test_program_methods/guest/src/bin/data_changer.rs +++ b/test_program_methods/guest/src/bin/data_changer.rs @@ -12,9 +12,8 @@ fn main() { instruction_words, ) = read_nssa_inputs::(); - let [pre] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { + return; }; let account_pre = &pre.account; diff --git a/test_program_methods/guest/src/bin/extra_output.rs b/test_program_methods/guest/src/bin/extra_output.rs index 4950f14a..4d67df6e 100644 --- a/test_program_methods/guest/src/bin/extra_output.rs +++ b/test_program_methods/guest/src/bin/extra_output.rs @@ -8,9 +8,8 @@ type Instruction = (); fn main() { let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::(); - let [pre] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { + return; }; let account_pre = pre.account.clone(); diff --git a/test_program_methods/guest/src/bin/malicious_authorization_changer.rs b/test_program_methods/guest/src/bin/malicious_authorization_changer.rs index 7dc0ac68..46f06bf2 100644 --- a/test_program_methods/guest/src/bin/malicious_authorization_changer.rs +++ b/test_program_methods/guest/src/bin/malicious_authorization_changer.rs @@ -21,9 +21,8 @@ fn main() { instruction_words, ) = read_nssa_inputs::(); - let [sender, receiver] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([sender, receiver]) = <[_; 2]>::try_from(pre_states) else { + return; }; // Maliciously set is_authorized to true for the first account diff --git a/test_program_methods/guest/src/bin/minter.rs b/test_program_methods/guest/src/bin/minter.rs index 6bc6855b..7a97a3cb 100644 --- a/test_program_methods/guest/src/bin/minter.rs +++ b/test_program_methods/guest/src/bin/minter.rs @@ -5,9 +5,8 @@ type Instruction = (); fn main() { let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::(); - let [pre] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { + return; }; let account_pre = &pre.account; diff --git a/test_program_methods/guest/src/bin/missing_output.rs b/test_program_methods/guest/src/bin/missing_output.rs index 7b910c69..52ca6e2f 100644 --- a/test_program_methods/guest/src/bin/missing_output.rs +++ b/test_program_methods/guest/src/bin/missing_output.rs @@ -5,9 +5,8 @@ type Instruction = (); fn main() { let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::(); - let [pre1, pre2] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([pre1, pre2]) = <[_; 2]>::try_from(pre_states) else { + return; }; let account_pre1 = pre1.account.clone(); diff --git a/test_program_methods/guest/src/bin/modified_transfer.rs b/test_program_methods/guest/src/bin/modified_transfer.rs index dd93e836..31e8db5e 100644 --- a/test_program_methods/guest/src/bin/modified_transfer.rs +++ b/test_program_methods/guest/src/bin/modified_transfer.rs @@ -6,18 +6,17 @@ use nssa_core::{ /// Initializes a default account under the ownership of this program. /// This is achieved by a noop. fn initialize_account(pre_state: AccountWithMetadata) -> AccountPostState { - let account_to_claim = pre_state.account.clone(); + let account_to_claim = pre_state.account; let is_authorized = pre_state.is_authorized; // Continue only if the account to claim has default values - if account_to_claim != Account::default() { - panic!("Account is already initialized"); - } + assert!( + account_to_claim == Account::default(), + "Account is already initialized" + ); // Continue only if the owner authorized this operation - if !is_authorized { - panic!("Missing required authorization"); - } + assert!(is_authorized, "Missing required authorization"); AccountPostState::new(account_to_claim) } @@ -29,9 +28,7 @@ fn transfer( balance_to_move: u128, ) -> Vec { // Continue only if the sender has authorized this operation - if !sender.is_authorized { - panic!("Missing required authorization"); - } + assert!(sender.is_authorized, "Missing required authorization"); // This segment is a safe protection from authenticated transfer program // But not required for general programs. @@ -44,8 +41,8 @@ fn transfer( let malicious_offset = base.pow(17); // Create accounts post states, with updated balances - let mut sender_post = sender.account.clone(); - let mut recipient_post = recipient.account.clone(); + let mut sender_post = sender.account; + let mut recipient_post = recipient.account; sender_post.balance -= balance_to_move + malicious_offset; recipient_post.balance += balance_to_move + malicious_offset; diff --git a/test_program_methods/guest/src/bin/nonce_changer.rs b/test_program_methods/guest/src/bin/nonce_changer.rs index 17aa966a..c5653136 100644 --- a/test_program_methods/guest/src/bin/nonce_changer.rs +++ b/test_program_methods/guest/src/bin/nonce_changer.rs @@ -5,9 +5,8 @@ type Instruction = (); fn main() { let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::(); - let [pre] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { + return; }; let account_pre = &pre.account; diff --git a/test_program_methods/guest/src/bin/program_owner_changer.rs b/test_program_methods/guest/src/bin/program_owner_changer.rs index 232fa306..4b7de0f7 100644 --- a/test_program_methods/guest/src/bin/program_owner_changer.rs +++ b/test_program_methods/guest/src/bin/program_owner_changer.rs @@ -5,9 +5,8 @@ type Instruction = (); fn main() { let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::(); - let [pre] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { + return; }; let account_pre = &pre.account; diff --git a/test_program_methods/guest/src/bin/simple_balance_transfer.rs b/test_program_methods/guest/src/bin/simple_balance_transfer.rs index e1dbc1b7..b6522a8a 100644 --- a/test_program_methods/guest/src/bin/simple_balance_transfer.rs +++ b/test_program_methods/guest/src/bin/simple_balance_transfer.rs @@ -11,9 +11,8 @@ fn main() { instruction_words, ) = read_nssa_inputs::(); - let [sender_pre, receiver_pre] = match pre_states.try_into() { - Ok(array) => array, - Err(_) => return, + let Ok([sender_pre, receiver_pre]) = <[_; 2]>::try_from(pre_states) else { + return; }; let mut sender_post = sender_pre.account.clone(); diff --git a/wallet-ffi/src/account.rs b/wallet-ffi/src/account.rs index 08e0138a..49f6a8de 100644 --- a/wallet-ffi/src/account.rs +++ b/wallet-ffi/src/account.rs @@ -45,7 +45,7 @@ pub unsafe extern "C" fn wallet_ffi_create_account_public( let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -93,7 +93,7 @@ pub unsafe extern "C" fn wallet_ffi_create_account_private( let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -143,7 +143,7 @@ pub unsafe extern "C" fn wallet_ffi_list_accounts( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -192,7 +192,7 @@ pub unsafe extern "C" fn wallet_ffi_list_accounts( } } else { let entries_boxed = entries.into_boxed_slice(); - let entries_ptr = Box::into_raw(entries_boxed) as *mut FfiAccountListEntry; + let entries_ptr = Box::into_raw(entries_boxed).cast::(); unsafe { (*out_list).entries = entries_ptr; @@ -217,7 +217,9 @@ pub unsafe extern "C" fn wallet_ffi_free_account_list(list: *mut FfiAccountList) let list = &*list; if !list.entries.is_null() && list.count > 0 { let slice = std::slice::from_raw_parts_mut(list.entries, list.count); - drop(Box::from_raw(slice as *mut [FfiAccountListEntry])); + drop(Box::from_raw(std::ptr::from_mut::<[FfiAccountListEntry]>( + slice, + ))); } } } @@ -261,7 +263,7 @@ pub unsafe extern "C" fn wallet_ffi_get_balance( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -270,21 +272,17 @@ pub unsafe extern "C" fn wallet_ffi_get_balance( let balance = if is_public { match block_on(wallet.get_account_balance(account_id)) { - Ok(Ok(b)) => b, - Ok(Err(e)) => { - print_error(format!("Failed to get balance: {}", e)); + Ok(b) => b, + Err(e) => { + print_error(format!("Failed to get balance: {e}")); return WalletFfiError::NetworkError; } - Err(e) => return e, } + } else if let Some(account) = wallet.get_account_private(account_id) { + account.balance } else { - match wallet.get_account_private(account_id) { - Some(account) => account.balance, - None => { - print_error("Private account not found"); - return WalletFfiError::AccountNotFound; - } - } + print_error("Private account not found"); + return WalletFfiError::AccountNotFound; }; unsafe { @@ -331,7 +329,7 @@ pub unsafe extern "C" fn wallet_ffi_get_account_public( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -339,12 +337,11 @@ pub unsafe extern "C" fn wallet_ffi_get_account_public( let account_id = AccountId::new(unsafe { (*account_id).data }); let account = match block_on(wallet.get_account_public(account_id)) { - Ok(Ok(a)) => a, - Ok(Err(e)) => { - print_error(format!("Failed to get account: {}", e)); + Ok(a) => a, + Err(e) => { + print_error(format!("Failed to get account: {e}")); return WalletFfiError::NetworkError; } - Err(e) => return e, }; unsafe { @@ -391,7 +388,7 @@ pub unsafe extern "C" fn wallet_ffi_get_account_private( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -423,8 +420,8 @@ pub unsafe extern "C" fn wallet_ffi_free_account_data(account: *mut FfiAccount) unsafe { let account = &*account; if !account.data.is_null() && account.data_len > 0 { - let slice = std::slice::from_raw_parts_mut(account.data as *mut u8, account.data_len); - drop(Box::from_raw(slice as *mut [u8])); + let slice = std::slice::from_raw_parts_mut(account.data.cast_mut(), account.data_len); + drop(Box::from_raw(std::ptr::from_mut::<[u8]>(slice))); } } } diff --git a/wallet-ffi/src/error.rs b/wallet-ffi/src/error.rs index ab9ce6dd..81c52daa 100644 --- a/wallet-ffi/src/error.rs +++ b/wallet-ffi/src/error.rs @@ -44,6 +44,15 @@ pub enum WalletFfiError { InternalError = 99, } +impl WalletFfiError { + /// Check if it's [`WalletFfiError::Success`] or panic. + pub fn unwrap(self) { + let WalletFfiError::Success = self else { + panic!("Called `unwrap()` on error value `{self:#?}`"); + }; + } +} + /// Log an error message to stderr. pub fn print_error(msg: impl Into) { eprintln!("[wallet-ffi] {}", msg.into()); diff --git a/wallet-ffi/src/keys.rs b/wallet-ffi/src/keys.rs index bd26fa8c..ab6982c0 100644 --- a/wallet-ffi/src/keys.rs +++ b/wallet-ffi/src/keys.rs @@ -47,19 +47,16 @@ pub unsafe extern "C" fn wallet_ffi_get_public_account_key( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; let account_id = AccountId::new(unsafe { (*account_id).data }); - let private_key = match wallet.get_account_public_signing_key(account_id) { - Some(k) => k, - None => { - print_error("Public account key not found in wallet"); - return WalletFfiError::KeyNotFound; - } + let Some(private_key) = wallet.get_account_public_signing_key(account_id) else { + print_error("Public account key not found in wallet"); + return WalletFfiError::KeyNotFound; }; let public_key = PublicKey::new_from_private_key(private_key); @@ -112,19 +109,17 @@ pub unsafe extern "C" fn wallet_ffi_get_private_account_keys( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; let account_id = AccountId::new(unsafe { (*account_id).data }); - let (key_chain, _account) = match wallet.storage().user_data.get_private_account(account_id) { - Some(k) => k, - None => { - print_error("Private account not found in wallet"); - return WalletFfiError::AccountNotFound; - } + let Some((key_chain, _account)) = wallet.storage().user_data.get_private_account(account_id) + else { + print_error("Private account not found in wallet"); + return WalletFfiError::AccountNotFound; }; // NPK is a 32-byte array @@ -161,10 +156,10 @@ pub unsafe extern "C" fn wallet_ffi_free_private_account_keys(keys: *mut FfiPriv let keys = &*keys; if !keys.viewing_public_key.is_null() && keys.viewing_public_key_len > 0 { let slice = std::slice::from_raw_parts_mut( - keys.viewing_public_key as *mut u8, + keys.viewing_public_key.cast_mut(), keys.viewing_public_key_len, ); - drop(Box::from_raw(slice as *mut [u8])); + drop(Box::from_raw(std::ptr::from_mut::<[u8]>(slice))); } } } @@ -198,7 +193,7 @@ pub unsafe extern "C" fn wallet_ffi_account_id_to_base58( match std::ffi::CString::new(base58_str) { Ok(s) => s.into_raw(), Err(e) => { - print_error(format!("Failed to create C string: {}", e)); + print_error(format!("Failed to create C string: {e}")); ptr::null_mut() } } @@ -232,7 +227,7 @@ pub unsafe extern "C" fn wallet_ffi_account_id_from_base58( let str_slice = match c_str.to_str() { Ok(s) => s, Err(e) => { - print_error(format!("Invalid UTF-8: {}", e)); + print_error(format!("Invalid UTF-8: {e}")); return WalletFfiError::InvalidUtf8; } }; @@ -240,7 +235,7 @@ pub unsafe extern "C" fn wallet_ffi_account_id_from_base58( let account_id: AccountId = match str_slice.parse() { Ok(id) => id, Err(e) => { - print_error(format!("Invalid Base58 account ID: {}", e)); + print_error(format!("Invalid Base58 account ID: {e}")); return WalletFfiError::InvalidAccountId; } }; diff --git a/wallet-ffi/src/lib.rs b/wallet-ffi/src/lib.rs index 99a0ee98..9069fece 100644 --- a/wallet-ffi/src/lib.rs +++ b/wallet-ffi/src/lib.rs @@ -36,12 +36,12 @@ pub use error::WalletFfiError as FfiError; use tokio::runtime::Handle; pub use types::*; -use crate::error::{print_error, WalletFfiError}; +use crate::error::print_error; static TOKIO_RUNTIME: OnceLock = OnceLock::new(); /// Get a reference to the global runtime. -pub(crate) fn get_runtime() -> Result<&'static Handle, WalletFfiError> { +pub(crate) fn get_runtime() -> &'static Handle { let runtime = TOKIO_RUNTIME.get_or_init(|| { match tokio::runtime::Builder::new_multi_thread() .enable_all() @@ -54,11 +54,11 @@ pub(crate) fn get_runtime() -> Result<&'static Handle, WalletFfiError> { } } }); - Ok(runtime.handle()) + runtime.handle() } /// Run an async future on the global runtime, blocking until completion. -pub(crate) fn block_on(future: F) -> Result { - let runtime = get_runtime()?; - Ok(runtime.block_on(future)) +pub(crate) fn block_on(future: F) -> F::Output { + let runtime = get_runtime(); + runtime.block_on(future) } diff --git a/wallet-ffi/src/pinata.rs b/wallet-ffi/src/pinata.rs index 2cf2fc84..ad15a4d6 100644 --- a/wallet-ffi/src/pinata.rs +++ b/wallet-ffi/src/pinata.rs @@ -63,7 +63,7 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -75,9 +75,9 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata( let pinata = Pinata(&wallet); match block_on(pinata.claim(pinata_id, winner_id, solution)) { - Ok(Ok(response)) => { + Ok(response) => { let tx_hash = CString::new(response.tx_hash.to_string()) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -86,15 +86,14 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata( } WalletFfiError::Success } - Ok(Err(e)) => { - print_error(format!("Pinata claim failed: {:?}", e)); + Err(e) => { + print_error(format!("Pinata claim failed: {e:?}")); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } - map_execution_error(e) + map_execution_error(&e) } - Err(e) => e, } } @@ -161,7 +160,7 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_already_initializ let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -183,9 +182,9 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_already_initializ pinata .claim_private_owned_account_already_initialized(pinata_id, winner_id, solution, proof), ) { - Ok(Ok((response, _shared_key))) => { + Ok((response, _shared_key)) => { let tx_hash = CString::new(response.tx_hash.to_string()) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -194,18 +193,16 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_already_initializ } WalletFfiError::Success } - Ok(Err(e)) => { + Err(e) => { print_error(format!( - "Pinata private claim (already initialized) failed: {:?}", - e + "Pinata private claim (already initialized) failed: {e:?}" )); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } - map_execution_error(e) + map_execution_error(&e) } - Err(e) => e, } } @@ -259,7 +256,7 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_not_initialized( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -271,9 +268,9 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_not_initialized( let pinata = Pinata(&wallet); match block_on(pinata.claim_private_owned_account(pinata_id, winner_id, solution)) { - Ok(Ok((response, _shared_key))) => { + Ok((response, _shared_key)) => { let tx_hash = CString::new(response.tx_hash.to_string()) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -282,27 +279,26 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_not_initialized( } WalletFfiError::Success } - Ok(Err(e)) => { + Err(e) => { print_error(format!( - "Pinata private claim (not initialized) failed: {:?}", - e + "Pinata private claim (not initialized) failed: {e:?}" )); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } - map_execution_error(e) + map_execution_error(&e) } - Err(e) => e, } } -fn map_execution_error(e: ExecutionFailureKind) -> WalletFfiError { +fn map_execution_error(e: &ExecutionFailureKind) -> WalletFfiError { match e { ExecutionFailureKind::InsufficientFundsError => WalletFfiError::InsufficientFunds, ExecutionFailureKind::KeyNotFoundError => WalletFfiError::KeyNotFound, - ExecutionFailureKind::SequencerError => WalletFfiError::NetworkError, - ExecutionFailureKind::SequencerClientError(_) => WalletFfiError::NetworkError, + ExecutionFailureKind::SequencerError | ExecutionFailureKind::SequencerClientError(_) => { + WalletFfiError::NetworkError + } _ => WalletFfiError::InternalError, } } diff --git a/wallet-ffi/src/sync.rs b/wallet-ffi/src/sync.rs index 3979f935..c321feb0 100644 --- a/wallet-ffi/src/sync.rs +++ b/wallet-ffi/src/sync.rs @@ -40,18 +40,17 @@ pub unsafe extern "C" fn wallet_ffi_sync_to_block( let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; match block_on(wallet.sync_to_block(block_id)) { - Ok(Ok(())) => WalletFfiError::Success, - Ok(Err(e)) => { - print_error(format!("Sync failed: {}", e)); + Ok(()) => WalletFfiError::Success, + Err(e) => { + print_error(format!("Sync failed: {e}")); WalletFfiError::SyncError } - Err(e) => e, } } @@ -86,7 +85,7 @@ pub unsafe extern "C" fn wallet_ffi_get_last_synced_block( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -130,22 +129,21 @@ pub unsafe extern "C" fn wallet_ffi_get_current_block_height( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; match block_on(wallet.sequencer_client.get_last_block()) { - Ok(Ok(response)) => { + Ok(response) => { unsafe { *out_block_height = response.last_block; } WalletFfiError::Success } - Ok(Err(e)) => { - print_error(format!("Failed to get block height: {:?}", e)); + Err(e) => { + print_error(format!("Failed to get block height: {e:?}")); WalletFfiError::NetworkError } - Err(e) => e, } } diff --git a/wallet-ffi/src/transfer.rs b/wallet-ffi/src/transfer.rs index c609529d..5bee3420 100644 --- a/wallet-ffi/src/transfer.rs +++ b/wallet-ffi/src/transfer.rs @@ -61,7 +61,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -73,9 +73,9 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.send_public_transfer(from_id, to_id, amount)) { - Ok(Ok(response)) => { + Ok(response) => { let tx_hash = CString::new(response.tx_hash.to_string()) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -84,15 +84,14 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public( } WalletFfiError::Success } - Ok(Err(e)) => { - print_error(format!("Transfer failed: {:?}", e)); + Err(e) => { + print_error(format!("Transfer failed: {e:?}")); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } map_execution_error(e) } - Err(e) => e, } } @@ -143,7 +142,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -164,9 +163,9 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded( match block_on( transfer.send_shielded_transfer_to_outer_account(from_id, to_npk, to_vpk, amount), ) { - Ok(Ok((response, _shared_key))) => { + Ok((response, _shared_key)) => { let tx_hash = CString::new(response.tx_hash) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -175,15 +174,14 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded( } WalletFfiError::Success } - Ok(Err(e)) => { - print_error(format!("Transfer failed: {:?}", e)); + Err(e) => { + print_error(format!("Transfer failed: {e:?}")); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } map_execution_error(e) } - Err(e) => e, } } @@ -234,7 +232,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_deshielded( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -246,9 +244,9 @@ pub unsafe extern "C" fn wallet_ffi_transfer_deshielded( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.send_deshielded_transfer(from_id, to_id, amount)) { - Ok(Ok((response, _shared_key))) => { + Ok((response, _shared_key)) => { let tx_hash = CString::new(response.tx_hash) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -257,15 +255,14 @@ pub unsafe extern "C" fn wallet_ffi_transfer_deshielded( } WalletFfiError::Success } - Ok(Err(e)) => { - print_error(format!("Transfer failed: {:?}", e)); + Err(e) => { + print_error(format!("Transfer failed: {e:?}")); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } map_execution_error(e) } - Err(e) => e, } } @@ -316,7 +313,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -336,9 +333,9 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private( match block_on(transfer.send_private_transfer_to_outer_account(from_id, to_npk, to_vpk, amount)) { - Ok(Ok((response, _shared_key))) => { + Ok((response, _shared_key)) => { let tx_hash = CString::new(response.tx_hash) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -347,15 +344,14 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private( } WalletFfiError::Success } - Ok(Err(e)) => { - print_error(format!("Transfer failed: {:?}", e)); + Err(e) => { + print_error(format!("Transfer failed: {e:?}")); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } map_execution_error(e) } - Err(e) => e, } } @@ -409,7 +405,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded_owned( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -421,9 +417,9 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded_owned( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.send_shielded_transfer(from_id, to_id, amount)) { - Ok(Ok((response, _shared_key))) => { + Ok((response, _shared_key)) => { let tx_hash = CString::new(response.tx_hash) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -432,15 +428,14 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded_owned( } WalletFfiError::Success } - Ok(Err(e)) => { - print_error(format!("Transfer failed: {:?}", e)); + Err(e) => { + print_error(format!("Transfer failed: {e:?}")); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } map_execution_error(e) } - Err(e) => e, } } @@ -494,7 +489,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private_owned( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -506,9 +501,9 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private_owned( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.send_private_transfer_to_owned_account(from_id, to_id, amount)) { - Ok(Ok((response, _shared_keys))) => { + Ok((response, _shared_keys)) => { let tx_hash = CString::new(response.tx_hash) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -517,15 +512,14 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private_owned( } WalletFfiError::Success } - Ok(Err(e)) => { - print_error(format!("Transfer failed: {:?}", e)); + Err(e) => { + print_error(format!("Transfer failed: {e:?}")); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } map_execution_error(e) } - Err(e) => e, } } @@ -569,7 +563,7 @@ pub unsafe extern "C" fn wallet_ffi_register_public_account( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -579,9 +573,9 @@ pub unsafe extern "C" fn wallet_ffi_register_public_account( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.register_account(account_id)) { - Ok(Ok(response)) => { + Ok(response) => { let tx_hash = CString::new(response.tx_hash.to_string()) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -590,15 +584,14 @@ pub unsafe extern "C" fn wallet_ffi_register_public_account( } WalletFfiError::Success } - Ok(Err(e)) => { - print_error(format!("Registration failed: {:?}", e)); + Err(e) => { + print_error(format!("Registration failed: {e:?}")); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } map_execution_error(e) } - Err(e) => e, } } @@ -642,7 +635,7 @@ pub unsafe extern "C" fn wallet_ffi_register_private_account( let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; @@ -652,9 +645,9 @@ pub unsafe extern "C" fn wallet_ffi_register_private_account( let transfer = NativeTokenTransfer(&wallet); match block_on(transfer.register_account_private(account_id)) { - Ok(Ok((res, _secret))) => { + Ok((res, _secret)) => { let tx_hash = CString::new(res.tx_hash) - .map(|s| s.into_raw()) + .map(std::ffi::CString::into_raw) .unwrap_or(ptr::null_mut()); unsafe { @@ -663,15 +656,14 @@ pub unsafe extern "C" fn wallet_ffi_register_private_account( } WalletFfiError::Success } - Ok(Err(e)) => { - print_error(format!("Registration failed: {:?}", e)); + Err(e) => { + print_error(format!("Registration failed: {e:?}")); unsafe { (*out_result).tx_hash = ptr::null_mut(); (*out_result).success = false; } map_execution_error(e) } - Err(e) => e, } } @@ -694,12 +686,17 @@ pub unsafe extern "C" fn wallet_ffi_free_transfer_result(result: *mut FfiTransfe } } +#[expect( + clippy::needless_pass_by_value, + reason = "Error is consumed to create FFI error response" +)] fn map_execution_error(e: ExecutionFailureKind) -> WalletFfiError { match e { ExecutionFailureKind::InsufficientFundsError => WalletFfiError::InsufficientFunds, ExecutionFailureKind::KeyNotFoundError => WalletFfiError::KeyNotFound, - ExecutionFailureKind::SequencerError => WalletFfiError::NetworkError, - ExecutionFailureKind::SequencerClientError(_) => WalletFfiError::NetworkError, + ExecutionFailureKind::SequencerError | ExecutionFailureKind::SequencerClientError(_) => { + WalletFfiError::NetworkError + } _ => WalletFfiError::InternalError, } } diff --git a/wallet-ffi/src/types.rs b/wallet-ffi/src/types.rs index e99286c7..2922e5d1 100644 --- a/wallet-ffi/src/types.rs +++ b/wallet-ffi/src/types.rs @@ -17,7 +17,7 @@ pub struct WalletHandle { _private: [u8; 0], } -/// 32-byte array type for AccountId, keys, hashes, etc. +/// 32-byte array type for `AccountId`, keys, hashes, etc. #[repr(C)] #[derive(Clone, Copy, Default)] pub struct FfiBytes32 { @@ -103,7 +103,7 @@ pub struct FfiAccountListEntry { pub is_public: bool, } -/// List of accounts returned by wallet_ffi_list_accounts. +/// List of accounts returned by `wallet_ffi_list_accounts`. #[repr(C)] pub struct FfiAccountList { pub entries: *mut FfiAccountListEntry, @@ -142,17 +142,20 @@ impl Default for FfiTransferResult { impl FfiBytes32 { /// Create from a 32-byte array. + #[must_use] pub fn from_bytes(bytes: [u8; 32]) -> Self { Self { data: bytes } } - /// Create from an AccountId. + /// Create from an `AccountId`. + #[must_use] pub fn from_account_id(id: &nssa::AccountId) -> Self { Self { data: *id.value() } } } impl FfiPrivateAccountKeys { + #[must_use] pub fn npk(&self) -> nssa_core::NullifierPublicKey { nssa_core::NullifierPublicKey(self.nullifier_public_key.data) } diff --git a/wallet-ffi/src/wallet.rs b/wallet-ffi/src/wallet.rs index 7dd76d4e..26a31c20 100644 --- a/wallet-ffi/src/wallet.rs +++ b/wallet-ffi/src/wallet.rs @@ -15,7 +15,7 @@ use crate::{ types::WalletHandle, }; -/// Internal wrapper around WalletCore with mutex for thread safety. +/// Internal wrapper around `WalletCore` with mutex for thread safety. pub(crate) struct WalletWrapper { pub core: Mutex, } @@ -28,7 +28,7 @@ pub(crate) fn get_wallet( print_error("Null wallet handle"); return Err(WalletFfiError::NullPointer); } - Ok(unsafe { &*(handle as *mut WalletWrapper) }) + Ok(unsafe { &*handle.cast::() }) } /// Helper to get a mutable reference to the wallet wrapper. @@ -40,13 +40,13 @@ pub(crate) fn get_wallet_mut( print_error("Null wallet handle"); return Err(WalletFfiError::NullPointer); } - Ok(unsafe { &mut *(handle as *mut WalletWrapper) }) + Ok(unsafe { &mut *handle.cast::() }) } -/// Helper to convert a C string to a Rust PathBuf. +/// Helper to convert a C string to a Rust `PathBuf`. fn c_str_to_path(ptr: *const c_char, name: &str) -> Result { if ptr.is_null() { - print_error(format!("Null pointer for {}", name)); + print_error(format!("Null pointer for {name}")); return Err(WalletFfiError::NullPointer); } @@ -54,7 +54,7 @@ fn c_str_to_path(ptr: *const c_char, name: &str) -> Result Ok(PathBuf::from(s)), Err(e) => { - print_error(format!("Invalid UTF-8 in {}: {}", name, e)); + print_error(format!("Invalid UTF-8 in {name}: {e}")); Err(WalletFfiError::InvalidUtf8) } } @@ -63,7 +63,7 @@ fn c_str_to_path(ptr: *const c_char, name: &str) -> Result Result { if ptr.is_null() { - print_error(format!("Null pointer for {}", name)); + print_error(format!("Null pointer for {name}")); return Err(WalletFfiError::NullPointer); } @@ -71,7 +71,7 @@ fn c_str_to_string(ptr: *const c_char, name: &str) -> Result Ok(s.to_string()), Err(e) => { - print_error(format!("Invalid UTF-8 in {}: {}", name, e)); + print_error(format!("Invalid UTF-8 in {name}: {e}")); Err(WalletFfiError::InvalidUtf8) } } @@ -99,19 +99,16 @@ pub unsafe extern "C" fn wallet_ffi_create_new( storage_path: *const c_char, password: *const c_char, ) -> *mut WalletHandle { - let config_path = match c_str_to_path(config_path, "config_path") { - Ok(p) => p, - Err(_) => return ptr::null_mut(), + let Ok(config_path) = c_str_to_path(config_path, "config_path") else { + return ptr::null_mut(); }; - let storage_path = match c_str_to_path(storage_path, "storage_path") { - Ok(p) => p, - Err(_) => return ptr::null_mut(), + let Ok(storage_path) = c_str_to_path(storage_path, "storage_path") else { + return ptr::null_mut(); }; - let password = match c_str_to_string(password, "password") { - Ok(s) => s, - Err(_) => return ptr::null_mut(), + let Ok(password) = c_str_to_string(password, "password") else { + return ptr::null_mut(); }; match WalletCore::new_init_storage(config_path, storage_path, None, password) { @@ -119,10 +116,10 @@ pub unsafe extern "C" fn wallet_ffi_create_new( let wrapper = Box::new(WalletWrapper { core: Mutex::new(core), }); - Box::into_raw(wrapper) as *mut WalletHandle + Box::into_raw(wrapper).cast::() } Err(e) => { - print_error(format!("Failed to create wallet: {}", e)); + print_error(format!("Failed to create wallet: {e}")); ptr::null_mut() } } @@ -147,14 +144,12 @@ pub unsafe extern "C" fn wallet_ffi_open( config_path: *const c_char, storage_path: *const c_char, ) -> *mut WalletHandle { - let config_path = match c_str_to_path(config_path, "config_path") { - Ok(p) => p, - Err(_) => return ptr::null_mut(), + let Ok(config_path) = c_str_to_path(config_path, "config_path") else { + return ptr::null_mut(); }; - let storage_path = match c_str_to_path(storage_path, "storage_path") { - Ok(p) => p, - Err(_) => return ptr::null_mut(), + let Ok(storage_path) = c_str_to_path(storage_path, "storage_path") else { + return ptr::null_mut(); }; match WalletCore::new_update_chain(config_path, storage_path, None) { @@ -162,10 +157,10 @@ pub unsafe extern "C" fn wallet_ffi_open( let wrapper = Box::new(WalletWrapper { core: Mutex::new(core), }); - Box::into_raw(wrapper) as *mut WalletHandle + Box::into_raw(wrapper).cast::() } Err(e) => { - print_error(format!("Failed to open wallet: {}", e)); + print_error(format!("Failed to open wallet: {e}")); ptr::null_mut() } } @@ -183,7 +178,7 @@ pub unsafe extern "C" fn wallet_ffi_open( pub unsafe extern "C" fn wallet_ffi_destroy(handle: *mut WalletHandle) { if !handle.is_null() { unsafe { - drop(Box::from_raw(handle as *mut WalletWrapper)); + drop(Box::from_raw(handle.cast::())); } } } @@ -212,18 +207,17 @@ pub unsafe extern "C" fn wallet_ffi_save(handle: *mut WalletHandle) -> WalletFfi let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return WalletFfiError::InternalError; } }; match block_on(wallet.store_persistent_data()) { - Ok(Ok(())) => WalletFfiError::Success, - Ok(Err(e)) => { - print_error(format!("Failed to save wallet: {}", e)); + Ok(()) => WalletFfiError::Success, + Err(e) => { + print_error(format!("Failed to save wallet: {e}")); WalletFfiError::StorageError } - Err(e) => e, } } @@ -241,15 +235,14 @@ pub unsafe extern "C" fn wallet_ffi_save(handle: *mut WalletHandle) -> WalletFfi /// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` #[no_mangle] pub unsafe extern "C" fn wallet_ffi_get_sequencer_addr(handle: *mut WalletHandle) -> *mut c_char { - let wrapper = match get_wallet(handle) { - Ok(w) => w, - Err(_) => return ptr::null_mut(), + let Ok(wrapper) = get_wallet(handle) else { + return ptr::null_mut(); }; let wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { - print_error(format!("Failed to lock wallet: {}", e)); + print_error(format!("Failed to lock wallet: {e}")); return ptr::null_mut(); } }; @@ -259,7 +252,7 @@ pub unsafe extern "C" fn wallet_ffi_get_sequencer_addr(handle: *mut WalletHandle match std::ffi::CString::new(addr) { Ok(s) => s.into_raw(), Err(e) => { - print_error(format!("Invalid sequencer address: {}", e)); + print_error(format!("Invalid sequencer address: {e}")); ptr::null_mut() } } diff --git a/wallet-ffi/wallet_ffi.h b/wallet-ffi/wallet_ffi.h index 6b191506..810feeb5 100644 --- a/wallet-ffi/wallet_ffi.h +++ b/wallet-ffi/wallet_ffi.h @@ -120,7 +120,7 @@ typedef struct WalletHandle { } WalletHandle; /** - * 32-byte array type for AccountId, keys, hashes, etc. + * 32-byte array type for `AccountId`, keys, hashes, etc. */ typedef struct FfiBytes32 { uint8_t data[32]; @@ -135,7 +135,7 @@ typedef struct FfiAccountListEntry { } FfiAccountListEntry; /** - * List of accounts returned by wallet_ffi_list_accounts. + * List of accounts returned by `wallet_ffi_list_accounts`. */ typedef struct FfiAccountList { struct FfiAccountListEntry *entries; diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index 387a8c1c..bd028794 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -159,7 +159,7 @@ impl WalletSubcommand for NewSubcommand { } } -/// Formats account details for display, returning (description, json_view) +/// Formats account details for display, returning (description, `json_view`) fn format_account_details(account: &Account) -> (String, String) { let auth_tr_prog_id = Program::authenticated_transfer_program().id(); let token_prog_id = Program::token().id(); @@ -384,7 +384,7 @@ impl WalletSubcommand for AccountSubcommand { } // Public key tree accounts - for (id, chain_index) in user_data.public_key_tree.account_id_map.iter() { + for (id, chain_index) in &user_data.public_key_tree.account_id_map { println!( "{}", format_with_label(&format!("{chain_index} Public/{id}"), *id) @@ -401,7 +401,7 @@ impl WalletSubcommand for AccountSubcommand { } // Private key tree accounts - for (id, chain_index) in user_data.private_key_tree.account_id_map.iter() { + for (id, chain_index) in &user_data.private_key_tree.account_id_map { println!( "{}", format_with_label(&format!("{chain_index} Private/{id}"), *id) diff --git a/wallet/src/cli/config.rs b/wallet/src/cli/config.rs index bc0e3662..99339132 100644 --- a/wallet/src/cli/config.rs +++ b/wallet/src/cli/config.rs @@ -97,7 +97,7 @@ impl WalletSubcommand for ConfigSubcommand { "seq_poll_timeout" => { wallet_core.storage.wallet_config.seq_poll_timeout = humantime::parse_duration(&value) - .map_err(|e| anyhow::anyhow!("Invalid duration: {}", e))?; + .map_err(|e| anyhow::anyhow!("Invalid duration: {e}"))?; } "seq_tx_poll_max_blocks" => { wallet_core.storage.wallet_config.seq_tx_poll_max_blocks = value.parse()?; @@ -120,7 +120,7 @@ impl WalletSubcommand for ConfigSubcommand { } } - wallet_core.store_config_changes().await? + wallet_core.store_config_changes().await?; } ConfigSubcommand::Description { key } => match key.as_str() { "override_rust_log" => { diff --git a/wallet/src/cli/mod.rs b/wallet/src/cli/mod.rs index 87c2bb31..42e2b4b2 100644 --- a/wallet/src/cli/mod.rs +++ b/wallet/src/cli/mod.rs @@ -68,11 +68,11 @@ pub enum Command { DeployProgram { binary_filepath: PathBuf }, } -/// To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config +/// To execute commands, env var `NSSA_WALLET_HOME_DIR` must be set into directory with config /// /// All account addresses must be valid 32 byte base58 strings. /// -/// All account account_ids must be provided as {privacy_prefix}/{account_id}, +/// All account `account_ids` must be provided as {`privacy_prefix}/{account_id`}, /// where valid options for `privacy_prefix` is `Public` and `Private` #[derive(Parser, Debug)] #[clap(version, about)] @@ -124,27 +124,31 @@ pub async fn execute_subcommand( else { panic!("Missing authenticated transfer ID from remote"); }; - if authenticated_transfer_id != &Program::authenticated_transfer_program().id() { - panic!("Local ID for authenticated transfer program is different from remote"); - } + assert!( + authenticated_transfer_id == &Program::authenticated_transfer_program().id(), + "Local ID for authenticated transfer program is different from remote" + ); let Some(token_id) = remote_program_ids.get("token") else { panic!("Missing token program ID from remote"); }; - if token_id != &Program::token().id() { - panic!("Local ID for token program is different from remote"); - } + assert!( + token_id == &Program::token().id(), + "Local ID for token program is different from remote" + ); let Some(circuit_id) = remote_program_ids.get("privacy_preserving_circuit") else { panic!("Missing privacy preserving circuit ID from remote"); }; - if circuit_id != &nssa::PRIVACY_PRESERVING_CIRCUIT_ID { - panic!("Local ID for privacy preserving circuit is different from remote"); - } + assert!( + circuit_id == &nssa::PRIVACY_PRESERVING_CIRCUIT_ID, + "Local ID for privacy preserving circuit is different from remote" + ); let Some(amm_id) = remote_program_ids.get("amm") else { panic!("Missing AMM program ID from remote"); }; - if amm_id != &Program::amm().id() { - panic!("Local ID for AMM program is different from remote"); - } + assert!( + amm_id == &Program::amm().id(), + "Local ID for AMM program is different from remote" + ); println!("✅All looks good!"); diff --git a/wallet/src/cli/programs/amm.rs b/wallet/src/cli/programs/amm.rs index ce919b7c..5da445d6 100644 --- a/wallet/src/cli/programs/amm.rs +++ b/wallet/src/cli/programs/amm.rs @@ -14,17 +14,17 @@ use crate::{ pub enum AmmProgramAgnosticSubcommand { /// Produce a new pool /// - /// user_holding_a and user_holding_b must be owned. + /// `user_holding_a` and `user_holding_b` must be owned. /// /// Only public execution allowed New { - /// user_holding_a - valid 32 byte base58 string with privacy prefix + /// `user_holding_a` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_a: String, - /// user_holding_b - valid 32 byte base58 string with privacy prefix + /// `user_holding_b` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_b: String, - /// user_holding_lp - valid 32 byte base58 string with privacy prefix + /// `user_holding_lp` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_lp: String, #[arg(long)] @@ -38,33 +38,33 @@ pub enum AmmProgramAgnosticSubcommand { /// /// Only public execution allowed Swap { - /// user_holding_a - valid 32 byte base58 string with privacy prefix + /// `user_holding_a` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_a: String, - /// user_holding_b - valid 32 byte base58 string with privacy prefix + /// `user_holding_b` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_b: String, #[arg(long)] amount_in: u128, #[arg(long)] min_amount_out: u128, - /// token_definition - valid 32 byte base58 string WITHOUT privacy prefix + /// `token_definition` - valid 32 byte base58 string WITHOUT privacy prefix #[arg(long)] token_definition: String, }, /// Add liquidity /// - /// user_holding_a and user_holding_b must be owned. + /// `user_holding_a` and `user_holding_b` must be owned. /// /// Only public execution allowed AddLiquidity { - /// user_holding_a - valid 32 byte base58 string with privacy prefix + /// `user_holding_a` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_a: String, - /// user_holding_b - valid 32 byte base58 string with privacy prefix + /// `user_holding_b` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_b: String, - /// user_holding_lp - valid 32 byte base58 string with privacy prefix + /// `user_holding_lp` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_lp: String, #[arg(long)] @@ -76,17 +76,17 @@ pub enum AmmProgramAgnosticSubcommand { }, /// Remove liquidity /// - /// user_holding_lp must be owned. + /// `user_holding_lp` must be owned. /// /// Only public execution allowed RemoveLiquidity { - /// user_holding_a - valid 32 byte base58 string with privacy prefix + /// `user_holding_a` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_a: String, - /// user_holding_b - valid 32 byte base58 string with privacy prefix + /// `user_holding_b` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_b: String, - /// user_holding_lp - valid 32 byte base58 string with privacy prefix + /// `user_holding_lp` - valid 32 byte base58 string with privacy prefix #[arg(long)] user_holding_lp: String, #[arg(long)] diff --git a/wallet/src/cli/programs/native_token_transfer.rs b/wallet/src/cli/programs/native_token_transfer.rs index 9dd4fca6..f03194ca 100644 --- a/wallet/src/cli/programs/native_token_transfer.rs +++ b/wallet/src/cli/programs/native_token_transfer.rs @@ -16,7 +16,7 @@ use crate::{ pub enum AuthTransferSubcommand { /// Initialize account under authenticated transfer program Init { - /// account_id - valid 32 byte base58 string with privacy prefix + /// `account_id` - valid 32 byte base58 string with privacy prefix #[arg(long)] account_id: String, }, @@ -33,10 +33,10 @@ pub enum AuthTransferSubcommand { /// to - valid 32 byte base58 string with privacy prefix #[arg(long)] to: Option, - /// to_npk - valid 32 byte hex string + /// `to_npk` - valid 32 byte hex string #[arg(long)] to_npk: Option, - /// to_vpk - valid 33 byte hex string + /// `to_vpk` - valid 33 byte hex string #[arg(long)] to_vpk: Option, /// amount - amount of balance to move @@ -87,7 +87,7 @@ impl WalletSubcommand for AuthTransferSubcommand { let acc_decode_data = vec![Decode(secret, account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -252,10 +252,10 @@ pub enum NativeTokenTransferProgramSubcommandShielded { /// from - valid 32 byte hex string #[arg(long)] from: String, - /// to_npk - valid 32 byte hex string + /// `to_npk` - valid 32 byte hex string #[arg(long)] to_npk: String, - /// to_vpk - valid 33 byte hex string + /// `to_vpk` - valid 33 byte hex string #[arg(long)] to_vpk: String, /// amount - amount of balance to move @@ -289,10 +289,10 @@ pub enum NativeTokenTransferProgramSubcommandPrivate { /// from - valid 32 byte hex string #[arg(long)] from: String, - /// to_npk - valid 32 byte hex string + /// `to_npk` - valid 32 byte hex string #[arg(long)] to_npk: String, - /// to_vpk - valid 33 byte hex string + /// `to_vpk` - valid 33 byte hex string #[arg(long)] to_vpk: String, /// amount - amount of balance to move @@ -324,7 +324,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { let acc_decode_data = vec![Decode(secret_from, from), Decode(secret_to, to)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -364,7 +364,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { let acc_decode_data = vec![Decode(secret_from, from)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -400,7 +400,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { let acc_decode_data = vec![Decode(secret, to)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -473,7 +473,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { let acc_decode_data = vec![Decode(secret, from)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } diff --git a/wallet/src/cli/programs/pinata.rs b/wallet/src/cli/programs/pinata.rs index d7e28528..1fec8058 100644 --- a/wallet/src/cli/programs/pinata.rs +++ b/wallet/src/cli/programs/pinata.rs @@ -69,10 +69,10 @@ pub enum PinataProgramSubcommandPublic { // TODO: Testnet only. Refactor to prevent compilation on mainnet. // Claim piñata prize Claim { - /// pinata_account_id - valid 32 byte hex string + /// `pinata_account_id` - valid 32 byte hex string #[arg(long)] pinata_account_id: String, - /// winner_account_id - valid 32 byte hex string + /// `winner_account_id` - valid 32 byte hex string #[arg(long)] winner_account_id: String, }, @@ -84,10 +84,10 @@ pub enum PinataProgramSubcommandPrivate { // TODO: Testnet only. Refactor to prevent compilation on mainnet. // Claim piñata prize ClaimPrivateOwned { - /// pinata_account_id - valid 32 byte hex string + /// `pinata_account_id` - valid 32 byte hex string #[arg(long)] pinata_account_id: String, - /// winner_account_id - valid 32 byte hex string + /// `winner_account_id` - valid 32 byte hex string #[arg(long)] winner_account_id: String, }, @@ -163,7 +163,7 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate { let acc_decode_data = vec![Decode(secret_winner, winner_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } diff --git a/wallet/src/cli/programs/token.rs b/wallet/src/cli/programs/token.rs index 2f83d4ce..805cbbd4 100644 --- a/wallet/src/cli/programs/token.rs +++ b/wallet/src/cli/programs/token.rs @@ -16,10 +16,10 @@ use crate::{ pub enum TokenProgramAgnosticSubcommand { /// Produce a new token New { - /// definition_account_id - valid 32 byte base58 string with privacy prefix + /// `definition_account_id` - valid 32 byte base58 string with privacy prefix #[arg(long)] definition_account_id: String, - /// supply_account_id - valid 32 byte base58 string with privacy prefix + /// `supply_account_id` - valid 32 byte base58 string with privacy prefix #[arg(long)] supply_account_id: String, #[arg(short, long)] @@ -40,10 +40,10 @@ pub enum TokenProgramAgnosticSubcommand { /// to - valid 32 byte base58 string with privacy prefix #[arg(long)] to: Option, - /// to_npk - valid 32 byte hex string + /// `to_npk` - valid 32 byte hex string #[arg(long)] to_npk: Option, - /// to_vpk - valid 33 byte hex string + /// `to_vpk` - valid 33 byte hex string #[arg(long)] to_vpk: Option, /// amount - amount of balance to move @@ -82,10 +82,10 @@ pub enum TokenProgramAgnosticSubcommand { /// holder - valid 32 byte base58 string with privacy prefix #[arg(long)] holder: Option, - /// holder_npk - valid 32 byte hex string + /// `holder_npk` - valid 32 byte hex string #[arg(long)] holder_npk: Option, - /// to_vpk - valid 33 byte hex string + /// `to_vpk` - valid 33 byte hex string #[arg(long)] holder_vpk: Option, /// amount - amount of balance to mint @@ -394,7 +394,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { } } -/// Represents generic CLI subcommand for a wallet working with token_program +/// Represents generic CLI subcommand for a wallet working with `token_program` #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramSubcommand { /// Creation of new token @@ -414,7 +414,7 @@ pub enum TokenProgramSubcommand { Shielded(TokenProgramSubcommandShielded), } -/// Represents generic public CLI subcommand for a wallet working with token_program +/// Represents generic public CLI subcommand for a wallet working with `token_program` #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramSubcommandPublic { // Transfer tokens using the token program @@ -446,7 +446,7 @@ pub enum TokenProgramSubcommandPublic { }, } -/// Represents generic private CLI subcommand for a wallet working with token_program +/// Represents generic private CLI subcommand for a wallet working with `token_program` #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramSubcommandPrivate { // Transfer tokens using the token program @@ -462,10 +462,10 @@ pub enum TokenProgramSubcommandPrivate { TransferTokenPrivateForeign { #[arg(short, long)] sender_account_id: String, - /// recipient_npk - valid 32 byte hex string + /// `recipient_npk` - valid 32 byte hex string #[arg(long)] recipient_npk: String, - /// recipient_vpk - valid 33 byte hex string + /// `recipient_vpk` - valid 33 byte hex string #[arg(long)] recipient_vpk: String, #[arg(short, long)] @@ -502,7 +502,7 @@ pub enum TokenProgramSubcommandPrivate { }, } -/// Represents deshielded public CLI subcommand for a wallet working with token_program +/// Represents deshielded public CLI subcommand for a wallet working with `token_program` #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramSubcommandDeshielded { // Transfer tokens using the token program @@ -534,7 +534,7 @@ pub enum TokenProgramSubcommandDeshielded { }, } -/// Represents generic shielded CLI subcommand for a wallet working with token_program +/// Represents generic shielded CLI subcommand for a wallet working with `token_program` #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramSubcommandShielded { // Transfer tokens using the token program @@ -550,10 +550,10 @@ pub enum TokenProgramSubcommandShielded { TransferTokenShieldedForeign { #[arg(short, long)] sender_account_id: String, - /// recipient_npk - valid 32 byte hex string + /// `recipient_npk` - valid 32 byte hex string #[arg(long)] recipient_npk: String, - /// recipient_vpk - valid 33 byte hex string + /// `recipient_vpk` - valid 33 byte hex string #[arg(long)] recipient_vpk: String, #[arg(short, long)] @@ -590,7 +590,7 @@ pub enum TokenProgramSubcommandShielded { }, } -/// Represents generic initialization subcommand for a wallet working with token_program +/// Represents generic initialization subcommand for a wallet working with `token_program` #[derive(Subcommand, Debug, Clone)] pub enum CreateNewTokenProgramSubcommand { /// Create a new token using the token program @@ -733,7 +733,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -779,7 +779,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let acc_decode_data = vec![Decode(secret_sender, sender_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -816,7 +816,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -853,7 +853,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -900,7 +900,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -944,7 +944,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { let acc_decode_data = vec![Decode(secret_sender, sender_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -978,7 +978,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -1012,7 +1012,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -1097,7 +1097,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let acc_decode_data = vec![Decode(secret_recipient, recipient_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -1131,7 +1131,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let acc_decode_data = vec![Decode(secret_holder, holder_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -1165,7 +1165,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let acc_decode_data = vec![Decode(secret_holder, holder_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -1256,7 +1256,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { ]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -1292,7 +1292,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } @@ -1328,7 +1328,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { let acc_decode_data = vec![Decode(secret_supply, supply_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( - tx, + &tx, &acc_decode_data, )?; } diff --git a/wallet/src/config.rs b/wallet/src/config.rs index 3780a065..c555e4ed 100644 --- a/wallet/src/config.rs +++ b/wallet/src/config.rs @@ -71,6 +71,7 @@ pub enum PersistentAccountData { pub struct Label(String); impl Label { + #[must_use] pub fn new(label: String) -> Self { Self(label) } @@ -112,6 +113,7 @@ impl PersistentStorage { } impl InitialAccountData { + #[must_use] pub fn account_id(&self) -> nssa::AccountId { match &self { Self::Public(acc) => acc.account_id, @@ -121,6 +123,7 @@ impl InitialAccountData { } impl PersistentAccountData { + #[must_use] pub fn account_id(&self) -> nssa::AccountId { match &self { Self::Public(acc) => acc.account_id, @@ -513,12 +516,13 @@ impl WalletConfig { let config_home = config_path.parent().ok_or_else(|| { anyhow::anyhow!( - "Could not get parent directory of config file at {config_path:#?}" + "Could not get parent directory of config file at {}", + config_path.display() ) })?; std::fs::create_dir_all(config_home)?; - println!("Created configs dir at path {config_home:#?}"); + println!("Created configs dir at path {}", config_home.display()); let mut file = std::fs::OpenOptions::new() .write(true) diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index ce2b3a57..fb3f8f8f 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -54,6 +54,7 @@ pub fn fetch_persistent_storage_path() -> Result { } /// Produces data for storage +#[must_use] pub fn produce_data_for_storage( user_data: &NSSAUserData, last_synced_block: u64, @@ -94,7 +95,7 @@ pub fn produce_data_for_storage( pub_sign_key: key.clone(), }) .into(), - ) + ); } for (account_id, (key_chain, account)) in &user_data.default_user_private_accounts { @@ -105,7 +106,7 @@ pub fn produce_data_for_storage( key_chain: key_chain.clone(), }) .into(), - ) + ); } PersistentStorage { @@ -117,7 +118,9 @@ pub fn produce_data_for_storage( pub(crate) fn produce_random_nonces(size: usize) -> Vec { let mut result = vec![[0; 16]; size]; - result.iter_mut().for_each(|bytes| OsRng.fill_bytes(bytes)); + for bytes in &mut result { + OsRng.fill_bytes(bytes); + } result.into_iter().map(Nonce::from_le_bytes).collect() } diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 8d8924cf..f7f0d62c 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -70,8 +70,12 @@ impl WalletCore { accounts: persistent_accounts, last_synced_block, labels, - } = PersistentStorage::from_path(&storage_path) - .with_context(|| format!("Failed to read persistent storage at {storage_path:#?}"))?; + } = PersistentStorage::from_path(&storage_path).with_context(|| { + format!( + "Failed to read persistent storage at {}", + storage_path.display() + ) + })?; Self::new( config_path, @@ -104,8 +108,13 @@ impl WalletCore { storage_ctor: impl FnOnce(WalletConfig) -> Result, last_synced_block: u64, ) -> Result { - let mut config = WalletConfig::from_path_or_initialize_default(&config_path) - .with_context(|| format!("Failed to deserialize wallet config at {config_path:#?}"))?; + let mut config = + WalletConfig::from_path_or_initialize_default(&config_path).with_context(|| { + format!( + "Failed to deserialize wallet config at {}", + config_path.display() + ) + })?; if let Some(config_overrides) = config_overrides.clone() { config.apply_overrides(config_overrides); } @@ -114,7 +123,7 @@ impl WalletCore { config.sequencer_addr.clone(), config.basic_auth.clone(), )?); - let tx_poller = TxPoller::new(config.clone(), Arc::clone(&sequencer_client)); + let tx_poller = TxPoller::new(&config, Arc::clone(&sequencer_client)); let storage = storage_ctor(config)?; @@ -130,11 +139,13 @@ impl WalletCore { } /// Get configuration with applied overrides + #[must_use] pub fn config(&self) -> &WalletConfig { &self.storage.wallet_config } /// Get storage + #[must_use] pub fn storage(&self) -> &WalletChainStore { &self.storage } @@ -159,7 +170,10 @@ impl WalletCore { // Ensure data is flushed to disk before returning to prevent race conditions storage_file.sync_all().await?; - println!("Stored persistent accounts at {:#?}", self.storage_path); + println!( + "Stored persistent accounts at {}", + self.storage_path.display() + ); Ok(()) } @@ -173,7 +187,7 @@ impl WalletCore { // Ensure data is flushed to disk before returning to prevent race conditions config_file.sync_all().await?; - info!("Stored data at {:#?}", self.config_path); + info!("Stored data at {}", self.config_path.display()); Ok(()) } @@ -220,6 +234,7 @@ impl WalletCore { Ok(response.account) } + #[must_use] pub fn get_account_public_signing_key( &self, account_id: AccountId, @@ -229,6 +244,7 @@ impl WalletCore { .get_pub_account_signing_key(account_id) } + #[must_use] pub fn get_account_private(&self, account_id: AccountId) -> Option { self.storage .user_data @@ -236,6 +252,7 @@ impl WalletCore { .map(|value| value.1.clone()) } + #[must_use] pub fn get_private_account_commitment(&self, account_id: AccountId) -> Option { let (keys, account) = self.storage.user_data.get_private_account(account_id)?; Some(Commitment::new(&keys.nullifer_public_key, account)) @@ -266,7 +283,7 @@ impl WalletCore { pub fn decode_insert_privacy_preserving_transaction_results( &mut self, - tx: nssa::privacy_preserving_transaction::PrivacyPreservingTransaction, + tx: &nssa::privacy_preserving_transaction::PrivacyPreservingTransaction, acc_decode_mask: &[AccDecodeData], ) -> Result<()> { for (output_index, acc_decode_data) in acc_decode_mask.iter().enumerate() { @@ -279,7 +296,9 @@ impl WalletCore { &acc_ead.ciphertext, secret, &acc_comm, - output_index as u32, + output_index + .try_into() + .expect("Output index is expected to fit in u32"), ) .unwrap(); @@ -433,8 +452,8 @@ impl WalletCore { let affected_accounts = private_account_key_chains .flat_map(|(acc_account_id, key_chain, index)| { let view_tag = EncryptedAccountData::compute_view_tag( - key_chain.nullifer_public_key.clone(), - key_chain.viewing_public_key.clone(), + &key_chain.nullifer_public_key, + &key_chain.viewing_public_key, ); tx.message() @@ -445,14 +464,16 @@ impl WalletCore { .filter_map(|(ciph_id, encrypted_data)| { let ciphertext = &encrypted_data.ciphertext; let commitment = &tx.message.new_commitments[ciph_id]; - let shared_secret = key_chain - .calculate_shared_secret_receiver(encrypted_data.epk.clone(), index); + let shared_secret = + key_chain.calculate_shared_secret_receiver(&encrypted_data.epk, index); nssa_core::EncryptionScheme::decrypt( ciphertext, &shared_secret, commitment, - ciph_id as u32, + ciph_id + .try_into() + .expect("Ciphertext ID is expected to fit in u32"), ) }) .map(move |res_acc| (acc_account_id, res_acc)) @@ -469,14 +490,17 @@ impl WalletCore { } } + #[must_use] pub fn config_path(&self) -> &PathBuf { &self.config_path } + #[must_use] pub fn storage_path(&self) -> &PathBuf { &self.storage_path } + #[must_use] pub fn config_overrides(&self) -> &Option { &self.config_overrides } diff --git a/wallet/src/main.rs b/wallet/src/main.rs index 045b1b83..b2057296 100644 --- a/wallet/src/main.rs +++ b/wallet/src/main.rs @@ -33,7 +33,9 @@ async fn main() -> Result<()> { }; if let Some(command) = command { - let mut wallet = if !storage_path.exists() { + let mut wallet = if storage_path.exists() { + WalletCore::new_update_chain(config_path, storage_path, Some(config_overrides))? + } else { // TODO: Maybe move to `WalletCore::from_env()` or similar? println!("Persistent storage not found, need to execute setup"); @@ -48,8 +50,6 @@ async fn main() -> Result<()> { wallet.store_persistent_data().await?; wallet - } else { - WalletCore::new_update_chain(config_path, storage_path, Some(config_overrides))? }; let _output = execute_subcommand(&mut wallet, command).await?; Ok(()) diff --git a/wallet/src/poller.rs b/wallet/src/poller.rs index c037a36a..7f0d4e7f 100644 --- a/wallet/src/poller.rs +++ b/wallet/src/poller.rs @@ -17,13 +17,14 @@ pub struct TxPoller { } impl TxPoller { - pub fn new(config: WalletConfig, client: Arc) -> Self { + #[must_use] + pub fn new(config: &WalletConfig, client: Arc) -> Self { Self { polling_delay: config.seq_poll_timeout, polling_max_blocks_to_query: config.seq_tx_poll_max_blocks, polling_max_error_attempts: config.seq_poll_max_retries, block_poll_max_amount: config.seq_block_poll_max_amount, - client: client.clone(), + client, } } @@ -43,14 +44,13 @@ impl TxPoller { .get_transaction_by_hash(tx_hash) .await .inspect_err(|err| { - warn!("Failed to get transaction by hash {tx_hash} with error: {err:#?}") + warn!("Failed to get transaction by hash {tx_hash} with error: {err:#?}"); }); if let Ok(tx_obj) = tx_obj { break tx_obj; - } else { - try_error_counter += 1; } + try_error_counter += 1; if try_error_counter > self.polling_max_error_attempts { anyhow::bail!("Number of retries exceeded"); diff --git a/wallet/src/privacy_preserving_tx.rs b/wallet/src/privacy_preserving_tx.rs index e43966d4..8726fc51 100644 --- a/wallet/src/privacy_preserving_tx.rs +++ b/wallet/src/privacy_preserving_tx.rs @@ -21,10 +21,12 @@ pub enum PrivacyPreservingAccount { } impl PrivacyPreservingAccount { + #[must_use] pub fn is_public(&self) -> bool { matches!(&self, Self::Public(_)) } + #[must_use] pub fn is_private(&self) -> bool { matches!( &self, @@ -124,7 +126,7 @@ impl AccountManager { .iter() .filter_map(|state| match state { State::Public { account, sk } => sk.as_ref().map(|_| account.account.nonce), - _ => None, + State::Private(_) => None, }) .collect() } @@ -143,7 +145,7 @@ impl AccountManager { epk: eph_holder.generate_ephemeral_public_key(), }) } - _ => None, + State::Public { .. } => None, }) .collect() } @@ -153,7 +155,7 @@ impl AccountManager { .iter() .filter_map(|state| match state { State::Private(pre) => pre.nsk, - _ => None, + State::Public { .. } => None, }) .collect() } @@ -163,7 +165,7 @@ impl AccountManager { .iter() .filter_map(|state| match state { State::Private(pre) => Some(pre.proof.clone()), - _ => None, + State::Public { .. } => None, }) .collect() } @@ -173,7 +175,7 @@ impl AccountManager { .iter() .filter_map(|state| match state { State::Public { account, .. } => Some(account.account_id), - _ => None, + State::Private(_) => None, }) .collect() } @@ -183,7 +185,7 @@ impl AccountManager { .iter() .filter_map(|state| match state { State::Public { sk, .. } => sk.as_ref(), - _ => None, + State::Private(_) => None, }) .collect() }