feat: add bpf-c-noop example
This commit is contained in:
parent
866e8d6892
commit
d328d23faa
1
web3.js/examples/bpf-c-noop/.gitignore
vendored
Normal file
1
web3.js/examples/bpf-c-noop/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/out/
|
1
web3.js/examples/bpf-c-noop/makefile
Normal file
1
web3.js/examples/bpf-c-noop/makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
include ../../bpf-sdk/bpf.mk
|
24
web3.js/examples/bpf-c-noop/src/noop.c
Normal file
24
web3.js/examples/bpf-c-noop/src/noop.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* @brief Example C-based BPF program that prints out the parameters
|
||||||
|
* passed to it
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sol_bpf.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of SolKeyedAccounts expected. The program should bail if an
|
||||||
|
* unexpected number of accounts are passed to the program's entrypoint
|
||||||
|
*/
|
||||||
|
#define NUM_KA 1
|
||||||
|
|
||||||
|
extern bool entrypoint(const uint8_t *input) {
|
||||||
|
SolKeyedAccounts ka[NUM_KA];
|
||||||
|
uint8_t *data;
|
||||||
|
uint64_t data_len;
|
||||||
|
|
||||||
|
if (!sol_deserialize(input, NUM_KA, ka, &data, &data_len)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sol_print_params(NUM_KA, ka, data, data_len);
|
||||||
|
return true;
|
||||||
|
}
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash -ex
|
|
||||||
|
|
||||||
/usr/local/opt/llvm/bin/clang -Werror -target bpf -O2 -emit-llvm -fno-builtin -o noop_c.bc -c noop.c
|
|
||||||
/usr/local/opt/llvm/bin/llc -march=bpf -filetype=obj -function-sections -o noop_c.o noop_c.bc
|
|
@ -1,133 +0,0 @@
|
|||||||
|
|
||||||
//#include <stdint.h>
|
|
||||||
//#include <stddef.h>
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
// one way to define a helper function is with index as a fixed value
|
|
||||||
#define BPF_TRACE_PRINTK_IDX 6
|
|
||||||
static int (*sol_print)(int, int, int, int, int) = (void *)BPF_TRACE_PRINTK_IDX;
|
|
||||||
#else
|
|
||||||
// relocation is another option
|
|
||||||
extern int sol_print(int, int, int, int, int);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef long long unsigned int uint64_t;
|
|
||||||
typedef long long int int64_t;
|
|
||||||
typedef unsigned char uint8_t;
|
|
||||||
|
|
||||||
typedef enum { false = 0, true } bool;
|
|
||||||
|
|
||||||
#define SIZE_PUBKEY 32
|
|
||||||
typedef struct {
|
|
||||||
uint8_t x[SIZE_PUBKEY];
|
|
||||||
} SolPubkey;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
SolPubkey *key;
|
|
||||||
int64_t* tokens;
|
|
||||||
uint64_t userdata_len;
|
|
||||||
uint8_t *userdata;
|
|
||||||
SolPubkey *program_id;
|
|
||||||
} SolKeyedAccounts;
|
|
||||||
|
|
||||||
// TODO support BPF function calls rather then forcing everything to be inlined
|
|
||||||
#define SOL_FN_PREFIX __attribute__((always_inline)) static
|
|
||||||
|
|
||||||
// TODO move this to a registered helper
|
|
||||||
SOL_FN_PREFIX void sol_memcpy(void *dst, void *src, int len) {
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
*((uint8_t *)dst + i) = *((uint8_t *)src + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define sol_panic() _sol_panic(__LINE__)
|
|
||||||
SOL_FN_PREFIX void _sol_panic(uint64_t line) {
|
|
||||||
sol_print(0, 0, 0xFF, 0xFF, line);
|
|
||||||
char *pv = (char *)1;
|
|
||||||
*pv = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
SOL_FN_PREFIX int sol_deserialize(uint8_t *src, uint64_t num_ka, SolKeyedAccounts *ka,
|
|
||||||
uint8_t **userdata, uint64_t *userdata_len) {
|
|
||||||
if (num_ka != *(uint64_t *)src) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
src += sizeof(uint64_t);
|
|
||||||
|
|
||||||
// TODO fixed iteration loops ok? unrolled?
|
|
||||||
for (int i = 0; i < num_ka; i++) { // TODO this should end up unrolled, confirm
|
|
||||||
// key
|
|
||||||
ka[i].key = (SolPubkey *)src;
|
|
||||||
src += SIZE_PUBKEY;
|
|
||||||
|
|
||||||
// tokens
|
|
||||||
ka[i].tokens = (int64_t *)src;
|
|
||||||
src += sizeof(int64_t);
|
|
||||||
|
|
||||||
// account userdata
|
|
||||||
ka[i].userdata_len = *(uint64_t *)src;
|
|
||||||
src += sizeof(uint64_t);
|
|
||||||
ka[i].userdata = src;
|
|
||||||
src += ka[i].userdata_len;
|
|
||||||
|
|
||||||
// program_id
|
|
||||||
ka[i].program_id = (SolPubkey *)src;
|
|
||||||
src += SIZE_PUBKEY;
|
|
||||||
}
|
|
||||||
// tx userdata
|
|
||||||
*userdata_len = *(uint64_t *)src;
|
|
||||||
src += sizeof(uint64_t);
|
|
||||||
*userdata = src;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -- Debug --
|
|
||||||
|
|
||||||
SOL_FN_PREFIX void print_key(SolPubkey *key) {
|
|
||||||
for (int j = 0; j < SIZE_PUBKEY; j++) {
|
|
||||||
sol_print(0, 0, 0, j, key->x[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SOL_FN_PREFIX void print_userdata(uint8_t *data, int len) {
|
|
||||||
for (int j = 0; j < len; j++) {
|
|
||||||
sol_print(0, 0, 0, j, data[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SOL_FN_PREFIX void print_params(uint64_t num_ka, SolKeyedAccounts *ka,
|
|
||||||
uint8_t *userdata, uint64_t userdata_len) {
|
|
||||||
sol_print(0, 0, 0, 0, num_ka);
|
|
||||||
for (int i = 0; i < num_ka; i++) {
|
|
||||||
// key
|
|
||||||
print_key(ka[i].key);
|
|
||||||
|
|
||||||
// tokens
|
|
||||||
sol_print(0, 0, 0, 0, *ka[i].tokens);
|
|
||||||
|
|
||||||
// account userdata
|
|
||||||
print_userdata(ka[i].userdata, ka[i].userdata_len);
|
|
||||||
|
|
||||||
// program_id
|
|
||||||
print_key(ka[i].program_id);
|
|
||||||
}
|
|
||||||
// tx userdata
|
|
||||||
print_userdata(userdata, userdata_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Program entrypoint --
|
|
||||||
|
|
||||||
uint64_t entrypoint(char *buf) {
|
|
||||||
SolKeyedAccounts ka[1];
|
|
||||||
uint64_t userdata_len;
|
|
||||||
uint8_t *userdata;
|
|
||||||
|
|
||||||
if (1 != sol_deserialize((uint8_t *)buf, 1, ka, &userdata, &userdata_len)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
print_params(1, ka, userdata, userdata_len);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
Binary file not shown.
@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
The Solana SDK Test Binary
|
|
||||||
|
|
||||||
One of the functions that the SDK tests exercises is the loading and calling of Berkley Packet Filter programs (BPF).
|
|
||||||
|
|
||||||
The test file noop_c.o is an ELF object file containing a small BPF program contained in the ELF section named ".text.entrypoint".
|
|
||||||
|
|
||||||
The C source file for noop_c.o is noop_c.c and it can be rebuilt using the build.sh script.
|
|
||||||
The build.sh script depends on LLVM 6.0 to be installed.
|
|
@ -25,7 +25,7 @@ test('load BPF program', async () => {
|
|||||||
|
|
||||||
const connection = new Connection(url);
|
const connection = new Connection(url);
|
||||||
const from = await newAccountWithTokens(connection);
|
const from = await newAccountWithTokens(connection);
|
||||||
const data = await fs.readFile('test/bin/noop_c.o');
|
const data = await fs.readFile('test/fixtures/noop/noop.o');
|
||||||
const programId = await BpfLoader.load(connection, from, data);
|
const programId = await BpfLoader.load(connection, from, data);
|
||||||
const transaction = new Transaction().add({
|
const transaction = new Transaction().add({
|
||||||
keys: [from.publicKey],
|
keys: [from.publicKey],
|
||||||
|
4
web3.js/test/fixtures/noop/build.sh
vendored
Executable file
4
web3.js/test/fixtures/noop/build.sh
vendored
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash -ex
|
||||||
|
|
||||||
|
make -C ../../../examples/bpf-c-noop/
|
||||||
|
cp ../../../examples/bpf-c-noop/out/noop.o .
|
BIN
web3.js/test/fixtures/noop/noop.o
vendored
Normal file
BIN
web3.js/test/fixtures/noop/noop.o
vendored
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user