使用Rust构建Solana程序

本文介绍了如何使用Rust编写和部署Solana区块链上的“Hello, world!”程序,重点介绍了Rust的基础知识、Solana程序的结构以及关键的solana_program crate。文章还解释了模块、crate、路径的概念,以及如何在Solana程序中使用entrypoint!宏和process_instruction函数来处理指令,是Solana入门级别的教程。

有没有想过在 Solana 区块链上创建一个程序需要做些什么?本指南将引导你使用 Rust 编写和部署一个“Hello, world!”程序的基础知识,而不依赖于任何框架。这会给你更多的控制权,但也意味着我们需要自己完成一些基本的工作。

Rust 基础知识快速浏览

在我们开始编写程序之前,让我们回顾一些关键的 Rust 概念。如果你想深入了解,Rust 编程语言 是一份很棒的资源。

组织你的代码:模块、Crates 和 Packages

Rust 有一个组织代码的系统,称为“模块系统”

  • 模块:将模块视为文件夹,可以整齐地组织你的代码并防止名称冲突。 它们可以帮助你控制代码的哪些部分对其他人可见。
  • Crates:Crate 是 Rust 编译的基本代码单元。 它可以是一个(其他项目可以使用的代码集合)或一个可执行程序(你可以直接运行的程序)。 一个 crate 通常由许多模块组成。
  • Packages:Package 是一个或多个 crate 的集合,以及一个描述 package 及其依赖项的特殊文件(称为 Cargo.toml 文件)。

在本指南中,我们将主要关注 crates模块

浏览你的代码:路径和作用域

Crates 包含模块,这些模块可以在不同的项目中共享。 要使用模块中的某些内容,你需要知道它的“路径”,就像在计算机上查找文件一样。

将你的 crate 想象成一棵树的根,模块是分支。 每个分支可以有较小的分支(子模块)或单个项目(如函数或数据结构)。 特定项目的路径就像从 crate 一直追溯到该项目的步骤,每个步骤用 :: 分隔。

例如,solana_program crate 有一个名为 account_info 的模块,该模块又包含一个名为 AccountInfo 的东西。 因此,AccountInfo 的完整路径将是:solana_program::account_info::AccountInfo

通常,每次你想使用 AccountInfo 时都必须写出整个路径。 但是 Rust 有一个方便的关键字叫做 useuse 关键字允许你将项目“引入”到你当前的作用域中,这意味着你可以使用它,而无需每次都输入其完整路径。 你经常会在 Rust 文件的顶部看到一堆 use 语句:

use solana_program::account_info::AccountInfo;

在 Rust 中创建函数

Rust 中的函数使用 fn 关键字定义,后跟函数名称和一组括号:

fn process_instruction()

我们可以通过在括号内列出变量名称及其数据类型来将参数(输入)添加到我们的函数中。

Rust 是一种“静态类型”语言,这意味着每个值都有一个特定的类型(如文本、数字等),Rust 在你的程序运行之前就知道这些类型。 如果 Rust 无法自行确定类型,你需要明确地告诉它。

在我们的“Hello, world!”程序中,我们将使用一个名为 process_instruction 的函数,该函数需要三个参数:

  • program_id:它的类型为 &Pubkey
  • accounts:它的类型为 &[AccountInfo]
  • instruction_data:它的类型为 &[u8]

请注意每个类型前面的 & 吗?在 Rust 中,& 表示你正在创建对另一个变量的“引用”。 这让你的函数可以使用一个值,而无需“拥有”它。 把它想象成看一本书,而没有从别人手中拿走它。 此操作称为“借用”。 当调用 process_instruction 时,它将“借用”提供的值,确保它们是正确的类型。

此外,&[AccountInfo]&[u8] 周围的方括号 [] 表示这些参数期望“切片”。 切片就像列表的一部分,但事先不知道它的确切长度。 因此,accountsinstruction_data 可以接收各种长度的列表。

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
)

函数还可以返回值。 你在括号后的箭头 -> 之后指定返回类型。

我们的 process_instruction 函数将返回一个 ProgramResult 类型,我们将在接下来介绍。

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult

处理结果

Result 是一种标准的 Rust 类型,可帮助你处理可能成功Ok)或失败Err)的情况。 我们稍后将深入探讨“枚举”(enumerations),但现在了解 Result 是好事,因为我们会在程序中看到 Ok

当你使用 OkErr 时,你必须包含一个值。 此值的类型取决于你的代码的期望。 例如,如果一个函数需要返回一个 Result<String, i64>,它可以返回一个带有文本值(String)的 Ok,或者一个带有整数(i64)的 Err。 这里的 i64 可以是一个错误代码。

要用文本消息表示成功:

Ok(String::from("Success!"));

要用数字表示错误:

Err(404);

了解 Solana 程序

请记住,Solana 网络上的所有数据都存储在账户中。 每个帐户都有一个唯一的地址,可以帮助识别和访问其数据。 Solana 程序是一种特殊的 Solana 账户,用于存储在区块链上运行的实际代码。

solana_program Crate

要用 Rust 编写 Solana 程序,我们使用 solana_program 库 crate。 将 solana_program 视为构建 Solana 程序的基本工具包。 它提供了所有必要的模块和工具。

对于一个基本程序,我们需要将以下项目从 solana_program crate 引入到我们的代码中:

use solana_program::{
    account_info::AccountInfo, // 帮助我们获取有关帐户的信息(如地址、余额等)
    entrypoint,                // 一种特殊的工具,用于定义程序从哪里开始
    entrypoint::ProgramResult, // 我们的程序将返回的结果类型
    pubkey::Pubkey,            // 帮助我们处理帐户地址
    msg                        // 一种将消息打印到程序日志的简单方法
};

让我们分解一下这些操作的作用:

  • AccountInfo:一个结构,让我们能访问关于帐户的详细信息,例如其地址、所有者、持有的 Solana 数量、数据大小、是否可执行,以及它是否在当前交易中用于签名或写入。
  • entrypoint:这是一种特殊的工具(宏),用于标记程序开始的函数。 它就像进入我们程序的指令的“前门”。
  • ProgramResult:此类型位于 entrypoint 模块中,告诉我们程序是否成功运行(Result)或遇到错误(ProgramError)。
  • Pubkeypubkey 模块中的一个结构,允许我们使用帐户地址,即公钥。
  • msg:另一种特殊工具(宏),允许我们打印消息。 这些消息会显示在程序的日志中,这对于调试很有帮助。

Solana 程序入口点

每个 Solana 程序都需要一个入口点 —— 一个特定的函数,程序从该函数开始处理指令。 此入口点使用 entrypoint! 宏声明。

Solana 程序的入口点需要一个带有以下参数的 process_instruction 函数:

  • program_id:我们程序代码存储的帐户的地址。
  • accounts:我们的程序需要访问的其他帐户的列表才能完成其工作。
  • instruction_data:随指令附带的任何额外、特定的信息或命令。
entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult;

务必记住,Solana 程序帐户仅存储程序的逻辑。 这意味着它们是“只读”“无状态”的。 简单来说,它们本身不存储任何变化的数据。 “状态”(程序需要使用的实际数据)保存在单独的数据帐户中。

要运行指令,程序需要明确告知要使用哪些数据帐户,方法是通过 accounts 参数传递它们。 任何其他输入都通过 instruction_data 参数传递。

程序运行完成后,必须返回 ProgramResult 类型的值。 此类型是一个 Result,其中成功的结果由 () 表示(表示“无”或空值),失败的结果是 ProgramErrorsolana_program crate 中定义的错误类型)。

结论

你现在已经了解了如何从头开始用 Rust 构建基本的 Solana 程序。 通过了解模块、crates、路径以及 process_instruction 的工作原理,你已经获得了坚实的基础。 这种底层方法使你能更好地控制并更清楚地了解 Solana 程序如何运行。 从这里,你可以开始探索更高级的功能并进一步提高你的技能。

如果你对去中心化基础设施、链上数据系统或使用预言机网络构建真实世界的项目感兴趣,请关注:

  • 原文链接: blog.blockmagnates.com/b...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
blockmagnates
blockmagnates
江湖只有他的大名,没有他的介绍。