@ -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))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user