آموزش رویدادها در سالیدیتی

در سالیدیتی، رویدادها نقش ابزارهای ثبت و گزارش را ایفا می‌کنند و عملکردی شبیه به print یا console.log در محیط اتریوم دارند. در این بخش، نحوه استفاده از رویدادها، اصول مهم در طراحی آن‌ها و همچنین نکات فنی را بررسی می‌کنیم که بسیاری از منابع از آن‌ها غافل می‌مانند.

آموزش رویدادها در سالیدیتی

مثال زیر نشان می‌دهد که چطور می‌توان یک رویداد ساده را در سالیدیتی منتشر کرد:

توکن های ERC20 یکی از شناخته‌شده‌ترین کاربردهای رویدادها را ارائه می‌دهند. این توکن‌ ها هنگام انتقال، اطلاعاتی مانند آدرس فرستنده، آدرس گیرنده و مقدار توکن منتقل‌شده را در قالب یک رویداد ثبت می‌کنند.

در نگاه اول ممکن است این سؤال مطرح شود:

آیا این اطلاعات تکراری نیستند؟

در واقع، با بررسی تراکنش‌ ها و تحلیل calldata هم می‌توان به همین داده‌ ها رسید.

این نکته درست است؛ حذف رویدادها به منطق کلی قرارداد آسیبی نمی‌زند. اما اگر توسعه‌دهنده‌ ای این کار را انجام دهد، بررسی سابقه تراکنش‌ ها برای کاربران و برنامه‌  های خارجی به فرآیندی دشوار و ناکارآمد تبدیل می‌شود. رویدادها راهکاری سریع، ساختارمند و بهینه برای تحلیل اطلاعات تاریخی در بلاک چین فراهم می‌کنند.

بازیابی سریع‌تر تراکنش‌ ها در اتریوم

کلاینت اتریوم هیچ رابط برنامه نویسی (API) مشخصی برای فهرست کردن تراکنش‌ ها بر اساس نوع آن‌ها ارائه نمی‌دهد. اگر قصد دارید تراکنش‌ های گذشته را بررسی کنید، چند گزینه در اختیار دارید:

  • getTransaction

  • getTransactionFromBlock

تابع getTransactionFromBlock تنها می‌تواند تراکنش‌ های موجود در یک بلاک مشخص را به شما نشان دهد و نمی‌تواند اطلاعاتی درباره تراکنش‌ های مربوط به یک قرارداد هوشمند در بلاک‌ های مختلف ارائه کند.

تابع getTransaction هم فقط زمانی کارآمد است که هش دقیق تراکنش را در اختیار داشته باشید. اما رویدادها، در مقایسه با این روش‌ها، بسیار ساده‌تر قابل بازیابی هستند. در این زمینه، کلاینت اتریوم گزینه‌های زیر را ارائه می‌دهد:

  • events

  • events.allEvents

  • getPastEvents

برای استفاده از این توابع، ابتدا آدرس قرارداد هوشمند مورد نظر را مشخص می‌کنید. سپس با توجه به پارامترهای جستجو، این توابع مجموعه‌ای از رویدادهایی را که قرارداد ثبت کرده است، برمی‌گردانند.

اتریوم هیچ روشی برای بازیابی تمام تراکنش‌ های مربوط به یک قرارداد هوشمند ارائه نمی‌دهد، اما به شما این امکان را می‌دهد که تمام رویدادهای منتشرشده توسط یک قرارداد را بازیابی کنید.

چرا چنین تفاوتی وجود دارد؟ برای اینکه رویدادها سریع و بهینه قابل جستجو باشند، باید اطلاعات آن‌ها به‌صورت مجزا ذخیره شود؛ این موضوع باعث افزایش حجم داده‌ها می‌شود. اگر اتریوم می‌خواست این سطح از قابلیت جستجو را برای تمام تراکنش‌ ها فراهم کند، اندازه بلاک چین به‌صورت چشمگیری افزایش پیدا می‌کرد. در عوض، زبان سالیدیتی این امکان را در اختیار برنامه‌ نویس می‌گذارد تا خودش تعیین کند که چه اطلاعاتی ارزش این افزایش حجم را دارند. به این ترتیب، فقط داده‌ هایی که بازیابی سریع آن‌ها اهمیت دارد، به‌عنوان رویداد ثبت می‌شوند تا از بیرون زنجیره (off-chain) بتوان آن‌ها را به راحتی واکشی کرد.

گوش دادن به رویدادها (Listening to Events)

توسعه‌ دهندگان سالیدیتی رویدادها را با هدف استفاده خارج از زنجیره (off-chain) طراحی کرده‌اند.

در ادامه، مثالی از کاربرد عملی API هایی که پیش‌تر معرفی شدند ارائه می‌شود. در این مثال، کلاینت به رویدادهایی که یک قرارداد هوشمند منتشر می‌کند، گوش می‌دهد و در صورت انتشار، آن‌ها را دریافت و پردازش می‌کند.

مثال اول: گوش دادن به رویدادهای انتقال در توکن های ERC20

در این مثال، هر زمان که یک توکن ERC20 رویداد Transfer را منتشر می‌کند، کد نوشته‌شده به‌طور خودکار یک تابع برگشتی (callback) را اجرا می‌کند.

مثال دوم: فیلتر کردن رویداد Approval برای یک آدرس خاص در توکن ERC20

برای بررسی رویدادهای گذشته، می‌توانیم از کد زیر استفاده کنیم. در این مثال، به دنبال تراکنش‌ های Approval در یک قرارداد توکن ERC20 می‌گردیم که مربوط به یک آدرس مشخص باشند.

اگر بخواهید یک تراکنش انتقال بین دو آدرس مشخص را جستجو کنید (در صورتی که چنین تراکنشی وجود داشته باشد)، کد جاوا اسکریپت با استفاده از کتابخانه Ethers.js به صورت زیر خواهد بود:

در کد بالا، مقدار null به این معناست که هر مقدار برای آن فیلد قابل پذیرش است. در رویداد Transfer نیز همین مقدار به ما اجازه می‌دهد تمام مقادیر انتقال را بدون هیچ محدودیتی بررسی کنیم.

برای درک بهتر، نگاهی به نمونه‌ای مشابه در کتابخانه web3.js می‌اندازیم. در این نسخه، بازه جستجو با پارامترهای fromBlock و toBlock مشخص شده است. علاوه بر این، نشان می‌دهیم چگونه می‌توان به‌طور همزمان رویدادهایی را دریافت کرد که فرستنده آن‌ها یکی از چند آدرس خاص باشد. این آدرس‌ها با استفاده از شرط منطقی «OR» با یکدیگر ترکیب می‌شوند.

در حال حاضر، نمی‌توان در فیلترها از شروط بازه‌ ای استفاده کرد. نمی‌توانید فیلتری تعریف کنید که مثلاً بگوید «تمام تراکنش‌هایی را نمایش بده که مقدار انتقال‌یافته بین یک حد پایین و یک حد بالا قرار دارد». برای این کار، باید ابتدا همه رویدادها را دریافت کرده و سپس در کد سمت کلاینت، فیلتر دلخواه را روی داده‌ها اعمال کنید.

مثال سوم: ساخت جدول رتبه‌بندی (Leaderboard) بدون ذخیره داده‌ها در قرارداد

فرض کنید یک قرارداد هوشمند دارید که افراد می‌توانند به آن اتریوم اهدا کنند و شما می‌خواهید در بخش رابط کاربری (Frontend)، اهداکنندگان را بر اساس میزان کمک مالی رتبه‌بندی کنید. در ادامه، ابتدا یک روش ناکارآمد را بررسی می‌کنیم:

اگر قرار نیست این اطلاعات روی زنجیره (on-chain) خوانده شوند، این روش ساده‌ انگارانه است. چون هر بار که فردی اتریوم ارسال می‌کند، باید هزینه گس قابل توجهی برای ذخیره داده‌ ها روی بلاک چین پرداخت کند.

در مقابل، می‌توان راهکار بسیار بهینه‌ تری با استفاده از رویدادها (events) پیاده‌ سازی کرد:

در این روش، رابط کاربری (Frontend) می‌تواند به راحتی تمام رویدادهای Donation را از قرارداد هوشمند بازیابی کرده و آن‌ها را بر اساس مقدار amount مرتب کند تا جدول رتبه‌ بندی اهداکنندگان ساخته شود.

نکته مهم اینجاست که رویدادها در وضعیت (state) بلاک چین ذخیره می‌شوند و موقتی یا فرار (ephemeral) نیستند. بنابراین، نیازی نیست نگران از دست رفتن رویدادی باشید؛ کلاینت در هر زمان می‌تواند دوباره همه رویدادها را استعلام و بازیابی کند.

رویدادهای indexed و non-indexed در سالیدیتی

در مثال قبلی، کد به درستی عمل می‌کرد چون رویدادهای Approve و Transfer در استاندارد ERC20 پارامتر sender را به‌صورت indexed تعریف کرده‌اند. در ادامه، نحوه تعریف این رویداد را در سالیدیتی مشاهده می‌کنید:

اگر پارامتر owner در این تعریف به‌صورت indexed مشخص نشده بود، کد جاوا اسکریپتی که در بخش قبلی دیدید بدون هیچ پیغام خطایی، نتیجه‌ای برنمی‌گرداند و عملاً عملکردی نداشت.

این نکته اهمیت زیادی دارد، چون به ما می‌گوید نمی‌توان رویدادهای ERC20 را بر اساس مقدار value فیلتر کرد؛ چون این فیلد indexed نیست. بنابراین، اگر بخواهید فقط تراکنش‌ هایی با مقدار خاص را بررسی کنید، باید تمام رویدادها را دریافت کرده و فیلتر را در سمت جاوا اسکریپت اعمال کنید؛ این کار از طریق کلاینت اتریوم امکان‌پذیر نیست.

در سالیدیتی، به هر پارامتری که در تعریف رویداد با کلیدواژه indexed مشخص شده باشد، یک تاپیک (topic) گفته می‌شود. کلاینت‌ ها می‌توانند بر اساس این تاپیک‌ ها، رویدادها را به‌صورت بهینه فیلتر و جستجو کنند.

بهترین شیوه‌ ها در استفاده از رویدادها در سالیدیتی

بر اساس عرف رایج میان توسعه‌ دهندگان، بهترین زمان برای ثبت رویداد (emit) در سالیدیتی زمانی است که تغییری مهم در وضعیت قرارداد اتفاق می‌افتد. برخی از مثال‌های رایج برای این موقعیت‌ ها عبارت‌اند از:

  • تغییر مالکیت قرارداد

  • انتقال اتر

  • انجام معامله یا تبادل

البته، هر تغییر وضعیت (state change) نیازی به ثبت رویداد ندارد. توسعه‌ دهنده باید از خود بپرسد:

“آیا کسی ممکن است بخواهد این تراکنش را سریع‌تر کشف یا بازیابی کند؟”

اگر پاسخ مثبت است، ثبت رویداد توجیه‌پذیر خواهد بود.

پارامترهای مناسب را index کنید

در انتخاب پارامترهایی که باید با کلیدواژه indexed مشخص شوند، باید با دقت و تشخیص درست عمل کرد. به یاد داشته باشید که پارامترهای غیر indexed به‌صورت مستقیم قابل جستجو نیستند.
برای درک بهتر این موضوع، توصیه می‌شود طراحی رویدادها را در پروژه‌ های معتبر بررسی کنید، از جمله:

به‌عنوان یک قاعده کلی:

مقادیر رمزارز (مانند مبلغ انتقال) معمولاً نباید indexed شوند، اما آدرس‌ها باید indexed باشند.

البته این قاعده نباید به‌صورت کورکورانه اجرا شود؛ همیشه شرایط خاص پروژه را در نظر بگیرید.

از ثبت رویدادهای تکراری خودداری کنید

برای مثال، اگر یک کتابخانه داخلی هنگام ضرب (mint) توکن به‌طور خودکار رویداد مربوطه را منتشر می‌کند، نیازی نیست که شما دوباره همان رویداد را در قرارداد خود ثبت کنید. این کار تنها باعث افزوده شدن داده‌های غیرضروری می‌شود.

رویدادها را نمی‌توان در توابع view یا pure استفاده کرد

رویدادها وضعیت بلاک چین را با ذخیره لاگ تغییر می‌دهند، به همین دلیل جزو عملیات تغییر وضعیت محسوب می‌شوند. به همین علت، در توابع view یا pure که نباید تغییری در بلاک چین ایجاد کنند، امکان استفاده از رویدادها وجود ندارد.

برخلاف زبان‌ هایی که از print یا console.log برای دیباگ کردن استفاده می‌کنند، رویدادها برای این کار مناسب نیستند. چون رویدادها فقط زمانی ثبت می‌شوند که تراکنش با موفقیت انجام شده باشد. اگر تراکنش بازگردانده شود (revert)، رویداد مربوطه هم منتشر نمی‌شود. بنابراین، برای دیباگ باید از ابزارهای شبیه‌ سازی یا ثبت در حافظه محلی استفاده کنید.

یک رویداد در سالیدیتی چند آرگومان می‌تواند داشته باشد؟

از نظر فنی، برای پارامترهای غیر indexed محدودیتی بر تعداد آرگومان ها وجود ندارد، اما اگر تعداد آن‌ها بیش از حد زیاد شود، با محدودیت پشته (stack limit) در ماشین مجازی اتریوم مواجه خواهید شد. به‌عنوان نمونه، کد زیر با اینکه معنای خاصی ندارد، از نظر نگارشی در سالیدیتی معتبر است:

همچنین، هیچ محدودیتی ذاتی برای طول رشته ها (string) یا آرایه ها (array) در داده های ثبت‌شده در لاگ وجود ندارد. این نوع داده ها را می‌توان بدون محدودیت مشخص در رویدادها ذخیره کرد (البته باید به هزینه گس توجه داشت).

اما یک محدودیت مهم در مورد پارامترهای indexed (تاپیک‌ها) وجود دارد:
در یک رویداد معمولی، حداکثر می‌توان سه پارامتر را به‌صورت indexed مشخص کرد. اگر بخواهید چهار پارامتر را index کنید، باید از رویدادهای anonymous استفاده کنید (که در بخش‌های بعدی به تفاوت آن‌ها می‌پردازیم).

در نهایت، تعریف رویدادی که هیچ آرگومانی ندارد نیز کاملاً معتبر است و از نظر سالیدیتی مشکلی ندارد.

نام‌گذاری متغیرها در رویدادها: اختیاری اما توصیه‌شده

در سالیدیتی، مشخص کردن نام برای پارامترهای رویداد الزامی نیست، اما به شدت توصیه می‌شود. به‌عنوان مثال، دو رویداد زیر از نظر عملکرد کاملاً یکسان هستند:

با این حال، استفاده از نام متغیر باعث خوانایی بهتر کد می‌شود. در غیر این صورت، معنا و مفهوم رویداد می‌تواند بسیار مبهم باشد. به مثال زیر توجه کنید:

در این مثال، ممکن است بتوان حدس زد که آدرس‌ها به ترتیب مربوط به فرستنده و دو توکن هستند، و مقادیر uint256 بیانگر حجم مبادله باشند. اما چون نامی برای پارامترها مشخص نشده، تفسیر دقیق آن دشوار خواهد بود و درک معنای رویداد برای توسعه‌دهندگان دیگر پیچیده می‌شود.

به‌صورت قراردادی، معمول است که نام رویدادها با حرف بزرگ (حرف اول Capital) نوشته شود، اما کامپایلر سالیدیتی چنین الزامی را ایجاد نمی‌کند و در صورت رعایت نکردن آن هم کد اجرا می‌شود.

ارث‌بری رویدادها از قراردادهای والد و اینترفیس‌ها

در سالیدیتی، اگر یک رویداد در یک قرارداد والد (parent contract) تعریف شده باشد، قرارداد فرزند (child contract) نیز می‌تواند آن رویداد را ارسال (emit) کند.
نکته مهم این است که رویدادها از نظر سطح دسترسی همواره داخلی (internal) هستند و نمی‌توان آن‌ها را private یا public تعریف کرد.

در مثال زیر، رویداد NewNumber در قرارداد والد تعریف شده و هم در همان قرارداد و هم در قرارداد فرزند قابل استفاده است:

به‌طور مشابه، می‌توان رویدادی را در یک اینترفیس (interface) تعریف کرد و سپس آن را در یک قرارداد پیاده‌سازی‌شده مورد استفاده قرار داد. مثال زیر این موضوع را نشان می‌دهد:
در این ساختار، قرارداد ExampleContract رویدادی را منتشر می‌کند که قبلاً در اینترفیس IExampleInterface تعریف شده است، بدون نیاز به تعریف مجدد آن در بدنه قرارداد.

سلکتور رویداد (Event Selector)

ماشین مجازی اتریوم (EVM) برای شناسایی رویدادها، از هش keccak256 امضای رویداد (event signature) استفاده می‌کند.

از نسخه ۰.۸.۱۵ به بعد سالیدیتی، می‌توان سلکتور یک رویداد را به‌صورت مستقیم با استفاده از عضو .selector نیز به دست آورد.

در مثال زیر، این قابلیت نشان داده شده است:

سلکتور رویداد در واقع خودش یکی از تاپیک‌ها (topics) به شمار می‌رود (در بخش‌های بعدی بیشتر درباره این موضوع توضیح خواهیم داد).

نکته مهم این است که قرار دادن یا حذف کلیدواژه indexed روی پارامترهای رویداد، هیچ تغییری در سلکتور ایجاد نمی‌کند؛ چرا که سلکتور فقط به امضای تابع (نام و نوع پارامترها) بستگی دارد و نه به نحوه فیلترپذیری آن‌ها.

رویدادهای ناشناس (Anonymous Events)

در سالیدیتی، می‌توان رویدادها را با استفاده از کلیدواژه anonymous به‌صورت ناشناس تعریف کرد. در این حالت، رویداد فاقد سلکتور خواهد بود.
این موضوع بدان معناست که کد سمت کلاینت نمی‌تواند مانند مثال‌های قبلی، این رویدادها را به‌صورت خاص و مستقیم فیلتر کند.

مثال زیر، نحوه تعریف یک رویداد ناشناس را نشان می‌دهد:

در حالت عادی، امضای رویداد (event signature) به‌عنوان یکی از تاپیک‌ها (topics) در نظر گرفته می‌شود. اما وقتی رویدادی را به‌صورت ناشناس تعریف می‌کنیم، چون دیگر نیازی به تاپیک مربوط به امضا نداریم، می‌توانیم چهار پارامتر را به‌صورت indexed مشخص کنیم (درحالی‌که در حالت معمولی فقط سه پارامتر را می‌توان index کرد).

مثال زیر، تعریف معتبر یک رویداد ناشناس با چهار پارامتر indexed را نشان می‌دهد:

در عمل، استفاده از رویدادهای ناشناس بسیار نادر است و تنها در موارد خاص به‌کار می‌روند، مثلاً در برخی قراردادهای سطح پایین یا برای ذخیره‌سازی لاگ‌های خاص که نیازی به فیلتر یا دسته‌بندی ندارند.

مباحث پیشرفته درباره رویدادها در سطح اسمبلی EVM

در این بخش، جزئیات رویدادها در سطح اسمبلی ماشین مجازی اتریوم (EVM) بررسی می‌شود. اگر در ابتدای مسیر یادگیری توسعه قراردادهای هوشمند هستید، می‌توانید از این بخش عبور کنید.

جزئیات پیاده‌سازی: فیلتر بلوم (Bloom Filters)

اگر یک کلاینت اتریوم بخواهد تمام تراکنش‌هایی که در یک قرارداد هوشمند انجام شده‌اند را بازیابی کند، باید همه بلاک‌ها را یکی‌یکی اسکن کند. این کار بار ورودی/خروجی بسیار سنگینی به همراه دارد. برای حل این مشکل، اتریوم از یک بهینه‌سازی مهم استفاده می‌کند: فیلتر بلوم.

در هر بلاک، رویدادها در یک ساختار داده‌ای به نام Bloom Filter ذخیره می‌شوند.
فیلتر بلوم مجموعه‌ای احتمالاتی (probabilistic set) است که می‌تواند با سرعت بالا پاسخ دهد که آیا یک عضو خاص در آن مجموعه وجود دارد یا نه. به‌جای اسکن کامل بلاک، کلاینت می‌تواند از فیلتر بلوم بپرسد که آیا رویدادی خاص در آن بلاک منتشر شده است یا خیر.
این روش بسیار سریع‌تر از بررسی خط‌به‌خط داده‌های بلاک است.

استفاده از فیلتر بلوم، امکان جستجوی سریع رویدادها در بلاک چین را برای کلاینت فراهم می‌کند.

فیلتر بلوم یک ساختار احتمالاتی است؛ به این معنا که گاهی به‌اشتباه اعلام می‌کند یک عضو در مجموعه وجود دارد، در حالی که چنین نیست.
هرچه تعداد اعضای ذخیره‌شده در فیلتر بیشتر شود، احتمال خطا نیز افزایش می‌یابد. برای جبران این خطاها، اندازه فیلتر باید بزرگ‌تر شود که به معنی مصرف بیشتر حافظه خواهد بود.

به همین دلیل، اتریوم تراکنش‌ها را در فیلتر بلوم ذخیره نمی‌کند و فقط رویدادها را در این ساختار نگه‌داری می‌کند. چون تعداد رویدادها به‌مراتب کمتر از تراکنش‌هاست، این تصمیم باعث می‌شود اندازه بلاک چین در حد معقول باقی بماند.

زمانی که فیلتر بلوم اعلام می‌کند که یک رویداد ممکن است در بلاک وجود داشته باشد، کلاینت باید بلاک را بررسی کند تا از وقوع آن رویداد مطمئن شود. اما از آنجا که چنین بررسی‌هایی فقط در تعداد محدودی از بلاک‌ها انجام می‌شوند، در مجموع این فرآیند باعث کاهش قابل توجه بار پردازشی برای کلاینت خواهد شد.

رویدادها در Yul (سطح اسمبلی سالیدیتی)

در زبان میانی Yul، تفاوت میان پارامترهای indexed (موضوعات یا topics) و پارامترهای غیر indexed (بدنه داده) به‌روشنی نمایان می‌شود.

برای ارسال (emit) رویدادها در Yul، مجموعه‌ای از توابع با نام‌های log0 تا log4 در اختیار برنامه‌نویس قرار دارد. این توابع مستقیماً به opcodeهای معادل در ماشین مجازی اتریوم (EVM) تبدیل می‌شوند. جدول زیر، که با ساده‌سازی از مستندات Yul استخراج شده، این توابع را شرح می‌دهد:

تابع Yul کاربرد
log0(p, s) ارسال لاگ بدون topic؛ داده از حافظه در بازه [p … p + s) گرفته می‌شود
log1(p, s, t1) ارسال لاگ با یک topic (t1) و داده از بازه حافظه [p … p + s)
log2(p, s, t1, t2) ارسال لاگ با دو topic و داده
log3(p, s, t1, t2, t3) ارسال لاگ با سه topic و داده
log4(p, s, t1, t2, t3, t4) ارسال لاگ با چهار topic و داده

در Yul (و EVM)، هر لاگ می‌تواند حداکثر ۴ topic داشته باشد. اما در سالیدیتی، یک رویداد غیرناشناس (non-anonymous) تنها می‌تواند ۳ پارامتر indexed داشته باشد. دلیل این محدودیت آن است که اولین topic به هش امضای رویداد اختصاص می‌یابد.

در نتیجه، باقی‌مانده فضا برای پارامترهای قابل فیلتر فقط سه عدد است.
در رویدادهای ناشناس (anonymous)، چون امضای رویداد ذخیره نمی‌شود، می‌توان تا ۴ پارامتر indexed را استفاده کرد.

پارامترهای غیرindexed به‌صورت کدگذاری ABI (ABI-encoded) در یک ناحیه پیوسته از حافظه قرار می‌گیرند؛ این ناحیه در بازه [p … p + s) تعریف شده و داده‌ها به‌صورت یک رشته بایت متوالی در لاگ ذخیره می‌شوند.

همان‌طور که پیش‌تر اشاره شد، سالیدیتی به‌طور نظری هیچ محدودیتی برای تعداد پارامترهای غیرindexed در رویدادها اعمال نمی‌کند. دلیل این موضوع در معماری سطح پایین EVM نهفته است:
در opcodeهای log، هیچ محدودیتی برای اندازه ناحیه حافظه‌ای که داده در آن ذخیره می‌شود وجود ندارد. تنها محدودیت‌های موجود، مربوط به محدودیت کلی اندازه قرارداد و هزینه گس ناشی از گسترش حافظه هستند.

هزینه گس برای ارسال رویداد در سالیدیتی

ارسال (emit) رویدادها در سالیدیتی به‌مراتب ارزان‌تر از نوشتن داده در متغیرهای ذخیره‌سازی (storage) است. دلیل این تفاوت در این است که رویدادها برای استفاده خارج از زنجیره (off-chain) طراحی شده‌اند و نیازی نیست که قراردادهای هوشمند به آن‌ها دسترسی مستقیم داشته باشند؛ همین موضوع باعث کاهش سربار محاسباتی و در نتیجه هزینه گس کمتر می‌شود.

فرمول محاسبه گس برای ارسال یک رویداد (منبع):

  • حداقل هزینه برای هر رویداد ۳۷۵ گس است.

  • برای هر پارامتر indexed (تاپیک)، ۳۷۵ گس اضافی محاسبه می‌شود.

  • در رویدادهای غیرناشناس، امضای رویداد نیز به‌عنوان یک تاپیک ذخیره می‌شود، بنابراین یک هزینه اضافی برای سلکتور رویداد در نظر گرفته می‌شود.

  • سپس، برای داده‌هایی که در حافظه ذخیره و روی زنجیره منتشر می‌شوند، به ازای هر کلمه ۳۲ بایتی، ۸ گس پرداخت می‌شود.

  • چون داده قبل از ارسال در حافظه نگه‌داری می‌شود، باید هزینه گسترش حافظه را نیز در محاسبه گس در نظر گرفت.

تعداد پارامترهای indexed (تاپیک‌ها) بیشترین تأثیر را در هزینه گس رویدادها دارد. بنابراین اگر نیاز واقعی به جستجو و فیلتر روی یک پارامتر وجود ندارد، بهتر است آن را indexed نکنید تا هزینه گس بهینه بماند.

جمع‌بندی

رویدادها ابزار بسیار مؤثری برای دسترسی سریع کلاینت‌ها به تراکنش‌های مهم هستند. اگرچه رویدادها تأثیری بر منطق اجرایی قرارداد ندارند، اما به برنامه‌نویس این امکان را می‌دهند که تعیین کند کدام تراکنش‌ها ارزش ثبت و پیگیری از خارج زنجیره را دارند. این ویژگی برای شفافیت بیشتر در قراردادهای هوشمند بسیار حیاتی است.

از نظر مصرف گس، رویدادها در مقایسه با عملیات‌هایی مانند نوشتن در storage بسیار مقرون‌به‌صرفه هستند، البته در صورتی که از حافظه زیاد استفاده نشود و تعداد پارامترهای indexed نیز کنترل‌شده باشد.

5/5 - (1 امتیاز)

راستی! برای دریافت مطالب جدید در کانال تلگرام یا پیج اینستاگرام سورس باران عضو شوید.

پکیج جامع و پروژه محور ASP.NET MVC + طراحی فروشگاه اینترنتی فروش فایل
  • انتشار: ۵ خرداد ۱۴۰۴

دسته بندی موضوعات

آخرین محصولات فروشگاه

مشاهده همه

نظرات

بازخوردهای خود را برای ما ارسال کنید