mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-21 06:33:08 +00:00
add transition function for program deployment
This commit is contained in:
parent
54c54199d7
commit
da28f3317b
@ -14,6 +14,7 @@ secp256k1 = "0.31.1"
|
||||
rand = "0.8"
|
||||
borsh = "1.5.7"
|
||||
hex = "0.4.3"
|
||||
risc0-binfmt = "3.0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
test-program-methods = { path = "test_program_methods" }
|
||||
|
||||
@ -48,4 +48,10 @@ pub enum NssaError {
|
||||
|
||||
#[error("Circuit proving error")]
|
||||
CircuitProvingError(String),
|
||||
|
||||
#[error("Invalid program bytecode")]
|
||||
InvalidProgramBytecode,
|
||||
|
||||
#[error("Program already exists")]
|
||||
ProgramAlreadyExists,
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@ pub mod error;
|
||||
mod merkle_tree;
|
||||
pub mod privacy_preserving_transaction;
|
||||
pub mod program;
|
||||
pub mod public_transaction;
|
||||
pub mod program_deployment_transaction;
|
||||
pub mod public_transaction;
|
||||
mod signature;
|
||||
mod state;
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ impl PrivacyPreservingTransaction {
|
||||
|
||||
pub(crate) fn validate_and_produce_public_state_diff(
|
||||
&self,
|
||||
state: &mut V01State,
|
||||
state: &V01State,
|
||||
) -> Result<HashMap<Address, Account>, NssaError> {
|
||||
let message = &self.message;
|
||||
let witness_set = &self.witness_set;
|
||||
|
||||
@ -2,10 +2,7 @@ use nssa_core::{
|
||||
account::{Account, AccountWithMetadata},
|
||||
program::{InstructionData, ProgramId, ProgramOutput},
|
||||
};
|
||||
use program_methods::{
|
||||
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF,
|
||||
TOKEN_ID,
|
||||
};
|
||||
use program_methods::{AUTHENTICATED_TRANSFER_ELF, PINATA_ELF, TOKEN_ELF};
|
||||
use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec};
|
||||
use serde::Serialize;
|
||||
|
||||
@ -14,16 +11,26 @@ use crate::error::NssaError;
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Program {
|
||||
id: ProgramId,
|
||||
elf: &'static [u8],
|
||||
elf: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Program {
|
||||
pub(crate) fn new(bytecode: Vec<u8>) -> Result<Self, NssaError> {
|
||||
let binary = risc0_binfmt::ProgramBinary::decode(&bytecode)
|
||||
.map_err(|_| NssaError::InvalidProgramBytecode)?;
|
||||
let id = binary
|
||||
.compute_image_id()
|
||||
.map_err(|_| NssaError::InvalidProgramBytecode)?
|
||||
.into();
|
||||
Ok(Self { elf: bytecode, id })
|
||||
}
|
||||
|
||||
pub fn id(&self) -> ProgramId {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub(crate) fn elf(&self) -> &'static [u8] {
|
||||
self.elf
|
||||
pub(crate) fn elf(&self) -> &[u8] {
|
||||
&self.elf
|
||||
}
|
||||
|
||||
pub fn serialize_instruction<T: Serialize>(
|
||||
@ -45,7 +52,7 @@ impl Program {
|
||||
// Execute the program (without proving)
|
||||
let executor = default_executor();
|
||||
let session_info = executor
|
||||
.execute(env, self.elf)
|
||||
.execute(env, self.elf())
|
||||
.map_err(|e| NssaError::ProgramExecutionFailed(e.to_string()))?;
|
||||
|
||||
// Get outputs
|
||||
@ -71,33 +78,34 @@ impl Program {
|
||||
}
|
||||
|
||||
pub fn authenticated_transfer_program() -> Self {
|
||||
Self {
|
||||
id: AUTHENTICATED_TRANSFER_ID,
|
||||
elf: AUTHENTICATED_TRANSFER_ELF,
|
||||
}
|
||||
// This unwrap won't panic since the `AUTHENTICATED_TRANSFER_ELF` comes from risc0 build of
|
||||
// `program_methods`
|
||||
Self::new(AUTHENTICATED_TRANSFER_ELF.to_vec()).unwrap()
|
||||
}
|
||||
|
||||
pub fn token() -> Self {
|
||||
Self {
|
||||
id: TOKEN_ID,
|
||||
elf: TOKEN_ELF,
|
||||
}
|
||||
// This unwrap won't panic since the `TOKEN_ELF` comes from risc0 build of
|
||||
// `program_methods`
|
||||
Self::new(TOKEN_ELF.to_vec()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
|
||||
impl Program {
|
||||
pub fn pinata() -> Self {
|
||||
Self {
|
||||
id: PINATA_ID,
|
||||
elf: PINATA_ELF,
|
||||
}
|
||||
// This unwrap won't panic since the `PINATA_ELF` comes from risc0 build of
|
||||
// `program_methods`
|
||||
Self::new(PINATA_ELF.to_vec()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nssa_core::account::{Account, AccountId, AccountWithMetadata};
|
||||
use program_methods::{
|
||||
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF,
|
||||
TOKEN_ID,
|
||||
};
|
||||
|
||||
use crate::program::Program;
|
||||
|
||||
@ -108,7 +116,7 @@ mod tests {
|
||||
|
||||
Program {
|
||||
id: NONCE_CHANGER_ID,
|
||||
elf: NONCE_CHANGER_ELF,
|
||||
elf: NONCE_CHANGER_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +126,7 @@ mod tests {
|
||||
|
||||
Program {
|
||||
id: EXTRA_OUTPUT_ID,
|
||||
elf: EXTRA_OUTPUT_ELF,
|
||||
elf: EXTRA_OUTPUT_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,7 +136,7 @@ mod tests {
|
||||
|
||||
Program {
|
||||
id: MISSING_OUTPUT_ID,
|
||||
elf: MISSING_OUTPUT_ELF,
|
||||
elf: MISSING_OUTPUT_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +146,7 @@ mod tests {
|
||||
|
||||
Program {
|
||||
id: PROGRAM_OWNER_CHANGER_ID,
|
||||
elf: PROGRAM_OWNER_CHANGER_ELF,
|
||||
elf: PROGRAM_OWNER_CHANGER_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,7 +156,7 @@ mod tests {
|
||||
|
||||
Program {
|
||||
id: SIMPLE_BALANCE_TRANSFER_ID,
|
||||
elf: SIMPLE_BALANCE_TRANSFER_ELF,
|
||||
elf: SIMPLE_BALANCE_TRANSFER_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,7 +166,7 @@ mod tests {
|
||||
|
||||
Program {
|
||||
id: DATA_CHANGER_ID,
|
||||
elf: DATA_CHANGER_ELF,
|
||||
elf: DATA_CHANGER_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +176,7 @@ mod tests {
|
||||
|
||||
Program {
|
||||
id: MINTER_ID,
|
||||
elf: MINTER_ELF,
|
||||
elf: MINTER_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,7 +186,7 @@ mod tests {
|
||||
|
||||
Program {
|
||||
id: BURNER_ID,
|
||||
elf: BURNER_ELF,
|
||||
elf: BURNER_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -216,4 +224,18 @@ mod tests {
|
||||
assert_eq!(sender_post, expected_sender_post);
|
||||
assert_eq!(recipient_post, expected_recipient_post);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_builtin_programs() {
|
||||
let auth_transfer_program = Program::authenticated_transfer_program();
|
||||
let token_program = Program::token();
|
||||
let pinata_program = Program::pinata();
|
||||
|
||||
assert_eq!(auth_transfer_program.id, AUTHENTICATED_TRANSFER_ID);
|
||||
assert_eq!(auth_transfer_program.elf, AUTHENTICATED_TRANSFER_ELF);
|
||||
assert_eq!(token_program.id, TOKEN_ID);
|
||||
assert_eq!(token_program.elf, TOKEN_ELF);
|
||||
assert_eq!(pinata_program.id, PINATA_ID);
|
||||
assert_eq!(pinata_program.elf, PINATA_ELF);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
mod message;
|
||||
mod transaction;
|
||||
|
||||
pub use transaction::ProgramDeploymentTransaction;
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use nssa_core::{account::Account, address::Address};
|
||||
|
||||
use crate::{V01State, error::NssaError, program_deployment_transaction::message::Message};
|
||||
use crate::{
|
||||
V01State, error::NssaError, program::Program, program_deployment_transaction::message::Message,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ProgramDeploymentTransaction {
|
||||
@ -13,10 +11,17 @@ impl ProgramDeploymentTransaction {
|
||||
pub fn new(message: Message) -> Self {
|
||||
Self { message }
|
||||
}
|
||||
|
||||
pub(crate) fn validate_and_produce_public_state_diff(
|
||||
&self,
|
||||
state: &mut V01State,
|
||||
) -> Result<HashMap<Address, Account>, NssaError> {
|
||||
todo!()
|
||||
state: &V01State,
|
||||
) -> Result<Program, NssaError> {
|
||||
// TODO: remove clone
|
||||
let program = Program::new(self.message.bytecode.clone())?;
|
||||
if state.programs().contains_key(&program.id()) {
|
||||
Err(NssaError::ProgramAlreadyExists)
|
||||
} else {
|
||||
Ok(program)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ impl PublicTransaction {
|
||||
|
||||
// Check the `program_id` corresponds to a built-in program
|
||||
// Only allowed program so far is the authenticated transfer program
|
||||
let Some(program) = state.builtin_programs().get(&message.program_id) else {
|
||||
let Some(program) = state.programs().get(&message.program_id) else {
|
||||
return Err(NssaError::InvalidInput("Unknown program".into()));
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
error::NssaError, merkle_tree::MerkleTree,
|
||||
privacy_preserving_transaction::PrivacyPreservingTransaction, program::Program,
|
||||
program_deployment_transaction::ProgramDeploymentTransaction,
|
||||
public_transaction::PublicTransaction,
|
||||
};
|
||||
use nssa_core::{
|
||||
@ -157,6 +158,15 @@ impl V01State {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn transition_from_program_deployment_transaction(
|
||||
&mut self,
|
||||
tx: &ProgramDeploymentTransaction,
|
||||
) -> Result<(), NssaError> {
|
||||
let program = tx.validate_and_produce_public_state_diff(self)?;
|
||||
self.insert_program(program);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_account_by_address_mut(&mut self, address: Address) -> &mut Account {
|
||||
self.public_state.entry(address).or_default()
|
||||
}
|
||||
@ -172,7 +182,7 @@ impl V01State {
|
||||
self.private_state.0.get_proof_for(commitment)
|
||||
}
|
||||
|
||||
pub(crate) fn builtin_programs(&self) -> &HashMap<ProgramId, Program> {
|
||||
pub(crate) fn programs(&self) -> &HashMap<ProgramId, Program> {
|
||||
&self.programs
|
||||
}
|
||||
|
||||
@ -355,7 +365,7 @@ pub mod tests {
|
||||
fn test_builtin_programs_getter() {
|
||||
let state = V01State::new_with_genesis_accounts(&[], &[]);
|
||||
|
||||
let builtin_programs = state.builtin_programs();
|
||||
let builtin_programs = state.programs();
|
||||
|
||||
assert_eq!(builtin_programs, &state.programs);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user