From 89efc3b4ebc11139a73a4d5c97f99ab710e29d3c Mon Sep 17 00:00:00 2001 From: Sonic Date: Thu, 10 Oct 2024 13:56:53 +0300 Subject: [PATCH] feat: add C version of CPI program (#6) * feat: add C CPI program * add forgotten CI step & more comments --- .github/workflows/main.yml | 2 +- README.md | 1 + cpi/c/Makefile | 49 +++++++++++++++++++++++++++++++ cpi/c/src/main.c | 53 ++++++++++++++++++++++++++++++++++ transfer-lamports/c/src/main.c | 2 +- 5 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 cpi/c/Makefile create mode 100644 cpi/c/src/main.c diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7c31d04..12ac923 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -80,7 +80,7 @@ jobs: name: Run tests against C implementations strategy: matrix: - program: [helloworld, transfer-lamports] + program: [helloworld, transfer-lamports, cpi] fail-fast: false runs-on: ubuntu-latest steps: diff --git a/README.md b/README.md index 2be463f..82ef07a 100644 --- a/README.md +++ b/README.md @@ -181,3 +181,4 @@ the address and `invoke_signed` to CPI to the system program. | --- | --- | | Rust | 3662 | | Zig | 3141 | +| C | 3122 | diff --git a/cpi/c/Makefile b/cpi/c/Makefile new file mode 100644 index 0000000..7a889b1 --- /dev/null +++ b/cpi/c/Makefile @@ -0,0 +1,49 @@ +LOCAL_PATH := ../../solana-c-sdk/c/ + +.PHONY: all clean + +SRC_DIR ?= ./src +OUT_DIR ?= ./out + +all: $(OUT_DIR)/solana_program_rosetta_cpi.so + +clean: + rm -rf $(OUT_DIR) + +LLVM_DIR = $(LOCAL_PATH)../dependencies/platform-tools/llvm +LLVM_SYSTEM_INC_DIRS := $(LLVM_DIR)/lib/clang/17/include +STD_INC_DIRS := $(LLVM_DIR)/include +STD_LIB_DIRS := $(LLVM_DIR)/lib + +CC := $(LLVM_DIR)/bin/clang +LLD := $(LLVM_DIR)/bin/ld.lld + +SYSTEM_INC_DIRS := \ + $(LOCAL_PATH)inc \ + $(LLVM_SYSTEM_INC_DIRS) \ + +C_FLAGS := \ + -Werror \ + -O2 \ + -fno-builtin \ + -std=c17 \ + $(addprefix -isystem,$(SYSTEM_INC_DIRS)) \ + $(addprefix -I,$(STD_INC_DIRS)) \ + -target sbf \ + -fPIC + +SBF_LLD_FLAGS := \ + -z notext \ + -shared \ + --Bdynamic \ + $(LOCAL_PATH)sbf.ld \ + --entry entrypoint \ + -L $(STD_LIB_DIRS) \ + -lc \ + +$(OUT_DIR)/main.o: $(SRC_DIR)/main.c + mkdir -p $(OUT_DIR) + $(CC) $(C_FLAGS) -o $(OUT_DIR)/main.o -c $(SRC_DIR)/main.c + +$(OUT_DIR)/solana_program_rosetta_cpi.so: $(OUT_DIR)/main.o + $(LLD) $(SBF_LLD_FLAGS) -o $(OUT_DIR)/solana_program_rosetta_cpi.so $(OUT_DIR)/main.o diff --git a/cpi/c/src/main.c b/cpi/c/src/main.c new file mode 100644 index 0000000..6d3c43e --- /dev/null +++ b/cpi/c/src/main.c @@ -0,0 +1,53 @@ +/** + * @brief C-based CPI BPF program + */ +#include + +/// Amount of bytes of account data to allocate +#define SIZE 42 + +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; + } + + SolAccountInfo allocated_info = params.ka[0]; + SolAccountInfo system_program_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)}, + {¶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; + } + + // allocated key does not match the derived address + if (!SolPubkey_same(&expected_allocated_key, allocated_info.key)) + { + return ERROR_INVALID_ARGUMENT; + } + + SolAccountMeta arguments[] = {{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)); +} diff --git a/transfer-lamports/c/src/main.c b/transfer-lamports/c/src/main.c index 906b5c6..0800b9c 100644 --- a/transfer-lamports/c/src/main.c +++ b/transfer-lamports/c/src/main.c @@ -1,5 +1,5 @@ /** - * @brief C-based Helloworld BPF program + * @brief C-based Transfer Lamports BPF program */ #include