交易 Transaction
在 Solana
区块链上,程序的执行开始于将交易提交到集群。交易就是链外数据和链上数据产生的一次交互。
每个交易包含一个或多个指令,Solana
的运行环境 Runtime
会将按顺序、原子性地处理交易中包含的每个指令。如果指令的任何部分失败,整个交易将失败。
比如:从账户中扣款,那么这笔交易包括 3 个部分:
- 一个或多个指令
- 一个读取或写入账户的数组
- 一个或多个签名
指令是 Solana
上最小的执行逻辑单元。指令基本上是更新全局 Solana
状态的调用。指令调用程序,该程序调用 Solana
运行环境 Runtime
以更新状态。
Solana
程序不存储状态,状态存储在账户中。
这里的签名是用来验证是否有权读写账户的数据。
1. 交易结构
交易 Transaction 的定义:
pub struct Message { /// The message header, identifying signed and read-only `account_keys`. /// Header values only describe static `account_keys`, they do not describe /// any additional account keys loaded via address table lookups. pub header: MessageHeader, /// List of accounts loaded by this transaction. #[serde(with = "short_vec")] pub account_keys: Vec, /// The blockhash of a recent block. pub recent_blockhash: Hash, /// Instructions that invoke a designated program, are executed in sequence, /// and committed in one atomic transaction if all succeed. /// /// # Notes /// /// Program indexes must index into the list of message `account_keys` because /// program id's cannot be dynamically loaded from a lookup table. /// /// Account indexes must index into the list of addresses /// constructed from the concatenation of three key lists: /// 1) message `account_keys` /// 2) ordered list of keys loaded from `writable` lookup table indexes /// 3) ordered list of keys loaded from `readable` lookup table indexes #[serde(with = "short_vec")] pub instructions: Vec, /// List of address table lookups used to load additional accounts /// for this transaction. #[serde(with = "short_vec")] pub address_table_lookups: Vec, } pub enum VersionedMessage { Legacy(LegacyMessage), V0(v0::Message), } pub struct VersionedTransaction { /// List of signatures #[serde(with = "short_vec")] pub signatures: Vec, /// Message to sign. pub message: VersionedMessage, }
从中可以简单理解为,交易就是一连串的交易指令,以及需要签名的指令的签名内容。
2. 交易指令
上面说到的交易指令又是什么呢?先来看下定义:
pub struct CompiledInstruction { /// Index into the transaction keys array indicating the program account that executes this instruction. pub program_id_index: u8, /// Ordered indices into the transaction keys array indicating which accounts to pass to the program. #[serde(with = "short_vec")] pub accounts: Vec, /// The program input data. #[serde(with = "short_vec")] pub data: Vec, }
从这些成员变量名就可以猜到。交易指令就是执行哪个合约(program_id_index),输入为数据 data,执行过程中需要用到哪些Account: accounts。
类似函数调用一样,program_id_index是函数名,因为合约都是用地址标识的,所以这里指在accounts数组中的第几个地址。
传入的参数包含两部分,二进制数据data和需要使用到的Account资源:accounts。