diff --git a/Cargo.lock b/Cargo.lock index 9db26c18a11..1f10619d095 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3364,6 +3364,44 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "mollusk-svm" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fceaf67fe3f95a9478f4f5b0d71e77c073eee7a795a74d6143317a22454c289" +dependencies = [ + "bincode", + "mollusk-svm-error", + "mollusk-svm-keys", + "solana-bpf-loader-program", + "solana-compute-budget", + "solana-logger", + "solana-program-runtime", + "solana-sdk", + "solana-system-program", + "solana-timings", +] + +[[package]] +name = "mollusk-svm-error" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8738bc85a52d123012209a573f17faffa1db440493396ae2e1f64fbb8f3579bf" +dependencies = [ + "solana-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "mollusk-svm-keys" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a7656d86d743de0a9788ce4c0e9ff63028a42e350131ebe67c476cdde6ac9f" +dependencies = [ + "mollusk-svm-error", + "solana-sdk", +] + [[package]] name = "multimap" version = "0.8.3" @@ -8514,13 +8552,13 @@ dependencies = [ "arrayref", "bytemuck", "lazy_static", + "mollusk-svm", "num-derive", "num-traits", "num_enum", "proptest", "serial_test", "solana-program", - "solana-program-test", "solana-sdk", "thiserror 2.0.7", ] @@ -8593,6 +8631,7 @@ dependencies = [ "borsh 1.5.3", "bytemuck", "futures-util", + "mollusk-svm", "solana-program", "solana-program-test", "solana-sdk", diff --git a/token/program-2022-test/Cargo.toml b/token/program-2022-test/Cargo.toml index 99c4e1842d6..0c79f673367 100644 --- a/token/program-2022-test/Cargo.toml +++ b/token/program-2022-test/Cargo.toml @@ -20,6 +20,7 @@ async-trait = "0.1" borsh = "1.5.3" bytemuck = "1.20.0" futures-util = "0.3" +mollusk-svm = "0.0.13" solana-program = "2.1.0" solana-program-test = "2.1.0" solana-sdk = "2.1.0" diff --git a/token/program/Cargo.toml b/token/program/Cargo.toml index c0788db3792..eef01592282 100644 --- a/token/program/Cargo.toml +++ b/token/program/Cargo.toml @@ -23,9 +23,9 @@ thiserror = "2.0" [dev-dependencies] lazy_static = "1.5.0" +mollusk-svm = "0.0.13" proptest = "1.6" serial_test = "3.2.0" -solana-program-test = "2.1.0" solana-sdk = "2.1.0" [lib] diff --git a/token/program/tests/action.rs b/token/program/tests/action.rs deleted file mode 100644 index 0a67538b0ff..00000000000 --- a/token/program/tests/action.rs +++ /dev/null @@ -1,140 +0,0 @@ -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 index 009fb1edb28..ab5de7c8d1d 100644 --- a/token/program/tests/assert_instruction_count.rs +++ b/token/program/tests/assert_instruction_count.rs @@ -1,332 +1,201 @@ #![cfg(feature = "test-sbf")] -mod action; +mod setup; + use { - solana_program_test::{processor, tokio, ProgramTest}, + mollusk_svm::{result::Check, Mollusk}, solana_sdk::{ + account::{AccountSharedData, ReadableAccount}, 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_compute_max_units(5_000); // last known 2252 - let (banks_client, payer, recent_blockhash) = pt.start().await; +#[test] +fn initialize_mint() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 5_000; // last known 2252 - let owner_key = Pubkey::new_unique(); - let mint = Keypair::new(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); 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 mint_account = { + let space = Mint::LEN; + let lamports = mollusk.sysvars.rent.minimum_balance(space); + AccountSharedData::new(lamports, space, &id()) + }; - let transaction = Transaction::new_signed_with_payer( + mollusk.process_and_validate_instruction( + &instruction::initialize_mint(&id(), &mint, &owner, None, decimals).unwrap(), + &[ + (mint, mint_account), + mollusk.sysvars.keyed_account_for_rent_sysvar(), + ], &[ - instruction::initialize_mint(&id(), &mint.pubkey(), &owner_key, None, decimals) - .unwrap(), + Check::success(), + Check::account(&mint) + .data(setup::setup_mint_account(Some(&owner), None, 0, decimals).data()) + .build(), ], - 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_compute_max_units(6_000); // last known 3284 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; +#[test] +fn initialize_account() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 6_000; // last known 3284 - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); 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 mint_account = setup::setup_mint_account(None, None, 0, decimals); + let token_account = { + let space = Account::LEN; + let lamports = mollusk.sysvars.rent.minimum_balance(space); + AccountSharedData::new(lamports, space, &id()) + }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::initialize_account( - &id(), - &account.pubkey(), - &mint.pubkey(), - &owner.pubkey(), - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, + mollusk.process_and_validate_instruction( + &instruction::initialize_account(&id(), &account, &mint, &owner).unwrap(), + &[ + (account, token_account), + (mint, mint_account), + (owner, AccountSharedData::default()), + mollusk.sysvars.keyed_account_for_rent_sysvar(), + ], + &[ + Check::success(), + Check::account(&account) + .data(setup::setup_token_account(&mint, &owner, 0).data()) + .build(), + ], ); - 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_compute_max_units(6_000); // last known 2668 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; +#[test] +fn mint_to() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 6_000; // last known 2668 - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); 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 mint_account = setup::setup_mint_account(Some(&owner), None, 0, decimals); + let token_account = setup::setup_token_account(&mint, &owner, 0); - 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, + mollusk.process_and_validate_instruction( + &instruction::mint_to(&id(), &mint, &account, &owner, &[], TRANSFER_AMOUNT).unwrap(), + &[ + (mint, mint_account), + (account, token_account), + (owner, AccountSharedData::default()), + ], + &[ + Check::success(), + Check::account(&mint) + .data( + setup::setup_mint_account(Some(&owner), None, TRANSFER_AMOUNT, decimals).data(), + ) + .build(), + Check::account(&account) + .data(setup::setup_token_account(&mint, &owner, TRANSFER_AMOUNT).data()) + .build(), + ], ); - 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_compute_max_units(7_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; +#[test] +fn transfer() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 7_000; // last known 2972 - 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(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let source = Pubkey::new_unique(); + let destination = Pubkey::new_unique(); - action::mint_to( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &source.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); + let source_token_account = setup::setup_token_account(&mint, &owner, TRANSFER_AMOUNT); + let destination_token_account = setup::setup_token_account(&mint, &owner, 0); - action::transfer( - &mut banks_client, - &payer, - recent_blockhash, - &source.pubkey(), - &destination.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); + mollusk.process_and_validate_instruction( + &instruction::transfer(&id(), &source, &destination, &owner, &[], TRANSFER_AMOUNT).unwrap(), + &[ + (source, source_token_account), + (destination, destination_token_account), + (owner, AccountSharedData::default()), + ], + &[ + Check::success(), + Check::account(&source) + .data(setup::setup_token_account(&mint, &owner, 0).data()) + .build(), + Check::account(&destination) + .data(setup::setup_token_account(&mint, &owner, TRANSFER_AMOUNT).data()) + .build(), + ], + ); } -#[tokio::test] -async fn burn() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(6_000); // last known 2655 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; +#[test] +fn burn() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 6_000; // last known 2655 - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); 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(); + let mint_account = setup::setup_mint_account(None, None, TRANSFER_AMOUNT, decimals); + let token_account = setup::setup_token_account(&mint, &owner, TRANSFER_AMOUNT); - action::burn( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &account.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); + mollusk.process_and_validate_instruction( + &instruction::burn(&id(), &account, &mint, &owner, &[], TRANSFER_AMOUNT).unwrap(), + &[ + (mint, mint_account), + (account, token_account), + (owner, AccountSharedData::default()), + ], + &[ + Check::success(), + Check::account(&account) + .data(setup::setup_token_account(&mint, &owner, 0).data()) + .build(), + ], + ); } -#[tokio::test] -async fn close_account() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(6_000); // last known 1783 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; +#[test] +fn close_account() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 6_000; // last known 1783 - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); 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 mint_account = setup::setup_mint_account(None, None, 0, decimals); + let token_account = setup::setup_token_account(&mint, &owner, 0); - let transaction = Transaction::new_signed_with_payer( - &[instruction::close_account( - &id(), - &account.pubkey(), - &owner.pubkey(), - &owner.pubkey(), - &[], - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer, &owner], - recent_blockhash, + mollusk.process_and_validate_instruction( + &instruction::close_account(&id(), &account, &owner, &owner, &[]).unwrap(), + &[ + (mint, mint_account), + (account, token_account), + (owner, AccountSharedData::default()), + ], + &[Check::success(), Check::account(&account).closed().build()], ); - banks_client.process_transaction(transaction).await.unwrap(); } diff --git a/token/program/tests/close_account.rs b/token/program/tests/close_account.rs index 8425fe206bf..b3b309a53d8 100644 --- a/token/program/tests/close_account.rs +++ b/token/program/tests/close_account.rs @@ -1,200 +1,93 @@ #![cfg(feature = "test-sbf")] +mod setup; + use { - solana_program_test::{processor, tokio, ProgramTest, ProgramTestContext}, + mollusk_svm::{result::Check, Mollusk}, solana_sdk::{ - instruction::InstructionError, + account::{AccountSharedData, ReadableAccount}, + program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, - signature::Signer, - signer::keypair::Keypair, - system_instruction, - transaction::{Transaction, TransactionError}, - }, - spl_token::{ - instruction, - processor::Processor, - state::{Account, Mint}, + system_instruction, system_program, }, + spl_token::{instruction, state::Account}, }; -async fn setup_mint_and_account( - context: &mut ProgramTestContext, - mint: &Keypair, - token_account: &Keypair, - owner: &Pubkey, - token_program_id: &Pubkey, -) { - let rent = context.banks_client.get_rent().await.unwrap(); - let mint_authority_pubkey = Pubkey::new_unique(); +#[test] +fn success_init_after_close_account() { + let mollusk = Mollusk::new(&spl_token::id(), "spl_token"); - let space = Mint::LEN; - let tx = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &context.payer.pubkey(), - &mint.pubkey(), - rent.minimum_balance(space), - space as u64, - token_program_id, - ), - instruction::initialize_mint( - token_program_id, - &mint.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - ], - Some(&context.payer.pubkey()), - &[&context.payer, mint], - context.last_blockhash, - ); - context.banks_client.process_transaction(tx).await.unwrap(); - let space = Account::LEN; - let tx = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &context.payer.pubkey(), - &token_account.pubkey(), - rent.minimum_balance(space), - space as u64, - token_program_id, - ), - instruction::initialize_account( - token_program_id, - &token_account.pubkey(), - &mint.pubkey(), - owner, - ) - .unwrap(), - ], - Some(&context.payer.pubkey()), - &[&context.payer, token_account], - context.last_blockhash, - ); - context.banks_client.process_transaction(tx).await.unwrap(); -} + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); + let decimals = 9; -#[tokio::test] -async fn success_init_after_close_account() { - let program_test = - ProgramTest::new("spl_token", spl_token::id(), processor!(Processor::process)); - let mut context = program_test.start_with_context().await; - let mint = Keypair::new(); - let token_account = Keypair::new(); - let owner = Keypair::new(); - let token_program_id = spl_token::id(); - setup_mint_and_account( - &mut context, - &mint, - &token_account, - &owner.pubkey(), - &token_program_id, - ) - .await; + let owner_account = AccountSharedData::new(1_000_000_000, 0, &system_program::id()); + let mint_account = setup::setup_mint_account(None, None, 0, decimals); + let token_account = setup::setup_token_account(&mint, &owner, 0); - let destination = Pubkey::new_unique(); - let tx = Transaction::new_signed_with_payer( + mollusk.process_and_validate_instruction_chain( &[ - instruction::close_account( - &token_program_id, - &token_account.pubkey(), - &destination, - &owner.pubkey(), - &[], - ) - .unwrap(), + instruction::close_account(&spl_token::id(), &account, &owner, &owner, &[]).unwrap(), system_instruction::create_account( - &context.payer.pubkey(), - &token_account.pubkey(), + &owner, + &account, 1_000_000_000, Account::LEN as u64, - &token_program_id, + &spl_token::id(), ), - instruction::initialize_account( - &token_program_id, - &token_account.pubkey(), - &mint.pubkey(), - &owner.pubkey(), - ) - .unwrap(), + instruction::initialize_account(&spl_token::id(), &account, &mint, &owner).unwrap(), + ], + &[ + (mint, mint_account), + (account, token_account), + (owner, owner_account), + mollusk.sysvars.keyed_account_for_rent_sysvar(), + ], + &[ + Check::success(), + // Account successfully initialized. + Check::account(&account) + .data(setup::setup_token_account(&mint, &owner, 0).data()) + .owner(&spl_token::id()) + .build(), ], - Some(&context.payer.pubkey()), - &[&context.payer, &owner, &token_account], - context.last_blockhash, ); - context.banks_client.process_transaction(tx).await.unwrap(); - let destination = context - .banks_client - .get_account(destination) - .await - .unwrap() - .unwrap(); - assert!(destination.lamports > 0); } -#[tokio::test] -async fn fail_init_after_close_account() { - let program_test = - ProgramTest::new("spl_token", spl_token::id(), processor!(Processor::process)); - let mut context = program_test.start_with_context().await; - let mint = Keypair::new(); - let token_account = Keypair::new(); - let owner = Keypair::new(); - let token_program_id = spl_token::id(); - setup_mint_and_account( - &mut context, - &mint, - &token_account, - &owner.pubkey(), - &token_program_id, - ) - .await; +#[test] +fn fail_init_after_close_account() { + let mollusk = Mollusk::new(&spl_token::id(), "spl_token"); - let destination = Pubkey::new_unique(); - let tx = Transaction::new_signed_with_payer( + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); + let decimals = 9; + + let owner_account = AccountSharedData::new(1_000_000_000, 0, &system_program::id()); + let mint_account = setup::setup_mint_account(None, None, 0, decimals); + let token_account = setup::setup_token_account(&mint, &owner, 0); + + mollusk.process_and_validate_instruction_chain( &[ - instruction::close_account( - &token_program_id, - &token_account.pubkey(), - &destination, - &owner.pubkey(), - &[], - ) - .unwrap(), - system_instruction::transfer( - &context.payer.pubkey(), - &token_account.pubkey(), - 1_000_000_000, - ), - instruction::initialize_account( - &token_program_id, - &token_account.pubkey(), - &mint.pubkey(), - &owner.pubkey(), - ) - .unwrap(), + instruction::close_account(&spl_token::id(), &account, &owner, &owner, &[]).unwrap(), + system_instruction::transfer(&owner, &account, 1_000_000_000), + instruction::initialize_account(&spl_token::id(), &account, &mint, &owner).unwrap(), + ], + &[ + (mint, mint_account), + (account, token_account), + (owner, owner_account), + mollusk.sysvars.keyed_account_for_rent_sysvar(), + ], + &[ + Check::err(ProgramError::InvalidAccountData), + // Account not initialized. + Check::account(&account) + .lamports(1_000_000_000) + .owner(&system_program::id()) + .build(), ], - Some(&context.payer.pubkey()), - &[&context.payer, &owner], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap(); - assert_eq!( - error, - TransactionError::InstructionError(2, InstructionError::InvalidAccountData) ); - assert!(context - .banks_client - .get_account(destination) - .await - .unwrap() - .is_none()); } diff --git a/token/program/tests/setup.rs b/token/program/tests/setup.rs new file mode 100644 index 00000000000..df793815cb3 --- /dev/null +++ b/token/program/tests/setup.rs @@ -0,0 +1,69 @@ +#![cfg(feature = "test-sbf")] + +use { + solana_sdk::{ + account::{Account as SolanaAccount, AccountSharedData}, + program_pack::Pack, + pubkey::Pubkey, + rent::Rent, + }, + spl_token::state::{Account, AccountState, Mint}, +}; + +pub fn setup_mint_account( + mint_authority: Option<&Pubkey>, + freeze_authority: Option<&Pubkey>, + supply: u64, + decimals: u8, +) -> AccountSharedData { + let data = { + let mut data = vec![0; Mint::LEN]; + let state = Mint { + mint_authority: mint_authority.cloned().into(), + supply, + decimals, + is_initialized: true, + freeze_authority: freeze_authority.cloned().into(), + }; + state.pack_into_slice(&mut data); + data + }; + + let space = data.len(); + let lamports = Rent::default().minimum_balance(space); + + AccountSharedData::from(SolanaAccount { + lamports, + data, + owner: spl_token::id(), + ..Default::default() + }) +} + +pub fn setup_token_account(mint: &Pubkey, owner: &Pubkey, amount: u64) -> AccountSharedData { + let data = { + let mut data = vec![0; Account::LEN]; + let state = Account { + mint: *mint, + owner: *owner, + amount, + delegate: None.into(), + state: AccountState::Initialized, + is_native: None.into(), + delegated_amount: 0, + close_authority: None.into(), + }; + state.pack_into_slice(&mut data); + data + }; + + let space = data.len(); + let lamports = Rent::default().minimum_balance(space); + + AccountSharedData::from(SolanaAccount { + lamports, + data, + owner: spl_token::id(), + ..Default::default() + }) +}