Programs can only sign their accounts
This commit is contained in:
		| @@ -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 <solana_sdk.h> | ||||
|  | ||||
| #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); | ||||
|   | ||||
| @@ -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 <solana_sdk.h> | ||||
|  | ||||
| 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; | ||||
|   | ||||
| @@ -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"); | ||||
|   | ||||
| @@ -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)], | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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] | ||||
|   | ||||
| @@ -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( | ||||
|   | ||||
| @@ -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>; | ||||
|   | ||||
| @@ -157,4 +157,5 @@ pub trait InvokeContext { | ||||
|         signers: &[Pubkey], | ||||
|         accounts: &[Rc<RefCell<Account>>], | ||||
|     ) -> Result<(), InstructionError>; | ||||
|     fn get_caller(&self) -> Result<&Pubkey, InstructionError>; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user