本文详细介绍了Solana区块链的基本构建模块,包括账户、程序、指令、交易、RPC和订阅等内容,适合初学者和有经验的开发者阅读,帮助他们快速理解并开始Solana开发。
Solana 区块链是一个强大的工具,每秒可处理数千笔交易,几乎没有交易费用。如果你对 Web3 感到陌生,或者之前在基于 EVM 的区块链上开发过,这份指南将帮助你理解 Solana 的基本元素,并开启你在 Solana 开发的旅程。如果你已经在 Solana 上进行开发,可以将这份指南作为参考,继续增强你对 Solana 基础知识的理解。
在本指南中,我们将介绍 Solana 的基本构建块,具体包括:账户、程序、指令、交易、RPC 和订阅。让我们开始吧!
渴望了解更多?继续阅读!👇
Solana 是一个优化速度和成本的开源区块链,它允许信息和状态在全球范围内同步。Solana 利用一种称为历史证明的独特形式的权益证明共识,该共识使用细粒度可验证延迟函数来有效地对发送到网络的交易进行时间戳和排序。根据 Anatoly Yakovenko 在 Solana 白皮书 中所说,“它使用了一种密码学上安全的函数,以便输出不能通过输入来预测,并且必须完全执行才能生成输出”(3)。“领导者在系统中对用户消息进行排序,以便其他节点能够有效地处理,从而最大化吞吐量”(2)。
在本文中,我们将对 Solana 的运行时进行的探讨大致到此为止,接下来我们将转向如何与 Solana 互动和构建。如果你想深入了解 Solana 的架构及其某些设计特征背后的理论,这里有几个很好的资源:
像操作系统中的文件一样,账户用于运行系统、存储数据或状态以及执行代码。
在 Solana 上有三种主要类型的账户:
本文将重点讨论 #1 和 #2。如果你想了解更多关于 #3 本地系统账户的信息,请查看 docs.solana.com。
简而言之,Solana 上几乎所有东西都是一个账户。最常见的账户类型是用户钱包,这是一个管理用户 SOL 余额状态的数据账户。
每个账户都有一个独特的地址或公钥(很像文件路径)以及一组相关的元数据:
lamports 是 SOL 的最小面额,是 Solana 的原生代币(代表一个 SOL 的十亿分之一)
可以通过运行 getAccountInfo JSON RPC 查询 或在 Solana Explorer 上搜索来读取任何账户的元数据。Solana Explorer 允许你搜索任何账户,并查看有关该账户类型和关联程序的基本详细信息。下面是一个系统拥有数据账户(用户钱包)的示例:
让我们可视化所有账户类型的示例:
这里有很多内容,但你在此图中看到的每个元素都是一个账户。在左侧,我们有一个名为系统程序的系统账户,管理所有用户钱包。我们还拥有一个可执行程序账户,称为 Solana SPL Token Program,用户可以用来铸造、销毁和转移 SPL 代币。最后,我们有程序派生账户。在这种情况下,这些是由 Token Program 拥有并与用户账户关联的代币账户。请注意,一个用户钱包可以拥有多个代币账户。
请记住,你可以在 Solana Explorer 中搜索任何账户地址,以获取其元数据,并了解它的账户类型及其关联的程序。
Lamports 和租赁纪元:账户及其所包含的数据存储在验证者的内存中,并要求以 lamports(在账户的 lamports 元数据字段中表示)支付“租金”,以维持存储状态。存储在账户中的数据越多,所需的租金就越多 (注意:当前账户的最大大小为 10MB)。你可以使用 JSON RPC 方法 getMinimumBalanceForRentExemption 计算租赁要求。验证者负责定期扫描所有账户并收取租金——账户在 rent_epoch 元数据字段中标识的纪元进行检查。如果一个账户的 lamport 余额降至零,网络将清除该账户,数据将会丢失。在撰写本文时,所有新账户均需保持免租状态,该状态的获得是通过在账户中持有 2 年的租金。来源:https://docs.solana.com/developing/programming-model/accounts。纪元是 Solana 上时间的度量,目前大约代表 2.5 天。
程序是 Solana 所称的智能合约——它们是处理信息和请求的引擎:从代币转账和 Candy Machine 铸造到 "hello world" 日志和 DeFi 托管治理。
实际上,用户必须向程序提供特定于程序的指令,程序处理这些指令,然后程序可能调用其他程序和/或更新它拥有的程序派生账户(PDAs,详细见下文)。
程序派生地址(PDA)是由特定程序创建和控制的账户。PDA:
这使得程序能够提供无信任服务,例如安全管理交易、下注或 DeFi 协议的托管账户。如果我们参考上面的示意图,SPL Token Program 会根据用户的钱包和特定代币的铸造地址为用户生成一个 PDA。该 PDA 将存储用户拥有的该代币的数量或数据的状态。
让我们深入了解如何使程序与指令和交易协同工作。
指令的核心是告知程序执行某个操作。Solana 将指令定义为“程序中的最小连续执行逻辑单元。” (来源:docs.solana.com/terminology)。
一条指令由三个部分组成:
最后一点是至关重要的——指令是特定于程序的。如果你输入错误的程序 ID 或不清楚程序所需的数据结构,则交易将失败。
在 Javascript 中,交易指令看起来像这样:
new TransactionInstruction({
programId: new PublicKey(PROGRAM_ID),
keys: [\
{ pubkey: signerKeypair.publicKey, isSigner: true, isWritable: true },\
{ pubkey: pda, isSigner: false, isWritable: true },\
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\
],
data: Buffer.from(SOME_ENCODED_DATA),
})
简化调试的日志
你现在可以访问 RPC 端点的日志,帮助你更有效地排查问题。如果你在 RPC 调用中遇到问题,只需查看 QuickNode 仪表板中的日志即可快速确定和解决问题。了解有关日志历史限制的更多信息,请访问 我们的定价页面。
在此值得一提的是,交易指令所需的账户信息。我们必须提供账户的公钥,该账户是否在交易中是签署者,以及该账户是否将作为交易的一部分被写入(这有助于贡献于 Solana 的快速执行能力)。在上面的示例中,用户签署钱包,数据被写入到一个 PDA。通常还必须包括系统程序账户(例如,用于创建新账户)。最后,我们传入 SOME_ENCODED_DATA。所需的数据类型在程序内部定义。程序必须对输入数据进行反序列化以正确处理它。
交易是将指令发送到网络上某个程序的手段。交易可以将多个指令打包在一起,以便同时处理多个操作。例如,想象一下当你有三个不同的指令时:一条指令让钱包 A 向钱包 B 发送 1 个 $SOL,一条指令让钱包 B 向钱包 A 发送 33 个 $USDC,以及一条指令记录交易备注,声明 “钱包 A 用 1 个 $SOL 交换了与钱包 B 交易的 33 个 $USDC,日期为 YYYY-MM-DD。”尽管这些可以单独发送到网络,但如果一条指令失败而其他指令成功会发生什么?你将会遇到一种情况,一个人获得他的代币,而另一个人却没有。通过将指令打包在一起,我们可以确保所有的交易要么一起成功,要么一起失败。
当前交易的大小限制为 1232 字节。每笔交易必须包括以下内容:
一旦网络收到交易,它会返回一个交易 ID(base-58 编码字符串),可用于查找交易详细信息。
让我们讨论一下如何将你的交易发送到网络上!
JSON-RPC 是一种以 JSON 编码的远程过程调用协议,使用户能够向 Solana 集群发送信息并从网络获取响应。Solana 目前维护三个网络集群:
客户端可以通过 Solana 节点对任何三个集群发起读写请求。节点在处理请求到网络方面充当“空中交通管制”。客户端通过 Solana Web3 Connection 类连接到 Solana 节点:
const HTTP_ENDPOINT = 'https://example.solana-devnet.quiknode.pro/000/'
const SOLANA_CONNECTION = new Connection(HTTP_ENDPOINT)
在上述示例中,HTTP_ENDPOINT 是指向 Solana 节点的 HTTP URL,最终将你的请求路由到三个集群之一。
每个请求都需要一个 API 端点,以便连接到网络。这就是 QuickNode 登场的地方!你可以使用公共节点或部署和管理自己的基础设施;然而,如果你希望获得 8 倍的响应速度,你可以把繁重的工作留给我们。
一旦你建立了与 Solana 集群的 Connection,就可以对网络执行许多读写方法。有关 RPC 方法的完整列表和文档可以在 QuickNode 文档 上找到。尽管每个方法都有其目的,但在本指南中讨论的一些相关方法包括:
HTTP 调用允许我们告诉网络执行某个操作(例如,处理交易及其指令,返回有关账户的当前状态信息等),但是如果我们想让网络在账户状态发生变化时提醒我们怎么办?
订阅是一种特殊的 RPC 请求,我们会使用 WebSocket (WSS) 请求,而不是使用 HTTP 端点。Solana Web3 JSON RPC 包含几种订阅方法(例如,accountSubscribe,它将监听账户 lamports 或数据的变化)。然后,我们可以使用回调函数订阅这些事件,以便在网络发生更改时执行某些期望的操作。
Connection 类构造函数允许我们传递一个可选的 commitmentOrConfig。在这个配置中,我们可以传递一个 wsEndpoint。这是一个选项,让你提供指向完整节点 JSON RPC Websocket 端点的 URL。如果你创建了一个 QuickNode 端点,你应该能在你的 端点页面 的右侧看到这个选项。
const HTTP_ENDPOINT = 'https://example.solana-devnet.quiknode.pro/000/'
const WSS_ENDPOINT = 'wss://example.solana-devnet.quiknode.pro/000/'
const solanaConnection = new Connection(HTTP_ENDPOINT, {
wsEndpoint: WSS_ENDPOINT,
})
如果你不传递 wsEndpoint 会发生什么?好吧,Solana 用一个名为 makeWebsocketUrl 的函数来处理这一点,该函数将你端点 URL 中的 https 替换为 wss 或 http 替换为 ws(来源)。由于所有 QuickNode HTTP 端点都有相应的 WSS 端点,且使用相同的身份验证令牌,因此如果你不想为 WebSocket 查询使用单独的端点,则可以省略此参数。
要深入了解如何创建 WebSocket 订阅,请查看我们的 指南:如何使用 TypeScript 创建 Websocket 订阅到 Solana 区块链。
好的!这是一堆信息——你可能开始看到了这些基本元素之间的某些连接,但在将所有部分联系在一起之前,让我们快速回顾一下:
让我们通过一个说明性的示例来说明。想象一下一个名为 “GM” 的程序,它持有一个计数器,用于记录每当用户向程序发送 “GM” 消息时的数量。
在上述示例中,客户端创建一个交易,其中包含多个交易指令。这些指令是特定于程序的,因此需要与 GM 程序的期望结构相匹配。客户端签署并通过 RPC 提供者(如 QuickNode)使用 Connection 类将交易发送到 Solana 集群。RPC 提供者将请求路由到集群。程序账户执行和处理接收到的输入指令。程序账户是无状态的,并不会改变,但授权对 PDA 中数据的更改以递增 GM 计数器的值。客户端创建的订阅侦听对 PDA 的更改;然后,网络会通知客户端账户已被更改。
哇!我们刚刚覆盖了很多信息。不要害怕多读几遍,以确保理解这些概念。
现在你对 Solana 有了更深入的理解,是时候开始构建了!试试我们的一些 Solana 开发指南 来开始吧。以下是几个示例:
对这些概念有疑问,或者只是想聊聊?在 Discord 或 Twitter 联系我们,告诉我们你正在构建什么!
- 原文链接: quicknode.com/guides/sol...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!