本文介绍了Solana比较重要的一些核心概念和基本原理,包括Solan程序,交易,指令等等
参考文档: HackQuest社区:https://www.hackquest.io/zh Solana中文文档: https://www.solana-cn.com/SolanaDocumention/home.html
更多更及时的文章请访问作者博客 原文链接:https://leapwhale.com/zh/article/q84o82vf
Solana 程序,在其他链上叫做智能合约,是所有链上活动的基础。任何开发者都可以在 Solana 链上编写以及部署程序。每个程序都是一个链上账户,用于存储可执行逻辑,并组织成特定的功能,称为指令。链上的一切活动,从去中心化金融(DeFi),到非同质化代币(NFT),再到社交媒体,链上游戏,都由Solana程序所驱动。
Solana 程序模型的显着特征之一是代码和数据的分离。程序存储在程序账户中,它是无状态的,这意味着它们不会在内部存储任何状态,但它是可执行的executable,会执行相应的逻辑。相反,它们需要操作的所有数据都存储在单独的数据帐户中,这些帐户在 Transaction 交易中通过引用传递给程序账户,因为它本身是不可执行的。
Solana中将程序和状态分离的设计,使得程序可以独立于状态进行开发、测试、部署和升级,提高了程序的可重用性和可扩展性。相反在以太坊中,智能合约和状态是绑定到一起的,合约的升级是一件非常麻烦的事情,必须通过代理模式间接实现逻辑和状态的分离,才可以进行逻辑的升级,并且在新的智能合约中,新增变量的处理要非常小心,避免存储布局 Layout 冲突,覆盖掉旧变量。
Solana程序通常可以分为以下两种:
On-chain Programs:这些是部署在 Solana 上的用户编写的程序,由开发者在 Solana 网络上根据具体业务场景开发的程序。它们可以通过升级权限进行升级,该权限通常是部署程序的帐户或者指定的其他账户。
Native programs:这些是集成到 Solana 核心模块中的程序。它们提供了验证节点(validator)运行所需的基本功能。native programs 只能通过网络范围内的软件更新进行升级。常见的原生程序有:
System Program:这是Solana最基础的原生程序之一。它负责管理新账户的创建和SOL代币在账户之间的转移。System Program的功能包括:
BPF Loader Program 这个程序负责加载和执行其他程序。它将编译后的程序代码加载到Solana运行时环境中,使其可以被执行。BPF Loader的主要功能包括:
Vote program:这个程序在Solana的共识机制中扮演重要角色。它管理验证者节点的投票过程,包括:
记录验证者投票
管理投票账户
计算验证者的权益和奖励
Solana Program Libraries - SPL:虽然SPL不是单一的程序,而是一系列标准化程序的集合,但它们也被视为原生程序的一部分。SPL定义了许多重要的链上活动标准,包括:
代币创建和管理(如SPL Token程序)
代币交换(如SPL Token Swap程序)
借贷协议
质押池管理
链上域名解析服务(如SPL Name Service)
其中 System Program 这个程序负责管理建立新账户以及在两个账户之间转账SOL。Solana SPL 程序定义了一系列的链上活动,其中包括针对代币的创建,交换,借贷,以及创建质押池,维护链上域名解析服务等。
默认情况下,所有新帐户都归系统程序所有。系统程序执行几个关键任务,例如:
New Account Creation: Only the System Program can create new accounts.
只有系统程序拥有的帐户才能用作交易费用支付方。
Solana程序是“无状态的”,这意味着程序帐户仅包含程序的可执行字节码。若要存储和修改其他数据,必须创建新帐户。这些帐户通常称为“数据帐户”。
数据帐户可以存储所有者程序代码中定义的任何任意数据。
请注意,只有系统程序可以创建新帐户。一旦系统程序创建了一个帐户,它就可以将新帐户的所有权转移到另一个程序。
换句话说,为自定义程序创建数据帐户需要两个步骤:
此数据帐户创建过程通常抽象为单个步骤,但了解基础过程很有帮助。
这里我们看一个简单的 solana 程序,这是 Rust 编写的 hello world 程序,实现了简单的日志打印。通常我们将程序写在lib.rs文件中:
// 引入 Solana 程序的相关依赖
use solana_program::{
account_info::AccountInfo,
entrypoint,
entrypoint::ProgramResult,
pubkey::Pubkey,
msg
};
// 程序入口点
entrypoint!(process_instruction);
// 指令处理逻辑
pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8]
) -> ProgramResult{
msg!("Hello, world!");
Ok(())
}
所有的程序都有一个单独的入口点,类似于 Rust 中的main函数,指令的执行就是从这里开始的(即process_instruction),参数须包括:
在实际的项目中,通常不会把所有逻辑都写在lib.rs文件中,为了更清晰的划分功能模块,大部分程序遵循以下架构:
在Solana上,我们发送交易与网络进行交互。交易包括一个或多个 指令,每个指令代表一个要处理的具体操作。指令的执行逻辑存储在部署到Solana网络的程序上,每个程序都存储自己的指令集。
以下是有关如何执行交易的关键细节:
简单来说,可以将交易视为处理一条或多条指令的请求。
Solana交易由以下组成:
交易消息的结构包括:
在进行一笔转账交易后我们可以在区块链浏览器查看相关操作,就可以看见一笔转账交易包含了三个指令:
Solana 网络坚持 1280 字节的最大传输单元 (MTU) 大小,符合IPv6 MTU大小限制,以确保通过 UDP 快速可靠地传输集群信息。在考虑必要的标头(IPv6 为 40 字节,分段为8 字节)后,仍有 1232 个字节可用于数据包的数据,例如序列化交易。
这意味着 Solana 交易的总大小限制为 1232 字节。签名和消息的组合不能超过此限制。
执行一个交易就需要 Compute unit。 如果你熟悉 EVM,CU(Compute unit)就像是gas fee
当然如果你不熟悉也没关系,Solana 就像个由多个节点连接组成的公共巨型计算机,节点运行者往往需要投入大量的物理资源(如CPU, GPU)来维持巨型计算机的稳定运行,为了奖励节点运行者处理链上大量的交易维持网络的稳定,gas费将做为他们贡献的补偿。
当然 CU 的存在还有一些别的目的,比如:
1.通过对交易引入实际成本,减少网络垃圾
2.设定每笔交易的最低费用金额,为网络提供长期的经济稳定性
因此,当用户在链上发送一笔交易时,往往需要支付一笔手续费用于处理交易中所包含的指令。
CU最大限制
由于每笔交易中所包含的指令调用数量和数据量的不同,每笔交易都设定了最大的CU限制——”compute budget”以确保单笔交易的数据量不会过大从而造成网络的拥堵。
每条指令的执行都会消耗不同数量的CU,在消耗了大量的CU后(即消耗的CU已经超出了”compute budget”所限定的最大CU),指令运行将停止并返回错误,从而导致交易失败。
交易费
在一笔转账交易中,我们可以看到其中包含了对于CU limit和CU price的设置。
指令Set Compute Unit Price中,可以看到compute budget 程序将每CU的价格设定为 50000 lamports (1 SOL = 1000,000,000 lamports)
指令Set Compute Unit Limit中,compute budget程序将该笔交易的CU消耗上限设置为200,000. 当一笔交易所有的指令CU消耗超过了200,000时,交易将会失败。
手续费的计算公式为: CU数量 * CU价格 = 手续费用
一笔交易在根据在solana网络上的确认程度可以分为以下几类主要状态:
'processed': 查询已通过连接节点获得1次确认的最新区块
'confirmed': 查询已通过集群获得1次确认的最新区块
'finalized': 查询已由集群完成的最新区块
指令是链上处理特定操作的请求,是 程序中最小的连续执行逻辑单元。
在构建要添加到交易中的指令时,每个指令必须包括以下信息:
AccountMeta
结构体的其他程序。
对于指令所需的每个账户,必须指定以下信息:
pubkey
:账户的链上地址is_signer
:指定是否需要该帐户作为交易的签署者is_writable
:指定是否修改帐户数据这些信息被称为AccountMeta账户元。
通过指定指令所需的所有账户,以及每个账户是否可写,交易可以并行处理。
例如,两个不包含写入相同状态的任何账户的交易可以同时执行。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!