304 lines
13 KiB
C
Raw Normal View History

2020-04-28 14:33:56 -07:00
/**
2020-05-08 12:24:36 -07:00
* @brief Example C-based BPF program that tests cross-program invocations
2020-04-28 14:33:56 -07:00
*/
2020-05-08 12:24:36 -07:00
#include "../invoked/instruction.h"
2020-04-28 14:33:56 -07:00
#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 uint8_t TEST_PPROGRAM_NOT_EXECUTABLE = 4;
2020-05-08 12:24:36 -07:00
static const int MINT_INDEX = 0;
static const int ARGUMENT_INDEX = 1;
static const int INVOKED_PROGRAM_INDEX = 2;
static const int INVOKED_ARGUMENT_INDEX = 3;
static const int INVOKED_PROGRAM_DUP_INDEX = 4;
static const int ARGUMENT_DUP_INDEX = 5;
static const int DERIVED_KEY1_INDEX = 6;
static const int DERIVED_KEY2_INDEX = 7;
static const int DERIVED_KEY3_INDEX = 8;
static const int SYSTEM_PROGRAM_INDEX = 9;
static const int FROM_INDEX = 10;
2020-04-28 14:33:56 -07:00
extern uint64_t entrypoint(const uint8_t *input) {
sol_log("Invoke C program");
SolAccountInfo accounts[11];
2020-04-28 14:33:56 -07:00
SolParameters params = (SolParameters){.ka = accounts};
if (!sol_deserialize(input, &params, SOL_ARRAY_SIZE(accounts))) {
return ERROR_INVALID_ARGUMENT;
}
uint8_t nonce1 = params.data[1];
uint8_t nonce2 = params.data[2];
uint8_t nonce3 = params.data[3];
switch (params.data[0]) {
case TEST_SUCCESS: {
sol_log("Call system program create account");
{
uint64_t from_lamports = *accounts[FROM_INDEX].lamports;
uint64_t to_lamports = *accounts[DERIVED_KEY1_INDEX].lamports;
SolAccountMeta arguments[] = {
{accounts[FROM_INDEX].key, true, true},
{accounts[DERIVED_KEY1_INDEX].key, true, true}};
uint8_t data[4 + 8 + 8 + 32];
*(uint64_t *)(data + 4) = 42;
*(uint64_t *)(data + 4 + 8) = MAX_PERMITTED_DATA_INCREASE;
sol_memcpy(data + 4 + 8 + 8, params.program_id, SIZE_PUBKEY);
const SolInstruction instruction = {accounts[SYSTEM_PROGRAM_INDEX].key,
arguments, SOL_ARRAY_SIZE(arguments),
data, SOL_ARRAY_SIZE(data)};
uint8_t seed1[] = {'Y', 'o', 'u', ' ', 'p', 'a', 's', 's',
' ', 'b', 'u', 't', 't', 'e', 'r'};
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)},
{&nonce1, 1}};
const SolSignerSeeds signers_seeds[] = {{seeds1, SOL_ARRAY_SIZE(seeds1)}};
sol_assert(SUCCESS == sol_invoke_signed(&instruction, accounts,
SOL_ARRAY_SIZE(accounts),
signers_seeds,
SOL_ARRAY_SIZE(signers_seeds)));
sol_assert(*accounts[FROM_INDEX].lamports == from_lamports - 42);
sol_assert(*accounts[DERIVED_KEY1_INDEX].lamports == to_lamports + 42);
sol_assert(SolPubkey_same(accounts[DERIVED_KEY1_INDEX].owner,
params.program_id));
sol_assert(accounts[DERIVED_KEY1_INDEX].data_len ==
MAX_PERMITTED_DATA_INCREASE);
sol_assert(
accounts[DERIVED_KEY1_INDEX].data[MAX_PERMITTED_DATA_INCREASE - 1] ==
0);
accounts[DERIVED_KEY1_INDEX].data[MAX_PERMITTED_DATA_INCREASE - 1] = 0x0f;
sol_assert(
accounts[DERIVED_KEY1_INDEX].data[MAX_PERMITTED_DATA_INCREASE - 1] ==
0x0f);
for (uint8_t i = 0; i < 20; i++) {
accounts[DERIVED_KEY1_INDEX].data[i] = i;
}
}
sol_log("Call system program transfer");
{
uint64_t from_lamports = *accounts[FROM_INDEX].lamports;
uint64_t to_lamports = *accounts[DERIVED_KEY1_INDEX].lamports;
SolAccountMeta arguments[] = {
{accounts[FROM_INDEX].key, true, true},
{accounts[DERIVED_KEY1_INDEX].key, true, 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 == from_lamports - 1);
sol_assert(*accounts[DERIVED_KEY1_INDEX].lamports == to_lamports + 1);
}
sol_log("Test data translation");
{
for (int i = 0; i < accounts[ARGUMENT_INDEX].data_len; i++) {
accounts[ARGUMENT_INDEX].data[i] = i;
}
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 no instruction data");
{
SolAccountMeta arguments[] = {{accounts[ARGUMENT_INDEX].key, true, true}};
uint8_t data[] = {};
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)));
2020-04-28 14:33:56 -07:00
}
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)};
2020-04-28 14:33:56 -07:00
sol_assert(42 ==
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
}
2020-04-28 14:33:56 -07:00
sol_log("Test create_program_address");
{
uint8_t seed1[] = {'Y', 'o', 'u', ' ', 'p', 'a', 's', 's',
' ', 'b', 'u', 't', 't', 'e', 'r'};
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)},
{&nonce1, 1}};
SolPubkey address;
sol_assert(SUCCESS ==
sol_create_program_address(seeds1, SOL_ARRAY_SIZE(seeds1),
params.program_id, &address));
sol_assert(SolPubkey_same(&address, accounts[DERIVED_KEY1_INDEX].key));
}
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, nonce2, nonce3};
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
arguments, SOL_ARRAY_SIZE(arguments),
data, SOL_ARRAY_SIZE(data)};
uint8_t seed1[] = {'Y', 'o', 'u', ' ', 'p', 'a', 's', 's',
' ', 'b', 'u', 't', 't', 'e', 'r'};
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)},
{&nonce1, 1}};
const SolSignerSeeds signers_seeds[] = {{seeds1, SOL_ARRAY_SIZE(seeds1)}};
sol_assert(SUCCESS == sol_invoke_signed(&instruction, accounts,
SOL_ARRAY_SIZE(accounts),
signers_seeds,
SOL_ARRAY_SIZE(signers_seeds)));
}
2020-04-28 14:33:56 -07:00
sol_log("Test multiple derived signers");
{
SolAccountMeta arguments[] = {
{accounts[DERIVED_KEY1_INDEX].key, true, false},
{accounts[DERIVED_KEY2_INDEX].key, true, true},
{accounts[DERIVED_KEY3_INDEX].key, false, true}};
uint8_t data[] = {TEST_VERIFY_NESTED_SIGNERS};
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
arguments, SOL_ARRAY_SIZE(arguments),
data, SOL_ARRAY_SIZE(data)};
uint8_t seed1[] = {'L', 'i', 'l', '\''};
uint8_t seed2[] = {'B', 'i', 't', 's'};
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)},
{seed2, SOL_ARRAY_SIZE(seed2)},
{&nonce2, 1}};
const SolSignerSeed seeds2[] = {
{(uint8_t *)accounts[DERIVED_KEY2_INDEX].key, SIZE_PUBKEY},
{&nonce3, 1}};
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)));
}
2020-04-28 14:33:56 -07:00
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);
}
2020-05-08 12:24:36 -07:00
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;
2020-04-28 14:33:56 -07:00
}
case TEST_PRIVILEGE_ESCALATION_SIGNER: {
sol_log("Test privilege escalation signer");
2020-04-28 14:33:56 -07:00
SolAccountMeta arguments[] = {
{accounts[DERIVED_KEY3_INDEX].key, false, false}};
uint8_t data[] = {TEST_VERIFY_PRIVILEGE_ESCALATION};
2020-04-28 14:33:56 -07:00
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
arguments, SOL_ARRAY_SIZE(arguments),
data, SOL_ARRAY_SIZE(data)};
2020-05-08 12:24:36 -07:00
sol_assert(SUCCESS ==
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
2020-04-28 14:33:56 -07:00
// Signer privilege escalation will always fail the whole transaction
instruction.accounts[0].is_signer = true;
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts));
break;
}
case TEST_PRIVILEGE_ESCALATION_WRITABLE: {
sol_log("Test privilege escalation writable");
2020-04-28 14:33:56 -07:00
SolAccountMeta arguments[] = {
{accounts[DERIVED_KEY3_INDEX].key, false, false}};
uint8_t data[] = {TEST_VERIFY_PRIVILEGE_ESCALATION};
2020-04-28 14:33:56 -07:00
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
arguments, SOL_ARRAY_SIZE(arguments),
data, SOL_ARRAY_SIZE(data)};
2020-05-08 12:24:36 -07:00
sol_assert(SUCCESS ==
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
2020-04-28 14:33:56 -07:00
// Writable privilege escalation will always fail the whole transaction
instruction.accounts[0].is_writable = true;
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts));
break;
2020-04-28 14:33:56 -07:00
}
case TEST_PPROGRAM_NOT_EXECUTABLE: {
sol_log("Test program not executable");
SolAccountMeta arguments[] = {
{accounts[DERIVED_KEY3_INDEX].key, false, false}};
uint8_t data[] = {TEST_VERIFY_PRIVILEGE_ESCALATION};
const SolInstruction instruction = {accounts[ARGUMENT_INDEX].key, arguments,
SOL_ARRAY_SIZE(arguments), data,
SOL_ARRAY_SIZE(data)};
return sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts));
}
default:
sol_panic();
2020-04-28 14:33:56 -07:00
}
return SUCCESS;
}