From c2e1a53d756553e4db7dfcaf26b0f21436b94485 Mon Sep 17 00:00:00 2001 From: lukacan Date: Wed, 23 Oct 2024 22:25:24 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=94=A5=20Remove=20unnecessary=20optio?= =?UTF-8?q?ns=20for=20account=20storages=20methods=20+=20add=20get=20funct?= =?UTF-8?q?ion=20that=20returns=20simple=20Pubkey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/fuzz/src/accounts_storage.rs | 67 +++++--- .../arbitrary-custom-types-4/Cargo.lock | 11 +- .../arbitrary-limit-inputs-5/Cargo.lock | 11 +- .../arbitrary-limit-inputs-5/Trident.toml | 2 +- .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 157 ++++++++---------- examples/fuzz-tests/cpi-metaplex-7/Cargo.lock | 11 +- examples/fuzz-tests/hello_world/Cargo.lock | 11 +- .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 15 +- .../Trident.toml | 4 +- .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 156 ++++++++--------- .../incorrect-ix-sequence-1/Cargo.lock | 11 +- .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 101 +++++------ examples/fuzz-tests/simple-cpi-6/Cargo.lock | 11 +- examples/fuzz-tests/simple-cpi-6/Trident.toml | 2 +- .../unauthorized-access-2/Cargo.lock | 11 +- .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 46 +++-- .../unchecked-arithmetic-0/Cargo.lock | 28 ++-- 17 files changed, 301 insertions(+), 354 deletions(-) diff --git a/crates/fuzz/src/accounts_storage.rs b/crates/fuzz/src/accounts_storage.rs index 4e5145d6e..2b5106a8f 100644 --- a/crates/fuzz/src/accounts_storage.rs +++ b/crates/fuzz/src/accounts_storage.rs @@ -41,13 +41,8 @@ impl AccountsStorage { } } - /// Gets a reference to the account with the given account ID - pub fn get(&self, account_id: AccountId) -> Option<&T> { - self.accounts.get(&account_id) - } - /// Returns a mutable reference to the underlying HashMap that stores accounts with IDs as keys - pub fn storage(&mut self) -> &mut HashMap { + fn storage(&mut self) -> &mut HashMap { &mut self.accounts } } @@ -71,6 +66,12 @@ impl AccountsStorage { .or_insert_with(|| client.set_account(lamports)); key.insecure_clone() } + pub fn get(&self, account_id: AccountId) -> Keypair { + match self.accounts.get(&account_id) { + Some(v) => v.insecure_clone(), + None => Keypair::new(), + } + } } impl AccountsStorage { @@ -86,7 +87,7 @@ impl AccountsStorage { is_native: Option, delegated_amount: u64, close_authority: Option, - ) -> Option { + ) -> Pubkey { let key = self.accounts.entry(account_id).or_insert_with(|| { let key = client.set_token_account( mint, @@ -99,7 +100,13 @@ impl AccountsStorage { ); TokenStore { pubkey: key } }); - Some(key.pubkey) + key.pubkey + } + pub fn get(&self, account_id: AccountId) -> Pubkey { + match self.accounts.get(&account_id) { + Some(v) => v.pubkey, + None => Pubkey::default(), + } } } @@ -111,12 +118,18 @@ impl AccountsStorage { decimals: u8, owner: &Pubkey, freeze_authority: Option, - ) -> Option { + ) -> Pubkey { let key = self.accounts.entry(account_id).or_insert_with(|| { let key = client.set_mint_account(decimals, owner, freeze_authority); MintStore { pubkey: key } }); - Some(key.pubkey) + key.pubkey + } + pub fn get(&self, account_id: AccountId) -> Pubkey { + match self.accounts.get(&account_id) { + Some(v) => v.pubkey, + None => Pubkey::default(), + } } } @@ -126,18 +139,28 @@ impl AccountsStorage { account_id: AccountId, seeds: &[&[u8]], program_id: &Pubkey, - ) -> Option<&PdaStore> { - let key = self.accounts.entry(account_id).or_insert( - if let Some((key, _)) = Pubkey::try_find_program_address(seeds, program_id) { - let seeds_vec: Vec<_> = seeds.iter().map(|&s| s.to_vec()).collect(); - PdaStore { - pubkey: key, - seeds: seeds_vec, + ) -> Pubkey { + match self.accounts.get(&account_id) { + Some(v) => v.pubkey, + None => { + if let Some((key, _)) = Pubkey::try_find_program_address(seeds, program_id) { + let seeds_vec: Vec<_> = seeds.iter().map(|&s| s.to_vec()).collect(); + let pda_store = PdaStore { + pubkey: key, + seeds: seeds_vec, + }; + self.accounts.insert(account_id, pda_store); + key + } else { + Pubkey::default() } - } else { - return None; - }, - ); - Some(key) + } + } + } + pub fn get(&self, account_id: AccountId) -> Pubkey { + match self.accounts.get(&account_id) { + Some(v) => v.pubkey, + None => Pubkey::default(), + } } } diff --git a/examples/fuzz-tests/arbitrary-custom-types-4/Cargo.lock b/examples/fuzz-tests/arbitrary-custom-types-4/Cargo.lock index 43f766f47..3d326956c 100644 --- a/examples/fuzz-tests/arbitrary-custom-types-4/Cargo.lock +++ b/examples/fuzz-tests/arbitrary-custom-types-4/Cargo.lock @@ -5879,7 +5879,7 @@ dependencies = [ [[package]] name = "trident-client" -version = "0.7.0" +version = "0.8.0" dependencies = [ "afl", "anchor-lang", @@ -5904,6 +5904,7 @@ dependencies = [ "thiserror", "tokio", "toml 0.8.19", + "trident-derive-accounts-snapshots", "trident-derive-displayix", "trident-derive-fuzz-test-executor", "trident-fuzz", @@ -5911,7 +5912,7 @@ dependencies = [ [[package]] name = "trident-derive-accounts-snapshots" -version = "0.0.1" +version = "0.0.2" dependencies = [ "anchor-syn", "convert_case", @@ -5922,7 +5923,7 @@ dependencies = [ [[package]] name = "trident-derive-displayix" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5931,7 +5932,7 @@ dependencies = [ [[package]] name = "trident-derive-fuzz-test-executor" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5940,7 +5941,7 @@ dependencies = [ [[package]] name = "trident-fuzz" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anchor-lang", "anyhow", diff --git a/examples/fuzz-tests/arbitrary-limit-inputs-5/Cargo.lock b/examples/fuzz-tests/arbitrary-limit-inputs-5/Cargo.lock index 692d75789..29297eecd 100644 --- a/examples/fuzz-tests/arbitrary-limit-inputs-5/Cargo.lock +++ b/examples/fuzz-tests/arbitrary-limit-inputs-5/Cargo.lock @@ -6079,7 +6079,7 @@ dependencies = [ [[package]] name = "trident-client" -version = "0.7.0" +version = "0.8.0" dependencies = [ "afl", "anchor-lang", @@ -6104,6 +6104,7 @@ dependencies = [ "thiserror", "tokio", "toml 0.8.19", + "trident-derive-accounts-snapshots", "trident-derive-displayix", "trident-derive-fuzz-test-executor", "trident-fuzz", @@ -6111,7 +6112,7 @@ dependencies = [ [[package]] name = "trident-derive-accounts-snapshots" -version = "0.0.1" +version = "0.0.2" dependencies = [ "anchor-syn", "convert_case", @@ -6122,7 +6123,7 @@ dependencies = [ [[package]] name = "trident-derive-displayix" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -6131,7 +6132,7 @@ dependencies = [ [[package]] name = "trident-derive-fuzz-test-executor" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -6140,7 +6141,7 @@ dependencies = [ [[package]] name = "trident-fuzz" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anchor-lang", "anyhow", diff --git a/examples/fuzz-tests/arbitrary-limit-inputs-5/Trident.toml b/examples/fuzz-tests/arbitrary-limit-inputs-5/Trident.toml index 6de0eb954..2c1032328 100644 --- a/examples/fuzz-tests/arbitrary-limit-inputs-5/Trident.toml +++ b/examples/fuzz-tests/arbitrary-limit-inputs-5/Trident.toml @@ -34,4 +34,4 @@ save_all = false allow_duplicate_txs = false # Trident will show statistics after the fuzzing session. This option forces use of honggfuzz parameter # `keep_output` as true in order to be able to catch fuzzer stdout. (default: false) -fuzzing_with_stats = false +fuzzing_with_stats = true diff --git a/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 6d355267b..c307b24a7 100644 --- a/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -172,57 +172,47 @@ impl<'info> IxOps<'info> for InitVesting { // and also we can easily link to Withdraw let mint = fuzz_accounts .mint - .get_or_create_account(0, client, 6, &sender.pubkey(), None) - .unwrap(); + .get_or_create_account(0, client, 6, &sender.pubkey(), None); - let sender_token_account = fuzz_accounts - .sender_token_account - .get_or_create_account( - self.accounts.sender_token_account, - client, - mint, - sender.pubkey(), - u64::MAX, - None, - None, - 0, - None, - ) - .unwrap(); + let sender_token_account = fuzz_accounts.sender_token_account.get_or_create_account( + self.accounts.sender_token_account, + client, + mint, + sender.pubkey(), + u64::MAX, + None, + None, + 0, + None, + ); let recipient = fuzz_accounts.recipient.get_or_create_account( self.data.recipient, client, 10 * LAMPORTS_PER_SOL, ); - let escrow = fuzz_accounts - .escrow - .get_or_create_account( - self.accounts.escrow, - &[recipient.pubkey().as_ref(), b"ESCROW_SEED"], - &arbitrary_limit_inputs_5::ID, - ) - .unwrap(); + let escrow = fuzz_accounts.escrow.get_or_create_account( + self.accounts.escrow, + &[recipient.pubkey().as_ref(), b"ESCROW_SEED"], + &arbitrary_limit_inputs_5::ID, + ); - let escrow_token_account = fuzz_accounts - .escrow_token_account - .get_or_create_account( - self.accounts.escrow_token_account, - client, - mint, - sender.pubkey(), - 0, - None, - None, - 0, - None, - ) - .unwrap(); + let escrow_token_account = fuzz_accounts.escrow_token_account.get_or_create_account( + self.accounts.escrow_token_account, + client, + mint, + sender.pubkey(), + 0, + None, + None, + 0, + None, + ); let acc_meta = arbitrary_limit_inputs_5::accounts::InitVestingContext { sender: sender.pubkey(), sender_token_account, - escrow: escrow.pubkey(), + escrow, escrow_token_account, mint, token_program: anchor_spl::token::ID, @@ -273,70 +263,59 @@ impl<'info> IxOps<'info> for WithdrawUnlocked { // INFO use constant Account ID, so we will not generate multiple mints, // and also we can easily link to Initialize - let mint = fuzz_accounts - .mint - .get_or_create_account(0, client, 6, &recipient.pubkey(), None) - .unwrap(); + let mint = + fuzz_accounts + .mint + .get_or_create_account(0, client, 6, &recipient.pubkey(), None); - let recipient_token_account = fuzz_accounts - .recipient_token_account - .get_or_create_account( - self.accounts.recipient_token_account, - client, - mint, - recipient.pubkey(), - 0, - None, - None, - 0, - None, - ) - .unwrap(); + let recipient_token_account = fuzz_accounts.recipient_token_account.get_or_create_account( + self.accounts.recipient_token_account, + client, + mint, + recipient.pubkey(), + 0, + None, + None, + 0, + None, + ); - let escrow = fuzz_accounts - .escrow - .get_or_create_account( - self.accounts.escrow, - &[recipient.pubkey().as_ref(), b"ESCROW_SEED"], - &arbitrary_limit_inputs_5::ID, - ) - .unwrap(); + let escrow = fuzz_accounts.escrow.get_or_create_account( + self.accounts.escrow, + &[recipient.pubkey().as_ref(), b"ESCROW_SEED"], + &arbitrary_limit_inputs_5::ID, + ); - let escrow_pda_authority = fuzz_accounts - .escrow_pda_authority - .get_or_create_account( - self.accounts.escrow_pda_authority, - &[b"ESCROW_PDA_AUTHORITY"], - &arbitrary_limit_inputs_5::ID, - ) - .unwrap(); + let escrow_pda_authority = fuzz_accounts.escrow_pda_authority.get_or_create_account( + self.accounts.escrow_pda_authority, + &[b"ESCROW_PDA_AUTHORITY"], + &arbitrary_limit_inputs_5::ID, + ); - let escrow_token_account = fuzz_accounts - .escrow_token_account - .get_or_create_account( - self.accounts.escrow_token_account, - client, - mint, - escrow_pda_authority.pubkey(), - u64::MAX, - None, - None, - 0, - None, - ) - .unwrap(); + let escrow_token_account = fuzz_accounts.escrow_token_account.get_or_create_account( + self.accounts.escrow_token_account, + client, + mint, + escrow_pda_authority, + u64::MAX, + None, + None, + 0, + None, + ); let acc_meta = arbitrary_limit_inputs_5::accounts::WithdrawUnlocked { recipient: recipient.pubkey(), recipient_token_account, - escrow: escrow.pubkey(), + escrow, escrow_token_account, - escrow_pda_authority: escrow_pda_authority.pubkey(), + escrow_pda_authority, mint, token_program: anchor_spl::token::ID, system_program: solana_sdk::system_program::ID, } .to_account_metas(None); + Ok((vec![recipient], acc_meta)) } fn check( diff --git a/examples/fuzz-tests/cpi-metaplex-7/Cargo.lock b/examples/fuzz-tests/cpi-metaplex-7/Cargo.lock index f15592be3..dd94eb0b9 100644 --- a/examples/fuzz-tests/cpi-metaplex-7/Cargo.lock +++ b/examples/fuzz-tests/cpi-metaplex-7/Cargo.lock @@ -6094,7 +6094,7 @@ dependencies = [ [[package]] name = "trident-client" -version = "0.7.0" +version = "0.8.0" dependencies = [ "afl", "anchor-lang", @@ -6119,6 +6119,7 @@ dependencies = [ "thiserror", "tokio", "toml 0.8.19", + "trident-derive-accounts-snapshots", "trident-derive-displayix", "trident-derive-fuzz-test-executor", "trident-fuzz", @@ -6126,7 +6127,7 @@ dependencies = [ [[package]] name = "trident-derive-accounts-snapshots" -version = "0.0.1" +version = "0.0.2" dependencies = [ "anchor-syn", "convert_case", @@ -6137,7 +6138,7 @@ dependencies = [ [[package]] name = "trident-derive-displayix" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -6146,7 +6147,7 @@ dependencies = [ [[package]] name = "trident-derive-fuzz-test-executor" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -6155,7 +6156,7 @@ dependencies = [ [[package]] name = "trident-fuzz" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anchor-lang", "anyhow", diff --git a/examples/fuzz-tests/hello_world/Cargo.lock b/examples/fuzz-tests/hello_world/Cargo.lock index 65a3145ad..d874db5a6 100644 --- a/examples/fuzz-tests/hello_world/Cargo.lock +++ b/examples/fuzz-tests/hello_world/Cargo.lock @@ -5882,7 +5882,7 @@ dependencies = [ [[package]] name = "trident-client" -version = "0.7.0" +version = "0.8.0" dependencies = [ "afl", "anchor-lang", @@ -5907,6 +5907,7 @@ dependencies = [ "thiserror", "tokio", "toml 0.8.19", + "trident-derive-accounts-snapshots", "trident-derive-displayix", "trident-derive-fuzz-test-executor", "trident-fuzz", @@ -5914,7 +5915,7 @@ dependencies = [ [[package]] name = "trident-derive-accounts-snapshots" -version = "0.0.1" +version = "0.0.2" dependencies = [ "anchor-syn", "convert_case", @@ -5925,7 +5926,7 @@ dependencies = [ [[package]] name = "trident-derive-displayix" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5934,7 +5935,7 @@ dependencies = [ [[package]] name = "trident-derive-fuzz-test-executor" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5943,7 +5944,7 @@ dependencies = [ [[package]] name = "trident-fuzz" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anchor-lang", "anyhow", diff --git a/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 4c5d1fa18..e1ad8c29e 100644 --- a/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -70,18 +70,15 @@ impl<'info> IxOps<'info> for InitializeFn { 5 * LAMPORTS_PER_SOL, ); - let hello_world_account = fuzz_accounts - .hello_world_account - .get_or_create_account( - self.accounts.hello_world_account, - &[b"hello_world_seed"], - &hello_world::ID, - ) - .unwrap(); + let hello_world_account = fuzz_accounts.hello_world_account.get_or_create_account( + self.accounts.hello_world_account, + &[b"hello_world_seed"], + &hello_world::ID, + ); let signers = vec![author.clone()]; let acc_meta = hello_world::accounts::InitializeContext { author: author.pubkey(), - hello_world_account: hello_world_account.pubkey(), + hello_world_account, system_program: solana_sdk::system_program::ID, } .to_account_metas(None); diff --git a/examples/fuzz-tests/incorrect-integer-arithmetic-3/Trident.toml b/examples/fuzz-tests/incorrect-integer-arithmetic-3/Trident.toml index b976b8222..f4f804949 100644 --- a/examples/fuzz-tests/incorrect-integer-arithmetic-3/Trident.toml +++ b/examples/fuzz-tests/incorrect-integer-arithmetic-3/Trident.toml @@ -2,7 +2,7 @@ # Timeout in seconds (default: 10) timeout = 10 # Number of fuzzing iterations (default: 0 [no limit]) -iterations = 0 +iterations = 1000 # Number of concurrent fuzzing threads (default: 0 [number of CPUs / 2]) threads = 0 # Don't close children's stdin, stdout, stderr; can be noisy (default: false) @@ -34,4 +34,4 @@ save_all = false allow_duplicate_txs = false # Trident will show statistics after the fuzzing session. This option forces use of honggfuzz parameter # `keep_output` as true in order to be able to catch fuzzer stdout. (default: false) -fuzzing_with_stats = false +fuzzing_with_stats = true diff --git a/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 59a0951fe..8959fc205 100644 --- a/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -122,57 +122,47 @@ impl<'info> IxOps<'info> for InitVesting { // and also we can easily link to Withdraw let mint = fuzz_accounts .mint - .get_or_create_account(0, client, 6, &sender.pubkey(), None) - .unwrap(); + .get_or_create_account(0, client, 6, &sender.pubkey(), None); - let sender_token_account = fuzz_accounts - .sender_token_account - .get_or_create_account( - self.accounts.sender_token_account, - client, - mint, - sender.pubkey(), - u64::MAX, - None, - None, - 0, - None, - ) - .unwrap(); + let sender_token_account = fuzz_accounts.sender_token_account.get_or_create_account( + self.accounts.sender_token_account, + client, + mint, + sender.pubkey(), + u64::MAX, + None, + None, + 0, + None, + ); let recipient = fuzz_accounts.recipient.get_or_create_account( self.data.recipient, client, 10 * LAMPORTS_PER_SOL, ); - let escrow = fuzz_accounts - .escrow - .get_or_create_account( - self.accounts.escrow, - &[recipient.pubkey().as_ref(), b"ESCROW_SEED"], - &incorrect_integer_arithmetic_3::ID, - ) - .unwrap(); + let escrow = fuzz_accounts.escrow.get_or_create_account( + self.accounts.escrow, + &[recipient.pubkey().as_ref(), b"ESCROW_SEED"], + &incorrect_integer_arithmetic_3::ID, + ); - let escrow_token_account = fuzz_accounts - .escrow_token_account - .get_or_create_account( - self.accounts.escrow_token_account, - client, - mint, - sender.pubkey(), - 0, - None, - None, - 0, - None, - ) - .unwrap(); + let escrow_token_account = fuzz_accounts.escrow_token_account.get_or_create_account( + self.accounts.escrow_token_account, + client, + mint, + sender.pubkey(), + 0, + None, + None, + 0, + None, + ); let acc_meta = incorrect_integer_arithmetic_3::accounts::InitVesting { sender: sender.pubkey(), sender_token_account, - escrow: escrow.pubkey(), + escrow, escrow_token_account, mint, token_program: anchor_spl::token::ID, @@ -223,65 +213,53 @@ impl<'info> IxOps<'info> for WithdrawUnlocked { // INFO use constant Account ID, so we will not generate multiple mints, // and also we can easily link to Initialize - let mint = fuzz_accounts - .mint - .get_or_create_account(0, client, 6, &recipient.pubkey(), None) - .unwrap(); + let mint = + fuzz_accounts + .mint + .get_or_create_account(0, client, 6, &recipient.pubkey(), None); - let recipient_token_account = fuzz_accounts - .recipient_token_account - .get_or_create_account( - self.accounts.recipient_token_account, - client, - mint, - recipient.pubkey(), - 0, - None, - None, - 0, - None, - ) - .unwrap(); + let recipient_token_account = fuzz_accounts.recipient_token_account.get_or_create_account( + self.accounts.recipient_token_account, + client, + mint, + recipient.pubkey(), + 0, + None, + None, + 0, + None, + ); - let escrow = fuzz_accounts - .escrow - .get_or_create_account( - self.accounts.escrow, - &[recipient.pubkey().as_ref(), b"ESCROW_SEED"], - &incorrect_integer_arithmetic_3::ID, - ) - .unwrap(); + let escrow = fuzz_accounts.escrow.get_or_create_account( + self.accounts.escrow, + &[recipient.pubkey().as_ref(), b"ESCROW_SEED"], + &incorrect_integer_arithmetic_3::ID, + ); - let escrow_pda_authority = fuzz_accounts - .escrow_pda_authority - .get_or_create_account( - self.accounts.escrow_pda_authority, - &[b"ESCROW_PDA_AUTHORITY"], - &incorrect_integer_arithmetic_3::ID, - ) - .unwrap(); + let escrow_pda_authority = fuzz_accounts.escrow_pda_authority.get_or_create_account( + self.accounts.escrow_pda_authority, + &[b"ESCROW_PDA_AUTHORITY"], + &incorrect_integer_arithmetic_3::ID, + ); - let escrow_token_account = fuzz_accounts - .escrow_token_account - .get_or_create_account( - self.accounts.escrow_token_account, - client, - mint, - escrow_pda_authority.pubkey(), - u64::MAX, - None, - None, - 0, - None, - ) - .unwrap(); + let escrow_token_account = fuzz_accounts.escrow_token_account.get_or_create_account( + self.accounts.escrow_token_account, + client, + mint, + escrow_pda_authority, + u64::MAX, + None, + None, + 0, + None, + ); let acc_meta = incorrect_integer_arithmetic_3::accounts::WithdrawUnlocked { recipient: recipient.pubkey(), recipient_token_account, - escrow: escrow.pubkey(), + escrow, escrow_token_account, - escrow_pda_authority: escrow_pda_authority.pubkey(), + escrow_pda_authority, mint, token_program: anchor_spl::token::ID, system_program: solana_sdk::system_program::ID, diff --git a/examples/fuzz-tests/incorrect-ix-sequence-1/Cargo.lock b/examples/fuzz-tests/incorrect-ix-sequence-1/Cargo.lock index ed03d9ef2..b76f34ebc 100644 --- a/examples/fuzz-tests/incorrect-ix-sequence-1/Cargo.lock +++ b/examples/fuzz-tests/incorrect-ix-sequence-1/Cargo.lock @@ -5873,7 +5873,7 @@ dependencies = [ [[package]] name = "trident-client" -version = "0.7.0" +version = "0.8.0" dependencies = [ "afl", "anchor-lang", @@ -5898,6 +5898,7 @@ dependencies = [ "thiserror", "tokio", "toml 0.8.19", + "trident-derive-accounts-snapshots", "trident-derive-displayix", "trident-derive-fuzz-test-executor", "trident-fuzz", @@ -5905,7 +5906,7 @@ dependencies = [ [[package]] name = "trident-derive-accounts-snapshots" -version = "0.0.1" +version = "0.0.2" dependencies = [ "anchor-syn", "convert_case", @@ -5916,7 +5917,7 @@ dependencies = [ [[package]] name = "trident-derive-displayix" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5925,7 +5926,7 @@ dependencies = [ [[package]] name = "trident-derive-fuzz-test-executor" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5934,7 +5935,7 @@ dependencies = [ [[package]] name = "trident-fuzz" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anchor-lang", "anyhow", diff --git a/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 9cee12e63..d66bb03d5 100644 --- a/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -133,15 +133,11 @@ impl<'info> IxOps<'info> for EndRegistrations { 5 * LAMPORTS_PER_SOL, ); let signers = vec![author.clone()]; - let state = fuzz_accounts - .state - .get_or_create_account( - self.accounts.state, - &[author.pubkey().as_ref(), STATE_SEED.as_ref()], - &incorrect_ix_sequence_1::ID, - ) - .ok_or(FuzzingError::Custom(4))? - .pubkey(); + let state = fuzz_accounts.state.get_or_create_account( + self.accounts.state, + &[author.pubkey().as_ref(), STATE_SEED.as_ref()], + &incorrect_ix_sequence_1::ID, + ); let acc_meta = incorrect_ix_sequence_1::accounts::EndRegistration { author: author.pubkey(), state, @@ -188,16 +184,11 @@ impl<'info> IxOps<'info> for Initialize { 5 * LAMPORTS_PER_SOL, ); let signers = vec![author.clone()]; - let state = fuzz_accounts - .state - .get_or_create_account( - self.accounts.state, - &[author.pubkey().as_ref(), STATE_SEED.as_ref()], - &incorrect_ix_sequence_1::ID, - ) - .ok_or(FuzzingError::Custom(1))? - .pubkey(); - + let state = fuzz_accounts.state.get_or_create_account( + self.accounts.state, + &[author.pubkey().as_ref(), STATE_SEED.as_ref()], + &incorrect_ix_sequence_1::ID, + ); let acc_meta = incorrect_ix_sequence_1::accounts::Initialize { author: author.pubkey(), state, @@ -253,29 +244,21 @@ impl<'info> IxOps<'info> for Invest { client, 5 * LAMPORTS_PER_SOL, ); - let state = fuzz_accounts - .state - .get_or_create_account( - self.accounts.state, - &[project_author.pubkey().as_ref(), STATE_SEED.as_ref()], - &incorrect_ix_sequence_1::ID, - ) - .ok_or(FuzzingError::Custom(5))? - .pubkey(); + let state = fuzz_accounts.state.get_or_create_account( + self.accounts.state, + &[project_author.pubkey().as_ref(), STATE_SEED.as_ref()], + &incorrect_ix_sequence_1::ID, + ); - let project = fuzz_accounts - .project - .get_or_create_account( - self.accounts.project, - &[ - project_author.pubkey().as_ref(), - state.as_ref(), - PROJECT_SEED.as_ref(), - ], - &incorrect_ix_sequence_1::ID, - ) - .ok_or(FuzzingError::Custom(6))? - .pubkey(); + let project = fuzz_accounts.project.get_or_create_account( + self.accounts.project, + &[ + project_author.pubkey().as_ref(), + state.as_ref(), + PROJECT_SEED.as_ref(), + ], + &incorrect_ix_sequence_1::ID, + ); let acc_meta = incorrect_ix_sequence_1::accounts::Invest { investor: investor.pubkey(), project, @@ -324,29 +307,21 @@ impl<'info> IxOps<'info> for Register { 5 * LAMPORTS_PER_SOL, ); let signers = vec![project_author.clone()]; - let state = fuzz_accounts - .state - .get_or_create_account( - self.accounts.state, - &[project_author.pubkey().as_ref(), STATE_SEED.as_ref()], - &incorrect_ix_sequence_1::ID, - ) - .ok_or(FuzzingError::Custom(2))? - .pubkey(); + let state = fuzz_accounts.state.get_or_create_account( + self.accounts.state, + &[project_author.pubkey().as_ref(), STATE_SEED.as_ref()], + &incorrect_ix_sequence_1::ID, + ); - let project = fuzz_accounts - .project - .get_or_create_account( - self.accounts.project, - &[ - project_author.pubkey().as_ref(), - state.as_ref(), - PROJECT_SEED.as_ref(), - ], - &incorrect_ix_sequence_1::ID, - ) - .ok_or(FuzzingError::Custom(3))? - .pubkey(); + let project = fuzz_accounts.project.get_or_create_account( + self.accounts.project, + &[ + project_author.pubkey().as_ref(), + state.as_ref(), + PROJECT_SEED.as_ref(), + ], + &incorrect_ix_sequence_1::ID, + ); let acc_meta = incorrect_ix_sequence_1::accounts::Register { project_author: project_author.pubkey(), diff --git a/examples/fuzz-tests/simple-cpi-6/Cargo.lock b/examples/fuzz-tests/simple-cpi-6/Cargo.lock index f09db6fee..178c83386 100644 --- a/examples/fuzz-tests/simple-cpi-6/Cargo.lock +++ b/examples/fuzz-tests/simple-cpi-6/Cargo.lock @@ -5890,7 +5890,7 @@ dependencies = [ [[package]] name = "trident-client" -version = "0.7.0" +version = "0.8.0" dependencies = [ "afl", "anchor-lang", @@ -5915,6 +5915,7 @@ dependencies = [ "thiserror", "tokio", "toml 0.8.19", + "trident-derive-accounts-snapshots", "trident-derive-displayix", "trident-derive-fuzz-test-executor", "trident-fuzz", @@ -5922,7 +5923,7 @@ dependencies = [ [[package]] name = "trident-derive-accounts-snapshots" -version = "0.0.1" +version = "0.0.2" dependencies = [ "anchor-syn", "convert_case", @@ -5933,7 +5934,7 @@ dependencies = [ [[package]] name = "trident-derive-displayix" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5942,7 +5943,7 @@ dependencies = [ [[package]] name = "trident-derive-fuzz-test-executor" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5951,7 +5952,7 @@ dependencies = [ [[package]] name = "trident-fuzz" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anchor-lang", "anyhow", diff --git a/examples/fuzz-tests/simple-cpi-6/Trident.toml b/examples/fuzz-tests/simple-cpi-6/Trident.toml index 6de0eb954..2c1032328 100644 --- a/examples/fuzz-tests/simple-cpi-6/Trident.toml +++ b/examples/fuzz-tests/simple-cpi-6/Trident.toml @@ -34,4 +34,4 @@ save_all = false allow_duplicate_txs = false # Trident will show statistics after the fuzzing session. This option forces use of honggfuzz parameter # `keep_output` as true in order to be able to catch fuzzer stdout. (default: false) -fuzzing_with_stats = false +fuzzing_with_stats = true diff --git a/examples/fuzz-tests/unauthorized-access-2/Cargo.lock b/examples/fuzz-tests/unauthorized-access-2/Cargo.lock index 562f28909..42c994149 100644 --- a/examples/fuzz-tests/unauthorized-access-2/Cargo.lock +++ b/examples/fuzz-tests/unauthorized-access-2/Cargo.lock @@ -5870,7 +5870,7 @@ dependencies = [ [[package]] name = "trident-client" -version = "0.7.0" +version = "0.8.0" dependencies = [ "afl", "anchor-lang", @@ -5895,6 +5895,7 @@ dependencies = [ "thiserror", "tokio", "toml 0.8.19", + "trident-derive-accounts-snapshots", "trident-derive-displayix", "trident-derive-fuzz-test-executor", "trident-fuzz", @@ -5902,7 +5903,7 @@ dependencies = [ [[package]] name = "trident-derive-accounts-snapshots" -version = "0.0.1" +version = "0.0.2" dependencies = [ "anchor-syn", "convert_case", @@ -5913,7 +5914,7 @@ dependencies = [ [[package]] name = "trident-derive-displayix" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5922,7 +5923,7 @@ dependencies = [ [[package]] name = "trident-derive-fuzz-test-executor" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5931,7 +5932,7 @@ dependencies = [ [[package]] name = "trident-fuzz" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anchor-lang", "anyhow", diff --git a/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index c2a1cc76c..2b9195007 100644 --- a/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -105,21 +105,18 @@ impl<'info> IxOps<'info> for Initialize { 10 * LAMPORTS_PER_SOL, ); - let escrow = fuzz_accounts - .escrow - .get_or_create_account( - self.accounts.escrow, - &[ - author.pubkey().as_ref(), - receiver.pubkey().as_ref(), - ESCROW_SEED.as_ref(), - ], - &unauthorized_access_2::ID, - ) - .unwrap(); + let escrow = fuzz_accounts.escrow.get_or_create_account( + self.accounts.escrow, + &[ + author.pubkey().as_ref(), + receiver.pubkey().as_ref(), + ESCROW_SEED.as_ref(), + ], + &unauthorized_access_2::ID, + ); let acc_meta = unauthorized_access_2::accounts::Initialize { author: author.pubkey(), - escrow: escrow.pubkey(), + escrow, system_program: solana_sdk::system_program::ID, } .to_account_metas(None); @@ -164,22 +161,19 @@ impl<'info> IxOps<'info> for Withdraw { 10 * LAMPORTS_PER_SOL, ); - let escrow = fuzz_accounts - .escrow - .get_or_create_account( - self.accounts.escrow, - &[ - receiver.pubkey().as_ref(), - receiver.pubkey().as_ref(), - ESCROW_SEED.as_ref(), - ], - &unauthorized_access_2::ID, - ) - .unwrap(); + let escrow = fuzz_accounts.escrow.get_or_create_account( + self.accounts.escrow, + &[ + receiver.pubkey().as_ref(), + receiver.pubkey().as_ref(), + ESCROW_SEED.as_ref(), + ], + &unauthorized_access_2::ID, + ); let acc_meta = unauthorized_access_2::accounts::Withdraw { receiver: receiver.pubkey(), - escrow: escrow.pubkey(), + escrow, system_program: solana_sdk::system_program::ID, } .to_account_metas(None); diff --git a/examples/fuzz-tests/unchecked-arithmetic-0/Cargo.lock b/examples/fuzz-tests/unchecked-arithmetic-0/Cargo.lock index 5d63f94ca..222bad3a4 100644 --- a/examples/fuzz-tests/unchecked-arithmetic-0/Cargo.lock +++ b/examples/fuzz-tests/unchecked-arithmetic-0/Cargo.lock @@ -971,9 +971,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.17.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7daec1a2a2129eeba1644b220b4647ec537b0b5d4bfd6876fcc5a540056b592" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", @@ -5766,7 +5766,6 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "indexmap 1.9.3", "serde", ] @@ -5776,6 +5775,7 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ + "indexmap 2.4.0", "serde", "serde_spanned", "toml_datetime", @@ -5880,7 +5880,7 @@ dependencies = [ [[package]] name = "trident-client" -version = "0.7.0" +version = "0.8.0" dependencies = [ "afl", "anchor-lang", @@ -5889,27 +5889,22 @@ dependencies = [ "anyhow", "arbitrary", "bincode", - "borsh 0.10.3", "cargo_metadata", "convert_case", "fehler", "futures", "honggfuzz", - "indicatif", - "log", "pathdiff", - "proc-macro2", "quinn-proto", "quote", - "regex", "serde", "serde_json", "solana-program-test", "solana-sdk", - "syn 1.0.109", + "syn 2.0.76", "thiserror", "tokio", - "toml 0.5.11", + "toml 0.8.19", "trident-derive-accounts-snapshots", "trident-derive-displayix", "trident-derive-fuzz-test-executor", @@ -5918,7 +5913,7 @@ dependencies = [ [[package]] name = "trident-derive-accounts-snapshots" -version = "0.0.1" +version = "0.0.2" dependencies = [ "anchor-syn", "convert_case", @@ -5929,7 +5924,7 @@ dependencies = [ [[package]] name = "trident-derive-displayix" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5938,7 +5933,7 @@ dependencies = [ [[package]] name = "trident-derive-fuzz-test-executor" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro2", "quote", @@ -5947,7 +5942,7 @@ dependencies = [ [[package]] name = "trident-fuzz" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anchor-lang", "anyhow", @@ -5955,7 +5950,6 @@ dependencies = [ "fehler", "prettytable", "rand 0.8.5", - "regex", "serde", "serde_json", "solana-banks-client", @@ -5965,7 +5959,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", - "toml 0.5.11", + "toml 0.8.19", ] [[package]] From ec9b597770b08f4c696c028d8c5c1ecf41983469 Mon Sep 17 00:00:00 2001 From: lukacan Date: Thu, 24 Oct 2024 12:13:20 +0200 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20stake=20a?= =?UTF-8?q?nd=20vote=20accounts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/fuzz/src/accounts_storage.rs | 96 +++++++++++- crates/fuzz/src/fuzz_client.rs | 37 +++++ .../fuzz/src/program_test_client_blocking.rs | 143 ++++++++++++++++++ 3 files changed, 275 insertions(+), 1 deletion(-) diff --git a/crates/fuzz/src/accounts_storage.rs b/crates/fuzz/src/accounts_storage.rs index 2b5106a8f..37b804a3a 100644 --- a/crates/fuzz/src/accounts_storage.rs +++ b/crates/fuzz/src/accounts_storage.rs @@ -1,7 +1,12 @@ #![allow(dead_code)] use std::collections::HashMap; -use solana_sdk::{pubkey::Pubkey, signature::Keypair}; +use solana_sdk::{ + clock::{Clock, Epoch}, + pubkey::Pubkey, + signature::Keypair, + stake::state::Lockup, +}; use crate::{fuzz_client::FuzzClient, AccountId}; @@ -26,6 +31,13 @@ pub struct MintStore { pub struct ProgramStore { pub pubkey: u8, } +pub struct VoteAccountStore { + pub pubkey: Pubkey, +} + +pub struct StakeAccountStore { + pub pubkey: Pubkey, +} pub struct AccountsStorage { accounts: HashMap, @@ -164,3 +176,85 @@ impl AccountsStorage { } } } + +impl AccountsStorage { + #[allow(clippy::too_many_arguments)] + pub fn get_or_create_account( + &mut self, + account_id: AccountId, + client: &mut impl FuzzClient, + node_pubkey: &Pubkey, + authorized_voter: &Pubkey, + authorized_withdrawer: &Pubkey, + commission: u8, + clock: &Clock, + ) -> Pubkey { + let key = self.accounts.entry(account_id).or_insert_with(|| { + let key = client.set_vote_account( + node_pubkey, + authorized_voter, + authorized_withdrawer, + commission, + clock, + ); + VoteAccountStore { pubkey: key } + }); + key.pubkey + } + pub fn get(&self, account_id: AccountId) -> Pubkey { + match self.accounts.get(&account_id) { + Some(v) => v.pubkey, + None => Pubkey::default(), + } + } +} + +impl AccountsStorage { + #[allow(clippy::too_many_arguments)] + pub fn get_or_create_delegated_account( + &mut self, + account_id: AccountId, + client: &mut impl FuzzClient, + voter_pubkey: Pubkey, + staker: Pubkey, + withdrawer: Pubkey, + stake: u64, + activation_epoch: Epoch, + deactivation_epoch: Option, + lockup: Option, + ) -> Pubkey { + let key = self.accounts.entry(account_id).or_insert_with(|| { + let key = client.set_delegated_stake_account( + voter_pubkey, + staker, + withdrawer, + stake, + activation_epoch, + deactivation_epoch, + lockup, + ); + StakeAccountStore { pubkey: key } + }); + key.pubkey + } + pub fn get_or_create_initialized_account( + &mut self, + account_id: AccountId, + client: &mut impl FuzzClient, + staker: Pubkey, + withdrawer: Pubkey, + lockup: Option, + ) -> Pubkey { + let key = self.accounts.entry(account_id).or_insert_with(|| { + let key = client.set_initialized_stake_account(staker, withdrawer, lockup); + StakeAccountStore { pubkey: key } + }); + key.pubkey + } + pub fn get(&self, account_id: AccountId) -> Pubkey { + match self.accounts.get(&account_id) { + Some(v) => v.pubkey, + None => Pubkey::default(), + } + } +} diff --git a/crates/fuzz/src/fuzz_client.rs b/crates/fuzz/src/fuzz_client.rs index 3106b2286..87880121b 100644 --- a/crates/fuzz/src/fuzz_client.rs +++ b/crates/fuzz/src/fuzz_client.rs @@ -4,15 +4,52 @@ use anchor_lang::prelude::Rent; use anchor_lang::solana_program::hash::Hash; use solana_sdk::account::{Account, AccountSharedData}; +use solana_sdk::clock::{Clock, Epoch}; use solana_sdk::instruction::AccountMeta; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::Keypair; +use solana_sdk::stake::state::Lockup; +use solana_sdk::sysvar::Sysvar; use solana_sdk::transaction::VersionedTransaction; use crate::error::*; /// A trait providing methods to read and write (manipulate) accounts pub trait FuzzClient { + /// Create a initialzied stake account + fn set_initialized_stake_account( + &mut self, + staker: Pubkey, + withdrawer: Pubkey, + lockup: Option, + ) -> Pubkey; + + /// Create a delegated stake account + #[allow(clippy::too_many_arguments)] + fn set_delegated_stake_account( + &mut self, + voter_pubkey: Pubkey, // vote account delegated to + staker: Pubkey, + withdrawer: Pubkey, + stake: u64, + activation_epoch: Epoch, + deactivation_epoch: Option, + lockup: Option, + ) -> Pubkey; + + /// Get the cluster rent + fn get_sysvar(&mut self) -> T; + + /// Create a vote account + fn set_vote_account( + &mut self, + node_pubkey: &Pubkey, // validator identity + authorized_voter: &Pubkey, + authorized_withdrawer: &Pubkey, + commission: u8, + clock: &Clock, + ) -> Pubkey; + /// Warp to specific epoch fn warp_to_epoch(&mut self, warp_epoch: u64); diff --git a/crates/fuzz/src/program_test_client_blocking.rs b/crates/fuzz/src/program_test_client_blocking.rs index fc9f57ca5..748abaded 100644 --- a/crates/fuzz/src/program_test_client_blocking.rs +++ b/crates/fuzz/src/program_test_client_blocking.rs @@ -2,10 +2,24 @@ use solana_program_runtime::invoke_context::BuiltinFunctionWithContext; use solana_program_test::ProgramTest; use solana_program_test::ProgramTestContext; use solana_sdk::account::Account; +use solana_sdk::account::WritableAccount; use solana_sdk::account_info::AccountInfo; use solana_sdk::clock::Clock; +use solana_sdk::clock::Epoch; use solana_sdk::entrypoint::ProgramResult; +use solana_sdk::native_token::LAMPORTS_PER_SOL; +use solana_sdk::stake::stake_flags::StakeFlags; +use solana_sdk::stake::state::Authorized; +use solana_sdk::stake::state::Delegation; +use solana_sdk::stake::state::Lockup; +use solana_sdk::stake::state::Meta; +use solana_sdk::stake::state::Stake; +use solana_sdk::stake::state::StakeStateV2; use solana_sdk::system_program::ID as SYSTEM_PROGRAM_ID; +use solana_sdk::sysvar::Sysvar; +use solana_sdk::vote::state::VoteInit; +use solana_sdk::vote::state::VoteState; +use solana_sdk::vote::state::VoteStateVersions; use solana_sdk::{ account::AccountSharedData, hash::Hash, instruction::AccountMeta, program_option::COption, program_pack::Pack, pubkey::Pubkey, rent::Rent, signature::Keypair, signature::Signer, @@ -106,6 +120,45 @@ macro_rules! convert_entry { } impl FuzzClient for ProgramTestClientBlocking { + fn set_vote_account( + &mut self, + node_pubkey: &Pubkey, + authorized_voter: &Pubkey, + authorized_withdrawer: &Pubkey, + commission: u8, + clock: &Clock, + ) -> Pubkey { + let vote_account = Keypair::new(); + + let rent = Rent::default(); + let lamports = rent.minimum_balance(VoteState::size_of()); + let mut account = AccountSharedData::new( + lamports, + VoteState::size_of(), + &solana_sdk::vote::program::ID, + ); + + let vote_state = VoteState::new( + &VoteInit { + node_pubkey: *node_pubkey, + authorized_voter: *authorized_voter, + authorized_withdrawer: *authorized_withdrawer, + commission, + }, + clock, + ); + + VoteState::serialize( + &VoteStateVersions::Current(Box::new(vote_state)), + account.data_as_mut_slice(), + ) + .unwrap(); + + self.ctx.set_account(&vote_account.pubkey(), &account); + + vote_account.pubkey() + } + fn set_account(&mut self, lamports: u64) -> Keypair { let owner = Keypair::new(); let account = AccountSharedData::new(lamports, 0, &SYSTEM_PROGRAM_ID); @@ -266,4 +319,94 @@ impl FuzzClient for ProgramTestClientBlocking { fn warp_to_epoch(&mut self, warp_epoch: u64) { let _ = self.ctx.warp_to_epoch(warp_epoch); } + fn get_sysvar(&mut self) -> T { + match self.rt.block_on(self.ctx.banks_client.get_sysvar::()) { + Ok(sysvar) => sysvar, + Err(_) => T::default(), + } + } + fn set_delegated_stake_account( + &mut self, + voter_pubkey: Pubkey, // vote account delegated to + staker: Pubkey, + withdrawer: Pubkey, + stake: u64, + activation_epoch: Epoch, + deactivation_epoch: Option, + lockup: Option, + ) -> Pubkey { + let stake_account = Keypair::new(); + + let rent = Rent::default(); + let rent_exempt_lamports = rent.minimum_balance(StakeStateV2::size_of()); + let minimum_delegation = LAMPORTS_PER_SOL; // TODO: a way to get minimum delegation with feature set? + let minimum_lamports = rent_exempt_lamports.saturating_add(minimum_delegation); + + let stake_state = StakeStateV2::Stake( + Meta { + authorized: Authorized { staker, withdrawer }, + lockup: lockup.unwrap_or_default(), + rent_exempt_reserve: rent_exempt_lamports, + }, + Stake { + delegation: Delegation { + stake, + activation_epoch, + voter_pubkey, + deactivation_epoch: if let Some(epoch) = deactivation_epoch { + epoch + } else { + u64::MAX + }, + ..Delegation::default() + }, + ..Stake::default() + }, + StakeFlags::default(), + ); + let account = AccountSharedData::new_data_with_space( + if stake > minimum_lamports { + stake + } else { + minimum_lamports + }, + &stake_state, + StakeStateV2::size_of(), + &solana_sdk::stake::program::ID, + ) + .unwrap(); + + self.ctx.set_account(&stake_account.pubkey(), &account); + + stake_account.pubkey() + } + + fn set_initialized_stake_account( + &mut self, + staker: Pubkey, + withdrawer: Pubkey, + lockup: Option, + ) -> Pubkey { + let stake_account = Keypair::new(); + + let rent = Rent::default(); + let rent_exempt_lamports = rent.minimum_balance(StakeStateV2::size_of()); + + let stake_state = StakeStateV2::Initialized(Meta { + authorized: Authorized { staker, withdrawer }, + lockup: lockup.unwrap_or_default(), + rent_exempt_reserve: rent_exempt_lamports, + }); + let account = AccountSharedData::new_data_with_space( + rent_exempt_lamports, + &stake_state, + StakeStateV2::size_of(), + &solana_sdk::stake::program::ID, + ) + .unwrap(); + + self.ctx.set_account(&stake_account.pubkey(), &account); + + stake_account.pubkey() + } } From 5da85419f050ff149e19e045485ce036d1767eb6 Mon Sep 17 00:00:00 2001 From: lukacan Date: Thu, 31 Oct 2024 10:51:29 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=E2=9C=A8=20Set=20custom=20+=20some=20addit?= =?UTF-8?q?ional=20docs=20updates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 + .../fuzz_instructions_generator.rs | 13 +- .../test_fuzz_generator.rs | 2 +- .../expected_fuzz_instructions.rs | 16 +- .../expected_test_fuzz.rs | 2 +- crates/fuzz/src/accounts_storage.rs | 84 ++++++++- .../docs/features/account-storages.md | 3 + .../docs/features/fuzz-instructions.md | 168 ++++++------------ 8 files changed, 155 insertions(+), 137 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6bacccd0..3ff4c62ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ incremented upon a breaking change and the patch version will be incremented for ## [dev] - Unreleased +**Changed** + +- improve manipulations with AccountsStorages in get_accounts() function ([219](https://github.com/Ackee-Blockchain/trident/pull/219)) + **Added** - add/ add support for Clock sysvar manipulations with the client(i.e. warp to slot/epoch and forward in time) ([217](https://github.com/Ackee-Blockchain/trident/pull/217)) diff --git a/crates/client/src/source_code_generators/fuzz_instructions_generator.rs b/crates/client/src/source_code_generators/fuzz_instructions_generator.rs index 951ac7f73..5c2c120cf 100644 --- a/crates/client/src/source_code_generators/fuzz_instructions_generator.rs +++ b/crates/client/src/source_code_generators/fuzz_instructions_generator.rs @@ -49,8 +49,8 @@ pub fn generate_source_code(idls: &[Idl]) -> String { #(#all_instructions_ixops_impls)* - /// Use AccountsStorage where T can be one of: - /// Keypair, PdaStore, TokenStore, MintStore, ProgramStore + /// Check supported AccountsStorages at + /// https://ackee.xyz/trident/docs/latest/features/account-storages/ #[derive(Default)] pub struct FuzzAccounts { #(#all_fuzz_accounts),* @@ -219,7 +219,7 @@ fn get_instruction_inputs( /// Custom data types must derive `Debug` and `Arbitrary`. /// To do this, redefine the type in the fuzz test and implement the `From` trait /// to convert it into the type defined in the program. - /// For more details, see: https://ackee.xyz/trident/docs/dev/features/arbitrary-data/#custom-data-types + /// For more details, see: https://ackee.xyz/trident/docs/latest/features/fuzz-instructions/#custom-data-types #[derive(Arbitrary, Debug)] pub struct #instruction_data_name { #(pub #parameters),* @@ -309,7 +309,7 @@ fn get_instruction_ixops( /// Definition of the Instruction data. /// Use randomly generated data from the fuzzer using `self.data.arg_name` /// or customize the data as needed. - /// For more details, visit: https://ackee.xyz/trident/docs/dev/features/fuzz-instructions/#get-data + /// For more details, visit: https://ackee.xyz/trident/docs/latest/features/fuzz-instructions/#get-data fn get_data( &self, _client: &mut impl FuzzClient, @@ -322,10 +322,11 @@ fn get_instruction_ixops( } /// Definition of of the accounts required by the Instruction. - /// To utilize accounts stored in `FuzzAccounts`, use `fuzz_accounts.account_name.get_or_create_account()`. + /// To utilize accounts stored in `FuzzAccounts`, use + /// `fuzz_accounts.account_name.get_or_create_account()`. /// If no signers are required, leave the vector empty. /// For AccountMetas use ::accounts:: - /// For more details, see: https://ackee.xyz/trident/docs/dev/features/fuzz-instructions/#get-accounts + /// For more details, see: https://ackee.xyz/trident/docs/latest/features/fuzz-instructions/#get-accounts fn get_accounts( &self, client: &mut impl FuzzClient, diff --git a/crates/client/src/source_code_generators/test_fuzz_generator.rs b/crates/client/src/source_code_generators/test_fuzz_generator.rs index 0df0cdaac..8f521f1e9 100644 --- a/crates/client/src/source_code_generators/test_fuzz_generator.rs +++ b/crates/client/src/source_code_generators/test_fuzz_generator.rs @@ -29,7 +29,7 @@ pub fn generate_source_code(idl_instructions: &[Idl]) -> String { /// Ok(vec![init]) /// } /// ``` - /// For more details, see: https://ackee.xyz/trident/docs/dev/features/instructions-sequences/#instructions-sequences + /// For more details, see: https://ackee.xyz/trident/docs/latest/features/instructions-sequences/#instructions-sequences impl FuzzDataBuilder for MyFuzzData {} /// `fn fuzz_iteration` runs during every fuzzing iteration. diff --git a/crates/client/tests/expected_source_codes/expected_fuzz_instructions.rs b/crates/client/tests/expected_source_codes/expected_fuzz_instructions.rs index 08208d17e..de2762509 100644 --- a/crates/client/tests/expected_source_codes/expected_fuzz_instructions.rs +++ b/crates/client/tests/expected_source_codes/expected_fuzz_instructions.rs @@ -23,7 +23,7 @@ pub struct InitializeIxDummy2Accounts { /// To do this, redefine the type in the fuzz test and implement the `From` /// trait /// to convert it into the type defined in the program. -/// For more details, see: https://ackee.xyz/trident/docs/dev/features/arbitrary-data/#custom-data-types +/// For more details, see: https://ackee.xyz/trident/docs/latest/features/fuzz-instructions/#custom-data-types #[derive(Arbitrary, Debug)] pub struct InitializeIxDummy2Data { pub _var1: bool, @@ -73,7 +73,7 @@ pub struct InitializeIxDummyExampleAccounts { /// To do this, redefine the type in the fuzz test and implement the `From` /// trait /// to convert it into the type defined in the program. -/// For more details, see: https://ackee.xyz/trident/docs/dev/features/arbitrary-data/#custom-data-types +/// For more details, see: https://ackee.xyz/trident/docs/latest/features/fuzz-instructions/#custom-data-types #[derive(Arbitrary, Debug)] pub struct InitializeIxDummyExampleData { pub _var1: bool, @@ -111,7 +111,7 @@ impl<'info> IxOps<'info> for InitializeIxDummy2 { /// Definition of the Instruction data. /// Use randomly generated data from the fuzzer using `self.data.arg_name` /// or customize the data as needed. - /// For more details, visit: https://ackee.xyz/trident/docs/dev/features/fuzz-instructions/#get-data + /// For more details, visit: https://ackee.xyz/trident/docs/latest/features/fuzz-instructions/#get-data fn get_data( &self, _client: &mut impl FuzzClient, @@ -148,7 +148,7 @@ impl<'info> IxOps<'info> for InitializeIxDummy2 { /// `fuzz_accounts.account_name.get_or_create_account()`. /// If no signers are required, leave the vector empty. /// For AccountMetas use ::accounts:: - /// For more details, see: https://ackee.xyz/trident/docs/dev/features/fuzz-instructions/#get-accounts + /// For more details, see: https://ackee.xyz/trident/docs/latest/features/fuzz-instructions/#get-accounts fn get_accounts( &self, client: &mut impl FuzzClient, @@ -172,7 +172,7 @@ impl<'info> IxOps<'info> for InitializeIxDummyExample { /// Definition of the Instruction data. /// Use randomly generated data from the fuzzer using `self.data.arg_name` /// or customize the data as needed. - /// For more details, visit: https://ackee.xyz/trident/docs/dev/features/fuzz-instructions/#get-data + /// For more details, visit: https://ackee.xyz/trident/docs/latest/features/fuzz-instructions/#get-data fn get_data( &self, _client: &mut impl FuzzClient, @@ -209,7 +209,7 @@ impl<'info> IxOps<'info> for InitializeIxDummyExample { /// `fuzz_accounts.account_name.get_or_create_account()`. /// If no signers are required, leave the vector empty. /// For AccountMetas use ::accounts:: - /// For more details, see: https://ackee.xyz/trident/docs/dev/features/fuzz-instructions/#get-accounts + /// For more details, see: https://ackee.xyz/trident/docs/latest/features/fuzz-instructions/#get-accounts fn get_accounts( &self, client: &mut impl FuzzClient, @@ -220,8 +220,8 @@ impl<'info> IxOps<'info> for InitializeIxDummyExample { Ok((signers, acc_meta)) } } -/// Use AccountsStorage where T can be one of: -/// Keypair, PdaStore, TokenStore, MintStore, ProgramStore +/// Check supported AccountsStorages at +/// https://ackee.xyz/trident/docs/latest/features/account-storages/ #[derive(Default)] pub struct FuzzAccounts { signer_dummy_2: AccountsStorage, diff --git a/crates/client/tests/expected_source_codes/expected_test_fuzz.rs b/crates/client/tests/expected_source_codes/expected_test_fuzz.rs index 342881434..ecb51ed6e 100644 --- a/crates/client/tests/expected_source_codes/expected_test_fuzz.rs +++ b/crates/client/tests/expected_source_codes/expected_test_fuzz.rs @@ -18,7 +18,7 @@ struct MyFuzzData; /// Ok(vec![init]) /// } /// ``` -/// For more details, see: https://ackee.xyz/trident/docs/dev/features/instructions-sequences/#instructions-sequences +/// For more details, see: https://ackee.xyz/trident/docs/latest/features/instructions-sequences/#instructions-sequences impl FuzzDataBuilder for MyFuzzData {} /// `fn fuzz_iteration` runs during every fuzzing iteration. /// Modification is not required. diff --git a/crates/fuzz/src/accounts_storage.rs b/crates/fuzz/src/accounts_storage.rs index 37b804a3a..65d33dbb2 100644 --- a/crates/fuzz/src/accounts_storage.rs +++ b/crates/fuzz/src/accounts_storage.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use solana_sdk::{ + account::AccountSharedData, clock::{Clock, Epoch}, pubkey::Pubkey, signature::Keypair, @@ -29,7 +30,7 @@ pub struct MintStore { } pub struct ProgramStore { - pub pubkey: u8, + pub pubkey: Pubkey, } pub struct VoteAccountStore { pub pubkey: Pubkey, @@ -53,9 +54,17 @@ impl AccountsStorage { } } - /// Returns a mutable reference to the underlying HashMap that stores accounts with IDs as keys - fn storage(&mut self) -> &mut HashMap { - &mut self.accounts + pub fn set_custom( + &mut self, + account_id: AccountId, + client: &mut impl FuzzClient, + address: Pubkey, + account: AccountSharedData, + ) where + T: From, + { + client.set_account_custom(&address, &account); + self.accounts.insert(account_id, T::from(address)); } } @@ -86,6 +95,63 @@ impl AccountsStorage { } } +impl AccountsStorage { + pub fn get_or_create_account( + &mut self, + account_id: AccountId, + _client: &mut impl FuzzClient, + program_id: Pubkey, + ) -> Pubkey { + let program_id = self + .accounts + .entry(account_id) + .or_insert_with(|| ProgramStore { pubkey: program_id }); + program_id.pubkey + } + pub fn get(&self, account_id: AccountId) -> Pubkey { + match self.accounts.get(&account_id) { + Some(v) => v.pubkey, + None => Pubkey::new_unique(), + } + } +} +impl From for TokenStore { + fn from(pubkey: Pubkey) -> Self { + TokenStore { pubkey } + } +} +impl From for MintStore { + fn from(pubkey: Pubkey) -> Self { + MintStore { pubkey } + } +} + +impl From for ProgramStore { + fn from(pubkey: Pubkey) -> Self { + ProgramStore { pubkey } + } +} + +impl From for VoteAccountStore { + fn from(pubkey: Pubkey) -> Self { + VoteAccountStore { pubkey } + } +} + +impl From for StakeAccountStore { + fn from(pubkey: Pubkey) -> Self { + StakeAccountStore { pubkey } + } +} +impl From for PdaStore { + fn from(pubkey: Pubkey) -> Self { + PdaStore { + pubkey, + seeds: Vec::new(), // Note: This creates empty seeds + } + } +} + impl AccountsStorage { #[allow(clippy::too_many_arguments)] pub fn get_or_create_account( @@ -140,7 +206,7 @@ impl AccountsStorage { pub fn get(&self, account_id: AccountId) -> Pubkey { match self.accounts.get(&account_id) { Some(v) => v.pubkey, - None => Pubkey::default(), + None => Pubkey::new_unique(), } } } @@ -164,7 +230,7 @@ impl AccountsStorage { self.accounts.insert(account_id, pda_store); key } else { - Pubkey::default() + Pubkey::new_unique() } } } @@ -172,7 +238,7 @@ impl AccountsStorage { pub fn get(&self, account_id: AccountId) -> Pubkey { match self.accounts.get(&account_id) { Some(v) => v.pubkey, - None => Pubkey::default(), + None => Pubkey::new_unique(), } } } @@ -204,7 +270,7 @@ impl AccountsStorage { pub fn get(&self, account_id: AccountId) -> Pubkey { match self.accounts.get(&account_id) { Some(v) => v.pubkey, - None => Pubkey::default(), + None => Pubkey::new_unique(), } } } @@ -254,7 +320,7 @@ impl AccountsStorage { pub fn get(&self, account_id: AccountId) -> Pubkey { match self.accounts.get(&account_id) { Some(v) => v.pubkey, - None => Pubkey::default(), + None => Pubkey::new_unique(), } } } diff --git a/documentation/docs/features/account-storages.md b/documentation/docs/features/account-storages.md index 35d276cba..94ec797a1 100644 --- a/documentation/docs/features/account-storages.md +++ b/documentation/docs/features/account-storages.md @@ -22,6 +22,9 @@ Instead, Trident generates random **AccountIDs** which are indexes to **Account - PDA - Token Account - Program account + - Stake account + - Vote account + Then use the corresponding AccountsStorage. diff --git a/documentation/docs/features/fuzz-instructions.md b/documentation/docs/features/fuzz-instructions.md index 9cea29906..ee1ca0bce 100644 --- a/documentation/docs/features/fuzz-instructions.md +++ b/documentation/docs/features/fuzz-instructions.md @@ -27,21 +27,21 @@ pub struct Update { Each Instruction variant has to define `IxOps` trait containing the following methods: -- `get_program_id()` (required) -- `get_data()` (required) -- `get_accounts()` (required) -- `check()` (optional) -- `tx_error_handler()` (optional) +- [`get_program_id()`](./fuzz-instructions.md/#get_program_id) (automatically implemented) +- [`get_data()`](./fuzz-instructions.md/#get_data) (required) +- [`get_accounts()`](./fuzz-instructions.md/#get_accounts) (required) +- [`check()`](./fuzz-instructions.md/#check) (optional) +- [`tx_error_handler()`](./fuzz-instructions.md/#tx_error_handler) (optional) - `deserialize_accounts()` (automatically implemented) -## Get Program ID +## `get_program_id()` This method specifies **program ID** to which the Instruction corresponds. In case you have only one program in the Anchor Workspace it is not really important. The importance occurs when you have multiple programs in the Workspace and you want to call Instructions of every Program. In that case each Instruction Variant corresponds to its program by the Program ID. -## Get Data +## `get_data()` This method specifies what the Instruction Input Data should look like. You can use completely random data generated by the fuzzer, such as: @@ -105,134 +105,78 @@ Then, you would also need to implement the [`std::convert::From`](https://doc Consider checking the [Examples](../examples/examples.md) section for more tips. -## Get Accounts +## `get_accounts()` This method specifies how the **Accounts** for the corresponding Instruction should be resolved. You can use accounts stored within the **FuzzAccounts Account Storages**, or you can define custom Account using the **client**. +There are two main functions to use within the `get_accounts()`: -!!! important +- [`get_or_create_account()`](./fuzz-instructions.md/#get_or_create_account) +- [`get()`](./fuzz-instructions.md/#get) +- [`set_custom()`](./fuzz-instructions.md/#set_custom) - Source Code below +### `get_or_create_account()` - - Take the author from the `FuzzAccounts` Account Storage author on `self.accounts.author` index. If Account on that index does not exist yet, it will be created and returned. In case it is already created, the corresponding Account will be returned. - - `hello_world_account` Account Storage is of type PdaStore, in this case `get_or_create_account` function do the same as for the authority, but you need to specify seeds to derive its PDA. - - Next, you need to specify signers if there should be any. - - Lastly, specify the Account Metas of the corresponding Instruction. - - for example `::accounts:: {}.to_account_metas(None);` +Insert a new record into AccountsStorage based on the `account_id`. If a record with the entered `account_id` already exists, it is returned, and no insertion is performed. -```rust -fn get_accounts( - &self, - client: &mut impl FuzzClient, - fuzz_accounts: &mut FuzzAccounts, -) -> Result<(Vec, Vec), FuzzingError> { - let author = fuzz_accounts.author.get_or_create_account( - self.accounts.author, - client, - 5 * LAMPORTS_PER_SOL, +!!! tip + + - This function is particularly useful for instructions that initialize accounts. + + Example: + + ```rust + let hello_world_account = fuzz_accounts.hello_world_account.get_or_create_account( + self.accounts.hello_world_account, + &[b"hello_world_seed"], + &hello_world::ID, ); + ``` + The code above will return the PDA from `hello_world`'s AccountsStorage if a record for the entered `account_id` exists. If not, the function will create a new record corresponding to the PDA derived from the provided seeds and return the PDA. - let hello_world_account = fuzz_accounts - .hello_world_account - .get_or_create_account( - self.accounts.hello_world_account, - &[b"hello_world_seed"], - &hello_world::ID, - ) - .unwrap(); - let signers = vec![author.clone()]; - let acc_meta = hello_world::accounts::InitializeContext { - author: author.pubkey(), - hello_world_account: hello_world_account.pubkey(), - system_program: solana_sdk::system_program::ID, - } - .to_account_metas(None); - Ok((signers, acc_meta)) -} -``` +### `get()` +Retrieves a record from AccountsStorage based on the entered `account_id`. If no record exists for the `account_id`, a random public key is returned. -### Create an arbitrary account -The `AccountsStorage` type provides an implementation of the `get_or_create_account` method that helps you create new or read already existing accounts. There are different implementations for different types of storage (`Keypair`, `TokenStore`, `MintStore`, `PdaStore`) to simplify the creation of new accounts. +!!! tip -However, there are cases when the provided implementation is not sufficient and it is necessary to create an account manually. These cases can be (but are not limited to) for example: + - This function is particularly useful for instructions other than those that perform initialization. -- you need to create a new account with a predefined address -- you need to create a new account that is not owned by the system program -- you need to create and initialize a new PDA account -- your program expects an account to be initialized in a previous instruction + Example: -In that case, you can use the `storage` method of the `AccountsStorage` struct that exposes the underlying `HashMap` and you can add new accounts directly to it. + ```rust + let hello_world_account = fuzz_accounts + .hello_world_account + .get(self.accounts.hello_world_account); + ``` + The code above will return the PDA from `hello_world`'s AccountsStorage if a record for the entered `account_id` exists. If not, the function will return a random public key. -It is possible to create and store any kind of account. For example: -- to add an account that uses the `#[account(zero)]` anchor constraint (must be rent exempt, owned by your program, with empty data): +### `set_custom()` -```rust -let state = fuzz_accounts - .state - // gets the storage of all `state` account variants - .storage() - // returns the Keypair of the `state` account with - // the given `AccountId` if it has been added previously - .entry(self.accounts.state) - .or_insert_with(|| { - let space = State::SIZE; - let rent_exempt_lamports = client.get_rent().unwrap() - .minimum_balance(space); - let keypair = Keypair::new(); - let account = AccountSharedData::new_data_with_space::<[u8; 0]>( - rent_exempt_lamports, - &[], - space, - &my_program::id(), - ).unwrap(); - // insert the custom account also into the client - client.set_account_custom(&keypair.pubkey(), &account); - keypair - }); -``` +If the previous two functions are insufficient, you can use `set_custom()` to manually set an account with data you select. This function accepts `account_id`, which specifies the record in the corresponding AccountsStorage; `client`, which handles the insertion of AccountSharedData; the account's `address` (particularly helpful if a predefined address is needed); and `AccountSharedData`, which you can configure as needed. -- to add a new system-owned account with a specific PDA (address): +!!! tip + + Example: + + ```rust + let address = Keypair::new(); + fuzz_accounts.hello_world_account.set_custom( + self.accounts.hello_world_account, + client, + address.pubkey(), + AccountSharedData::new(10 * LAMPORTS_PER_SOL, 0, &solana_sdk::system_program::ID), + ); + ``` + The code above will generate a new random keypair. The `set_account` function will insert the specified `AccountSharedData` into the client and create a record in the corresponding AccountsStorage based on the entered `account_id`. -```rust -let rent_exempt_for_token_acc = client - .get_rent() - .unwrap() - .minimum_balance(anchor_spl::token::spl_token::state::Account::LEN); - -let my_pda = fuzz_accounts - .my_pda - // gets the storage of all `my_pda` account variants - .storage() - // returns the PdaStore struct of the `my_pda` account with - // the given `AccountId` if it has been added previously - .entry(self.accounts.my_pda) - .or_insert_with(|| { - let seeds = &[b"some-seeds"]; - let pda = Pubkey::find_program_address(seeds, &my_program::id()).0; - let account = AccountSharedData::new_data_with_space::<[u8; 0]>( - rent_exempt_for_token_acc, - &[], - 0, - &SYSTEM_PROGRAM_ID, - ).unwrap(); - // insert the custom account also into the client - client.set_account_custom(&pda, &account); - let vec_of_seeds: Vec> = seeds.iter().map(|&seed| seed.to_vec()) - .collect(); - PdaStore { - pubkey: pda, - seeds: vec_of_seeds, - } - }).pubkey(); -``` -## Check +## `check()` This method provides Invariant Check for the corresponding Instruction. Check [Invariant Checks](./invariant-checks.md). -## Tx Error Handler +## `tx_error_handler()` This method provides Tx Error Handler for the corresponding Instruction. Check [Error Handler](./error-handlers.md).