Solana programs भी घटनाओं (events) को एमिट (emit) कर सकते हैं, ठीक उसी तरह जैसे Ethereum events एमिट करता है, हालांकि इनमें कुछ अंतर हैं जिन पर हम चर्चा करेंगे।
विशेष रूप से, Solana में events का उद्देश्य पिछले ट्रांजेक्शन्स (past transactions) को डॉक्यूमेंट करने के बजाय frontend को जानकारी पास करना है। पिछले इतिहास (past history) को प्राप्त करने के लिए, Solana ट्रांजेक्शन्स को address द्वारा query किया जा सकता है।
Solana Logs और Events
नीचे दिए गए program में दो events हैं: MyEvent और MySecondEvent। जैसे Ethereum events में “arguments” होते हैं, उसी तरह Solana events के struct में fields होते हैं:
use anchor_lang::prelude::*;
declare_id!("FmyZrMmPvRzmJCG3p5R1AnbkPqSmzdJrcYzgnQiGKuBq");
#[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,
}
Events Solana program के IDL का हिस्सा बन जाते हैं, ठीक उसी तरह जैसे events एक Solidity smart contract के ABI का हिस्सा होते हैं। नीचे हमने संबंधित हिस्से को हाईलाइट करते हुए ऊपर दिए गए program के IDL का स्क्रीनशॉट दिया है:

Solana में Ethereum की तरह “indexed” या “non-indexed” जानकारी जैसी कोई चीज़ नहीं होती है (भले ही ऊपर दिए गए स्क्रीनशॉट में एक “index” field है, लेकिन इसका कोई उपयोग नहीं है)।
Ethereum के विपरीत, हम सीधे block numbers की एक रेंज में past events के लिए query नहीं कर सकते हैं। हम events को केवल तभी सुन (listen) सकते हैं जब वे घटित हो रहे हों। (हम बाद में past transactions को ऑडिट करने का Solana का तरीका देखेंगे)। नीचे दिया गया कोड दिखाता है कि Solana में events को कैसे listen किया जाए:
import * as anchor from "@coral-xyz/anchor";
import { BorshCoder, EventParser, Program } from "@coral-xyz/anchor";
import { Emit } from "../target/types/emit";
describe("emit", () => {
// Configure the client to use the local cluster.
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();
// This line is only for test purposes to ensure the event
// listener has time to listen to event.
await new Promise((resolve) => setTimeout(resolve, 5000));
program.removeEventListener(listenerMyEvent);
program.removeEventListener(listenerMySecondEvent);
});
});
Ethereum की तरह past logs को स्कैन करना संभव नहीं है, उन्हें ट्रांजेक्शन (transaction) होने के दौरान ही देखा जाना चाहिए।

पर्दे के पीछे (Under the hood) logs कैसे काम करते हैं
EVM में, log0, log1, log2 आदि opcode को रन करके logs को एमिट (emit) किया जाता है। Solana में, system call sol_log_data को कॉल करके logs रन किए जाते हैं। एक argument के रूप में, यह केवल bytes का एक क्रम (sequence) है:
https://docs.rs/solana-program/latest/src/solana_program/log.rs.html#116-124
नीचे Solana client में system call का function दिया गया है:
/// Print some slices as 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);
}
एक event बनाने के लिए हम जिस “struct” स्ट्रक्चर का उपयोग कर रहे हैं, वह byte sequence पर एक एब्स्ट्रैक्शन (abstraction) है। पर्दे के पीछे, Anchor इस function में पास करने के लिए struct को एक byte sequence में बदल देता है। Solana system call केवल एक byte sequence लेता है, struct नहीं।
Solana logs ऐतिहासिक querying (historical querying) के लिए नहीं हैं
Ethereum में, logs का उपयोग ऑडिटिंग (auditing) के उद्देश्यों के लिए किया जाता है, लेकिन Solana में, logs का उपयोग उस तरह से नहीं किया जा सकता क्योंकि उन्हें केवल घटित होने के समय ही query किया जा सकता है। इसलिए, वे frontend एप्लिकेशन को जानकारी पास करने के लिए अधिक उपयुक्त हैं। Solana functions उस तरह से frontend को डेटा वापस (return) नहीं कर सकते जैसे Solidity view functions कर सकते हैं, इसलिए Solana logs इसे पूरा करने का एक हल्का (lightweight) तरीका हैं।
हालाँकि, Events ब्लॉक एक्सप्लोरर (block explorer) में सुरक्षित रहते हैं। उदाहरण के रूप में इस ट्रांजेक्शन के निचले भाग को देखें:
https://explorer.solana.com/tx/JgyHQPxL3cPLFtV4cx5i842ZgBx57R2fkNn2TZn1wsQZqVXKfijd43CEHo88C3ridK27Kw8KkMzfvDdqaS398SX
Ethereum के विपरीत, Solana transactions को address द्वारा query किया जा सकता है
Ethereum में, किसी स्मार्ट कॉन्ट्रैक्ट (smart contract) को भेजे गए या किसी विशेष वॉलेट (wallet) से किए गए ट्रांजेक्शन्स को query करने का कोई सीधा तरीका नहीं है।
हम eth_getTransactionCount का उपयोग करके किसी address से भेजे गए ट्रांजेक्शन्स की संख्या को गिन (count) सकते हैं। हम eth_getTransactionByHash के साथ transaction hash का उपयोग करके एक विशिष्ट ट्रांजेक्शन प्राप्त कर सकते हैं। हम eth_getBlockByNumber या eth_getBlockByHash का उपयोग करके किसी विशिष्ट ब्लॉक में ट्रांजेक्शन्स प्राप्त कर सकते हैं।
हालाँकि, address द्वारा सभी ट्रांजेक्शन्स प्राप्त करना संभव नहीं है। इसे अप्रत्यक्ष रूप से हर उस ब्लॉक को पार्स (parse) करके किया जाना चाहिए जब से वॉलेट सक्रिय (active) हुआ था या स्मार्ट कॉन्ट्रैक्ट डिप्लॉय (deploy) किया गया था।
एक स्मार्ट कॉन्ट्रैक्ट में ट्रांजेक्शन्स का ऑडिट करने के लिए, डेवलपर्स रुचि के ट्रांजेक्शन्स को query करने के लिए smart contract events जोड़ते हैं।
Solana में transaction history प्राप्त करना
दूसरी ओर, Solana में एक RPC function getSignaturesForAddress है जो एक address द्वारा किए गए सभी ट्रांजेक्शन्स को सूचीबद्ध (list) करता है। Address कोई program या वॉलेट हो सकता है।
किसी address से ट्रांजेक्शन्स को सूचीबद्ध करने के लिए नीचे एक स्क्रिप्ट दी गई है:
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);
ध्यान दें कि ट्रांजेक्शन का वास्तविक कंटेंट (content) getParsedTransaction RPC method का उपयोग करके प्राप्त किया जाता है, जो केवल @solana/web3.js SDK में समर्थित है। अन्य लाइब्रेरीज़ (libraries) के लिए, इसके बजाय getTransaction देखें।
मूल रूप से 20 फरवरी, 2024 को प्रकाशित