Add c examples (#823)

This commit is contained in:
Jack May 2020-11-11 00:54:15 -08:00 committed by GitHub
parent 7d4e51399a
commit 686c12984b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 312 additions and 0 deletions

View File

@ -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

2
examples/c/makefile Normal file
View File

@ -0,0 +1,2 @@
OUT_DIR := ../../target/deploy
include ~/.local/share/solana/install/active_release/bin/sdk/bpf/c/bpf.mk

View File

@ -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 = &params->ka[0];
SolAccountInfo *allocated_info = &params->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)},
{&params->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, &params, SOL_ARRAY_SIZE(accounts))) {
return ERROR_INVALID_ARGUMENT;
}
return do_invoke(&params);
}

View File

@ -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, &params, 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;
}

View File

@ -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));
}

View File

@ -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, &params, SOL_ARRAY_SIZE(accounts))) {
return ERROR_INVALID_ARGUMENT;
}
return logging(&params);
}

View File

@ -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(&params));
// }

View File

@ -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(&params));
cr_assert(0 == *accounts[0].lamports);
cr_assert(5 == *accounts[1].lamports);
}

View File

@ -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 = &params->ka[0];
SolAccountInfo *destination_info = &params->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, &params, SOL_ARRAY_SIZE(accounts))) {
return ERROR_INVALID_ARGUMENT;
}
return transfer(&params);
}