From efcb58092eae4fff0f5f6baaceaf2ea5a8c4579f Mon Sep 17 00:00:00 2001 From: Jack May Date: Fri, 5 Mar 2021 20:36:27 -0800 Subject: [PATCH] Add more duplicate account tests (#15746) --- .../bpf/c/src/dup_accounts/dup_accounts.c | 113 ++++++++++++------ programs/bpf/rust/dup_accounts/src/lib.rs | 64 ++++++++-- programs/bpf/tests/programs.rs | 17 ++- 3 files changed, 148 insertions(+), 46 deletions(-) diff --git a/programs/bpf/c/src/dup_accounts/dup_accounts.c b/programs/bpf/c/src/dup_accounts/dup_accounts.c index b3914592a..4f33ff8be 100644 --- a/programs/bpf/c/src/dup_accounts/dup_accounts.c +++ b/programs/bpf/c/src/dup_accounts/dup_accounts.c @@ -1,5 +1,5 @@ /** - * @brief Example C-based BPF program that exercises duplicate keyed ka + * @brief Example C-based BPF program that exercises duplicate keyed accounts * passed to it */ #include @@ -9,46 +9,87 @@ */ extern uint64_t entrypoint(const uint8_t *input) { - SolAccountInfo ka[4]; - SolParameters params = (SolParameters) { .ka = ka }; + SolAccountInfo accounts[5]; + SolParameters params = (SolParameters){.ka = accounts}; - if (!sol_deserialize(input, ¶ms, SOL_ARRAY_SIZE(ka))) { + if (!sol_deserialize(input, ¶ms, SOL_ARRAY_SIZE(accounts))) { return ERROR_INVALID_ARGUMENT; } switch (params.data[0]) { - case(1): - sol_log("modify first account data"); - ka[2].data[0] = 1; - break; - case(2): - sol_log("modify first account data"); - ka[3].data[0] = 2; - break; - case(3): - sol_log("modify both account data"); - ka[2].data[0] += 1; - ka[3].data[0] += 2; - break; - case(4): - sol_log("modify first account lamports"); - *ka[1].lamports -= 1; - *ka[2].lamports += 1; - break; - case(5): - sol_log("modify first account lamports"); - *ka[1].lamports -= 2; - *ka[3].lamports += 2; - break; - case(6): - sol_log("modify both account lamports"); - *ka[1].lamports -= 3; - *ka[2].lamports += 1; - *ka[3].lamports += 2; - break; - default: - sol_log("Unrecognized command"); - return ERROR_INVALID_INSTRUCTION_DATA; + case (1): + sol_log("modify first account data"); + accounts[2].data[0] = 1; + break; + case (2): + sol_log("modify first account data"); + accounts[3].data[0] = 2; + break; + case (3): + sol_log("modify both account data"); + accounts[2].data[0] += 1; + accounts[3].data[0] += 2; + break; + case (4): + sol_log("modify first account lamports"); + *accounts[1].lamports -= 1; + *accounts[2].lamports += 1; + break; + case (5): + sol_log("modify first account lamports"); + *accounts[1].lamports -= 2; + *accounts[3].lamports += 2; + break; + case (6): + sol_log("modify both account lamports"); + *accounts[1].lamports -= 3; + *accounts[2].lamports += 1; + *accounts[3].lamports += 2; + break; + case (7): + sol_log("check account (0,1,2,3) privs"); + sol_assert(accounts[0].is_signer); + sol_assert(!accounts[1].is_signer); + sol_assert(accounts[2].is_signer); + sol_assert(accounts[3].is_signer); + + sol_assert(accounts[0].is_writable); + sol_assert(accounts[1].is_writable); + sol_assert(accounts[2].is_writable); + sol_assert(accounts[3].is_writable); + + if (params.ka_num > 4) { + { + SolAccountMeta arguments[] = {{accounts[0].key, true, true}, + {accounts[1].key, true, false}, + {accounts[2].key, true, false}, + {accounts[3].key, false, true}}; + uint8_t data[] = {7}; + const SolInstruction instruction = { + (SolPubkey *)params.program_id, arguments, + SOL_ARRAY_SIZE(arguments), data, SOL_ARRAY_SIZE(data)}; + sol_assert(SUCCESS == + sol_invoke(&instruction, accounts, params.ka_num)); + } + { + SolAccountMeta arguments[] = {{accounts[0].key, true, true}, + {accounts[1].key, true, false}, + {accounts[2].key, true, false}, + {accounts[3].key, true, false}}; + uint8_t data[] = {3}; + const SolInstruction instruction = { + (SolPubkey *)params.program_id, arguments, + SOL_ARRAY_SIZE(arguments), data, SOL_ARRAY_SIZE(data)}; + sol_assert(SUCCESS == + sol_invoke(&instruction, accounts, params.ka_num)); + } + sol_assert(accounts[2].data[0] == 3); + sol_assert(accounts[3].data[0] == 3); + } + break; + default: + sol_log("Unrecognized command"); + return ERROR_INVALID_INSTRUCTION_DATA; } return SUCCESS; } diff --git a/programs/bpf/rust/dup_accounts/src/lib.rs b/programs/bpf/rust/dup_accounts/src/lib.rs index bc831cfaa..25c1f8bd2 100644 --- a/programs/bpf/rust/dup_accounts/src/lib.rs +++ b/programs/bpf/rust/dup_accounts/src/lib.rs @@ -2,46 +2,92 @@ extern crate solana_program; use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, - program_error::ProgramError, pubkey::Pubkey, + account_info::AccountInfo, + entrypoint, + entrypoint::ProgramResult, + instruction::{AccountMeta, Instruction}, + msg, + program::invoke, + program_error::ProgramError, + pubkey::Pubkey, }; entrypoint!(process_instruction); fn process_instruction( - _program_id: &Pubkey, + program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { match instruction_data[0] { 1 => { - msg!("modify first account data"); + msg!("modify account (2) data"); accounts[2].data.borrow_mut()[0] = 1; } 2 => { - msg!("modify first account data"); + msg!("modify account (3) data"); accounts[3].data.borrow_mut()[0] = 2; } 3 => { - msg!("modify both account data"); + msg!("modify account (2,3) data"); accounts[2].data.borrow_mut()[0] += 1; accounts[3].data.borrow_mut()[0] += 2; } 4 => { - msg!("modify first account lamports"); + msg!("modify account (1,2) lamports"); **accounts[1].lamports.borrow_mut() -= 1; **accounts[2].lamports.borrow_mut() += 1; } 5 => { - msg!("modify first account lamports"); + msg!("modify account (1,3) lamports"); **accounts[1].lamports.borrow_mut() -= 2; **accounts[3].lamports.borrow_mut() += 2; } 6 => { - msg!("modify both account lamports"); + msg!("modify account (1,2,3) lamports"); **accounts[1].lamports.borrow_mut() -= 3; **accounts[2].lamports.borrow_mut() += 1; **accounts[3].lamports.borrow_mut() += 2; } + 7 => { + msg!("check account (0,1,2,3) privs"); + assert!(accounts[0].is_signer); + assert!(!accounts[1].is_signer); + assert!(accounts[2].is_signer); + assert!(accounts[3].is_signer); + + assert!(accounts[0].is_writable); + assert!(accounts[1].is_writable); + assert!(accounts[2].is_writable); + assert!(accounts[3].is_writable); + + if accounts.len() > 4 { + let instruction = Instruction::new_with_bytes( + *program_id, + &[7], + vec![ + AccountMeta::new(*accounts[0].key, true), + AccountMeta::new(*accounts[1].key, false), + AccountMeta::new(*accounts[2].key, false), + AccountMeta::new_readonly(*accounts[3].key, true), + ], + ); + invoke(&instruction, &accounts)?; + + let instruction = Instruction::new_with_bytes( + *program_id, + &[3], + vec![ + AccountMeta::new(*accounts[0].key, true), + AccountMeta::new(*accounts[1].key, false), + AccountMeta::new(*accounts[2].key, false), + AccountMeta::new(*accounts[3].key, false), + ], + ); + invoke(&instruction, &accounts)?; + assert_eq!(accounts[2].try_borrow_mut_data()?[0], 3); + assert_eq!(accounts[3].try_borrow_mut_data()?[0], 3); + } + } _ => { msg!("Unrecognized command"); return Err(ProgramError::InvalidArgument); diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 321d519b3..a12f33f9c 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -547,8 +547,8 @@ fn test_program_bpf_duplicate_accounts() { let payee_account = Account::new(10, 1, &program_id); let payee_pubkey = solana_sdk::pubkey::new_rand(); bank.store_account(&payee_pubkey, &payee_account); - let account = Account::new(10, 1, &program_id); + let pubkey = solana_sdk::pubkey::new_rand(); let account_metas = vec![ AccountMeta::new(mint_keypair.pubkey(), true), @@ -598,6 +598,21 @@ fn test_program_bpf_duplicate_accounts() { let lamports = bank_client.get_balance(&pubkey).unwrap(); assert!(result.is_ok()); assert_eq!(lamports, 13); + + let keypair = Keypair::new(); + let pubkey = keypair.pubkey(); + let account_metas = vec![ + AccountMeta::new(mint_keypair.pubkey(), true), + AccountMeta::new(payee_pubkey, false), + AccountMeta::new(pubkey, false), + AccountMeta::new_readonly(pubkey, true), + AccountMeta::new_readonly(program_id, false), + ]; + bank.store_account(&pubkey, &account); + let instruction = Instruction::new_with_bytes(program_id, &[7], account_metas.clone()); + let message = Message::new(&[instruction], Some(&mint_keypair.pubkey())); + let result = bank_client.send_and_confirm_message(&[&mint_keypair, &keypair], message); + assert!(result.is_ok()); } }