EIP-150 در اتریوم چیست؟ نگاهی به قانون گس 64/63

پیشنهاد بهبود اتریوم شماره 150 یا همان EIP-150 یکی از ارتقاءهای مهم پروتکل بلاکچین اتریوم محسوب می‌شود. این پیشنهاد در تاریخ 18 مارس 2016 ارائه شد و نهایتاً در 20 ژوئیه 2016 به‌عنوان بخشی از هاردفورک Byzantium پیاده سازی گردید. این ارتقاء شامل چندین تغییر مهم بود، اما در این مقاله تمرکز اصلی ما روی قانون 63/64 است که در همین به‌روزرسانی معرفی شد.

پیش از آنکه وارد جزئیات EIP-150 شویم، لازم است ابتدا مفهوم گس (Gas) و فراخوانی قراردادها در اتریوم را بشناسیم.

مفهوم Gas در اتریوم

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

هر عملیات یا اجرای یک قرارداد در EVM نیاز به مقدار مشخصی گس دارد که باید توسط کاربر و به‌صورت اتر (Ether) پرداخت شود. زمانی که کاربر یک تراکنش را ارسال می‌کند، موظف است تمام هزینه‌های ناشی از عملیات‌های مختلف آن تراکنش را پوشش دهد. این موضوع یکی از مفاهیم کلیدی در برنامه نویسی قراردادهای هوشمند محسوب می‌شود، به‌ویژه زمانی که توسعه دهندگان قصد دارند عملیات بهینه ای طراحی کنند.

برای مثال، یک انتقال ساده اتر در شبکه اتریوم، دقیقاً 21,000 گس مصرف می‌کند؛ اما اگر عملیات پیچیده‌تری انجام شود، این عدد می‌تواند تا چندین میلیون گس افزایش یابد.

فراخوانی قراردادها (Contract Calls)

در اتریوم، یک قرارداد هوشمند (که به آن caller یا فراخواننده گفته می‌شود) می‌تواند قراردادهای دیگر را (که به آن‌ها callee یا فراخوان‌شونده گفته می‌شود) از طریق اپ‌کدهای خاصی مانند CALL، STATICCALL و DELEGATECALL فراخوانی کند.

زمانی که چنین فراخوانی انجام شود، قرارداد فراخوان‌شونده مقدار مشخصی گس دریافت می‌کند، مشابه زمانی که مستقیماً از طریق یک تراکنش توسط کاربر فراخوانی می‌شود.

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

اگر قرارداد فراخوان‌شونده گس کافی دریافت نکند، اجرای آن متوقف شده و تمام عملیات انجام‌شده لغو می‌شود، که این وضعیت باعث ایجاد خطای “Out of Gas” می‌گردد.

مشخصات فنی EIP-150

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

این ویژگی در عمل می‌توانست منجر به بروز مشکل “Stack Too Deep” در پیاده سازی نودهای اتریوم شود. برای جلوگیری از چنین وضعیتی، توسعه دهندگان پروتکل، عمق مجاز برای فراخوانی تو در توی قراردادها را به 1024 سطح محدود کردند — این محدودیت هنوز هم در نسخه‌های فعلی اتریوم برقرار است. اگر یک فراخوانی به سطح 1024 برسد، آن فراخوانی به‌طور خودکار revert می‌شود و عملیات لغو می‌گردد.

اما این محدودیت خودش یک آسیب‌پذیری جدید به‌وجود آورد. امضاکنندگان تراکنش می‌توانستند با ایجاد زنجیره‌ای از 1023 فراخوانی متوالی، عمداً عمق استک را پر کنند و سپس قرارداد هدف را فراخوانی کنند. در این حالت، فراخوانی نهایی به دلیل رسیدن به محدودیت عمق، به‌صورت تضمینی شکست می‌خورد و revert می‌شد. به این نوع حمله، “حمله عمق فراخوانی” (Call Depth Attack) گفته می‌شود.

در ادامه، مثالی از یک قرارداد هوشمند آورده شده که نسبت به این حمله آسیب‌پذیر است:

پیش از پیاده سازی EIP-150، قرارداد بالا در برابر «حمله عمق فراخوانی» آسیب‌پذیر بود. علت این آسیب‌پذیری این بود که یک شرکت‌کننده مخرب در مزایده می‌توانست یک فراخوانی بازگشتی (Recursive Call) به خود انجام دهد، و با این کار عمق استک را به 1023 برساند. سپس، تابع bid() را فراخوانی می‌کرد. در این حالت، فراخوانی send(highestBid) که برای بازپرداخت به مزایده‌گذار قبلی انجام می‌شود، بی‌سروصدا شکست می‌خورد، چون دیگر عمق استک اجازه اجرای آن را نمی‌داد. نتیجه این بود که مزایده‌گذار قبلی پول خود را پس نمی‌گرفت، اما فرد مهاجم همچنان به‌عنوان بالاترین مزایده‌گذار ثبت می‌شد.

راه‌حل ارائه‌شده در EIP-150

برای مقابله با این نوع حمله، در EIP-150 قانونی معرفی شد که براساس آن، قرارداد فراخواننده باید بخشی از گس در دسترس را برای خودش نگه دارد و اجازه ندارد تمام گس را به قرارداد فراخوان‌شونده منتقل کند. این قانون به‌صورت دقیق بیان می‌کند که قرارداد فراخواننده نمی‌تواند بیش از 63/64 گس در دسترس را در یک فراخوانی مصرف کند.

فرمول گس رزروشده برای قرارداد فراخواننده:

بیایید این فرمول را با یک مثال ساده بررسی کنیم:

فرض کنید مقدار گس در دسترس در عمق 0 برابر 1000 واحد باشد.

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

قانون 64/63: میزان گسی که به قرارداد فراخوان‌شونده می‌رسد

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

مثال عددی:

فرض کنیم گس اولیه برابر 3000 واحد باشد.

  • گس در عمق استک 10:
    3000 × (63/64)^10 ≈ 2562

  • گس در عمق استک 20:
    3000 × (63/64)^20 ≈ 2189

eip 150 گس اتریوم در زمان فراخوانی پشته

به دلیل کاهش سریع مقدار گس در هر سطح جدید از عمق استک، عمق بازگشتی (recursive depth) در اتریوم به‌طور طبیعی محدود می‌شود. اگرچه محدودیت عمق استک تا 1024 سطح همچنان در پیاده سازی فعلی اتریوم اعمال می‌شود، اما در عمل دستیابی به این عمق تقریباً ناممکن است؛ زیرا با افزایش هر سطح، گس به‌شدت کاهش می‌یابد و امکان فراخوانی در سطوح بالاتر از بین می‌رود.

علاوه‌بر قانون 64/63 که پیش‌تر توضیح داده شد، EIP-150 یک تغییر مهم دیگر هم در رفتار اپ‌کدهای CALL* ایجاد کرد.

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

اما پس از EIP-150، این رفتار تغییر کرد. اکنون، مقدار گسی که در اپ‌کد تعیین می‌شود، حداکثر مقدار مجاز تلقی می‌شود، نه یک مقدار قطعی. بنابراین، اگر در لحظه اجرا قرارداد فراخوان‌شونده (callee) گس کمتری در اختیار داشته باشد، فراخوانی همچنان انجام می‌شود. اما با همان مقدار محدود موجود، نه اینکه به‌دلیل کمبود گس متوقف شود.

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

جمع بندی

در یک نگاه کلی، EIP-150 با هدف جلوگیری از حمله عمق فراخوانی (Call Depth Attack) معرفی شد. این حمله می‌توانست با پر کردن بیش از حد عمق استک، باعث شود فراخوانی‌های حیاتی در یک قرارداد شکست بخورند.

برای مقابله با این مشکل، EIP-150 قانون 64/63 را به‌عنوان یک قاعده اجباری اعمال کرد.

بر اساس این قانون، حتی اگر در یک فراخوانی مقدار باقی‌مانده گس به‌صورت کامل به قرارداد مقصد ارسال شود، همچنان بخشی از گس (دقیقاً 1/64 آن) برای قرارداد فراخواننده رزرو می‌شود و قابل مصرف توسط قرارداد فراخوان‌شونده نیست.

در نتیجه، این محدودیت باعث شد که دیگر نتوان با زنجیره‌ای از فراخوانی‌های بازگشتی، عمق استک را تا حد بحرانی پر کرد و جلوی اجرای صحیح قراردادها را گرفت. این تغییر، یک لایه محافظتی مؤثر و سبک‌وزن برای امنیت ساختاری در ماشین مجازی اتریوم (EVM) فراهم کرد.

4.7/5 - (3 امتیاز)

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

دوره آموزش برنامه نویسی پایتون در 24 ساعت + ساخت ربات تلگرامی
  • انتشار: ۵ مرداد ۱۴۰۴

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

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

مشاهده همه

نظرات

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