交易 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。