lssa/nssa/src/program.rs

522 lines
16 KiB
Rust
Raw Normal View History

2026-01-27 01:20:17 -03:00
use borsh::{BorshDeserialize, BorshSerialize};
2025-08-09 20:25:58 -03:00
use nssa_core::{
2025-10-29 15:34:11 -03:00
account::AccountWithMetadata,
2025-08-27 16:24:20 -03:00
program::{InstructionData, ProgramId, ProgramOutput},
2025-08-09 20:25:58 -03:00
};
2025-08-27 18:23:56 -03:00
use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec};
2025-08-10 18:59:29 -03:00
use serde::Serialize;
2025-08-09 20:25:58 -03:00
2025-11-26 00:27:20 +03:00
use crate::{
error::NssaError,
program_methods::{
AMM_ELF, AMM_ID, ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID,
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, CLOCK_ELF, CLOCK_ID, PINATA_ELF,
PINATA_ID, TOKEN_ELF, TOKEN_ID,
},
2025-11-26 00:27:20 +03:00
};
2025-08-09 20:25:58 -03:00
/// Maximum number of cycles for a public execution.
2026-03-10 00:17:43 +03:00
/// TODO: Make this variable when fees are implemented.
const MAX_NUM_CYCLES_PUBLIC_EXECUTION: u64 = 1024 * 1024 * 32; // 32M cycles
2026-01-27 01:20:17 -03:00
#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
2025-08-09 20:25:58 -03:00
pub struct Program {
2025-08-13 01:33:11 -03:00
id: ProgramId,
elf: Vec<u8>,
2025-08-09 20:25:58 -03:00
}
impl Program {
pub fn new(bytecode: Vec<u8>) -> Result<Self, NssaError> {
let binary = risc0_binfmt::ProgramBinary::decode(&bytecode)
2026-03-04 18:42:33 +03:00
.map_err(NssaError::InvalidProgramBytecode)?;
let id = binary
.compute_image_id()
2026-03-04 18:42:33 +03:00
.map_err(NssaError::InvalidProgramBytecode)?
.into();
Ok(Self { elf: bytecode, id })
}
2026-03-03 23:21:08 +03:00
#[must_use]
2026-03-09 18:27:56 +03:00
pub const fn id(&self) -> ProgramId {
2025-08-09 20:25:58 -03:00
self.id
}
2025-08-09 20:35:44 -03:00
2026-03-03 23:21:08 +03:00
#[must_use]
pub fn elf(&self) -> &[u8] {
&self.elf
2025-08-18 19:57:21 -03:00
}
2025-08-10 19:53:05 -03:00
pub fn serialize_instruction<T: Serialize>(
2025-08-11 12:07:30 -03:00
instruction: T,
2025-08-10 18:51:55 -03:00
) -> Result<InstructionData, NssaError> {
2025-08-11 19:14:12 -03:00
to_vec(&instruction).map_err(|e| NssaError::InstructionSerializationError(e.to_string()))
2025-08-10 18:51:55 -03:00
}
2025-08-09 20:25:58 -03:00
pub(crate) fn execute(
&self,
caller_program_id: Option<ProgramId>,
2025-08-09 20:25:58 -03:00
pre_states: &[AccountWithMetadata],
2025-08-10 18:51:55 -03:00
instruction_data: &InstructionData,
) -> Result<ProgramOutput, NssaError> {
2025-08-09 20:25:58 -03:00
// Write inputs to the program
let mut env_builder = ExecutorEnv::builder();
env_builder.session_limit(Some(MAX_NUM_CYCLES_PUBLIC_EXECUTION));
Self::write_inputs(
self.id,
caller_program_id,
pre_states,
instruction_data,
&mut env_builder,
)?;
2025-08-09 20:25:58 -03:00
let env = env_builder.build().unwrap();
// Execute the program (without proving)
let executor = default_executor();
let session_info = executor
.execute(env, self.elf())
2025-08-09 20:25:58 -03:00
.map_err(|e| NssaError::ProgramExecutionFailed(e.to_string()))?;
// Get outputs
let program_output = session_info
2025-08-09 20:25:58 -03:00
.journal
.decode()
.map_err(|e| NssaError::ProgramExecutionFailed(e.to_string()))?;
Ok(program_output)
2025-08-14 13:28:23 -03:00
}
2026-03-10 00:17:43 +03:00
/// Writes inputs to `env_builder` in the order expected by the programs.
2025-08-18 19:57:21 -03:00
pub(crate) fn write_inputs(
program_id: ProgramId,
caller_program_id: Option<ProgramId>,
2025-08-09 20:25:58 -03:00
pre_states: &[AccountWithMetadata],
2025-08-10 18:51:55 -03:00
instruction_data: &[u32],
2025-08-09 20:25:58 -03:00
env_builder: &mut ExecutorEnvBuilder,
) -> Result<(), NssaError> {
env_builder
.write(&program_id)
.map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?;
env_builder
.write(&caller_program_id)
.map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?;
2025-08-09 20:25:58 -03:00
let pre_states = pre_states.to_vec();
env_builder
.write(&pre_states)
.map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?;
env_builder
.write(&instruction_data)
2025-08-14 13:28:23 -03:00
.map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?;
2025-08-09 20:25:58 -03:00
Ok(())
}
2025-08-10 00:53:53 -03:00
2026-03-03 23:21:08 +03:00
#[must_use]
2025-08-10 00:53:53 -03:00
pub fn authenticated_transfer_program() -> Self {
Self {
id: AUTHENTICATED_TRANSFER_ID,
elf: AUTHENTICATED_TRANSFER_ELF.to_vec(),
}
2025-08-10 00:53:53 -03:00
}
2025-09-12 15:18:25 -03:00
2026-03-03 23:21:08 +03:00
#[must_use]
2025-09-12 15:18:25 -03:00
pub fn token() -> Self {
Self {
id: TOKEN_ID,
elf: TOKEN_ELF.to_vec(),
}
2025-09-12 15:18:25 -03:00
}
2025-11-14 20:59:42 -05:00
2026-03-03 23:21:08 +03:00
#[must_use]
2025-11-14 20:59:42 -05:00
pub fn amm() -> Self {
Self {
id: AMM_ID,
elf: AMM_ELF.to_vec(),
}
2025-11-14 20:59:42 -05:00
}
#[must_use]
pub fn clock() -> Self {
Self {
id: CLOCK_ID,
elf: CLOCK_ELF.to_vec(),
}
}
#[must_use]
pub fn ata() -> Self {
Self {
id: ASSOCIATED_TOKEN_ACCOUNT_ID,
elf: ASSOCIATED_TOKEN_ACCOUNT_ELF.to_vec(),
}
}
2025-08-10 00:53:53 -03:00
}
2025-08-13 01:33:11 -03:00
2025-09-05 23:45:44 -03:00
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
2025-09-04 17:05:12 -03:00
impl Program {
2026-03-03 23:21:08 +03:00
#[must_use]
2025-09-04 12:44:22 -03:00
pub fn pinata() -> Self {
Self {
id: PINATA_ID,
elf: PINATA_ELF.to_vec(),
}
2025-09-04 12:44:22 -03:00
}
2025-11-28 11:10:00 -03:00
2026-03-03 23:21:08 +03:00
#[must_use]
2025-11-28 11:10:00 -03:00
pub fn pinata_token() -> Self {
use crate::program_methods::{PINATA_TOKEN_ELF, PINATA_TOKEN_ID};
Self {
id: PINATA_TOKEN_ID,
elf: PINATA_TOKEN_ELF.to_vec(),
}
2025-11-28 11:10:00 -03:00
}
2025-08-10 00:53:53 -03:00
}
2025-08-13 01:33:11 -03:00
#[cfg(test)]
mod tests {
2025-10-29 15:34:11 -03:00
use nssa_core::account::{Account, AccountId, AccountWithMetadata};
2025-08-13 01:33:11 -03:00
2025-11-26 00:27:20 +03:00
use crate::{
program::Program,
program_methods::{
2026-04-07 17:25:47 -03:00
AMM_ELF, AMM_ID, ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID,
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, CLOCK_ELF, CLOCK_ID, PINATA_ELF,
PINATA_ID, PINATA_TOKEN_ELF, PINATA_TOKEN_ID, TOKEN_ELF, TOKEN_ID,
2025-11-26 00:27:20 +03:00
},
};
2025-08-13 01:33:11 -03:00
impl Program {
2026-03-10 00:17:43 +03:00
/// A program that changes the nonce of an account.
2026-03-03 23:21:08 +03:00
#[must_use]
2025-08-13 01:33:11 -03:00
pub fn nonce_changer_program() -> Self {
use test_program_methods::{NONCE_CHANGER_ELF, NONCE_CHANGER_ID};
2026-03-09 18:27:56 +03:00
Self {
2025-08-13 01:33:11 -03:00
id: NONCE_CHANGER_ID,
elf: NONCE_CHANGER_ELF.to_vec(),
2025-08-13 01:33:11 -03:00
}
}
2026-03-10 00:17:43 +03:00
/// A program that produces more output accounts than the inputs it received.
2026-03-03 23:21:08 +03:00
#[must_use]
2025-08-13 01:33:11 -03:00
pub fn extra_output_program() -> Self {
use test_program_methods::{EXTRA_OUTPUT_ELF, EXTRA_OUTPUT_ID};
2026-03-09 18:27:56 +03:00
Self {
2025-08-13 01:33:11 -03:00
id: EXTRA_OUTPUT_ID,
elf: EXTRA_OUTPUT_ELF.to_vec(),
2025-08-13 01:33:11 -03:00
}
}
2026-03-10 00:17:43 +03:00
/// A program that produces less output accounts than the inputs it received.
2026-03-03 23:21:08 +03:00
#[must_use]
2025-08-13 01:33:11 -03:00
pub fn missing_output_program() -> Self {
use test_program_methods::{MISSING_OUTPUT_ELF, MISSING_OUTPUT_ID};
2026-03-09 18:27:56 +03:00
Self {
2025-08-13 01:33:11 -03:00
id: MISSING_OUTPUT_ID,
elf: MISSING_OUTPUT_ELF.to_vec(),
2025-08-13 01:33:11 -03:00
}
}
2026-03-10 00:17:43 +03:00
/// A program that changes the program owner of an account to [0, 1, 2, 3, 4, 5, 6, 7].
2026-03-03 23:21:08 +03:00
#[must_use]
2025-08-13 01:33:11 -03:00
pub fn program_owner_changer() -> Self {
use test_program_methods::{PROGRAM_OWNER_CHANGER_ELF, PROGRAM_OWNER_CHANGER_ID};
2026-03-09 18:27:56 +03:00
Self {
2025-08-13 01:33:11 -03:00
id: PROGRAM_OWNER_CHANGER_ID,
elf: PROGRAM_OWNER_CHANGER_ELF.to_vec(),
2025-08-13 01:33:11 -03:00
}
}
2026-03-10 00:17:43 +03:00
/// A program that transfers balance without caring about authorizations.
2026-03-03 23:21:08 +03:00
#[must_use]
2025-08-13 01:33:11 -03:00
pub fn simple_balance_transfer() -> Self {
use test_program_methods::{SIMPLE_BALANCE_TRANSFER_ELF, SIMPLE_BALANCE_TRANSFER_ID};
2026-03-09 18:27:56 +03:00
Self {
2025-08-13 01:33:11 -03:00
id: SIMPLE_BALANCE_TRANSFER_ID,
elf: SIMPLE_BALANCE_TRANSFER_ELF.to_vec(),
2025-08-13 01:33:11 -03:00
}
}
2026-03-10 00:17:43 +03:00
/// A program that modifies the data of an account.
2026-03-03 23:21:08 +03:00
#[must_use]
2025-08-13 01:33:11 -03:00
pub fn data_changer() -> Self {
use test_program_methods::{DATA_CHANGER_ELF, DATA_CHANGER_ID};
2026-03-09 18:27:56 +03:00
Self {
2025-08-13 01:33:11 -03:00
id: DATA_CHANGER_ID,
elf: DATA_CHANGER_ELF.to_vec(),
2025-08-13 01:33:11 -03:00
}
}
2026-03-10 00:17:43 +03:00
/// A program that mints balance.
2026-03-03 23:21:08 +03:00
#[must_use]
2025-08-13 01:33:11 -03:00
pub fn minter() -> Self {
use test_program_methods::{MINTER_ELF, MINTER_ID};
2026-03-09 18:27:56 +03:00
Self {
2025-08-13 01:33:11 -03:00
id: MINTER_ID,
elf: MINTER_ELF.to_vec(),
2025-08-13 01:33:11 -03:00
}
}
2026-03-10 00:17:43 +03:00
/// A program that burns balance.
2026-03-03 23:21:08 +03:00
#[must_use]
2025-08-13 01:33:11 -03:00
pub fn burner() -> Self {
use test_program_methods::{BURNER_ELF, BURNER_ID};
2026-03-09 18:27:56 +03:00
Self {
2025-08-13 01:33:11 -03:00
id: BURNER_ID,
elf: BURNER_ELF.to_vec(),
2025-08-13 01:33:11 -03:00
}
}
2025-10-29 15:34:11 -03:00
2026-03-03 23:21:08 +03:00
#[must_use]
2025-10-29 15:34:11 -03:00
pub fn chain_caller() -> Self {
use test_program_methods::{CHAIN_CALLER_ELF, CHAIN_CALLER_ID};
2026-03-09 18:27:56 +03:00
Self {
2025-10-29 15:34:11 -03:00
id: CHAIN_CALLER_ID,
elf: CHAIN_CALLER_ELF.to_vec(),
}
}
2026-03-03 23:21:08 +03:00
#[must_use]
pub fn claimer() -> Self {
use test_program_methods::{CLAIMER_ELF, CLAIMER_ID};
2026-03-09 18:27:56 +03:00
Self {
id: CLAIMER_ID,
elf: CLAIMER_ELF.to_vec(),
}
}
#[must_use]
pub fn pda_claimer() -> Self {
use test_program_methods::{PDA_CLAIMER_ELF, PDA_CLAIMER_ID};
Self {
id: PDA_CLAIMER_ID,
elf: PDA_CLAIMER_ELF.to_vec(),
}
}
#[must_use]
pub fn private_pda_delegator() -> Self {
use test_program_methods::{PRIVATE_PDA_DELEGATOR_ELF, PRIVATE_PDA_DELEGATOR_ID};
Self {
id: PRIVATE_PDA_DELEGATOR_ID,
elf: PRIVATE_PDA_DELEGATOR_ELF.to_vec(),
}
}
#[must_use]
pub fn auth_transfer_proxy() -> Self {
use test_program_methods::{AUTH_TRANSFER_PROXY_ELF, AUTH_TRANSFER_PROXY_ID};
Self {
id: AUTH_TRANSFER_PROXY_ID,
elf: AUTH_TRANSFER_PROXY_ELF.to_vec(),
}
}
#[must_use]
pub fn two_pda_claimer() -> Self {
use test_program_methods::{TWO_PDA_CLAIMER_ELF, TWO_PDA_CLAIMER_ID};
Self {
id: TWO_PDA_CLAIMER_ID,
elf: TWO_PDA_CLAIMER_ELF.to_vec(),
}
}
2026-05-05 20:27:17 -03:00
#[must_use]
2026-05-11 17:09:46 -03:00
pub fn auth_transfer_pda_proxy() -> Self {
use test_program_methods::{AUTH_TRANSFER_PDA_PROXY_ELF, AUTH_TRANSFER_PDA_PROXY_ID};
2026-05-05 20:27:17 -03:00
Self {
2026-05-11 17:09:46 -03:00
id: AUTH_TRANSFER_PDA_PROXY_ID,
elf: AUTH_TRANSFER_PDA_PROXY_ELF.to_vec(),
2026-05-05 20:27:17 -03:00
}
}
2026-03-03 23:21:08 +03:00
#[must_use]
pub fn changer_claimer() -> Self {
use test_program_methods::{CHANGER_CLAIMER_ELF, CHANGER_CLAIMER_ID};
2026-03-09 18:27:56 +03:00
Self {
id: CHANGER_CLAIMER_ID,
elf: CHANGER_CLAIMER_ELF.to_vec(),
}
}
2026-03-03 23:21:08 +03:00
#[must_use]
pub fn noop() -> Self {
use test_program_methods::{NOOP_ELF, NOOP_ID};
2026-03-09 18:27:56 +03:00
Self {
id: NOOP_ID,
elf: NOOP_ELF.to_vec(),
}
}
test: exercise callee authorization in private-PDA delegation tests Addresses the following review comments: - "Shouldn't we use a program that checks authorization in this test as callee? If not, I'm not sure if we are fully testing what the test docs describe (namely, that the callee got the input account with is_authorized=true). Maybe add a variant of the noop that checks the input account is authorized." I added test_program_methods/guest/src/bin/auth_asserting_noop.rs: same shape as noop.rs except it asserts pre.is_authorized == true for every pre_state before echoing the post_states. Any unauthorized pre_state panics the guest, failing the whole circuit proof. I added Program::auth_asserting_noop() as the matching helper. In caller_pda_seeds_authorize_private_pda_for_callee and caller_pda_seeds_with_wrong_seed_rejects_private_pda_for_callee, I swapped Program::noop() for Program::auth_asserting_noop() as the callee. The positive test now proves the callee actually sees is_authorized=true, not just that the circuit's consistency check did not reject. The negative test doubles its evidence, both the circuit's authorization reconciliation and the callee guest would now reject a wrong-seed delegation. - "This branching logic is only correct because we are not supporting non-authorized private accounts with non-default values. Likely to be changed in the future. I'm sure there's use cases for this. For example the multisig program if ran completely private it would need a private non-default and non-authorized input account." Agreed. Supporting this needs wallet-supplied `(seed, owner)` side input so the npk-to-account_id binding can be re-verified for an existing private PDA without a fresh Claim::Pda or a caller pda_seeds match. I handled this in the second PR. I added a TODO(private-pdas-pr-2/3) marker on the `else` branch in privacy_preserving_circuit.rs:3 => { ... } so the constraint is visible to future maintainers, along with a comment noting the multisig use case.
2026-04-21 02:08:02 +02:00
#[must_use]
pub fn auth_asserting_noop() -> Self {
use test_program_methods::{AUTH_ASSERTING_NOOP_ELF, AUTH_ASSERTING_NOOP_ID};
Self {
id: AUTH_ASSERTING_NOOP_ID,
elf: AUTH_ASSERTING_NOOP_ELF.to_vec(),
}
}
2026-03-03 23:21:08 +03:00
#[must_use]
pub fn malicious_authorization_changer() -> Self {
use test_program_methods::{
MALICIOUS_AUTHORIZATION_CHANGER_ELF, MALICIOUS_AUTHORIZATION_CHANGER_ID,
};
2026-03-09 18:27:56 +03:00
Self {
id: MALICIOUS_AUTHORIZATION_CHANGER_ID,
elf: MALICIOUS_AUTHORIZATION_CHANGER_ELF.to_vec(),
}
}
2026-03-03 23:21:08 +03:00
#[must_use]
pub fn modified_transfer_program() -> Self {
use test_program_methods::{MODIFIED_TRANSFER_ELF, MODIFIED_TRANSFER_ID};
Self {
id: MODIFIED_TRANSFER_ID,
elf: MODIFIED_TRANSFER_ELF.to_vec(),
}
}
2026-03-19 15:03:45 -03:00
#[must_use]
pub fn validity_window() -> Self {
use test_program_methods::{VALIDITY_WINDOW_ELF, VALIDITY_WINDOW_ID};
Self {
id: VALIDITY_WINDOW_ID,
elf: VALIDITY_WINDOW_ELF.to_vec(),
}
2026-03-19 15:03:45 -03:00
}
#[must_use]
pub fn validity_window_chain_caller() -> Self {
use test_program_methods::{
VALIDITY_WINDOW_CHAIN_CALLER_ELF, VALIDITY_WINDOW_CHAIN_CALLER_ID,
};
Self {
id: VALIDITY_WINDOW_CHAIN_CALLER_ID,
elf: VALIDITY_WINDOW_CHAIN_CALLER_ELF.to_vec(),
}
}
#[must_use]
pub fn flash_swap_initiator() -> Self {
use test_program_methods::FLASH_SWAP_INITIATOR_ELF;
Self::new(FLASH_SWAP_INITIATOR_ELF.to_vec())
.expect("flash_swap_initiator must be a valid Risc0 program")
}
#[must_use]
pub fn flash_swap_callback() -> Self {
use test_program_methods::FLASH_SWAP_CALLBACK_ELF;
Self::new(FLASH_SWAP_CALLBACK_ELF.to_vec())
.expect("flash_swap_callback must be a valid Risc0 program")
}
#[must_use]
pub fn malicious_self_program_id() -> Self {
use test_program_methods::MALICIOUS_SELF_PROGRAM_ID_ELF;
Self::new(MALICIOUS_SELF_PROGRAM_ID_ELF.to_vec())
.expect("malicious_self_program_id must be a valid Risc0 program")
}
#[must_use]
pub fn malicious_caller_program_id() -> Self {
use test_program_methods::MALICIOUS_CALLER_PROGRAM_ID_ELF;
Self::new(MALICIOUS_CALLER_PROGRAM_ID_ELF.to_vec())
.expect("malicious_caller_program_id must be a valid Risc0 program")
}
#[must_use]
pub fn time_locked_transfer() -> Self {
use test_program_methods::TIME_LOCKED_TRANSFER_ELF;
Self::new(TIME_LOCKED_TRANSFER_ELF.to_vec()).unwrap()
}
#[must_use]
pub fn pinata_cooldown() -> Self {
use test_program_methods::PINATA_COOLDOWN_ELF;
Self::new(PINATA_COOLDOWN_ELF.to_vec()).unwrap()
}
2025-08-13 01:33:11 -03:00
}
#[test]
2026-03-04 18:42:33 +03:00
fn program_execution() {
2025-08-13 01:33:11 -03:00
let program = Program::simple_balance_transfer();
2026-03-03 23:21:08 +03:00
let balance_to_move: u128 = 11_223_344_556_677;
2025-08-13 01:33:11 -03:00
let instruction_data = Program::serialize_instruction(balance_to_move).unwrap();
2025-09-11 16:37:28 -03:00
let sender = AccountWithMetadata::new(
Account {
2026-03-03 23:21:08 +03:00
balance: 77_665_544_332_211,
2025-08-13 01:33:11 -03:00
..Account::default()
},
2025-09-11 16:37:28 -03:00
true,
2025-09-12 09:18:40 -03:00
AccountId::new([0; 32]),
2025-09-11 16:37:28 -03:00
);
let recipient =
2025-09-12 09:18:40 -03:00
AccountWithMetadata::new(Account::default(), false, AccountId::new([1; 32]));
2025-08-13 01:33:11 -03:00
let expected_sender_post = Account {
2026-03-03 23:21:08 +03:00
balance: 77_665_544_332_211 - balance_to_move,
2025-08-13 01:33:11 -03:00
..Account::default()
};
let expected_recipient_post = Account {
balance: balance_to_move,
..Account::default()
};
let program_output = program
.execute(None, &[sender, recipient], &instruction_data)
2025-08-13 01:33:11 -03:00
.unwrap();
let [sender_post, recipient_post] = program_output.post_states.try_into().unwrap();
2025-12-04 16:26:40 -03:00
assert_eq!(sender_post.account(), &expected_sender_post);
assert_eq!(recipient_post.account(), &expected_recipient_post);
2025-08-13 01:33:11 -03:00
}
#[test]
2026-03-04 18:42:33 +03:00
fn 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);
}
2026-04-07 17:25:47 -03:00
#[test]
fn builtin_program_ids_match_elfs() {
let cases: &[(&[u8], [u32; 8])] = &[
(AMM_ELF, AMM_ID),
(AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID),
2026-04-07 17:25:47 -03:00
(ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID),
(CLOCK_ELF, CLOCK_ID),
2026-04-07 17:25:47 -03:00
(PINATA_ELF, PINATA_ID),
(PINATA_TOKEN_ELF, PINATA_TOKEN_ID),
(TOKEN_ELF, TOKEN_ID),
2026-04-07 17:25:47 -03:00
];
for (elf, expected_id) in cases {
let program = Program::new(elf.to_vec()).unwrap();
assert_eq!(program.id(), *expected_id);
}
}
2025-08-13 01:33:11 -03:00
}