{"content":{"title":"Solana 开发系列 1 - 理解 Solana","body":"这是一个系列文章介绍 Solana 开发。\r\n\r\nSolana 是一个高性能的区块链平台，通过独特的共识机制和账户模型实现高吞吐量和低延。\r\n\r\n作为系列文章第一篇，这篇文章主要介绍 Solana 开发前需要了解的一些知识：\r\n\r\n1. Solana 诞生背景\r\n\r\n2. Solana 是如何出块（共识运作）\r\n\r\n3. Solana 核心概念： 账户模型、PDA、交易及费用、集群等。\r\n   \r\n\r\n## Solana 诞生背景\r\n\r\nSolana 于 2017 年由 Anatoly Yakovenko 创立。Anatoly 选择名为 Solana 的名字，以致敬他们在工作于高通期间住和冲浪了三年的圣地亚哥北部的一个小海滩城镇Solana Beach。\r\n\r\n在创立 Solana 之前，Anatoly 在高通、Mesosphere 和 Dropbox 工作过多年，在高性能网络和分布式系统领域有着丰富经验。\r\n\r\n他认识到区块链在可扩展性方面的瓶颈限制了其大规模应用的潜力。受到分布式系统中时间同步技术的启发，他提出了 Proof of History (PoH) 的概念。用于在不信任彼此的计算机之间进行时间同步。\r\n\r\n我们开看看 Solana 如何应用 PoH 实现验证者之间的高效同步的。\r\n\r\n## Solana 共识 -  如何出块\r\n\r\n> 注：Solana 共识算法文档有些过时，这部分的内容是参考[深入 Solana 共识](https://learnblockchain.cn/article/10458) 加上我理解。\r\n\r\n\r\n\r\nSolana 是一条权益证明（PoS）区块链，共识算法遵循两阶段：1. **选出验证者**出块 2. 其他验证者对块进行投票，积累了足够多投票之后，区块被最终确认。\r\n\r\n### 选出验证者\r\n\r\n在 Solana 的协议中，有两个重要时间间隔相关的词：**Epoch** 与 **时隙（slot）**：\r\n\r\n- **时隙（slot）：** 验证者生成区块的时间单位。每个时隙可以生成一个区块，每个时隙持续 400 毫秒。\r\n- **Epoch：** 在每个Epoch 开始时，Solana 网络会根据质押权重和之前的区块随机选举出一个验证者（称为领导者Leader）序列 ， 这个领导者序列负责在该Epoch 内出块，领导者序列在此期间保持固定，每个领导者可以连续处理 **4 个 Slot**（即出 4 个块)，每个Epoch大约持续两天（包含 432,000 个 Slot）。直到下一个Epoch 重新产生领导者 Leader。\r\n\r\n\r\n\r\n![Solana 领导者序列](https://img.learnblockchain.cn/pics/20250107214700.png)\r\n\r\n> 上图中，每个有颜色的块表示一个区块，不同的颜色表示不同的验证出的块。\r\n\r\n\r\n\r\n随机选举这里不细说（主要是不懂），在每个 Epoch 开始时，验证者就会知道在哪些 slot 需要他来出块。\r\n\r\n但是这里有**两个问题**需要解决：\r\n\r\n1. 验证者怎么知道该轮到自己出块了？ 如果只依靠网络通信，由上一个验证者告诉下一个验证者，很可能由于网络延迟（或上一个验证者掉线了）错过宝贵的出块时间，毕竟出块时间只有 0.4 秒。\r\n\r\n2. 如何在一个块里面，塞入尽可能多的交易。如果类似以太坊一个交易一个交易接着执行，这么短的时间里，是放不了很多交易的。\r\n\r\n   \r\n\r\nSolana 最重要的创新 - POH ， 主要就是用来解决这两个问题的。\r\n\r\n### 出块\r\n\r\nSolana 为了实现高性能，引入了并行处理交易， 把交易的排序和执行分成了两个阶段，这样执行阶段就可以并行处理了。\r\n\r\n其他验证者在验证交易时，也是按照同样的排序序列来执行验证，为了让交易排序序列可以被验证， Solana 使用  POH 历史证明哈希链的方式来确定交易的顺序。\r\n\r\n![img](https://img.learnblockchain.cn/attachments/migrate/1736299460426)\r\n\r\n\r\n\r\nPoH 通过创建一系列加密哈希（SHA256 算法），每次哈希计算都需要使用前一个哈希值，这样就可以确保下一个哈希总是在上一个哈希之后发生，因此 POH 哈希链结合介意数据就可以确定交易次序。\r\n\r\n![img](https://img.learnblockchain.cn/attachments/migrate/1736299460431)\r\n\r\n\r\n\r\n只需要在计算哈希时，加入交易数据作为输入的一部分，就可以确定交易的序列。而且这个序列是可并行可验证和不可篡改的。\r\n\r\n当前的**领导验证者**会不停从 RPC服务器和其他的验证者那里接收交易，做了初步的验证（如验证交易签名和账户余额）之后，就会加入的 POH 哈希链的计算当中排序，即给每笔交易打上一个全局、可验证的时间顺序标签，然后再对交易进行并行执行。\r\n\r\n\r\n\r\n在 Solana 中，整个**交易处理流程**被拆分成多个相互衔接的阶段（交易验证阶段、POH 排序阶段、执行阶段、广播阶段），形成一个**流水线（pipeline）**。不同阶段之间可以并行、重叠地处理不同批次的交易，就不同 CPU 核或 GPU 在同时处理某一批交易的验证核另一批交易的执行（称为banking）。\r\n\r\n\r\n\r\n交易的执行也是并行的，交易执行基于**账户的读写依赖**来安排并行度，将交易按照依赖分组，并行的放进不同线程/CPU 核心/GPU 任务中执行。\r\n\r\n>  若两笔交易操作的账户完全不同或都是只读，理论上可以同时执行；如果存在写冲突，则必须按顺序执行，避免数据不一致。\r\n\r\n \r\n\r\n现在我们明白了 Solana 出块的过程，这个如上的方式，Solana 在单个 Slot（约 400ms）内能够处理大量交易。\r\n\r\n\r\n\r\n### POH - 同步时钟 \r\n\r\n还有一个问题，验证者怎么知道该轮到自己出块了？\r\n\r\n每次哈希操作都是需要最小时间，且每次哈希计算都需要使用前一个哈希值。这确保了无法进行并行化。因此PoH 哈希链，可以作为时间流逝的证明。\r\n\r\n在 Solana 中，每个区块（的PoH 哈希链）必须包含 12,500 个哈希。当前Slot 的领导者负责生成这些 PoH 链（区块）。\r\n\r\n实际上，没有验证者都在后台自己计算着 PoH 链（没有交易数据的空 Hash 链），如果前一个领导者（或多个前领导者）未发布区块（或者当前领导者未收到），只要经过 Slot 要求的哈希数量，当前领导者就可以按时生成区块。\r\n\r\n\r\n\r\n如下图 Slot3 离线，Slot4 的验证者为 slot3 填充 PoH 序列。\r\n\r\n![image-20250108110531830](https://img.learnblockchain.cn/pics/20250108110533.png)\r\n\r\n### 验证和投票区块\r\n\r\n区块的验证过程包括验证区块元数据和重新计算 PoH 哈希，会验证并重放来自区块的所有交易，并更新账本。\r\n\r\n验证通过后，通过投票表示验证者对一个区块的承诺，验证者持有的委托权益（币）越多，投票的权重就越大。\r\n\r\n通常，验证者会选择**最重**的链出块和投票，如果出现了前一个领导者的区块未能到达当前领导者， 则可能会出现分叉的情况：\r\n\r\n\r\n\r\n![image-20250108120307092](https://img.learnblockchain.cn/pics/20250108120308.png)\r\n\r\n在分叉的情况下，验证者会为每个子树计算总的按股份加权投票，并选择投票最多的那个。如果一个区块获得至少三分之二的持权加权投票，则该区块被确认。\r\n\r\n\r\n\r\n## Solana 核心概念\r\n\r\n### Solana 账户\r\n\r\n在 Solana 上开发时， 与以太坊感受最大不同，是账户模型不一样。\r\n\r\nSolana 的账户和 Linux 的文件很类似，一切皆是账户，它是一个存储单元，它们有多种形式：\r\n\r\n- 用户账户：由一个私钥控制的账户，通常由钱包软件为用户生成。\r\n- 程序账户：用于存储可执行字节码（智能合约代码）的账户。\r\n- 数据账户：存储状态信息的账户，例如用户持有的特定代币数量。\r\n- 原生程序账户：这些是执行网络各种核心功能的特殊预部署程序账户。包括系统程序、投票程序和 BPF 加载器。\r\n\r\n\r\n\r\n```rust\r\npub struct Account {\r\n        pub lamports: u64,  // 表示账号余额 \r\n        #[serde(with = \"serde_bytes\")]\r\n        pub data: Vec<u8>,  // 表示存储的内容, 如可执行字节码\r\n        pub owner: Pubkey, // 所有者, 这个Account可以被谁来操作， 非 owner 没法修改数据\r\n        pub executable: bool,  // 是否可以被执行\r\n        pub rent_epoch: Epoch,  // 用于表示账户下一个纪元所欠租金\r\n    }\r\n```\r\n\r\nSolana 的中程序账户（即智能合约），是无状态的，是只读的，不存储任何数据/状态。数据是存储在独立的数据账户下。\r\n\r\n当你调用 Solana 合约的函数时，需要我们把使用的数据账户传给函数。很容易让没有相互依赖的交易并发执行。\r\n\r\n> 如果你了解 EVM 的话，会知道状态数据也都是保存在合约中，以一个计数器为例，在EVM 合约中，计数器的值保存在合约账户中，在Solana 中，必须创建两个账户：一个是程序账户，用来存储程序的代码，一个账户用来存储计数器的值。\r\n>\r\n> 租金是Solana 减少状态臃肿一种方式，要求账户保持最低余额以保持活跃。租金可确保网络最终收回未使用或资金不足的账户。 如果账户保持相当于两年租金的最低余额，就可以免租。\r\n\r\n\r\n\r\nSolana 的账户的设计，除了并发执行的好处外，还可以带来程序的可重用性， 在以太坊上有大量相同的 ERC20 的代码。\r\n\r\nSolana 则不同，在创建新代币时，无需重新部署智能合约。相反，只需要创建一个新账户，称为铸币账户，该账户定义代币数量、名称、谁可以铸造更多代币等。\r\n\r\n### 程序衍生地址（PDA：Program Derived Addresses）\r\n\r\n用来保存程序数据的账户，就是PDA，\r\n\r\n普通的用户账户，有公钥/地址，他们对应 ed25519 椭圆曲线上的一个点，私钥用于签名以证明修改账户的权限（authority）。\r\n\r\n程序派生地址（PDA）是使用 bump （即使输出偏离曲线的值）在曲线外生成的账户。PDA 需要三个主要部分：父程序 ID、一组种子和跳值。种子是一个字符串数组，通常在程序中最设置一个状态变量相关的特定种子，以创建类似哈希表的数据结构。来生成对应的 PDA 。\r\n\r\n推导出该 PDA 的程序，是其 owner，只有该程序可以修改 PDA 的数据。\r\n\r\n\r\n\r\n![img](https://img.learnblockchain.cn/attachments/migrate/1735874601656)\r\n\r\n### 交易\r\n\r\n我们发送到 Solana 网络中的一笔交易包括四个部分：\r\n\r\n- 一个或多个指令 （`instructions`）\r\n\r\n- 一个要读取或写入的账户数组 （`account_keys`）\r\n\r\n- 一个或多个签名 （`signatures`）\r\n\r\n- 最近的区块哈希 （`recent_blockhash`）\r\n\r\n  \r\n\r\n一个[指令](https://solana.com/docs/terminology#instruction)是 Solana 上最小的执行逻辑。指令指定了执行程序、涉及的所有账户和操作数据。指令调用程序更新状态（例如，调用代币程序将代币从你的帐户转移到另一个帐户），程序解释指令中的数据，并对指定账户进行操作。\r\n\r\n>  指令类似于以太坊智能合约上的函数调用。\r\n\r\n交易中多个指令的执行是原子性的，所有指令要么一起成功，要么一起失败。\r\n\r\n![Solana交易](https://img.learnblockchain.cn/2024/01/03/58272.jpeg)\r\n\r\n\r\n\r\nSolana 使用最近的区块哈希，来指示交易的有效性，但我们想要进行交易时，将从[集群](#Solana集群)中提取最近的 blockhash 来创建有效的交易。交易在最近的 blockhash 后后的 150 个区块内有效。如果超过了改时间，需要重新发起交易。\r\n\r\n> Solana 中没有以太坊中的交易的 Nonce 的概念。\r\n\r\n\r\n\r\n Solana 交易费用与以太坊的Gas 机制有很大的不同，交易费用与交易中包含的签名数量相关（`lamports_per_signature`），**基础手续费**目前设定为每个签名 0.000005 SOL（5k lamports），这是一次性的费用，以便获得使用网络资源的权利，无论实际使用多少资源来执行交易（或者交易是否执行），都需要预先支付给网络。50% 的费用支付给产生区块的验证节点，剩余的 50% 则被销毁。\r\n\r\n\r\n\r\n如果想提高其交易的优先级【可选的费用】，它可以设置一个 \"计算单元价格\"。 这个价格与 [计算单元限制](https://solana.com/zh/docs/core/fees#compute-unit-limit) 结合使用，用来确定交易的优先级费用。\r\n\r\n 默认的计算单元限制为 [每个指令 20 万 CU](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/program-runtime/src/compute_budget_processor.rs#L18)， 如果计算量比较大，可以设置最大为 140 万 Cu。 Solana 交易会预先请求指定数量的计算单元（CUs），如果超出这个数量，交易将失败。 \r\n\r\n\r\n\r\n另外，Solana 交易还会收交易包大小的限制，Solana 网络遵循最大传输单元 (MTU) 大小为 1280 字节，这与 IPv6 MTU 大小约束一致，以确保通过 UDP 传输集群信息的快速和可靠性。在计算必要的标头（IPv6 的 40 字节和 8 字节的片段头）后，1232 字节仍然可用于数据包， 签名和消息的组合不能超过此限制。\r\n\r\n\r\n\r\n### Solana 集群\r\n\r\nSolana 集群  ( cluster ) 是一组验证者共同处理交易并维护自己的[账本数据（ledger）](https://docs.solana.com/terminology#ledger)。Solana有几个不同的集群，每个集群都有特定的用途：\r\n\r\n>  集群对应着以太坊不同的网络。\r\n\r\n\r\n\r\n- [本地主机（localnet）](https://docs.solana.com/getstarted/local)：位于默认端口8899的本地开发集群。[Solana命令行界面（CLI）](https://docs.solana.com/cli)配备了一个内置的[测试验证者 solana-test-validator ](https://docs.solana.com/developing/test-validator)，可以根据个人开发者的需求进行定制，而无需任何空投或也不会遇到速率限制\r\n- [开发网络（Devnet）](https://docs.solana.com/clusters#devnet)：用于在 Solana 上进行测试和实验的无价值沙盒环境\r\n- [测试网络（Testnet）](https://docs.solana.com/clusters#testnet)：Solana核心贡献者试验新更新和功能的测试场所，以便在它们到达主网之前进行测试。它也用作开发人员进行性能测试的测试环境\r\n- [主网测试版（Mainnet Beta）](https://docs.solana.com/clusters#mainnet-beta)：实时、无许可的集群，发生真实世界的交易。这是用户、开发者、代币持有者和验证者每天交互使用的“真实”Solana\r\n\r\n\r\n![img](https://img.learnblockchain.cn/pics/20240210215126.jpg)\r\n\r\n每个集群都独立运行，完全不知道其他集群的存在。发送到错误集群的交易将被拒绝，以确保每个运行环境的完整性。\r\n\r\n\r\n\r\n## 总结\r\n\r\n本文介绍了 Solana 的核心概念，包括其账户模型、出块机制、交易记费用结构。\r\n\r\n理解这些基础知识，接下来我们就要开始上手 Solana 开发应用了。\r\n\r\n\r\n\r\n## 参考文章\r\n\r\n\r\n\r\n* [Solana 是如何工作的- 工作原理 ](https://learnblockchain.cn/article/10486)\r\n\r\n* [深入 Solana 共识 - 从分叉到最终确定性](https://learnblockchain.cn/article/10458)"},"author":{"user":"https://learnblockchain.cn/people/15","address":"0xD6823f807C45eFDC56c9aE8Db0226CA10af6E8AB"},"history":"bafkreiaaxrusph4eza4jwnvgx3a7gfrkwvzkswvdjcnxdz4mzuoict3pbe","timestamp":1736949567,"version":1}