diff --git a/web3.js/examples/bpf-c-noop/.gitignore b/web3.js/examples/bpf-c-noop/.gitignore new file mode 100644 index 0000000000..6a3417b8d9 --- /dev/null +++ b/web3.js/examples/bpf-c-noop/.gitignore @@ -0,0 +1 @@ +/out/ diff --git a/web3.js/examples/bpf-c-noop/makefile b/web3.js/examples/bpf-c-noop/makefile new file mode 100644 index 0000000000..24740ee5d5 --- /dev/null +++ b/web3.js/examples/bpf-c-noop/makefile @@ -0,0 +1 @@ +include ../../bpf-sdk/bpf.mk diff --git a/web3.js/examples/bpf-c-noop/src/noop.c b/web3.js/examples/bpf-c-noop/src/noop.c new file mode 100644 index 0000000000..d78b32454a --- /dev/null +++ b/web3.js/examples/bpf-c-noop/src/noop.c @@ -0,0 +1,24 @@ +/** + * @brief Example C-based BPF program that prints out the parameters + * passed to it + */ + +#include + +/** + * 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; +} diff --git a/web3.js/test/bin/build.sh b/web3.js/test/bin/build.sh deleted file mode 100755 index 0eccaee228..0000000000 --- a/web3.js/test/bin/build.sh +++ /dev/null @@ -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 diff --git a/web3.js/test/bin/noop.c b/web3.js/test/bin/noop.c deleted file mode 100644 index d01220a709..0000000000 --- a/web3.js/test/bin/noop.c +++ /dev/null @@ -1,133 +0,0 @@ - -//#include -//#include - -#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; -} - diff --git a/web3.js/test/bin/noop_c.o b/web3.js/test/bin/noop_c.o deleted file mode 100644 index a6c812d028..0000000000 Binary files a/web3.js/test/bin/noop_c.o and /dev/null differ diff --git a/web3.js/test/bin/noop_c.readme.txt b/web3.js/test/bin/noop_c.readme.txt deleted file mode 100644 index 7836d1b2bf..0000000000 --- a/web3.js/test/bin/noop_c.readme.txt +++ /dev/null @@ -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. \ No newline at end of file diff --git a/web3.js/test/bpf-loader.test.js b/web3.js/test/bpf-loader.test.js index 7deafce3c6..23c855ab88 100644 --- a/web3.js/test/bpf-loader.test.js +++ b/web3.js/test/bpf-loader.test.js @@ -25,7 +25,7 @@ test('load BPF program', async () => { const connection = new Connection(url); 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 transaction = new Transaction().add({ keys: [from.publicKey], diff --git a/web3.js/test/fixtures/noop/build.sh b/web3.js/test/fixtures/noop/build.sh new file mode 100755 index 0000000000..9ed8c83f50 --- /dev/null +++ b/web3.js/test/fixtures/noop/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash -ex + +make -C ../../../examples/bpf-c-noop/ +cp ../../../examples/bpf-c-noop/out/noop.o . diff --git a/web3.js/test/fixtures/noop/noop.o b/web3.js/test/fixtures/noop/noop.o new file mode 100644 index 0000000000..041d82bf46 Binary files /dev/null and b/web3.js/test/fixtures/noop/noop.o differ