diff --git a/common/src/sequencer_client/mod.rs b/common/src/sequencer_client/mod.rs index 1aec903..5f0bb85 100644 --- a/common/src/sequencer_client/mod.rs +++ b/common/src/sequencer_client/mod.rs @@ -237,4 +237,23 @@ impl SequencerClient { Ok(resp_deser) } + + pub async fn send_tx_program( + &self, + transaction: nssa::ProgramDeploymentTransaction, + ) -> Result { + 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) + } } diff --git a/common/src/test_utils/mod.rs b/common/src/test_utils.rs similarity index 99% rename from common/src/test_utils/mod.rs rename to common/src/test_utils.rs index 9d68db8..9678580 100644 --- a/common/src/test_utils/mod.rs +++ b/common/src/test_utils.rs @@ -68,3 +68,4 @@ pub fn create_transaction_native_token_transfer( EncodedTransaction::from(NSSATransaction::Public(nssa_tx)) } + diff --git a/common/src/transaction.rs b/common/src/transaction.rs index add67b0..0a6c057 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -30,6 +30,12 @@ impl From for NSSATransaction { } } +impl From for NSSATransaction { + fn from(value: nssa::ProgramDeploymentTransaction) -> Self { + Self::ProgramDeployment(value) + } +} + use crate::TreeHashType; pub type CipherText = Vec; @@ -66,7 +72,7 @@ impl From for EncodedTransaction { }, NSSATransaction::ProgramDeployment(tx) => Self { tx_kind: TxKind::ProgramDeployment, - encoded_transaction_data: todo!(), + encoded_transaction_data: tx.to_bytes(), }, } } @@ -83,7 +89,10 @@ impl TryFrom<&EncodedTransaction> for NSSATransaction { nssa::PrivacyPreservingTransaction::from_bytes(&value.encoded_transaction_data) .map(|tx| tx.into()) } - TxKind::ProgramDeployment => todo!(), + TxKind::ProgramDeployment => { + nssa::ProgramDeploymentTransaction::from_bytes(&value.encoded_transaction_data) + .map(|tx| tx.into()) + } } } } diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 1690445..85cb7a1 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -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, }; @@ -42,6 +42,8 @@ pub const ACC_RECEIVER_PRIVATE: &str = pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12; +pub const NSSA_PROGRAM_FOR_TEST: &'static [u8] = include_bytes!("simple_balance_transfer.bin"); + #[allow(clippy::type_complexity)] pub async fn pre_test( home_dir: PathBuf, @@ -791,6 +793,20 @@ pub async fn test_pinata() { info!("Success!"); } +pub async fn test_program_deployment() { + info!("test program deployment"); + println!("{}", NSSA_PROGRAM_FOR_TEST.len()); + let bytecode = NSSA_PROGRAM_FOR_TEST.to_vec(); + let message = nssa::program_deployment_transaction::Message::new(bytecode); + 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(); + println!("response: {:?}", response); +} + macro_rules! test_cleanup_wrap { ($home_dir:ident, $test_func:ident) => {{ let res = pre_test($home_dir.clone()).await.unwrap(); @@ -871,6 +887,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); + } "all" => { test_cleanup_wrap!(home_dir, test_success_move_to_another_account); test_cleanup_wrap!(home_dir, test_success); @@ -902,6 +921,7 @@ pub async fn main_tests_runner() -> Result<()> { test_success_private_transfer_to_another_owned_account_claiming_path ); test_cleanup_wrap!(home_dir, test_pinata); + test_cleanup_wrap!(home_dir, test_program_deployment); } "all_private" => { test_cleanup_wrap!( diff --git a/integration_tests/src/simple_balance_transfer.bin b/integration_tests/src/simple_balance_transfer.bin new file mode 100644 index 0000000..f4e72c9 Binary files /dev/null and b/integration_tests/src/simple_balance_transfer.bin differ diff --git a/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs b/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs index 266db1a..a1aa8c9 100644 --- a/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs +++ b/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs @@ -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(); diff --git a/nssa/src/encoding/program_deployment_transaction.rs b/nssa/src/encoding/program_deployment_transaction.rs index 1a31e59..70bd4ea 100644 --- a/nssa/src/encoding/program_deployment_transaction.rs +++ b/nssa/src/encoding/program_deployment_transaction.rs @@ -36,9 +36,10 @@ impl Message { )); } let bytecode_len = u32_from_cursor(cursor)?; - let mut bytecode = Vec::with_capacity(bytecode_len as usize); + 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(), )); @@ -68,3 +69,20 @@ fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { 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); + } +} diff --git a/nssa/src/program_deployment_transaction/message.rs b/nssa/src/program_deployment_transaction/message.rs index 4601975..6a5c670 100644 --- a/nssa/src/program_deployment_transaction/message.rs +++ b/nssa/src/program_deployment_transaction/message.rs @@ -2,3 +2,9 @@ pub struct Message { pub(crate) bytecode: Vec, } + +impl Message { + pub fn new(bytecode: Vec) -> Self { + Self { bytecode } + } +} diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 92db97e..ea9c430 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -100,8 +100,7 @@ impl PublicTransaction { }) .collect(); - // Check the `program_id` corresponds to a built-in program - // Only allowed program so far is the authenticated transfer program + // 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())); }; diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 172d41e..f7fc9be 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -98,7 +98,7 @@ impl SequencerCore { Err(TransactionMalformationErrorKind::InvalidSignature) } } - NSSATransaction::ProgramDeployment(program_deployment_transaction) => todo!(), + NSSATransaction::ProgramDeployment(tx) => Ok(NSSATransaction::ProgramDeployment(tx)), } }