Add c examples (#823)
This commit is contained in:
parent
7d4e51399a
commit
686c12984b
|
@ -11,6 +11,9 @@ export RUSTBACKTRACE=1
|
|||
|
||||
set -x
|
||||
|
||||
# Build all C examples
|
||||
make -C examples/c
|
||||
|
||||
# Build/test all BPF programs
|
||||
cargo +"$rust_stable" test-bpf -- --nocapture
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
OUT_DIR := ../../target/deploy
|
||||
include ~/.local/share/solana/install/active_release/bin/sdk/bpf/c/bpf.mk
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* @brief A program demonstrating cross program invocations
|
||||
*/
|
||||
#include <solana_sdk.h>
|
||||
|
||||
/// Amount of bytes of account data to allocate
|
||||
#define SIZE 42
|
||||
|
||||
extern uint64_t do_invoke(SolParameters *params) {
|
||||
// As part of the program specification the first account is the system
|
||||
// program's executable account and the second is the account to allocate
|
||||
if (params->ka_num != 2) {
|
||||
return ERROR_NOT_ENOUGH_ACCOUNT_KEYS;
|
||||
}
|
||||
SolAccountInfo *system_program_info = ¶ms->ka[0];
|
||||
SolAccountInfo *allocated_info = ¶ms->ka[1];
|
||||
|
||||
uint8_t seed[] = {'Y', 'o', 'u', ' ', 'p', 'a', 's', 's',
|
||||
' ', 'b', 'u', 't', 't', 'e', 'r'};
|
||||
const SolSignerSeed seeds[] = {{seed, SOL_ARRAY_SIZE(seed)},
|
||||
{¶ms->data[0], 1}};
|
||||
const SolSignerSeeds signers_seeds[] = {{seeds, SOL_ARRAY_SIZE(seeds)}};
|
||||
|
||||
SolPubkey expected_allocated_key;
|
||||
if (SUCCESS == sol_create_program_address(seeds, SOL_ARRAY_SIZE(seeds),
|
||||
params->program_id,
|
||||
&expected_allocated_key)) {
|
||||
return ERROR_INVALID_INSTRUCTION_DATA;
|
||||
}
|
||||
if (!SolPubkey_same(&expected_allocated_key, allocated_info->key)) {
|
||||
return ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
SolAccountMeta arguments[] = {{system_program_info->key, false, false},
|
||||
{allocated_info->key, true, true}};
|
||||
uint8_t data[4 + 8]; // Enough room for the Allocate instruction
|
||||
*(uint16_t *)data = 8; // Allocate instruction enum value
|
||||
*(uint64_t *)(data + 4) = SIZE; // Size to allocate
|
||||
const SolInstruction instruction = {system_program_info->key, arguments,
|
||||
SOL_ARRAY_SIZE(arguments), data,
|
||||
SOL_ARRAY_SIZE(data)};
|
||||
return sol_invoke_signed(&instruction, params->ka, params->ka_num,
|
||||
signers_seeds, SOL_ARRAY_SIZE(signers_seeds));
|
||||
}
|
||||
|
||||
extern uint64_t entrypoint(const uint8_t *input) {
|
||||
SolAccountInfo accounts[2];
|
||||
SolParameters params = (SolParameters){.ka = accounts};
|
||||
|
||||
if (!sol_deserialize(input, ¶ms, SOL_ARRAY_SIZE(accounts))) {
|
||||
return ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return do_invoke(¶ms);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @brief A program demonstrating the implementation of a custom heap
|
||||
*/
|
||||
#include <solana_sdk.h>
|
||||
|
||||
/// Start address of the memory region used for program heap.
|
||||
#define HEAP_START_ADDRESS_ (uint64_t)0x300000000
|
||||
/// Length of the heap memory region used for program heap.
|
||||
#define HEAP_LENGTH_ (uint64_t)(32 * 1024)
|
||||
|
||||
typedef struct BumpAllocator {
|
||||
uint64_t start;
|
||||
uint64_t size;
|
||||
} BumpAllocator;
|
||||
void *alloc(BumpAllocator *self, uint64_t size, uint64_t align) {
|
||||
uint64_t *pos_ptr = (uint64_t *)self->start;
|
||||
|
||||
uint64_t pos = *pos_ptr;
|
||||
if (pos == 0) {
|
||||
// First time, set starting position
|
||||
pos = self->start + self->size;
|
||||
}
|
||||
if (pos < size) {
|
||||
pos = 0;
|
||||
} else {
|
||||
pos = pos - size;
|
||||
}
|
||||
pos &= ~(align - 1);
|
||||
if (pos < self->start + sizeof(uint8_t)) {
|
||||
return NULL;
|
||||
}
|
||||
*pos_ptr = pos;
|
||||
return (void *)pos;
|
||||
}
|
||||
void dealloc(BumpAllocator *self, void *ptr) {
|
||||
// I'm a bump allocator, I don't free
|
||||
}
|
||||
|
||||
extern uint64_t entrypoint(const uint8_t *input) {
|
||||
SolAccountInfo accounts[2];
|
||||
SolParameters params = (SolParameters){.ka = accounts};
|
||||
|
||||
if (!sol_deserialize(input, ¶ms, SOL_ARRAY_SIZE(accounts))) {
|
||||
return ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
BumpAllocator heap = {HEAP_START_ADDRESS_, HEAP_LENGTH_};
|
||||
sol_assert(0 != alloc(&heap, 1, sizeof(uint64_t)));
|
||||
|
||||
return SUCCESS;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// goes away when the sdk incorporates it
|
||||
int printf(const char * restrictformat, ... );
|
||||
|
||||
#include "custom-heap.c"
|
||||
#include <criterion/criterion.h>
|
||||
|
||||
// goes away when the sdk incorporates it
|
||||
void sol_panic_(const char *file, uint64_t len, uint64_t line, uint64_t column) {
|
||||
printf("Panic in %s at %d:%d\n", file, line, column);
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
bool is_aligned(void *ptr, uint64_t align) {
|
||||
if (0 == ((uint64_t)ptr & (align - 1))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t test_heap(uint64_t start, uint64_t size) {
|
||||
|
||||
// alloc the entire
|
||||
{
|
||||
BumpAllocator heap = {start, size};
|
||||
for (int i = 0; i < size - sizeof(uint8_t); i++) {
|
||||
void *ptr = alloc(&heap, 1, sizeof(uint8_t));
|
||||
sol_assert(NULL != ptr);
|
||||
sol_assert(ptr == (void *)(start + size - 1 - i));
|
||||
}
|
||||
sol_assert(NULL == alloc(&heap, 1, sizeof(uint8_t)));
|
||||
}
|
||||
// check alignment
|
||||
{
|
||||
sol_memset((void *)start, 0, size);
|
||||
BumpAllocator heap = {start, size};
|
||||
void *ptr = NULL;
|
||||
ptr = alloc(&heap, 1, sizeof(uint16_t));
|
||||
sol_assert(is_aligned(ptr, sizeof(uint16_t)));
|
||||
ptr = alloc(&heap, 1, sizeof(uint32_t));
|
||||
sol_assert(is_aligned(ptr, sizeof(uint32_t)));
|
||||
ptr = alloc(&heap, 1, sizeof(uint64_t));
|
||||
sol_assert(is_aligned(ptr, sizeof(uint64_t)));
|
||||
ptr = alloc(&heap, 1, 64);
|
||||
sol_assert(is_aligned(ptr, 64));
|
||||
}
|
||||
// alloc entire block (minus the pos ptr)
|
||||
{
|
||||
sol_memset((void *)start, 0, size);
|
||||
BumpAllocator heap = {start, size};
|
||||
void *ptr = alloc(&heap, size - 8, sizeof(uint8_t));
|
||||
sol_assert(ptr != NULL);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Test(custom_heap, sanity) {
|
||||
uint8_t heap[128] = {0};
|
||||
cr_assert(SUCCESS == test_heap((uint64_t)heap, 128));
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* @brief A program demonstrating logging
|
||||
*/
|
||||
#include <solana_sdk.h>
|
||||
|
||||
extern uint64_t logging(SolParameters *params) {
|
||||
// Log a string
|
||||
sol_log("static string");
|
||||
|
||||
// Log 5 numbers as u64s in hexadecimal format
|
||||
sol_log_64(params->data[0], params->data[1], params->data[2], params->data[3],
|
||||
params->data[4]);
|
||||
|
||||
// Log a slice
|
||||
sol_log_array(params->data, params->data_len);
|
||||
|
||||
// Log a public key
|
||||
sol_log_pubkey(params->program_id);
|
||||
|
||||
// Log all the program's input parameters
|
||||
sol_log_params(params);
|
||||
|
||||
// Log the number of compute units remaining that the program can consume.
|
||||
sol_log_compute_units();
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
extern uint64_t entrypoint(const uint8_t *input) {
|
||||
SolAccountInfo accounts[0];
|
||||
SolParameters params = (SolParameters){.ka = accounts};
|
||||
|
||||
if (!sol_deserialize(input, ¶ms, SOL_ARRAY_SIZE(accounts))) {
|
||||
return ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return logging(¶ms);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// #include "logging.c"
|
||||
// #include <criterion/criterion.h>
|
||||
|
||||
// Test(logging, sanity) {
|
||||
// uint8_t instruction_data[] = {10, 11, 12, 13, 14};
|
||||
// SolPubkey program_id = {.x = {
|
||||
// 1,
|
||||
// }};
|
||||
// SolPubkey key = {.x = {
|
||||
// 2,
|
||||
// }};
|
||||
// uint64_t lamports = 1;
|
||||
// uint8_t data[] = {0, 0, 0, 0};
|
||||
// SolAccountInfo accounts[] = {};
|
||||
// SolParameters params = {accounts, sizeof(accounts) /
|
||||
// sizeof(SolAccountInfo), instruction_data,
|
||||
// sizeof(instruction_data), &program_id};
|
||||
|
||||
// cr_assert(SUCCESS == logging(¶ms));
|
||||
// }
|
|
@ -0,0 +1,51 @@
|
|||
#include "transfer-lamports.c"
|
||||
#include <criterion/criterion.h>
|
||||
|
||||
Test(transfer, sanity) {
|
||||
uint8_t instruction_data[] = {};
|
||||
SolPubkey program_id = {.x = {
|
||||
1,
|
||||
}};
|
||||
SolPubkey source_key = {.x = {
|
||||
2,
|
||||
}};
|
||||
uint64_t source_lamports = 5;
|
||||
uint8_t source_data[] = {};
|
||||
SolPubkey destination_program_id = {.x = {
|
||||
3,
|
||||
}};
|
||||
SolPubkey destination_key = {.x = {
|
||||
4,
|
||||
}};
|
||||
uint64_t destination_lamports = 0;
|
||||
uint8_t destination_data[] = {};
|
||||
SolAccountInfo accounts[] = {{
|
||||
&source_key,
|
||||
&source_lamports,
|
||||
sizeof(source_data),
|
||||
source_data,
|
||||
&program_id,
|
||||
0,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
&destination_key,
|
||||
&destination_lamports,
|
||||
sizeof(destination_data),
|
||||
destination_data,
|
||||
&program_id,
|
||||
0,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
}};
|
||||
SolParameters params = {accounts, sizeof(accounts) / sizeof(SolAccountInfo),
|
||||
instruction_data, sizeof(instruction_data),
|
||||
&program_id};
|
||||
|
||||
cr_assert(SUCCESS == transfer(¶ms));
|
||||
cr_assert(0 == *accounts[0].lamports);
|
||||
cr_assert(5 == *accounts[1].lamports);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* @brief A program demonstrating the transfer of lamports
|
||||
*/
|
||||
#include <solana_sdk.h>
|
||||
|
||||
extern uint64_t transfer(SolParameters *params) {
|
||||
// As part of the program specification the first account is the source
|
||||
// account and the second is the destination account
|
||||
if (params->ka_num != 2) {
|
||||
return ERROR_NOT_ENOUGH_ACCOUNT_KEYS;
|
||||
}
|
||||
SolAccountInfo *source_info = ¶ms->ka[0];
|
||||
SolAccountInfo *destination_info = ¶ms->ka[1];
|
||||
|
||||
// Withdraw five lamports from the source
|
||||
*source_info->lamports -= 5;
|
||||
// Deposit five lamports into the destination
|
||||
*destination_info->lamports += 5;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
extern uint64_t entrypoint(const uint8_t *input) {
|
||||
SolAccountInfo accounts[2];
|
||||
SolParameters params = (SolParameters){.ka = accounts};
|
||||
|
||||
if (!sol_deserialize(input, ¶ms, SOL_ARRAY_SIZE(accounts))) {
|
||||
return ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return transfer(¶ms);
|
||||
}
|
Loading…
Reference in New Issue