From 4a44b12384ccf2bfc01ca08c4da2a18feb8bd1c9 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Thu, 4 Sep 2025 12:44:22 -0300 Subject: [PATCH] wip --- .../guest/src/bin/authenticated_transfer.rs | 1 + nssa/program_methods/guest/src/bin/pinata.rs | 68 +++++++++++++++++++ nssa/src/program.rs | 9 ++- nssa/src/state.rs | 36 ++++++++++ sequencer_core/src/sequencer_store/mod.rs | 6 +- sequencer_runner/src/lib.rs | 4 +- 6 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 nssa/program_methods/guest/src/bin/pinata.rs diff --git a/nssa/program_methods/guest/src/bin/authenticated_transfer.rs b/nssa/program_methods/guest/src/bin/authenticated_transfer.rs index 9e7f399..89b84fd 100644 --- a/nssa/program_methods/guest/src/bin/authenticated_transfer.rs +++ b/nssa/program_methods/guest/src/bin/authenticated_transfer.rs @@ -34,3 +34,4 @@ fn main() { write_nssa_outputs(vec![sender, receiver], vec![sender_post, receiver_post]); } + diff --git a/nssa/program_methods/guest/src/bin/pinata.rs b/nssa/program_methods/guest/src/bin/pinata.rs new file mode 100644 index 0000000..43b0190 --- /dev/null +++ b/nssa/program_methods/guest/src/bin/pinata.rs @@ -0,0 +1,68 @@ +use nssa_core::program::{read_nssa_inputs, write_nssa_outputs, ProgramInput}; +use risc0_zkvm::sha::{Impl, Sha256}; + +const PRIZE: u128 = 150; + +type Instruction = u128; + +struct Challenge { + difficulty: u8, + seed: [u8; 32], +} + +impl Challenge { + fn new(bytes: &[u8]) -> Self { + assert_eq!(bytes.len(), 33); + let difficulty = bytes[0]; + assert!(difficulty <= 32); + + let mut seed = [0; 32]; + seed.copy_from_slice(&bytes[1..]); + Self { difficulty, seed } + } + + fn is_nonce_valid(&self, nonce: Instruction) -> bool { + let mut bytes = [0; 32 + 16]; + bytes.copy_from_slice(&self.seed); + bytes[32..].copy_from_slice(&nonce.to_le_bytes()); + let digest: [u8; 32] = Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap(); + let difficulty = self.difficulty as usize; + digest[..difficulty].iter().all(|&b| b == 0) + } + + fn next_data(self) -> [u8; 33] { + let mut result = [0; 33]; + result[0] = self.difficulty; + result.copy_from_slice(Impl::hash_bytes(&self.seed).as_bytes()); + result + } +} + +/// A pinata program +fn main() { + // Read input accounts. + // It is expected to receive only two accounts: [pinata_account, winner_account] + let ProgramInput { + pre_states, + instruction: nonce, + } = read_nssa_inputs::(); + + let [pinata, winner] = match pre_states.try_into() { + Ok(array) => array, + Err(_) => return, + }; + + let data = Challenge::new(&pinata.account.data); + + if !data.is_nonce_valid(nonce) { + return; + } + + let mut pinata_post = pinata.account.clone(); + let mut winner_post = winner.account.clone(); + pinata_post.balance -= PRIZE; + pinata_post.data = data.next_data().to_vec(); + winner_post.balance += PRIZE; + + write_nssa_outputs(vec![pinata, winner], vec![pinata_post, winner_post]); +} diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 66358e9..63b7dc4 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -2,7 +2,7 @@ use nssa_core::{ account::{Account, AccountWithMetadata}, program::{InstructionData, ProgramId, ProgramOutput}, }; -use program_methods::{AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID}; +use program_methods::{AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID}; use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec}; use serde::Serialize; @@ -73,6 +73,13 @@ impl Program { elf: AUTHENTICATED_TRANSFER_ELF, } } + + pub fn pinata() -> Self { + Self { + id: PINATA_ID, + elf: PINATA_ELF + } + } } #[cfg(test)] diff --git a/nssa/src/state.rs b/nssa/src/state.rs index f975804..ba6c49b 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -8,6 +8,7 @@ use nssa_core::{ account::Account, program::{DEFAULT_PROGRAM_ID, ProgramId}, }; +use rand::{Rng, RngCore, rngs::OsRng}; use std::collections::{HashMap, HashSet}; pub(crate) struct CommitmentSet { @@ -85,6 +86,41 @@ impl V01State { this } + pub fn add_pinata_accounts(&mut self) { + self.insert_program(Program::pinata()); + + let mut rng = OsRng; + let mut seed = [0; 32]; + + rng.fill_bytes(&mut seed); + self.public_state.insert( + "6a79aee868a1c641ea895582af7ddd6f2da339e3091a67eddcbfdaa1b9010001" + .parse() + .unwrap(), + Account { + program_owner: Program::pinata().id(), + balance: 1500, + // Difficulty: 3 + data: std::iter::once(3).chain(seed).collect(), + nonce: 0, + }, + ); + + rng.fill_bytes(&mut seed); + self.public_state.insert( + "6a79aee868a1c641ea895582af7ddd6f2da339e3091a67eddcbfdaa1b9010002" + .parse() + .unwrap(), + Account { + program_owner: Program::pinata().id(), + balance: 1500, + // Difficulty: 4 + data: std::iter::once(4).chain(seed).collect(), + nonce: 0, + }, + ); + } + pub(crate) fn insert_program(&mut self, program: Program) { self.builtin_programs.insert(program.id(), program); } diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index 4254ed7..374e7d5 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -26,7 +26,11 @@ impl SequecerChainStore { .map(|acc_data| (acc_data.addr.parse().unwrap(), acc_data.balance)) .collect(); - let state = nssa::V01State::new_with_genesis_accounts(&init_accs); + let state = { + let mut this = nssa::V01State::new_with_genesis_accounts(&init_accs); + this.add_pinata_accounts(); + this + }; let mut data = [0; 32]; let mut prev_block_hash = [0; 32]; diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index 625350b..d7a574e 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -75,7 +75,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(()) }