Solana 计算单元与交易费用介绍

  • RareSkills
  • 发布于 2024-02-25 17:25
  • 阅读 276

文章详细介绍了Solana区块链中的计算单元(Compute Units)概念,与以太坊的gas机制进行了对比,并探讨了计算单元的优化策略及其对交易费用的影响。

Solana 计算单元

在以太坊中,交易的价格计算为 $\text{gasUsed} \times \text{gasPrice}$。这告诉我们,将交易包含在区块链中将花费多少 Ether。在发送交易之前,会指定并预付 gasLimit。如果交易用尽了 gas,它将被回滚。

与 EVM 链不同,Solana 的操作码/指令消耗的是“计算单元”(可以说是一个更好的名称),而不是 gas,每笔交易的软上限为 200,000 个计算单元。如果交易消耗的计算单元超过 200,000,它将被回滚。

在以太坊中,计算所需的 gas 成本与存储相关的 gas 成本是相同的。在 Solana 中,存储的处理方式不同,因此 Solana 中持久化数据的定价是一个不同的讨论话题。

然而,从运行操作码的定价角度来看,以太坊和 Solana 的行为是相似的。

两条链都执行编译后的字节码,并对每条执行的指令收取费用。以太坊使用 EVM 字节码,但 Solana 运行的是 Berkeley Packet Filter 的修改版本,称为 Solana Packet Filter。

以太坊根据执行时间的长短对不同操作码收取不同的费用,范围从 1 gas 到数千 gas。在 Solana 中,每个操作码消耗 1 个计算单元。

当计算单元不足时该怎么办

在执行无法在限制内完成的重计算操作时,传统策略是“保存你的工作”并在多个交易中完成。

“保存你的工作”部分需要放入永久存储中,这是我们尚未涉及的内容。这类似于在以太坊中尝试遍历一个巨大的循环;你会有一个存储变量来保存你离开时的索引,以及一个存储变量来保存到该点为止的计算结果。

计算单元优化

正如我们所知,Solana 使用计算单元来防止停机问题,并防止运行永远执行的代码。每笔交易的计算单元限制为 200,000 CU(可以以额外成本增加到 1.4m CU),如果超过(选择的限制),程序将终止,所有更改的状态将回滚,费用不会退还给调用者。这可以防止攻击者意图在节点上运行永不结束或计算密集型的程序以减慢或停止链。

然而,与 EVM 链不同,交易中使用的计算资源不会影响为该交易支付的费用。无论你使用了整个限制还是只使用了很少的一部分,你都将被收取相同的费用。例如,400 计算单元的交易与 200,000 计算单元的交易费用相同。

除了计算单元之外,Solana 交易的签名者数量也会影响计算单元成本。根据 Solana 文档

“目前,交易费用仅由交易中需要验证的签名数量决定。交易中签名数量的唯一限制是交易本身的最大大小。交易中的每个签名(64 字节)(最大 1232 字节)必须引用一个唯一的公钥(32 字节),因此单个交易最多可以包含 12 个签名(不确定为什么要这样做)。”

我们可以通过这个小例子看到这一点。从一个空的 Solana 程序开始:

use anchor_lang::prelude::*;

declare_id!("6CCLqLGeyExCFegJDjRDirWQRRSbM5XNq3yKvmaWS2ZC");

##[program]
pub mod compute_unit {
    use super::*;

    pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
        Ok(())
    }
}

##[derive(Accounts)]
pub struct Initialize {}

更新测试文件:


import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { ComputeUnit } from "../target/types/compute_unit";

describe("compute_unit", () => {
  // 配置客户端以使用本地集群。
  anchor.setProvider(anchor.AnchorProvider.env());
  const program = anchor.workspace.ComputeUnit as Program<ComputeUnit>;
  const defaultKeyPair = new anchor.web3.PublicKey(
    // 将此替换为你的默认提供者密钥对,你可以通过在终端中运行 `solana address` 来获取它
    "EXJupeVMqDbHk7xY4XP4TVXq22L3ZJxJ9Gm68hJccpLp"
  );

  it("Is initialized!", async () => {
    // 记录密钥对的初始余额
    let bal_before = await program.provider.connection.getBalance(
      defaultKeyPair
    );
    console.log("before:", bal_before);

    // 调用我们程序的初始化函数
    const tx = await program.methods.initialize().rpc();

    // 记录密钥对的余额之后
    let bal_after = a...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/