#[cfg(test)]
mod uploader_tests {
use super::super::tn_tools::{KeyPair, Pubkey};
use super::super::txn_tools::*;
#[test]
fn test_uploader_create_transaction() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let uploader_program = Pubkey::from_bytes(&[1u8; 32]);
let meta_account = Pubkey::from_bytes(&[2u8; 32]);
let buffer_account = Pubkey::from_bytes(&[3u8; 32]);
let program_hash = [0u8; 32]; let seed = "test_seed";
let create_tx = TransactionBuilder::build_uploader_create(
fee_payer.public_key,
uploader_program.to_bytes().unwrap(),
meta_account.to_bytes().unwrap(),
buffer_account.to_bytes().unwrap(),
1024, program_hash,
seed.as_bytes(),
1000, 1, 100, )
.unwrap();
assert!(
create_tx.instructions.is_some(),
"CREATE transaction should have instructions"
);
let instructions = create_tx.instructions.as_ref().unwrap();
assert_eq!(
&instructions[0..4],
&TN_UPLOADER_PROGRAM_INSTRUCTION_CREATE.to_le_bytes()
);
assert_eq!(
create_tx.rw_accs.as_ref().unwrap().len(),
2,
"CREATE transaction should have 2 additional accounts"
);
}
#[test]
fn test_uploader_write_transaction() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let uploader_program = Pubkey::from_bytes(&[1u8; 32]);
let meta_account = Pubkey::from_bytes(&[2u8; 32]);
let buffer_account = Pubkey::from_bytes(&[3u8; 32]);
let test_data = b"Hello, Thru blockchain!";
let write_tx = TransactionBuilder::build_uploader_write(
fee_payer.public_key,
uploader_program.to_bytes().unwrap(),
meta_account.to_bytes().unwrap(),
buffer_account.to_bytes().unwrap(),
test_data,
0, 1000, 2, 100, )
.unwrap();
assert!(
write_tx.instructions.is_some(),
"WRITE transaction should have instructions"
);
let instructions = write_tx.instructions.as_ref().unwrap();
assert_eq!(
&instructions[0..4],
&TN_UPLOADER_PROGRAM_INSTRUCTION_WRITE.to_le_bytes()
);
assert!(
instructions.len() >= test_data.len(),
"WRITE instruction should contain test data"
);
assert_eq!(
write_tx.rw_accs.as_ref().unwrap().len(),
2,
"WRITE transaction should have 2 additional accounts"
);
}
#[test]
fn test_uploader_write_rejects_elf_magic_at_start() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let uploader_program = Pubkey::from_bytes(&[1u8; 32]);
let meta_account = Pubkey::from_bytes(&[2u8; 32]);
let buffer_account = Pubkey::from_bytes(&[3u8; 32]);
let err = match TransactionBuilder::build_uploader_write(
fee_payer.public_key,
uploader_program.to_bytes().unwrap(),
meta_account.to_bytes().unwrap(),
buffer_account.to_bytes().unwrap(),
&[0x7f, b'E', b'L', b'F', 0x02],
0, 1000, 2, 100, ) {
Ok(_) => panic!("WRITE transaction should reject ELF input at offset 0"),
Err(err) => err,
};
assert!(
err.to_string().contains("ELF magic"),
"WRITE transaction should reject ELF input at offset 0"
);
}
#[test]
fn test_uploader_write_can_skip_elf_magic_check() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let uploader_program = Pubkey::from_bytes(&[1u8; 32]);
let meta_account = Pubkey::from_bytes(&[2u8; 32]);
let buffer_account = Pubkey::from_bytes(&[3u8; 32]);
let write_tx = TransactionBuilder::build_uploader_write_with_options(
fee_payer.public_key,
uploader_program.to_bytes().unwrap(),
meta_account.to_bytes().unwrap(),
buffer_account.to_bytes().unwrap(),
&[0x7f, 0x45, 0x4c, 0x46, 0x02],
0,
1000,
2,
100,
UploaderWriteOptions {
skip_elf_check: true,
},
)
.unwrap();
assert!(
write_tx.instructions.is_some(),
"WRITE transaction should allow ELF bytes when skip_elf_check is set"
);
}
#[test]
fn test_uploader_write_allows_elf_magic_after_start() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let uploader_program = Pubkey::from_bytes(&[1u8; 32]);
let meta_account = Pubkey::from_bytes(&[2u8; 32]);
let buffer_account = Pubkey::from_bytes(&[3u8; 32]);
let write_tx = TransactionBuilder::build_uploader_write(
fee_payer.public_key,
uploader_program.to_bytes().unwrap(),
meta_account.to_bytes().unwrap(),
buffer_account.to_bytes().unwrap(),
&[0x7f, b'E', b'L', b'F', 0x02],
4, 1000, 2, 100, )
.unwrap();
assert!(
write_tx.instructions.is_some(),
"WRITE transaction should allow ELF bytes after offset 0"
);
}
#[test]
fn test_uploader_finalize_transaction() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let uploader_program = Pubkey::from_bytes(&[1u8; 32]);
let meta_account = Pubkey::from_bytes(&[2u8; 32]);
let buffer_account = Pubkey::from_bytes(&[3u8; 32]);
let program_hash = [0u8; 32];
let finalize_tx = TransactionBuilder::build_uploader_finalize(
fee_payer.public_key,
uploader_program.to_bytes().unwrap(),
meta_account.to_bytes().unwrap(),
buffer_account.to_bytes().unwrap(),
1024,
program_hash,
1000, 3, 100, )
.unwrap();
assert!(
finalize_tx.instructions.is_some(),
"FINALIZE transaction should have instructions"
);
let instructions = finalize_tx.instructions.as_ref().unwrap();
assert_eq!(
&instructions[0..4],
&TN_UPLOADER_PROGRAM_INSTRUCTION_FINALIZE.to_le_bytes()
);
assert_eq!(
finalize_tx.rw_accs.as_ref().unwrap().len(),
2,
"FINALIZE transaction should have 2 additional accounts"
);
}
#[test]
fn test_uploader_destroy_transaction() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let uploader_program = Pubkey::from_bytes(&[1u8; 32]);
let meta_account = Pubkey::from_bytes(&[2u8; 32]);
let buffer_account = Pubkey::from_bytes(&[3u8; 32]);
let destroy_tx = TransactionBuilder::build_uploader_destroy(
fee_payer.public_key,
uploader_program.to_bytes().unwrap(),
meta_account.to_bytes().unwrap(),
buffer_account.to_bytes().unwrap(),
1000, 4, 100, )
.unwrap();
assert!(
destroy_tx.instructions.is_some(),
"DESTROY transaction should have instructions"
);
let instructions = destroy_tx.instructions.as_ref().unwrap();
assert_eq!(
&instructions[0..4],
&TN_UPLOADER_PROGRAM_INSTRUCTION_DESTROY.to_le_bytes()
);
assert_eq!(
destroy_tx.rw_accs.as_ref().unwrap().len(),
2,
"DESTROY transaction should have 2 additional accounts"
);
}
#[test]
fn test_uploader_instruction_discriminants() {
assert_eq!(TN_UPLOADER_PROGRAM_INSTRUCTION_CREATE, 0x00);
assert_eq!(TN_UPLOADER_PROGRAM_INSTRUCTION_WRITE, 0x01);
assert_eq!(TN_UPLOADER_PROGRAM_INSTRUCTION_DESTROY, 0x02);
assert_eq!(TN_UPLOADER_PROGRAM_INSTRUCTION_FINALIZE, 0x03);
}
}
#[cfg(test)]
mod test_uploader_tests {
use super::super::tn_tools::{KeyPair, Pubkey};
use super::super::txn_tools::*;
#[test]
fn test_test_uploader_create_ephemeral_transaction() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let test_uploader_program = Pubkey::from_bytes(&[1u8; 32]);
let target_account = Pubkey::from_bytes(&[2u8; 32]);
let seed = b"test_seed_123";
let create_tx = TransactionBuilder::build_test_uploader_create(
fee_payer.public_key,
test_uploader_program.to_bytes().unwrap(),
target_account.to_bytes().unwrap(),
1024, seed,
true, None, 1000, 1, 100, )
.unwrap();
assert!(
create_tx.instructions.is_some(),
"CREATE transaction should have instructions"
);
let instructions = create_tx.instructions.as_ref().unwrap();
assert_eq!(
instructions[0],
TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_CREATE
);
assert_eq!(
create_tx.rw_accs.as_ref().unwrap().len(),
1,
"CREATE transaction should have 1 additional account"
);
}
#[test]
fn test_test_uploader_create_with_proof_transaction() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let test_uploader_program = Pubkey::from_bytes(&[1u8; 32]);
let target_account = Pubkey::from_bytes(&[2u8; 32]);
let seed = b"test_seed_123";
let state_proof = b"dummy_state_proof_data";
let create_tx = TransactionBuilder::build_test_uploader_create(
fee_payer.public_key,
test_uploader_program.to_bytes().unwrap(),
target_account.to_bytes().unwrap(),
2048, seed,
false, Some(state_proof), 1000, 1, 100, )
.unwrap();
assert!(
create_tx.instructions.is_some(),
"CREATE transaction should have instructions"
);
let instructions = create_tx.instructions.as_ref().unwrap();
assert_eq!(
instructions[0],
TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_CREATE
);
assert!(
instructions.len() >= state_proof.len(),
"CREATE instruction should contain state proof"
);
}
#[test]
fn test_test_uploader_write_transaction() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let test_uploader_program = Pubkey::from_bytes(&[1u8; 32]);
let target_account = Pubkey::from_bytes(&[2u8; 32]);
let test_data = b"Hello, test uploader program!";
let offset = 42u32;
let write_tx = TransactionBuilder::build_test_uploader_write(
fee_payer.public_key,
test_uploader_program.to_bytes().unwrap(),
target_account.to_bytes().unwrap(),
offset,
test_data,
1000, 2, 100, )
.unwrap();
assert!(
write_tx.instructions.is_some(),
"WRITE transaction should have instructions"
);
let instructions = write_tx.instructions.as_ref().unwrap();
assert_eq!(instructions[0], TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_WRITE);
assert!(
instructions.len() >= test_data.len(),
"WRITE instruction should contain test data"
);
assert_eq!(
write_tx.rw_accs.as_ref().unwrap().len(),
1,
"WRITE transaction should have 1 additional account"
);
}
#[test]
fn test_test_uploader_discriminants() {
assert_eq!(TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_CREATE, 0x00);
assert_eq!(TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_WRITE, 0x01);
}
}
#[cfg(test)]
mod system_program_tests {
use super::super::tn_tools::{KeyPair, Pubkey};
use super::super::txn_tools::*;
#[test]
fn test_decompress2_account_transaction() {
let private_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let fee_payer = KeyPair::from_hex_private_key("test", private_key_hex).unwrap();
let system_program = Pubkey::from_bytes(&[0u8; 32]);
let target_account = Pubkey::from_bytes(&[1u8; 32]);
let meta_account = Pubkey::from_bytes(&[2u8; 32]);
let data_account = Pubkey::from_bytes(&[3u8; 32]);
let data_offset = 64u32;
let state_proof = b"dummy_state_proof_for_decompress2";
let decompress2_tx = TransactionBuilder::build_decompress2(
fee_payer.public_key,
system_program.to_bytes().unwrap(),
target_account.to_bytes().unwrap(),
meta_account.to_bytes().unwrap(),
data_account.to_bytes().unwrap(),
data_offset,
state_proof,
1000, 1, 100, 1024,
)
.unwrap();
assert!(
decompress2_tx.instructions.is_some(),
"DECOMPRESS2 transaction should have instructions"
);
let instructions = decompress2_tx.instructions.as_ref().unwrap();
assert_eq!(
instructions[0], 0x08,
"First byte should be DECOMPRESS2 discriminant"
);
assert!(
instructions.len() >= state_proof.len(),
"DECOMPRESS2 instruction should contain state proof"
);
assert_eq!(
decompress2_tx.rw_accs.as_ref().unwrap().len(),
1,
"DECOMPRESS2 transaction should have 1 RW account"
);
assert_eq!(
decompress2_tx.r_accs.as_ref().unwrap().len(),
2,
"DECOMPRESS2 transaction should have 2 R accounts"
);
}
#[test]
fn test_decompress2_instruction_format() {
let target_account_idx = 2u16;
let meta_account_idx = 3u16;
let data_account_idx = 4u16;
let data_offset = 128u32;
let state_proof = b"test_proof_data";
let instruction = build_decompress2_instruction(
target_account_idx,
meta_account_idx,
data_account_idx,
data_offset,
state_proof,
)
.unwrap();
assert_eq!(instruction[0], 0x08);
let expected_min_size =
1 + std::mem::size_of::<SystemProgramDecompress2Args>() + state_proof.len();
assert_eq!(instruction.len(), expected_min_size);
let proof_start = instruction.len() - state_proof.len();
assert_eq!(&instruction[proof_start..], state_proof);
}
}