diff --git a/CHANGELOG.md b/CHANGELOG.md index e4a07914..06c3288f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ incremented upon a breaking change and the patch version will be incremented for **Added** +- added support for composite accounts ([245](https://github.com/Ackee-Blockchain/trident/pull/245)) - Trident SVM + AFL (see the PR for more details) ([234](https://github.com/Ackee-Blockchain/trident/pull/234)) **Removed** diff --git a/crates/client/tests/anchor_idl/idl_test.json b/crates/client/tests/anchor_idl/idl_test.json index 0700a7bf..a393fe6a 100644 --- a/crates/client/tests/anchor_idl/idl_test.json +++ b/crates/client/tests/anchor_idl/idl_test.json @@ -20,6 +20,26 @@ 108 ], "accounts": [ + { + "name": "composite_account_nested", + "accounts": [ + { + "name": "some_account" + }, + { + "name": "nested_inner", + "accounts": [ + { + "name": "some_account" + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ] + } + ] + }, { "name": "signer", "signer": true @@ -41,6 +61,21 @@ }, { "name": "data_account_6" + }, + { + "name": "composite_account", + "accounts": [ + { + "name": "some_account" + }, + { + "name": "signer", + "signer": true + }, + { + "name": "data_account_1" + } + ] } ], "args": [ @@ -167,6 +202,26 @@ 246 ], "accounts": [ + { + "name": "composite_account_nested", + "accounts": [ + { + "name": "some_account" + }, + { + "name": "nested_inner", + "accounts": [ + { + "name": "some_account" + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ] + } + ] + }, { "name": "signer", "signer": true @@ -188,6 +243,21 @@ }, { "name": "data_account_6" + }, + { + "name": "composite_account", + "accounts": [ + { + "name": "some_account" + }, + { + "name": "signer", + "signer": true + }, + { + "name": "data_account_1" + } + ] } ], "args": [ @@ -832,4 +902,4 @@ } } ] -} \ No newline at end of file +} 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 6af01b3a..36840c24 100644 --- a/crates/client/tests/expected_source_codes/expected_fuzz_instructions.rs +++ b/crates/client/tests/expected_source_codes/expected_fuzz_instructions.rs @@ -15,6 +15,8 @@ pub struct ProcessCustomTypes { } #[derive(Arbitrary, Debug)] pub struct ProcessCustomTypesAccounts { + pub some_account: AccountId, + pub some_account: AccountId, pub signer: AccountId, pub data_account_1: AccountId, pub data_account_2: AccountId, @@ -22,6 +24,9 @@ pub struct ProcessCustomTypesAccounts { pub data_account_4: AccountId, pub data_account_5: AccountId, pub data_account_6: AccountId, + pub some_account: AccountId, + pub signer: AccountId, + pub data_account_1: AccountId, } /// Custom data types must derive `Debug` and `Arbitrary`. /// To do this, redefine the type in the fuzz test and implement the `From` @@ -50,6 +55,8 @@ pub struct ProcessRustTypes { } #[derive(Arbitrary, Debug)] pub struct ProcessRustTypesAccounts { + pub some_account: AccountId, + pub some_account: AccountId, pub signer: AccountId, pub data_account_1: AccountId, pub data_account_2: AccountId, @@ -57,6 +64,9 @@ pub struct ProcessRustTypesAccounts { pub data_account_4: AccountId, pub data_account_5: AccountId, pub data_account_6: AccountId, + pub some_account: AccountId, + pub signer: AccountId, + pub data_account_1: AccountId, } /// Custom data types must derive `Debug` and `Arbitrary`. /// To do this, redefine the type in the fuzz test and implement the `From` @@ -167,6 +177,20 @@ impl IxOps for ProcessCustomTypes { ) -> Result<(Vec, Vec), FuzzingError> { let mut account_metas = vec![]; let mut signers = vec![]; + { + let some_account = todo!(); + account_metas.push(todo!()); + } + { + let some_account = todo!(); + account_metas.push(todo!()); + } + { + account_metas.push(AccountMeta::new_readonly( + pubkey!("11111111111111111111111111111111"), + false, + )); + } { let signer = fuzz_accounts.signer.get_or_create_account( self.accounts.signer, @@ -200,6 +224,23 @@ impl IxOps for ProcessCustomTypes { let data_account_6 = todo!(); account_metas.push(todo!()); } + { + let some_account = todo!(); + account_metas.push(todo!()); + } + { + let signer = fuzz_accounts.signer.get_or_create_account( + self.accounts.signer, + client, + 500 * LAMPORTS_PER_SOL, + ); + account_metas.push(AccountMeta::new_readonly(signer.pubkey(), true)); + signers.push(signer.insecure_clone()); + } + { + let data_account_1 = todo!(); + account_metas.push(todo!()); + } Ok((signers, account_metas)) } } @@ -284,6 +325,20 @@ impl IxOps for ProcessRustTypes { ) -> Result<(Vec, Vec), FuzzingError> { let mut account_metas = vec![]; let mut signers = vec![]; + { + let some_account = todo!(); + account_metas.push(todo!()); + } + { + let some_account = todo!(); + account_metas.push(todo!()); + } + { + account_metas.push(AccountMeta::new_readonly( + pubkey!("11111111111111111111111111111111"), + false, + )); + } { let signer = fuzz_accounts.signer.get_or_create_account( self.accounts.signer, @@ -317,6 +372,23 @@ impl IxOps for ProcessRustTypes { let data_account_6 = todo!(); account_metas.push(todo!()); } + { + let some_account = todo!(); + account_metas.push(todo!()); + } + { + let signer = fuzz_accounts.signer.get_or_create_account( + self.accounts.signer, + client, + 500 * LAMPORTS_PER_SOL, + ); + account_metas.push(AccountMeta::new_readonly(signer.pubkey(), true)); + signers.push(signer.insecure_clone()); + } + { + let data_account_1 = todo!(); + account_metas.push(todo!()); + } Ok((signers, account_metas)) } } @@ -370,6 +442,7 @@ pub struct FuzzAccounts { data_account_5: AccountsStorage, data_account_6: AccountsStorage, signer: AccountsStorage, + some_account: AccountsStorage, } #[derive(Arbitrary, Debug, BorshDeserialize, BorshSerialize, Clone)] pub struct ClassicStruct { diff --git a/crates/template/src/fuzz_accounts.rs b/crates/template/src/fuzz_accounts.rs index 4637c7c0..4cdee7ba 100644 --- a/crates/template/src/fuzz_accounts.rs +++ b/crates/template/src/fuzz_accounts.rs @@ -25,7 +25,11 @@ pub(crate) fn get_fuzz_accounts( .fold(&mut fuzz_accounts, |fuzz_accounts, account| { match account { IdlInstructionAccountItem::Composite(idl_instruction_accounts) => { - process_composite_account(idl_instruction_accounts); + process_composite_account( + idl_instruction_accounts, + fuzz_accounts, + instructions_accounts, + ); } IdlInstructionAccountItem::Single(idl_instruction_account) => { process_single_account( @@ -48,11 +52,30 @@ pub(crate) fn get_fuzz_accounts( sorted_accounts.into_iter().map(|(_, v)| v).collect() } -fn process_composite_account(idl_instruction_accounts: &IdlInstructionAccounts) { - panic!( - "Composite accounts not supported. Composite account with name {} found", - idl_instruction_accounts.name - ) +fn process_composite_account( + idl_instruction_accounts: &IdlInstructionAccounts, + fuzz_accounts: &mut HashMap, + instructions_accounts: &HashMap, +) { + for account in &idl_instruction_accounts.accounts { + match account { + IdlInstructionAccountItem::Single(idl_instruction_account) => { + process_single_account( + idl_instruction_account, + fuzz_accounts, + instructions_accounts, + ); + } + // This creates recursion, but there should not be infinite recursion + IdlInstructionAccountItem::Composite(idl_instruction_accounts) => { + process_composite_account( + idl_instruction_accounts, + fuzz_accounts, + instructions_accounts, + ); + } + } + } } fn process_single_account( diff --git a/crates/template/src/fuzz_instructions_generator.rs b/crates/template/src/fuzz_instructions_generator.rs index 09cbeec2..605151e8 100644 --- a/crates/template/src/fuzz_instructions_generator.rs +++ b/crates/template/src/fuzz_instructions_generator.rs @@ -70,11 +70,15 @@ fn get_instructions_accounts(idl: &Idl) -> HashMap { for account in &instruction.accounts { match account { IdlInstructionAccountItem::Composite(idl_instruction_accounts) => { - process_composite_account(idl_instruction_accounts) + process_composite_account( + &instruction.name, + idl_instruction_accounts, + &mut instruction_accounts, + ); } IdlInstructionAccountItem::Single(idl_instruction_account) => { process_single_account( - instruction.name.clone(), + &instruction.name, idl_instruction_account, &mut instruction_accounts, ); @@ -86,15 +90,34 @@ fn get_instructions_accounts(idl: &Idl) -> HashMap { ) } -fn process_composite_account(idl_instruction_accounts: &IdlInstructionAccounts) { - panic!( - "Composite accounts not supported. Composite account with name {} found", - idl_instruction_accounts.name - ) +fn process_composite_account( + instruction_name: &str, + idl_instruction_accounts: &IdlInstructionAccounts, + instruction_accounts: &mut HashMap, +) { + for account in &idl_instruction_accounts.accounts { + match account { + IdlInstructionAccountItem::Single(idl_instruction_account) => { + process_single_account( + instruction_name, + idl_instruction_account, + instruction_accounts, + ); + } + // This creates recursion, but there should not be infinite recursion + IdlInstructionAccountItem::Composite(idl_instruction_accounts) => { + process_composite_account( + instruction_name, + idl_instruction_accounts, + instruction_accounts, + ); + } + } + } } fn process_single_account( - instruction_name: String, + instruction_name: &str, idl_instruction_account: &IdlInstructionAccount, instruction_accounts: &mut HashMap, ) { @@ -107,13 +130,13 @@ fn process_single_account( let mut new_account = InstructionAccount::new(account_name.to_string()); // insert infor about current instruction and the account type within the instruction - new_account.insert(instruction_name, account_type); + new_account.insert(instruction_name.to_owned(), account_type); entry.insert(new_account); } Entry::Occupied(mut entry) => { // if there is an entry, insert infor about current instruction and the account type within the instruction let account = entry.get_mut(); - account.insert(instruction_name, account_type); + account.insert(instruction_name.to_owned(), account_type); } }; } diff --git a/crates/template/src/get_accounts.rs b/crates/template/src/get_accounts.rs index 29494933..64199133 100644 --- a/crates/template/src/get_accounts.rs +++ b/crates/template/src/get_accounts.rs @@ -17,7 +17,12 @@ pub(crate) fn get_accounts( for account in &instruction.accounts { match account { IdlInstructionAccountItem::Composite(idl_instruction_accounts) => { - process_composite_account(idl_instruction_accounts) + process_composite_account( + &instruction.name, + idl_instruction_accounts, + instructions_accounts, + &mut account_implementations, + ); } IdlInstructionAccountItem::Single(idl_instruction_account) => { process_single_account( @@ -33,11 +38,32 @@ pub(crate) fn get_accounts( account_implementations } -fn process_composite_account(idl_instruction_accounts: &IdlInstructionAccounts) { - panic!( - "Composite accounts not supported. Composite account with name {} found", - idl_instruction_accounts.name - ) +fn process_composite_account( + instruction: &str, + accounts: &IdlInstructionAccounts, + instructions_accounts: &HashMap, + account_implementations: &mut Vec, +) { + for account in &accounts.accounts { + match account { + IdlInstructionAccountItem::Single(idl_instruction_account) => { + process_single_account( + instruction, + idl_instruction_account, + instructions_accounts, + account_implementations, + ); + } + IdlInstructionAccountItem::Composite(idl_instruction_accounts) => { + process_composite_account( + instruction, + idl_instruction_accounts, + instructions_accounts, + account_implementations, + ); + } + } + } } fn process_single_account( diff --git a/crates/template/src/instruction_inputs.rs b/crates/template/src/instruction_inputs.rs index bb62da71..05a8f9d9 100644 --- a/crates/template/src/instruction_inputs.rs +++ b/crates/template/src/instruction_inputs.rs @@ -2,6 +2,7 @@ use convert_case::{Case, Casing}; use quote::format_ident; use syn::{parse_quote, FnArg}; +use trident_idl_spec::IdlInstructionAccounts; use trident_idl_spec::{ idl_type_to_syn_type, Idl, IdlField, IdlInstruction, IdlInstructionAccount, IdlInstructionAccountItem, @@ -64,21 +65,36 @@ pub(crate) fn get_instruction_inputs(idl: &Idl) -> Vec { } fn get_instruction_accounts(instruction: &IdlInstruction) -> Vec { - instruction.accounts.iter().fold( - Vec::new(), - |mut account_parameters, account| match account { - IdlInstructionAccountItem::Composite(idl_instruction_accounts) => { - panic!( - "Composite accounts not supported. Composite account with name {} found", - idl_instruction_accounts.name - ) - } + instruction + .accounts + .iter() + .fold(Vec::new(), |mut account_parameters, account| { + match account { + IdlInstructionAccountItem::Composite(idl_instruction_accounts) => { + process_composite_account(idl_instruction_accounts, &mut account_parameters); + } + IdlInstructionAccountItem::Single(idl_instruction_account) => { + process_single_account(idl_instruction_account, &mut account_parameters); + } + }; + account_parameters + }) +} + +fn process_composite_account( + idl_instruction_accounts: &IdlInstructionAccounts, + account_parameters: &mut Vec, +) { + for account in &idl_instruction_accounts.accounts { + match account { IdlInstructionAccountItem::Single(idl_instruction_account) => { - process_single_account(idl_instruction_account, &mut account_parameters); - account_parameters + process_single_account(idl_instruction_account, account_parameters); } - }, - ) + IdlInstructionAccountItem::Composite(idl_instruction_accounts) => { + process_composite_account(idl_instruction_accounts, account_parameters); + } + } + } } fn process_single_account( diff --git a/documentation/docs/features/limitations.md b/documentation/docs/features/limitations.md index 02125c32..b8c0a1b1 100644 --- a/documentation/docs/features/limitations.md +++ b/documentation/docs/features/limitations.md @@ -9,4 +9,3 @@ hide: This section summarizes some known limitations in the current development stage. Further development will be focused on resolving these limitations. - Remaining accounts in check methods are not supported. -- Composite accounts are not supported. diff --git a/examples/idl-test/programs/idl-test/src/lib.rs b/examples/idl-test/programs/idl-test/src/lib.rs index 0d2c2678..edbe7e96 100644 --- a/examples/idl-test/programs/idl-test/src/lib.rs +++ b/examples/idl-test/programs/idl-test/src/lib.rs @@ -59,6 +59,7 @@ pub mod idl_test { #[derive(Accounts)] pub struct Initialize<'info> { + pub composite_account_nested: NestedInitialize<'info>, pub signer: Signer<'info>, pub data_account_1: Account<'info, DataAccount>, pub data_account_2: Account<'info, UnitStructAccount>, @@ -66,4 +67,27 @@ pub struct Initialize<'info> { pub data_account_4: Account<'info, ClassicStructAccount>, pub data_account_5: Account<'info, NestedStructAccount>, pub data_account_6: Account<'info, OptionalFieldsAccount>, + pub composite_account: InnerInitialize<'info>, +} + +#[derive(Accounts)] +pub struct InnerInitialize<'info> { + /// CHECK: we test here + pub some_account: AccountInfo<'info>, + pub signer: Signer<'info>, + pub data_account_1: Account<'info, DataAccount>, +} + +#[derive(Accounts)] +pub struct NestedInitialize<'info> { + /// CHECK: we test here + pub some_account: AccountInfo<'info>, + pub nested_inner: NestedInnerInitialize<'info>, +} + +#[derive(Accounts)] +pub struct NestedInnerInitialize<'info> { + /// CHECK: we test here + pub some_account: AccountInfo<'info>, + pub system_program: Program<'info, System>, }