(四)Solana 入门指南——Solana 基本概念

1,500 阅读22分钟

(四)Solana 入门指南——Solana 基本概念

看完上一节教程后,您可能心中存有不少疑问。请放心,本节将深入浅出地介绍Solana的基本概念,帮助您理解Account的含义及其设计初衷,同时阐明它所解决的问题。

1. Solana 的历史

2017年11月,Anatoly Yakovenko 发表了一篇白皮书,介绍了一种名为“Proof of History”(PoH)的技术。PoH 用于在不信任的计算机之间实现时间同步。Anatoly 曾在高通、Mesosphere 和 Dropbox 设计分布式系统,深知可靠的时钟可以简化网络同步,使网络运行速度仅受限于网络带宽。

Anatoly 发现,比特币和以太坊等没有内置时钟的区块链系统每秒只能处理约15笔交易,而要成为像 Visa 这样的全球支付系统,需要每秒处理65,000笔交易。解决时间同步问题后,Anatoly 认为这将是区块链技术的重大突破,可以大幅提升效率和速度。

Anatoly 最初在自己的 GitHub 上用 C 语言实现了 Solana 的原型。Greg Fitzgerald(曾与 Anatoly 在高通共事)建议他用 Rust 语言重写项目。Anatoly 仅用两周时间就完成了迁移,并将项目命名为 Loom。

2018年2月13日,Greg 开始为 Anatoly 的白皮书创建开源实现的原型。2月28日,Greg 发布了首个版本,该版本可以在半秒内处理超过10,000个签名交易。随后,Stephen Akridge(另一位前高通同事)展示了如何利用图形处理器加速签名验证,进一步提升了处理速度。Anatoly 邀请 Greg、Stephen 和其他三人共同创立了 Loom 公司。

然而,当时已有一个基于以太坊的项目也叫 Loom Network,为了避免混淆,团队决定重新命名项目。最终,他们选择将项目命名为 Solana,以纪念他们在圣地亚哥北部的 Solana Beach 工作和冲浪的三年时光。2018年3月28日,团队在 GitHub 上创建了 Solana 项目,并正式命名 Greg Fitzgerald 创建的原型为 Solana。

自此,Solana 项目迅速发展,成为高性能区块链平台的代表之一。

2. Solana 与以太坊的差异

了解 Solana 和以太坊的技术细节和生态系统的差异对于开发者和生态参与者至关重要。

一、共识机制

Solana

  • Proof of History (PoH) + Proof of Stake (PoS):Solana 使用独特的 PoH 机制来记录和验证区块的时间戳和顺序,通过在每个区块中引入时间证明,使得节点能够迅速达成共识,而无需等待整个网络确认。PoS 机制用于选择验证者,验证者通过抵押一定数量的代币来参与网络验证。持有更多代币的验证者有更大的机会被选中生成新的区块和验证交易。
  • 优势:PoH 确保区块的时间戳和顺序,PoS 确保网络的安全性和抗攻击性,使得 Solana 成为一个适用于高性能去中心化应用和高频交易场景的区块链平台。

以太坊

  • Proof of Stake (PoS):以太坊于 2022 年 9 月完成了从 Proof of Work (PoW) 到 PoS 的以太坊 2.0 版本升级。这次升级将保护以太坊安全所需的能源消耗减少了 99.95%,同时创建了一个更安全、碳成本更低的以太坊网络。
  • 优势:PoS 提高了网络的安全性和可持续性,降低了能源消耗。

二、交易处理能力

Solana

  • 并行处理:Solana 支持对交易的并行处理,通过将交易分成多个子集,并将每个子集分配给不同的验证节点进行处理,从而实现交易的并行处理。这种方法可以显著提高交易吞吐量,同时保证交易的安全性和可靠性。
  • 性能:Solana 的平均出块时间为 400 毫秒,平均每秒处理 2000+ 笔交易,在高负载时保持较低的交易费用。

以太坊

  • 串行处理:以太坊每笔交易串行执行,一笔交易执行完成再开始下一笔交易,状态依次更新,这限制了以太坊的吞吐量长期维持在每秒 15 笔~30 笔。
  • 提升方案:以太坊通过 Layer 2 的 Rollup 方案来提升交易处理能力,Rollup 将数百笔交易捆绑为以太坊网络上的单笔交易,能够将燃料费减少多达 100 倍。2024 年初即将上线的 Proto-Danksharding 升级将进一步降低 gas 费,提升交易吞吐量。

三、交易费用(Gas费)

Solana

  • 动态计算:Solana 的交易费用是根据交易的复杂度和大小动态计算的,这意味着交易费用会根据交易的执行成本而变化,而不是根据网络上的交易量变化。
  • 费用:Solana 的平均交易费用通常低于 0.01 美元,平均为 0.00025 美元,这使得进行小额交易更具成本效益。

以太坊

  • 市场机制:以太坊的交易费用因网络拥堵而波动,这是一种纯粹的市场机制。在网络中交易拥堵情况下,交易要想被确认,就需要支付高昂的手续费。目前一笔转账交易的手续费大概在 1 ~ 10 美元左右。
  • EIP-1559:以太坊的 EIP-1559 升级引入了一种新的费用市场机制,旨在使费用更可预测。

四、智能合约

Solana

  • 程序账户和数据账户:Solana 的智能合约(称为程序)也是账户,但细分为可执行账户和数据账户。可执行账户存储程序的代码,用于执行特定的逻辑;数据账户存储状态,即程序运行时的数据。这种分离的模式使得程序的升级更加简单,因为程序本身无状态,可以直接升级为新的代码逻辑。

以太坊

  • 合约账户:以太坊的智能合约本身就包含了合约的逻辑代码和状态数据。因此,合约部署之后,不支持直接的升级,只能通过代理的方式间接升级,即重新部署一套合约代码,生成新的合约地址,代理再指向这个新的合约地址。

五、账户

Solana

  • 一切皆账户:Solana 的账户像一个容器,可以包含程序代码、状态数据以及账户元数据。按功能可划分为可执行账户和数据账户。可执行账户存储程序代码,数据账户存储用户的余额、交易历史和其他相关数据。
  • 优势:这种单一账户模型使得多个交易能够并行处理,这是 Solana 高性能的基础。

以太坊

  • EOA 账户和合约账户:以太坊分为 EOA 账户和合约账户。EOA 账户是普通用户在以太坊网络中的账户,用于存储以太币(ETH)和进行交易。合约账户包含智能合约代码和状态,这些账户由合约创建并部署在以太坊区块链上。
  • 优势:通过这两种账户类型的结合,以太坊提供了一个灵活且功能强大的去中心化应用开发平台。

六、编程语言和开发友好性

Solana

  • 支持多种语言:Solana 支持包括 Rust 和 C 在内的多种编程语言,这些语言以高性能而闻名。
  • 优势:Rust 语言的安全性和高性能为开发者提供了强大的工具。

以太坊

  • Solidity:以太坊的 Solidity 语言是专门为智能合约设计的,拥有大量的开发工具和广泛的开发者社区,这为新加入的开发者提供了丰富的资源和支持。
  • 优势:Solidity 的成熟生态和丰富的工具链为开发者提供了便利。

七、生态系统和用户基础

Solana

  • 快速发展:Solana 正在快速建立其生态系统,但相对于以太坊来说还较新,存在很多机会。
  • 优势:Solana 的高性能和低成本为那些需要这些特性的应用提供了优势。

以太坊

  • 成熟生态:以太坊拥有最大的去中心化应用(DApp)生态系统,以及广泛的用户和开发者社区,这为其提供了强大的网络效应和更高的去中心化程度。
  • 优势:以太坊的广泛采用和成熟的生态系统为其提供了稳定性和信任。

3. 什么是PoH

比特币创世区块

比特币创世区块中,中本聪引用了2009年1月3日《泰晤士报》的头条新闻:“财政大臣濒临第二次救助银行”。这表明创世区块至少是在这一天或之后生成的。所有后续的比特币交易都发生在这一时间点之后。

时间戳与历史事件序列

如果所有交易都有时间戳,并按顺序记录,这就形成了一个基于时间的历史事件序列。要证明某笔交易存在于此序列中,只需从历史记录中查找即可。

Hash函数

Solana 使用 SHA-256 哈希函数,它将任意长度的输入转换为固定长度的输出。SHA-256 的主要特性包括:

  1. 唯一性:每个不同的输入对应唯一的哈希值,且从哈希值反推出原始输入在计算上不可行。
  2. 敏感性:输入的微小变化会导致输出哈希值的显著变化。
  3. 一致性:相同的输入始终产生相同的哈希值。

PoH 工作流程

PoH(Proof of History)通过以下步骤记录时间顺序:

  1. 初始化:从一个随机值开始,运行哈希函数。
  2. 迭代:将上一次的输出作为新输入,继续运行哈希函数。
  3. 记录:记录每次哈希运算的次数(index)和结果(output)。
  4. 形成证据链:通过连续的哈希运算,形成一条不可篡改的证据链。

例如,从一个随机值开始,经过300次哈希运算,可以得到一个特定的哈希值。这个过程确保了时间顺序的不可篡改性。

PoH 的可验证性

PoH 流是可验证的有序数据结构。在进行哈希计算时,会加入额外数据(如哈希次数、事件信息等),确保可以确定哈希(区块)的先后顺序。

PoH 的广播

生成新区块时,Solana 会将块的数据和结构切片,并在多核 GPU 上并行验证。验证完成后,区块在网络中广播。由于区块的时序性和一致的时间钟,各节点可以轻松验证区块的有效性和顺序。

通过 PoH,Solana 实现了全局一致的时间钟,确保了交易的顺序性和安全性。

4. 什么是PoS

在Solana的系统中,有两种关键角色:Leader(出块者)Validator(验证者)。两者都是质押了SOL代币的全节点,但Leader负责创建新区块,而Validator则验证这些区块。Leader按周期轮换,未当选的节点则作为Validator。Solana使用PoS(权益证明)机制来挑选验证者,即节点通过质押SOL代币来获得参与交易验证的资格。质押更多的代币可以增加被选为Leader的机会。

Solana如何通过PoS指定Leader

  • 时间单位:Solana的共识协议使用**Epoch(纪元)Slot(间隔)**两个时间单位。每个Slot约为0.40.8秒,代表一个区块的生成时间;每个Epoch包含约43.2万个Slot,持续24天。
  • Leader选举:每个新的Epoch开始时,根据节点质押的代币数量、性能、网络延迟和可用性等标准,Solana会选出一系列Leader,安排他们在未来的特定时刻担任出块者的角色。Leader名单会在Epoch开始前确定,确保出块过程的透明和高效。

Solana的工作流程

  1. 生成交易:用户创建并广播带有数字签名的交易。
  2. 排序:交易通过哈希链接到PoH(Proof of History)链上,形成有序的交易序列。
  3. 验证:Validator节点验证交易的有效性,并决定哪些交易进入下一个区块。
  4. 打包区块:选定的交易被打包成区块,包括当前PoH链的哈希值。
  5. 传播与确认:区块被广播至全网,其他节点验证其有效性。一旦确认,该区块及其交易即被加入区块链中。

通过这种方式,Solana结合了PoH的时间有序特性和PoS的验证机制,实现了快速、低成本的交易处理。

5. Solana 账户

在了解完历史证明(PoH)的概念后,让我们一起来学习 Solana 中最重要的概念之一:账户。Solana 作为一个分布式区块链系统,所有的信息都存储在账户中,包括智能合约(Solana 称为 Onchain Program)、状态信息、Token 数据和配置信息等。

以太坊的账户类型

在学习 Solana 账户之前,我们先回顾一下以太坊的账户类型:

  1. 外部账户(EOA)

    • 由个人通过私钥创建。
    • 控制该账户的人必须拥有对应的私钥。
    • 特点:
      • 拥有以太币余额。
      • 可以发送交易,包括转账和执行合约代码。
      • 没有相关的可执行代码。
  2. 合约账户

    • 含有合约代码的账户。
    • 由外部账户或另一个合约创建。
    • 存储合约代码和执行过程中产生的状态数据。
    • 地址通过 SHA3 哈希算法生成,没有私钥。
    • 只能通过外部账户调用合约代码。

Solana 账户

Solana 账户的最大不同在于将代码和数据分开存储,具体分为两种类型:

  1. 程序账户(可执行账户)

    • 存储不可变的数据,主要用于存储程序的代码(BPF 字节码)。
    • 是无状态的,不存储任何状态信息。
  2. 数据账户(不可执行账户)

    • 存储可变的数据,主要用于存储程序的状态。
    • 如果一个程序账户是某个数据账户的所有者,它可以修改该数据账户中的状态。

Solana 账户的分类

  1. 用户账户

    • 普通的用户钱包,类似于以太坊的 EOA 账户。
  2. 程序账户

    • 执行特定任务的账户,存储程序的二进制文件。
  3. PDA (程序派生地址)

    • 存储程序的状态,即程序执行过程中存储的数据。
    • 由程序的 program_id 和种子(seed)派生而来,没有对应的私钥。
  4. ATA (关联 Token 账户)

    • 关联用户与特定的 SPL Token 代币,方便用户管理持有的代币。

Solana 账户的定义

pub struct Account {
    /// 余额
    pub lamports: u64,
    /// 数据
    pub data: Vec<u8>,
    /// 所有者
    pub owner: Pubkey,
    /// 是否可执行账户
    pub executable: bool,
    /// 下次收租的时期
    pub rent_epoch: Epoch,
}
  • lamports: 表示账户余额,是 Solana 中的基本货币单位。
  • data: 存储的内容,是一个字节数组,可以包含任意类型的数据。
  • owner: 拥有或管理该账户的程序的公钥。
  • executable: 表示是否可执行,如果为 true,表示该账户中的数据可以被执行,是程序账户。
  • rent_epoch: 表示下一次该账户将被扣除租金的时期。

租金(Rent)

Solana 账户模型中有一个特殊的“租金”概念。租金与交易费用不同,用户支付租金以将数据存储在 Solana 区块链上。如果账户无法支付租金,系统将删除该账户。如果账户中的资产超过两年租金的最低余额,该账户可以免交租金。Solana 上的租金存储费用为每字节 0.00000348 SOL/年,钱包数据大小为 372 字节,每个活跃钱包持有者必须保留 0.0026 SOL。

PDA (程序派生地址)

什么是 PDA?

PDA(Program Derived Address)是一种特殊类型的地址,由 Solana 的程序生成,而不是由用户的私钥直接派生。PDA 的主要目的是允许程序拥有和控制某些数据或资产,而不需要传统的私钥签名。

私钥、公钥与助记词
  • 私钥:用于签名交易,保证交易的安全性。
  • 公钥:从私钥推算得出,用于标识账户。
  • 助记词:通过算法可以从助记词推算出私钥,方便用户记忆。

11c6df8f-f3f0-4c87-bbe5-6eb12b7f7031.webp 如上图所示(这是一个简化的图示),每一个 X 轴私钥会在曲线上对应一个 Y轴公钥,**但是 Q 点的 公钥没有对应任何一个 X 轴上的私钥。那么这就意味着这个公钥没有对应的私钥!**这意味着这个公钥不是从私钥派生/衍生(Secret Key Derived)出来的。

这就是 PDA 的原理,“程序派生地址”(Program Derived Address)是没有对应的私钥的,它是由一个程序的program_id和seed派生/衍生出来的,这也是为什么它被称之为“程序派生地址”(Program Derived Address)。有时候我们通过 program_id 和 seed 获得的公钥正好有对应的私钥,那么这种情况下我们就需要重新生成一个公钥,通常是在我们的 program_id 和 seed 之外再加上一个数字(这个数字有个专有名词叫 bump),这个数字从 255 开始,依次往下,直到生成的公钥没有私钥为止。

**概括的说:**PDA 的公钥没有对应的私钥,由程序的 program_id 和种子(seed)派生而来。如果生成的公钥恰好有对应的私钥,需要加上一个数字(bump),从 255 开始,依次往下,直到生成的公钥没有私钥为止。

为什么需要 PDA?

在区块链中,需要一个私钥来证明对公钥的所有权。但对于去中心化程序,将私钥放在程序上是不安全的。PDA 通过没有私钥的地址,允许程序对地址进行签名操作,从而避免了私钥泄露的风险。

如何生成 PDA 地址?

使用 Solana 的 Anchor 开发框架,可以生成 PDA 账户。

// PDA 账户存储的数据
#[account]
pub struct Counter {
    count: u64
}

#[derive(Accounts)]
pub struct InitializeAccounts<'info> {
		#[account(
			init, 
			seeds = [b"my_seed", 
							 user.key.to_bytes().as_ref()
							]
			bump,
			payer = user, 
			space = 8 + 8
		)]
		pub pda_counter: Account<'info, Counter>,
}

其中的pda_counter字段为要生成的PDA账户,该字段标记了初始化时使用的seeds值及bump。这里的seeds可以根据业务场景设置为任意字节数组,Anchor会默认使用符合条件的第一个bump值,无需手动指定。同时,Anchor内部也会自动获取program_id,同样无需手动指定。

Solana 程序

什么是程序?

Solana 程序(在其他链上称为智能合约)是所有链上活动的基础。任何开发者都可以在 Solana 链上编写和部署程序,驱动各种链上活动,如 DeFi、NFT、社交媒体和链上游戏等。

Solana 程序的类型
  1. On-chain Programs
    • 由开发者根据具体业务场景开发的程序。
    • 可以通过升级权限进行升级。
  2. Native Programs
    • 集成到 Solana 核心模块中的程序。
    • 提供验证节点(validator)运行所需的基本功能。
    • 只能通过网络范围内的软件更新进行升级。
    • 常见的原生程序有 System ProgramBPF Loader ProgramVote programSolana Program Libraries - SPL等。其中 System Program 这个程序负责管理建立新账户以及在两个账户之间转账SOL。Solana SPL 程序定义了一系列的链上活动,其中包括针对代币的创建,交换,借贷,以及创建质押池,维护链上域名解析服务等。

e673a07d-72da-4dd7-91c7-0dddcfa50ea5.webp

Solana 程序的特点
  • 代码和数据的分离:程序存储在程序账户中,是无状态的,不存储任何状态信息。相反,所有数据都存储在单独的数据账户中。
  • 可重用性和可扩展性:程序可以独立于状态进行开发、测试、部署和升级,提高了程序的可重用性和可扩展性。
  • 分片和并行处理:状态数据以账户形式存储在网络中,方便进行分片和并行处理,提高了 Solana 网络的吞吐量和效率。

通过这种设计,Solana 提高了程序的可重用性和可扩展性,同时也提高了网络的吞吐量和效率,使得网络的升级和维护变得更加容易。

6. 交易与指令

交易(Transaction)

交易是一组原子性的操作,代表对区块链状态的一系列更改,包括转账代币、调用程序、更新账户状态等。每个交易都具有唯一的签名,并由一个或多个指令组成。交易费用通常使用 Solana 的原生代币 SOL 支付。

签名:每个交易都必须由一个或多个账户的私钥进行签名,以确保交易的身份和完整性。

指令(Instruction)

指令是交易中的一条具体指令,包含执行指令所需的具体数据,例如执行指令的程序唯一标识 program_id、账户列表、指令参数、配置信息等,用于执行一个特定的操作。

多个指令组成的交易可以实现多个不同的操作,形成一个原子性的事务。也就是说,要么所有指令都成功执行,要么全部失败。

当我们需要通过 Solana 发起一笔转账或调用一个程序时,就需要通过交易(Transaction)来完成。每个交易包含以下内容:

  • instructions:一个或多个指令
  • blockhash:最新的块哈希值
  • signatures:指令对应的发起人的签名

我们通过交易与 Solana 发生交互,而交互的最小单元就是交易中的指令(Instruction)。一个交易可以包含多个指令,每个指令指定调用哪个程序、要读取或修改哪些账户,以及执行程序需要的额外数据。

例如,上一节的increment函数就是一个指令

// 增加计数器的函数
pub fn increment(ctx: Context<Increment>) -> Result<()> {
    // 获取当前计数器的值,并将其增加 1
    ctx.accounts.counter.count = ctx.accounts.counter.count.checked_add(1).unwrap();
    // 返回成功结果
    Ok(())
}
// ...

交易费用

执行一个交易需要 Compute Unit (CU)。如果你熟悉以太坊虚拟机(EVM),CU 类似于 gas fee。

Solana 可以看作是由多个节点连接组成的公共巨型计算机,节点运行者需要投入大量物理资源(如 CPU、GPU)来维持巨型计算机的稳定运行。为了奖励节点运行者处理链上大量的交易并维持网络的稳定,用户需要支付交易费用作为补偿。

CU 的存在还有其他目的,例如:

  1. 通过对交易引入实际成本,减少网络垃圾。
  2. 设定每笔交易的最低费用金额,为网络提供长期的经济稳定性。

因此,当用户在链上发送一笔交易时,需要支付一笔手续费用于处理交易中所包含的指令。

CU 最大限制

由于每笔交易中所包含的指令调用数量和数据量不同,每笔交易都设定了最大的 CU 限制——“compute budget”,以确保单笔交易的数据量不会过大,从而避免网络拥堵。

每条指令的执行都会消耗不同数量的 CU。如果消耗的 CU 数量超过“compute budget”所限定的最大 CU,指令运行将停止并返回错误,导致交易失败。

交易费计算

在一笔转账交易中,我们可以看到其中包含了对 CU limitCU price 的设置。

  • Set Compute Unit Price:将每 CU 的价格设定为 50000 lamports(1 SOL = 1000,000,000 lamports)。
  • Set Compute Unit Limit:将该笔交易的 CU 消耗上限设置为 200,000。如果一笔交易的所有指令 CU 消耗超过 200,000,交易将会失败。

手续费的计算公式为:CU 数量 * CU 价格 = 手续费用

交易的确认

一笔交易在 Solana 网络上的确认程度可以分为以下几类主要状态:

  1. processed:查询已通过连接节点获得 1 次确认的最新区块。
  2. confirmed:查询已通过集群获得 1 次确认的最新区块。
  3. finalized:查询已由集群完成的最新区块。

通过这些状态,用户可以了解交易在 Solana 网络上的确认进度,确保交易的安全性和可靠性。

最后

通过本节的学习,希望您对Solana有了更深刻的理解,不仅掌握了其设计理念,还了解了它的实现目标。若您认为本系列教程对您有所帮助,建议收藏并持续关注,以便及时获取更多更新和支持。感谢您的阅读!