Solana中的存储成本、最大存储容量和账户调整

文章详细介绍了Solana区块链中账户存储空间租金的计算方式及其相关概念,包括租金豁免、存储成本比较、账户大小限制和调整、以及部署程序的成本预估。

Solana 账户租赁 在分配存储空间时,付款方必须支付每字节分配一定数量的SOL。

Solana称之为“租赁”。这个名称有点误导,因为它暗示需要每月充值,但情况并非总是如此。一旦租金支付,就不再需要支付,即使两年过去了。当支付了两年的租金后,账户被认为是“免租”的。

这个名称来源于Solana最初按字节每年的形式向账户收费。如果你只支付了半年的租金,那么你的账户将在六个月后被删除。如果你提前支付了两年的租金,账户就会“免租”。该账户将不再需要支付租金。如今,所有账户都必须是免租的;你不能支付少于两年的租金。

虽然租金是按照“每字节”计算的,但零数据的账户不是免费的;Solana仍需要对其进行索引并存储与之相关的元数据。

当账户初始化时,所需租金的数量会在后台计算;你无需明确计算租金

然而,你确实想要能够预测存储的成本,以便能够恰当地设计你的应用程序。

如果你想要一个快速的估算,运行 solana rent <字节数> 在命令行中会给出快速的答案:solana rent 32

如前所述,分配零字节是非免费的:solana rent 0

让我们看看这个费用是如何计算的。

Anchor Rent Module给我们提供了一些与租金相关的常量:

  • ACCOUNT_STORAGE_OVERHEAD:该常量的值为128(字节),顾名思义,一个空账户有128字节的开销。
  • DEFAULT_EXEMPTION_THRESHOLD:该常量的值为2.0(浮点数64),指的是提前支付两年的租金使得账户免于支付进一步的租金。
  • DEFAULT_LAMPORTS_PER_BYTE_YEAR:该常量的值为3,480,意味着每字节每年需要3,480 lamports。由于我们需要支付两年, 每字节将花费6,960 lamports。

以下Rust程序打印出一个空账户将花费的金额。请注意,结果与上面的 solana rent 0 截图相符:

use anchor_lang::prelude::*;
use anchor_lang::solana_program::rent as rent_module;

declare_id!("BfMny1VwizQh89rZtikEVSXbNCVYRmi6ah8kzvze5j1S");

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

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let cost_of_empty_acc = rent_module:: ACCOUNT_STORAGE_OVERHEAD as f64 * 
                                rent_module::DEFAULT_LAMPORTS_PER_BYTE_YEAR as f64 *
                                rent_module::DEFAULT_EXEMPTION_THRESHOLD; 

        msg!("创建空账户的成本: {}", cost_of_empty_acc);
        // 890880

        Ok(())
    }
}

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

如果我们想计算一个非空账户的费用,那么我们只需将字节数加入到空账户的费用中,如下所示:

use anchor_lang::prelude::*;
use anchor_lang::solana_program::rent as rent_module;

declare_id!("BfMny1VwizQh89rZtikEVSXbNCVYRmi6ah8kzvze5j1S");

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

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let cost_of_empty_acc = rent_module:: ACCOUNT_STORAGE_OVERHEAD as f64 * 
                                rent_module::DEFAULT_LAMPORTS_PER_BYTE_YEAR as f64 *
                                rent_module::DEFAULT_EXEMPTION_THRESHOLD;

        msg!("创建空账户的成本: {}", cost_of_empty_acc);
        // 890,880 lamports

        let cost_for_32_bytes = cost_of_empty_acc + 
                                32 as f64 * 
                                rent_module::DEFAULT_LAMPORTS_PER_BYTE_YEAR as f64 *
                                rent_module::DEFAULT_EXEMPTION_THRESHOLD;

        msg!("创建32字节账户的成本: {}", cost_for_32_bytes);
        // 1,113,600 lamports
        Ok(())
    }
}

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

同样,请注意该程序的输出与命令行上的输出相符。

比较存储成本与ETH

截至本文写成时,ETH的价值约为$2,425。初始化一个新账户的费用为22,100 gas,因此我们可以计算32字节的gas成本为$0.80,假设gas费为15 gwei。

目前,Solana的价格为$90 / SOL,因此支付1,113,600 lamports以初始化32字节存储将花费$0.10。

然而,ETH的市场资本是SOL的7.5倍,因此如果SOL的市场资本与ETH相同,SOL的当前价格将为$675,而32字节的存储将花费$0.75。

Solana有一个永久的通胀模型,最终将收敛到每年1.5%,这应有助于反映出存储随着时间的推移变得更便宜,根据摩尔定律,成本相同的晶体管密度每18个月翻倍。

请记住,从字节到加密的转换是协议中设置的常量,可能在任何时候由于硬分叉而改变。

余额低于2年免租阈值的账户会减少直到账户被删除

可以在这里阅读一个用户钱包账户逐渐被“耗尽”的趣味Reddit帖子:<https://www.reddit.com/r/solana/comments/qwin1h/my_sol_balance_in_the_wallet_is_decreasing/>

原因是该钱包的余额低于租赁豁免阈值,Solana运行时正在慢慢减少账户余额以支付租金。

如果由于余额低于免租阈值而导致钱包最终被删除,可以通过向其发送更多SOL进行“复活”,但如果数据存储在账户中,则该数据将会丢失。

大小限制

当我们初始化一个账户时,大小不得超过10,240字节。

练习:创建一个基本的存储初始化程序并设置space=10241。这比限制高出1字节。你应该会看到类似以下的错误:solana 账户无法初始化,因为超过了大小限制

更改账户大小

如果你需要增加账户的大小,可以使用realloc宏。这在账户存储一个向量并需要更多空间时可能会很方便。增加1000字节的代码在increase_account_size函数和IncreaseAccountSize上下文结构中可以找到(请查看以下代码中的大写注释):

use anchor_lang::prelude::*;
use std::mem::size_of;

declare_id!("GLKUcCtHx6nkuDLTz5TNFrR4tt4wDNuk24Aid2GrDLC6");

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

    pub fn initialize(ctx: Context&lt;Initialize>) -> Result&lt;()> {
        Ok(())
    }

    pub fn increase_account_size(ctx: Context&lt;IncreaseAccountSize>) -> Result&lt;()> {
        Ok(())
    }
}

#[derive(Accounts)]
pub struct IncreaseAccountSize&lt;'info> {

    #[account(mut,
              // ***** 增加1,000 BYTE点在这里 *****
              realloc = size_of::&lt;MyStorage>() + 8 + 1000,
              realloc::payer = signer,
              realloc::zero = false,
              seeds = [],
              bump)]
    pub my_storage: Account&lt;'info, MyStorage>,

    #[account(mut)]
    pub signer: Signer&lt;'info>,

    pub system_program: Program&lt;'info, System>,
}

#[derive(Accounts)]
pub struct Initialize&lt;'info> {

    #[account(init,
              payer = signer,
              space=size_of::&lt;MyStorage>() + 8,
              seeds = [],
              bump)]
    pub my_storage: Account&lt;'info, MyStorage>,

    #[account(mut)]
    pub signer: Signer&lt;'info>,

    pub system_program: Program&lt;'info, System>,
}

#[account]
pub struct MyStorage {
    x: u64,
}

在增加账户大小时,如果你不想删除账户数据,请确保设置realloc::zero = false(在上面的代码中)。如果你希望账户数据被设置为全零,请使用realloc::zero = true。你不需要更改测试。该宏会为你在后台处理这些。

练习:在测试中初始化一个账户,然后调用increase_account_size函数。通过在命令行中执行solana account &lt;addr> 查看账户大小。你需要在本地验证器上执行此操作,以使账户持续存在。

最大Solana账户大小

每次重新分配的最大账户增加为10240。Solana中账户的最大大小为10MB。

预测程序部署的成本

部署Solana程序的主要费用来自支付存储字节码的租金。字节码存储在与anchor deploy返回的地址不同的单独账户中。

下面的屏幕截图展示了如何获取此信息:程序部署成本

目前,简单的Hello World程序的部署费用略高于2.47 SOL。通过直接编写原生Rust代码而不是使用Anchor框架,费用可以显著降低,但我们不建议在你完全理解Anchor默认消除的所有安全风险之前这样做。

了解更多

请参阅我们的Solana开发者课程以了解更多。

最初发布于2024年2月28日

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

0 条评论

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