@@ -80,7 +80,7 @@ fn bench_program_alu(bencher: &mut Bencher) {
 | 
			
		||||
    let mut invoke_context = MockInvokeContext::default();
 | 
			
		||||
 | 
			
		||||
    let elf = load_elf().unwrap();
 | 
			
		||||
    let (mut vm, _) = solana_bpf_loader_program::create_vm(&elf, &mut invoke_context).unwrap();
 | 
			
		||||
    let (mut vm, _) = solana_bpf_loader_program::create_vm(&elf, &[], &mut invoke_context).unwrap();
 | 
			
		||||
 | 
			
		||||
    println!("Interpreted:");
 | 
			
		||||
    assert_eq!(
 | 
			
		||||
@@ -145,7 +145,6 @@ impl InvokeContext for MockInvokeContext {
 | 
			
		||||
        &mut self,
 | 
			
		||||
        _message: &Message,
 | 
			
		||||
        _instruction: &CompiledInstruction,
 | 
			
		||||
        _signers: &[Pubkey],
 | 
			
		||||
        _accounts: &[Rc<RefCell<Account>>],
 | 
			
		||||
    ) -> Result<(), InstructionError> {
 | 
			
		||||
        Ok(())
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,10 @@
 | 
			
		||||
#include "../invoked/instruction.h"
 | 
			
		||||
#include <solana_sdk.h>
 | 
			
		||||
 | 
			
		||||
static const uint8_t TEST_SUCCESS = 1;
 | 
			
		||||
static const uint8_t TEST_PRIVILEGE_ESCALATION_SIGNER = 2;
 | 
			
		||||
static const uint8_t TEST_PRIVILEGE_ESCALATION_WRITABLE = 3;
 | 
			
		||||
 | 
			
		||||
static const int MINT_INDEX = 0;
 | 
			
		||||
static const int ARGUMENT_INDEX = 1;
 | 
			
		||||
static const int INVOKED_PROGRAM_INDEX = 2;
 | 
			
		||||
@@ -26,127 +30,168 @@ extern uint64_t entrypoint(const uint8_t *input) {
 | 
			
		||||
    return ERROR_INVALID_ARGUMENT;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sol_log("Call system program");
 | 
			
		||||
  {
 | 
			
		||||
    sol_assert(*accounts[FROM_INDEX].lamports = 43);
 | 
			
		||||
    sol_assert(*accounts[ARGUMENT_INDEX].lamports = 41);
 | 
			
		||||
    SolAccountMeta arguments[] = {{accounts[FROM_INDEX].key, false, true},
 | 
			
		||||
                                  {accounts[ARGUMENT_INDEX].key, false, false}};
 | 
			
		||||
    uint8_t data[] = {2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0};
 | 
			
		||||
    const SolInstruction instruction = {accounts[SYSTEM_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(*accounts[FROM_INDEX].lamports = 42);
 | 
			
		||||
    sol_assert(*accounts[ARGUMENT_INDEX].lamports = 42);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sol_log("Test data translation");
 | 
			
		||||
  {
 | 
			
		||||
    for (int i = 0; i < accounts[ARGUMENT_INDEX].data_len; i++) {
 | 
			
		||||
      accounts[ARGUMENT_INDEX].data[i] = i;
 | 
			
		||||
  switch (params.data[0]) {
 | 
			
		||||
  case TEST_SUCCESS: {
 | 
			
		||||
    sol_log("Call system program");
 | 
			
		||||
    {
 | 
			
		||||
      sol_assert(*accounts[FROM_INDEX].lamports = 43);
 | 
			
		||||
      sol_assert(*accounts[ARGUMENT_INDEX].lamports = 41);
 | 
			
		||||
      SolAccountMeta arguments[] = {
 | 
			
		||||
          {accounts[FROM_INDEX].key, false, true},
 | 
			
		||||
          {accounts[ARGUMENT_INDEX].key, false, false}};
 | 
			
		||||
      uint8_t data[] = {2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0};
 | 
			
		||||
      const SolInstruction instruction = {accounts[SYSTEM_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(*accounts[FROM_INDEX].lamports = 42);
 | 
			
		||||
      sol_assert(*accounts[ARGUMENT_INDEX].lamports = 42);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SolAccountMeta arguments[] = {
 | 
			
		||||
        {accounts[ARGUMENT_INDEX].key, true, true},
 | 
			
		||||
        {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[] = {TEST_VERIFY_TRANSLATIONS, 1, 2, 3, 4, 5};
 | 
			
		||||
    const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
                                        arguments, SOL_ARRAY_SIZE(arguments),
 | 
			
		||||
                                        data, SOL_ARRAY_SIZE(data)};
 | 
			
		||||
    sol_log("Test data translation");
 | 
			
		||||
    {
 | 
			
		||||
      for (int i = 0; i < accounts[ARGUMENT_INDEX].data_len; i++) {
 | 
			
		||||
        accounts[ARGUMENT_INDEX].data[i] = i;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    sol_assert(SUCCESS ==
 | 
			
		||||
               sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
 | 
			
		||||
      SolAccountMeta arguments[] = {
 | 
			
		||||
          {accounts[ARGUMENT_INDEX].key, true, true},
 | 
			
		||||
          {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[] = {TEST_VERIFY_TRANSLATIONS, 1, 2, 3, 4, 5};
 | 
			
		||||
      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_log("Test return error");
 | 
			
		||||
    {
 | 
			
		||||
      SolAccountMeta arguments[] = {{accounts[ARGUMENT_INDEX].key, true, true}};
 | 
			
		||||
      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_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[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)};
 | 
			
		||||
      char seed1[] = "You pass butter";
 | 
			
		||||
      char seed2[] = "Lil'";
 | 
			
		||||
      char seed3[] = "Bits";
 | 
			
		||||
      const SolSignerSeed seeds1[] = {{seed1, sol_strlen(seed1)}};
 | 
			
		||||
      const SolSignerSeed seeds2[] = {{seed2, sol_strlen(seed2)},
 | 
			
		||||
                                      {seed3, sol_strlen(seed3)}};
 | 
			
		||||
      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)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sol_log("Test readonly with writable account");
 | 
			
		||||
    {
 | 
			
		||||
      SolAccountMeta arguments[] = {
 | 
			
		||||
          {accounts[INVOKED_ARGUMENT_INDEX].key, true, false}};
 | 
			
		||||
      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_log("Test invoke");
 | 
			
		||||
    {
 | 
			
		||||
      sol_assert(accounts[ARGUMENT_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}};
 | 
			
		||||
      uint8_t data[] = {TEST_NESTED_INVOKE};
 | 
			
		||||
      const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
                                          arguments, SOL_ARRAY_SIZE(arguments),
 | 
			
		||||
                                          data, SOL_ARRAY_SIZE(data)};
 | 
			
		||||
 | 
			
		||||
      sol_log("First invoke");
 | 
			
		||||
      sol_assert(SUCCESS ==
 | 
			
		||||
                 sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
 | 
			
		||||
      sol_log("2nd invoke from first program");
 | 
			
		||||
      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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sol_log("Verify data values are retained and updated");
 | 
			
		||||
    for (int i = 0; i < accounts[ARGUMENT_INDEX].data_len; i++) {
 | 
			
		||||
      sol_assert(accounts[ARGUMENT_INDEX].data[i] == i);
 | 
			
		||||
    }
 | 
			
		||||
    for (int i = 0; i < accounts[INVOKED_ARGUMENT_INDEX].data_len; i++) {
 | 
			
		||||
      sol_assert(accounts[INVOKED_ARGUMENT_INDEX].data[i] == i);
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sol_log("Test return error");
 | 
			
		||||
  {
 | 
			
		||||
    SolAccountMeta arguments[] = {{accounts[ARGUMENT_INDEX].key, true, true}};
 | 
			
		||||
    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_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);
 | 
			
		||||
 | 
			
		||||
  case TEST_PRIVILEGE_ESCALATION_SIGNER: {
 | 
			
		||||
    sol_log("Test privilege escalation signer");
 | 
			
		||||
    SolAccountMeta arguments[] = {
 | 
			
		||||
        {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};
 | 
			
		||||
    uint8_t data[] = {TEST_VERIFY_PRIVILEGE_ESCALATION};
 | 
			
		||||
    const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
                                        arguments, SOL_ARRAY_SIZE(arguments),
 | 
			
		||||
                                        data, SOL_ARRAY_SIZE(data)};
 | 
			
		||||
    char seed1[] = "You pass butter";
 | 
			
		||||
    char seed2[] = "Lil'";
 | 
			
		||||
    char seed3[] = "Bits";
 | 
			
		||||
    const SolSignerSeed seeds1[] = {{seed1, sol_strlen(seed1)}};
 | 
			
		||||
    const SolSignerSeed seeds2[] = {{seed2, sol_strlen(seed2)},
 | 
			
		||||
                                    {seed3, sol_strlen(seed3)}};
 | 
			
		||||
    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)));
 | 
			
		||||
  }
 | 
			
		||||
    sol_assert(SUCCESS ==
 | 
			
		||||
               sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
 | 
			
		||||
 | 
			
		||||
  sol_log("Test readonly with writable account");
 | 
			
		||||
  {
 | 
			
		||||
    instruction.accounts[0].is_signer = true;
 | 
			
		||||
    sol_assert(SUCCESS !=
 | 
			
		||||
               sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
  case TEST_PRIVILEGE_ESCALATION_WRITABLE: {
 | 
			
		||||
    sol_log("Test privilege escalation writable");
 | 
			
		||||
    SolAccountMeta arguments[] = {
 | 
			
		||||
        {accounts[INVOKED_ARGUMENT_INDEX].key, true, false}};
 | 
			
		||||
    uint8_t data[] = {TEST_VERIFY_WRITER};
 | 
			
		||||
        {accounts[DERIVED_KEY3_INDEX].key, false, false}};
 | 
			
		||||
    uint8_t data[] = {TEST_VERIFY_PRIVILEGE_ESCALATION};
 | 
			
		||||
    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_log("Test invoke");
 | 
			
		||||
  {
 | 
			
		||||
    sol_assert(accounts[ARGUMENT_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}};
 | 
			
		||||
    uint8_t data[] = {TEST_NESTED_INVOKE};
 | 
			
		||||
    const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
                                        arguments, SOL_ARRAY_SIZE(arguments),
 | 
			
		||||
                                        data, SOL_ARRAY_SIZE(data)};
 | 
			
		||||
 | 
			
		||||
    sol_log("Fist invoke");
 | 
			
		||||
    sol_assert(SUCCESS ==
 | 
			
		||||
               sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
 | 
			
		||||
    sol_log("2nd invoke from first program");
 | 
			
		||||
    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);
 | 
			
		||||
    instruction.accounts[0].is_writable = true;
 | 
			
		||||
    sol_assert(SUCCESS !=
 | 
			
		||||
               sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sol_log("Verify data values are retained and updated");
 | 
			
		||||
  for (int i = 0; i < accounts[ARGUMENT_INDEX].data_len; i++) {
 | 
			
		||||
    sol_assert(accounts[ARGUMENT_INDEX].data[i] == i);
 | 
			
		||||
  }
 | 
			
		||||
  for (int i = 0; i < accounts[INVOKED_ARGUMENT_INDEX].data_len; i++) {
 | 
			
		||||
    sol_assert(accounts[INVOKED_ARGUMENT_INDEX].data[i] == i);
 | 
			
		||||
  default:
 | 
			
		||||
    sol_panic();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return SUCCESS;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,12 @@
 | 
			
		||||
 * @brief Instruction definitions for the invoked program
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const int TEST_VERIFY_TRANSLATIONS = 0;
 | 
			
		||||
const int TEST_RETURN_ERROR = 1;
 | 
			
		||||
const int TEST_DERIVED_SIGNERS = 2;
 | 
			
		||||
const int TEST_VERIFY_NESTED_SIGNERS = 3;
 | 
			
		||||
const int TEST_VERIFY_WRITER = 4;
 | 
			
		||||
const int TEST_NESTED_INVOKE = 5;
 | 
			
		||||
#include <solana_sdk.h>
 | 
			
		||||
 | 
			
		||||
const uint8_t TEST_VERIFY_TRANSLATIONS = 0;
 | 
			
		||||
const uint8_t TEST_RETURN_ERROR = 1;
 | 
			
		||||
const uint8_t TEST_DERIVED_SIGNERS = 2;
 | 
			
		||||
const uint8_t TEST_VERIFY_NESTED_SIGNERS = 3;
 | 
			
		||||
const uint8_t TEST_VERIFY_WRITER = 4;
 | 
			
		||||
const uint8_t TEST_VERIFY_PRIVILEGE_ESCALATION = 5;
 | 
			
		||||
const uint8_t TEST_NESTED_INVOKE = 6;
 | 
			
		||||
 
 | 
			
		||||
@@ -136,6 +136,9 @@ extern uint64_t entrypoint(const uint8_t *input) {
 | 
			
		||||
    sol_assert(accounts[ARGUMENT_INDEX].is_writable);
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
  case TEST_VERIFY_PRIVILEGE_ESCALATION: {
 | 
			
		||||
    sol_log("Success");
 | 
			
		||||
  }
 | 
			
		||||
  case TEST_NESTED_INVOKE: {
 | 
			
		||||
    sol_log("invoke");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,10 @@ use solana_sdk::{
 | 
			
		||||
    system_instruction,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const TEST_SUCCESS: u8 = 1;
 | 
			
		||||
const TEST_PRIVILEGE_ESCALATION_SIGNER: u8 = 2;
 | 
			
		||||
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
 | 
			
		||||
 | 
			
		||||
// const MINT_INDEX: usize = 0;
 | 
			
		||||
const ARGUMENT_INDEX: usize = 1;
 | 
			
		||||
const INVOKED_PROGRAM_INDEX: usize = 2;
 | 
			
		||||
@@ -32,128 +36,166 @@ entrypoint!(process_instruction);
 | 
			
		||||
fn process_instruction(
 | 
			
		||||
    _program_id: &Pubkey,
 | 
			
		||||
    accounts: &[AccountInfo],
 | 
			
		||||
    _instruction_data: &[u8],
 | 
			
		||||
    instruction_data: &[u8],
 | 
			
		||||
) -> ProgramResult {
 | 
			
		||||
    info!("invoke Rust program");
 | 
			
		||||
 | 
			
		||||
    info!("Call system program");
 | 
			
		||||
    {
 | 
			
		||||
        assert_eq!(accounts[FROM_INDEX].lamports(), 43);
 | 
			
		||||
        assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 41);
 | 
			
		||||
        let instruction =
 | 
			
		||||
            system_instruction::transfer(accounts[FROM_INDEX].key, accounts[ARGUMENT_INDEX].key, 1);
 | 
			
		||||
        invoke(&instruction, accounts)?;
 | 
			
		||||
        assert_eq!(accounts[FROM_INDEX].lamports(), 42);
 | 
			
		||||
        assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 42);
 | 
			
		||||
    }
 | 
			
		||||
    match instruction_data[0] {
 | 
			
		||||
        TEST_SUCCESS => {
 | 
			
		||||
            info!("Call system program");
 | 
			
		||||
            {
 | 
			
		||||
                assert_eq!(accounts[FROM_INDEX].lamports(), 43);
 | 
			
		||||
                assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 41);
 | 
			
		||||
                let instruction = system_instruction::transfer(
 | 
			
		||||
                    accounts[FROM_INDEX].key,
 | 
			
		||||
                    accounts[ARGUMENT_INDEX].key,
 | 
			
		||||
                    1,
 | 
			
		||||
                );
 | 
			
		||||
                invoke(&instruction, accounts)?;
 | 
			
		||||
                assert_eq!(accounts[FROM_INDEX].lamports(), 42);
 | 
			
		||||
                assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 42);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
    info!("Test data translation");
 | 
			
		||||
    {
 | 
			
		||||
        {
 | 
			
		||||
            let mut data = accounts[ARGUMENT_INDEX].try_borrow_mut_data()?;
 | 
			
		||||
            for i in 0..100 {
 | 
			
		||||
                data[i as usize] = i;
 | 
			
		||||
            info!("Test data translation");
 | 
			
		||||
            {
 | 
			
		||||
                {
 | 
			
		||||
                    let mut data = accounts[ARGUMENT_INDEX].try_borrow_mut_data()?;
 | 
			
		||||
                    for i in 0..100 {
 | 
			
		||||
                        data[i as usize] = i;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let instruction = create_instruction(
 | 
			
		||||
                    *accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
                    &[
 | 
			
		||||
                        (accounts[ARGUMENT_INDEX].key, true, true),
 | 
			
		||||
                        (accounts[INVOKED_ARGUMENT_INDEX].key, true, true),
 | 
			
		||||
                        (accounts[INVOKED_PROGRAM_INDEX].key, false, false),
 | 
			
		||||
                        (accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false),
 | 
			
		||||
                    ],
 | 
			
		||||
                    vec![TEST_VERIFY_TRANSLATIONS, 1, 2, 3, 4, 5],
 | 
			
		||||
                );
 | 
			
		||||
                invoke(&instruction, accounts)?;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            info!("Test return error");
 | 
			
		||||
            {
 | 
			
		||||
                let instruction = create_instruction(
 | 
			
		||||
                    *accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
                    &[(accounts[ARGUMENT_INDEX].key, true, true)],
 | 
			
		||||
                    vec![TEST_RETURN_ERROR],
 | 
			
		||||
                );
 | 
			
		||||
                assert_eq!(
 | 
			
		||||
                    invoke(&instruction, accounts),
 | 
			
		||||
                    Err(ProgramError::Custom(42))
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            info!("Test derived signers");
 | 
			
		||||
            {
 | 
			
		||||
                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[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![TEST_DERIVED_SIGNERS],
 | 
			
		||||
                );
 | 
			
		||||
                invoke_signed(
 | 
			
		||||
                    &invoked_instruction,
 | 
			
		||||
                    accounts,
 | 
			
		||||
                    &[&["You pass butter"], &["Lil'", "Bits"]],
 | 
			
		||||
                )?;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            info!("Test readonly with writable account");
 | 
			
		||||
            {
 | 
			
		||||
                let invoked_instruction = create_instruction(
 | 
			
		||||
                    *accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
                    &[(accounts[ARGUMENT_INDEX].key, false, true)],
 | 
			
		||||
                    vec![TEST_VERIFY_WRITER],
 | 
			
		||||
                );
 | 
			
		||||
                invoke(&invoked_instruction, accounts)?;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            info!("Test nested invoke");
 | 
			
		||||
            {
 | 
			
		||||
                assert!(accounts[ARGUMENT_INDEX].is_signer);
 | 
			
		||||
 | 
			
		||||
                **accounts[ARGUMENT_INDEX].lamports.borrow_mut() -= 5;
 | 
			
		||||
                **accounts[INVOKED_ARGUMENT_INDEX].lamports.borrow_mut() += 5;
 | 
			
		||||
 | 
			
		||||
                info!("First invoke");
 | 
			
		||||
                let instruction = create_instruction(
 | 
			
		||||
                    *accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
                    &[
 | 
			
		||||
                        (accounts[ARGUMENT_INDEX].key, true, true),
 | 
			
		||||
                        (accounts[INVOKED_ARGUMENT_INDEX].key, true, true),
 | 
			
		||||
                        (accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false),
 | 
			
		||||
                        (accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false),
 | 
			
		||||
                    ],
 | 
			
		||||
                    vec![TEST_NESTED_INVOKE],
 | 
			
		||||
                );
 | 
			
		||||
                invoke(&instruction, accounts)?;
 | 
			
		||||
                info!("2nd invoke from first program");
 | 
			
		||||
                invoke(&instruction, accounts)?;
 | 
			
		||||
 | 
			
		||||
                assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 42 - 5 + 1 + 1 + 1 + 1);
 | 
			
		||||
                assert_eq!(
 | 
			
		||||
                    accounts[INVOKED_ARGUMENT_INDEX].lamports(),
 | 
			
		||||
                    10 + 5 - 1 - 1 - 1 - 1
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            info!("Verify data values are retained and updated");
 | 
			
		||||
            {
 | 
			
		||||
                let data = accounts[ARGUMENT_INDEX].try_borrow_data()?;
 | 
			
		||||
                for i in 0..100 {
 | 
			
		||||
                    assert_eq!(data[i as usize], i);
 | 
			
		||||
                }
 | 
			
		||||
                let data = accounts[INVOKED_ARGUMENT_INDEX].try_borrow_data()?;
 | 
			
		||||
                for i in 0..10 {
 | 
			
		||||
                    assert_eq!(data[i as usize], i);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        TEST_PRIVILEGE_ESCALATION_SIGNER => {
 | 
			
		||||
            info!("Test privilege escalation signer");
 | 
			
		||||
            let mut invoked_instruction = create_instruction(
 | 
			
		||||
                *accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
                &[(accounts[DERIVED_KEY3_INDEX].key, false, false)],
 | 
			
		||||
                vec![TEST_VERIFY_PRIVILEGE_ESCALATION],
 | 
			
		||||
            );
 | 
			
		||||
            invoke(&invoked_instruction, accounts)?;
 | 
			
		||||
 | 
			
		||||
        let instruction = create_instruction(
 | 
			
		||||
            *accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
            &[
 | 
			
		||||
                (accounts[ARGUMENT_INDEX].key, true, true),
 | 
			
		||||
                (accounts[INVOKED_ARGUMENT_INDEX].key, true, true),
 | 
			
		||||
                (accounts[INVOKED_PROGRAM_INDEX].key, false, false),
 | 
			
		||||
                (accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false),
 | 
			
		||||
            ],
 | 
			
		||||
            vec![TEST_VERIFY_TRANSLATIONS, 1, 2, 3, 4, 5],
 | 
			
		||||
        );
 | 
			
		||||
        invoke(&instruction, accounts)?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    info!("Test return error");
 | 
			
		||||
    {
 | 
			
		||||
        let instruction = create_instruction(
 | 
			
		||||
            *accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
            &[(accounts[ARGUMENT_INDEX].key, true, true)],
 | 
			
		||||
            vec![TEST_RETURN_ERROR],
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            invoke(&instruction, accounts),
 | 
			
		||||
            Err(ProgramError::Custom(42))
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    info!("Test derived signers");
 | 
			
		||||
    {
 | 
			
		||||
        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[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![TEST_DERIVED_SIGNERS],
 | 
			
		||||
        );
 | 
			
		||||
        invoke_signed(
 | 
			
		||||
            &invoked_instruction,
 | 
			
		||||
            accounts,
 | 
			
		||||
            &[&["You pass butter"], &["Lil'", "Bits"]],
 | 
			
		||||
        )?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    info!("Test readonly with writable account");
 | 
			
		||||
    {
 | 
			
		||||
        let invoked_instruction = create_instruction(
 | 
			
		||||
            *accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
            &[(accounts[ARGUMENT_INDEX].key, false, true)],
 | 
			
		||||
            vec![TEST_VERIFY_WRITER],
 | 
			
		||||
        );
 | 
			
		||||
        invoke(&invoked_instruction, accounts)?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    info!("Test nested invoke");
 | 
			
		||||
    {
 | 
			
		||||
        assert!(accounts[ARGUMENT_INDEX].is_signer);
 | 
			
		||||
 | 
			
		||||
        **accounts[ARGUMENT_INDEX].lamports.borrow_mut() -= 5;
 | 
			
		||||
        **accounts[INVOKED_ARGUMENT_INDEX].lamports.borrow_mut() += 5;
 | 
			
		||||
 | 
			
		||||
        info!("Fist invoke");
 | 
			
		||||
        let instruction = create_instruction(
 | 
			
		||||
            *accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
            &[
 | 
			
		||||
                (accounts[ARGUMENT_INDEX].key, true, true),
 | 
			
		||||
                (accounts[INVOKED_ARGUMENT_INDEX].key, true, true),
 | 
			
		||||
                (accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false),
 | 
			
		||||
                (accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false),
 | 
			
		||||
            ],
 | 
			
		||||
            vec![TEST_NESTED_INVOKE],
 | 
			
		||||
        );
 | 
			
		||||
        invoke(&instruction, accounts)?;
 | 
			
		||||
        info!("2nd invoke from first program");
 | 
			
		||||
        invoke(&instruction, accounts)?;
 | 
			
		||||
 | 
			
		||||
        assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 42 - 5 + 1 + 1 + 1 + 1);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            accounts[INVOKED_ARGUMENT_INDEX].lamports(),
 | 
			
		||||
            10 + 5 - 1 - 1 - 1 - 1
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    info!("Verify data values are retained and updated");
 | 
			
		||||
    {
 | 
			
		||||
        let data = accounts[ARGUMENT_INDEX].try_borrow_data()?;
 | 
			
		||||
        for i in 0..100 {
 | 
			
		||||
            assert_eq!(data[i as usize], i);
 | 
			
		||||
            invoked_instruction.accounts[0].is_signer = true;
 | 
			
		||||
            assert_eq!(
 | 
			
		||||
                invoke(&invoked_instruction, accounts),
 | 
			
		||||
                Err(ProgramError::Custom(0x0b9f_0002))
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        let data = accounts[INVOKED_ARGUMENT_INDEX].try_borrow_data()?;
 | 
			
		||||
        for i in 0..10 {
 | 
			
		||||
            assert_eq!(data[i as usize], i);
 | 
			
		||||
        TEST_PRIVILEGE_ESCALATION_WRITABLE => {
 | 
			
		||||
            info!("Test privilege escalation writable");
 | 
			
		||||
            let mut invoked_instruction = create_instruction(
 | 
			
		||||
                *accounts[INVOKED_PROGRAM_INDEX].key,
 | 
			
		||||
                &[(accounts[DERIVED_KEY3_INDEX].key, false, false)],
 | 
			
		||||
                vec![TEST_VERIFY_PRIVILEGE_ESCALATION],
 | 
			
		||||
            );
 | 
			
		||||
            invoke(&invoked_instruction, accounts)?;
 | 
			
		||||
 | 
			
		||||
            invoked_instruction.accounts[0].is_writable = true;
 | 
			
		||||
            assert_eq!(
 | 
			
		||||
                invoke(&invoked_instruction, accounts),
 | 
			
		||||
                Err(ProgramError::Custom(0x0b9f_0002))
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        _ => panic!(),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,8 @@ 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 const TEST_VERIFY_PRIVILEGE_ESCALATION: u8 = 5;
 | 
			
		||||
pub const TEST_NESTED_INVOKE: u8 = 6;
 | 
			
		||||
 | 
			
		||||
pub fn create_instruction(
 | 
			
		||||
    program_id: Pubkey,
 | 
			
		||||
 
 | 
			
		||||
@@ -151,6 +151,9 @@ fn process_instruction(
 | 
			
		||||
 | 
			
		||||
            assert!(!accounts[ARGUMENT_INDEX].is_writable);
 | 
			
		||||
        }
 | 
			
		||||
        TEST_VERIFY_PRIVILEGE_ESCALATION => {
 | 
			
		||||
            info!("Success");
 | 
			
		||||
        }
 | 
			
		||||
        TEST_NESTED_INVOKE => {
 | 
			
		||||
            info!("nested invoke");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -309,6 +309,10 @@ mod bpf {
 | 
			
		||||
    fn test_program_bpf_invoke() {
 | 
			
		||||
        solana_logger::setup();
 | 
			
		||||
 | 
			
		||||
        const TEST_SUCCESS: u8 = 1;
 | 
			
		||||
        const TEST_PRIVILEGE_ESCALATION_SIGNER: u8 = 2;
 | 
			
		||||
        const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
 | 
			
		||||
 | 
			
		||||
        let mut programs = Vec::new();
 | 
			
		||||
        #[cfg(feature = "bpf_c")]
 | 
			
		||||
        {
 | 
			
		||||
@@ -369,9 +373,11 @@ mod bpf {
 | 
			
		||||
                AccountMeta::new(from_keypair.pubkey(), true),
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            let instruction = Instruction::new(invoke_program_id, &1u8, account_metas);
 | 
			
		||||
            let message = Message::new(&[instruction]);
 | 
			
		||||
            // success cases
 | 
			
		||||
 | 
			
		||||
            let instruction =
 | 
			
		||||
                Instruction::new(invoke_program_id, &TEST_SUCCESS, account_metas.clone());
 | 
			
		||||
            let message = Message::new(&[instruction]);
 | 
			
		||||
            assert!(bank_client
 | 
			
		||||
                .send_message(
 | 
			
		||||
                    &[
 | 
			
		||||
@@ -383,6 +389,52 @@ mod bpf {
 | 
			
		||||
                    message,
 | 
			
		||||
                )
 | 
			
		||||
                .is_ok());
 | 
			
		||||
 | 
			
		||||
            // failure cases
 | 
			
		||||
 | 
			
		||||
            let instruction = Instruction::new(
 | 
			
		||||
                invoke_program_id,
 | 
			
		||||
                &TEST_PRIVILEGE_ESCALATION_SIGNER,
 | 
			
		||||
                account_metas.clone(),
 | 
			
		||||
            );
 | 
			
		||||
            let message = Message::new(&[instruction]);
 | 
			
		||||
            assert_eq!(
 | 
			
		||||
                bank_client
 | 
			
		||||
                    .send_message(
 | 
			
		||||
                        &[
 | 
			
		||||
                            &mint_keypair,
 | 
			
		||||
                            &argument_keypair,
 | 
			
		||||
                            &invoked_argument_keypair,
 | 
			
		||||
                            &from_keypair
 | 
			
		||||
                        ],
 | 
			
		||||
                        message,
 | 
			
		||||
                    )
 | 
			
		||||
                    .unwrap_err()
 | 
			
		||||
                    .unwrap(),
 | 
			
		||||
                TransactionError::InstructionError(0, InstructionError::Custom(194969602))
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            let instruction = Instruction::new(
 | 
			
		||||
                invoke_program_id,
 | 
			
		||||
                &TEST_PRIVILEGE_ESCALATION_WRITABLE,
 | 
			
		||||
                account_metas.clone(),
 | 
			
		||||
            );
 | 
			
		||||
            let message = Message::new(&[instruction]);
 | 
			
		||||
            assert_eq!(
 | 
			
		||||
                bank_client
 | 
			
		||||
                    .send_message(
 | 
			
		||||
                        &[
 | 
			
		||||
                            &mint_keypair,
 | 
			
		||||
                            &argument_keypair,
 | 
			
		||||
                            &invoked_argument_keypair,
 | 
			
		||||
                            &from_keypair
 | 
			
		||||
                        ],
 | 
			
		||||
                        message,
 | 
			
		||||
                    )
 | 
			
		||||
                    .unwrap_err()
 | 
			
		||||
                    .unwrap(),
 | 
			
		||||
                TransactionError::InstructionError(0, InstructionError::Custom(194969602))
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,7 @@ impl UserDefinedError for BPFError {}
 | 
			
		||||
 | 
			
		||||
pub fn create_vm<'a>(
 | 
			
		||||
    prog: &'a [u8],
 | 
			
		||||
    parameter_accounts: &'a [KeyedAccount<'a>],
 | 
			
		||||
    invoke_context: &'a mut dyn InvokeContext,
 | 
			
		||||
) -> Result<(EbpfVm<'a, BPFError>, MemoryRegion), EbpfError<BPFError>> {
 | 
			
		||||
    let mut vm = EbpfVm::new(None)?;
 | 
			
		||||
@@ -64,7 +65,7 @@ pub fn create_vm<'a>(
 | 
			
		||||
    vm.set_max_instruction_count(100_000)?;
 | 
			
		||||
    vm.set_elf(&prog)?;
 | 
			
		||||
 | 
			
		||||
    let heap_region = syscalls::register_syscalls(&mut vm, invoke_context)?;
 | 
			
		||||
    let heap_region = syscalls::register_syscalls(&mut vm, parameter_accounts, invoke_context)?;
 | 
			
		||||
 | 
			
		||||
    Ok((vm, heap_region))
 | 
			
		||||
}
 | 
			
		||||
@@ -182,13 +183,14 @@ pub fn process_instruction(
 | 
			
		||||
        )?;
 | 
			
		||||
        {
 | 
			
		||||
            let program_account = program.try_account_ref_mut()?;
 | 
			
		||||
            let (mut vm, heap_region) = match create_vm(&program_account.data, invoke_context) {
 | 
			
		||||
                Ok(info) => info,
 | 
			
		||||
                Err(e) => {
 | 
			
		||||
                    warn!("Failed to create BPF VM: {}", e);
 | 
			
		||||
                    return Err(BPFLoaderError::VirtualMachineCreationFailed.into());
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            let (mut vm, heap_region) =
 | 
			
		||||
                match create_vm(&program_account.data, ¶meter_accounts, invoke_context) {
 | 
			
		||||
                    Ok(info) => info,
 | 
			
		||||
                    Err(e) => {
 | 
			
		||||
                        warn!("Failed to create BPF VM: {}", e);
 | 
			
		||||
                        return Err(BPFLoaderError::VirtualMachineCreationFailed.into());
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
            info!("Call BPF program {}", program.unsigned_key());
 | 
			
		||||
            match vm.execute_program(parameter_bytes.as_slice(), &[], &[heap_region]) {
 | 
			
		||||
@@ -274,7 +276,6 @@ mod tests {
 | 
			
		||||
            &mut self,
 | 
			
		||||
            _message: &Message,
 | 
			
		||||
            _instruction: &CompiledInstruction,
 | 
			
		||||
            _signers: &[Pubkey],
 | 
			
		||||
            _accounts: &[Rc<RefCell<Account>>],
 | 
			
		||||
        ) -> Result<(), InstructionError> {
 | 
			
		||||
            Ok(())
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ use solana_rbpf::{
 | 
			
		||||
use solana_runtime::{builtin_programs::get_builtin_programs, message_processor::MessageProcessor};
 | 
			
		||||
use solana_sdk::{
 | 
			
		||||
    account::Account,
 | 
			
		||||
    account::KeyedAccount,
 | 
			
		||||
    account_info::AccountInfo,
 | 
			
		||||
    bpf_loader,
 | 
			
		||||
    entrypoint::SUCCESS,
 | 
			
		||||
@@ -48,6 +49,8 @@ pub enum SyscallError {
 | 
			
		||||
    ProgramNotSupported,
 | 
			
		||||
    #[error("{0}")]
 | 
			
		||||
    InstructionError(InstructionError),
 | 
			
		||||
    #[error("Cross-program invocation with unauthorized signer or writable account")]
 | 
			
		||||
    PrivilegeEscalation,
 | 
			
		||||
}
 | 
			
		||||
impl From<SyscallError> for EbpfError<BPFError> {
 | 
			
		||||
    fn from(error: SyscallError) -> Self {
 | 
			
		||||
@@ -69,6 +72,7 @@ const DEFAULT_HEAP_SIZE: usize = 32 * 1024;
 | 
			
		||||
 | 
			
		||||
pub fn register_syscalls<'a>(
 | 
			
		||||
    vm: &mut EbpfVm<'a, BPFError>,
 | 
			
		||||
    callers_keyed_accounts: &'a [KeyedAccount<'a>],
 | 
			
		||||
    invoke_context: &'a mut dyn InvokeContext,
 | 
			
		||||
) -> Result<MemoryRegion, EbpfError<BPFError>> {
 | 
			
		||||
    // Syscall function common across languages
 | 
			
		||||
@@ -83,12 +87,14 @@ pub fn register_syscalls<'a>(
 | 
			
		||||
        vm.register_syscall_with_context_ex(
 | 
			
		||||
            "sol_invoke_signed_c",
 | 
			
		||||
            Box::new(SyscallProcessSolInstructionC {
 | 
			
		||||
                callers_keyed_accounts,
 | 
			
		||||
                invoke_context: invoke_context.clone(),
 | 
			
		||||
            }),
 | 
			
		||||
        )?;
 | 
			
		||||
        vm.register_syscall_with_context_ex(
 | 
			
		||||
            "sol_invoke_signed_rust",
 | 
			
		||||
            Box::new(SyscallProcessInstructionRust {
 | 
			
		||||
                callers_keyed_accounts,
 | 
			
		||||
                invoke_context: invoke_context.clone(),
 | 
			
		||||
            }),
 | 
			
		||||
        )?;
 | 
			
		||||
@@ -301,6 +307,7 @@ pub type TranslatedAccounts<'a> = (Vec<Rc<RefCell<Account>>>, Vec<(&'a mut u64,
 | 
			
		||||
/// Implemented by language specific data structure translators
 | 
			
		||||
trait SyscallProcessInstruction<'a> {
 | 
			
		||||
    fn get_context_mut(&self) -> Result<RefMut<&'a mut dyn InvokeContext>, EbpfError<BPFError>>;
 | 
			
		||||
    fn get_callers_keyed_accounts(&self) -> &'a [KeyedAccount<'a>];
 | 
			
		||||
    fn translate_instruction(
 | 
			
		||||
        &self,
 | 
			
		||||
        addr: u64,
 | 
			
		||||
@@ -325,6 +332,7 @@ trait SyscallProcessInstruction<'a> {
 | 
			
		||||
 | 
			
		||||
/// Cross-program invocation called from Rust
 | 
			
		||||
pub struct SyscallProcessInstructionRust<'a> {
 | 
			
		||||
    callers_keyed_accounts: &'a [KeyedAccount<'a>],
 | 
			
		||||
    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
 | 
			
		||||
}
 | 
			
		||||
impl<'a> SyscallProcessInstruction<'a> for SyscallProcessInstructionRust<'a> {
 | 
			
		||||
@@ -333,6 +341,9 @@ impl<'a> SyscallProcessInstruction<'a> for SyscallProcessInstructionRust<'a> {
 | 
			
		||||
            .try_borrow_mut()
 | 
			
		||||
            .map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
 | 
			
		||||
    }
 | 
			
		||||
    fn get_callers_keyed_accounts(&self) -> &'a [KeyedAccount<'a>] {
 | 
			
		||||
        self.callers_keyed_accounts
 | 
			
		||||
    }
 | 
			
		||||
    fn translate_instruction(
 | 
			
		||||
        &self,
 | 
			
		||||
        addr: u64,
 | 
			
		||||
@@ -519,6 +530,7 @@ struct SolSignerSeedsC {
 | 
			
		||||
 | 
			
		||||
/// Cross-program invocation called from C
 | 
			
		||||
pub struct SyscallProcessSolInstructionC<'a> {
 | 
			
		||||
    callers_keyed_accounts: &'a [KeyedAccount<'a>],
 | 
			
		||||
    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
 | 
			
		||||
}
 | 
			
		||||
impl<'a> SyscallProcessInstruction<'a> for SyscallProcessSolInstructionC<'a> {
 | 
			
		||||
@@ -527,7 +539,9 @@ impl<'a> SyscallProcessInstruction<'a> for SyscallProcessSolInstructionC<'a> {
 | 
			
		||||
            .try_borrow_mut()
 | 
			
		||||
            .map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_callers_keyed_accounts(&self) -> &'a [KeyedAccount<'a>] {
 | 
			
		||||
        self.callers_keyed_accounts
 | 
			
		||||
    }
 | 
			
		||||
    fn translate_instruction(
 | 
			
		||||
        &self,
 | 
			
		||||
        addr: u64,
 | 
			
		||||
@@ -673,6 +687,44 @@ impl<'a> SyscallObject<BPFError> for SyscallProcessSolInstructionC<'a> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn verify_instruction<'a>(
 | 
			
		||||
    syscall: &dyn SyscallProcessInstruction<'a>,
 | 
			
		||||
    instruction: &Instruction,
 | 
			
		||||
    signers: &[Pubkey],
 | 
			
		||||
) -> Result<(), EbpfError<BPFError>> {
 | 
			
		||||
    let callers_keyed_accounts = syscall.get_callers_keyed_accounts();
 | 
			
		||||
 | 
			
		||||
    // Check for privilege escalation
 | 
			
		||||
    for account in instruction.accounts.iter() {
 | 
			
		||||
        let keyed_account = callers_keyed_accounts
 | 
			
		||||
            .iter()
 | 
			
		||||
            .find_map(|keyed_account| {
 | 
			
		||||
                if &account.pubkey == keyed_account.unsigned_key() {
 | 
			
		||||
                    Some(keyed_account)
 | 
			
		||||
                } else {
 | 
			
		||||
                    None
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .ok_or(SyscallError::InstructionError(
 | 
			
		||||
                InstructionError::MissingAccount,
 | 
			
		||||
            ))?;
 | 
			
		||||
        // Readonly account cannot become writable
 | 
			
		||||
        if account.is_writable && !keyed_account.is_writable() {
 | 
			
		||||
            return Err(SyscallError::PrivilegeEscalation.into());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if account.is_signer && // If message indicates account is signed
 | 
			
		||||
        !( // one of the following needs to be true:
 | 
			
		||||
            keyed_account.signer_key().is_some() // Signed in the parent instruction
 | 
			
		||||
            || signers.contains(&account.pubkey) // Signed by the program
 | 
			
		||||
        ) {
 | 
			
		||||
            return Err(SyscallError::PrivilegeEscalation.into());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Call process instruction, common to both Rust and C
 | 
			
		||||
fn call<'a>(
 | 
			
		||||
    syscall: &mut dyn SyscallProcessInstruction<'a>,
 | 
			
		||||
@@ -689,12 +741,19 @@ fn call<'a>(
 | 
			
		||||
    // Translate data passed from the VM
 | 
			
		||||
 | 
			
		||||
    let instruction = syscall.translate_instruction(instruction_addr, ro_regions)?;
 | 
			
		||||
    let message = Message::new_with_payer(&[instruction], None);
 | 
			
		||||
    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(SyscallError::InstructionError)?;
 | 
			
		||||
    let signers = syscall.translate_signers(
 | 
			
		||||
        caller_program_id,
 | 
			
		||||
        signers_seeds_addr,
 | 
			
		||||
        signers_seeds_len as usize,
 | 
			
		||||
        ro_regions,
 | 
			
		||||
    )?;
 | 
			
		||||
    verify_instruction(syscall, &instruction, &signers)?;
 | 
			
		||||
    let message = Message::new_with_payer(&[instruction], None);
 | 
			
		||||
    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 (accounts, refs) = syscall.translate_accounts(
 | 
			
		||||
        &message,
 | 
			
		||||
        account_infos_addr,
 | 
			
		||||
@@ -702,12 +761,6 @@ fn call<'a>(
 | 
			
		||||
        ro_regions,
 | 
			
		||||
        rw_regions,
 | 
			
		||||
    )?;
 | 
			
		||||
    let signers = syscall.translate_signers(
 | 
			
		||||
        caller_program_id,
 | 
			
		||||
        signers_seeds_addr,
 | 
			
		||||
        signers_seeds_len as usize,
 | 
			
		||||
        ro_regions,
 | 
			
		||||
    )?;
 | 
			
		||||
 | 
			
		||||
    // Process instruction
 | 
			
		||||
 | 
			
		||||
@@ -725,7 +778,6 @@ fn call<'a>(
 | 
			
		||||
        &message,
 | 
			
		||||
        &executable_accounts,
 | 
			
		||||
        &accounts,
 | 
			
		||||
        &signers,
 | 
			
		||||
        *(&mut *invoke_context),
 | 
			
		||||
    ) {
 | 
			
		||||
        Ok(()) => (),
 | 
			
		||||
 
 | 
			
		||||
@@ -122,31 +122,6 @@ impl PreAccount {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn verify_cross_program(
 | 
			
		||||
        &self,
 | 
			
		||||
        is_writable: bool,
 | 
			
		||||
        is_signer: bool,
 | 
			
		||||
        signers: &[Pubkey],
 | 
			
		||||
        program_id: &Pubkey,
 | 
			
		||||
        rent: &Rent,
 | 
			
		||||
        post: &Account,
 | 
			
		||||
    ) -> Result<(), InstructionError> {
 | 
			
		||||
        // Readonly account cannot become writable
 | 
			
		||||
        if is_writable && !self.is_writable {
 | 
			
		||||
            return Err(InstructionError::WritableModified);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if is_signer && // If message indicates account is signed
 | 
			
		||||
        !( // one of the following needs to be true:
 | 
			
		||||
            self.is_signer // Signed in the original transaction
 | 
			
		||||
            || signers.contains(&self.key) // Signed by the program
 | 
			
		||||
        ) {
 | 
			
		||||
            return Err(InstructionError::SignerModified);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.verify(program_id, rent, post)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn update(&mut self, account: &Account) {
 | 
			
		||||
        self.lamports = account.lamports;
 | 
			
		||||
        if self.data.len() != account.data.len() {
 | 
			
		||||
@@ -213,7 +188,6 @@ impl InvokeContext for ThisInvokeContext {
 | 
			
		||||
        &mut self,
 | 
			
		||||
        message: &Message,
 | 
			
		||||
        instruction: &CompiledInstruction,
 | 
			
		||||
        signers: &[Pubkey],
 | 
			
		||||
        accounts: &[Rc<RefCell<Account>>],
 | 
			
		||||
    ) -> Result<(), InstructionError> {
 | 
			
		||||
        match self.program_ids.last() {
 | 
			
		||||
@@ -221,10 +195,9 @@ impl InvokeContext for ThisInvokeContext {
 | 
			
		||||
                message,
 | 
			
		||||
                instruction,
 | 
			
		||||
                &mut self.pre_accounts,
 | 
			
		||||
                accounts,
 | 
			
		||||
                key,
 | 
			
		||||
                &self.rent,
 | 
			
		||||
                signers,
 | 
			
		||||
                accounts,
 | 
			
		||||
            ),
 | 
			
		||||
            None => Err(InstructionError::GenericError), // Should never happen
 | 
			
		||||
        }
 | 
			
		||||
@@ -353,13 +326,12 @@ impl MessageProcessor {
 | 
			
		||||
        message: &Message,
 | 
			
		||||
        executable_accounts: &[(Pubkey, RefCell<Account>)],
 | 
			
		||||
        accounts: &[Rc<RefCell<Account>>],
 | 
			
		||||
        signers: &[Pubkey],
 | 
			
		||||
        invoke_context: &mut dyn InvokeContext,
 | 
			
		||||
    ) -> Result<(), InstructionError> {
 | 
			
		||||
        let instruction = &message.instructions[0];
 | 
			
		||||
 | 
			
		||||
        // Verify the calling program hasn't misbehaved
 | 
			
		||||
        invoke_context.verify_and_update(message, instruction, signers, accounts)?;
 | 
			
		||||
        invoke_context.verify_and_update(message, instruction, accounts)?;
 | 
			
		||||
 | 
			
		||||
        // Construct keyed accounts
 | 
			
		||||
        let keyed_accounts =
 | 
			
		||||
@@ -371,7 +343,7 @@ impl MessageProcessor {
 | 
			
		||||
            self.process_instruction(&keyed_accounts, &instruction.data, invoke_context);
 | 
			
		||||
        if result.is_ok() {
 | 
			
		||||
            // Verify the called program has not misbehaved
 | 
			
		||||
            result = invoke_context.verify_and_update(message, instruction, signers, accounts);
 | 
			
		||||
            result = invoke_context.verify_and_update(message, instruction, accounts);
 | 
			
		||||
        }
 | 
			
		||||
        invoke_context.pop();
 | 
			
		||||
 | 
			
		||||
@@ -419,7 +391,7 @@ impl MessageProcessor {
 | 
			
		||||
        pre_accounts: &[PreAccount],
 | 
			
		||||
        executable_accounts: &[(Pubkey, RefCell<Account>)],
 | 
			
		||||
        accounts: &[Rc<RefCell<Account>>],
 | 
			
		||||
        rent_collector: &RentCollector,
 | 
			
		||||
        rent: &Rent,
 | 
			
		||||
    ) -> Result<(), InstructionError> {
 | 
			
		||||
        // Verify all executable accounts have zero outstanding refs
 | 
			
		||||
        Self::verify_account_references(executable_accounts)?;
 | 
			
		||||
@@ -433,7 +405,7 @@ impl MessageProcessor {
 | 
			
		||||
                let account = accounts[account_index]
 | 
			
		||||
                    .try_borrow_mut()
 | 
			
		||||
                    .map_err(|_| InstructionError::AccountBorrowOutstanding)?;
 | 
			
		||||
                pre_accounts[unique_index].verify(&program_id, &rent_collector.rent, &account)?;
 | 
			
		||||
                pre_accounts[unique_index].verify(&program_id, rent, &account)?;
 | 
			
		||||
                pre_sum += u128::from(pre_accounts[unique_index].lamports());
 | 
			
		||||
                post_sum += u128::from(account.lamports);
 | 
			
		||||
                Ok(())
 | 
			
		||||
@@ -453,10 +425,9 @@ impl MessageProcessor {
 | 
			
		||||
        message: &Message,
 | 
			
		||||
        instruction: &CompiledInstruction,
 | 
			
		||||
        pre_accounts: &mut [PreAccount],
 | 
			
		||||
        accounts: &[Rc<RefCell<Account>>],
 | 
			
		||||
        program_id: &Pubkey,
 | 
			
		||||
        rent: &Rent,
 | 
			
		||||
        signers: &[Pubkey],
 | 
			
		||||
        accounts: &[Rc<RefCell<Account>>],
 | 
			
		||||
    ) -> Result<(), InstructionError> {
 | 
			
		||||
        // Verify the per-account instruction results
 | 
			
		||||
        let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
 | 
			
		||||
@@ -471,14 +442,7 @@ impl MessageProcessor {
 | 
			
		||||
                        .try_borrow_mut()
 | 
			
		||||
                        .map_err(|_| InstructionError::AccountBorrowOutstanding)?;
 | 
			
		||||
 | 
			
		||||
                    pre_account.verify_cross_program(
 | 
			
		||||
                        message.is_writable(account_index),
 | 
			
		||||
                        message.is_signer(account_index),
 | 
			
		||||
                        signers,
 | 
			
		||||
                        &program_id,
 | 
			
		||||
                        &rent,
 | 
			
		||||
                        &account,
 | 
			
		||||
                    )?;
 | 
			
		||||
                    pre_account.verify(&program_id, &rent, &account)?;
 | 
			
		||||
                    pre_sum += u128::from(pre_account.lamports());
 | 
			
		||||
                    post_sum += u128::from(account.lamports);
 | 
			
		||||
 | 
			
		||||
@@ -525,7 +489,7 @@ impl MessageProcessor {
 | 
			
		||||
            &invoke_context.pre_accounts,
 | 
			
		||||
            executable_accounts,
 | 
			
		||||
            accounts,
 | 
			
		||||
            rent_collector,
 | 
			
		||||
            &rent_collector.rent,
 | 
			
		||||
        )?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
@@ -622,7 +586,6 @@ mod tests {
 | 
			
		||||
                .verify_and_update(
 | 
			
		||||
                    &message,
 | 
			
		||||
                    &message.instructions[0],
 | 
			
		||||
                    &[],
 | 
			
		||||
                    &accounts[not_owned_index..owned_index + 1],
 | 
			
		||||
                )
 | 
			
		||||
                .unwrap();
 | 
			
		||||
@@ -638,7 +601,6 @@ mod tests {
 | 
			
		||||
                invoke_context.verify_and_update(
 | 
			
		||||
                    &message,
 | 
			
		||||
                    &message.instructions[0],
 | 
			
		||||
                    &[],
 | 
			
		||||
                    &accounts[not_owned_index..owned_index + 1],
 | 
			
		||||
                ),
 | 
			
		||||
                Err(InstructionError::ExternalAccountDataModified)
 | 
			
		||||
@@ -685,23 +647,16 @@ mod tests {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct Change<'a> {
 | 
			
		||||
    struct Change {
 | 
			
		||||
        program_id: Pubkey,
 | 
			
		||||
        message_is_writable: bool,
 | 
			
		||||
        message_is_signer: bool,
 | 
			
		||||
        signers: &'a [Pubkey],
 | 
			
		||||
        rent: Rent,
 | 
			
		||||
        pre: PreAccount,
 | 
			
		||||
        post: Account,
 | 
			
		||||
    }
 | 
			
		||||
    impl<'a> Change<'a> {
 | 
			
		||||
    impl Change {
 | 
			
		||||
        pub fn new(owner: &Pubkey, program_id: &Pubkey) -> Self {
 | 
			
		||||
            Self {
 | 
			
		||||
                // key: Pubkey::new_rand(),
 | 
			
		||||
                program_id: *program_id,
 | 
			
		||||
                message_is_writable: false,
 | 
			
		||||
                message_is_signer: false,
 | 
			
		||||
                signers: &[],
 | 
			
		||||
                rent: Rent::default(),
 | 
			
		||||
                pre: PreAccount::new(
 | 
			
		||||
                    &Pubkey::new_rand(),
 | 
			
		||||
@@ -721,26 +676,10 @@ mod tests {
 | 
			
		||||
                },
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        pub fn new_cross_program(owner: &Pubkey, program_id: &Pubkey, key: &Pubkey) -> Self {
 | 
			
		||||
            let mut change = Change::new(owner, program_id);
 | 
			
		||||
            change.pre.key = *key;
 | 
			
		||||
            change
 | 
			
		||||
        }
 | 
			
		||||
        pub fn read_only(mut self) -> Self {
 | 
			
		||||
            self.pre.is_writable = false;
 | 
			
		||||
            self
 | 
			
		||||
        }
 | 
			
		||||
        pub fn writable(mut self, pre: bool, message_is_writable: bool) -> Self {
 | 
			
		||||
            self.pre.is_writable = pre;
 | 
			
		||||
            self.message_is_writable = message_is_writable;
 | 
			
		||||
            self
 | 
			
		||||
        }
 | 
			
		||||
        pub fn signer(mut self, pre: bool, message_is_signer: bool, signers: &'a [Pubkey]) -> Self {
 | 
			
		||||
            self.pre.is_signer = pre;
 | 
			
		||||
            self.message_is_signer = message_is_signer;
 | 
			
		||||
            self.signers = signers;
 | 
			
		||||
            self
 | 
			
		||||
        }
 | 
			
		||||
        pub fn executable(mut self, pre: bool, post: bool) -> Self {
 | 
			
		||||
            self.pre.is_executable = pre;
 | 
			
		||||
            self.post.executable = post;
 | 
			
		||||
@@ -768,16 +707,6 @@ mod tests {
 | 
			
		||||
        pub fn verify(&self) -> Result<(), InstructionError> {
 | 
			
		||||
            self.pre.verify(&self.program_id, &self.rent, &self.post)
 | 
			
		||||
        }
 | 
			
		||||
        pub fn verify_cross_program(&self) -> Result<(), InstructionError> {
 | 
			
		||||
            self.pre.verify_cross_program(
 | 
			
		||||
                self.message_is_writable,
 | 
			
		||||
                self.message_is_signer,
 | 
			
		||||
                self.signers,
 | 
			
		||||
                &self.program_id,
 | 
			
		||||
                &self.rent,
 | 
			
		||||
                &self.post,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@@ -940,59 +869,6 @@ mod tests {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_verify_account_changes_writable() {
 | 
			
		||||
        let owner = Pubkey::new_rand();
 | 
			
		||||
        let system_program_id = system_program::id();
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Change::new(&owner, &system_program_id)
 | 
			
		||||
                .writable(true, false)
 | 
			
		||||
                .verify_cross_program(),
 | 
			
		||||
            Ok(()),
 | 
			
		||||
            "account can we changed to readonly"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Change::new(&owner, &system_program_id)
 | 
			
		||||
                .writable(false, true)
 | 
			
		||||
                .verify_cross_program(),
 | 
			
		||||
            Err(InstructionError::WritableModified),
 | 
			
		||||
            "account cannot be changed to writable"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_verify_account_changes_signer() {
 | 
			
		||||
        let owner = Pubkey::new_rand();
 | 
			
		||||
        let system_program_id = system_program::id();
 | 
			
		||||
        let key = Pubkey::new_rand();
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Change::new_cross_program(&owner, &system_program_id, &key)
 | 
			
		||||
                .signer(false, true, &[key])
 | 
			
		||||
                .verify_cross_program(),
 | 
			
		||||
            Ok(()),
 | 
			
		||||
            "account signed by a signer"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Change::new_cross_program(&owner, &system_program_id, &key)
 | 
			
		||||
                .signer(false, true, &[])
 | 
			
		||||
                .verify_cross_program(),
 | 
			
		||||
            Err(InstructionError::SignerModified),
 | 
			
		||||
            "account cannot be changed to signed if no signer"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Change::new_cross_program(&owner, &system_program_id, &key)
 | 
			
		||||
                .signer(false, true, &[Pubkey::new_rand(), Pubkey::new_rand()])
 | 
			
		||||
                .verify_cross_program(),
 | 
			
		||||
            Err(InstructionError::SignerModified),
 | 
			
		||||
            "account cannot be changed to signed if no signer exists"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_verify_account_changes_data_len() {
 | 
			
		||||
        let alice_program_id = Pubkey::new_rand();
 | 
			
		||||
@@ -1446,7 +1322,6 @@ mod tests {
 | 
			
		||||
                &message,
 | 
			
		||||
                &executable_accounts,
 | 
			
		||||
                &accounts,
 | 
			
		||||
                &[],
 | 
			
		||||
                &mut invoke_context,
 | 
			
		||||
            ),
 | 
			
		||||
            Err(InstructionError::ExternalAccountDataModified)
 | 
			
		||||
@@ -1474,7 +1349,6 @@ mod tests {
 | 
			
		||||
                    &message,
 | 
			
		||||
                    &executable_accounts,
 | 
			
		||||
                    &accounts,
 | 
			
		||||
                    &[],
 | 
			
		||||
                    &mut invoke_context,
 | 
			
		||||
                ),
 | 
			
		||||
                case.1
 | 
			
		||||
 
 | 
			
		||||
@@ -154,7 +154,6 @@ pub trait InvokeContext {
 | 
			
		||||
        &mut self,
 | 
			
		||||
        message: &Message,
 | 
			
		||||
        instruction: &CompiledInstruction,
 | 
			
		||||
        signers: &[Pubkey],
 | 
			
		||||
        accounts: &[Rc<RefCell<Account>>],
 | 
			
		||||
    ) -> Result<(), InstructionError>;
 | 
			
		||||
    fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
 | 
			
		||||
 
 | 
			
		||||
@@ -140,14 +140,6 @@ pub enum InstructionError {
 | 
			
		||||
    #[error("Unsupported program id")]
 | 
			
		||||
    UnsupportedProgramId,
 | 
			
		||||
 | 
			
		||||
    /// Writable bit on account info changed, but shouldn't have
 | 
			
		||||
    #[error("Writable bit on account info changed, but shouldn't have")]
 | 
			
		||||
    WritableModified,
 | 
			
		||||
 | 
			
		||||
    /// Signer bit on account info changed, but shouldn't have
 | 
			
		||||
    #[error("Signer bit on account info changed, but shouldn't have")]
 | 
			
		||||
    SignerModified,
 | 
			
		||||
 | 
			
		||||
    /// Cross-program invocation call depth too deep
 | 
			
		||||
    #[error("Cross-program invocation call depth too deep")]
 | 
			
		||||
    CallDepth,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user