Solidity events, Ethereum में print या console.log स्टेटमेंट के सबसे करीब की चीज़ हैं। हम समझाएंगे कि वे कैसे काम करते हैं, events के लिए सर्वोत्तम प्रथाएं (best practices) क्या हैं, और कई ऐसे तकनीकी विवरणों में गहराई से जाएंगे जिन्हें अक्सर अन्य संसाधनों में छोड़ दिया जाता है।
यहाँ एक solidity event को emit करने का एक न्यूनतम उदाहरण (minimal example) दिया गया है।
contract ExampleContract {
// We will explain the significance of the indexed parameter later.
event ExampleEvent(address indexed sender, uint256 someValue);
function exampleFunction(uint256 someValue) public {
emit ExampleEvent(sender, someValue);
}
}
शायद सबसे प्रसिद्ध events वे हैं जिन्हें ERC20 टोकन द्वारा ट्रांसफर किए जाने पर emit किया जाता है। सेंडर, रिसीवर और राशि (amount) को एक event में रिकॉर्ड किया जाता है।
क्या यह अनावश्यक (redundant) नहीं है? हम पहले से ही ट्रांसफर्स देखने के लिए पिछले transactions को देख सकते हैं, और फिर वही जानकारी देखने के लिए calldata को देख सकते हैं।
यह सही है; कोई events को हटा सकता है और इससे smart contract के बिज़नेस लॉजिक पर कोई प्रभाव नहीं पड़ेगा। हालाँकि, यह इतिहास (history) को देखने का एक कुशल (efficient) तरीका नहीं होगा।
Transactions को तेज़ी से प्राप्त करना
Ethereum क्लाइंट के पास “प्रकार (type)” के आधार पर transactions को सूचीबद्ध (list) करने के लिए कोई API नहीं है। यदि आप ऐतिहासिक transactions को query करना चाहते हैं, तो आपके पास ये विकल्प हैं:
- getTransaction
- getTransactionFromBlock
getTransactionFromBlock केवल आपको यह बता सकता है कि किसी विशेष ब्लॉक पर कौन से transactions हुए हैं, यह कई ब्लॉक्स में smart contracts को टारगेट नहीं कर सकता है।
getTransaction केवल उन्हीं transactions का निरीक्षण कर सकता है जिनका transaction hash आपको पता हो।
दूसरी ओर, Events को बहुत अधिक आसानी से प्राप्त (retrieve) किया जा सकता है। यहाँ Ethereum क्लाइंट के विकल्प दिए गए हैं:
eventsevents.allEventsgetPastEvents
इनमें से प्रत्येक के लिए उस smart contract address को निर्दिष्ट (specify) करने की आवश्यकता होती है जिसकी querier जांच करना चाहता है, और यह निर्दिष्ट query मापदंडों (parameters) के अनुसार smart contract द्वारा emit किए गए events का एक उपसमुच्चय (subset) या सभी events लौटाता है।
संक्षेप में कहें तो: Ethereum किसी smart contract के सभी transactions प्राप्त करने के लिए कोई तंत्र (mechanism) प्रदान नहीं करता है, लेकिन यह smart contract से सभी events प्राप्त करने के लिए एक तंत्र प्रदान करता है।
ऐसा क्यों है? Events को तेज़ी से प्राप्त करने योग्य बनाने के लिए अतिरिक्त स्टोरेज ओवरहेड (storage overhead) की आवश्यकता होती है। यदि Ethereum प्रत्येक transaction के लिए ऐसा करता है, तो यह चेन को काफी बड़ा बना देगा। Events के साथ, solidity प्रोग्रामर्स इस बारे में चयनात्मक (selective) हो सकते हैं कि किस प्रकार की जानकारी के लिए अतिरिक्त स्टोरेज ओवरहेड का भुगतान करना उचित है, ताकि त्वरित ऑफ-चेन (off-chain) रिट्रीवल को सक्षम किया जा सके।
Events को सुनना
Events का उद्देश्य ऑफ-चेन (off-chain) उपयोग किया जाना है।
यहाँ ऊपर वर्णित API का उपयोग करने का एक उदाहरण दिया गया है। इस कोड में, क्लाइंट एक smart contract से events को सब्सक्राइब करता है।
उदाहरण 1: ERC20 Transfer events को सुनना।
यह कोड हर बार तब एक कॉलबैक ट्रिगर करता है जब कोई ERC20 टोकन एक transfer Event को emit करता है।
const { ethers } = require("ethers");
// const provider = your provider
const abi = [
"event Transfer(address indexed from, address indexed to, uint256 value)"
];
const tokenAddress = "0x...";
const contract = new ethers.Contract(tokenAddress, abi, provider);
contract.on("Transfer", (from, to, value, event) => {
console.log(`Transfer event detected: from=${from}, to=${to}, value=${value}`);
});
उदाहरण 2: किसी विशिष्ट address के लिए ERC20 approval को फ़िल्टर करना
यदि हम events को पूर्वव्यापी (retroactively) रूप से देखना चाहते हैं, तो हम निम्नलिखित कोड का उपयोग कर सकते हैं। इस उदाहरण में, हम एक ERC20 टोकन में Approval transactions के लिए अतीत में देखते हैं।
const ethers = require('ethers');
const tokenAddress = '0x...';
const filterAddress = '0x...';
const tokenAbi = [
// ...
];
const tokenContract = new ethers.Contract(tokenAddress, tokenAbi, provider);
// this line filters for Approvals for a particular address.
const filter = tokenContract.filters.Approval(filterAddress, null, null);
tokenContract.queryFilter(filter).then((events) => {
console.log(events);
});
यदि आप दो विशेष addresses के बीच किसी ट्रेड की तलाश करना चाहते हैं (यदि ऐसा कोई transaction मौजूद है), तो ethers.js JavaScript कोड इस प्रकार होगा:
tokenContract.filters.Transfer(address1, address2, null);
ऊपर दिए गए कोड में null का अर्थ है “इस फ़ील्ड के लिए किसी भी मान (value) से मिलान करें।” transfer event के लिए, हम किसी भी राशि (amount) का मिलान कर रहे हैं।
यहाँ web3.js में एक समान उदाहरण दिया गया है। ध्यान दें कि fromBlock और toBlock query पैरामीटर्स जोड़े गए हैं, और हम सेंडर होने वाले कई addresses को सुनने की क्षमता प्रदर्शित करेंगे। इन addresses को “OR” शर्त (condition) के साथ जोड़ा गया है।
const Web3 = require('web3');
const web3 = new Web3('https://rpc-endpoint');
const contractAddress = '0x...'; // The address of the ERC20 contract
const contractAbi = [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "from",
"type": "address"
},
{
"indexed": true,
"name": "to",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
}
];
const contract = new web3.eth.Contract(contractAbi, contractAddress);
const senderAddressesToWatch = ['0x...', '0x...', '0x...']; // The addresses to watch for transfers from
const filter = {
fromBlock: 0,
toBlock: 'latest',
topics: [
web3.utils.sha3('Transfer(address,address,uint256)'),
null,
senderAddressesToWatch,
]
};
contract.getPastEvents('Transfer', {
filter: filter,
fromBlock: 0,
toBlock: 'latest',
}, (error, events) => {
if (!error) {
console.log(events);
}
});
रेंज़्ड क्वेरीज़ (Ranged queries) संभव नहीं हैं। आप ऐसा फ़िल्टर निर्दिष्ट नहीं कर सकते जो कहता हो कि “मुझे वे सभी transactions दें जहाँ राशि (amount) इस निचली सीमा (lower bound) और उस ऊपरी सीमा (upper bound) के बीच आती है।” आपको सभी events प्राप्त करने होंगे और फिर उन्हें क्लाइंट कोड में फ़िल्टर करना होगा।
उदाहरण 3: एंट्रीज़ को स्टोर किए बिना लीडरबोर्ड बनाना
एक donation फ़ंक्शन वाले smart contract पर विचार करें, और आप चाहते हैं कि फ्रंटएंड (frontend) दी गई राशि के आधार पर डोनेशन्स को रैंक करे। यहाँ एक अकुशल (inefficient) समाधान दिया गया है:
contract Donations {
struct Donation {
address donator;
uint256 amount;
}
Donation[] public donations; // frontend queries this
fallback() external payable {
donations.push(Donation({
donator: msg.sender,
amount: msg.value
}));
}
// more functions for the owner to withdraw
}
यदि डोनेशन्स को ऑन-चेन (on-chain) पढ़ने की आवश्यकता नहीं है, तो यह एक अनुभवहीन (naïve) समाधान है, क्योंकि यह contract में Ethereum भेजने वाले व्यक्ति के लिए गैस की लागत (gas cost) को काफी बढ़ा देगा।
Events का उपयोग करने वाला एक बेहतर समाधान यहाँ दिया गया है:
contract Donations {
event Donation(address indexed donator; uint256 amount);
fallback() external payable {
emit Donation(msg.sender, msg.value);
}
// more functions for the owner to withdraw
}
फ्रंटएंड आसानी से सभी Donation events के लिए smart contract को query कर सकता है और फिर उन्हें amount फ़ील्ड के आधार पर सॉर्ट कर सकता है।
Events ब्लॉकचेन की स्टेट (state) में स्टोर होते हैं, वे अल्पकालिक (ephemeral) नहीं होते हैं। इसलिए, क्लाइंट द्वारा किसी event के छूट जाने (missing) के बारे में चिंता करने की कोई आवश्यकता नहीं है। वे केवल contract के लिए events को फिर से query कर सकते हैं।
Solidity indexed events बनाम non-indexed events
ऊपर दिया गया उदाहरण काम करता है क्योंकि ERC20 में Approve (और Transfer) event सेंडर को indexed के रूप में सेट करता है। यहाँ Solidity में डिक्लेरेशन दिया गया है।
event Approval(address indexed owner, address indexed spender, uint256 value);
यदि owner आर्गुमेंट indexed नहीं होता, तो पहले वाला javascript कोड चुपचाप विफल (silently fail) हो जाता। इसका तात्पर्य यह है कि आप उन ERC20 events के लिए फ़िल्टर नहीं कर सकते जिनमें transfer के लिए एक विशिष्ट मान (value) है, क्योंकि वह indexed नहीं है। आपको सभी events को खींचना (pull) होगा और उन्हें javascript-साइड पर फ़िल्टर करना होगा; यह Ethereum क्लाइंट में नहीं किया जा सकता है।
Event डिक्लेरेशन के लिए एक indexed आर्गुमेंट को topic कहा जाता है।
Solidity events की सर्वोत्तम प्रथाएं (best practices)
Events के लिए आम तौर पर स्वीकृत सर्वोत्तम प्रथा यह है कि जब भी कोई परिणामी स्टेट परिवर्तन (consequential state change) हो, तो उन्हें लॉग किया जाए। कुछ उदाहरणों में शामिल हैं:
- contract के owner को बदलना
- ईथर (ether) को ट्रांसफर करना
- कोई ट्रेड करना
हर स्टेट परिवर्तन के लिए event की आवश्यकता नहीं होती है। Solidity डेवलपर्स को खुद से यह सवाल पूछना चाहिए कि “क्या किसी को इस transaction को तेज़ी से प्राप्त करने या खोजने में कोई दिलचस्पी होगी?”
सही event पैरामीटर्स को Index करें
इसके लिए कुछ व्यक्तिपरक निर्णय (subjective judgment) की आवश्यकता होगी। याद रखें, एक unindexed पैरामीटर को सीधे नहीं खोजा जा सकता है। इसके लिए एक समझ विकसित करने का एक अच्छा तरीका यह देखना है कि स्थापित (established) कोडबेस अपने events को कैसे डिज़ाइन करते हैं
एक सामान्य नियम (rule of thumb) के रूप में, क्रिप्टोकरेंसी की मात्रा (amounts) को indexed नहीं किया जाना चाहिए, और एक address को indexed किया जाना चाहिए, लेकिन इस नियम को आँख बंद करके लागू नहीं किया जाना चाहिए।
अनावश्यक (Redundant) events से बचें
इसका एक उदाहरण टोकन मिंट (mint) होने पर एक event जोड़ना होगा, क्योंकि अंतर्निहित लाइब्रेरीज़ (underlying libraries) पहले से ही इस event को emit करती हैं।
Events का उपयोग view functions में नहीं किया जा सकता है
Events स्टेट बदलने (state changing) वाले होते हैं; वे लॉग को स्टोर करके ब्लॉकचेन की स्टेट को बदल देते हैं। इसलिए, उनका उपयोग view (या pure) functions में नहीं किया जा सकता है।
Events डीबगिंग के लिए उतने उपयोगी नहीं हैं जितने अन्य प्रोग्रामिंग भाषाओं में console.log और print होते हैं; क्योंकि events स्वयं स्टेट-बदलने वाले होते हैं, यदि कोई transaction रिवर्ट (revert) हो जाता है तो वे emit नहीं होते हैं।
एक event कितने arguments ले सकता है?
Unindexed आर्गुमेंट्स के लिए, यदि आप बहुत अधिक आर्गुमेंट्स का उपयोग करते हैं तो आप काफी तेज़ी से स्टैक लिमिट (stack limit) तक पहुंच जाएंगे। निम्नलिखित निरर्थक (nonsensical) उदाहरण एक मान्य (valid) solidity कोड है:
contract ExampleContract {
event Numbers(uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256);
}
इसी तरह, लॉग में स्टोर किए गए स्ट्रिंग्स या एरेज़ (arrays) की लंबाई की कोई आंतरिक सीमा (intrinsic limit) नहीं है।
हालाँकि, किसी event में तीन से अधिक indexed आर्गुमेंट्स (topics) नहीं हो सकते हैं। एक anonymous event में 4 indexed आर्गुमेंट्स हो सकते हैं (हम इस अंतर को बाद में कवर करेंगे)।
शून्य (zero) आर्गुमेंट्स वाला event भी मान्य है।
Events में वेरिएबल नाम वैकल्पिक (optional) हैं लेकिन अनुशंसित (recommended) हैं
निम्नलिखित events समान रूप से व्यवहार करते हैं
event NewOwner(address newOwner);
event NewOwner(address);
सामान्य तौर पर, वेरिएबल का नाम शामिल करना आदर्श होगा क्योंकि निम्नलिखित उदाहरण के पीछे के अर्थ (semantics) बहुत अस्पष्ट (ambiguous) हैं
event Trade(address,address,address,uint256,uint256);
हम अनुमान लगा सकते हैं कि addresses सेंडर और टोकन addresses से मेल खाते हैं, जबकि uint256 प्रकार amounts से मेल खाते हैं, लेकिन इसे समझना मुश्किल है।
Event के नाम का पहला अक्षर बड़ा (capitalize) रखना पारंपरिक है, लेकिन कंपाइलर के लिए यह आवश्यक नहीं है।
Events को parent contracts और interfaces के माध्यम से इनहेरिट (inherit) किया जा सकता है
जब किसी event को parent contract में घोषित (declare) किया जाता है, तो उसे child contract द्वारा emit किया जा सकता है। Events इंटरनल (internal) होते हैं और उन्हें private या public होने के लिए संशोधित नहीं किया जा सकता है। यहाँ एक उदाहरण दिया गया है
contract ParentContract {
event NewNumber(uint256 number);
function doSomething(uint256 number) public {
emit NewNumber(number);
}
}
contract ChildContract is ParentContract {
function doSomethingElse(uint256 number) public {
emit NewNumber(number);
}
}
इसी तरह, events को एक इंटरफ़ेस में घोषित किया जा सकता है और child में उपयोग किया जा सकता है, जैसा कि निम्नलिखित उदाहरण में दिखाया गया है।
interface IExampleInterface {
event Deposit(address indexed sender, uint256 amount);
}
contract ExampleContract is IExampleInterface {
function deposit() external payable {
emit Deposit(msg.sender, msg.value);
}
}
Event selector
EVM (Ethereum Virtual Machine) events को उनके हस्ताक्षर (signature) के keccak256 से पहचानती है।
solidity संस्करण 0.8.15 या उससे उच्च (higher) के लिए, आप .selector मेंबर का उपयोग करके भी सेलेक्टर प्राप्त कर सकते हैं।
pragma solidity ^0.8.15;
contract ExampleContract {
event SomeEvent(uint256 blocknum, uint256 indexed timestamp);
function selector() external pure returns (bool) {
// true
return SomeEvent.selector == keccak256("SomeEvent(uint256,uint256)");
}
}
Event selector वास्तव में स्वयं एक topic है (हम बाद के अनुभाग में इस पर अधिक चर्चा करेंगे)।
वेरिएबल्स को indexed के रूप में चिह्नित करने या न करने से selector नहीं बदलता है।
Anonymous Events
Events को anonymous (अनाम) के रूप में चिह्नित किया जा सकता है, इस स्थिति में उनके पास कोई selector नहीं होगा। इसका मतलब यह है कि क्लाइंट-साइड कोड हमारे पिछले उदाहरणों की तरह उन्हें एक उपसमुच्चय (subset) के रूप में विशेष रूप से अलग नहीं कर सकता है।
pragma solidity ^0.8.15;
contract ExampleContract {
event SomeEvent(uint256 blocknum, uint256 timestamp) anonymous;
function selector() public pure returns (bool) {
// ERROR: does not compile, anonymous events don't have selectors
return SomeEvent.selector == keccak256("SomeEvent(uint256,uint256)");
}
}
चूँकि event signature का उपयोग इंडेक्स में से एक के रूप में किया जाता है, एक anonymous फ़ंक्शन में चार indexed topics हो सकते हैं, क्योंकि फ़ंक्शन signature एक topic के रूप में “मुक्त (freed up)” हो जाता है।
contract ExampleContract {
// valid
event SomeEvent(uint256 indexed, uint256 indexed, address indexed, address indexed) anonymous;
}
व्यवहार में Anonymous events का उपयोग शायद ही कभी किया जाता है।
Events के बारे में उन्नत (Advanced) विषय
यह अनुभाग EVM के असेंबली स्तर पर events का वर्णन करता है। blockchain development में नए प्रोग्रामर्स इस अनुभाग को छोड़ सकते हैं।
कार्यान्वयन विवरण (Implementation detail): Bloom filters
किसी smart contract के साथ हुए प्रत्येक transaction को प्राप्त करने के लिए, Ethereum क्लाइंट को हर एक ब्लॉक को स्कैन करना होगा, जो एक बेहद भारी I/O ऑपरेशन होगा; लेकिन Ethereum एक महत्वपूर्ण अनुकूलन (optimization) का उपयोग करता है।
प्रत्येक ब्लॉक के लिए Events को एक Bloom Filter डेटा संरचना (data structure) में स्टोर किया जाता है। Bloom Filter एक संभाव्य सेट (probabilistic set) है जो कुशलतापूर्वक उत्तर देता है कि कोई सदस्य सेट में है या नहीं। पूरे ब्लॉक को स्कैन करने के बजाय, क्लाइंट Bloom filter से पूछ सकता है कि क्या ब्लॉक में कोई event emit किया गया था; पूरे ब्लॉक को स्कैन करने की तुलना में Bloom filter को query करना कहीं अधिक तेज़ है।
यह क्लाइंट को events को खोजने के लिए ब्लॉकचेन पर बहुत तेज़ी से खोज करने की अनुमति देता है।
Bloom Filters संभाव्य (probabilistic) होते हैं: वे कभी-कभी गलत तरीके से यह परिणाम देते हैं कि कोई आइटम सेट का सदस्य है, भले ही वह न हो। Bloom Filter में जितने अधिक सदस्य स्टोर होंगे, त्रुटि की संभावना उतनी ही अधिक होगी, और इसकी भरपाई के लिए Bloom filter (स्टोरेज के लिहाज से) उतना ही बड़ा होना चाहिए। इस कारण से, Ethereum transactions को Bloom Filter में स्टोर नहीं करता है, केवल events को करता है। Transactions की तुलना में events बहुत कम होते हैं। यह ब्लॉकचेन पर स्टोरेज के आकार को प्रबंधनीय (manageable) रखता है।
जब क्लाइंट को Bloom filter से सकारात्मक सदस्यता (positive membership) प्रतिक्रिया मिलती है, तो उसे यह सत्यापित करने के लिए ब्लॉक को स्कैन करना होगा कि event वास्तव में हुआ था या नहीं। हालाँकि, ऐसा केवल ब्लॉक्स के एक छोटे से उपसमुच्चय (subset) के लिए होगा, इसलिए औसतन Ethereum क्लाइंट पहले event की उपस्थिति के लिए Bloom filter की जाँच करके बहुत सारी गणना (computation) बचाता है।
Yul Events (Solidity assembly)
Yul मध्यवर्ती प्रतिनिधित्व (intermediate representation) में indexed आर्गुमेंट्स (topics) और unindexed आर्गुमेंट्स के बीच का अंतर स्पष्ट हो जाता है।
Events को emit करने के लिए निम्नलिखित yul फ़ंक्शंस उपलब्ध हैं (और उनके EVM ऑपकोड (opcode) का भी वही नाम है)। तालिका (table) को कुछ सरलीकरण के साथ yul documentation से कॉपी किया गया है।
| op code | Usage (उपयोग) |
|---|---|
| log0(p, s) | बिना topics के लॉग और डेटा mem[p…(p+s)) |
| log1(p, s, t1) | topic t1 के साथ लॉग और डेटा mem[p…(p+s)) |
| log2(p, s, t1, t2) | topics t1, t2 के साथ लॉग और डेटा mem[p…(p+s)) |
| log3(p, s, t1, t2, t3) | topics t1, t2, t3 के साथ लॉग और डेटा mem[p…(p+s)) |
| log4(p, s, t1, t2, t3, t4) | topics t1, t2, t3, t4 के साथ लॉग और डेटा mem[p…(p+s)) |
एक लॉग में अधिकतम 4 topics हो सकते हैं, लेकिन एक गैर-अनाम (non-anonymous) solidity event में अधिकतम 3 indexed आर्गुमेंट्स हो सकते हैं। ऐसा इसलिए है क्योंकि पहले topic का उपयोग event signature को स्टोर करने के लिए किया जाता है। चार से अधिक topics को emit करने के लिए कोई ऑपकोड या Yul फ़ंक्शन नहीं है।
Unindexed पैरामीटर्स को मेमोरी क्षेत्र [p…(p+s)) में केवल ABI encoded किया जाता है और एक लंबे बाइट अनुक्रम (byte sequence) के रूप में emit किया जाता है।
याद करें कि पहले यह बताया गया था कि सिद्धांत रूप में Solidity में किसी event के लिए कितने unindexed आर्गुमेंट्स हो सकते हैं, इसकी कोई सीमा नहीं थी। इसका अंतर्निहित कारण यह है कि log ऑपकोड के पहले दो पैरामीटर्स द्वारा इंगित मेमोरी क्षेत्र कितनी लंबाई लेता है, इसकी कोई स्पष्ट सीमा नहीं है। निश्चित रूप से, contract के आकार और मेमोरी विस्तार गैस लागत (memory expansion gas costs) द्वारा प्रदान की गई सीमाएं होती हैं।
Solidity event को emit करने की गैस लागत (Gas cost)
स्टोरेज वेरिएबल्स में लिखने की तुलना में Events काफी सस्ते होते हैं। Events का उद्देश्य smart contracts द्वारा एक्सेस किया जाना नहीं है, इसलिए ओवरहेड की सापेक्ष कमी एक कम गैस लागत (gas cost) को उचित ठहराती है।
किसी event में कितनी गैस लगती है, इसका फॉर्मूला इस प्रकार है (स्रोत/source):
375 + 375 * num_topics + 8 * data_size + mem_expansion_cost
प्रत्येक event की लागत कम से कम 375 गैस होती है। प्रत्येक indexed पैरामीटर के लिए अतिरिक्त 375 का भुगतान किया जाता है। एक non-anonymous event में event selector एक indexed पैरामीटर के रूप में होता है, इसलिए यह लागत अधिकांश समय शामिल होती है। फिर हम चेन पर लिखे गए 32 बाइट शब्दों की संख्या का 8 गुना भुगतान करते हैं। चूँकि इस क्षेत्र को emit होने से पहले मेमोरी में स्टोर किया जाता है, इसलिए मेमोरी विस्तार लागत (memory expansion cost) को भी ध्यान में रखा जाना चाहिए।
किसी event की गैस लागत में सबसे महत्वपूर्ण कारक indexed events की संख्या है, इसलिए यदि आवश्यक न हो तो वेरिएबल्स को index न करें।
निष्कर्ष (Conclusion)
Events क्लाइंट्स के लिए उन transactions को तेज़ी से प्राप्त करने के लिए होते हैं जो उनके हित के हो सकते हैं। हालाँकि वे smart contract की कार्यक्षमता (functionality) को नहीं बदलते हैं, वे प्रोग्रामर को यह निर्दिष्ट करने की अनुमति देते हैं कि किन transactions को तेज़ी से प्राप्त करने योग्य होना चाहिए। Smart contracts में पारदर्शिता (transparency) में सुधार के लिए यह महत्वपूर्ण है।
अन्य ऑपरेशन्स की तुलना में Events गैस के मामले में अपेक्षाकृत सस्ते होते हैं, लेकिन उनकी लागत में सबसे महत्वपूर्ण कारक indexed पैरामीटर्स की संख्या है, यह मानते हुए कि कोडर बहुत अधिक मात्रा में मेमोरी का उपयोग नहीं करता है।
और जानें (Learn More)
यहाँ जो आपने देखा वह पसंद आया? अधिक जानने के लिए हमारा Solidity Bootcamp देखें।
शुरुआत करने के लिए हमारे पास एक मुफ्त solidity ट्यूटोरियल (solidity tutorial) भी है।
मूल रूप से 1 अप्रैल, 2023 को प्रकाशित