یکی از ویژگیهای قراردادهای هوشمند تغییر ناپذیر بودن آن است. همین ویژگی باعث شده تا مردم به این قراردادها اعتماد داشته باشند. اما گاهی همین تغییر ناپذیر بودن قراردادهای هوشمند شبکه اتریوم مسئله ساز شده است. به علاوه، اگر برنامهریزی مناسبی برای رفع آن در این شبکه وجود نداشته باشد، برای انتقال به شبکه دیگر با هزینه چشمگیری مواجه خواهیم بود. بنابراین، این موضوع باید در طراحی محصولهای مبتنی بر قرارداد هوشمند اتریوم مدنظر قرار بگیرد و سپس با بررسی جوانب احتیاط پیادهسازی و اجرا شود. امنیت و تکامل موارد بسیار مهمی هستند، مخصوصا هنگامی که بحث سرمایه مردم و کاربران در میان باشد.
هدف این مقاله، بررسی ارتباط و تاثیر تغییر ناپذیری در مدلهای تجاری مختلف نیست، بلکه در این مقاله، به جوانب فنی این موضوع میپردازیم. از آنجایی که ابزار توسعه استانداردی برای جلوگیری از بروز اشتباهات یا تشخیص زود هنگام رویدادهای مختلف وجود ندارد، این مسأله باعث محدودیت توانایی و قابلیت برنامهنویسان قراردادهای هوشمند در توسعه برنامههای خود شده است.
هرچند، روشها و الگوهای ابتکاری و اکتشافی جدیدی نظیر از بین بردن قرارداد یا در اختیار داشتن تصدی آدرس برای خروج سرمایه در مواقع اضطراری برای توسعه ایمنتر مورد استفاده قرار میگیرد. در خصوص تغییر ناپذیری قابل بهروزرسانی، یک الگو و پارادایم رایج وجود دارد: قراردادهای پروکسی (proxy contract).
تغییر ناپذیر بودن قرارداد هوشمند
اگرچه بهروزرسانی کد قرارداد هوشمندی که اجرا شده است امکانپذیر نیست، اما میتوان ساختار قرارداد واسطهای ایجاد کرد که استفاده از قراردادهای جدید را امکانپذیر خواهد ساخت، به طوری که به نظر میرسد منطق اصلی قرارداد بهروزرسانی شده است. در ادامه به بررسی معتبرترین پروپوزالهای مرتبط با قراردادهای قابل بهروزرسانی میپردازیم.
آپکد (opcode) یا همان کد عملیاتی delegatecall در سالیدیتی به قرارداد امکان میدهد تا تابعی را از یک قرارداد دیگر اجرا کند، اما نحوه اجرای آن به صورتی است که انگار تابع مورد نظر از قرارداد فراخوانی (calling) میشود. Delegatecall به قراردادهای هوشمند این امکان را میدهد که تابع قرارداد دیگری را قرض بگیرد. توابعی که با delegatecall اجرا میشوند به جای قراردادهایی که توابع در آنها تعریف شدهاند، بر متغیرهای ذخیرهسازی قرارداد فراخوانی تاثیرگذار هستند.
پروپوزالهای بهبود اتریوم
توسعه و بهبود شبکه اتریوم به عهده توسعهدهندگان و برنامهنویسان این شبکه است. فرد یا گروه خاصی مسئول این کار نیست بلکه جامعه اتریوم به دنبال بهبود این شبکه بلاک چین هستند. از این رو طرحهای پیسنهادی یا پروپوزالهایی برای بهبود عملکرد این شبکه ارائه میشود. این طرحها توسط تمام افراد مطالعه شده و مورد بررسی قرار میگیرد. در صورت توافق همه اعضا، این پروپوزال به بروز رسانی این شبکه منجر خواهد شد. در زمینه مورد بحث ما در این مقاله نیز پروپوزالهایی ارائه شده که در ادامه آنها را معرفی میکنیم.
پروپوزال EIP 1538
این پروپوزال شامل سیستم کنترلی است که تغییرات قرارداد طی رویدادهای استاندارد را برای امکان رصد و پیگیری، به طوری عمومی ثبت میکند. این پروپوزال همچنین از حجم ذخیرهسازی نامحدود، بهروزرسانیهای اتمی و رابط کاربری استاندارد برای فراخوانیهای خارجی پشتیبانی میکند.
این پروپوزال بیانگر نقاط مثبت و منفی و مقایسه قرارداد شفاف بدون نیاز به اعتماد و تغییرناپذیر با قراردادهای وکالتی مبهم و قابل بهروزرسانی است. از جمله ویژگیهای این پروپوزال میتوان به موارد زیر اشاره کرد:
- قرارداد شفاف شامل fallback است که با استفاده از آپکد delegatecall، فراخوانی توابع را به قرارداد وکالتی ارسال میکند. این قرارداد همچنین در صورت نیاز از سایر توابع تغییرناپذیر نیز پشتیبانی میکند.
- قراردادهای وکالتی با ارائه آدرس جدید به تابع updateContract قابل تغییر است. هرچند، کاربران فقط میتوانند با آدرسهای ثابت تعامل برقرار کنند.
- قرارداد استاندارد باید دارای مکانیزم تایید باشد تا بهروزرسانیهای وکالتی را از قرارداد شفاف امکانپذیر سازد.
- هر بهروزرسانی در تابع، به حذف رویدادهای CommitMessage و FunctionUpdate میپردازد تا تغییرات را ثبت کند.
- با توجه به فهرست امضاهای توابع، میتوان چندین بهروزرسانی را یکباره و با هم اجرا کرد.
- هر زمان که تابع updateContract از قرارداد وکالتی تازه اجرا شده حذف شود، تغییرپذیری غیرفعال میشود.
پروپوزال EIP 2535
این پروپوزال که به اسم استاندارد دایموند (Diamond Standard) نیز شناخته میشود، به عنوان جانشین EIP 1538 یک طراحی ماژولار برای توسعههای مختلف قراردادهای هوشمند ارائه میدهد، از بهروزرسانیهای کامل و جزیی پشتیبانی میکند، بر اساس قرارداد دایموند و چندین فاست مختلف است. دایموند، قراردادی است که توابع خارجی را به فاستها متصل میکند. فاستها، قراردادهای مجزایی هستند که توابع خارجی را ارائه میدهند.
توضیحات:
- هربار که تابع خارجی فراخوانی شود، دایموند به اجرای fallback خود میپردازد. دایموند، آدرسهای فاست را از مپینگ selectorToFacet دریافت کرده و سپس delegatecall را اجرا میکند.
- بهروزرسانیهای فاست از طریق فراخوانی تابع DiamondCut انجام میشوند و به آدرس فاست و انتخاب کننده آن یک عملکرد اضافی (افزودن، جایگزین کردن یا حذف کردن) میدهد تا عملکرد تابع ادامه یابد. به علاوه، برای ثبت تغییرات جدید، رویدادی حذف شده است.
- متغیرهای وضعیت فاست باید در اسلات ذخیرهسازی ایستا (static) باقی بمانند.
- ذخیرهسازی دایموند، روشی برای کنترل محدوده عملکرد متغیرهای وضعیت در بین فاستهای مختلف است.
- فاستها همچنین میتوانند هنگامی که با توابع داخلی در یک قرارداد یا کتابخانه قرار دارند، آنها را به اشتراک بگذارند.
- از فاستها میتوان مجددا استفاده کرد و توسط چند دایموند به اشتراکگذاری آنها پرداخت.
- هر دایموند دارای یک فاست لوپ (Loop) است که شامل چهار تابع استاندارد خارجی برای نمایش تمام فاستها و توابع آنها است.
پروپوزال EIP 1822
این استاندارد کاملا ساده است و متکی به قرارداد پروکسی به منظور کنترل و مدیریت بهروزرسانیها و انجام بررسی تطابق پذیری و امکان پشتیبانی از نسخههای قبلی است. قرارداد پروکسی همچنین دارای یک اسلات ذخیرهسازی منحصربهفرد است که به آدرس قرارداد منطقی جدید ارجاع دارد. این استاندارد، بررسی بایت کد قرارداد پروکسی را نیز امکانپذیر میسازد.
توضیحات:
- آدرس قرارداد منطقی در اسلات حافظه ثابت در قرارداد پروکسی قرار دارد: آدرس اسلاتkeccak256(“PROXIABLE”)
- تمام قراردادهای منطقی بعد از آن باید در قرارداد پروکسی استاندارد وجود داشته باشند.
- قرارداد پروکسی شامل تابع updateCodeAddress برای اجرای بهروزرسانیها است.
- بررسی تطابقپذیری قبل از بهروزرسانی انجام میشود تا اطمینان حاصل شود که قرارداد منطقی مطابق با استاندارد پروکسی قابل بهروزرسانی است.
- ترتیب متغیرها در قراردادهای منطقی بعدی برای جلوگیری از بازنویسی مقادیر موجود در پروکسی بسیار مهم است. توصیه میشود که از قرارداد پایه و مبنا برای این کار استفاده شود که تمام قراردادهای جدید را شامل شود.
- معمولا قراردادهای Owner و LibraryLock در امتداد قرارداد منطقی اجرا میشود تا دسترسیها را کنترل کند و از اجرای توابع آسیبرسان جلوگیری کند.
- قرارداد پروکسی از چندین کانستراکتور موجود در قرارداد منطقی پشتیبانی میکند و اطلاعات دلخواه در کانستراکتور خود را نیز میپذیرد.
پروپوزال EIP 1155
این استاندارد که نمای کلی از انواع مختلف توکنها نظیر توکنهای قابل تعویض، تعویض ناپذیر و نیمه تعویضپذیر است را میتوان برای پشتیبانی از انواع جدید توکنها تغییر داد و مجددا تنظیم کرد. این استاندارد همچنین اقدامات اتمی در بین انواع مختلف توکنها را امکانپذیر میسازد.
توضیحات:
- هر توکن یک ID منحصربهفرد دارد.
- قرارداد باید قبل از بررسی آدرس مقصد، تابع ERC-165 supportsInterface را اجرا کند.
- هر تابع در قرارداد، یک پارامتر ID را میپذیرد تا درخواست را به توکن ارسال کند.
- پردازش چند عملیات در آن واحد را امکانپذیر میسازد.
کلام آخر
اگرچه این الگوها، مشکل تغییر ناپذیر بودن یک قرارداد هوشمند را برطرف میکنند اما همه آنها مبتنی بر رویکرد آپکد هستند. این رویکرد بر خوانایی کد تاثیرگذار است و در نتیجه کار را برای توسعهدهندگان دشوار میکند. بعضی از اتفاقات پرخطر نظیر هک شدن DAO به تغییرات اندک و سطح پایینی نیاز دارند. این موضوع، بر اعتمادپذیر بودن پروتکل تاثیر میگذارد. الگوهای دیگری به غیر از الگوی پروکسی وجود دارند که به جای رویکرد تفکیک منطق و ذخیرهسازی، بر قابلیت بهروزرسانی ساختار اطلاعات متکی هستند.