这篇应该是正式写代码前最后的理论知识了,我这篇绝对比看官网文档效率高,官网像一个冰冷的机器,而我的是一个有温度的肉体Solana交易入门:从拼装参数到SVM执行我之前学过BTC、Sui和CKB的开发,感觉区块链交易这东西其实挺简单的。说白了,跟Web2调用接口没啥本质
这篇应该是正式写代码前最后的理论知识了, 我这篇绝对比看官网文档效率高, 官网像一个冰冷的机器, 而我的是一个有温度的肉体
我之前学过 BTC、Sui 和 CKB 的开发,感觉区块链交易这东西其实挺简单的。说白了,跟 Web2 调用接口没啥本质区别,就是拼装参数,扔给网络执行。Solana 也不例外,无论是用 SDK 的高级方法直接调用业务逻辑,还是手动拼装底层交易结构,最终都是为了生成一个符合规范的交易包。
下面我结合官方文档和自己的理解,梳理一下 Solana 交易的要点,顺便分享一个转账 SOL 的 JSON 示例,帮你快速入门。
Solana 的交易(Transaction
)本质上是一个数据包,提交后会在 Solana 虚拟机(SVM)中执行。执行者是当前 slot 的 Leader,执行完后广播给其他 Validator 验证。出于网络性能考虑,交易数据包大小被控制在 1232 字节以内,比 IPv4/IPv6 的 1500 字节 MTU 小得多,避免了分片或重组失败的风险。
一个 Transaction
可以包含多个指令(Instruction
),这些指令按你在代码中添加的顺序依次执行,整个交易是原子性的——要么全成功,要么全失败,跟数据库事务或银行转账一个道理。
每个 Instruction
是交易的基本单元,定义了:
programIdIndex
指定。accounts
指定账户索引。data
定义具体方法和参数。用代码调用时,SDK 提供两种方式:
SystemProgram.transfer
,简单省事。Instruction
,写起来复杂,但灵活性更高。我们来看一个实际的转账交易 JSON(发送时是二进制形式,这里是人类可读的表示):
{
"transaction": {
"message": {
"accountKeys": [
"3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R",
"5snoUseZG8s8CDFHrXY2ZHaCrJYsW457piktDmhyb5Jd",
"11111111111111111111111111111111"
],
"header": {
"numReadonlySignedAccounts": 0,
"numReadonlyUnsignedAccounts": 1,
"numRequiredSignatures": 1
},
"recentBlockhash": "DzfXchZJoLMG3cNftcf2sw7qatkkuwQf4xH15N5wkKAb",
"instructions": [
{
"accounts": [0, 1],
"programIdIndex": 2,
"data": "3Bxs4NN8M2Yn4TLb"
}
]
},
"signatures": [
"5LrcE2f6uvydKRquEJ8xp19heGxSvqsVbcqUeFoiWbXe8JNip7ftPQNTAVPyTK7ijVdpkzmKKaAQR7MWMmujAhXD"
]
}
}
这个交易是从账户 3z9v...
转账 100 lamports 到 5sno...
,调用的是 SystemProgram
的 Transfer
方法。下面逐一拆解。
accountKeys
instructions
只需要用索引引用,避免重复写 32 字节的公钥。accountKeys[0]
: "3z9v..."
(付款方)。accountKeys[1]
: "5sno..."
(收款方)。accountKeys[2]
: "1111..."
(SystemProgram
,程序也是账户!)。header
作用:定义 accountKeys
中账户的角色和属性,分为四类:
排序规则:accountKeys
的顺序是固定的:先签名后非签名,先可写后只读。
示例解析:
numRequiredSignatures = 1
:前 1 个账户(3z9v...
)需要签名。numReadonlySignedAccounts = 0
:签名账户中没有只读的,3z9v...
是可写的。numReadonlyUnsignedAccounts = 1
:非签名账户(5sno...
和 1111...
)中,最后 1 个(1111...
)是只读的。3z9v...
:签名 + 可写(付款方)。5sno...
:无签名 + 可写(收款方)。1111...
:无签名 + 只读(SystemProgram
)。一个比较极限的例子:
accountKeys = [A, B, C, D, E, F, G, H, L, M]
(10 个账户):num_required_signatures = 5
:[A, B, C, D, E]
需要签名。num_readonly_signed_accounts = 2
:签名账户中后 2 个(D, E
)是只读,[A, B, C]
是可写。num_readonly_unsigned_accounts = 2
:非签名账户 [F, G, H, L, M]
中后 2 个(L, M
)是只读,[F, G, H]
是可写。A, B, C
:签名 + 可写。D, E
:签名 + 只读。F, G, H
:无签名 + 可写。L, M
:无签名 + 只读。recentBlockhash
message
中,签名者对其签名。getLatestBlockhash
从 RPC 获取(高层方法如 sendAndConfirmTransaction
会自动处理)。"DzfXchZJoLMG3cNftcf2sw7qatkkuwQf4xH15N5wkKAb"
是某个已确认区块的哈希。instructions
programIdIndex
:指向 accountKeys
中的程序账户,决定调用哪个程序。2
-> accountKeys[2]
-> SystemProgram
。accounts
:指向 accountKeys
的索引,指定操作哪些账户,顺序由程序定义。[0, 1]
-> 操作 3z9v...
(付款方)和 5sno...
(收款方)。data
:指定调用程序的哪个方法和参数。"3Bxs4NN8M2Yn4TLb"
解码为 [2, 0, 0, 0, 100, 0, 0, 0]
:
[2, 0, 0, 0]
:Transfer
指令(ID = 2)。[100, 0, 0, 0, 0, 0, 0, 0]
:转账金额 100 lamports。SystemProgram
的 Transfer
从 accounts[0]
转账 100 lamports 到 accounts[1]
。signatures
message
的签名,证明交易授权。accountKeys[0]
(3z9v...
)。具体如何计算暂不深入,以后有需要再研究
Solana 的交易跟其他区块链类似,就是拼装参数扔给网络执行。核心是理解 accountKeys
、header
和 instructions
的关系:
accountKeys
定义所有账户。header
指定账户角色。instructions
描述具体操作。用 SDK 时,高级方法省心,底层拼装灵活,选哪种看需求。希望这篇笔记能帮你快速上手 Solana 交易开发,有问题欢迎留言讨论!
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!