Solana

2025年07月21日更新 10 人订阅
原价: ¥ 8.6 限时优惠
专栏简介 Solana 开发学习之Solana 基础知识 Solana 开发学习之通过RPC与Solana交互 Web3与Solana实操指南:如何签名与发送交易 Web3 新玩法:Solana Nonce Account 让你交易无忧 Web3 快上手:Solana 造你的链上名片 Web3 开发实战:用 Anchor 打造 Solana 猜数游戏 @solana/web3.js 2.0:Solana 转账全流程解析 玩转 Web3 Solana:从零到代币开发 Web3 开发入门:Solana CLI 配置与本地验证器实战 Web3 Eclipse 开发环境搭建与资产跨链桥接实战指南 用 Gill 库解锁 Web3:Solana 代币转账实战 Web3开发:用Rust实现Solana SOL转账教程 用 Rust 开发 Solana:解锁 Web3 交易费用计算 Web3开发入门:Solana账户创建与Rust实践全攻略 Web3 实战:用 Anchor 打造 Solana 智能合约全流程 Solana Web3 快速入门:创建并获取钱包账户的完整指南 Web3 开发实操:用 Anchor 在 Solana 创建代币 Mint Account 从零到 Web3:使用 @solana/kit 快速查询 Solana 账户余额 快速上手 Web3:用 @solana/kit 在 Solana 上创建钱包并查询余额 Web3实战:使用Anchor与Rust开发和调用Solana智能合约 Web3实战:Solana CPI全解析,从Anchor封装到PDA转账 用 Rust 在 Solana 上打造你的专属代币:从零到一的 Web3 实践 探索Solana SDK实战:Web3开发的双路径与轻量模块化 手把手教你用 Solana Token-2022 创建支持元数据的区块链代币 Solana 开发实战:Rust 客户端调用链上程序全流程 Solana 开发进阶:在 Devnet 上实现链上程序部署、调用与更新 Solana 开发进阶:链上事件到链下解析全攻略 从零打造Solana空投工具库:Rust开发实战指南 从零开始:用 Rust 开发 Solana 链上 Token 元数据查询工具 Solana 智能合约终极部署指南:从入门到主网,定制你的专属靓号 Program ID 【Solana 开发实战】轻松搞定链上 IDL:从上传到获取全解析 Solana 投票 DApp 开发实战:从合约到部署的完整指南

Solana 开发进阶:链上事件到链下解析全攻略

Solana开发进阶:链上事件到链下解析全攻略在之前我们已经写了三篇文章《探索SolanaSDK实战:Web3开发的双路径与轻量模块化》、《Solana开发实战:Rust客户端调用链上程序全流程》和《Solana开发进阶:在Devnet上实现链上程序部署、调用与更新》完美实现开

Solana 开发进阶:链上事件到链下解析全攻略

在之前我们已经写了三篇文章《探索 Solana SDK 实战:Web3 开发的双路径与轻量模块化》、《Solana 开发实战:Rust 客户端调用链上程序全流程》和《Solana 开发进阶:在 Devnet 上实现链上程序部署、调用与更新》完美实现开发、测试、部署、客户端调用、更新全流程。Solana 的高性能区块链为 Web3 开发打开了新视野,而链上事件是实现智能合约与链下交互的关键枢纽。本文将通过 Rust 实战案例,带你深入掌握链上事件定义、触发到链下解析的全流程,解锁 Solana 开发进阶技能,助你构建更高效的 Web3 应用!

本文延续 Solana 开发系列的实战风格,聚焦智能合约事件的开发与解析全流程。我们通过 Rust 实现一个 Solana 程序,定义并触发 GreetingEvent 事件,利用 JSON-RPC 接口从区块数据中提取日志并反序列化事件内容,完成链上到链下的无缝衔接。文章涵盖 Borsh 序列化、日志提取、RPC 配置等核心技术,配以详细代码解析和运行示例,为希望掌握 Solana 事件机制的开发者提供进阶指南。

实战

查看项目目录

solana-sandbox/sol-program on  main [!?] is 📦 0.1.0 via 🦀 1.87.0 on 🐳 v28.2.2 (orbstack) took 4.0s 
➜ tree . -L 6 -I "coverage_report|lib|.vscode|out|test-ledger|target|node_modules"
.
├── Cargo.lock
├── Cargo.toml
├── examples
│   ├── client.rs
│   └── event.rs
├── keys
│   └── SSoyAkBN9E3CjbWpr2SdgLa6Ejbqqdvasuxd8j1YsmN.json
└── src
    ├── lib.rs
    └── lib2.rs

4 directories, 7 files

合约程序 src/lib.rs 文件

#![allow(unexpected_cfgs)]

use borsh_derive::{BorshDeserialize, BorshSerialize};
use solana_account_info::AccountInfo;
use solana_msg::msg;
use solana_program_entrypoint::entrypoint;
use solana_program_error::{ProgramError, ProgramResult};
use solana_pubkey::Pubkey;

// 定义事件结构体
#[derive(BorshDeserialize, BorshSerialize, Debug)]
pub struct GreetingEvent {
    pub message: String, // Greeting message contained in the event
}

// 自定义事件触发函数
fn emit_event(event: &GreetingEvent) -> ProgramResult {
    let event_data = borsh::to_vec(event).map_err(|_| ProgramError::Custom(1))?; // Serialize to byte array
    msg!("EVENT:GREETING:{:?}", event_data); // Output event log
    Ok(())
}

entrypoint!(process_instruction);

pub fn process_instruction(
    _program_id: &Pubkey,
    _accounts: &[AccountInfo],
    _instruction_data: &[u8],
) -> ProgramResult {
    msg!("Hello, Solana!");

    let event = GreetingEvent {
        message: "Hello from Solana program!".to_string(),
    };
    emit_event(&event)?;

    msg!("Program executed successfully with greeting event!");

    Ok(())
}

#[cfg(test)]
mod test {
    use solana_program_test::*;
    use solana_sdk::{
        instruction::Instruction, pubkey::Pubkey, signature::Signer, transaction::Transaction,
    };

    #[tokio::test]
    async fn test_sol_program() {
        // let program_id = Pubkey::from_str("GGBjDqYdicSE6Qmtu6SAsueX1biM5LjbJ8R8vZvFfofA").unwrap();
        let program_id = Pubkey::new_unique();
        let mut program_test = ProgramTest::default();
        program_test.add_program("sol_program", program_id, None);
        let mut context = program_test.start_with_context().await;
        let (banks_client, payer, recent_blockhash) = (
            &mut context.banks_client,
            &context.payer,
            context.last_blockhash,
        );
        // Create instruction
        let instruction = Instruction {
            program_id,
            accounts: vec![],
            data: vec![],
        };
        // Create transaction with instruction
        let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));

        // Sign transaction
        transaction.sign(&[&payer], recent_blockhash);

        let transaction_result = banks_client
            .process_transaction_with_metadata(transaction)
            .await
            .expect("Failed to process transaction");

        assert!(transaction_result.result.is_ok());

        let logs = transaction_result.metadata.unwrap().log_messages;
        assert!(logs.iter().any(|log| log.contains("Hello, Solana!")));
        assert!(logs.iter().any(|log| log.contains("EVENT:GREETING:")));
    }
}

解析合约程序事件 examples/event.rs 文件


use anyhow::Result;
use anyhow::anyhow;
use borsh::{BorshDeserialize, BorshSerialize};
use serde_json::Value;
use std::error::Error;

// 定义与程序相同的 GreetingEvent 结构体
#[derive(BorshDeserialize, BorshSerialize, Debug)]
pub struct GreetingEvent {
    pub message: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let client = reqwest::Client::builder().build()?;

    let mut headers = reqwest::header::HeaderMap::new();
    headers.insert("Content-Type", "application/json".parse()?);

    let data = r#"
    {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "getBlock",...

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

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

0 条评论

请先 登录 后评论