Solana 日志、事件日志与历史交易查询

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

本节将探讨 Solana 中的日志和事件日志,以及如何查询历史交易。

Solana 程序可以发出类似 Ethereum 事件的事件日志,但其设计和用途有所不同。本节将探讨 Solana 中的日志和事件日志,以及如何查询历史交易。


Solana 日志与事件日志

以下程序定义了两个事件日志:MyEvent 和 MySecondEvent,类似于 Ethereum 事件通过参数传递数据,Solana 使用结构体字段:

use anchor_lang::prelude::*;

declare_id!("8kSqq6R5YL4ZudFtnRH4xeRSP8xQNFdS4naWxunR5RKh");

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

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        emit!(MyEvent { value: 42 });
        emit!(MySecondEvent { value: 3, message: "hello world".to_string() });
        Ok(())
    }
}

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

#[event]
pub struct MyEvent {
    pub value: u64,
}

#[event]
pub struct MySecondEvent {
    pub value: u64,
    pub message: String,
}

事件日志会纳入 Solana 程序的 IDL,类似 Solidity 的事件定义在 ABI 中:

  "events": [
    {
      "name": "MyEvent",
      "fields": [
        {
          "name": "value",
          "type": "u64",
          "index": false
        }
      ]
    },
    {
      "name": "MySecondEvent",
      "fields": [
        {
          "name": "value",
          "type": "u64",
          "index": false
        },
        {
          "name": "message",
          "type": "string",
          "index": false
        }
      ]
    }
  ]

与 Ethereum 不同,Solana 没有“索引”或“非索引”字段的概念。

Solana 事件日志无法像 Ethereum 那样查询历史记录,只能实时监听。以下是监听示例:

import * as anchor from "@coral-xyz/anchor";
import { BorshCoder, EventParser, Program } from "@coral-xyz/anchor";
import { Emit } from "../target/types/emit";

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

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

  it("Is initialized!", async () => {
    const listenerMyEvent = program.addEventListener('MyEvent', (event, slot) => {
      console.log(`slot ${slot} event value ${event.value}`);
    });

    const listenerMySecondEvent = program.addEventListener('MySecondEvent', (event, slot) => {
      console.log(`slot ${slot} event value ${event.value} event message ${event.message}`);
    });

    await program.methods.initialize().rpc();

    await new Promise((resolve) => setTimeout(resolve, 5000));

    program.removeEventListener(listenerMyEvent);
    program.removeEventListener(listenerMySecondEvent);
  });
});

输出示例:

slot 4 event value 42
slot 4 event value 3 event message hello world
✔ Is initialized! (5264ms)

Solana 不支持扫描历史日志,必须在交易发生时监听。


日志的底层原理

Ethereum 通过 log0、log1 等操作码发出日志,而 Solana 使用系统调用 sol_log_data,接受字节序列作为参数(详见 Solana 日志文档):

/// 以 base64 格式打印字节切片
pub fn sol_log_data(data: &[&[u8]]) {
    #[cfg(target_os = "solana")]
    unsafe {
        crate::syscalls::sol_log_data(data as *const _ as *const u8, data.len() as u64);
    }
    #[cfg(not(target_os = "solana"))]
    crate::program_stubs::sol_log_data(data);
}

事件日志的结构体是字节序列的抽象,Anchor 在幕后将其序列化为字节传递给 sol_log_data。


Solana 日志不适合历史查询

Ethereum 的日志常用于审计,而 Solana 的日志仅限实时查询,更适合向前端传递信息。Solana 函数无法像 Solidity 的 view 函数那样返回数据,日志因此成为轻量级替代方案。事件日志会在区块浏览器中保留,例如 此交易


Solana 交易的地址查询

Ethereum 无法直接按地址查询交易,需通过 eth_getTransactionCounteth_getTransactionByHasheth_getBlockByNumber 间接获取,审计依赖事件日志(见 Ethereum 事件)。

Solana 则提供 getSignaturesForAddress RPC 方法,可查询地址(程序或钱包)的所有交易。示例脚本:

let web3 = require('@solana/web3.js');

const solanaConnection = new web3.Connection(web3.clusterApiUrl("mainnet-beta"));

const getTransactions = async (address, limit) => {
  const pubKey = new web3.PublicKey(address);
  let transactionList = await solanaConnection.getSignaturesForAddress(pubKey, { limit: limit });
  let signatureList = transactionList.map(transaction => transaction.signature);

  console.log(signatureList);

  for await (const sig of signatureList) {
    console.log(await solanaConnection.getParsedTransaction(sig, { maxSupportedTransactionVersion: 0 }));
  }
};

let myAddress = "enter and address here"; // 替换为实际地址
getTransactions(myAddress, 3);

说明:getParsedTransaction 用于获取交易详情。


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

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

0 条评论

请先 登录 后评论
0xE
0xE
0x59f6...a17e
17年进入币圈,Web3 开发者。刨根问底探链上真相,品味坎坷悟 Web3 人生。