بالاخره اتریوم چطور کار می‌کند؟ (بخش ۲ - حساب، پرداخت و کارمزد)

این یک ترجمه آزاد از مقاله‌ای به زبان انگلیسی است. لینک مقاله اصلی در انتهای پست ذکر شده است.ترجمه بخش اول این مقاله را می‌توانید اینجا ببینید.حالت حساب (Account State)حالت حساب، صرفنظر از نوع حساب، از چهار جزء (component) تشکیل شده است.نانس nonce: اگر حساب دارای مالک بیرونی باشد، این عدد نشان‌دهنده تعداد تراکنش‌هایی است که تا آن لحظه از آدرس این حساب ارسال شده است. اگر حساب یک حساب قرارداد هوشمند باشد،‌ nonce برابر با تعداد قراردادهایی است که تاکنون توسط این حساب ایجاد شده است.موجودی balance: مجموع موجودی حساب بر حسب Wei (هر Ethere معادل ۱۰ به توان ۱۸ Wei است)استوریج روت storageRoot: حاوی مقدار هش ریشه درخت مرکل (Merkle Patricia Tree) است. این درخت مقدارهای هش شده‌ی محتوای حافظه (storage) حساب را نگه می‌دارد و به صورت پیش‌فرض خالی است.کد هش codeHash: در حساب‌های قرارداد هوشمند برابر با مقدار هش شده‌ی کد (برنامه) EVM یا همان Ethereum Virtual Machine (این یکی را هم جلوتر توضیح می‌دهیم) است. برای حساب‌های دارای مالک بیرونی این فیلد مساوی مقدار هش یک رشته خالی است.World Stateمی‌دانیم که global state اتریوم (یا همان حالت کل شبکه) از یک نگاشت (mapping) بین آدرس حساب‌ها و حالت حساب‌ها تشکیل شده است. این نگاشت در ساختار داده‌ای نگهداری می‌شود که Merkle Patricia tree نام دارد.یک درخت Merkle نوعی درخت دو-دویی (binary tree) متشکل از مجموعه‌ای از گره‌هاست با:تعداد زیادی گره برگ (leaf node) در پایین درخت که حاوی اطلاعات درخت هستندمجموعه‌ای از گره‌های میانی، هر گره میانی حاوی مقدار هش دو گره فرزند خود استیک گره ریشه که آن هم حاوی مقدار هش دو فرزند خود است و بالاترین گره درخت استداده‌های بخش پایینی درخت اینطور تولید می‌شوند: داده‌ای که قرار است ذخیره شود به chunk ها و سپس chunk ها به bucket ها تقسیم می‌شوند، پس از آن هر bucket هش می‌شود و این پروسه آنقدر تکرار می‌شود که در نهایت یک هش باقی بماند: هش ریشه (Root hash).درخت باید به ازای هر مقداری که در آن ذخیره می‌شود یک کلید (key) داشته باشد. با شروع [مسیر] از گره ریشه درخت،‌ کلید باید به شما نشان دهد که کدام گره فرزند را باید دنبال کنید تا مقدار مورد نظر خود را که در گره‌های برگ ذخیره شده پیدا کنید. در اتریوم، نگاشت کلید/مقداری درخت حالت، نگاشتی از آدرس‌ها به حساب‌های مرتبط به آن‌هاست و حساب‌ها همانطور که گفتیم حاوی موجودی، nonce، codeHash و storageRoot هستند (storageRoot خود یک درخت است). Source: Ethereum whitepaper برای ذخیره تراکنش‌ها و رسید‌ تراکنش‌ها (transaction receipts) از ساختار درختی مشابهی استفاده می‌شود. مشخصاً هر بلوک یک header دارد که هش گره ریشه سه درخت مرکل در آن ذخیره می‌شود:درخت حالت (State trie)درخت تراکنش‌هادرخت رسیدهادر اتریوم قابلیت ذخیره همه این اطلاعات در درخت‌های مرکل برای داشتن آنچه light node یا light client خوانده می‌شود بسیار مفید است. به خاطر دارید که یک زنجیره‌بلوک توسط تعدادی node نگهداری می‌شود. به طور کلی دو نوع node وجود دارد: full node و light node.یک full node برای sync شدن با شبکه زنجیره‌بلوک تمام زنجیره را از genesis block تا آخرین بلوک دانلود می‌کند، و ضمناً تمام تراکنش‌های موجود در بلاک‌ها را یک به یک اجرا می‌کند. البته داشتن full node ای که همه‌ تراکنش‌ها را اجرا نکند امکان‌پذیر است، اما در هر صورت یک full node تمام [اطلاعات] زنجیره را ذخیره می‌کند. معمولاً ماینرها از full node استفاده می‌کنند زیرا برای انجام فرایند ماینینگ، داشتن full node ضروری است.اما اگر node نیاز به اجرای تمام تراکنش‌ها یا جستجو در داده‌های قبلی نداشته باشد، نیازی به ذخیره همه زنجیره روی node نیست. light node ها به جای دانلود و ذخیره کردن تمام زنجیره و اجرای همه تراکنش‌ها، تنها زنجیره‌ای از header بلوک‌ها از genesis block تا آخرین بلوک را دانلود می‌کنند (درباره ساختار بلوک در ادامه توضیح می‌دهیم)، بدون آن که همه تراکنش‌ها را اجرا کنند یا حالت مرتبط با آن‌ها را بازیابی کنند. light node ها به header بلوک‌ها دسترسی دارند و header حاوی هش سه درخت حالت، تراکنش‌ها و رسید‌ها است، به همین دلیل آن‌ها هم (مانند full node ها) می‌توانند تراکنش ایجاد کنند و پاسخ‌های معتبر درباره تراکنش‌ها، event های شبکه،‌ موجودی حساب‌ها و غیره دریافت کنند.این امکان با استفاده از درخت مرکل فراهم شده است. هش‌ها در درخت مرکل از پایین به بالا منتشر (propagate) می‌شوند - اگر یک کاربر خرابکار تلاش کند تا یک تراکنش جعلی را در یک گره برگ در پایین درخت مرکل جا بزند، این تغییر موجب تغییر مقدار هش گره بالای آن خواهد شد، و تغییر همین‌طور تا بالا (تا ریشه درخت) ادامه پیدا می‌کند.هر node ای که بخواهد یک بخش از داده‌های ذخیره شده در state را اعتبارسنجی کند، می‌تواند از مکانیسمی به نام Merkle Proof استفاده کند. یک Merkle Proof تشکیل شده از:یک تکه (chunk) از داده که قرار است اعتبارسنجی شود و هش آنهش ریشه درختشاخه (همه هش‌های والد در مسیر گره حاوی chunk تا ریشه)هر کسی با استفاده از Merkle Proof می‌تواند مطمئن شود که عمل هش کردن در تمام مسیر از پایین تا بالای درخت به درستی انجام شده، و در نتیجه می‌تواند مطمئن شود که تکه داده مورد بررسی دقیقاً در همان موقعیت در درخت قرار دارد. به طور خلاصه مزیت استفاده از یک Merkle Patricia tree این است که گره ریشه این ساختار با استفاده از رمزنگاری به تمام اطلاعات ذخیره شده در درخت وابسته شده، و به همین دلیل هش ریشه می‌تواند به عنوان یک شناسه امن برای تمام اطلاعات ذخیره شده روی درخت به کار رود. چون header بلوک حاوی هش ریشه سه درخت حالت، تراکنش‌ها و رسید‌هاست، هر node می‌تواند بخش کوچک و دلخواهی از حالت شبکه اتریوم را بدون نیاز به ذخیره کردن کل حالت اعتبارسنجی کند. پرداخت و Gasیکی از مفاهیم بسیار مهم در اتریوم مفهوم کارمزد است. برای هر پردازشی که در نتیجه یک تراکنش در شبکه اتریوم انجام می‌گیرد باید کارمزد پرداخت شود- از ناهار مجانی خبری نیست! این کارمزد با واحد پولی به نام Gas پرداخت می‌شود. ـ Gas واحدی است که برای اندازه‌گیری کارمزدهایی که برای یک پردازش مشخص مورد نیاز است به کار می‌رود. قیمت Gas یا Gas Price مقدار اتری است که شما می‌خواهید به ازای هر واحد از Gas به عنوان کارمزد پرداخت کنید و بر حسب gwei اندازه‌گیری می‌شود. Wei کوچکترین واحد اتر است و هر ۱۰ به توان ۱۸ Wei معادل یک اتر است. هر gwei معادل ۱۰۰۰۰۰۰۰۰۰ (یک میلیارد) Wei است.در هنگام ارسال هر تراکنش، فرستنده تراکنش دو مقدار gas limit و gas price را تعیین می‌کند. حاصل‌ضرب gas price و gas limit معادل بیشترین مقدار Wei ای است که فرستنده می‌خواهد برای اجرای تراکنش بپردازد.برای مثال فرض کنیم که فرستنده gas limit را معادل ۵۰۰۰۰ و gas price را معادل ۲۰ gwei تعیین می‌کند. این دو عدد به این معنی است که بیشترین کارمزدی که فرستنده حاضر است برای اجرای این تراکنش بپردازد معادل ۵۰۰۰۰ ضربدر ۲۰ gwei برابر با ۱,۰۰۰,۰۰۰,۰۰۰,۰۰۰,۰۰۰ Wei یا ۰.۰۰۱ اتر است.به خاطر بیاورید که gas limit نشان‌دهنده بیشترین مقدار gas ای است که فرستنده حاضر است به عنوان کارمزد بپردازد. اگر فرستنده مقدار کافی اتر برای پرداخت این مقدار را در حساب خود داشته باشد، تراکنش ارسال می‌شود. در انتهای اجرای تراکنش، هر مقدار از gas که استفاده نشده باقی بماند با نرخ تبدیل یا همان gas price ای که فرستنده تعیین کرده است به اتر تبدیل می‌شود و به حساب فرستنده بازمی‌گردد.در صورتی که فرستنده در حساب خود مقدار کافی gas برای اجرای تراکنش را نداشته باشد، تراکنش به اصطلاح run out of gas می‌شود (gas تمام می‌کند) و نامعتبر محسوب می‌شود. در حین اجرای تراکنش در هر مرحله‌ای که gas تمام شود، پردازش تراکنش متوقف شده و هر تغییر حالتی (state change) که تا آن مرحله رخ داده باشد بازگردانی (revert) می‌شود. به علاوه، یک رکوردِ ناموفق شدن تراکنش ثبت می‌شود که نشان می‌دهد چه تراکنشی ارسال شده و در کدام مرحله fail شده است. از آنجا که دستگاه اجرای کننده تراکنش (میزبان node) تا قبل از تمام شدن gas منابع خود را صرف محاسبات و پردازش برای اجرای تراکنش کرده است، تمام gas به این node تعلق می‌گیرد و هیچ مقداری به فرستنده برگردانده نمی‌شود (برخلاف حالت قبل). پول gas دقیقاً به چه کسی می‌رسد؟ تمام پولی که توسط فرستنده تراکنش صرف gas شده به «آدرس ذینفع» ارسال می‌شود، که معمولاً همان آدرس ماینر است. از آنجا که ماینرها توان پردازشی خود را صرف محاسبات و اعتبارسنجی تراکنش‌ها می‌کنند، کارمزدها به عنوان جایزه به آنها پرداخت می‌شود.معمولاً هر چه فرستنده gas price را بالاتر ببرد، ارزشی که ماینر از پردازش تراکنش دریافت می‌کند بیشتر است. به همین دلیل ماینرها به پردازش تراکنش‌هایی که gas price بالاتر دارند تمایل بیشتری دارند. به این ترتیب، ماینرها در انتخاب این که چه تراکنشی را اعتبارسنجی کنند و چه تراکنشی را نادیده بگیرند آزاد هستند. به منظور راهنمایی فرستنده‌ها در تعیین gas price، ماینرها امکان این را دارند که کمترین مقدار gas price ای را که برای اجرای تراکنش می‌پذیرند در شبکه اعلان کنند.استفاده از حافظه هم کارمزد دارد ـ gas فقط برای اجرای مراحل محاسباتی خرج نمی‌شود، بلکه برای استفاده از حافظه شبکه نیز باید کارمزد پرداخت شود. مجموع کارمزدی که برای حافظه پرداخت می‌شود متناسب است با کوچکترین مضربی از ۳۲ بایت در مقدار حافظه‌ای که در عملیات مورد استفاده قرار می‌گیرد.کارمزد حافظه جنبه‌های ظریفی دارد. برای مثال، از آنجا که افزایش اندازه حافظه موجب افزایش اندازه دیتابیس حالت اتریوم روی همه نودها می‌شود، توصیه می‌شود که مقدار داده‌ای که ذخیره می‌شود کوچک باشد. به همین دلیل اگر یک تراکنش در یک مرحله از اجرا یک رکورد ثبت شده در حافظه را پاک کند، کارمزد اجرای آن عملیات دریافت نمی‌شود و حساب فرستنده به خاطر آزاد کردن مقداری از حافظه مبلغی را به عنوان جایزه دریافت می‌کند.فایده کارمزد چیست؟یک جنبه مهم نحوه کار اتریوم این است که هر تک عملیاتی که توسط شبکه اجرا می‌شود به طور همزمان توسط تمام full node ها اجرا می‌شود. با این حال، مراحل محاسباتی در EVM بسیار پرهزینه هستند. بنابراین قراردادهای هوشمند اتریوم بهتر است که برای وظایف ساده مانند اجرای منطق ساده کسب‌و‌کار (business logic) یا تایید signature ها و دیگر اشیاء رمزنگاری‌شده استفاده شود. استفاده از قرارداد هوشمند برای عملیاتی مانند ذخیره فایل یا پیاده‌سازی الگوریتم‌های یادگیری ماشین به شبکه آسیب وارد می‌کند. اعمال کارمزد، مانع از از تحمیل عملیات سنگین و آسیب‌زا به شبکه توسط کاربران می‌شود.اتریوم یک ماشین تورینگ کامل است (به طور خلاصه ماشین تورینگ کامل ماشینی است که می‌تواند هر نوع الگوریتم کامپیوتری را شبیه‌سازی کند، برای اطلاعات بیشتر در مورد ماشین‌های تورینگ اینجا و اینجا را ببینید). این یعنی نوشتن حلقه (loop) در قراردادهای هوشمند امکان‌پذیر است و همین شبکه اتریوم را در برابر مسئله توقف (Halting Problem) آسیب‌پذیر می‌کند. در مسئله توقف شما نمی‌توانید تعیین کنید که آیا یک برنامه بدون توقف و تا ابد اجرا می‌شود یا بالاخره در نقطه‌ای اجرای برنامه پایان می‌یابد (یک حلقه بی‌نهایت را در نظر بگیرید). اگر کارمزد وجود نداشت یک عامل خرابکار به راحتی می‌توانست با اجرا کردن یک حلقه بی‌نهایت در یک تراکنش، بدون هیچ مانعی شبکه را مختل کند. بنابراین کارمزدها از شبکه در مقابل حملات عمدی محافظت می‌کنند.ممکن است فکر کنید "چرا باید برای استفاده از حافظه هم کارمزد پرداخت کرد"؟ حافظه هم مانند عملیات محاسباتی هزینه‌ای است که تمام شبکه باید آن را پرداخت کند (نوشتن روی حافظه، حجم دیتابیس node ها را افزایش می‌دهد).