diff --git a/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs b/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs index 83f593a..61f431c 100644 --- a/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs +++ b/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs @@ -32,11 +32,13 @@ fn main() { // Check that the program is well behaved. // See the # Programs section for the definition of the `validate_execution` method. - validate_execution(&pre_states, &post_states, program_id); + if !validate_execution(&pre_states, &post_states, program_id) { + panic!("Bad behaved program"); + } let n_accounts = pre_states.len(); if visibility_mask.len() != n_accounts { - panic!(); + panic!("Invalid visibility mask length"); } // These lists will be the public outputs of this circuit @@ -59,7 +61,9 @@ fn main() { public_pre_states.push(pre_states[i].clone()); let mut post = post_states[i].clone(); - post.nonce += 1; + if pre_states[i].is_authorized { + post.nonce += 1; + } if post.program_owner == DEFAULT_PROGRAM_ID { // Claim account post.program_owner = program_id; @@ -136,7 +140,7 @@ fn main() { } if private_keys_iter.next().is_some() { - panic!("Too many private accounts keys."); + panic!("Too many private account keys."); } if private_auth_iter.next().is_some() { diff --git a/nssa/src/error.rs b/nssa/src/error.rs index 1d6d6ad..0e85789 100644 --- a/nssa/src/error.rs +++ b/nssa/src/error.rs @@ -45,4 +45,7 @@ pub enum NssaError { #[error("Invalid privacy preserving execution circuit proof")] InvalidPrivacyPreservingProof, + + #[error("Circuit proving error")] + CircuitProvingError(String), } diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 1421f62..8a62087 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -47,7 +47,9 @@ pub fn execute_and_prove( env_builder.write(&circuit_input).unwrap(); let env = env_builder.build().unwrap(); let prover = default_prover(); - let prove_info = prover.prove(env, PRIVACY_PRESERVING_CIRCUIT_ELF).unwrap(); + let prove_info = prover + .prove(env, PRIVACY_PRESERVING_CIRCUIT_ELF) + .map_err(|e| NssaError::CircuitProvingError(e.to_string()))?; let proof = Proof(borsh::to_vec(&prove_info.receipt.inner)?); @@ -109,6 +111,7 @@ mod tests { let program = Program::authenticated_transfer_program(); let sender = AccountWithMetadata { account: Account { + program_owner: program.id(), balance: 100, ..Account::default() }, @@ -175,11 +178,13 @@ mod tests { #[test] fn prove_privacy_preserving_execution_circuit_fully_private() { + let program = Program::authenticated_transfer_program(); let sender_pre = AccountWithMetadata { account: Account { balance: 100, nonce: 0xdeadbeef, - ..Account::default() + program_owner: program.id(), + data: vec![], }, is_authorized: true, }; diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 9ca3a19..3dfca41 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -151,12 +151,6 @@ impl V01State { *current_account = post; } - // // 5. Increment nonces - for address in tx.signer_addresses() { - let current_account = self.get_account_by_address_mut(address); - current_account.nonce += 1; - } - Ok(()) } @@ -225,6 +219,7 @@ pub mod tests { use crate::{ Address, PublicKey, PublicTransaction, V01State, error::NssaError, + execute_and_prove, privacy_preserving_transaction::{ PrivacyPreservingTransaction, circuit, message::Message, witness_set::WitnessSet, }, @@ -954,6 +949,13 @@ pub mod tests { &state, ); + let expected_sender_post = { + let mut this = state.get_account_by_address(&sender_keys.address()); + this.balance -= balance_to_move; + this.nonce += 1; + this + }; + let [expected_new_commitment] = tx.message().new_commitments.clone().try_into().unwrap(); assert!(!state.private_state.0.contains(&expected_new_commitment)); @@ -961,6 +963,8 @@ pub mod tests { .transition_from_privacy_preserving_transaction(&tx) .unwrap(); + let sender_post = state.get_account_by_address(&sender_keys.address()); + assert_eq!(sender_post, expected_sender_post); assert!(state.private_state.0.contains(&expected_new_commitment)); assert_eq!( @@ -1053,6 +1057,12 @@ pub mod tests { let balance_to_move = 37; + let expected_recipient_post = { + let mut this = state.get_account_by_address(&recipient_keys.address()); + this.balance += balance_to_move; + this + }; + let tx = deshielded_balance_transfer_for_tests( &sender_keys, &sender_private_account, @@ -1083,6 +1093,8 @@ pub mod tests { .transition_from_privacy_preserving_transaction(&tx) .unwrap(); + let recipient_post = state.get_account_by_address(&recipient_keys.address()); + assert_eq!(recipient_post, expected_recipient_post); assert!(state.private_state.0.contains(&sender_pre_commitment)); assert!(state.private_state.0.contains(&expected_new_commitment)); assert!(state.private_state.1.contains(&expected_new_nullifier)); @@ -1093,4 +1105,809 @@ pub mod tests { recipient_initial_balance + balance_to_move ); } + + #[test] + fn test_burner_program_should_fail_in_privacy_preserving_circuit() { + let program = Program::burner(); + let public_account = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + + let result = execute_and_prove( + &[public_account], + &Program::serialize_instruction(10u128).unwrap(), + &[0], + &[], + &[], + &[], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_minter_program_should_fail_in_privacy_preserving_circuit() { + let program = Program::minter(); + let public_account = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 0, + ..Account::default() + }, + is_authorized: true, + }; + + let result = execute_and_prove( + &[public_account], + &Program::serialize_instruction(10u128).unwrap(), + &[0], + &[], + &[], + &[], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_nonce_changer_program_should_fail_in_privacy_preserving_circuit() { + let program = Program::nonce_changer_program(); + let public_account = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 0, + ..Account::default() + }, + is_authorized: true, + }; + + let result = execute_and_prove( + &[public_account], + &Program::serialize_instruction(()).unwrap(), + &[0], + &[], + &[], + &[], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_data_changer_program_should_fail_for_non_owned_account_in_privacy_preserving_circuit() { + let program = Program::data_changer(); + let public_account = AccountWithMetadata { + account: Account { + program_owner: [0, 1, 2, 3, 4, 5, 6, 7], + balance: 0, + ..Account::default() + }, + is_authorized: true, + }; + + let result = execute_and_prove( + &[public_account], + &Program::serialize_instruction(()).unwrap(), + &[0], + &[], + &[], + &[], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_extra_output_program_should_fail_in_privacy_preserving_circuit() { + let program = Program::extra_output_program(); + let public_account = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 0, + ..Account::default() + }, + is_authorized: true, + }; + + let result = execute_and_prove( + &[public_account], + &Program::serialize_instruction(()).unwrap(), + &[0], + &[], + &[], + &[], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_missing_output_program_should_fail_in_privacy_preserving_circuit() { + let program = Program::missing_output_program(); + let public_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 0, + ..Account::default() + }, + is_authorized: true, + }; + let public_account_2 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 0, + ..Account::default() + }, + is_authorized: true, + }; + + let result = execute_and_prove( + &[public_account_1, public_account_2], + &Program::serialize_instruction(()).unwrap(), + &[0, 0], + &[], + &[], + &[], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_program_owner_changer_should_fail_in_privacy_preserving_circuit() { + let program = Program::program_owner_changer(); + let public_account = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 0, + ..Account::default() + }, + is_authorized: true, + }; + + let result = execute_and_prove( + &[public_account], + &Program::serialize_instruction(()).unwrap(), + &[0], + &[], + &[], + &[], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_transfer_from_non_owned_account_should_fail_in_privacy_preserving_circuit() { + let program = Program::simple_balance_transfer(); + let public_account_1 = AccountWithMetadata { + account: Account { + program_owner: [0, 1, 2, 3, 4, 5, 6, 7], + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let public_account_2 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 0, + ..Account::default() + }, + is_authorized: true, + }; + + let result = execute_and_prove( + &[public_account_1, public_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[0, 0], + &[], + &[], + &[], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_fails_if_visibility_masks_have_incorrect_lenght() { + let program = Program::simple_balance_transfer(); + let public_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let public_account_2 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 0, + ..Account::default() + }, + is_authorized: true, + }; + + // Setting only one visibility mask for a circuit execution with two pre_state accounts. + let visibility_mask = [0]; + let result = execute_and_prove( + &[public_account_1, public_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &visibility_mask, + &[], + &[], + &[], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_fails_if_insufficient_nonces_are_provided() { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account::default(), + is_authorized: false, + }; + + // Setting only one nonce for an execution with two private accounts. + let private_account_nonces = [0xdeadbeef1]; + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &private_account_nonces, + &[ + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ], + &[(sender_keys.nsk, (0, vec![]))], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_fails_if_insufficient_keys_are_provided() { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account::default(), + is_authorized: false, + }; + + // Setting only one key for an execution with two private accounts. + let private_account_keys = [( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + )]; + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &[0xdeadbeef1, 0xdeadbeef2], + &private_account_keys, + &[(sender_keys.nsk, (0, vec![]))], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_fails_if_insufficient_auth_keys_are_provided() { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account::default(), + is_authorized: false, + }; + + // Setting no auth key for an execution with one non default private accounts. + let private_account_auth = []; + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &[0xdeadbeef1, 0xdeadbeef2], + &[ + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ], + &private_account_auth, + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_fails_if_invalid_auth_keys_are_provided() { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account::default(), + is_authorized: false, + }; + + let private_account_keys = [ + // First private account is the sender + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + // Second private account is the recipient + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ]; + let private_account_auth = [ + // Setting the recipient key to authorize the sender. + // This should be set to the sender private account in + // a normal circumstance. The recipient can't authorize this. + (recipient_keys.nsk, (0, vec![])), + ]; + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &[0xdeadbeef1, 0xdeadbeef2], + &private_account_keys, + &private_account_auth, + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_should_fail_if_new_private_account_with_non_default_balance_is_provided() { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account { + // Non default balance + balance: 1, + ..Account::default() + }, + is_authorized: false, + }; + + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &[0xdeadbeef1, 0xdeadbeef2], + &[ + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ], + &[(sender_keys.nsk, (0, vec![]))], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_should_fail_if_new_private_account_with_non_default_program_owner_is_provided() + { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account { + // Non default program_owner + program_owner: [0, 1, 2, 3, 4, 5, 6, 7], + ..Account::default() + }, + is_authorized: false, + }; + + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &[0xdeadbeef1, 0xdeadbeef2], + &[ + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ], + &[(sender_keys.nsk, (0, vec![]))], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_should_fail_if_new_private_account_with_non_default_data_is_provided() { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account { + // Non default data + data: b"hola mundo".to_vec(), + ..Account::default() + }, + is_authorized: false, + }; + + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &[0xdeadbeef1, 0xdeadbeef2], + &[ + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ], + &[(sender_keys.nsk, (0, vec![]))], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_should_fail_if_new_private_account_with_non_default_nonce_is_provided() { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account { + // Non default nonce + nonce: 0xdeadbeef, + ..Account::default() + }, + is_authorized: false, + }; + + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &[0xdeadbeef1, 0xdeadbeef2], + &[ + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ], + &[(sender_keys.nsk, (0, vec![]))], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_should_fail_if_new_private_account_is_provided_with_default_values_but_marked_as_authorized() + { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account::default(), + // This should be set to false in normal circumstances + is_authorized: true, + }; + + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &[0xdeadbeef1, 0xdeadbeef2], + &[ + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ], + &[(sender_keys.nsk, (0, vec![]))], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_should_fail_with_invalid_visibility_mask_value() { + let program = Program::simple_balance_transfer(); + let public_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let public_account_2 = AccountWithMetadata { + account: Account::default(), + is_authorized: false, + }; + + let visibility_mask = [0, 3]; + let result = execute_and_prove( + &[public_account_1, public_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &visibility_mask, + &[], + &[], + &[], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_should_fail_with_too_many_nonces() { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account::default(), + is_authorized: false, + }; + + // Setting three new private account nonces for a circuit execution with only two private + // accounts. + let private_account_nonces = [0xdeadbeef1, 0xdeadbeef2, 0xdeadbeef3]; + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &private_account_nonces, + &[ + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ], + &[(sender_keys.nsk, (0, vec![]))], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_should_fail_with_too_many_private_account_keys() { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account::default(), + is_authorized: false, + }; + + // Setting three private account keys for a circuit execution with only two private + // accounts. + let private_account_keys = [ + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ( + sender_keys.npk(), + SharedSecretKey::new(&[57; 32], &sender_keys.ivk()), + ), + ]; + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &[1, 2], + &[0xdeadbeef1, 0xdeadbeef2], + &private_account_keys, + &[(sender_keys.nsk, (0, vec![]))], + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } + + #[test] + fn test_circuit_should_fail_with_too_many_private_account_auth_keys() { + let program = Program::simple_balance_transfer(); + let sender_keys = test_private_account_keys_1(); + let recipient_keys = test_private_account_keys_2(); + let private_account_1 = AccountWithMetadata { + account: Account { + program_owner: program.id(), + balance: 100, + ..Account::default() + }, + is_authorized: true, + }; + let private_account_2 = AccountWithMetadata { + account: Account::default(), + is_authorized: false, + }; + + // Setting two private account keys for a circuit execution with only one non default + // private account (visibility mask equal to 1 means that auth keys are expected). + let visibility_mask = [1, 2]; + let private_account_auth = [ + (sender_keys.nsk, (0, vec![])), + (recipient_keys.nsk, (1, vec![])), + ]; + let result = execute_and_prove( + &[private_account_1, private_account_2], + &Program::serialize_instruction(10u128).unwrap(), + &visibility_mask, + &[0xdeadbeef1, 0xdeadbeef2], + &[ + ( + sender_keys.npk(), + SharedSecretKey::new(&[55; 32], &sender_keys.ivk()), + ), + ( + recipient_keys.npk(), + SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()), + ), + ], + &private_account_auth, + &program, + ); + + assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + } } diff --git a/nssa/test_program_methods/guest/src/bin/missing_output.rs b/nssa/test_program_methods/guest/src/bin/missing_output.rs index 2174266..7b6016c 100644 --- a/nssa/test_program_methods/guest/src/bin/missing_output.rs +++ b/nssa/test_program_methods/guest/src/bin/missing_output.rs @@ -5,12 +5,12 @@ type Instruction = (); fn main() { let ProgramInput { pre_states, .. } = read_nssa_inputs::(); - let [pre1, _] = match pre_states.try_into() { + let [pre1, pre2] = match pre_states.try_into() { Ok(array) => array, Err(_) => return, }; let account_pre1 = pre1.account.clone(); - write_nssa_outputs(vec![pre1], vec![account_pre1]); + write_nssa_outputs(vec![pre1, pre2], vec![account_pre1]); } diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 010a9ba..f7c6369 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -7,6 +7,13 @@ "block_create_timeout_millis": 10000, "port": 3040, "initial_accounts": [ - + { + "addr": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "balance": 10000 + }, + { + "addr": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "balance": 20000 + } ] -} \ No newline at end of file +} diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index b682a18..068d3d7 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -77,7 +77,9 @@ pub async fn main_runner() -> Result<()> { } //ToDo: Add restart on failures - let (_, _) = startup_sequencer(app_config).await?; + let (_, main_loop_handle) = startup_sequencer(app_config).await?; + + main_loop_handle.await??; Ok(()) }