From d58df166e7dc0159f7c3eb2ba8ab76057e347c3f Mon Sep 17 00:00:00 2001 From: jonesmarvin8 <83104039+jonesmarvin8@users.noreply.github.com> Date: Wed, 25 Feb 2026 15:32:31 -0500 Subject: [PATCH 1/4] initialize branch --- nssa/src/error.rs | 9 +++ nssa/src/public_transaction/transaction.rs | 79 ++++++++++++---------- 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/nssa/src/error.rs b/nssa/src/error.rs index 45d53108..37177465 100644 --- a/nssa/src/error.rs +++ b/nssa/src/error.rs @@ -2,6 +2,15 @@ use std::io; use thiserror::Error; +#[macro_export] +macro_rules! ensure { + ($cond:expr, $err:expr) => { + if !$cond { + return Err($err); + } + }; +} + #[derive(Error, Debug)] pub enum NssaError { #[error("Invalid input: {0}")] diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 7c8f7f74..f5fcc0fb 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -9,7 +9,7 @@ use nssa_core::{ use sha2::{Digest, digest::FixedOutput}; use crate::{ - V02State, + V02State, ensure, error::NssaError, public_transaction::{Message, WitnessSet}, state::MAX_NUMBER_CHAINED_CALLS, @@ -60,33 +60,33 @@ impl PublicTransaction { let witness_set = self.witness_set(); // All account_ids must be different - if message.account_ids.iter().collect::>().len() != message.account_ids.len() { - return Err(NssaError::InvalidInput( - "Duplicate account_ids found in message".into(), - )); - } + ensure!( + message.account_ids.iter().collect::>().len() == message.account_ids.len(), + NssaError::InvalidInput("Duplicate account_ids found in message".into(),) + ); // Check exactly one nonce is provided for each signature - if message.nonces.len() != witness_set.signatures_and_public_keys.len() { - return Err(NssaError::InvalidInput( + ensure!( + message.nonces.len() == witness_set.signatures_and_public_keys.len(), + NssaError::InvalidInput( "Mismatch between number of nonces and signatures/public keys".into(), - )); - } + ) + ); // Check the signatures are valid - if !witness_set.is_valid_for(message) { - return Err(NssaError::InvalidInput( - "Invalid signature for given message and public key".into(), - )); - } + ensure!( + witness_set.is_valid_for(message), + NssaError::InvalidInput("Invalid signature for given message and public key".into()) + ); let signer_account_ids = self.signer_account_ids(); // Check nonces corresponds to the current nonces on the public state. for (account_id, nonce) in signer_account_ids.iter().zip(&message.nonces) { let current_nonce = state.get_account_by_id(*account_id).nonce; - if current_nonce != *nonce { - return Err(NssaError::InvalidInput("Nonce mismatch".into())); - } + ensure!( + current_nonce == *nonce, + NssaError::InvalidInput("Nonce mismatch".into()) + ); } // Build pre_states for execution @@ -115,9 +115,10 @@ impl PublicTransaction { let mut chain_calls_counter = 0; while let Some((chained_call, caller_program_id)) = chained_calls.pop_front() { - if chain_calls_counter > MAX_NUMBER_CHAINED_CALLS { - return Err(NssaError::MaxChainedCallsDepthExceeded); - } + ensure!( + chain_calls_counter <= MAX_NUMBER_CHAINED_CALLS, + NssaError::MaxChainedCallsDepthExceeded + ); // Check that the `program_id` corresponds to a deployed program let Some(program) = state.programs().get(&chained_call.program_id) else { @@ -148,28 +149,31 @@ impl PublicTransaction { .get(&account_id) .cloned() .unwrap_or_else(|| state.get_account_by_id(account_id)); - if pre.account != expected_pre { - return Err(NssaError::InvalidProgramBehavior); - } + ensure!( + pre.account == expected_pre, + NssaError::InvalidProgramBehavior + ); // Check that authorization flags are consistent with the provided ones or // authorized by program through the PDA mechanism let is_authorized = signer_account_ids.contains(&account_id) || authorized_pdas.contains(&account_id); - if pre.is_authorized != is_authorized { - return Err(NssaError::InvalidProgramBehavior); - } + ensure!( + pre.is_authorized == is_authorized, + NssaError::InvalidProgramBehavior + ); } // Verify execution corresponds to a well-behaved program. // See the # Programs section for the definition of the `validate_execution` method. - if !validate_execution( - &program_output.pre_states, - &program_output.post_states, - chained_call.program_id, - ) { - return Err(NssaError::InvalidProgramBehavior); - } + ensure!( + validate_execution( + &program_output.pre_states, + &program_output.post_states, + chained_call.program_id, + ), + NssaError::InvalidProgramBehavior + ); for post in program_output .post_states @@ -211,9 +215,10 @@ impl PublicTransaction { } Some(post) }) { - if post.program_owner == DEFAULT_PROGRAM_ID { - return Err(NssaError::InvalidProgramBehavior); - } + ensure!( + post.program_owner != DEFAULT_PROGRAM_ID, + NssaError::InvalidProgramBehavior + ); } Ok(state_diff) From d029def7c7b8a6c51832532aa4bf965489339770 Mon Sep 17 00:00:00 2001 From: jonesmarvin8 <83104039+jonesmarvin8@users.noreply.github.com> Date: Mon, 9 Mar 2026 12:21:44 -0400 Subject: [PATCH 2/4] add ensure test --- nssa/src/error.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/nssa/src/error.rs b/nssa/src/error.rs index 37177465..19f39c9f 100644 --- a/nssa/src/error.rs +++ b/nssa/src/error.rs @@ -67,3 +67,23 @@ pub enum NssaError { #[error("Chain of calls is too long")] MaxChainedCallsDepthExceeded, } + +#[derive(Debug)] +enum testError { + testErr, +} + + +fn test_function_ensure(cond: bool) -> Result<(), testError> { + ensure!(cond, testError::testErr); + + Ok(()) +} + + +#[test] +fn test_ensure() { + assert!(test_function_ensure(true).is_ok()); + assert!(test_function_ensure(false).is_err()); + +} \ No newline at end of file From b5d0d2d0c151e18a12f789c3380f5fa2671897ae Mon Sep 17 00:00:00 2001 From: jonesmarvin8 <83104039+jonesmarvin8@users.noreply.github.com> Date: Mon, 9 Mar 2026 13:05:29 -0400 Subject: [PATCH 3/4] fmt and lint --- nssa/src/error.rs | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/nssa/src/error.rs b/nssa/src/error.rs index 19f39c9f..83c88998 100644 --- a/nssa/src/error.rs +++ b/nssa/src/error.rs @@ -68,22 +68,23 @@ pub enum NssaError { MaxChainedCallsDepthExceeded, } -#[derive(Debug)] -enum testError { - testErr, +#[cfg(test)] +mod tests { + + #[derive(Debug)] + enum TestError { + TestErr, + } + + fn test_function_ensure(cond: bool) -> Result<(), testError> { + ensure!(cond, TestError::TestErr); + + Ok(()) + } + + #[test] + fn test_ensure() { + assert!(test_function_ensure(true).is_ok()); + assert!(test_function_ensure(false).is_err()); + } } - - -fn test_function_ensure(cond: bool) -> Result<(), testError> { - ensure!(cond, testError::testErr); - - Ok(()) -} - - -#[test] -fn test_ensure() { - assert!(test_function_ensure(true).is_ok()); - assert!(test_function_ensure(false).is_err()); - -} \ No newline at end of file From 6e74cca512288d8328e45c08ca5f3274b3f9160e Mon Sep 17 00:00:00 2001 From: jonesmarvin8 <83104039+jonesmarvin8@users.noreply.github.com> Date: Mon, 16 Mar 2026 09:12:29 -0400 Subject: [PATCH 4/4] fixed unit test --- nssa/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nssa/src/error.rs b/nssa/src/error.rs index 83c88998..c42b70d2 100644 --- a/nssa/src/error.rs +++ b/nssa/src/error.rs @@ -76,7 +76,7 @@ mod tests { TestErr, } - fn test_function_ensure(cond: bool) -> Result<(), testError> { + fn test_function_ensure(cond: bool) -> Result<(), TestError> { ensure!(cond, TestError::TestErr); Ok(())