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