add test for extra outputs

This commit is contained in:
Sergio Chouhy 2025-08-10 09:57:10 -03:00
parent bfdf039ef3
commit ecdb4ba130
7 changed files with 80 additions and 31 deletions

View File

@ -9,7 +9,7 @@ pub const DEFAULT_PROGRAM_ID: ProgramId = [0; 8];
/// - `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.
pub fn validate_constraints(
pub fn validate_execution(
pre_states: &[AccountWithMetadata],
post_states: &[Account],
executing_program_id: ProgramId,

View File

@ -85,4 +85,14 @@ impl Program {
elf: NONCE_CHANGER_ELF,
}
}
/// A program that produces more output accounts than the inputs it received
pub fn extra_outputs_program() -> Self {
use test_program_methods::{EXTRA_OUTPUTS_ELF, EXTRA_OUTPUTS_ID};
Program {
id: EXTRA_OUTPUTS_ID,
elf: EXTRA_OUTPUTS_ELF,
}
}
}

View File

@ -3,7 +3,7 @@ use crate::{
};
use nssa_core::{
account::{Account, AccountWithMetadata},
program::{ProgramId, validate_constraints},
program::{ProgramId, validate_execution},
};
use std::collections::{HashMap, HashSet};
@ -29,15 +29,18 @@ impl V01State {
})
.collect();
let builtin_programs = HashMap::from([(
authenticated_transfer_program.id(),
authenticated_transfer_program,
)]);
Self {
let mut this = Self {
public_state,
builtin_programs,
}
builtin_programs: HashMap::new(),
};
this.insert_program(Program::authenticated_transfer_program());
this
}
fn insert_program(&mut self, program: Program) {
self.builtin_programs.insert(program.id(), program);
}
pub fn transition_from_public_transaction(
@ -129,8 +132,8 @@ impl V01State {
let post_states = program.execute(&pre_states, message.instruction_data)?;
// Verify execution corresponds to a well-behaved program.
// See the # Programs section for the definition of the `validate_constraints` method.
if !validate_constraints(&pre_states, &post_states, message.program_id) {
// See the # Programs section for the definition of the `validate_execution` method.
if !validate_execution(&pre_states, &post_states, message.program_id) {
return Err(NssaError::InvalidProgramBehavior);
}
@ -143,10 +146,8 @@ impl V01State {
impl V01State {
/// Include test programs in the builtin programs map
pub fn with_test_programs(mut self) -> Self {
self.builtin_programs.insert(
Program::nonce_changer_program().id(),
Program::nonce_changer_program(),
);
self.insert_program(Program::nonce_changer_program());
self.insert_program(Program::extra_outputs_program());
self
}
}

View File

@ -1 +1,2 @@
mod state_tests;
mod valid_execution_tests;

View File

@ -4,21 +4,6 @@ use crate::{
};
use nssa_core::account::Account;
#[test]
fn test_programs_cant_change_account_nonces() {
let initial_data = [([1; 32], 100)];
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
let addresses = vec![Address::new([1; 32])];
let nonces = vec![];
let program_id = Program::nonce_changer_program().id();
let message = public_transaction::Message::new(program_id, addresses, nonces, 5);
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set);
let result = state.transition_from_public_transaction(&tx);
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
}
fn transfer_transaction(
from: Address,

View File

@ -0,0 +1,35 @@
use crate::{
Address, PublicTransaction, V01State, error::NssaError, program::Program, public_transaction,
};
#[test]
fn test_program_should_fail_if_it_modifies_nonces() {
let initial_data = [([1; 32], 100)];
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
let addresses = vec![Address::new([1; 32])];
let nonces = vec![];
let program_id = Program::nonce_changer_program().id();
let message = public_transaction::Message::new(program_id, addresses, nonces, 0);
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set);
let result = state.transition_from_public_transaction(&tx);
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
}
#[test]
fn test_program_should_fail_if_output_accounts_exceed_inputs() {
let initial_data = [([1; 32], 100)];
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
let addresses = vec![Address::new([1; 32])];
let nonces = vec![];
let program_id = Program::extra_outputs_program().id();
let message = public_transaction::Message::new(program_id, addresses, nonces, 0);
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set);
let result = state.transition_from_public_transaction(&tx);
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
}

View File

@ -0,0 +1,17 @@
use nssa_core::account::{Account, AccountWithMetadata};
use risc0_zkvm::guest::env;
fn main() {
let input_accounts: Vec<AccountWithMetadata> = env::read();
let _instruction_data: u128 = env::read();
let [pre] = match input_accounts.try_into() {
Ok(array) => array,
Err(_) => return,
};
let account_pre = pre.account;
env::commit(&vec![account_pre, Account::default()]);
}