diff --git a/Cargo.lock b/Cargo.lock index 05077110ace..19d4e244179 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3956,6 +3956,7 @@ dependencies = [ "num-traits", "num_enum", "solana-program", + "solana-program-test", "solana-sdk", "thiserror", ] @@ -3983,6 +3984,7 @@ dependencies = [ "num-traits", "num_enum", "solana-program", + "solana-program-test", "solana-sdk", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 4b12838ec8e..881882d3766 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,6 @@ members = [ exclude = [ "themis/client_ristretto", "themis/program_ristretto", - "token/perf-monitor", # TODO: Rework perf-monitor to use solana-program-test, avoiding the need to link directly with the BPF VM ] [profile.dev] diff --git a/token/perf-monitor/Cargo.toml b/token/perf-monitor/Cargo.toml deleted file mode 100644 index 801675f6def..00000000000 --- a/token/perf-monitor/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "spl_token_perf_monitor" -version = "0.0.1" -description = "SPL Token performance monitor" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" -license = "Apache-2.0" -edition = "2018" - -[dev-dependencies] -rand = { version = "0.7.0"} -spl-token = { path = "../program", features = [ "no-entrypoint" ] } -solana-runtime = "1.8.1" -solana-sdk = "1.8.1" -solana-bpf-loader-program = "1.8.1" -solana_rbpf = "0.2" - -[workspace] diff --git a/token/perf-monitor/tests/assert_instruction_count.rs b/token/perf-monitor/tests/assert_instruction_count.rs deleted file mode 100644 index 41753395ba6..00000000000 --- a/token/perf-monitor/tests/assert_instruction_count.rs +++ /dev/null @@ -1,165 +0,0 @@ -use solana_bpf_loader_program::{ - create_vm, - serialization::{deserialize_parameters, serialize_parameters}, -}; -use solana_rbpf::vm::EbpfVm; -use solana_sdk::{ - account::{create_account, Account as SolanaAccount}, - bpf_loader, - entrypoint::SUCCESS, - keyed_account::KeyedAccount, - process_instruction::MockInvokeContext, - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, - sysvar::rent::{self, Rent}, -}; -use spl_token::{ - instruction::TokenInstruction, - state::{Account, Mint}, -}; -use std::{cell::RefCell, fs::File, io::Read}; - -fn load_program(name: &str) -> Vec { - let mut file = File::open(name).unwrap(); - - let mut program = Vec::new(); - file.read_to_end(&mut program).unwrap(); - program -} - -fn run_program( - program_id: &Pubkey, - parameter_accounts: &[KeyedAccount], - instruction_data: &[u8], -) -> u64 { - let program_account = SolanaAccount { - data: load_program("../../target/deploy/spl_token.so"), - ..SolanaAccount::default() - }; - let loader_id = bpf_loader::id(); - let mut invoke_context = MockInvokeContext::default(); - - let executable = EbpfVm::::create_executable_from_elf( - &&program_account.data, - None, - ) - .unwrap(); - let (mut vm, heap_region) = create_vm( - &loader_id, - executable.as_ref(), - parameter_accounts, - &mut invoke_context, - ) - .unwrap(); - let mut parameter_bytes = serialize_parameters( - &loader_id, - program_id, - parameter_accounts, - &instruction_data, - ) - .unwrap(); - assert_eq!( - Ok(SUCCESS), - vm.execute_program(parameter_bytes.as_mut_slice(), &[], &[heap_region]) - ); - deserialize_parameters(&loader_id, parameter_accounts, ¶meter_bytes).unwrap(); - vm.get_total_instruction_count() -} - -#[test] -fn assert_instruction_count() { - let program_id = Pubkey::new_unique(); - let source_key = Pubkey::new_unique(); - let source_account = SolanaAccount::new_ref(u64::MAX, Account::get_packed_len(), &program_id); - let destination_key = Pubkey::new_unique(); - let destination_account = - SolanaAccount::new_ref(u64::MAX, Account::get_packed_len(), &program_id); - let owner_key = Pubkey::new_unique(); - let owner_account = RefCell::new(SolanaAccount::default()); - let mint_key = Pubkey::new_unique(); - let mint_account = SolanaAccount::new_ref(0, Mint::get_packed_len(), &program_id); - let rent_key = rent::id(); - let rent_account = RefCell::new(create_account(&Rent::free(), 42)); - - // Create new mint - let instruction_data = TokenInstruction::InitializeMint { - decimals: 9, - mint_authority: owner_key, - freeze_authority: COption::None, - } - .pack(); - let parameter_accounts = vec![ - KeyedAccount::new(&mint_key, false, &mint_account), - KeyedAccount::new(&rent_key, false, &rent_account), - ]; - let initialize_mint_count = - run_program(&program_id, ¶meter_accounts[..], &instruction_data); - - // Create source account - let instruction_data = TokenInstruction::InitializeAccount.pack(); - let parameter_accounts = vec![ - KeyedAccount::new(&source_key, false, &source_account), - KeyedAccount::new(&mint_key, false, &mint_account), - KeyedAccount::new(&owner_key, false, &owner_account), - KeyedAccount::new(&rent_key, false, &rent_account), - ]; - let mintto_count = run_program(&program_id, ¶meter_accounts[..], &instruction_data); - - // Create destination account - let instruction_data = TokenInstruction::InitializeAccount.pack(); - let parameter_accounts = vec![ - KeyedAccount::new(&destination_key, false, &destination_account), - KeyedAccount::new(&mint_key, false, &mint_account), - KeyedAccount::new(&owner_key, false, &owner_account), - KeyedAccount::new(&rent_key, false, &rent_account), - ]; - let _ = run_program(&program_id, ¶meter_accounts[..], &instruction_data); - - // MintTo source account - let instruction_data = TokenInstruction::MintTo { amount: 100 }.pack(); - let parameter_accounts = vec![ - KeyedAccount::new(&mint_key, false, &mint_account), - KeyedAccount::new(&source_key, false, &source_account), - KeyedAccount::new(&owner_key, true, &owner_account), - ]; - let initialize_account_count = - run_program(&program_id, ¶meter_accounts[..], &instruction_data); - - // Transfer from source to destination - let instruction = TokenInstruction::Transfer { amount: 100 }; - let instruction_data = instruction.pack(); - let parameter_accounts = vec![ - KeyedAccount::new(&source_key, false, &source_account), - KeyedAccount::new(&destination_key, false, &destination_account), - KeyedAccount::new(&owner_key, true, &owner_account), - ]; - let transfer_count = run_program(&program_id, ¶meter_accounts[..], &instruction_data); - - const BASELINE_NEW_MINT_COUNT: u64 = 4000; // last known 3802 - const BASELINE_INITIALIZE_ACCOUNT_COUNT: u64 = 6500; // last known 6445 - const BASELINE_MINTTO_COUNT: u64 = 6500; // last known 6194 - const BASELINE_TRANSFER_COUNT: u64 = 8000; // last known 7609 - - println!("BPF instructions executed"); - println!( - " InitializeMint : {:?} ({:?})", - initialize_mint_count, BASELINE_NEW_MINT_COUNT - ); - println!( - " InitializeAccount: {:?} ({:?})", - initialize_account_count, BASELINE_INITIALIZE_ACCOUNT_COUNT - ); - println!( - " MintTo : {:?} ({:?})", - mintto_count, BASELINE_MINTTO_COUNT - ); - println!( - " Transfer : {:?} ({:?})", - transfer_count, BASELINE_TRANSFER_COUNT, - ); - - assert!(initialize_account_count <= BASELINE_INITIALIZE_ACCOUNT_COUNT); - assert!(initialize_mint_count <= BASELINE_NEW_MINT_COUNT); - assert!(transfer_count <= BASELINE_TRANSFER_COUNT); -} diff --git a/token/program-2022/Cargo.toml b/token/program-2022/Cargo.toml index 5d352b909fe..6bf8ed8d9f5 100644 --- a/token/program-2022/Cargo.toml +++ b/token/program-2022/Cargo.toml @@ -10,6 +10,7 @@ exclude = ["js/**"] [features] no-entrypoint = [] +test-bpf = [] [dependencies] arrayref = "0.3.6" @@ -20,6 +21,7 @@ solana-program = "1.8.1" thiserror = "1.0" [dev-dependencies] +solana-program-test = "1.8.1" solana-sdk = "1.8.1" [lib] diff --git a/token/program-2022/tests/action.rs b/token/program-2022/tests/action.rs new file mode 100644 index 00000000000..841582203ee --- /dev/null +++ b/token/program-2022/tests/action.rs @@ -0,0 +1,140 @@ +use { + solana_program_test::BanksClient, + solana_sdk::{ + hash::Hash, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + transport::TransportError, + }, + spl_token_2022::{ + id, instruction, + state::{Account, Mint}, + }, +}; + +pub async fn create_mint( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + pool_mint: &Keypair, + manager: &Pubkey, + decimals: u8, +) -> Result<(), TransportError> { + let rent = banks_client.get_rent().await.unwrap(); + let mint_rent = rent.minimum_balance(Mint::LEN); + + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &payer.pubkey(), + &pool_mint.pubkey(), + mint_rent, + Mint::LEN as u64, + &id(), + ), + instruction::initialize_mint(&id(), &pool_mint.pubkey(), manager, None, decimals) + .unwrap(), + ], + Some(&payer.pubkey()), + &[payer, pool_mint], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn create_account( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + account: &Keypair, + pool_mint: &Pubkey, + owner: &Pubkey, +) -> Result<(), TransportError> { + let rent = banks_client.get_rent().await.unwrap(); + let account_rent = rent.minimum_balance(Account::LEN); + + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &payer.pubkey(), + &account.pubkey(), + account_rent, + Account::LEN as u64, + &id(), + ), + instruction::initialize_account(&id(), &account.pubkey(), pool_mint, owner).unwrap(), + ], + Some(&payer.pubkey()), + &[payer, account], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn mint_to( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + mint: &Pubkey, + account: &Pubkey, + mint_authority: &Keypair, + amount: u64, +) -> Result<(), TransportError> { + let transaction = Transaction::new_signed_with_payer( + &[ + instruction::mint_to(&id(), mint, account, &mint_authority.pubkey(), &[], amount) + .unwrap(), + ], + Some(&payer.pubkey()), + &[payer, mint_authority], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn transfer( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + source: &Pubkey, + destination: &Pubkey, + authority: &Keypair, + amount: u64, +) -> Result<(), TransportError> { + let transaction = Transaction::new_signed_with_payer( + &[ + instruction::transfer(&id(), source, destination, &authority.pubkey(), &[], amount) + .unwrap(), + ], + Some(&payer.pubkey()), + &[payer, authority], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn burn( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + mint: &Pubkey, + account: &Pubkey, + authority: &Keypair, + amount: u64, +) -> Result<(), TransportError> { + let transaction = Transaction::new_signed_with_payer( + &[instruction::burn(&id(), account, mint, &authority.pubkey(), &[], amount).unwrap()], + Some(&payer.pubkey()), + &[payer, authority], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} diff --git a/token/program-2022/tests/assert_instruction_count.rs b/token/program-2022/tests/assert_instruction_count.rs new file mode 100644 index 00000000000..6d9ce24b24b --- /dev/null +++ b/token/program-2022/tests/assert_instruction_count.rs @@ -0,0 +1,284 @@ +#![cfg(feature = "test-bpf")] + +mod action; +use { + solana_program_test::{processor, tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, + spl_token_2022::{ + id, instruction, + processor::Processor, + state::{Account, Mint}, + }, +}; + +const TRANSFER_AMOUNT: u64 = 1_000_000_000_000_000; + +#[tokio::test] +async fn initialize_mint() { + let mut pt = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(2_500); // last known 2252 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner_key = Pubkey::new_unique(); + let mint = Keypair::new(); + let decimals = 9; + + let rent = banks_client.get_rent().await.unwrap(); + let mint_rent = rent.minimum_balance(Mint::LEN); + let transaction = Transaction::new_signed_with_payer( + &[system_instruction::create_account( + &payer.pubkey(), + &mint.pubkey(), + mint_rent, + Mint::LEN as u64, + &id(), + )], + Some(&payer.pubkey()), + &[&payer, &mint], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); + + let transaction = Transaction::new_signed_with_payer( + &[ + instruction::initialize_mint(&id(), &mint.pubkey(), &owner_key, None, decimals) + .unwrap(), + ], + Some(&payer.pubkey()), + &[&payer], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn initialize_account() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 3284 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let account = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + let rent = banks_client.get_rent().await.unwrap(); + let account_rent = rent.minimum_balance(Account::LEN); + let transaction = Transaction::new_signed_with_payer( + &[system_instruction::create_account( + &payer.pubkey(), + &account.pubkey(), + account_rent, + Account::LEN as u64, + &id(), + )], + Some(&payer.pubkey()), + &[&payer, &account], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); + + let transaction = Transaction::new_signed_with_payer( + &[instruction::initialize_account( + &id(), + &account.pubkey(), + &mint.pubkey(), + &owner.pubkey(), + ) + .unwrap()], + Some(&payer.pubkey()), + &[&payer], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn mint_to() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 2668 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let account = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &account, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + + let transaction = Transaction::new_signed_with_payer( + &[instruction::mint_to( + &id(), + &mint.pubkey(), + &account.pubkey(), + &owner.pubkey(), + &[], + TRANSFER_AMOUNT, + ) + .unwrap()], + Some(&payer.pubkey()), + &[&payer, &owner], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn transfer() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 2972 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let source = Keypair::new(); + let destination = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &source, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &destination, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + + action::mint_to( + &mut banks_client, + &payer, + recent_blockhash, + &mint.pubkey(), + &source.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); + + action::transfer( + &mut banks_client, + &payer, + recent_blockhash, + &source.pubkey(), + &destination.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn burn() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 2655 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let account = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &account, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + + action::mint_to( + &mut banks_client, + &payer, + recent_blockhash, + &mint.pubkey(), + &account.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); + + action::burn( + &mut banks_client, + &payer, + recent_blockhash, + &mint.pubkey(), + &account.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); +} diff --git a/token/program/Cargo.toml b/token/program/Cargo.toml index a199dab391f..5b9a976a2b2 100644 --- a/token/program/Cargo.toml +++ b/token/program/Cargo.toml @@ -10,6 +10,7 @@ exclude = ["js/**"] [features] no-entrypoint = [] +test-bpf = [] [dependencies] arrayref = "0.3.6" @@ -20,6 +21,7 @@ solana-program = "1.8.1" thiserror = "1.0" [dev-dependencies] +solana-program-test = "1.8.1" solana-sdk = "1.8.1" [lib] diff --git a/token/program/tests/action.rs b/token/program/tests/action.rs new file mode 100644 index 00000000000..0a67538b0ff --- /dev/null +++ b/token/program/tests/action.rs @@ -0,0 +1,140 @@ +use { + solana_program_test::BanksClient, + solana_sdk::{ + hash::Hash, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + transport::TransportError, + }, + spl_token::{ + id, instruction, + state::{Account, Mint}, + }, +}; + +pub async fn create_mint( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + pool_mint: &Keypair, + manager: &Pubkey, + decimals: u8, +) -> Result<(), TransportError> { + let rent = banks_client.get_rent().await.unwrap(); + let mint_rent = rent.minimum_balance(Mint::LEN); + + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &payer.pubkey(), + &pool_mint.pubkey(), + mint_rent, + Mint::LEN as u64, + &id(), + ), + instruction::initialize_mint(&id(), &pool_mint.pubkey(), manager, None, decimals) + .unwrap(), + ], + Some(&payer.pubkey()), + &[payer, pool_mint], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn create_account( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + account: &Keypair, + pool_mint: &Pubkey, + owner: &Pubkey, +) -> Result<(), TransportError> { + let rent = banks_client.get_rent().await.unwrap(); + let account_rent = rent.minimum_balance(Account::LEN); + + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &payer.pubkey(), + &account.pubkey(), + account_rent, + Account::LEN as u64, + &id(), + ), + instruction::initialize_account(&id(), &account.pubkey(), pool_mint, owner).unwrap(), + ], + Some(&payer.pubkey()), + &[payer, account], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn mint_to( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + mint: &Pubkey, + account: &Pubkey, + mint_authority: &Keypair, + amount: u64, +) -> Result<(), TransportError> { + let transaction = Transaction::new_signed_with_payer( + &[ + instruction::mint_to(&id(), mint, account, &mint_authority.pubkey(), &[], amount) + .unwrap(), + ], + Some(&payer.pubkey()), + &[payer, mint_authority], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn transfer( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + source: &Pubkey, + destination: &Pubkey, + authority: &Keypair, + amount: u64, +) -> Result<(), TransportError> { + let transaction = Transaction::new_signed_with_payer( + &[ + instruction::transfer(&id(), source, destination, &authority.pubkey(), &[], amount) + .unwrap(), + ], + Some(&payer.pubkey()), + &[payer, authority], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn burn( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + mint: &Pubkey, + account: &Pubkey, + authority: &Keypair, + amount: u64, +) -> Result<(), TransportError> { + let transaction = Transaction::new_signed_with_payer( + &[instruction::burn(&id(), account, mint, &authority.pubkey(), &[], amount).unwrap()], + Some(&payer.pubkey()), + &[payer, authority], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} diff --git a/token/program/tests/assert_instruction_count.rs b/token/program/tests/assert_instruction_count.rs new file mode 100644 index 00000000000..858bd55acb7 --- /dev/null +++ b/token/program/tests/assert_instruction_count.rs @@ -0,0 +1,284 @@ +#![cfg(feature = "test-bpf")] + +mod action; +use { + solana_program_test::{processor, tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, + spl_token::{ + id, instruction, + processor::Processor, + state::{Account, Mint}, + }, +}; + +const TRANSFER_AMOUNT: u64 = 1_000_000_000_000_000; + +#[tokio::test] +async fn initialize_mint() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(2_500); // last known 2252 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner_key = Pubkey::new_unique(); + let mint = Keypair::new(); + let decimals = 9; + + let rent = banks_client.get_rent().await.unwrap(); + let mint_rent = rent.minimum_balance(Mint::LEN); + let transaction = Transaction::new_signed_with_payer( + &[system_instruction::create_account( + &payer.pubkey(), + &mint.pubkey(), + mint_rent, + Mint::LEN as u64, + &id(), + )], + Some(&payer.pubkey()), + &[&payer, &mint], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); + + let transaction = Transaction::new_signed_with_payer( + &[ + instruction::initialize_mint(&id(), &mint.pubkey(), &owner_key, None, decimals) + .unwrap(), + ], + Some(&payer.pubkey()), + &[&payer], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn initialize_account() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 3284 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let account = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + let rent = banks_client.get_rent().await.unwrap(); + let account_rent = rent.minimum_balance(Account::LEN); + let transaction = Transaction::new_signed_with_payer( + &[system_instruction::create_account( + &payer.pubkey(), + &account.pubkey(), + account_rent, + Account::LEN as u64, + &id(), + )], + Some(&payer.pubkey()), + &[&payer, &account], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); + + let transaction = Transaction::new_signed_with_payer( + &[instruction::initialize_account( + &id(), + &account.pubkey(), + &mint.pubkey(), + &owner.pubkey(), + ) + .unwrap()], + Some(&payer.pubkey()), + &[&payer], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn mint_to() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 2668 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let account = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &account, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + + let transaction = Transaction::new_signed_with_payer( + &[instruction::mint_to( + &id(), + &mint.pubkey(), + &account.pubkey(), + &owner.pubkey(), + &[], + TRANSFER_AMOUNT, + ) + .unwrap()], + Some(&payer.pubkey()), + &[&payer, &owner], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn transfer() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 2972 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let source = Keypair::new(); + let destination = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &source, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &destination, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + + action::mint_to( + &mut banks_client, + &payer, + recent_blockhash, + &mint.pubkey(), + &source.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); + + action::transfer( + &mut banks_client, + &payer, + recent_blockhash, + &source.pubkey(), + &destination.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn burn() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 2655 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let account = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &account, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + + action::mint_to( + &mut banks_client, + &payer, + recent_blockhash, + &mint.pubkey(), + &account.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); + + action::burn( + &mut banks_client, + &payer, + recent_blockhash, + &mint.pubkey(), + &account.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); +}