7.8 KiB
title |
---|
用 C 语言开发 |
Solana 支持使用 C 和 C++ 语言编写链上的程序。
项目布局
C 项目规定如下:
/src/<program name>
/makefile
makefile
应该包含以下内容:
OUT_DIR := <path to place to resulting shared object>
include ~/.local/share/solana/install/active_release/bin/sdk/bpf/c/bpf.mk
Bpf-sdk可能不在上面指定的确切位置,但是如果您根据如何开发来设置环境,那么就是这样。
来看一下的 C 程序的helloworld示例。
如何开发
首先设置环境:
- 从https://rustup.rs安装最新的Rust稳定版本
- 从https://docs.solana.com/cli/install-solana-cli-tools安装最新的Solana命令行工具
然后使用make构建:
make -C <program directory>
如何测试
Solana 使用 Criterion 测试框架,并且在每次构建程序时都会执行测试,如何开发。
要添加测试,请在源文件test_<program name>.c
旁边创建一个新文件,并使用标准测试用例填充它。 有关示例,请参见helloworld C测试或Criterion文档,获取编写测试用例的信息。
程序入口点
程序导出一个已知的入口点符号,在调用程序时,Solana运行时将查找并调用该入口点符号。 Solana支持多个BPF加载程序版本,它们之间的入口点可能会有所不同。 程序必须为相同的加载器编写并部署。 有关更多详细信息,请参见概览。
当前有两个受支持的加载器:BPF加载器和已弃用BFT加载器。
它们都有相同的原始入口点定义,以下是运行时查找和调用的原始符号:
extern uint64_t entrypoint(const uint8_t *input)
该入口点采用通用字节数组,其中包含序列化的程序参数(程序ID,帐户,指令数据等)。 为了反序列化参数,每个加载器都包含其自己的帮助器函数。
请参阅 使用入口点的简单实例,来看看它们是如何配合使用的。
序列化
每个加载程序都提供一个帮助程序功能,该功能将程序的输入参数反序列化为 C 类型:
某些程序可能希望自己执行序列化,并且可以通过提供其自己的原始入口点实现来实现。 请注意,提供的反序列化功能会将引用保留回序列化字节数组,以引用允许程序修改的变量(lamport,帐户数据)。 这样做的原因是,在返回时,加载程序将读取这些修改,以便可以将其提交。 如果程序实现其自己的反序列化功能,则需要确保将程序希望进行的所有修改都写回到输入字节数组中。
有关加载程序如何序列化程序输入的详细信息,请参见Input Parameter Serialization文档。
数据类型
加载程序的反序列化助手函数将填充SolParameters结构:
/**
* 程序进入点输入数据被反序列化的结构。
*/
typef structt volt_
SolAccountInfo* ka; /** 指向SolAccountInfo阵列的指针, 必须已经
指向一个 SolAccountInfos */
uint64_t ka_num; /** `ka`中的 SolAccountInfo 条目数 */
const uint8_t *数据; /** 指示数据指针*/
uint64_t data_len; /** 指令数据字节长度 */
const SolPubkey *program_id; /** 当前正在执行的程序 */
} Solameters;
“ ka”是指令引用帐户的有序数组,并表示为SolAccountInfo结构。 帐户在数组中的位置表示其含义,例如,在转移lamports时,一条指令可以将第一个帐户定义为源,将第二个帐户定义为目的地。
AccountInfo
结构的成员是只读的,但lamports
和data
除外。 程序都可以根据runtime执行策略对两者进行修改。 当一条指令多次引用相同的帐户时,数组中可能有重复的SolAccountInfo
条目,但它们都指向原来的输入字节数组。 程序应谨慎处理这些情况,以避免对同一缓冲区的读/写重叠。 如果程序实现其自己的反序列化功能,则应注意适当地处理重复帐户。
数据
是正在处理的指令的指令数据中的通用字节数组。
program_id
是当前正在执行的程序的公钥。
堆(Heap)
C 程序可以通过系统调用calloc
或者通过虚拟的 32 Kb heap 区域顶部实现它们自己的堆地址 x300000000。 堆区域也被 calloc
使用,因此如果一个程序实现了自己的堆,它不应该同时调用 calloc
。
日志
运行时提供了两个系统调用,这些系统调用将获取数据并将其记录到程序日志中。
调试 章节有更多关于程序日志工作的信息。
计算预算
使用系统调用sol_log_compute_units()
记录包含剩余编号的消息暂停执行之前程序可能消耗的计算单元数。
相关的更多信息,请参见计算预算。
ELF转储
可以将BPF共享对象的内部信息转储到文本文件中,以更深入地了解程序的组成及其在运行时的工作方式。 转储将包含ELF信息以及所有符号和实现它们的指令的列表。 一些BPF加载程序的错误日志消息将引用发生错误的特定指令号。 可以在ELF转储中查找这些引用,以标识有问题的指令及其上下文。
创建一个转储文件:
$ cd <program directory>
$ make dump_<program name>
示例
Solana 程序库github代码库包含了 C 语言的例子集合。