Merge pull request #128 from vacp2p/schouhy/add-program-deployment-transactions

Add program deployment transaction types
This commit is contained in:
Sergio Chouhy 2025-10-21 09:10:24 -03:00 committed by GitHub
commit bdb0c576a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 400 additions and 138 deletions

View File

@ -255,7 +255,26 @@ impl SequencerClient {
Ok(resp_deser)
}
// Get Ids of the programs used by the node
pub async fn send_tx_program(
&self,
transaction: nssa::ProgramDeploymentTransaction,
) -> Result<SendTxResponse, SequencerClientError> {
let transaction = EncodedTransaction::from(NSSATransaction::ProgramDeployment(transaction));
let tx_req = SendTxRequest {
transaction: borsh::to_vec(&transaction).unwrap(),
};
let req = serde_json::to_value(tx_req)?;
let resp = self.call_method_with_payload("send_tx", req).await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
/// Get Ids of the programs used by the node
pub async fn get_program_ids(
&self,
) -> Result<HashMap<String, ProgramId>, SequencerClientError> {

View File

@ -9,6 +9,7 @@ use sha2::{Digest, digest::FixedOutput};
pub enum NSSATransaction {
Public(nssa::PublicTransaction),
PrivacyPreserving(nssa::PrivacyPreservingTransaction),
ProgramDeployment(nssa::ProgramDeploymentTransaction),
}
impl From<nssa::PublicTransaction> for NSSATransaction {
@ -23,6 +24,12 @@ impl From<nssa::PrivacyPreservingTransaction> for NSSATransaction {
}
}
impl From<nssa::ProgramDeploymentTransaction> for NSSATransaction {
fn from(value: nssa::ProgramDeploymentTransaction) -> Self {
Self::ProgramDeployment(value)
}
}
use crate::TreeHashType;
pub type CipherText = Vec<u8>;
@ -34,6 +41,7 @@ pub type Tag = u8;
pub enum TxKind {
Public,
PrivacyPreserving,
ProgramDeployment,
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
@ -55,6 +63,10 @@ impl From<NSSATransaction> for EncodedTransaction {
tx_kind: TxKind::PrivacyPreserving,
encoded_transaction_data: tx.to_bytes(),
},
NSSATransaction::ProgramDeployment(tx) => Self {
tx_kind: TxKind::ProgramDeployment,
encoded_transaction_data: tx.to_bytes(),
},
}
}
}
@ -70,6 +82,10 @@ impl TryFrom<&EncodedTransaction> for NSSATransaction {
nssa::PrivacyPreservingTransaction::from_bytes(&value.encoded_transaction_data)
.map(|tx| tx.into())
}
TxKind::ProgramDeployment => {
nssa::ProgramDeploymentTransaction::from_bytes(&value.encoded_transaction_data)
.map(|tx| tx.into())
}
}
}
}

View File

@ -8,11 +8,11 @@
"port": 3040,
"initial_accounts": [
{
"addr": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065",
"addr": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
"balance": 10000
},
{
"addr": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2",
"addr": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
"balance": 20000
}
],

View File

@ -9,7 +9,7 @@
"initial_accounts": [
{
"Public": {
"address": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065",
"address": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
"pub_sign_key": [
1,
1,
@ -48,7 +48,7 @@
},
{
"Public": {
"address": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2",
"address": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
"pub_sign_key": [
2,
2,
@ -87,7 +87,7 @@
},
{
"Private": {
"address": "9cb6b0035320266e430eac9d96745769e7efcf30d2b9cc21ff000b3f873dc2a8",
"address": "d360d6b5763f71ac6af56253687fd7d556d5c6c64312e53c0b92ef039a4375df",
"account": {
"program_owner": [
0,
@ -316,7 +316,7 @@
},
{
"Private": {
"address": "a55f4f98d2f265c91d8a9868564242d8070b9bf7180a29363f52eb76988636fd",
"address": "f27087ffc29b99035303697dcf6c8e323b1847d4261e6afd49e0d71c6dfa31ea",
"account": {
"program_owner": [
0,

Binary file not shown.

View File

@ -9,7 +9,7 @@ use common::{
transaction::{EncodedTransaction, NSSATransaction},
};
use log::{info, warn};
use nssa::{Address, PrivacyPreservingTransaction, program::Program};
use nssa::{Address, PrivacyPreservingTransaction, ProgramDeploymentTransaction, program::Program};
use nssa_core::{
Commitment, NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point,
};
@ -47,16 +47,18 @@ struct Args {
test_name: String,
}
pub const ACC_SENDER: &str = "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065";
pub const ACC_RECEIVER: &str = "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2";
pub const ACC_SENDER: &str = "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44";
pub const ACC_RECEIVER: &str = "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc";
pub const ACC_SENDER_PRIVATE: &str =
"9cb6b0035320266e430eac9d96745769e7efcf30d2b9cc21ff000b3f873dc2a8";
"d360d6b5763f71ac6af56253687fd7d556d5c6c64312e53c0b92ef039a4375df";
pub const ACC_RECEIVER_PRIVATE: &str =
"a55f4f98d2f265c91d8a9868564242d8070b9bf7180a29363f52eb76988636fd";
"f27087ffc29b99035303697dcf6c8e323b1847d4261e6afd49e0d71c6dfa31ea";
pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin");
#[allow(clippy::type_complexity)]
pub async fn pre_test(
home_dir: PathBuf,
@ -1402,6 +1404,48 @@ pub async fn test_pinata() {
info!("Success!");
}
pub async fn test_program_deployment() {
info!("test program deployment");
let bytecode = NSSA_PROGRAM_FOR_TEST_DATA_CHANGER.to_vec();
let message = nssa::program_deployment_transaction::Message::new(bytecode.clone());
let transaction = ProgramDeploymentTransaction::new(message);
let wallet_config = fetch_config().unwrap();
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
let _response = seq_client.send_tx_program(transaction).await.unwrap();
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
// The program is the data changer and takes one account as input.
// We pass an uninitialized account and we expect after execution to be owned by the data
// changer program (NSSA account claiming mechanism) with data equal to [0] (due to program logic)
let data_changer = Program::new(bytecode).unwrap();
let address: Address = "deadbeef".repeat(8).parse().unwrap();
let message =
nssa::public_transaction::Message::try_new(data_changer.id(), vec![address], vec![], ())
.unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]);
let transaction = nssa::PublicTransaction::new(message, witness_set);
let _response = seq_client.send_tx_public(transaction).await.unwrap();
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let post_state_account = seq_client
.get_account(address.to_string())
.await
.unwrap()
.account;
assert_eq!(post_state_account.program_owner, data_changer.id());
assert_eq!(post_state_account.balance, 0);
assert_eq!(post_state_account.data, vec![0]);
assert_eq!(post_state_account.nonce, 0);
info!("Success!");
}
pub async fn test_authenticated_transfer_initialize_function() {
info!("test initialize account for authenticated transfer");
let command = Command::AuthenticatedTransferInitializePublicAccount {};
@ -1429,6 +1473,7 @@ pub async fn test_authenticated_transfer_initialize_function() {
assert_eq!(account.balance, expected_balance);
assert_eq!(account.nonce, expected_nonce);
assert!(account.data.is_empty());
info!("Success!");
}
@ -1636,6 +1681,9 @@ pub async fn main_tests_runner() -> Result<()> {
"test_pinata" => {
test_cleanup_wrap!(home_dir, test_pinata);
}
"test_program_deployment" => {
test_cleanup_wrap!(home_dir, test_program_deployment);
}
"test_authenticated_transfer_initialize_function" => {
test_cleanup_wrap!(home_dir, test_authenticated_transfer_initialize_function);
}
@ -1696,6 +1744,7 @@ pub async fn main_tests_runner() -> Result<()> {
);
test_cleanup_wrap!(home_dir, test_success_token_program_shielded_owned);
test_cleanup_wrap!(home_dir, test_pinata);
test_cleanup_wrap!(home_dir, test_program_deployment);
test_cleanup_wrap!(home_dir, test_authenticated_transfer_initialize_function);
test_cleanup_wrap!(home_dir, test_pinata_private_receiver);
test_cleanup_wrap!(home_dir, test_success_token_program_private_owned);

View File

@ -5,7 +5,6 @@ edition = "2024"
[dependencies]
anyhow.workspace = true
log.workspace = true
serde.workspace = true
k256.workspace = true
sha2.workspace = true

View File

@ -14,6 +14,7 @@ secp256k1 = "0.31.1"
rand = "0.8"
borsh = "1.5.7"
hex = "0.4.3"
risc0-binfmt = "3.0.2"
[build-dependencies]
risc0-build = "3.0.3"

View File

@ -54,7 +54,7 @@ impl EncryptionScheme {
) -> [u8; 32] {
let mut bytes = Vec::new();
bytes.extend_from_slice(b"NSSA/v0.1/KDF-SHA256");
bytes.extend_from_slice(b"NSSA/v0.2/KDF-SHA256/");
bytes.extend_from_slice(&shared_secret.0);
bytes.extend_from_slice(&commitment.to_byte_array());
bytes.extend_from_slice(&output_index.to_le_bytes());

View File

@ -9,7 +9,7 @@ pub struct NullifierPublicKey(pub [u8; 32]);
impl From<&NullifierPublicKey> for AccountId {
fn from(value: &NullifierPublicKey) -> Self {
const PRIVATE_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.1/AccountId/Private/\x00\x00\x00";
const PRIVATE_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.2/AccountId/Private/\x00\x00\x00";
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(PRIVATE_ACCOUNT_ID_PREFIX);
@ -46,7 +46,7 @@ pub struct Nullifier(pub(super) [u8; 32]);
impl Nullifier {
pub fn for_account_update(commitment: &Commitment, nsk: &NullifierSecretKey) -> Self {
const UPDATE_PREFIX: &[u8; 32] = b"/NSSA/v0.1/Nullifier/Update/\x00\x00\x00\x00";
const UPDATE_PREFIX: &[u8; 32] = b"/NSSA/v0.2/Nullifier/Update/\x00\x00\x00\x00";
let mut bytes = UPDATE_PREFIX.to_vec();
bytes.extend_from_slice(&commitment.to_byte_array());
bytes.extend_from_slice(nsk);
@ -54,7 +54,7 @@ impl Nullifier {
}
pub fn for_account_initialization(npk: &NullifierPublicKey) -> Self {
const INIT_PREFIX: &[u8; 32] = b"/NSSA/v0.1/Nullifier/Initialize/";
const INIT_PREFIX: &[u8; 32] = b"/NSSA/v0.2/Nullifier/Initialize/";
let mut bytes = INIT_PREFIX.to_vec();
bytes.extend_from_slice(&npk.to_byte_array());
Self(Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap())
@ -70,8 +70,8 @@ mod tests {
let commitment = Commitment((0..32u8).collect::<Vec<_>>().try_into().unwrap());
let nsk = [0x42; 32];
let expected_nullifier = Nullifier([
235, 128, 185, 229, 74, 74, 83, 13, 165, 48, 239, 24, 48, 101, 71, 251, 253, 92, 88,
201, 103, 43, 250, 135, 193, 54, 175, 82, 245, 171, 90, 135,
148, 243, 116, 209, 140, 231, 211, 61, 35, 62, 114, 110, 143, 224, 82, 201, 221, 34,
53, 80, 185, 48, 174, 28, 203, 43, 94, 187, 85, 199, 115, 81,
]);
let nullifier = Nullifier::for_account_update(&commitment, &nsk);
assert_eq!(nullifier, expected_nullifier);
@ -84,8 +84,8 @@ mod tests {
255, 29, 105, 42, 186, 43, 11, 157, 168, 132, 225, 17, 163,
]);
let expected_nullifier = Nullifier([
96, 99, 33, 1, 116, 84, 169, 18, 85, 201, 17, 243, 123, 240, 242, 34, 116, 233, 92,
203, 247, 92, 161, 162, 135, 66, 127, 108, 230, 149, 105, 157,
1, 6, 59, 168, 16, 146, 65, 252, 255, 91, 48, 85, 116, 189, 110, 218, 110, 136, 163,
193, 245, 103, 51, 27, 235, 170, 215, 115, 97, 144, 36, 238,
]);
let nullifier = Nullifier::for_account_initialization(&npk);
assert_eq!(nullifier, expected_nullifier);
@ -113,8 +113,8 @@ mod tests {
];
let npk = NullifierPublicKey::from(&nsk);
let expected_account_id = AccountId::new([
69, 160, 50, 67, 12, 56, 150, 116, 62, 145, 17, 161, 17, 45, 24, 53, 33, 167, 83, 178,
47, 114, 111, 233, 251, 30, 54, 244, 184, 22, 100, 236,
18, 153, 225, 78, 35, 214, 212, 205, 152, 83, 18, 246, 69, 41, 20, 217, 85, 1, 108, 7,
87, 133, 181, 53, 247, 221, 174, 12, 112, 194, 34, 121,
]);
let account_id = AccountId::from(&npk);

View File

@ -21,9 +21,6 @@ fn main() {
program_id,
} = env::read();
// TODO: Check that `program_execution_proof` is one of the allowed built-in programs
// assert_eq!(program_id, AUTHENTICATED_TRANSFER_PROGRAM_ID);
// Check that `program_output` is consistent with the execution of the corresponding program.
env::verify(program_id, &to_vec(&program_output).unwrap()).unwrap();

View File

@ -1,2 +1,3 @@
pub mod privacy_preserving_transaction;
pub mod program_deployment_transaction;
pub mod public_transaction;

View File

@ -16,8 +16,9 @@ use crate::{
},
};
const MESSAGE_ENCODING_PREFIX_LEN: usize = 22;
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"\x01/NSSA/v0.1/TxMessage/";
const MESSAGE_ENCODING_PREFIX_LEN: usize = 32;
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
b"/NSSA/v0.2/TxMessage/Private/\x00\x00\x00";
impl EncryptedAccountData {
pub fn to_bytes(&self) -> Vec<u8> {

View File

@ -0,0 +1,86 @@
// TODO: Consider switching to deriving Borsh
use std::io::{Cursor, Read};
use crate::{
ProgramDeploymentTransaction, error::NssaError, program_deployment_transaction::Message,
};
const MESSAGE_ENCODING_PREFIX_LEN: usize = 32;
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
b"/NSSA/v0.2/TxMessage/Program/\x00\x00\x00";
impl Message {
/// Serializes a `Message` into bytes in the following layout:
/// PREFIX || bytecode_len (4 bytes LE) || <bytecode>
/// Integers are encoded in little-endian byte order, and fields appear in the above order.
pub(crate) fn to_bytes(&self) -> Vec<u8> {
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
let bytecode_len = self.bytecode.len() as u32;
bytes.extend(&bytecode_len.to_le_bytes());
bytes.extend(&self.bytecode);
bytes
}
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
let prefix = {
let mut this = [0u8; MESSAGE_ENCODING_PREFIX_LEN];
cursor.read_exact(&mut this)?;
this
};
if &prefix != MESSAGE_ENCODING_PREFIX {
return Err(NssaError::TransactionDeserializationError(
"Invalid public message prefix".to_string(),
));
}
let bytecode_len = u32_from_cursor(cursor)?;
let mut bytecode = vec![0; bytecode_len as usize];
let num_bytes = cursor.read(&mut bytecode)?;
if num_bytes != bytecode_len as usize {
println!("num bytes: {}", num_bytes);
return Err(NssaError::TransactionDeserializationError(
"Invalid number of bytes".to_string(),
));
}
Ok(Self { bytecode })
}
}
impl ProgramDeploymentTransaction {
pub fn to_bytes(&self) -> Vec<u8> {
self.message.to_bytes()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, NssaError> {
let mut cursor = Cursor::new(bytes);
Self::from_cursor(&mut cursor)
}
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
let message = Message::from_cursor(cursor)?;
Ok(Self::new(message))
}
}
fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<u32, NssaError> {
let mut word_buf = [0u8; 4];
cursor.read_exact(&mut word_buf)?;
Ok(u32::from_le_bytes(word_buf))
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use crate::{ProgramDeploymentTransaction, program_deployment_transaction::Message};
#[test]
fn test_roundtrip() {
let message = Message::new(vec![0xca, 0xfe, 0xca, 0xfe, 0x01, 0x02, 0x03]);
let tx = ProgramDeploymentTransaction::new(message);
let bytes = tx.to_bytes();
let mut cursor = Cursor::new(bytes.as_ref());
let tx_from_cursor = ProgramDeploymentTransaction::from_cursor(&mut cursor).unwrap();
assert_eq!(tx, tx_from_cursor);
}
}

View File

@ -10,8 +10,9 @@ use crate::{
public_transaction::{Message, WitnessSet},
};
const MESSAGE_ENCODING_PREFIX_LEN: usize = 22;
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"\x00/NSSA/v0.1/TxMessage/";
const MESSAGE_ENCODING_PREFIX_LEN: usize = 32;
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
b"/NSSA/v0.2/TxMessage/Public/\x00\x00\x00\x00";
impl Message {
/// Serializes a `Message` into bytes in the following layout:

View File

@ -48,4 +48,10 @@ pub enum NssaError {
#[error("Circuit proving error")]
CircuitProvingError(String),
#[error("Invalid program bytecode")]
InvalidProgramBytecode,
#[error("Program already exists")]
ProgramAlreadyExists,
}

View File

@ -12,6 +12,7 @@ pub mod error;
mod merkle_tree;
pub mod privacy_preserving_transaction;
pub mod program;
pub mod program_deployment_transaction;
pub mod public_transaction;
mod signature;
mod state;
@ -21,9 +22,10 @@ pub use nssa_core::address::Address;
pub use privacy_preserving_transaction::{
PrivacyPreservingTransaction, circuit::execute_and_prove,
};
pub use program_deployment_transaction::ProgramDeploymentTransaction;
pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID;
pub use public_transaction::PublicTransaction;
pub use signature::PrivateKey;
pub use signature::PublicKey;
pub use signature::Signature;
pub use state::V01State;
pub use state::V02State;

View File

@ -31,10 +31,10 @@ impl EncryptedAccountData {
}
}
/// Computes the tag as the first byte of SHA256("/NSSA/v0.1/ViewTag" || Npk || Ivk)
/// Computes the tag as the first byte of SHA256("/NSSA/v0.2/ViewTag/" || Npk || Ivk)
pub fn compute_view_tag(npk: NullifierPublicKey, ivk: IncomingViewingPublicKey) -> ViewTag {
let mut hasher = Sha256::new();
hasher.update(b"/NSSA/v0.1/ViewTag");
hasher.update(b"/NSSA/v0.2/ViewTag/");
hasher.update(npk.to_byte_array());
hasher.update(ivk.to_bytes());
let digest: [u8; 32] = hasher.finalize().into();
@ -166,7 +166,7 @@ pub mod tests {
let expected_view_tag = {
let mut hasher = Sha256::new();
hasher.update(b"/NSSA/v0.1/ViewTag");
hasher.update(b"/NSSA/v0.2/ViewTag/");
hasher.update(npk.to_byte_array());
hasher.update(ivk.to_bytes());
let digest: [u8; 32] = hasher.finalize().into();

View File

@ -8,7 +8,7 @@ use nssa_core::{
use crate::error::NssaError;
use crate::privacy_preserving_transaction::circuit::Proof;
use crate::privacy_preserving_transaction::message::EncryptedAccountData;
use crate::{Address, V01State};
use crate::{Address, V02State};
use super::message::Message;
use super::witness_set::WitnessSet;
@ -29,7 +29,7 @@ impl PrivacyPreservingTransaction {
pub(crate) fn validate_and_produce_public_state_diff(
&self,
state: &mut V01State,
state: &V02State,
) -> Result<HashMap<Address, Account>, NssaError> {
let message = &self.message;
let witness_set = &self.witness_set;

View File

@ -1,29 +1,41 @@
use crate::program_methods::{
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF,
TOKEN_ID,
};
use crate::program_methods::{AUTHENTICATED_TRANSFER_ELF, PINATA_ELF, TOKEN_ELF};
use nssa_core::{
account::{Account, AccountWithMetadata},
program::{InstructionData, ProgramId, ProgramOutput},
};
use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec};
use serde::Serialize;
use crate::error::NssaError;
/// Maximum number of cycles for a public execution.
/// TODO: Make this variable when fees are implemented
const MAX_NUM_CYCLES_PUBLIC_EXECUTION: u64 = 1024 * 1024 * 32; // 32M cycles
#[derive(Debug, PartialEq, Eq)]
pub struct Program {
id: ProgramId,
elf: &'static [u8],
elf: Vec<u8>,
}
impl Program {
pub 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 fn elf(&self) -> &[u8] {
&self.elf
}
pub fn serialize_instruction<T: Serialize>(
@ -39,13 +51,14 @@ impl Program {
) -> Result<Vec<Account>, NssaError> {
// Write inputs to the program
let mut env_builder = ExecutorEnv::builder();
env_builder.session_limit(Some(MAX_NUM_CYCLES_PUBLIC_EXECUTION));
Self::write_inputs(pre_states, instruction_data, &mut env_builder)?;
let env = env_builder.build().unwrap();
// 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 +84,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 +122,7 @@ mod tests {
Program {
id: NONCE_CHANGER_ID,
elf: NONCE_CHANGER_ELF,
elf: NONCE_CHANGER_ELF.to_vec(),
}
}
@ -118,7 +132,7 @@ mod tests {
Program {
id: EXTRA_OUTPUT_ID,
elf: EXTRA_OUTPUT_ELF,
elf: EXTRA_OUTPUT_ELF.to_vec(),
}
}
@ -128,7 +142,7 @@ mod tests {
Program {
id: MISSING_OUTPUT_ID,
elf: MISSING_OUTPUT_ELF,
elf: MISSING_OUTPUT_ELF.to_vec(),
}
}
@ -138,7 +152,7 @@ mod tests {
Program {
id: PROGRAM_OWNER_CHANGER_ID,
elf: PROGRAM_OWNER_CHANGER_ELF,
elf: PROGRAM_OWNER_CHANGER_ELF.to_vec(),
}
}
@ -148,7 +162,7 @@ mod tests {
Program {
id: SIMPLE_BALANCE_TRANSFER_ID,
elf: SIMPLE_BALANCE_TRANSFER_ELF,
elf: SIMPLE_BALANCE_TRANSFER_ELF.to_vec(),
}
}
@ -158,7 +172,7 @@ mod tests {
Program {
id: DATA_CHANGER_ID,
elf: DATA_CHANGER_ELF,
elf: DATA_CHANGER_ELF.to_vec(),
}
}
@ -168,7 +182,7 @@ mod tests {
Program {
id: MINTER_ID,
elf: MINTER_ELF,
elf: MINTER_ELF.to_vec(),
}
}
@ -178,7 +192,7 @@ mod tests {
Program {
id: BURNER_ID,
elf: BURNER_ELF,
elf: BURNER_ELF.to_vec(),
}
}
}
@ -216,4 +230,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);
}
}

View File

@ -0,0 +1,10 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Message {
pub(crate) bytecode: Vec<u8>,
}
impl Message {
pub fn new(bytecode: Vec<u8>) -> Self {
Self { bytecode }
}
}

View File

@ -0,0 +1,5 @@
mod message;
mod transaction;
pub use message::Message;
pub use transaction::ProgramDeploymentTransaction;

View File

@ -0,0 +1,27 @@
use crate::{
V02State, error::NssaError, program::Program, program_deployment_transaction::message::Message,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProgramDeploymentTransaction {
pub(crate) message: Message,
}
impl ProgramDeploymentTransaction {
pub fn new(message: Message) -> Self {
Self { message }
}
pub(crate) fn validate_and_produce_public_state_diff(
&self,
state: &V02State,
) -> 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)
}
}
}

View File

@ -8,7 +8,7 @@ use nssa_core::{
use sha2::{Digest, digest::FixedOutput};
use crate::{
V01State,
V02State,
error::NssaError,
public_transaction::{Message, WitnessSet},
};
@ -52,7 +52,7 @@ impl PublicTransaction {
pub(crate) fn validate_and_produce_public_state_diff(
&self,
state: &V01State,
state: &V02State,
) -> Result<HashMap<Address, Account>, NssaError> {
let message = self.message();
let witness_set = self.witness_set();
@ -100,9 +100,8 @@ impl PublicTransaction {
})
.collect();
// 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 {
// Check the `program_id` corresponds to a deployed program
let Some(program) = state.programs().get(&message.program_id) else {
return Err(NssaError::InvalidInput("Unknown program".into()));
};
@ -124,7 +123,7 @@ pub mod tests {
use sha2::{Digest, digest::FixedOutput};
use crate::{
Address, PrivateKey, PublicKey, PublicTransaction, Signature, V01State,
Address, PrivateKey, PublicKey, PublicTransaction, Signature, V02State,
error::NssaError,
program::Program,
public_transaction::{Message, WitnessSet},
@ -138,10 +137,10 @@ pub mod tests {
(key1, key2, addr1, addr2)
}
fn state_for_tests() -> V01State {
fn state_for_tests() -> V02State {
let (_, _, addr1, addr2) = keys_for_tests();
let initial_data = [(addr1, 10000), (addr2, 20000)];
V01State::new_with_genesis_accounts(&initial_data, &[])
V02State::new_with_genesis_accounts(&initial_data, &[])
}
fn transaction_for_tests() -> PublicTransaction {
@ -187,12 +186,12 @@ pub mod tests {
let tx = transaction_for_tests();
let expected_signer_addresses = vec![
Address::new([
14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99,
102, 56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101,
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9,
115, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
]),
Address::new([
158, 61, 142, 101, 77, 68, 14, 149, 41, 58, 162, 220, 236, 235, 19, 120, 153, 165,
149, 53, 233, 82, 247, 71, 6, 142, 122, 14, 227, 9, 101, 242,
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57,
141, 98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
]),
];
let signer_addresses = tx.signer_addresses();

View File

@ -33,7 +33,7 @@ impl PublicKey {
impl From<&PublicKey> for Address {
fn from(key: &PublicKey) -> Self {
const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.1/AccountId/Public/\x00\x00\x00\x00";
const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.2/AccountId/Public/\x00\x00\x00\x00";
let mut hasher = Sha256::new();
hasher.update(PUBLIC_ACCOUNT_ID_PREFIX);

View File

@ -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::{
@ -58,13 +59,13 @@ impl CommitmentSet {
type NullifierSet = HashSet<Nullifier>;
pub struct V01State {
pub struct V02State {
public_state: HashMap<Address, Account>,
private_state: (CommitmentSet, NullifierSet),
builtin_programs: HashMap<ProgramId, Program>,
programs: HashMap<ProgramId, Program>,
}
impl V01State {
impl V02State {
pub fn new_with_genesis_accounts(
initial_data: &[(Address, u128)],
initial_commitments: &[nssa_core::Commitment],
@ -90,7 +91,7 @@ impl V01State {
let mut this = Self {
public_state,
private_state: (private_state, NullifierSet::new()),
builtin_programs: HashMap::new(),
programs: HashMap::new(),
};
this.insert_program(Program::authenticated_transfer_program());
@ -100,7 +101,7 @@ impl V01State {
}
pub(crate) fn insert_program(&mut self, program: Program) {
self.builtin_programs.insert(program.id(), program);
self.programs.insert(program.id(), program);
}
pub fn transition_from_public_transaction(
@ -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,8 +182,8 @@ impl V01State {
self.private_state.0.get_proof_for(commitment)
}
pub(crate) fn builtin_programs(&self) -> &HashMap<ProgramId, Program> {
&self.builtin_programs
pub(crate) fn programs(&self) -> &HashMap<ProgramId, Program> {
&self.programs
}
pub fn commitment_set_digest(&self) -> CommitmentSetDigest {
@ -215,7 +225,7 @@ impl V01State {
}
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
impl V01State {
impl V02State {
pub fn add_pinata_program(&mut self, address: Address) {
self.insert_program(Program::pinata());
@ -238,7 +248,7 @@ pub mod tests {
use std::collections::HashMap;
use crate::{
Address, PublicKey, PublicTransaction, V01State,
Address, PublicKey, PublicTransaction, V02State,
error::NssaError,
execute_and_prove,
privacy_preserving_transaction::{
@ -309,22 +319,22 @@ pub mod tests {
this
};
let state = V01State::new_with_genesis_accounts(&initial_data, &[]);
let state = V02State::new_with_genesis_accounts(&initial_data, &[]);
assert_eq!(state.public_state, expected_public_state);
assert_eq!(state.builtin_programs, expected_builtin_programs);
assert_eq!(state.programs, expected_builtin_programs);
}
#[test]
fn test_insert_program() {
let mut state = V01State::new_with_genesis_accounts(&[], &[]);
let mut state = V02State::new_with_genesis_accounts(&[], &[]);
let program_to_insert = Program::simple_balance_transfer();
let program_id = program_to_insert.id();
assert!(!state.builtin_programs.contains_key(&program_id));
assert!(!state.programs.contains_key(&program_id));
state.insert_program(program_to_insert);
assert!(state.builtin_programs.contains_key(&program_id));
assert!(state.programs.contains_key(&program_id));
}
#[test]
@ -332,7 +342,7 @@ pub mod tests {
let key = PrivateKey::try_new([1; 32]).unwrap();
let addr = Address::from(&PublicKey::new_from_private_key(&key));
let initial_data = [(addr, 100u128)];
let state = V01State::new_with_genesis_accounts(&initial_data, &[]);
let state = V02State::new_with_genesis_accounts(&initial_data, &[]);
let expected_account = state.public_state.get(&addr).unwrap();
let account = state.get_account_by_address(&addr);
@ -343,7 +353,7 @@ pub mod tests {
#[test]
fn test_get_account_by_address_default_account() {
let addr2 = Address::new([0; 32]);
let state = V01State::new_with_genesis_accounts(&[], &[]);
let state = V02State::new_with_genesis_accounts(&[], &[]);
let expected_account = Account::default();
let account = state.get_account_by_address(&addr2);
@ -353,11 +363,11 @@ pub mod tests {
#[test]
fn test_builtin_programs_getter() {
let state = V01State::new_with_genesis_accounts(&[], &[]);
let state = V02State::new_with_genesis_accounts(&[], &[]);
let builtin_programs = state.builtin_programs();
let builtin_programs = state.programs();
assert_eq!(builtin_programs, &state.builtin_programs);
assert_eq!(builtin_programs, &state.programs);
}
#[test]
@ -365,7 +375,7 @@ pub mod tests {
let key = PrivateKey::try_new([1; 32]).unwrap();
let address = Address::from(&PublicKey::new_from_private_key(&key));
let initial_data = [(address, 100)];
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
let from = address;
let to = Address::new([2; 32]);
assert_eq!(state.get_account_by_address(&to), Account::default());
@ -385,7 +395,7 @@ pub mod tests {
let key = PrivateKey::try_new([1; 32]).unwrap();
let address = Address::from(&PublicKey::new_from_private_key(&key));
let initial_data = [(address, 100)];
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
let from = address;
let from_key = key;
let to = Address::new([2; 32]);
@ -409,7 +419,7 @@ pub mod tests {
let address1 = Address::from(&PublicKey::new_from_private_key(&key1));
let address2 = Address::from(&PublicKey::new_from_private_key(&key2));
let initial_data = [(address1, 100), (address2, 200)];
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
let from = address2;
let from_key = key2;
let to = address1;
@ -432,7 +442,7 @@ pub mod tests {
let key2 = PrivateKey::try_new([2; 32]).unwrap();
let address2 = Address::from(&PublicKey::new_from_private_key(&key2));
let initial_data = [(address1, 100)];
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
let address3 = Address::new([3; 32]);
let balance_to_move = 5;
@ -450,7 +460,7 @@ pub mod tests {
assert_eq!(state.get_account_by_address(&address3).nonce, 0);
}
impl V01State {
impl V02State {
pub fn force_insert_account(&mut self, address: Address, account: Account) {
self.public_state.insert(address, account);
}
@ -517,7 +527,7 @@ pub mod tests {
fn test_program_should_fail_if_modifies_nonces() {
let initial_data = [(Address::new([1; 32]), 100)];
let mut state =
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
let addresses = vec![Address::new([1; 32])];
let program_id = Program::nonce_changer_program().id();
let message =
@ -534,7 +544,7 @@ pub mod tests {
fn test_program_should_fail_if_output_accounts_exceed_inputs() {
let initial_data = [(Address::new([1; 32]), 100)];
let mut state =
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
let addresses = vec![Address::new([1; 32])];
let program_id = Program::extra_output_program().id();
let message =
@ -551,7 +561,7 @@ pub mod tests {
fn test_program_should_fail_with_missing_output_accounts() {
let initial_data = [(Address::new([1; 32]), 100)];
let mut state =
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
let addresses = vec![Address::new([1; 32]), Address::new([2; 32])];
let program_id = Program::missing_output_program().id();
let message =
@ -568,7 +578,7 @@ pub mod tests {
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner() {
let initial_data = [(Address::new([1; 32]), 0)];
let mut state =
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
let address = Address::new([1; 32]);
let account = state.get_account_by_address(&address);
// Assert the target account only differs from the default account in the program owner field
@ -590,7 +600,7 @@ pub mod tests {
#[test]
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_balance() {
let initial_data = [];
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
.with_test_programs()
.with_non_default_accounts_but_default_program_owners();
let address = Address::new([255; 32]);
@ -614,7 +624,7 @@ pub mod tests {
#[test]
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_nonce() {
let initial_data = [];
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
.with_test_programs()
.with_non_default_accounts_but_default_program_owners();
let address = Address::new([254; 32]);
@ -638,7 +648,7 @@ pub mod tests {
#[test]
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_data() {
let initial_data = [];
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
.with_test_programs()
.with_non_default_accounts_but_default_program_owners();
let address = Address::new([253; 32]);
@ -663,7 +673,7 @@ pub mod tests {
fn test_program_should_fail_if_transfers_balance_from_non_owned_account() {
let initial_data = [(Address::new([1; 32]), 100)];
let mut state =
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
let sender_address = Address::new([1; 32]);
let receiver_address = Address::new([2; 32]);
let balance_to_move: u128 = 1;
@ -690,7 +700,7 @@ pub mod tests {
#[test]
fn test_program_should_fail_if_modifies_data_of_non_owned_account() {
let initial_data = [];
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
.with_test_programs()
.with_non_default_accounts_but_default_program_owners();
let address = Address::new([255; 32]);
@ -715,7 +725,7 @@ pub mod tests {
fn test_program_should_fail_if_does_not_preserve_total_balance_by_minting() {
let initial_data = [];
let mut state =
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
let address = Address::new([1; 32]);
let program_id = Program::minter().id();
@ -732,7 +742,7 @@ pub mod tests {
#[test]
fn test_program_should_fail_if_does_not_preserve_total_balance_by_burning() {
let initial_data = [];
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
.with_test_programs()
.with_account_owned_by_burner_program();
let program_id = Program::burner().id();
@ -807,7 +817,7 @@ pub mod tests {
sender_keys: &TestPublicKeys,
recipient_keys: &TestPrivateKeys,
balance_to_move: u128,
state: &V01State,
state: &V02State,
) -> PrivacyPreservingTransaction {
let sender = AccountWithMetadata::new(
state.get_account_by_address(&sender_keys.address()),
@ -852,7 +862,7 @@ pub mod tests {
recipient_keys: &TestPrivateKeys,
balance_to_move: u128,
new_nonces: [Nonce; 2],
state: &V01State,
state: &V02State,
) -> PrivacyPreservingTransaction {
let program = Program::authenticated_transfer_program();
let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account);
@ -908,7 +918,7 @@ pub mod tests {
recipient_address: &Address,
balance_to_move: u128,
new_nonce: Nonce,
state: &V01State,
state: &V02State,
) -> PrivacyPreservingTransaction {
let program = Program::authenticated_transfer_program();
let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account);
@ -956,7 +966,7 @@ pub mod tests {
let sender_keys = test_public_account_keys_1();
let recipient_keys = test_private_account_keys_1();
let mut state = V01State::new_with_genesis_accounts(&[(sender_keys.address(), 200)], &[]);
let mut state = V02State::new_with_genesis_accounts(&[(sender_keys.address(), 200)], &[]);
let balance_to_move = 37;
@ -1002,7 +1012,7 @@ pub mod tests {
};
let recipient_keys = test_private_account_keys_2();
let mut state = V01State::new_with_genesis_accounts(&[], &[])
let mut state = V02State::new_with_genesis_accounts(&[], &[])
.with_private_account(&sender_keys, &sender_private_account);
let balance_to_move = 37;
@ -1068,7 +1078,7 @@ pub mod tests {
};
let recipient_keys = test_public_account_keys_1();
let recipient_initial_balance = 400;
let mut state = V01State::new_with_genesis_accounts(
let mut state = V02State::new_with_genesis_accounts(
&[(recipient_keys.address(), recipient_initial_balance)],
&[],
)
@ -1956,7 +1966,7 @@ pub mod tests {
};
let recipient_keys = test_private_account_keys_2();
let mut state = V01State::new_with_genesis_accounts(&[], &[])
let mut state = V02State::new_with_genesis_accounts(&[], &[])
.with_private_account(&sender_keys, &sender_private_account);
let balance_to_move = 37;

View File

@ -98,6 +98,7 @@ impl SequencerCore {
Err(TransactionMalformationErrorKind::InvalidSignature)
}
}
NSSATransaction::ProgramDeployment(tx) => Ok(NSSATransaction::ProgramDeployment(tx)),
}
}
@ -142,6 +143,12 @@ impl SequencerCore {
.transition_from_privacy_preserving_transaction(tx)
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
}
NSSATransaction::ProgramDeployment(tx) => {
self.store
.state
.transition_from_program_deployment_transaction(tx)
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
}
}
Ok(tx)
@ -231,13 +238,13 @@ mod tests {
fn setup_sequencer_config() -> SequencerConfig {
let acc1_addr = vec![
14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99, 102,
56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101,
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115,
84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
];
let acc2_addr = vec![
158, 61, 142, 101, 77, 68, 14, 149, 41, 58, 162, 220, 236, 235, 19, 120, 153, 165, 149,
53, 233, 82, 247, 71, 6, 142, 122, 14, 227, 9, 101, 242,
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141,
98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
];
let initial_acc1 = AccountInitialData {

View File

@ -10,7 +10,7 @@ use crate::config::AccountInitialData;
pub mod block_store;
pub struct SequecerChainStore {
pub state: nssa::V01State,
pub state: nssa::V02State,
pub block_store: SequecerBlockStore,
}
@ -29,12 +29,12 @@ impl SequecerChainStore {
.collect();
#[cfg(not(feature = "testnet"))]
let state = nssa::V01State::new_with_genesis_accounts(&init_accs, initial_commitments);
let state = nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments);
#[cfg(feature = "testnet")]
let state = {
let mut this =
nssa::V01State::new_with_genesis_accounts(&init_accs, initial_commitments);
nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments);
this.add_pinata_program("cafe".repeat(16).parse().unwrap());
this
};

View File

@ -330,13 +330,13 @@ mod tests {
let tempdir = tempdir().unwrap();
let home = tempdir.path().to_path_buf();
let acc1_addr = vec![
14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99, 102,
56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101,
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115,
84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
];
let acc2_addr = vec![
158, 61, 142, 101, 77, 68, 14, 149, 41, 58, 162, 220, 236, 235, 19, 120, 153, 165, 149,
53, 233, 82, 247, 71, 6, 142, 122, 14, 227, 9, 101, 242,
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141,
98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
];
let initial_acc1 = AccountInitialData {
@ -374,8 +374,8 @@ mod tests {
let balance_to_move = 10;
let tx = common::test_utils::create_transaction_native_token_transfer(
[
14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99,
102, 56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101,
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9,
115, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
],
0,
[2; 32],

View File

@ -8,11 +8,11 @@
"port": 3040,
"initial_accounts": [
{
"addr": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065",
"addr": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
"balance": 10000
},
{
"addr": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2",
"addr": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
"balance": 20000
}
],

View File

@ -4,7 +4,6 @@ version = "0.1.0"
edition = "2024"
[dependencies]
anyhow.workspace = true
thiserror.workspace = true
borsh.workspace = true

View File

@ -14,7 +14,6 @@ tempfile.workspace = true
clap.workspace = true
nssa-core = { path = "../nssa/core" }
base64.workspace = true
k256 = { version = "0.13.3" }
bytemuck = "1.23.2"
borsh.workspace = true
hex.workspace = true

View File

@ -77,14 +77,14 @@ mod tests {
fn create_initial_accounts() -> Vec<InitialAccountData> {
let initial_acc1 = serde_json::from_str(r#"{
"Public": {
"address": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065",
"address": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
"pub_sign_key": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
}
}"#).unwrap();
let initial_acc2 = serde_json::from_str(r#"{
"Public": {
"address": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2",
"address": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
"pub_sign_key": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
}
}"#).unwrap();