Merge branch 'main' into Pravdyvy/indexer-final-state

This commit is contained in:
Pravdyvy
2026-03-18 09:15:45 +02:00
245 changed files with 8246 additions and 6274 deletions
+15 -11
View File
@@ -1,3 +1,8 @@
#![expect(
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
use anyhow::Result;
use integration_tests::TestContext;
use log::info;
@@ -36,7 +41,7 @@ async fn get_existing_account() -> Result<()> {
async fn new_public_account_with_label() -> Result<()> {
let mut ctx = TestContext::new().await?;
let label = "my-test-public-account".to_string();
let label = "my-test-public-account".to_owned();
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {
cci: None,
label: Some(label.clone()),
@@ -45,9 +50,8 @@ async fn new_public_account_with_label() -> Result<()> {
let result = execute_subcommand(ctx.wallet_mut(), command).await?;
// Extract the account_id from the result
let account_id = match result {
wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id,
_ => panic!("Expected RegisterAccount return value"),
let wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } = result else {
panic!("Expected RegisterAccount return value")
};
// Verify the label was stored
@@ -69,7 +73,7 @@ async fn new_public_account_with_label() -> Result<()> {
async fn new_private_account_with_label() -> Result<()> {
let mut ctx = TestContext::new().await?;
let label = "my-test-private-account".to_string();
let label = "my-test-private-account".to_owned();
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {
cci: None,
label: Some(label.clone()),
@@ -78,9 +82,9 @@ async fn new_private_account_with_label() -> Result<()> {
let result = execute_subcommand(ctx.wallet_mut(), command).await?;
// Extract the account_id from the result
let account_id = match result {
wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id,
_ => panic!("Expected RegisterAccount return value"),
let wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } = result else {
panic!("Expected RegisterAccount return value")
};
// Verify the label was stored
@@ -110,9 +114,9 @@ async fn new_public_account_without_label() -> Result<()> {
let result = execute_subcommand(ctx.wallet_mut(), command).await?;
// Extract the account_id from the result
let account_id = match result {
wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } => account_id,
_ => panic!("Expected RegisterAccount return value"),
let wallet::cli::SubcommandReturnValue::RegisterAccount { account_id } = result else {
panic!("Expected RegisterAccount return value")
};
// Verify no label was stored
+8 -2
View File
@@ -1,3 +1,9 @@
#![expect(
clippy::shadow_unrelated,
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
use std::time::Duration;
use anyhow::Result;
@@ -108,7 +114,7 @@ async fn amm_public() -> Result<()> {
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_public_account_id(definition_account_id_1),
supply_account_id: format_public_account_id(supply_account_id_1),
name: "A NAM1".to_string(),
name: "A NAM1".to_owned(),
total_supply: 37,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@@ -132,7 +138,7 @@ async fn amm_public() -> Result<()> {
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_public_account_id(definition_account_id_2),
supply_account_id: format_public_account_id(supply_account_id_2),
name: "A NAM2".to_string(),
name: "A NAM2".to_owned(),
total_supply: 37,
};
wallet::cli::execute_subcommand(ctx.wallet_mut(), Command::Token(subcommand)).await?;
@@ -1,2 +1,8 @@
#![expect(
clippy::shadow_unrelated,
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
mod private;
mod public;
@@ -86,7 +86,7 @@ async fn private_transfer_to_foreign_account() -> Result<()> {
assert_eq!(tx.message.new_commitments[0], new_commitment1);
assert_eq!(tx.message.new_commitments.len(), 2);
for commitment in tx.message.new_commitments.into_iter() {
for commitment in tx.message.new_commitments {
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
}
@@ -198,7 +198,7 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> {
assert_eq!(tx.message.new_commitments[0], new_commitment1);
assert_eq!(tx.message.new_commitments.len(), 2);
for commitment in tx.message.new_commitments.into_iter() {
for commitment in tx.message.new_commitments {
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
}
@@ -353,7 +353,7 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> {
// Verify commitments are in state
assert_eq!(tx.message.new_commitments.len(), 2);
for commitment in tx.message.new_commitments.into_iter() {
for commitment in tx.message.new_commitments {
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
}
@@ -112,7 +112,7 @@ async fn failed_transfer_with_insufficient_balance() -> Result<()> {
to: Some(format_public_account_id(ctx.existing_public_accounts()[1])),
to_npk: None,
to_vpk: None,
amount: 1000000,
amount: 1_000_000,
});
let failed_send = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await;
+10 -5
View File
@@ -1,3 +1,9 @@
#![expect(
clippy::as_conversions,
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
use std::time::Duration;
use anyhow::Result;
@@ -24,7 +30,7 @@ async fn reject_oversized_transaction() -> Result<()> {
// Create a transaction that's definitely too large
// Block size is 1 MiB (1,048,576 bytes), minus ~200 bytes for header = ~1,048,376 bytes max tx
// Create a 1.1 MiB binary to ensure it exceeds the limit
let oversized_binary = vec![0u8; 1100 * 1024]; // 1.1 MiB binary
let oversized_binary = vec![0_u8; 1100 * 1024]; // 1.1 MiB binary
let message = nssa::program_deployment_transaction::Message::new(oversized_binary);
let tx = nssa::ProgramDeploymentTransaction::new(message);
@@ -38,13 +44,12 @@ async fn reject_oversized_transaction() -> Result<()> {
);
let err = result.unwrap_err();
let err_str = format!("{:?}", err);
let err_str = format!("{err:?}");
// Check if the error contains information about transaction being too large
assert!(
err_str.contains("TransactionTooLarge") || err_str.contains("too large"),
"Expected TransactionTooLarge error, got: {}",
err_str
"Expected TransactionTooLarge error, got: {err_str}"
);
Ok(())
@@ -63,7 +68,7 @@ async fn accept_transaction_within_limit() -> Result<()> {
.await?;
// Create a small program deployment that should fit
let small_binary = vec![0u8; 1024]; // 1 KiB binary
let small_binary = vec![0_u8; 1024]; // 1 KiB binary
let message = nssa::program_deployment_transaction::Message::new(small_binary);
let tx = nssa::ProgramDeploymentTransaction::new(message);
+10 -4
View File
@@ -1,3 +1,9 @@
#![expect(
clippy::shadow_unrelated,
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
use anyhow::Result;
use integration_tests::TestContext;
use log::info;
@@ -12,8 +18,8 @@ async fn modify_config_field() -> Result<()> {
// Change config field
let command = Command::Config(ConfigSubcommand::Set {
key: "seq_poll_timeout".to_string(),
value: "1s".to_string(),
key: "seq_poll_timeout".to_owned(),
value: "1s".to_owned(),
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@@ -22,8 +28,8 @@ async fn modify_config_field() -> Result<()> {
// Return how it was at the beginning
let command = Command::Config(ConfigSubcommand::Set {
key: "seq_poll_timeout".to_string(),
value: format!("{:?}", old_seq_poll_timeout),
key: "seq_poll_timeout".to_owned(),
value: format!("{old_seq_poll_timeout:?}"),
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
+13 -5
View File
@@ -1,14 +1,19 @@
#![expect(
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
use std::time::Duration;
use anyhow::Result;
use indexer_service_rpc::RpcClient;
use indexer_service_rpc::RpcClient as _;
use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, format_public_account_id};
use log::info;
use tokio::test;
use wallet::cli::{Command, programs::native_token_transfer::AuthTransferSubcommand};
/// Timeout in milliseconds to reliably await for block finalization
const L2_TO_L1_TIMEOUT_MILLIS: u64 = 600000;
/// Timeout in milliseconds to reliably await for block finalization.
const L2_TO_L1_TIMEOUT_MILLIS: u64 = 600_000;
#[test]
async fn indexer_test_run() -> Result<()> {
@@ -57,8 +62,11 @@ async fn indexer_block_batching() -> Result<()> {
assert!(last_block_indexer > 1);
// Getting wide batch to fit all blocks
let block_batch = ctx.indexer_client().get_blocks(1, 100).await.unwrap();
// Getting wide batch to fit all blocks (from latest backwards)
let mut block_batch = ctx.indexer_client().get_blocks(None, 100).await.unwrap();
// Reverse to check chain consistency from oldest to newest
block_batch.reverse();
// Checking chain consistency
let mut prev_block_hash = block_batch.first().unwrap().header.hash;
+97 -4
View File
@@ -1,9 +1,15 @@
use std::{str::FromStr, time::Duration};
#![expect(
clippy::shadow_unrelated,
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
use anyhow::Result;
use std::{str::FromStr as _, time::Duration};
use anyhow::{Context as _, Result};
use integration_tests::{
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, format_private_account_id,
format_public_account_id, verify_commitment_is_in_state,
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, fetch_privacy_preserving_tx,
format_private_account_id, format_public_account_id, verify_commitment_is_in_state,
};
use key_protocol::key_management::key_tree::chain_index::ChainIndex;
use log::info;
@@ -15,6 +21,93 @@ use wallet::cli::{
programs::native_token_transfer::AuthTransferSubcommand,
};
#[test]
async fn sync_private_account_with_non_zero_chain_index() -> Result<()> {
let mut ctx = TestContext::new().await?;
let from: AccountId = ctx.existing_private_accounts()[0];
// Create a new private account
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {
cci: None,
label: None,
}));
for _ in 0..3 {
// Key Tree shift
// This way we have account with child index > 0.
let result = wallet::cli::execute_subcommand(
ctx.wallet_mut(),
Command::Account(AccountSubcommand::New(NewSubcommand::Private {
cci: None,
label: None,
})),
)
.await?;
let SubcommandReturnValue::RegisterAccount { account_id: _ } = result else {
anyhow::bail!("Expected RegisterAccount return value");
};
}
let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
let SubcommandReturnValue::RegisterAccount {
account_id: to_account_id,
} = sub_ret
else {
anyhow::bail!("Expected RegisterAccount return value");
};
// Get the keys for the newly created account
let (to_keys, _) = ctx
.wallet()
.storage()
.user_data
.get_private_account(to_account_id)
.cloned()
.context("Failed to get private account")?;
// Send to this account using claiming path (using npk and vpk instead of account ID)
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: format_private_account_id(from),
to: None,
to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)),
to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)),
amount: 100,
});
let sub_ret = wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
anyhow::bail!("Expected PrivacyPreservingTransfer return value");
};
let tx = fetch_privacy_preserving_tx(ctx.sequencer_client(), tx_hash).await;
// Sync the wallet to claim the new account
let command = Command::Account(AccountSubcommand::SyncPrivate {});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
let new_commitment1 = ctx
.wallet()
.get_private_account_commitment(from)
.context("Failed to get private account commitment for sender")?;
assert_eq!(tx.message.new_commitments[0], new_commitment1);
assert_eq!(tx.message.new_commitments.len(), 2);
for commitment in tx.message.new_commitments {
assert!(verify_commitment_is_in_state(commitment, ctx.sequencer_client()).await);
}
let to_res_acc = ctx
.wallet()
.get_account_private(to_account_id)
.context("Failed to get recipient's private account")?;
assert_eq!(to_res_acc.balance, 100);
info!("Successfully transferred using claiming path");
Ok(())
}
#[test]
async fn restore_keys_from_seed() -> Result<()> {
let mut ctx = TestContext::new().await?;
+118
View File
@@ -1,3 +1,9 @@
#![expect(
clippy::shadow_unrelated,
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
use std::time::Duration;
use anyhow::{Context as _, Result};
@@ -16,6 +22,118 @@ use wallet::cli::{
},
};
#[test]
async fn claim_pinata_to_uninitialized_public_account_fails_fast() -> Result<()> {
let mut ctx = TestContext::new().await?;
let result = wallet::cli::execute_subcommand(
ctx.wallet_mut(),
Command::Account(AccountSubcommand::New(NewSubcommand::Public {
cci: None,
label: None,
})),
)
.await?;
let SubcommandReturnValue::RegisterAccount {
account_id: winner_account_id,
} = result
else {
anyhow::bail!("Expected RegisterAccount return value");
};
let winner_account_id_formatted = format_public_account_id(winner_account_id);
let pinata_balance_pre = ctx
.sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap())
.await?
.balance;
let claim_result = wallet::cli::execute_subcommand(
ctx.wallet_mut(),
Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
to: winner_account_id_formatted,
}),
)
.await;
assert!(
claim_result.is_err(),
"Expected uninitialized account error"
);
let err = claim_result.unwrap_err().to_string();
assert!(
err.contains("wallet auth-transfer init --account-id Public/"),
"Expected init guidance, got: {err}",
);
let pinata_balance_post = ctx
.sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap())
.await?
.balance;
assert_eq!(pinata_balance_post, pinata_balance_pre);
Ok(())
}
#[test]
async fn claim_pinata_to_uninitialized_private_account_fails_fast() -> Result<()> {
let mut ctx = TestContext::new().await?;
let result = wallet::cli::execute_subcommand(
ctx.wallet_mut(),
Command::Account(AccountSubcommand::New(NewSubcommand::Private {
cci: None,
label: None,
})),
)
.await?;
let SubcommandReturnValue::RegisterAccount {
account_id: winner_account_id,
} = result
else {
anyhow::bail!("Expected RegisterAccount return value");
};
let winner_account_id_formatted = format_private_account_id(winner_account_id);
let pinata_balance_pre = ctx
.sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap())
.await?
.balance;
let claim_result = wallet::cli::execute_subcommand(
ctx.wallet_mut(),
Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
to: winner_account_id_formatted,
}),
)
.await;
assert!(
claim_result.is_err(),
"Expected uninitialized account error"
);
let err = claim_result.unwrap_err().to_string();
assert!(
err.contains("wallet auth-transfer init --account-id Private/"),
"Expected init guidance, got: {err}",
);
let pinata_balance_post = ctx
.sequencer_client()
.get_account_balance(PINATA_BASE58.parse().unwrap())
.await?
.balance;
assert_eq!(pinata_balance_post, pinata_balance_pre);
Ok(())
}
#[test]
async fn claim_pinata_to_existing_public_account() -> Result<()> {
let mut ctx = TestContext::new().await?;
@@ -1,3 +1,8 @@
#![expect(
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
use std::{path::PathBuf, time::Duration};
use anyhow::Result;
+13 -7
View File
@@ -1,3 +1,9 @@
#![expect(
clippy::shadow_unrelated,
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
use std::time::Duration;
use anyhow::{Context as _, Result};
@@ -69,7 +75,7 @@ async fn create_and_transfer_public_token() -> Result<()> {
};
// Create new token
let name = "A NAME".to_string();
let name = "A NAME".to_owned();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_public_account_id(definition_account_id),
@@ -317,7 +323,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> {
};
// Create new token
let name = "A NAME".to_string();
let name = "A NAME".to_owned();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_public_account_id(definition_account_id),
@@ -475,7 +481,7 @@ async fn create_token_with_private_definition() -> Result<()> {
};
// Create token with private definition
let name = "A NAME".to_string();
let name = "A NAME".to_owned();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_private_account_id(definition_account_id),
@@ -671,7 +677,7 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> {
};
// Create token with both private definition and supply
let name = "A NAME".to_string();
let name = "A NAME".to_owned();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_private_account_id(definition_account_id),
@@ -843,7 +849,7 @@ async fn shielded_token_transfer() -> Result<()> {
};
// Create token
let name = "A NAME".to_string();
let name = "A NAME".to_owned();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_public_account_id(definition_account_id),
@@ -966,7 +972,7 @@ async fn deshielded_token_transfer() -> Result<()> {
};
// Create token with private supply
let name = "A NAME".to_string();
let name = "A NAME".to_owned();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_public_account_id(definition_account_id),
@@ -1073,7 +1079,7 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> {
};
// Create token
let name = "A NAME".to_string();
let name = "A NAME".to_owned();
let total_supply = 37;
let subcommand = TokenProgramAgnosticSubcommand::New {
definition_account_id: format_private_account_id(definition_account_id),
+114 -98
View File
@@ -1,3 +1,14 @@
#![expect(
clippy::arithmetic_side_effects,
clippy::float_arithmetic,
clippy::missing_asserts_for_indexing,
clippy::as_conversions,
clippy::tests_outside_test_module,
clippy::integer_division,
clippy::integer_division_remainder_used,
reason = "We don't care about these in tests"
)]
use std::time::{Duration, Instant};
use anyhow::Result;
@@ -21,6 +32,102 @@ use nssa_core::{
};
use tokio::test;
pub(crate) struct TpsTestManager {
public_keypairs: Vec<(PrivateKey, AccountId)>,
target_tps: u64,
}
impl TpsTestManager {
/// Generates public account keypairs. These are used to populate the config and to generate
/// valid public transactions for the tps test.
pub(crate) fn new(target_tps: u64, number_transactions: usize) -> Self {
let public_keypairs = (1..(number_transactions + 2))
.map(|i| {
let mut private_key_bytes = [0_u8; 32];
private_key_bytes[..8].copy_from_slice(&i.to_le_bytes());
let private_key = PrivateKey::try_new(private_key_bytes).unwrap();
let public_key = PublicKey::new_from_private_key(&private_key);
let account_id = AccountId::from(&public_key);
(private_key, account_id)
})
.collect();
Self {
public_keypairs,
target_tps,
}
}
#[expect(
clippy::cast_precision_loss,
reason = "This is just for testing purposes, we don't care about precision loss here"
)]
pub(crate) fn target_time(&self) -> Duration {
let number_transactions = (self.public_keypairs.len() - 1) as u64;
Duration::from_secs_f64(number_transactions as f64 / self.target_tps as f64)
}
/// Build a batch of public transactions to submit to the node.
pub fn build_public_txs(&self) -> Vec<PublicTransaction> {
// Create valid public transactions
let program = Program::authenticated_transfer_program();
let public_txs: Vec<PublicTransaction> = self
.public_keypairs
.windows(2)
.map(|pair| {
let amount: u128 = 1;
let message = putx::Message::try_new(
program.id(),
[pair[0].1, pair[1].1].to_vec(),
[0_u128].to_vec(),
amount,
)
.unwrap();
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[&pair[0].0]);
PublicTransaction::new(message, witness_set)
})
.collect();
public_txs
}
/// Generates a sequencer configuration with initial balance in a number of public accounts.
/// The transactions generated with the function `build_public_txs` will be valid in a node
/// started with the config from this method.
fn generate_initial_data(&self) -> InitialData {
// Create public public keypairs
let public_accounts = self
.public_keypairs
.iter()
.map(|(key, _)| (key.clone(), 10))
.collect();
// Generate an initial commitment to be used with the privacy preserving transaction
// created with the `build_privacy_transaction` function.
let key_chain = KeyChain::new_os_random();
let account = Account {
balance: 100,
nonce: 0xdead_beef,
program_owner: Program::authenticated_transfer_program().id(),
data: Data::default(),
};
InitialData {
public_accounts,
private_accounts: vec![(key_chain, account)],
}
}
const fn generate_sequencer_partial_config() -> SequencerPartialConfig {
SequencerPartialConfig {
max_num_tx_in_block: 300,
max_block_size: ByteSize::mb(500),
mempool_max_size: 10_000,
block_create_timeout: Duration::from_secs(12),
}
}
}
// TODO: Make a proper benchmark instead of an ad-hoc test
#[test]
pub async fn tps_test() -> Result<()> {
@@ -56,16 +163,17 @@ pub async fn tps_test() -> Result<()> {
for (i, tx_hash) in tx_hashes.iter().enumerate() {
loop {
if now.elapsed().as_millis() > target_time.as_millis() {
panic!("TPS test failed by timeout");
}
assert!(
now.elapsed().as_millis() <= target_time.as_millis(),
"TPS test failed by timeout"
);
let tx_obj = ctx
.sequencer_client()
.get_transaction_by_hash(*tx_hash)
.await
.inspect_err(|err| {
log::warn!("Failed to get transaction by hash {tx_hash} with error: {err:#?}")
log::warn!("Failed to get transaction by hash {tx_hash} with error: {err:#?}");
});
if let Ok(tx_obj) = tx_obj
@@ -94,98 +202,6 @@ pub async fn tps_test() -> Result<()> {
Ok(())
}
pub(crate) struct TpsTestManager {
public_keypairs: Vec<(PrivateKey, AccountId)>,
target_tps: u64,
}
impl TpsTestManager {
/// Generates public account keypairs. These are used to populate the config and to generate
/// valid public transactions for the tps test.
pub(crate) fn new(target_tps: u64, number_transactions: usize) -> Self {
let public_keypairs = (1..(number_transactions + 2))
.map(|i| {
let mut private_key_bytes = [0u8; 32];
private_key_bytes[..8].copy_from_slice(&i.to_le_bytes());
let private_key = PrivateKey::try_new(private_key_bytes).unwrap();
let public_key = PublicKey::new_from_private_key(&private_key);
let account_id = AccountId::from(&public_key);
(private_key, account_id)
})
.collect();
Self {
public_keypairs,
target_tps,
}
}
pub(crate) fn target_time(&self) -> Duration {
let number_transactions = (self.public_keypairs.len() - 1) as u64;
Duration::from_secs_f64(number_transactions as f64 / self.target_tps as f64)
}
/// Build a batch of public transactions to submit to the node.
pub fn build_public_txs(&self) -> Vec<PublicTransaction> {
// Create valid public transactions
let program = Program::authenticated_transfer_program();
let public_txs: Vec<PublicTransaction> = self
.public_keypairs
.windows(2)
.map(|pair| {
let amount: u128 = 1;
let message = putx::Message::try_new(
program.id(),
[pair[0].1, pair[1].1].to_vec(),
[0u128].to_vec(),
amount,
)
.unwrap();
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[&pair[0].0]);
PublicTransaction::new(message, witness_set)
})
.collect();
public_txs
}
/// Generates a sequencer configuration with initial balance in a number of public accounts.
/// The transactions generated with the function `build_public_txs` will be valid in a node
/// started with the config from this method.
fn generate_initial_data(&self) -> InitialData {
// Create public public keypairs
let public_accounts = self
.public_keypairs
.iter()
.map(|(key, _)| (key.clone(), 10))
.collect();
// Generate an initial commitment to be used with the privacy preserving transaction
// created with the `build_privacy_transaction` function.
let key_chain = KeyChain::new_os_random();
let account = Account {
balance: 100,
nonce: 0xdeadbeef,
program_owner: Program::authenticated_transfer_program().id(),
data: Data::default(),
};
InitialData {
public_accounts,
private_accounts: vec![(key_chain, account)],
}
}
fn generate_sequencer_partial_config() -> SequencerPartialConfig {
SequencerPartialConfig {
max_num_tx_in_block: 300,
max_block_size: ByteSize::mb(500),
mempool_max_size: 10_000,
block_create_timeout: Duration::from_secs(12),
}
}
}
/// Builds a single privacy transaction to use in stress tests. This involves generating a proof so
/// it may take a while to run. In normal execution of the node this transaction will be accepted
/// only once. Disabling the node's nullifier uniqueness check allows to submit this transaction
@@ -200,7 +216,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction {
let sender_pre = AccountWithMetadata::new(
Account {
balance: 100,
nonce: 0xdeadbeef,
nonce: 0xdead_beef,
program_owner: program.id(),
data: Data::default(),
},
@@ -234,7 +250,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction {
vec![sender_pre, recipient_pre],
Program::serialize_instruction(balance_to_move).unwrap(),
vec![1, 2],
vec![0xdeadbeef1, 0xdeadbeef2],
vec![0xdead_beef1, 0xdead_beef2],
vec![
(sender_npk.clone(), sender_ss),
(recipient_npk.clone(), recipient_ss),
+219 -226
View File
@@ -1,7 +1,19 @@
#![expect(
clippy::redundant_test_prefix,
reason = "Otherwise names interfere with ffi bindings"
)]
#![expect(
clippy::tests_outside_test_module,
clippy::undocumented_unsafe_blocks,
clippy::multiple_unsafe_ops_per_block,
clippy::shadow_unrelated,
reason = "We don't care about these in tests"
)]
use std::{
collections::HashSet,
ffi::{CStr, CString, c_char},
io::Write,
io::Write as _,
path::Path,
time::Duration,
};
@@ -152,7 +164,7 @@ unsafe extern "C" {
fn new_wallet_ffi_with_test_context_config(
ctx: &BlockingTestContext,
home: &Path,
) -> *mut WalletHandle {
) -> Result<*mut WalletHandle> {
let config_path = home.join("wallet_config.json");
let storage_path = home.join("storage.json");
let mut config = ctx.ctx().wallet().config().to_owned();
@@ -163,75 +175,68 @@ fn new_wallet_ffi_with_test_context_config(
.write(true)
.create(true)
.truncate(true)
.open(&config_path)
.unwrap();
.open(&config_path)?;
let config_with_overrides_serialized = serde_json::to_vec_pretty(&config).unwrap();
let config_with_overrides_serialized = serde_json::to_vec_pretty(&config)?;
file.write_all(&config_with_overrides_serialized).unwrap();
file.write_all(&config_with_overrides_serialized)?;
let config_path = CString::new(config_path.to_str().unwrap()).unwrap();
let storage_path = CString::new(storage_path.to_str().unwrap()).unwrap();
let password = CString::new(ctx.ctx().wallet_password()).unwrap();
let config_path = CString::new(config_path.to_str().unwrap())?;
let storage_path = CString::new(storage_path.to_str().unwrap())?;
let password = CString::new(ctx.ctx().wallet_password())?;
unsafe {
Ok(unsafe {
wallet_ffi_create_new(
config_path.as_ptr(),
storage_path.as_ptr(),
password.as_ptr(),
)
}
})
}
fn new_wallet_ffi_with_default_config(password: &str) -> *mut WalletHandle {
let tempdir = tempdir().unwrap();
fn new_wallet_ffi_with_default_config(password: &str) -> Result<*mut WalletHandle> {
let tempdir = tempdir()?;
let config_path = tempdir.path().join("wallet_config.json");
let storage_path = tempdir.path().join("storage.json");
let config_path_c = CString::new(config_path.to_str().unwrap()).unwrap();
let storage_path_c = CString::new(storage_path.to_str().unwrap()).unwrap();
let password = CString::new(password).unwrap();
let config_path_c = CString::new(config_path.to_str().unwrap())?;
let storage_path_c = CString::new(storage_path.to_str().unwrap())?;
let password = CString::new(password)?;
unsafe {
Ok(unsafe {
wallet_ffi_create_new(
config_path_c.as_ptr(),
storage_path_c.as_ptr(),
password.as_ptr(),
)
}
})
}
fn new_wallet_rust_with_default_config(password: &str) -> WalletCore {
let tempdir = tempdir().unwrap();
fn new_wallet_rust_with_default_config(password: &str) -> Result<WalletCore> {
let tempdir = tempdir()?;
let config_path = tempdir.path().join("wallet_config.json");
let storage_path = tempdir.path().join("storage.json");
WalletCore::new_init_storage(
config_path.to_path_buf(),
storage_path.to_path_buf(),
None,
password.to_string(),
)
.unwrap()
WalletCore::new_init_storage(config_path, storage_path, None, password.to_owned())
}
fn load_existing_ffi_wallet(home: &Path) -> *mut WalletHandle {
fn load_existing_ffi_wallet(home: &Path) -> Result<*mut WalletHandle> {
let config_path = home.join("wallet_config.json");
let storage_path = home.join("storage.json");
let config_path = CString::new(config_path.to_str().unwrap()).unwrap();
let storage_path = CString::new(storage_path.to_str().unwrap()).unwrap();
let config_path = CString::new(config_path.to_str().unwrap())?;
let storage_path = CString::new(storage_path.to_str().unwrap())?;
unsafe { wallet_ffi_open(config_path.as_ptr(), storage_path.as_ptr()) }
Ok(unsafe { wallet_ffi_open(config_path.as_ptr(), storage_path.as_ptr()) })
}
#[test]
fn test_wallet_ffi_create_public_accounts() {
fn wallet_ffi_create_public_accounts() -> Result<()> {
let password = "password_for_tests";
let n_accounts = 10;
// First `n_accounts` public accounts created with Rust wallet
let new_public_account_ids_rust = {
let mut account_ids = Vec::new();
let mut wallet_rust = new_wallet_rust_with_default_config(password);
let mut wallet_rust = new_wallet_rust_with_default_config(password)?;
for _ in 0..n_accounts {
let account_id = wallet_rust.create_new_account_public(None).0;
account_ids.push(*account_id.value());
@@ -243,13 +248,10 @@ fn test_wallet_ffi_create_public_accounts() {
let new_public_account_ids_ffi = unsafe {
let mut account_ids = Vec::new();
let wallet_ffi_handle = new_wallet_ffi_with_default_config(password);
let wallet_ffi_handle = new_wallet_ffi_with_default_config(password)?;
for _ in 0..n_accounts {
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
wallet_ffi_create_account_public(
wallet_ffi_handle,
(&mut out_account_id) as *mut FfiBytes32,
);
wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut out_account_id);
account_ids.push(out_account_id.data);
}
wallet_ffi_destroy(wallet_ffi_handle);
@@ -257,17 +259,19 @@ fn test_wallet_ffi_create_public_accounts() {
};
assert_eq!(new_public_account_ids_ffi, new_public_account_ids_rust);
Ok(())
}
#[test]
fn test_wallet_ffi_create_private_accounts() {
fn wallet_ffi_create_private_accounts() -> Result<()> {
let password = "password_for_tests";
let n_accounts = 10;
// First `n_accounts` private accounts created with Rust wallet
let new_private_account_ids_rust = {
let mut account_ids = Vec::new();
let mut wallet_rust = new_wallet_rust_with_default_config(password);
let mut wallet_rust = new_wallet_rust_with_default_config(password)?;
for _ in 0..n_accounts {
let account_id = wallet_rust.create_new_account_private(None).0;
account_ids.push(*account_id.value());
@@ -279,56 +283,52 @@ fn test_wallet_ffi_create_private_accounts() {
let new_private_account_ids_ffi = unsafe {
let mut account_ids = Vec::new();
let wallet_ffi_handle = new_wallet_ffi_with_default_config(password);
let wallet_ffi_handle = new_wallet_ffi_with_default_config(password)?;
for _ in 0..n_accounts {
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
wallet_ffi_create_account_private(
wallet_ffi_handle,
(&mut out_account_id) as *mut FfiBytes32,
);
wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_account_id);
account_ids.push(out_account_id.data);
}
wallet_ffi_destroy(wallet_ffi_handle);
account_ids
};
assert_eq!(new_private_account_ids_ffi, new_private_account_ids_rust)
assert_eq!(new_private_account_ids_ffi, new_private_account_ids_rust);
Ok(())
}
#[test]
fn test_wallet_ffi_save_and_load_persistent_storage() -> Result<()> {
fn wallet_ffi_save_and_load_persistent_storage() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let mut out_private_account_id = FfiBytes32::from_bytes([0; 32]);
let home = tempfile::tempdir().unwrap();
let home = tempfile::tempdir()?;
// Create a private account with the wallet FFI and save it
unsafe {
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
wallet_ffi_create_account_private(
wallet_ffi_handle,
(&mut out_private_account_id) as *mut FfiBytes32,
);
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_private_account_id);
wallet_ffi_save(wallet_ffi_handle);
wallet_ffi_destroy(wallet_ffi_handle);
}
let private_account_keys = unsafe {
let wallet_ffi_handle = load_existing_ffi_wallet(home.path());
let wallet_ffi_handle = load_existing_ffi_wallet(home.path())?;
let mut private_account = FfiAccount::default();
let result = wallet_ffi_get_account_private(
wallet_ffi_handle,
(&out_private_account_id) as *const FfiBytes32,
(&mut private_account) as *mut FfiAccount,
&raw const out_private_account_id,
&raw mut private_account,
);
assert_eq!(result, error::WalletFfiError::Success);
let mut out_keys = FfiPrivateAccountKeys::default();
let result = wallet_ffi_get_private_account_keys(
wallet_ffi_handle,
(&out_private_account_id) as *const FfiBytes32,
(&mut out_keys) as *mut FfiPrivateAccountKeys,
&raw const out_private_account_id,
&raw mut out_keys,
);
assert_eq!(result, error::WalletFfiError::Success);
@@ -346,17 +346,17 @@ fn test_wallet_ffi_save_and_load_persistent_storage() -> Result<()> {
}
#[test]
fn test_wallet_ffi_list_accounts() {
fn test_wallet_ffi_list_accounts() -> Result<()> {
let password = "password_for_tests";
// Create the wallet FFI
let wallet_ffi_handle = unsafe {
let handle = new_wallet_ffi_with_default_config(password);
let handle = new_wallet_ffi_with_default_config(password)?;
// Create 5 public accounts and 5 private accounts
for _ in 0..5 {
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
wallet_ffi_create_account_public(handle, (&mut out_account_id) as *mut FfiBytes32);
wallet_ffi_create_account_private(handle, (&mut out_account_id) as *mut FfiBytes32);
wallet_ffi_create_account_public(handle, &raw mut out_account_id);
wallet_ffi_create_account_private(handle, &raw mut out_account_id);
}
handle
@@ -364,7 +364,7 @@ fn test_wallet_ffi_list_accounts() {
// Create the wallet Rust
let wallet_rust = {
let mut wallet = new_wallet_rust_with_default_config(password);
let mut wallet = new_wallet_rust_with_default_config(password)?;
// Create 5 public accounts and 5 private accounts
for _ in 0..5 {
wallet.create_new_account_public(None);
@@ -376,7 +376,7 @@ fn test_wallet_ffi_list_accounts() {
// Get the account list with FFI method
let mut wallet_ffi_account_list = unsafe {
let mut out_list = FfiAccountList::default();
wallet_ffi_list_accounts(wallet_ffi_handle, (&mut out_list) as *mut FfiAccountList);
wallet_ffi_list_accounts(wallet_ffi_handle, &raw mut out_list);
out_list
};
@@ -400,7 +400,7 @@ fn test_wallet_ffi_list_accounts() {
assert_eq!(
wallet_rust_account_ids
.iter()
.map(|id| id.value())
.map(nssa::AccountId::value)
.collect::<HashSet<_>>(),
wallet_ffi_account_list_slice
.iter()
@@ -409,7 +409,7 @@ fn test_wallet_ffi_list_accounts() {
);
// Assert `is_pub` flag is correct in the FFI result
for entry in wallet_ffi_account_list_slice.iter() {
for entry in wallet_ffi_account_list_slice {
let account_id = AccountId::new(entry.account_id.data);
let is_pub_default_in_rust_wallet = wallet_rust
.storage()
@@ -429,27 +429,30 @@ fn test_wallet_ffi_list_accounts() {
}
unsafe {
wallet_ffi_free_account_list((&mut wallet_ffi_account_list) as *mut FfiAccountList);
wallet_ffi_free_account_list(&raw mut wallet_ffi_account_list);
wallet_ffi_destroy(wallet_ffi_handle);
}
Ok(())
}
#[test]
fn test_wallet_ffi_get_balance_public() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let home = tempfile::tempdir()?;
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
let balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let ffi_account_id = FfiBytes32::from(&account_id);
let _result = wallet_ffi_get_balance(
wallet_ffi_get_balance(
wallet_ffi_handle,
(&ffi_account_id) as *const FfiBytes32,
&raw const ffi_account_id,
true,
(&mut out_balance) as *mut [u8; 16],
);
&raw mut out_balance,
)
.unwrap();
u128::from_le_bytes(out_balance)
};
assert_eq!(balance, 10000);
@@ -467,17 +470,18 @@ fn test_wallet_ffi_get_balance_public() -> Result<()> {
fn test_wallet_ffi_get_account_public() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let home = tempfile::tempdir()?;
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
let mut out_account = FfiAccount::default();
let account: Account = unsafe {
let ffi_account_id = FfiBytes32::from(&account_id);
let _result = wallet_ffi_get_account_public(
wallet_ffi_get_account_public(
wallet_ffi_handle,
(&ffi_account_id) as *const FfiBytes32,
(&mut out_account) as *mut FfiAccount,
);
&raw const ffi_account_id,
&raw mut out_account,
)
.unwrap();
(&out_account).try_into().unwrap()
};
@@ -490,7 +494,7 @@ fn test_wallet_ffi_get_account_public() -> Result<()> {
assert_eq!(account.nonce, 0);
unsafe {
wallet_ffi_free_account_data((&mut out_account) as *mut FfiAccount);
wallet_ffi_free_account_data(&raw mut out_account);
wallet_ffi_destroy(wallet_ffi_handle);
}
@@ -503,17 +507,18 @@ fn test_wallet_ffi_get_account_public() -> Result<()> {
fn test_wallet_ffi_get_account_private() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let home = tempfile::tempdir()?;
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
let mut out_account = FfiAccount::default();
let account: Account = unsafe {
let ffi_account_id = FfiBytes32::from(&account_id);
let _result = wallet_ffi_get_account_private(
wallet_ffi_get_account_private(
wallet_ffi_handle,
(&ffi_account_id) as *const FfiBytes32,
(&mut out_account) as *mut FfiAccount,
);
&raw const ffi_account_id,
&raw mut out_account,
)
.unwrap();
(&out_account).try_into().unwrap()
};
@@ -526,7 +531,7 @@ fn test_wallet_ffi_get_account_private() -> Result<()> {
assert_eq!(account.nonce, 0);
unsafe {
wallet_ffi_free_account_data((&mut out_account) as *mut FfiAccount);
wallet_ffi_free_account_data(&raw mut out_account);
wallet_ffi_destroy(wallet_ffi_handle);
}
@@ -539,17 +544,18 @@ fn test_wallet_ffi_get_account_private() -> Result<()> {
fn test_wallet_ffi_get_public_account_keys() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let home = tempfile::tempdir()?;
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
let mut out_key = FfiPublicAccountKey::default();
let key: PublicKey = unsafe {
let ffi_account_id = FfiBytes32::from(&account_id);
let _result = wallet_ffi_get_public_account_key(
wallet_ffi_get_public_account_key(
wallet_ffi_handle,
(&ffi_account_id) as *const FfiBytes32,
(&mut out_key) as *mut FfiPublicAccountKey,
);
&raw const ffi_account_id,
&raw mut out_key,
)
.unwrap();
(&out_key).try_into().unwrap()
};
@@ -577,17 +583,18 @@ fn test_wallet_ffi_get_public_account_keys() -> Result<()> {
fn test_wallet_ffi_get_private_account_keys() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let home = tempfile::tempdir()?;
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
let mut keys = FfiPrivateAccountKeys::default();
unsafe {
let ffi_account_id = FfiBytes32::from(&account_id);
let _result = wallet_ffi_get_private_account_keys(
wallet_ffi_get_private_account_keys(
wallet_ffi_handle,
(&ffi_account_id) as *const FfiBytes32,
(&mut keys) as *mut FfiPrivateAccountKeys,
);
&raw const ffi_account_id,
&raw mut keys,
)
.unwrap();
};
let key_chain = &ctx
@@ -606,7 +613,7 @@ fn test_wallet_ffi_get_private_account_keys() -> Result<()> {
assert_eq!(&keys.vpk().unwrap(), expected_vpk);
unsafe {
wallet_ffi_free_private_account_keys((&mut keys) as *mut FfiPrivateAccountKeys);
wallet_ffi_free_private_account_keys(&raw mut keys);
wallet_ffi_destroy(wallet_ffi_handle);
}
@@ -616,66 +623,65 @@ fn test_wallet_ffi_get_private_account_keys() -> Result<()> {
}
#[test]
fn test_wallet_ffi_account_id_to_base58() {
fn test_wallet_ffi_account_id_to_base58() -> Result<()> {
let private_key = PrivateKey::new_os_random();
let public_key = PublicKey::new_from_private_key(&private_key);
let account_id = AccountId::from(&public_key);
let ffi_bytes: FfiBytes32 = (&account_id).into();
let ptr = unsafe { wallet_ffi_account_id_to_base58((&ffi_bytes) as *const FfiBytes32) };
let ptr = unsafe { wallet_ffi_account_id_to_base58(&raw const ffi_bytes) };
let ffi_result = unsafe { CStr::from_ptr(ptr).to_str().unwrap() };
let ffi_result = unsafe { CStr::from_ptr(ptr).to_str()? };
assert_eq!(account_id.to_string(), ffi_result);
unsafe {
wallet_ffi_free_string(ptr);
}
Ok(())
}
#[test]
fn test_wallet_ffi_base58_to_account_id() {
fn wallet_ffi_base58_to_account_id() -> Result<()> {
let private_key = PrivateKey::new_os_random();
let public_key = PublicKey::new_from_private_key(&private_key);
let account_id = AccountId::from(&public_key);
let account_id_str = account_id.to_string();
let account_id_c_str = CString::new(account_id_str.clone()).unwrap();
let account_id_c_str = CString::new(account_id_str.clone())?;
let account_id: AccountId = unsafe {
let mut out_account_id_bytes = FfiBytes32::default();
wallet_ffi_account_id_from_base58(
account_id_c_str.as_ptr(),
(&mut out_account_id_bytes) as *mut FfiBytes32,
);
wallet_ffi_account_id_from_base58(account_id_c_str.as_ptr(), &raw mut out_account_id_bytes);
out_account_id_bytes.into()
};
let expected_account_id = account_id_str.parse().unwrap();
let expected_account_id = account_id_str.parse()?;
assert_eq!(account_id, expected_account_id);
Ok(())
}
#[test]
fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let home = tempfile::tempdir()?;
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
// Create a new uninitialized public account
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
unsafe {
wallet_ffi_create_account_public(
wallet_ffi_handle,
(&mut out_account_id) as *mut FfiBytes32,
);
wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut out_account_id);
}
// Check its program owner is the default program id
let account: Account = unsafe {
let mut out_account = FfiAccount::default();
let _result = wallet_ffi_get_account_public(
wallet_ffi_get_account_public(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut out_account) as *mut FfiAccount,
);
&raw const out_account_id,
&raw mut out_account,
)
.unwrap();
(&out_account).try_into().unwrap()
};
assert_eq!(account.program_owner, DEFAULT_PROGRAM_ID);
@@ -685,8 +691,8 @@ fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
unsafe {
wallet_ffi_register_public_account(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut transfer_result) as *mut FfiTransferResult,
&raw const out_account_id,
&raw mut transfer_result,
);
}
@@ -696,11 +702,12 @@ fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
// Check that the program owner is now the authenticated transfer program
let account: Account = unsafe {
let mut out_account = FfiAccount::default();
let _result = wallet_ffi_get_account_public(
wallet_ffi_get_account_public(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut out_account) as *mut FfiAccount,
);
&raw const out_account_id,
&raw mut out_account,
)
.unwrap();
(&out_account).try_into().unwrap()
};
assert_eq!(
@@ -709,7 +716,7 @@ fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
);
unsafe {
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
wallet_ffi_free_transfer_result(&raw mut transfer_result);
wallet_ffi_destroy(wallet_ffi_handle);
}
@@ -717,18 +724,15 @@ fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
}
#[test]
fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let home = tempfile::tempdir()?;
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?;
// Create a new uninitialized public account
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
unsafe {
wallet_ffi_create_account_private(
wallet_ffi_handle,
(&mut out_account_id) as *mut FfiBytes32,
);
wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_account_id);
}
// Check its program owner is the default program id
@@ -736,8 +740,8 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
let mut out_account = FfiAccount::default();
wallet_ffi_get_account_private(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut out_account) as *mut FfiAccount,
&raw const out_account_id,
&raw mut out_account,
);
(&out_account).try_into().unwrap()
};
@@ -748,8 +752,8 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
unsafe {
wallet_ffi_register_private_account(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut transfer_result) as *mut FfiTransferResult,
&raw const out_account_id,
&raw mut transfer_result,
);
}
@@ -759,18 +763,19 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
// Sync private account local storage with onchain encrypted state
unsafe {
let mut current_height = 0;
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height);
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height);
};
// Check that the program owner is now the authenticated transfer program
let account: Account = unsafe {
let mut out_account = FfiAccount::default();
let _result = wallet_ffi_get_account_private(
wallet_ffi_get_account_private(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut out_account) as *mut FfiAccount,
);
&raw const out_account_id,
&raw mut out_account,
)
.unwrap();
(&out_account).try_into().unwrap()
};
assert_eq!(
@@ -779,7 +784,7 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
);
unsafe {
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
wallet_ffi_free_transfer_result(&raw mut transfer_result);
wallet_ffi_destroy(wallet_ffi_handle);
}
@@ -788,21 +793,21 @@ fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
#[test]
fn test_wallet_ffi_transfer_public() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
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: [u8; 16] = 100u128.to_le_bytes();
let amount: [u8; 16] = 100_u128.to_le_bytes();
let mut transfer_result = FfiTransferResult::default();
unsafe {
wallet_ffi_transfer_public(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
(&to) as *const FfiBytes32,
(&amount) as *const [u8; 16],
(&mut transfer_result) as *mut FfiTransferResult,
&raw const from,
&raw const to,
&raw const amount,
&raw mut transfer_result,
);
}
@@ -811,23 +816,20 @@ fn test_wallet_ffi_transfer_public() -> Result<()> {
let from_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_get_balance(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
&raw const from,
true,
(&mut out_balance) as *mut [u8; 16],
);
&raw mut out_balance,
)
.unwrap();
u128::from_le_bytes(out_balance)
};
let to_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&to) as *const FfiBytes32,
true,
(&mut out_balance) as *mut [u8; 16],
);
wallet_ffi_get_balance(wallet_ffi_handle, &raw const to, true, &raw mut out_balance)
.unwrap();
u128::from_le_bytes(out_balance)
};
@@ -835,7 +837,7 @@ fn test_wallet_ffi_transfer_public() -> Result<()> {
assert_eq!(to_balance, 20100);
unsafe {
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
wallet_ffi_free_transfer_result(&raw mut transfer_result);
wallet_ffi_destroy(wallet_ffi_handle);
}
@@ -844,34 +846,31 @@ fn test_wallet_ffi_transfer_public() -> Result<()> {
#[test]
fn test_wallet_ffi_transfer_shielded() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
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, to_keys) = unsafe {
let mut out_account_id = FfiBytes32::default();
let mut out_keys = FfiPrivateAccountKeys::default();
wallet_ffi_create_account_private(
wallet_ffi_handle,
(&mut out_account_id) as *mut FfiBytes32,
);
wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_account_id);
wallet_ffi_get_private_account_keys(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut out_keys) as *mut FfiPrivateAccountKeys,
&raw const out_account_id,
&raw mut out_keys,
);
(out_account_id, out_keys)
};
let amount: [u8; 16] = 100u128.to_le_bytes();
let amount: [u8; 16] = 100_u128.to_le_bytes();
let mut transfer_result = FfiTransferResult::default();
unsafe {
wallet_ffi_transfer_shielded(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
(&to_keys) as *const FfiPrivateAccountKeys,
(&amount) as *const [u8; 16],
(&mut transfer_result) as *mut FfiTransferResult,
&raw const from,
&raw const to_keys,
&raw const amount,
&raw mut transfer_result,
);
}
@@ -881,18 +880,19 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> {
// Sync private account local storage with onchain encrypted state
unsafe {
let mut current_height = 0;
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height);
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height);
};
let from_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_get_balance(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
&raw const from,
true,
(&mut out_balance) as *mut [u8; 16],
);
&raw mut out_balance,
)
.unwrap();
u128::from_le_bytes(out_balance)
};
@@ -900,9 +900,9 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&to) as *const FfiBytes32,
&raw const to,
false,
(&mut out_balance) as *mut [u8; 16],
&raw mut out_balance,
);
u128::from_le_bytes(out_balance)
};
@@ -911,7 +911,7 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> {
assert_eq!(to_balance, 100);
unsafe {
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
wallet_ffi_free_transfer_result(&raw mut transfer_result);
wallet_ffi_destroy(wallet_ffi_handle);
}
@@ -920,21 +920,21 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> {
#[test]
fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
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_private_accounts()[0]).into();
let to = FfiBytes32::from_bytes([37; 32]);
let amount: [u8; 16] = 100u128.to_le_bytes();
let amount: [u8; 16] = 100_u128.to_le_bytes();
let mut transfer_result = FfiTransferResult::default();
unsafe {
wallet_ffi_transfer_deshielded(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
(&to) as *const FfiBytes32,
(&amount) as *const [u8; 16],
(&mut transfer_result) as *mut FfiTransferResult,
&raw const from,
&raw const to,
&raw const amount,
&raw mut transfer_result,
);
}
@@ -944,7 +944,7 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
// Sync private account local storage with onchain encrypted state
unsafe {
let mut current_height = 0;
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height);
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height);
};
@@ -952,21 +952,17 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
&raw const from,
false,
(&mut out_balance) as *mut [u8; 16],
&raw mut out_balance,
);
u128::from_le_bytes(out_balance)
};
let to_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&to) as *const FfiBytes32,
true,
(&mut out_balance) as *mut [u8; 16],
);
let _result =
wallet_ffi_get_balance(wallet_ffi_handle, &raw const to, true, &raw mut out_balance);
u128::from_le_bytes(out_balance)
};
@@ -974,7 +970,7 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
assert_eq!(to_balance, 100);
unsafe {
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
wallet_ffi_free_transfer_result(&raw mut transfer_result);
wallet_ffi_destroy(wallet_ffi_handle);
}
@@ -983,36 +979,33 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
#[test]
fn test_wallet_ffi_transfer_private() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
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_private_accounts()[0]).into();
let (to, to_keys) = unsafe {
let mut out_account_id = FfiBytes32::default();
let mut out_keys = FfiPrivateAccountKeys::default();
wallet_ffi_create_account_private(
wallet_ffi_handle,
(&mut out_account_id) as *mut FfiBytes32,
);
wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_account_id);
wallet_ffi_get_private_account_keys(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut out_keys) as *mut FfiPrivateAccountKeys,
&raw const out_account_id,
&raw mut out_keys,
);
(out_account_id, out_keys)
};
let amount: [u8; 16] = 100u128.to_le_bytes();
let amount: [u8; 16] = 100_u128.to_le_bytes();
let mut transfer_result = FfiTransferResult::default();
unsafe {
wallet_ffi_transfer_private(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
(&to_keys) as *const FfiPrivateAccountKeys,
(&amount) as *const [u8; 16],
(&mut transfer_result) as *mut FfiTransferResult,
&raw const from,
&raw const to_keys,
&raw const amount,
&raw mut transfer_result,
);
}
@@ -1022,7 +1015,7 @@ fn test_wallet_ffi_transfer_private() -> Result<()> {
// Sync private account local storage with onchain encrypted state
unsafe {
let mut current_height = 0;
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height);
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height);
};
@@ -1030,9 +1023,9 @@ fn test_wallet_ffi_transfer_private() -> Result<()> {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
&raw const from,
false,
(&mut out_balance) as *mut [u8; 16],
&raw mut out_balance,
);
u128::from_le_bytes(out_balance)
};
@@ -1041,9 +1034,9 @@ fn test_wallet_ffi_transfer_private() -> Result<()> {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&to) as *const FfiBytes32,
&raw const to,
false,
(&mut out_balance) as *mut [u8; 16],
&raw mut out_balance,
);
u128::from_le_bytes(out_balance)
};
@@ -1052,7 +1045,7 @@ fn test_wallet_ffi_transfer_private() -> Result<()> {
assert_eq!(to_balance, 100);
unsafe {
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
wallet_ffi_free_transfer_result(&raw mut transfer_result);
wallet_ffi_destroy(wallet_ffi_handle);
}