diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 3b372a22..6c43d752 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -8,7 +8,7 @@ use serde::Serialize; use crate::{ error::NssaError, - program_methods::{AMM_ELF, AUTHENTICATED_TRANSFER_ELF, PINATA_ELF, TOKEN_ELF}, + program_methods::{AMM_ELF, AUTHENTICATED_TRANSFER_ELF, PINATA_ELF, TOKEN_ELF, CLOCK_ELF}, }; /// Maximum number of cycles for a public execution. @@ -105,6 +105,11 @@ impl Program { pub fn amm() -> Self { Self::new(AMM_ELF.to_vec()).expect("The AMM program must be a valid Risc0 program") } + + #[must_use] + pub fn clock() -> Self { + Self::new(CLOCK_ELF.to_vec()).expect("The clock program must be a valid Risc0 program") + } } // TODO: Testnet only. Refactor to prevent compilation on mainnet. diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 6dec4f35..70906f68 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -146,6 +146,20 @@ impl V03State { this.insert_program(Program::authenticated_transfer_program()); this.insert_program(Program::token()); this.insert_program(Program::amm()); + this.insert_program(Program::clock()); + + this.force_insert_account( + AccountId::new(b"/LEZ/ClockProgramAccount/0000001".to_owned()), + Account { + program_owner: Program::clock().id(), + data: 0_u64 + .to_le_bytes() + .to_vec() + .try_into() + .expect("u64 bytes should fit within accounts data"), + ..Account::default() + }, + ); this } diff --git a/program_methods/guest/src/bin/clock.rs b/program_methods/guest/src/bin/clock.rs new file mode 100644 index 00000000..d07df4cd --- /dev/null +++ b/program_methods/guest/src/bin/clock.rs @@ -0,0 +1,37 @@ +use nssa_core::program::{AccountPostState, ProgramInput, read_nssa_inputs, write_nssa_outputs}; + +type Instruction = (); + +fn main() { + let ( + ProgramInput { + pre_states, + instruction: (), + }, + instruction_words, + ) = read_nssa_inputs::(); + + let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { + return; + }; + + let account_pre = &pre.account; + let account_pre_data = account_pre.data.clone(); + let clock = + u64::from_le_bytes(account_pre_data.into_inner().try_into().expect( + "Block context program account data should be the LE encoding of a u64 integer", + )); + + let mut account_post = account_pre.clone(); + account_post.data = clock + .checked_add(1) + .expect("Next timestap should be within u64 boundaries") + .to_le_bytes() + .to_vec() + .try_into() + .expect("u64 byte length should fit in account data"); + + let post = AccountPostState::new(account_post); + + write_nssa_outputs(instruction_words, vec![pre], vec![post]); +}