Merge pull request #426 from logos-blockchain/moudy/feat-self-program-id

add self_program_id
This commit is contained in:
Moudy 2026-04-02 21:15:32 +02:00 committed by GitHub
commit 42a2f04cd5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
55 changed files with 191 additions and 37 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -19,6 +19,7 @@ fn main() {
// Read inputs // Read inputs
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: greeting, instruction: greeting,
}, },
@ -50,5 +51,11 @@ fn main() {
// with the NSSA program rules. // with the NSSA program rules.
// WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be // WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be
// called to commit the output. // called to commit the output.
ProgramOutput::new(instruction_data, vec![pre_state], vec![post_state]).write(); ProgramOutput::new(
self_program_id,
instruction_data,
vec![pre_state],
vec![post_state],
)
.write();
} }

View File

@ -19,6 +19,7 @@ fn main() {
// Read inputs // Read inputs
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: greeting, instruction: greeting,
}, },
@ -57,5 +58,11 @@ fn main() {
// with the NSSA program rules. // with the NSSA program rules.
// WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be // WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be
// called to commit the output. // called to commit the output.
ProgramOutput::new(instruction_data, vec![pre_state], vec![post_state]).write(); ProgramOutput::new(
self_program_id,
instruction_data,
vec![pre_state],
vec![post_state],
)
.write();
} }

View File

@ -66,6 +66,7 @@ fn main() {
// Read input accounts. // Read input accounts.
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: (function_id, data), instruction: (function_id, data),
}, },
@ -85,5 +86,5 @@ fn main() {
// WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be // WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be
// called to commit the output. // called to commit the output.
ProgramOutput::new(instruction_words, pre_states, post_states).write(); ProgramOutput::new(self_program_id, instruction_words, pre_states, post_states).write();
} }

View File

@ -27,6 +27,7 @@ fn main() {
// Read inputs // Read inputs
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: (), instruction: (),
}, },
@ -55,7 +56,12 @@ fn main() {
// Write the outputs. // Write the outputs.
// WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be // WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be
// called to commit the output. // called to commit the output.
ProgramOutput::new(instruction_data, vec![pre_state], vec![post_state]) ProgramOutput::new(
.with_chained_calls(vec![chained_call]) self_program_id,
.write(); instruction_data,
vec![pre_state],
vec![post_state],
)
.with_chained_calls(vec![chained_call])
.write();
} }

View File

@ -33,6 +33,7 @@ fn main() {
// Read inputs // Read inputs
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: (), instruction: (),
}, },
@ -68,7 +69,12 @@ fn main() {
// Write the outputs. // Write the outputs.
// WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be // WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be
// called to commit the output. // called to commit the output.
ProgramOutput::new(instruction_data, vec![pre_state], vec![post_state]) ProgramOutput::new(
.with_chained_calls(vec![chained_call]) self_program_id,
.write(); instruction_data,
vec![pre_state],
vec![post_state],
)
.with_chained_calls(vec![chained_call])
.write();
} }

View File

@ -16,6 +16,7 @@ pub const MAX_NUMBER_CHAINED_CALLS: usize = 10;
pub type ProgramId = [u32; 8]; pub type ProgramId = [u32; 8];
pub type InstructionData = Vec<u32>; pub type InstructionData = Vec<u32>;
pub struct ProgramInput<T> { pub struct ProgramInput<T> {
pub self_program_id: ProgramId,
pub pre_states: Vec<AccountWithMetadata>, pub pre_states: Vec<AccountWithMetadata>,
pub instruction: T, pub instruction: T,
} }
@ -281,6 +282,8 @@ pub struct InvalidWindow;
#[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))] #[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))]
#[must_use = "ProgramOutput does nothing unless written"] #[must_use = "ProgramOutput does nothing unless written"]
pub struct ProgramOutput { pub struct ProgramOutput {
/// The program ID of the program that produced this output.
pub self_program_id: ProgramId,
/// The instruction data the program received to produce this output. /// The instruction data the program received to produce this output.
pub instruction_data: InstructionData, pub instruction_data: InstructionData,
/// The account pre states the program received to produce this output. /// The account pre states the program received to produce this output.
@ -297,11 +300,13 @@ pub struct ProgramOutput {
impl ProgramOutput { impl ProgramOutput {
pub const fn new( pub const fn new(
self_program_id: ProgramId,
instruction_data: InstructionData, instruction_data: InstructionData,
pre_states: Vec<AccountWithMetadata>, pre_states: Vec<AccountWithMetadata>,
post_states: Vec<AccountPostState>, post_states: Vec<AccountPostState>,
) -> Self { ) -> Self {
Self { Self {
self_program_id,
instruction_data, instruction_data,
pre_states, pre_states,
post_states, post_states,
@ -415,11 +420,13 @@ pub fn compute_authorized_pdas(
/// Reads the NSSA inputs from the guest environment. /// Reads the NSSA inputs from the guest environment.
#[must_use] #[must_use]
pub fn read_nssa_inputs<T: DeserializeOwned>() -> (ProgramInput<T>, InstructionData) { pub fn read_nssa_inputs<T: DeserializeOwned>() -> (ProgramInput<T>, InstructionData) {
let self_program_id: ProgramId = env::read();
let pre_states: Vec<AccountWithMetadata> = env::read(); let pre_states: Vec<AccountWithMetadata> = env::read();
let instruction_words: InstructionData = env::read(); let instruction_words: InstructionData = env::read();
let instruction = T::deserialize(&mut Deserializer::new(instruction_words.as_ref())).unwrap(); let instruction = T::deserialize(&mut Deserializer::new(instruction_words.as_ref())).unwrap();
( (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction, instruction,
}, },
@ -620,7 +627,7 @@ mod tests {
#[test] #[test]
fn program_output_try_with_block_validity_window_range() { fn program_output_try_with_block_validity_window_range() {
let output = ProgramOutput::new(vec![], vec![], vec![]) let output = ProgramOutput::new(DEFAULT_PROGRAM_ID, vec![], vec![], vec![])
.try_with_block_validity_window(10_u64..100) .try_with_block_validity_window(10_u64..100)
.unwrap(); .unwrap();
assert_eq!(output.block_validity_window.start(), Some(10)); assert_eq!(output.block_validity_window.start(), Some(10));
@ -629,24 +636,24 @@ mod tests {
#[test] #[test]
fn program_output_with_block_validity_window_range_from() { fn program_output_with_block_validity_window_range_from() {
let output = let output = ProgramOutput::new(DEFAULT_PROGRAM_ID, vec![], vec![], vec![])
ProgramOutput::new(vec![], vec![], vec![]).with_block_validity_window(10_u64..); .with_block_validity_window(10_u64..);
assert_eq!(output.block_validity_window.start(), Some(10)); assert_eq!(output.block_validity_window.start(), Some(10));
assert_eq!(output.block_validity_window.end(), None); assert_eq!(output.block_validity_window.end(), None);
} }
#[test] #[test]
fn program_output_with_block_validity_window_range_to() { fn program_output_with_block_validity_window_range_to() {
let output = let output = ProgramOutput::new(DEFAULT_PROGRAM_ID, vec![], vec![], vec![])
ProgramOutput::new(vec![], vec![], vec![]).with_block_validity_window(..100_u64); .with_block_validity_window(..100_u64);
assert_eq!(output.block_validity_window.start(), None); assert_eq!(output.block_validity_window.start(), None);
assert_eq!(output.block_validity_window.end(), Some(100)); assert_eq!(output.block_validity_window.end(), Some(100));
} }
#[test] #[test]
fn program_output_try_with_block_validity_window_empty_range_fails() { fn program_output_try_with_block_validity_window_empty_range_fails() {
let result = let result = ProgramOutput::new(DEFAULT_PROGRAM_ID, vec![], vec![], vec![])
ProgramOutput::new(vec![], vec![], vec![]).try_with_block_validity_window(5_u64..5); .try_with_block_validity_window(5_u64..5);
assert!(result.is_err()); assert!(result.is_err());
} }

View File

@ -158,7 +158,7 @@ fn execute_and_prove_program(
) -> Result<Receipt, NssaError> { ) -> Result<Receipt, NssaError> {
// Write inputs to the program // Write inputs to the program
let mut env_builder = ExecutorEnv::builder(); let mut env_builder = ExecutorEnv::builder();
Program::write_inputs(pre_states, instruction_data, &mut env_builder)?; Program::write_inputs(program.id(), pre_states, instruction_data, &mut env_builder)?;
let env = env_builder.build().unwrap(); let env = env_builder.build().unwrap();
// Prove the program // Prove the program

View File

@ -58,7 +58,7 @@ impl Program {
// Write inputs to the program // Write inputs to the program
let mut env_builder = ExecutorEnv::builder(); let mut env_builder = ExecutorEnv::builder();
env_builder.session_limit(Some(MAX_NUM_CYCLES_PUBLIC_EXECUTION)); env_builder.session_limit(Some(MAX_NUM_CYCLES_PUBLIC_EXECUTION));
Self::write_inputs(pre_states, instruction_data, &mut env_builder)?; Self::write_inputs(self.id, pre_states, instruction_data, &mut env_builder)?;
let env = env_builder.build().unwrap(); let env = env_builder.build().unwrap();
// Execute the program (without proving) // Execute the program (without proving)
@ -78,13 +78,20 @@ impl Program {
/// Writes inputs to `env_builder` in the order expected by the programs. /// Writes inputs to `env_builder` in the order expected by the programs.
pub(crate) fn write_inputs( pub(crate) fn write_inputs(
program_id: ProgramId,
pre_states: &[AccountWithMetadata], pre_states: &[AccountWithMetadata],
instruction_data: &[u32], instruction_data: &[u32],
env_builder: &mut ExecutorEnvBuilder, env_builder: &mut ExecutorEnvBuilder,
) -> Result<(), NssaError> { ) -> Result<(), NssaError> {
env_builder
.write(&program_id)
.map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?;
let pre_states = pre_states.to_vec(); let pre_states = pre_states.to_vec();
env_builder env_builder
.write(&(pre_states, instruction_data)) .write(&pre_states)
.map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?;
env_builder
.write(&instruction_data)
.map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?; .map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?;
Ok(()) Ok(())
} }

View File

@ -184,6 +184,12 @@ impl PublicTransaction {
); );
} }
// Verify that the program output's self_program_id matches the expected program ID.
ensure!(
program_output.self_program_id == chained_call.program_id,
NssaError::InvalidProgramBehavior
);
// Verify execution corresponds to a well-behaved program. // Verify execution corresponds to a well-behaved program.
// See the # Programs section for the definition of the `validate_execution` method. // See the # Programs section for the definition of the `validate_execution` method.
ensure!( ensure!(

View File

@ -14,6 +14,7 @@ use nssa_core::program::{ProgramInput, ProgramOutput, read_nssa_inputs};
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction, instruction,
}, },
@ -152,7 +153,12 @@ fn main() {
} }
}; };
ProgramOutput::new(instruction_words, pre_states_clone, post_states) ProgramOutput::new(
.with_chained_calls(chained_calls) self_program_id,
.write(); instruction_words,
pre_states_clone,
post_states,
)
.with_chained_calls(chained_calls)
.write();
} }

View File

@ -4,6 +4,7 @@ use nssa_core::program::{ProgramInput, ProgramOutput, read_nssa_inputs};
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction, instruction,
}, },
@ -56,7 +57,12 @@ fn main() {
} }
}; };
ProgramOutput::new(instruction_words, pre_states_clone, post_states) ProgramOutput::new(
.with_chained_calls(chained_calls) self_program_id,
.write(); instruction_words,
pre_states_clone,
post_states,
)
.with_chained_calls(chained_calls)
.write();
} }

View File

@ -67,6 +67,7 @@ fn main() {
// Read input accounts. // Read input accounts.
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: balance_to_move, instruction: balance_to_move,
}, },
@ -84,5 +85,5 @@ fn main() {
_ => panic!("invalid params"), _ => panic!("invalid params"),
}; };
ProgramOutput::new(instruction_words, pre_states, post_states).write(); ProgramOutput::new(self_program_id, instruction_words, pre_states, post_states).write();
} }

View File

@ -46,6 +46,7 @@ fn main() {
// It is expected to receive only two accounts: [pinata_account, winner_account] // It is expected to receive only two accounts: [pinata_account, winner_account]
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: solution, instruction: solution,
}, },
@ -79,6 +80,7 @@ fn main() {
.expect("Overflow when adding prize to winner"); .expect("Overflow when adding prize to winner");
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![pinata, winner], vec![pinata, winner],
vec![ vec![

View File

@ -52,6 +52,7 @@ fn main() {
// winner_token_holding] // winner_token_holding]
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: solution, instruction: solution,
}, },
@ -97,6 +98,7 @@ fn main() {
.with_pda_seeds(vec![PdaSeed::new([0; 32])]); .with_pda_seeds(vec![PdaSeed::new([0; 32])]);
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![ vec![
pinata_definition, pinata_definition,

View File

@ -107,6 +107,13 @@ impl ExecutionState {
|_: Infallible| unreachable!("Infallible error is never constructed"), |_: Infallible| unreachable!("Infallible error is never constructed"),
); );
// Verify that the program output's self_program_id matches the expected program ID.
// This ensures the proof commits to which program produced the output.
assert_eq!(
program_output.self_program_id, chained_call.program_id,
"Program output self_program_id does not match chained call program_id"
);
// Check that the program is well behaved. // Check that the program is well behaved.
// See the # Programs section for the definition of the `validate_execution` method. // See the # Programs section for the definition of the `validate_execution` method.
let execution_valid = validate_execution( let execution_valid = validate_execution(

View File

@ -12,6 +12,7 @@ use token_program::core::Instruction;
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction, instruction,
}, },
@ -81,5 +82,11 @@ fn main() {
} }
}; };
ProgramOutput::new(instruction_words, pre_states_clone, post_states).write(); ProgramOutput::new(
self_program_id,
instruction_words,
pre_states_clone,
post_states,
)
.write();
} }

View File

@ -5,6 +5,7 @@ type Instruction = u128;
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: balance_to_burn, instruction: balance_to_burn,
}, },
@ -20,6 +21,7 @@ fn main() {
account_post.balance = account_post.balance.saturating_sub(balance_to_burn); account_post.balance = account_post.balance.saturating_sub(balance_to_burn);
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![pre], vec![pre],
vec![AccountPostState::new(account_post)], vec![AccountPostState::new(account_post)],

View File

@ -13,6 +13,7 @@ type Instruction = (u128, ProgramId, u32, Option<PdaSeed>);
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: (balance, auth_transfer_id, num_chain_calls, pda_seed), instruction: (balance, auth_transfer_id, num_chain_calls, pda_seed),
}, },
@ -55,6 +56,7 @@ fn main() {
} }
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![sender_pre.clone(), recipient_pre.clone()], vec![sender_pre.clone(), recipient_pre.clone()],
vec![ vec![

View File

@ -6,6 +6,7 @@ type Instruction = (Option<Vec<u8>>, bool);
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: (data_opt, should_claim), instruction: (data_opt, should_claim),
}, },
@ -33,5 +34,11 @@ fn main() {
AccountPostState::new(account_post) AccountPostState::new(account_post)
}; };
ProgramOutput::new(instruction_words, vec![pre], vec![post_state]).write(); ProgramOutput::new(
self_program_id,
instruction_words,
vec![pre],
vec![post_state],
)
.write();
} }

View File

@ -5,6 +5,7 @@ type Instruction = ();
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: (), instruction: (),
}, },
@ -17,5 +18,11 @@ fn main() {
let account_post = AccountPostState::new_claimed(pre.account.clone(), Claim::Authorized); let account_post = AccountPostState::new_claimed(pre.account.clone(), Claim::Authorized);
ProgramOutput::new(instruction_words, vec![pre], vec![account_post]).write(); ProgramOutput::new(
self_program_id,
instruction_words,
vec![pre],
vec![account_post],
)
.write();
} }

View File

@ -6,6 +6,7 @@ type Instruction = Vec<u8>;
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: data, instruction: data,
}, },
@ -23,6 +24,7 @@ fn main() {
.expect("provided data should fit into data limit"); .expect("provided data should fit into data limit");
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![pre], vec![pre],
vec![AccountPostState::new_claimed( vec![AccountPostState::new_claimed(

View File

@ -6,7 +6,14 @@ use nssa_core::{
type Instruction = (); type Instruction = ();
fn main() { fn main() {
let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::<Instruction>(); let (
ProgramInput {
self_program_id,
pre_states,
..
},
instruction_words,
) = read_nssa_inputs::<Instruction>();
let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { let Ok([pre]) = <[_; 1]>::try_from(pre_states) else {
return; return;
@ -15,6 +22,7 @@ fn main() {
let account_pre = pre.account.clone(); let account_pre = pre.account.clone();
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![pre], vec![pre],
vec![ vec![

View File

@ -14,6 +14,7 @@ type Instruction = (u128, ProgramId);
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: (balance, transfer_program_id), instruction: (balance, transfer_program_id),
}, },
@ -40,6 +41,7 @@ fn main() {
}; };
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![sender.clone(), receiver.clone()], vec![sender.clone(), receiver.clone()],
vec![ vec![

View File

@ -3,7 +3,14 @@ use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nss
type Instruction = (); type Instruction = ();
fn main() { fn main() {
let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::<Instruction>(); let (
ProgramInput {
self_program_id,
pre_states,
..
},
instruction_words,
) = read_nssa_inputs::<Instruction>();
let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { let Ok([pre]) = <[_; 1]>::try_from(pre_states) else {
return; return;
@ -17,6 +24,7 @@ fn main() {
.expect("Balance overflow"); .expect("Balance overflow");
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![pre], vec![pre],
vec![AccountPostState::new(account_post)], vec![AccountPostState::new(account_post)],

View File

@ -3,7 +3,14 @@ use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nss
type Instruction = (); type Instruction = ();
fn main() { fn main() {
let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::<Instruction>(); let (
ProgramInput {
self_program_id,
pre_states,
..
},
instruction_words,
) = read_nssa_inputs::<Instruction>();
let Ok([pre1, pre2]) = <[_; 2]>::try_from(pre_states) else { let Ok([pre1, pre2]) = <[_; 2]>::try_from(pre_states) else {
return; return;
@ -12,6 +19,7 @@ fn main() {
let account_pre1 = pre1.account.clone(); let account_pre1 = pre1.account.clone();
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![pre1, pre2], vec![pre1, pre2],
vec![AccountPostState::new(account_pre1)], vec![AccountPostState::new(account_pre1)],

View File

@ -64,6 +64,7 @@ fn main() {
// Read input accounts. // Read input accounts.
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: balance_to_move, instruction: balance_to_move,
}, },
@ -80,5 +81,5 @@ fn main() {
} }
_ => panic!("invalid params"), _ => panic!("invalid params"),
}; };
ProgramOutput::new(instruction_data, pre_states, post_states).write(); ProgramOutput::new(self_program_id, instruction_data, pre_states, post_states).write();
} }

View File

@ -3,7 +3,14 @@ use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nss
type Instruction = (); type Instruction = ();
fn main() { fn main() {
let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::<Instruction>(); let (
ProgramInput {
self_program_id,
pre_states,
..
},
instruction_words,
) = read_nssa_inputs::<Instruction>();
let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { let Ok([pre]) = <[_; 1]>::try_from(pre_states) else {
return; return;
@ -14,6 +21,7 @@ fn main() {
account_post.nonce.public_account_nonce_increment(); account_post.nonce.public_account_nonce_increment();
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![pre], vec![pre],
vec![AccountPostState::new(account_post)], vec![AccountPostState::new(account_post)],

View File

@ -3,11 +3,18 @@ use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nss
type Instruction = (); type Instruction = ();
fn main() { fn main() {
let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::<Instruction>(); let (
ProgramInput {
self_program_id,
pre_states,
..
},
instruction_words,
) = read_nssa_inputs::<Instruction>();
let post_states = pre_states let post_states = pre_states
.iter() .iter()
.map(|account| AccountPostState::new(account.account.clone())) .map(|account| AccountPostState::new(account.account.clone()))
.collect(); .collect();
ProgramOutput::new(instruction_words, pre_states, post_states).write(); ProgramOutput::new(self_program_id, instruction_words, pre_states, post_states).write();
} }

View File

@ -3,7 +3,14 @@ use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nss
type Instruction = (); type Instruction = ();
fn main() { fn main() {
let (ProgramInput { pre_states, .. }, instruction_words) = read_nssa_inputs::<Instruction>(); let (
ProgramInput {
self_program_id,
pre_states,
..
},
instruction_words,
) = read_nssa_inputs::<Instruction>();
let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { let Ok([pre]) = <[_; 1]>::try_from(pre_states) else {
return; return;
@ -14,6 +21,7 @@ fn main() {
account_post.program_owner = [0, 1, 2, 3, 4, 5, 6, 7]; account_post.program_owner = [0, 1, 2, 3, 4, 5, 6, 7];
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![pre], vec![pre],
vec![AccountPostState::new(account_post)], vec![AccountPostState::new(account_post)],

View File

@ -5,6 +5,7 @@ type Instruction = u128;
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: balance, instruction: balance,
}, },
@ -27,6 +28,7 @@ fn main() {
.expect("Overflow when adding balance"); .expect("Overflow when adding balance");
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![sender_pre, receiver_pre], vec![sender_pre, receiver_pre],
vec![ vec![

View File

@ -8,6 +8,7 @@ type Instruction = (BlockValidityWindow, TimestampValidityWindow);
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: (block_validity_window, timestamp_validity_window), instruction: (block_validity_window, timestamp_validity_window),
}, },
@ -21,6 +22,7 @@ fn main() {
let post = pre.account.clone(); let post = pre.account.clone();
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![pre], vec![pre],
vec![AccountPostState::new(post)], vec![AccountPostState::new(post)],

View File

@ -16,6 +16,7 @@ type Instruction = (BlockValidityWindow, ProgramId, BlockValidityWindow);
fn main() { fn main() {
let ( let (
ProgramInput { ProgramInput {
self_program_id,
pre_states, pre_states,
instruction: (block_validity_window, chained_program_id, chained_block_validity_window), instruction: (block_validity_window, chained_program_id, chained_block_validity_window),
}, },
@ -38,6 +39,7 @@ fn main() {
}; };
ProgramOutput::new( ProgramOutput::new(
self_program_id,
instruction_words, instruction_words,
vec![pre], vec![pre],
vec![AccountPostState::new(post)], vec![AccountPostState::new(post)],