From b80c89848cce59486e62799a87007893789f45d7 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Fri, 22 May 2026 16:50:55 +0300 Subject: [PATCH] feat(integration_tests): generic call of a transfer test added --- integration_tests/tests/wallet_ffi.rs | 114 +++++++++++++++++++++++++- nssa/src/program.rs | 4 +- wallet-ffi/src/generic_transaction.rs | 26 +++++- wallet-ffi/wallet_ffi.h | 16 ++-- 4 files changed, 145 insertions(+), 15 deletions(-) diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index 2677e10e..51de9b3f 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -21,13 +21,12 @@ use std::{ use anyhow::Result; use integration_tests::{BlockingTestContext, TIME_TO_WAIT_FOR_BLOCK_SECONDS}; use log::info; -use nssa::{Account, AccountId, PrivateKey, PublicKey, program::Program}; +use nssa::{Account, AccountId, PrivateKey, PublicKey, privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program}; use nssa_core::program::DEFAULT_PROGRAM_ID; use tempfile::tempdir; use wallet::account::HumanReadableAccount; use wallet_ffi::{ - FfiAccount, FfiAccountList, FfiBytes32, FfiPrivateAccountKeys, FfiPublicAccountKey, - FfiTransferResult, FfiU128, WalletHandle, error, + FfiAccount, FfiAccountIdentity, FfiAccountList, FfiBytes32, FfiPrivateAccountKeys, FfiPublicAccountKey, FfiTransferResult, FfiU128, WalletHandle, error, generic_transaction::FfiProgramWithDependencies }; unsafe extern "C" { @@ -179,6 +178,22 @@ unsafe extern "C" { handle: *mut WalletHandle, out_block_height: *mut u64, ) -> error::WalletFfiError; + + fn wallet_ffi_resolve_public_account( + account_id: FfiBytes32, + needs_sign: bool, + out_account_identity: *mut FfiAccountIdentity, + ) -> error::WalletFfiError; + + fn wallet_ffi_send_generic_public_transaction( + handle: *mut WalletHandle, + account_identities: *const FfiAccountIdentity, + account_identities_size: usize, + instruction_words: *const u32, + instruction_words_size: usize, + program_with_dependencies: FfiProgramWithDependencies, + out_result: *mut FfiTransferResult, + ) -> error::WalletFfiError; } fn new_wallet_ffi_with_test_context_config( @@ -1066,3 +1081,96 @@ fn test_wallet_ffi_transfer_private() -> Result<()> { Ok(()) } + +#[test] +fn test_wallet_ffi_transfer_generic_public() -> Result<()> { + let ctx = BlockingTestContext::new()?; + let home = tempfile::tempdir()?; + let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into(); + let to: FfiBytes32 = ctx.ctx().existing_public_accounts()[1].into(); + let amount = 100_u128; + + let mut transfer_result = FfiTransferResult::default(); + + let mut from_account_identity = FfiAccountIdentity::default(); + let mut to_account_identity = FfiAccountIdentity::default(); + + unsafe{ + wallet_ffi_resolve_public_account( + from, + true, + &raw mut from_account_identity + ) + .unwrap(); + } + + unsafe{ + wallet_ffi_resolve_public_account( + to, + true, + &raw mut to_account_identity + ) + .unwrap(); + } + + let ffi_accs = vec![from_account_identity, to_account_identity]; + let account_identities_size = ffi_accs.len(); + let account_identities = Box::into_raw(ffi_accs.into_boxed_slice()) as *const FfiAccountIdentity; + + let instruction_data = + Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { + amount, + }) + .unwrap(); + let instruction_words_size = instruction_data.len(); + let instruction_words = Box::into_raw(instruction_data.into_boxed_slice()) as *const u32; + + let program: ProgramWithDependencies = Program::authenticated_transfer_program().into(); + let program_with_dependencies = program.into(); + + unsafe{ + wallet_ffi_send_generic_public_transaction( + wallet_ffi_handle, + account_identities, + account_identities_size, + instruction_words, + instruction_words_size, + program_with_dependencies, + &raw mut transfer_result + ) + .unwrap(); + } + + info!("Waiting for next block creation"); + std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)); + + let from_balance = unsafe { + let mut out_balance: [u8; 16] = [0; 16]; + wallet_ffi_get_balance( + wallet_ffi_handle, + &raw const from, + true, + &raw mut out_balance, + ) + .unwrap(); + u128::from_le_bytes(out_balance) + }; + + let to_balance = unsafe { + let mut out_balance: [u8; 16] = [0; 16]; + wallet_ffi_get_balance(wallet_ffi_handle, &raw const to, true, &raw mut out_balance) + .unwrap(); + u128::from_le_bytes(out_balance) + }; + + assert_eq!(from_balance, 9900); + assert_eq!(to_balance, 20100); + + unsafe { + wallet_ffi_free_transfer_result(&raw mut transfer_result); + wallet_ffi_destroy(wallet_ffi_handle); + } + + Ok(()) +} diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 1aff3bc9..ada2428f 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -21,8 +21,8 @@ const MAX_NUM_CYCLES_PUBLIC_EXECUTION: u64 = 1024 * 1024 * 32; // 32M cycles #[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Program { - id: ProgramId, - elf: Vec, + pub id: ProgramId, + pub elf: Vec, } impl Program { diff --git a/wallet-ffi/src/generic_transaction.rs b/wallet-ffi/src/generic_transaction.rs index 1195c131..ef4b77c2 100644 --- a/wallet-ffi/src/generic_transaction.rs +++ b/wallet-ffi/src/generic_transaction.rs @@ -96,6 +96,15 @@ impl TryFrom<&FfiProgram> for Program { } } +impl From for FfiProgram { + fn from(value: Program) -> Self { + let elf_size = value.elf.len(); + let elf_data = Box::into_raw(value.elf.into_boxed_slice()) as *const u8; + + Self { elf_data, elf_size } + } +} + #[repr(C)] /// Intended to be created manually pub struct FfiProgramWithDependencies { @@ -128,13 +137,26 @@ impl TryFrom for ProgramWithDependencies { } } +impl From for FfiProgramWithDependencies { + fn from(value: ProgramWithDependencies) -> Self { + let ffi_program = value.program.into(); + + let ffi_deps: Vec = value.dependencies.into_values().map(Into::into).collect::>(); + + let deps_size = ffi_deps.len(); + let deps = Box::into_raw(ffi_deps.into_boxed_slice()) as *const FfiProgram; + + Self { program: ffi_program, deps, deps_size } + } +} + #[repr(C)] pub enum FfiExecutionFlow { Public = 0, PrivacyPreserving = 1, } -/// Send generic transaction +/// Send generic public transaction /// /// # Parameters /// - `handle`: Valid pointer to wallet handle @@ -152,7 +174,7 @@ pub enum FfiExecutionFlow { /// - `instruction_words` must be a valid pointer /// - `out_result` must be a valid pointer #[no_mangle] -pub unsafe extern "C" fn wallet_ffi_send_generic_transaction( +pub unsafe extern "C" fn wallet_ffi_send_generic_public_transaction( handle: *mut WalletHandle, account_identities: *const FfiAccountIdentity, account_identities_size: usize, diff --git a/wallet-ffi/wallet_ffi.h b/wallet-ffi/wallet_ffi.h index 86b50de9..3c814c71 100644 --- a/wallet-ffi/wallet_ffi.h +++ b/wallet-ffi/wallet_ffi.h @@ -536,7 +536,7 @@ struct SerializationHelperResult wallet_ffi_serialization_helper(const uint8_t * uintptr_t input_instruction_data_size); /** - * Send generic transaction + * Send generic public transaction * * # Parameters * - `handle`: Valid pointer to wallet handle @@ -554,13 +554,13 @@ struct SerializationHelperResult wallet_ffi_serialization_helper(const uint8_t * * - `instruction_words` must be a valid pointer * - `out_result` must be a valid pointer */ -enum WalletFfiError wallet_ffi_send_generic_transaction(struct WalletHandle *handle, - const struct FfiAccountIdentity *account_identities, - uintptr_t account_identities_size, - const uint32_t *instruction_words, - uintptr_t instruction_words_size, - struct FfiProgramWithDependencies program_with_dependencies, - struct FfiTransferResult *out_result); +enum WalletFfiError wallet_ffi_send_generic_public_transaction(struct WalletHandle *handle, + const struct FfiAccountIdentity *account_identities, + uintptr_t account_identities_size, + const uint32_t *instruction_words, + uintptr_t instruction_words_size, + struct FfiProgramWithDependencies program_with_dependencies, + struct FfiTransferResult *out_result); /** * Get the public key for a public account.