diff --git a/programs/bpf/c/src/invoke/invoke.c b/programs/bpf/c/src/invoke/invoke.c index 2aee21d7d1..f253c6d084 100644 --- a/programs/bpf/c/src/invoke/invoke.c +++ b/programs/bpf/c/src/invoke/invoke.c @@ -1,22 +1,23 @@ /** - * @brief Example C-based BPF program that prints out the parameters - * passed to it + * @brief Example C-based BPF program that tests cross-program invocations */ +#include "../invoked/instruction.h" #include -#define MINT_INDEX 0 -#define ARGUMENT_INDEX 1 -#define INVOKED_PROGRAM_INDEX 2 -#define INVOKED_ARGUMENT_INDEX 3 -#define INVOKED_PROGRAM_DUP_INDEX 4 -#define ARGUMENT_DUP_INDEX 5 -#define DERIVED_KEY_INDEX 6 -#define DERIVED_KEY2_INDEX 7 +static const int MINT_INDEX = 0; +static const int ARGUMENT_INDEX = 1; +static const int INVOKED_PROGRAM_INDEX = 2; +static const int INVOKED_ARGUMENT_INDEX = 3; +static const int INVOKED_PROGRAM_DUP_INDEX = 4; +static const int ARGUMENT_DUP_INDEX = 5; +static const int DERIVED_KEY1_INDEX = 6; +static const int DERIVED_KEY2_INDEX = 7; +static const int DERIVED_KEY3_INDEX = 8; extern uint64_t entrypoint(const uint8_t *input) { sol_log("Invoke C program"); - SolAccountInfo accounts[8]; + SolAccountInfo accounts[9]; SolParameters params = (SolParameters){.ka = accounts}; if (!sol_deserialize(input, ¶ms, SOL_ARRAY_SIZE(accounts))) { @@ -34,40 +35,45 @@ extern uint64_t entrypoint(const uint8_t *input) { {accounts[INVOKED_ARGUMENT_INDEX].key, true, true}, {accounts[INVOKED_PROGRAM_INDEX].key, false, false}, {accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false}}; - uint8_t data[] = {0, 1, 2, 3, 4, 5}; + uint8_t data[] = {TEST_VERIFY_TRANSLATIONS, 1, 2, 3, 4, 5}; const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key, arguments, 4, data, 6}; - sol_assert(SUCCESS == sol_invoke(&instruction, accounts, - SOL_ARRAY_SIZE(accounts))); + sol_assert(SUCCESS == + sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts))); } sol_log("Test return error"); { SolAccountMeta arguments[] = {{accounts[ARGUMENT_INDEX].key, true, true}}; - uint8_t data[] = {1}; + uint8_t data[] = {TEST_RETURN_ERROR}; const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key, arguments, SOL_ARRAY_SIZE(arguments), data, SOL_ARRAY_SIZE(data)}; - sol_assert(42 == sol_invoke(&instruction, accounts, - SOL_ARRAY_SIZE(accounts))); + sol_assert(42 == + sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts))); } sol_log("Test derived signers"); { + sol_assert(!accounts[DERIVED_KEY1_INDEX].is_signer); + sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer); + sol_assert(!accounts[DERIVED_KEY3_INDEX].is_signer); + SolAccountMeta arguments[] = { - {accounts[DERIVED_KEY_INDEX].key, true, true}, - {accounts[DERIVED_KEY2_INDEX].key, false, true}}; - uint8_t data[] = {2}; + {accounts[INVOKED_PROGRAM_INDEX].key, false, false}, + {accounts[DERIVED_KEY1_INDEX].key, true, true}, + {accounts[DERIVED_KEY2_INDEX].key, true, false}, + {accounts[DERIVED_KEY3_INDEX].key, false, false}}; + uint8_t data[] = {TEST_DERIVED_SIGNERS}; const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key, arguments, SOL_ARRAY_SIZE(arguments), data, SOL_ARRAY_SIZE(data)}; - const SolSignerSeed seeds1[] = {{"Lil'", 4}, {"Bits", 4}}; - const SolSignerSeed seeds2[] = {{"Gar Ma Nar Nar", 14}}; + const SolSignerSeed seeds1[] = {{"You pass butter", 15}}; + const SolSignerSeed seeds2[] = {{"Lil'", 4}, {"Bits", 4}}; const SolSignerSeeds signers_seeds[] = {{seeds1, SOL_ARRAY_SIZE(seeds1)}, {seeds2, SOL_ARRAY_SIZE(seeds2)}}; - sol_assert(SUCCESS == sol_invoke_signed( &instruction, accounts, SOL_ARRAY_SIZE(accounts), signers_seeds, SOL_ARRAY_SIZE(signers_seeds))); @@ -77,43 +83,36 @@ extern uint64_t entrypoint(const uint8_t *input) { { SolAccountMeta arguments[] = { {accounts[INVOKED_ARGUMENT_INDEX].key, true, false}}; - uint8_t data[] = {3}; + uint8_t data[] = {TEST_VERIFY_WRITER}; const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key, arguments, SOL_ARRAY_SIZE(arguments), data, SOL_ARRAY_SIZE(data)}; - sol_assert(SUCCESS == sol_invoke(&instruction, accounts, - SOL_ARRAY_SIZE(accounts))); + sol_assert(SUCCESS == + sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts))); } sol_log("Test invoke"); { sol_assert(accounts[ARGUMENT_INDEX].is_signer); - sol_assert(!accounts[DERIVED_KEY_INDEX].is_signer); - sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer); *accounts[ARGUMENT_INDEX].lamports -= 5; *accounts[INVOKED_ARGUMENT_INDEX].lamports += 5; SolAccountMeta arguments[] = { {accounts[INVOKED_ARGUMENT_INDEX].key, true, true}, - {accounts[ARGUMENT_INDEX].key, true, true}, - {accounts[DERIVED_KEY_INDEX].key, true, true}}; - uint8_t data[] = {4}; + {accounts[ARGUMENT_INDEX].key, true, true}}; + uint8_t data[] = {TEST_NESTED_INVOKE}; const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key, arguments, SOL_ARRAY_SIZE(arguments), data, SOL_ARRAY_SIZE(data)}; - const SolSignerSeed seeds[] = {{"Lil'", 4}, {"Bits", 4}}; - const SolSignerSeeds signers_seeds[] = {{seeds, SOL_ARRAY_SIZE(seeds)}}; sol_log("Fist invoke"); - sol_assert(SUCCESS == sol_invoke_signed( - &instruction, accounts, SOL_ARRAY_SIZE(accounts), - signers_seeds, SOL_ARRAY_SIZE(signers_seeds))); + sol_assert(SUCCESS == + sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts))); sol_log("2nd invoke from first program"); - sol_assert(SUCCESS == sol_invoke_signed( - &instruction, accounts, SOL_ARRAY_SIZE(accounts), - signers_seeds, SOL_ARRAY_SIZE(signers_seeds))); + sol_assert(SUCCESS == + sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts))); sol_assert(*accounts[ARGUMENT_INDEX].lamports == 42 - 5 + 1 + 1); sol_assert(*accounts[INVOKED_ARGUMENT_INDEX].lamports == 10 + 5 - 1 - 1); diff --git a/programs/bpf/c/src/invoked/invoked.c b/programs/bpf/c/src/invoked/invoked.c index 63560f6a15..0d18c4abf8 100644 --- a/programs/bpf/c/src/invoked/invoked.c +++ b/programs/bpf/c/src/invoked/invoked.c @@ -1,7 +1,7 @@ /** - * @brief Example C-based BPF program that prints out the parameters - * passed to it + * @brief Example C-based BPF program that tests cross-program invocations */ +#include "instruction.h" #include extern uint64_t entrypoint(const uint8_t *input) { @@ -13,7 +13,7 @@ extern uint64_t entrypoint(const uint8_t *input) { } switch (params.data[0]) { - case (0): { + case TEST_VERIFY_TRANSLATIONS: { sol_log("verify data translations"); static const int ARGUMENT_INDEX = 0; @@ -54,7 +54,7 @@ extern uint64_t entrypoint(const uint8_t *input) { sol_assert( SolPubkey_same(accounts[INVOKED_PROGRAM_INDEX].key, params.program_id)) sol_assert(SolPubkey_same(accounts[INVOKED_PROGRAM_INDEX].owner, - &bpf_loader_id)); + &bpf_loader_id)); sol_assert(!accounts[INVOKED_PROGRAM_INDEX].is_signer); sol_assert(!accounts[INVOKED_PROGRAM_INDEX].is_writable); sol_assert(accounts[INVOKED_PROGRAM_INDEX].rent_epoch == 1); @@ -76,21 +76,55 @@ extern uint64_t entrypoint(const uint8_t *input) { accounts[INVOKED_PROGRAM_DUP_INDEX].executable); break; } - case (1): { + case TEST_RETURN_ERROR: { sol_log("reutrn error"); return 42; } - case (2): { + case TEST_DERIVED_SIGNERS: { sol_log("verify derived signers"); - static const int DERIVED_KEY_INDEX = 0; - static const int DERIVED_KEY2_INDEX = 1; - sol_assert(sol_deserialize(input, ¶ms, 2)); + static const int INVOKED_PROGRAM_INDEX = 0; + static const int DERIVED_KEY1_INDEX = 1; + static const int DERIVED_KEY2_INDEX = 2; + static const int DERIVED_KEY3_INDEX = 3; + sol_assert(sol_deserialize(input, ¶ms, 4)); - sol_assert(accounts[DERIVED_KEY_INDEX].is_signer); + sol_assert(accounts[DERIVED_KEY1_INDEX].is_signer); + sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer); + sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer); + + SolAccountMeta arguments[] = { + {accounts[DERIVED_KEY1_INDEX].key, true, false}, + {accounts[DERIVED_KEY2_INDEX].key, true, true}, + {accounts[DERIVED_KEY3_INDEX].key, false, true}}; + uint8_t data[] = {TEST_VERIFY_NESTED_SIGNERS}; + const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key, + arguments, SOL_ARRAY_SIZE(arguments), + data, SOL_ARRAY_SIZE(data)}; + const SolSignerSeed seeds1[] = {{"Lil'", 4}, {"Bits", 4}}; + const SolSignerSeed seeds2[] = {{"Gar Ma Nar Nar", 14}}; + const SolSignerSeeds signers_seeds[] = {{seeds1, SOL_ARRAY_SIZE(seeds1)}, + {seeds2, SOL_ARRAY_SIZE(seeds2)}}; + + sol_assert(SUCCESS == sol_invoke_signed( + &instruction, accounts, SOL_ARRAY_SIZE(accounts), + signers_seeds, SOL_ARRAY_SIZE(signers_seeds))); + break; + } + + case TEST_VERIFY_NESTED_SIGNERS: { + sol_log("verify derived nested signers"); + static const int DERIVED_KEY1_INDEX = 0; + static const int DERIVED_KEY2_INDEX = 1; + static const int DERIVED_KEY3_INDEX = 2; + sol_assert(sol_deserialize(input, ¶ms, 3)); + + sol_assert(!accounts[DERIVED_KEY1_INDEX].is_signer); + sol_assert(accounts[DERIVED_KEY2_INDEX].is_signer); sol_assert(accounts[DERIVED_KEY2_INDEX].is_signer); break; } - case (3): { + + case TEST_VERIFY_WRITER: { sol_log("verify writable"); static const int ARGUMENT_INDEX = 0; sol_assert(sol_deserialize(input, ¶ms, 1)); @@ -98,17 +132,15 @@ extern uint64_t entrypoint(const uint8_t *input) { sol_assert(accounts[ARGUMENT_INDEX].is_writable); break; } - case (4): { + case TEST_NESTED_INVOKE: { sol_log("invoke"); static const int INVOKED_ARGUMENT_INDEX = 0; static const int ARGUMENT_INDEX = 1; - static const int DERIVED_KEY_INDEX = 2; - sol_assert(sol_deserialize(input, ¶ms, 3)); + sol_assert(sol_deserialize(input, ¶ms, 2)); sol_assert(accounts[INVOKED_ARGUMENT_INDEX].is_signer); sol_assert(accounts[ARGUMENT_INDEX].is_signer); - sol_assert(accounts[DERIVED_KEY_INDEX].is_signer); *accounts[INVOKED_ARGUMENT_INDEX].lamports -= 1; *accounts[ARGUMENT_INDEX].lamports += 1; diff --git a/programs/bpf/rust/invoke/src/lib.rs b/programs/bpf/rust/invoke/src/lib.rs index 578d798014..a20fa7ef5c 100644 --- a/programs/bpf/rust/invoke/src/lib.rs +++ b/programs/bpf/rust/invoke/src/lib.rs @@ -4,7 +4,7 @@ extern crate solana_sdk; -use solana_bpf_rust_invoked::instruction::create_instruction; +use solana_bpf_rust_invoked::instruction::*; use solana_sdk::{ account_info::AccountInfo, entrypoint, @@ -21,8 +21,9 @@ const INVOKED_PROGRAM_INDEX: usize = 2; const INVOKED_ARGUMENT_INDEX: usize = 3; const INVOKED_PROGRAM_DUP_INDEX: usize = 4; // const ARGUMENT_DUP_INDEX: usize = 5; -const DERIVED_KEY_INDEX: usize = 6; +const DERIVED_KEY1_INDEX: usize = 6; const DERIVED_KEY2_INDEX: usize = 7; +const DERIVED_KEY3_INDEX: usize = 8; entrypoint!(process_instruction); fn process_instruction( @@ -49,7 +50,7 @@ fn process_instruction( (accounts[INVOKED_PROGRAM_INDEX].key, false, false), (accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false), ], - vec![0, 1, 2, 3, 4, 5], + vec![TEST_VERIFY_TRANSLATIONS, 1, 2, 3, 4, 5], ); invoke(&instruction, accounts)?; } @@ -59,7 +60,7 @@ fn process_instruction( let instruction = create_instruction( *accounts[INVOKED_PROGRAM_INDEX].key, &[(accounts[ARGUMENT_INDEX].key, true, true)], - vec![1], + vec![TEST_RETURN_ERROR], ); assert_eq!( invoke(&instruction, accounts), @@ -69,21 +70,24 @@ fn process_instruction( info!("Test derived signers"); { - assert!(!accounts[DERIVED_KEY_INDEX].is_signer); + assert!(!accounts[DERIVED_KEY1_INDEX].is_signer); assert!(!accounts[DERIVED_KEY2_INDEX].is_signer); + assert!(!accounts[DERIVED_KEY3_INDEX].is_signer); let invoked_instruction = create_instruction( *accounts[INVOKED_PROGRAM_INDEX].key, &[ - (accounts[DERIVED_KEY_INDEX].key, true, true), - (accounts[DERIVED_KEY2_INDEX].key, false, true), + (accounts[INVOKED_PROGRAM_INDEX].key, false, false), + (accounts[DERIVED_KEY1_INDEX].key, true, true), + (accounts[DERIVED_KEY2_INDEX].key, true, false), + (accounts[DERIVED_KEY3_INDEX].key, false, false), ], - vec![2], + vec![TEST_DERIVED_SIGNERS], ); invoke_signed( &invoked_instruction, accounts, - &[&["Lil'", "Bits"], &["Gar Ma Nar Nar"]], + &[&["You pass butter"], &["Lil'", "Bits"]], )?; } @@ -92,7 +96,7 @@ fn process_instruction( let invoked_instruction = create_instruction( *accounts[INVOKED_PROGRAM_INDEX].key, &[(accounts[ARGUMENT_INDEX].key, false, true)], - vec![3], + vec![TEST_VERIFY_WRITER], ); invoke(&invoked_instruction, accounts)?; } @@ -100,8 +104,6 @@ fn process_instruction( info!("Test nested invoke"); { assert!(accounts[ARGUMENT_INDEX].is_signer); - assert!(!accounts[DERIVED_KEY_INDEX].is_signer); - assert!(!accounts[DERIVED_KEY2_INDEX].is_signer); **accounts[ARGUMENT_INDEX].lamports.borrow_mut() -= 5; **accounts[INVOKED_ARGUMENT_INDEX].lamports.borrow_mut() += 5; @@ -112,11 +114,10 @@ fn process_instruction( &[ (accounts[ARGUMENT_INDEX].key, true, true), (accounts[INVOKED_ARGUMENT_INDEX].key, true, true), - (accounts[DERIVED_KEY_INDEX].key, true, false), (accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false), (accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false), ], - vec![4], + vec![TEST_NESTED_INVOKE], ); invoke(&instruction, accounts)?; info!("2nd invoke from first program"); diff --git a/programs/bpf/rust/invoked/src/instruction.rs b/programs/bpf/rust/invoked/src/instruction.rs index 29290a224d..f42706654d 100644 --- a/programs/bpf/rust/invoked/src/instruction.rs +++ b/programs/bpf/rust/invoked/src/instruction.rs @@ -5,6 +5,13 @@ use solana_sdk::{ pubkey::Pubkey, }; +pub const TEST_VERIFY_TRANSLATIONS: u8 = 0; +pub const TEST_RETURN_ERROR: u8 = 1; +pub const TEST_DERIVED_SIGNERS: u8 = 2; +pub const TEST_VERIFY_NESTED_SIGNERS: u8 = 3; +pub const TEST_VERIFY_WRITER: u8 = 4; +pub const TEST_NESTED_INVOKE: u8 = 5; + pub fn create_instruction( program_id: Pubkey, arguments: &[(&Pubkey, bool, bool)], diff --git a/programs/bpf/rust/invoked/src/lib.rs b/programs/bpf/rust/invoked/src/lib.rs index 32c05667e7..85aa0e8374 100644 --- a/programs/bpf/rust/invoked/src/lib.rs +++ b/programs/bpf/rust/invoked/src/lib.rs @@ -6,10 +6,15 @@ pub mod instruction; extern crate solana_sdk; -use crate::instruction::create_instruction; +use crate::instruction::*; use solana_sdk::{ - account_info::AccountInfo, bpf_loader, entrypoint, entrypoint::ProgramResult, info, - program::invoke_signed, program_error::ProgramError, pubkey::Pubkey, + account_info::AccountInfo, + bpf_loader, entrypoint, + entrypoint::ProgramResult, + info, + program::{invoke, invoke_signed}, + program_error::ProgramError, + pubkey::Pubkey, }; entrypoint!(process_instruction); @@ -22,7 +27,7 @@ fn process_instruction( info!("Invoked program"); match instruction_data[0] { - 0 => { + TEST_VERIFY_TRANSLATIONS => { info!("verify data translations"); const ARGUMENT_INDEX: usize = 0; @@ -30,7 +35,7 @@ fn process_instruction( const INVOKED_PROGRAM_INDEX: usize = 2; const INVOKED_PROGRAM_DUP_INDEX: usize = 3; - assert_eq!(instruction_data, &[0, 1, 2, 3, 4, 5]); + assert_eq!(&instruction_data[1..], &[1, 2, 3, 4, 5]); assert_eq!(accounts.len(), 4); assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 42); @@ -100,51 +105,76 @@ fn process_instruction( info!(data[0], 0, 0, 0, 0); } } - 1 => { + TEST_RETURN_ERROR => { info!("return error"); return Err(ProgramError::Custom(42)); } - 2 => { + TEST_DERIVED_SIGNERS => { info!("verify derived signers"); - const DERIVED_KEY_INDEX: usize = 0; - const DERIVED_KEY2_INDEX: usize = 1; + const INVOKED_PROGRAM_INDEX: usize = 0; + const DERIVED_KEY1_INDEX: usize = 1; + const DERIVED_KEY2_INDEX: usize = 2; + const DERIVED_KEY3_INDEX: usize = 3; - assert!(accounts[DERIVED_KEY_INDEX].is_signer); - assert!(accounts[DERIVED_KEY2_INDEX].is_signer); + assert!(accounts[DERIVED_KEY1_INDEX].is_signer); + assert!(!accounts[DERIVED_KEY2_INDEX].is_signer); + assert!(!accounts[DERIVED_KEY3_INDEX].is_signer); + + let invoked_instruction = create_instruction( + *accounts[INVOKED_PROGRAM_INDEX].key, + &[ + (accounts[DERIVED_KEY1_INDEX].key, true, false), + (accounts[DERIVED_KEY2_INDEX].key, true, true), + (accounts[DERIVED_KEY3_INDEX].key, false, true), + ], + vec![TEST_VERIFY_NESTED_SIGNERS], + ); + invoke_signed( + &invoked_instruction, + accounts, + &[&["Lil'", "Bits"], &["Gar Ma Nar Nar"]], + )?; } - 3 => { + TEST_VERIFY_NESTED_SIGNERS => { + info!("verify nested derived signers"); + const DERIVED_KEY1_INDEX: usize = 0; + const DERIVED_KEY2_INDEX: usize = 1; + const DERIVED_KEY3_INDEX: usize = 2; + + assert!(!accounts[DERIVED_KEY1_INDEX].is_signer); + assert!(accounts[DERIVED_KEY2_INDEX].is_signer); + assert!(accounts[DERIVED_KEY3_INDEX].is_signer); + } + TEST_VERIFY_WRITER => { info!("verify writable"); const ARGUMENT_INDEX: usize = 0; assert!(!accounts[ARGUMENT_INDEX].is_writable); } - 4 => { + TEST_NESTED_INVOKE => { info!("nested invoke"); const ARGUMENT_INDEX: usize = 0; const INVOKED_ARGUMENT_INDEX: usize = 1; - const DERIVED_KEY_INDEX: usize = 2; const INVOKED_PROGRAM_INDEX: usize = 3; assert!(accounts[INVOKED_ARGUMENT_INDEX].is_signer); **accounts[INVOKED_ARGUMENT_INDEX].lamports.borrow_mut() -= 1; **accounts[ARGUMENT_INDEX].lamports.borrow_mut() += 1; - if accounts.len() > 3 { + if accounts.len() > 2 { info!("Invoke again"); let invoked_instruction = create_instruction( *accounts[INVOKED_PROGRAM_INDEX].key, &[ (accounts[ARGUMENT_INDEX].key, true, true), (accounts[INVOKED_ARGUMENT_INDEX].key, true, true), - (accounts[DERIVED_KEY_INDEX].key, true, true), ], - vec![4], + vec![TEST_NESTED_INVOKE], ); - invoke_signed(&invoked_instruction, accounts, &[&["Lil'", "Bits"]])?; + invoke(&invoked_instruction, accounts)?; } else { info!("Last invoked"); - assert!(accounts[DERIVED_KEY_INDEX].is_signer); { let mut data = accounts[INVOKED_ARGUMENT_INDEX].try_borrow_mut_data()?; for i in 0..10 { diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 2a04658e6e..5dc0407a27 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -333,10 +333,10 @@ mod bpf { let bank = Arc::new(Bank::new(&genesis_config)); let bank_client = BankClient::new_shared(&bank); - let program_id = load_bpf_program(&bank_client, &mint_keypair, program.0); + let invoke_program_id = load_bpf_program(&bank_client, &mint_keypair, program.0); let invoked_program_id = load_bpf_program(&bank_client, &mint_keypair, program.1); - let account = Account::new(42, 100, &program_id); + let account = Account::new(42, 100, &invoke_program_id); let argument_keypair = Keypair::new(); bank.store_account(&argument_keypair.pubkey(), &account); @@ -344,9 +344,11 @@ mod bpf { let invoked_argument_keypair = Keypair::new(); bank.store_account(&invoked_argument_keypair.pubkey(), &account); - let derived_key = - Pubkey::create_program_address(&["Lil'", "Bits"], &invoked_program_id).unwrap(); + let derived_key1 = + Pubkey::create_program_address(&["You pass butter"], &invoke_program_id).unwrap(); let derived_key2 = + Pubkey::create_program_address(&["Lil'", "Bits"], &invoked_program_id).unwrap(); + let derived_key3 = Pubkey::create_program_address(&["Gar Ma Nar Nar"], &invoked_program_id).unwrap(); let account_metas = vec![ @@ -356,11 +358,12 @@ mod bpf { AccountMeta::new(invoked_argument_keypair.pubkey(), true), AccountMeta::new_readonly(invoked_program_id, false), AccountMeta::new(argument_keypair.pubkey(), true), - AccountMeta::new(derived_key, false), - AccountMeta::new_readonly(derived_key2, false), + AccountMeta::new(derived_key1, false), + AccountMeta::new(derived_key2, false), + AccountMeta::new_readonly(derived_key3, false), ]; - let instruction = Instruction::new(program_id, &1u8, account_metas); + let instruction = Instruction::new(invoke_program_id, &1u8, account_metas); let message = Message::new(&[instruction]); assert!(bank_client diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 47994fffd7..d1273a8f2b 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -262,7 +262,9 @@ mod tests { use std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc}; #[derive(Debug, Default)] - pub struct MockInvokeContext {} + pub struct MockInvokeContext { + key: Pubkey, + } impl InvokeContext for MockInvokeContext { fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> { Ok(()) @@ -277,6 +279,9 @@ mod tests { ) -> Result<(), InstructionError> { Ok(()) } + fn get_caller(&self) -> Result<&Pubkey, InstructionError> { + Ok(&self.key) + } } #[test] diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 396bb8a533..6645f71554 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -693,8 +693,12 @@ fn call<'a>( let instruction = syscall.translate_instruction(instruction_addr, ro_regions)?; let message = Message::new(&[instruction]); - let program_id_index = message.instructions[0].program_id_index as usize; - let program_id = message.account_keys[program_id_index]; + let callee_program_id_index = message.instructions[0].program_id_index as usize; + let callee_program_id = message.account_keys[callee_program_id_index]; + let caller_program_id = invoke_context + .get_caller() + .map_err(|err| SyscallError::InstructionError(err))? + .into(); let (accounts, refs) = syscall.translate_accounts( &message, account_infos_addr, @@ -703,7 +707,7 @@ fn call<'a>( rw_regions, )?; let signers = syscall.translate_signers( - &program_id, + caller_program_id, signers_seeds_addr, signers_seeds_len as usize, ro_regions, @@ -711,12 +715,12 @@ fn call<'a>( // Process instruction - let program_account = (*accounts[program_id_index]).clone(); + let program_account = (*accounts[callee_program_id_index]).clone(); if program_account.borrow().owner != bpf_loader::id() { // Only BPF programs supported for now return Err(SyscallError::ProgramNotSupported.into()); } - let executable_accounts = vec![(program_id, program_account)]; + let executable_accounts = vec![(callee_program_id, program_account)]; #[allow(clippy::deref_addrof)] match MessageProcessor::process_cross_program_instruction( diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index ce731051c6..30668ec6e8 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -229,6 +229,11 @@ impl InvokeContext for ThisInvokeContext { None => Err(InstructionError::GenericError), // Should never happen } } + fn get_caller(&self) -> Result<&Pubkey, InstructionError> { + self.program_ids + .last() + .ok_or(InstructionError::GenericError) + } } pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>; diff --git a/sdk/src/entrypoint_native.rs b/sdk/src/entrypoint_native.rs index 5b2e872dbc..33c7460567 100644 --- a/sdk/src/entrypoint_native.rs +++ b/sdk/src/entrypoint_native.rs @@ -157,4 +157,5 @@ pub trait InvokeContext { signers: &[Pubkey], accounts: &[Rc>], ) -> Result<(), InstructionError>; + fn get_caller(&self) -> Result<&Pubkey, InstructionError>; }