اتریوم چگونه کار می کند؟- بخش سوم

اجرای تراکنش
حالا به یکی از پیچیدهترین بخشهای پروتکل اتریوم رسیدهایم: اجرای یک تراکنش. فرض کنیم شما یک تراکنش را برای اجرا به شبکه اتریوم ارسال میکنید. چه اتفاقی میافتد تا حالت اتریوم تغییر کند و تراکنش شما به آن اضافه شود؟

قبل از هر چیز، همه تراکنشها باید مجموعهای از شرایط موردنیاز را فراهم کرده باشند تا اجرا شوند. برخی از این شرایط عبارتند از:
- این تراکنش باید به درستی در فرمت RLP ارسال شده باشد. RLP به معنای پیشوند طول بازگشتی (Recursive Length Prefix) است. این فرمت، نوعی فرمت داده است که برای کدگذاری آرایههای تودرتوی دادههای دودویی (باینری) به کار میرود. RLP فرمتی است که اتریوم از آن برای مرتبکردن اشیاء استفاده میکند.
- امضای تراکنش معتبر.
- نانس تراکنش معتبر. میدانید که نانس یک حساب، تعداد تراکنشهای ارسالشده از آن حساب است. نانس تراکنش برای معتبر بودن باید با نانس حساب فرستنده برابر باشد.
- حد سوخت تراکنش باید بزرگتر یا مساوی سوخت داخلی (intrinsic gas) استفاده شده توسط تراکنش باشد. سوخت داخلی شامل موارد زیر است:
- هزینه از پیش تعیینشده به مقدار ۲۱,۰۰۰ واحد سوخت (gas) برای اجرای تراکنش؛
- مقدار سوخت برای دادههای ارسال شده با این تراکنش (۴ واحد سوخت برای هر بایت داده یا کد که برابر با صفر باشد و ۶۸ سوخت برای هر بایت از داده یا کد که مقدار آن غیرصفر باشد)
- اگر این تراکنش از نوع تراکنش ایجادکننده قرارداد باشد ۳۲,۰۰۰ واحد سوخت اضافی هم باید در نظر گرفته شود.

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

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

در مرحله بعد، تراکنش شروع به اجرا میکند. در طی اجرای یک تراکنش، اتریوم یک حالت جانبی را پیگیری میکند. این حالت جانبی روشی برای نگهداری اطلاعات بهدستآمده در فرایند اجرای تراکنش است که بلافاصله پس از کاملشدن تراکنش به آن نیاز خواهیم داشت. این حالت شامل موارد زیر نیز هست:
- مجموعه دورریزشونده خودکار (Self-destruct set): مجموعهای از حسابها (در صورت وجود) که پس از تکمیل تراکنش دور ریخته میشود.
- لاگها: نقاط بررسی (چکپوینتهای) بایگانیشده و قابل اندیسگذاری از فرایند اجرای کد ماشین مجازی.
- بازپرداختیها: مبالغی که پس از انجام تراکنش به حساب فرستنده بازگردانده میشود. گفتیم که فضای ذخیرهسازی در اتریوم هزینه دارد و در ازای آزادسازی این فضا مبلغی را به فرستنده پرداخت میکنند. اتریوم با یک شمارنده بازپرداخت، حساب این مقادیر را نگه میدارد. این شمارنده از صفر آغاز میشود و هر بار که قرارداد چیزی را در فضای ذخیرهسازی پاک میکند افزایش مییابد.
در مرحله بعد، محاسبات مختلفی که برای اجرای تراکنش ضروری است بررسی میشوند.
هنگامیکه همه مراحل بررسی شدند و دیگر هیچ حالت نامعتبری وجود نداشت، حالت جدید با تعیین مقدار سوخت دستنخوردهای که باید به فرستنده بازگردانده شود به پایان میرسد. علاوه بر سوخت اضافی، فرستنده مقداری سوخت هم از محل فضای ذخیرهسازی که در بالا از آن صحبت کردیم دریافت میکند.
علاوه بر اضافی مبلغ سوخت که به فرستنده بازگردانده میشود، موارد زیر هم انجام میشوند:
- معادل سوخت پرداختشده به ماینرها اتر داده میشود؛
- سوخت استفادهشده توسط تراکنش به شمارنده سوخت بلاک اضافه میشود (این شمارنده حساب کل مقدار سوختی را که توسط همه تراکنشهای موجود در بلاک مصرف شده است نگه میدارد و در تایید اعتبار یک بلاک از آن استفاده میشود)؛
- همه حسابهای مجموعه دورریز شونده (اگر چیزی از آنها باقی مانده باشد) پاک میشوند زیرا دیگر به آنها نیازی نیست.
در نهایت، حالت جدید و مجموعهای از لاگهای ایجادشده توسط این تراکنش را خواهیم داشت.
حالا که اصول اجرای تراکنش را یاد گرفتهایم میتوانیم به تفاوتهای بین تراکنشهای ایجادکننده قرارداد و تراکنشهای فراخوانی پیام بپردازیم.
ایجاد قرارداد
همانطور که گفته شد در اتریوم دو نوع حساب داریم: حسابهای مبتنی بر قرارداد و حسابهای با مالکیت خارجی. وقتی میگوییم یک تراکنش ایجادکننده قرارداد است، منظورمان این است که هدف آن تراکنش ایجاد یک حساب مبتنی بر قرارداد جدید است.
برای ایجاد یک حساب مبتنی بر قرارداد جدید، ابتدا با استفاده از فرمول خاصی آدرس حساب جدید را مشخص میکنیم. سپس حساب جدید را به طریق زیر ایجاد میکنیم:
- نانس را صفر قرار میدهیم؛
- اگر فرستنده مقداری اتر به عنوان ارزش مورد مبادله تراکنش ارسال کرده بود، موجودی حساب را روی آن مبلغ تنظیم میکنیم؛
- مبلغ اضافهشده به موجودی حساب جدید را از موجودی حساب فرستنده کم میکنیم؛
- فضای ذخیرهسازی خالی را برای آن درنظر میگیریم؛
- کدهش قرارداد را به عنوان هش یک رشته خالی تنظیم میکنیم.
پس از مقداردهی اولیه حساب، میتوانیم این حساب را با استفاده از اینیت کد (init code) که با تراکنش فرستاده شده است (قبلا درباره آن در بخش تراکنشها و پیامها توضیح دادیم) ایجاد کنیم. چیزی که در طی اجرای اینیت کد اتفاق میافتد، بسته به شرایط متفاوت است. ممکن است فضای ذخیرهسازی حساب بهروزرسانی شود، حسابهای مبتنی بر قرارداد دیگری ایجاد شوند، فراخوانی پیام دیگری ایجاد شوند و نظایر آنها.
هنگامیکه این کد برای مقداردهی اولیه یک قرارداد اجرا میشود، سوخت مصرف میکند. یک تراکنش نمیتواند بیش از مقدار باقیمانده سوخت از آن استفاده کند. اما اگر سوخت به پایان رسیده باشد و هنوز تراکنش کامل نشده باشد، اعلام میشود که سوخت به پایان رسیده است و اجرای قرارداد متوقف میشود. اگر تراکنش بهدلیل اتمام سوخت لغو شود، حالت فعلی بلافاصله به نقطه قبل از اجرای تراکنش برمیگردد و فرستنده دیگر نمیتواند مبلغ سوخت پرداختی برای اجرای تراکنش را پس بگیرد.
بااینحال هر مقدار اتری که فرستنده با تراکنش فرستاده باشد، حتی در صورت عدم ایجاد قرارداد و اجرای تراکنش باز هم به او بازگردانده میشود. در واقع شما فقط سوختی را از دست میدهید که برای اجرای فرایند بررسی تراکنش مصرف شده است و مبلغ اتر فرستاده شده با تراکنش در هر صورت مال خودتان است.
اگر کد آغازکننده با موفقیت اجرا شود، هزینه نهایی ایجاد قرارداد پرداخت میشود. این هزینه برای فضای ذخیرهسازی است و متناسب با اندازه کد قرارداد ایجاد شده است (هیچ چیز اینجا رایگان نیست!). اگر هیچ سوختی برای این هزینه نهایی باقی نمانده باشد باز هم تراکنش بهدلیل اتمام سوخت لغو میشود.
اگر همه چیز خوب پیش برود و مشکلی پیش نیاید، در نهایت سوخت باقیمانده به فرستنده اصلی بازگردانده میشود و حالت جدید جایگزینشده باقی میماند.
فراخوانی پیام
اجرای یک فراخوانی پیام همانند ایجاد قرارداد است اما با آن تفاوتهایی جزئی دارد.
اجرای یک فراخوانی پیام نیازی به اینیت کد ندارد، چرا که هیچ حساب جدیدی قرار نیست ایجاد شود. با این حال، میتواند شامل دادههای ورودی باشد، آن هم به شرطی که این دادهها توسط فرستنده تراکنش ارائه شده باشند. فراخوانی پیام در هنگام اجرا ممکن است یک جزء اضافی حاوی دادههای خروجی هم داشته باشد. این زمانی است که قرار باشد به دنبال این تراکنش عمل دیگری هم انجام شود که به آن دادههای خروجی نیاز داشته باشد.
درست همانند ایجاد قرارداد، اگر اجرای یک فراخوانی پیام قبل از اجرای کامل بهدلیل اتمام سوخت یا نامعتبر بودن تراکنش (به عنوان مثال به خاطر سرریز پشته، مقصد نامعتبر یا دستورالعمل نادرست) لغو شود، سوخت پرداختی دوباره به فراخواندهنده اصلی بازگردانده نمیشود و حالت بلافاصله به حالت قبل از انتقال موجودی برمیگردد.
تا قبل از بهروزرسانی بیزانس اتریوم، هیچ راهی برای متوقفکردن یا بازگرداندن اجرای یک تراکنش تا زمانی که تمام سوخت مصرف شود وجود نداشت. برای مثال، فرض کنیم شما قراردادی نوشته بودید، اما گیرنده مجاز به انجام بعضی تراکنشها نبود و بنابراین تراکنش شما با خطا مواجه میشد. در نسخههای قبلی اتریوم، مقدار سوخت تا آخرین لحظه مصرف میشد و دیگر هیچ سوختی به شما بازگردانده نمیشد. اما نسخه بیزانس اتریوم شامل یک کد «برگشت» جدید است که به فرستنده قرارداد اجازه میدهد اجرای تراکنش را متوقف کند، تغییرات حالت را برگرداند و به این ترتیب از هدر رفتن سوخت برای تراکنشی که میداند دارد با شکست مواجه میشود جلوگیری کند. اگر یک تراکنش به دلیل این برگشت لغو شود، فرستنده میتواند مابقی سوخت استفاده نشده را دوباره دریافت کند.
امتیاز دادن به خبر
با لایک کردن هر خبر میتوانید کوین بیشتری جایزه بگیرید




