Solana 中的时钟与其他区块变量

  • 0xE
  • 发布于 2天前
  • 阅读 267

本文将介绍 Solana 中与 Solidity 区块变量对应的概念。

本文将介绍 Solana 中与 Solidity 区块变量对应的概念。

Solidity 中常见的区块变量包括:

  • block.timestamp(区块时间戳)
  • block.number(区块号)
  • blockhash()(区块哈希)
  • 较少使用的:block.coinbase(矿工地址)、block.basefee(基础费用)、block.chainid(链 ID)、block.difficulty / block.prevrandao(难度)

我们假设你已了解其作用,如需复习,可参考 Solidity 全局变量文档


Solana 中的区块时间戳

Solana 通过 Clock 系统变量 的 unix_timestamp 字段提供区块时间戳。

初始化 Anchor 项目:

anchor init sysvar

更新 lib.rs 中的 initialize 函数:

pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
    let clock: Clock = Clock::get()?;
    msg!(
        "Block timestamp: {}",
        // Get block.timestamp
        clock.unix_timestamp,
    );
    Ok(())
}

说明

  • Clock 由 anchor_lang::prelude::* 自动导入。
  • unix_timestamp 类型为 i64,支持负值(用于时间差计算),单位为秒。

获取星期几

使用 chrono 库计算星期几。更新 Cargo.toml:

[dependencies]
chrono = "0.4.31"

在 lib.rs 中导入并添加函数:

use anchor_lang::prelude::*;
use chrono::*;

declare_id!("5pgNWTorN1n9YBgGGmt7nWm8aebWWk4oFCJLR1CBe4vz");

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

    pub fn get_day_of_the_week(_ctx: Context<Initialize>) -> Result<()> {
        let clock = Clock::get()?;
        let time_stamp = clock.unix_timestamp;
        let date_time = NaiveDateTime::from_timestamp_opt(time_stamp, 0).unwrap();
        let day_of_the_week = date_time.weekday();
        msg!("Week day is: {}", day_of_the_week);
        Ok(())
    }
}

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

更新测试文件 tests/sysvar.ts:

it("Get day of the week", async () => {
    const tx = await program.methods.getDayOfTheWeek().rpc();
    console.log("Your transaction signature", tx);
});

运行 anchor test,日志示例:

Transaction executed in slot 8:
  Signature: 4sUThuBBDnb5fU4UvwkeBsvXePgHPVDunK9kMmgL8PXmM8RLJUJP5z49PzAngmQWzC7j3FcCTWjkQ5dMdhRjzREq
  Status: Ok
  Log Messages:
    Program 5pgNWTorN1n9YBgGGmt7nWm8aebWWk4oFCJLR1CBe4vz invoke [1]
    Program log: Instruction: GetDayOfTheWeek
    Program log: Week day is: Wed
    Program 5pgNWTorN1n9YBgGGmt7nWm8aebWWk4oFCJLR1CBe4vz consumed 1463 of 200000 compute units
    Program 5pgNWTorN1n9YBgGGmt7nWm8aebWWk4oFCJLR1CBe4vz success

Solana 中的区块号

Solana 使用“槽号(slot number)”而非直接的“区块号”。槽号与区块号相关但不完全相同,具体区别将在后续教程中讨论,暂不深入。


区块矿工地址(block.coinbase)

以太坊的 block.coinbase 表示矿工地址,而 Solana 使用 领导者计划(PoH + PoS 共识),无挖矿概念。目前无法直接获取领导者地址。


区块哈希(blockhash)

Solana 提供 RecentBlockhashes 系统变量,但已被弃用,未来将移除。然而,缺乏此方法的 sysvar 可以使用sysvar_name::from_account_info来访问。

use anchor_lang::{prelude::*, solana_program::sysvar::recent_blockhashes::RecentBlockhashes};

declare_id!("5pgNWTorN1n9YBgGGmt7nWm8aebWWk4oFCJLR1CBe4vz");

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

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        // RECENT BLOCK HASHES
        let arr = [ctx.accounts.recent_blockhashes.clone()];
        let accounts_iter = &mut arr.iter();
        let sh_sysvar_info = next_account_info(accounts_iter)?;
        let recent_blockhashes = RecentBlockhashes::from_account_info(sh_sysvar_info)?;
        let data = recent_blockhashes.last().unwrap();

        msg!("The recent block hash is: {:?}", data.blockhash);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    /// CHECK: readonly
    pub recent_blockhashes: AccountInfo<'info>,
}

测试文件 tests/sysvar.ts:

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

describe("sysvar", () => {
  anchor.setProvider(anchor.AnchorProvider.env());

  const program = anchor.workspace.Sysvar as Program<Sysvar>;

  it("Is initialized!", async () => {
    const tx = await program.methods
      .initialize()
      .accounts({
        recentBlockhashes: anchor.web3.SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
      })
      .rpc();

    console.log("Transaction hash:", tx);
  });
});

日志示例:

Transaction executed in slot 5:
  Signature: 5CU76Tj9zv84CDnLT1XDzDGTyCdE9DKdD8a8vaKxBuso8QJmU4RAWY5dL5Jz6yHV2sUBJJoMDtDkZn6jEgrH2NA5
  Status: Ok
  Log Messages:
    Program 5pgNWTorN1n9YBgGGmt7nWm8aebWWk4oFCJLR1CBe4vz invoke [1]
    Program log: Instruction: Initialize
    Program log: The recent block hash is: JAy9nAV7nEMDoc4iDSxxRRJNxNx76WsjaZsAUAiELgsF
    Program 5pgNWTorN1n9YBgGGmt7nWm8aebWWk4oFCJLR1CBe4vz consumed 13763 of 200000 compute units
    Program 5pgNWTorN1n9YBgGGmt7nWm8aebWWk4oFCJLR1CBe4vz success

注意:本地测试网的哈希与主网不同。


计算单位限制(block.gaslimit)

Solana 每个区块的计算单位上限为 4800 万,单笔交易默认限制为 20 万单位(可调整至 140 万,见 示例)。程序内无法直接访问此限制。


基础费用(block.basefee)

以太坊的 block.basefee 基于 EIP-1559 动态调整,而 Solana 的交易费用静态,无此变量。


区块难度(block.difficulty)

block.difficulty 是 PoW 区块链的概念,Solana 使用 PoH + PoS,无难度参数。


链 ID(block.chainid)

Solana 不兼容 EVM,无 block.chainid。程序无法直接感知运行于 Devnet、Testnet 或 Mainnet,但可通过 cfg 根据集群调整逻辑,见 示例


【笔记配套代码】
https://github.com/0xE1337/rareskills_evm_to_solana
【参考资料】
https://learnblockchain.cn/column/119
https://www.rareskills.io/solana-tutorial

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

0 条评论

请先 登录 后评论