عبارت nodelegatecall در سالیدیتی یک modifier است که جلوی اجرای توابع از طریق delegatecall را میگیرد. ابتدا سازوکار پیاده سازی این ویژگی را توضیح میدهیم، و سپس دلایل استفاده از آن را بررسی خواهیم کرد.
در ادامه، نسخه سادهشدهای از nodelegatecall
را میبینید که در ابتدا توسط نسخه سوم یونی سواپ (Uniswap V3) با عنوان noDelegateCall
معرفی شده بود:
1 2 3 4 5 6 7 8 9 10 11 12 |
contract NoDelegateCallExample { address immutable private originalAddress; constructor() { originalAddress = address(this); } modifier noDelegateCall() { require(address(this) == originalAddress, "no delegate call"); _; } } |
در این کد، مقدار address(this)
بستگی به محیط اجرایی دارد؛ اما متغیر originalAddress
همیشه برابر است با آدرس اصلی قراردادی که مستقیماً مستقر شده و noDelegateCall
را استفاده میکند. بنابراین اگر یک قرارداد دیگر، تابعی را که این modifier دارد از طریق delegatecall
اجرا کند، آدرس جاری address(this)
با originalAddress
یکسان نخواهد بود و در نتیجه تراکنش با خطا مواجه شده و متوقف میشود.
نکته بسیار مهم این است که originalAddress
حتماً باید بهصورت immutable
تعریف شود. اگر این متغیر قابل تغییر باشد، ممکن است قرارداد مهاجم بتواند بهصورت عمدی آدرس قرارداد اصلی را در آن جایگذاری کند و شرط require
را دور بزند. بنابراین، استفاده از متغیر غیرقابلتغییر یک اقدام امنیتی حیاتی برای جلوگیری از حملات delegatecall
است.
بررسی و تست عملکرد nodelegatecall در سالیدیتی
در ادامه، کدی را میبینید که عملکرد nodelegatecall
را تست میکند:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
contract NoDelegateCall { address immutable private originalAddress; constructor() { originalAddress = address(this); } modifier noDelegateCall() { require(address(this) == originalAddress, "no delegate call"); _; } } contract A is NoDelegateCall { uint256 public x; function increment() noDelegateCall public { x++; } } contract B { uint256 public x; // this variable does not increment function tryDelegatecall(address a) external { (bool ok, ) = a.delegatecall( abi.encodeWithSignature("increment()") );// ignore ok } } |
در این مثال، قرارداد B
تلاش میکند تا از طریق delegatecall
تابع increment
را از قرارداد A
فراخوانی کند. این تابع از modifier noDelegateCall
استفاده میکند تا جلوی چنین فراخوانیهایی را بگیرد. اگرچه tryDelegatecall
در قرارداد B
با خطا مواجه نمیشود، چون خروجی delegatecall
نادیده گرفته شده، اما در عمل مقدار x
در قرارداد B
هیچ تغییری نمیکند. این مثال ساده نشان میدهد که در دنیای برنامه نویسی قراردادهای هوشمند، نحوه مدیریت delegatecall نقش مهمی در حفظ امنیت داده ها دارد.
دلیل این موضوع آن است که شرط require
در داخل تابع increment
برقرار نمیشود و باعث میشود تراکنش در بستر delegatecall
لغو شود. بنابراین، حتی اگر ظاهر ماجرا نشان دهد که خطایی رخ نداده، تغییر در وضعیت قرارداد اتفاق نمیافتد و مقدار x
ثابت باقی میماند.
انگیزه استفاده از nodelegatecall در سالیدیتی
یونی سواپ نسخه ۲ (Uniswap V2) یکی از پراستفادهترین و پرانشعابترین پروتکلهای دیفای (DeFi) در تاریخ بلاکچین محسوب میشود. پس از انتشار این نسخه، بسیاری از پروژهها بدون هیچ تغییری، کد منبع یونی سواپ V2 را خط به خط کپی کردند و محصول جدید خود را بهعنوان جایگزینی برای یونی سواپ معرفی نمودند. برخی پروژهها با ارائه ایردراپ، کاربران را به استفاده از نسخه کپیشده تشویق میکردند.
برای جلوگیری از تکرار این اتفاق، تیم یونیسواپ نسخه ۳ را تحت مجوز خاصی به نام Business Source License منتشر کرد. طبق این مجوز، هر فرد یا پروژهای میتواند کد را مشاهده و کپی کند، اما حق استفاده تجاری از آن تا قبل از پایان اعتبار مجوز در آوریل ۲۰۲۳ را ندارد.
با این حال، حتی با وجود این محدودیت، یک توسعه دهنده میتوانست با ایجاد یک پراکسی کلون (clone proxy)، قرارداد خود را به یکی از نسخه های مستقر یونیسواپ V3 متصل کند و آن را بهعنوان یک جایگزین برای یونیسواپ V3 معرفی کند، بدون آنکه قوانین مجوز را مستقیماً نقض کند.
در چنین شرایطی، استفاده از مقدارکننده nodelegatecall
راهحلی مؤثر محسوب میشود. این ویژگی مانع از آن میشود که قراردادهای دیگر بتوانند از طریق delegatecall به توابع حیاتی پروتکل دسترسی پیدا کنند. در نتیجه، تیم یونیسواپ توانست با استفاده از این تکنیک از سوءاستفادههایی که حتی با وجود محدودیتهای مجوزی ممکن بود رخ دهد، جلوگیری کند.
راستی! برای دریافت مطالب جدید در کانال تلگرام یا پیج اینستاگرام سورس باران عضو شوید.
- انتشار: ۱۹ تیر ۱۴۰۴
دسته بندی موضوعات
- آموزش ارز دیجیتال
- آموزش برنامه نویسی
- آموزش متنی برنامه نویسی
- اطلاعیه و سایر مطالب
- پروژه برنامه نویسی
- دوره های تخصصی برنامه نویسی
- رپورتاژ
- فیلم های آموزشی
- ++C
- ADO.NET
- Adobe Flash
- Ajax
- AngularJS
- apache
- ARM
- Asp.Net
- ASP.NET MVC
- AVR
- Bootstrap
- CCNA
- CCNP
- CMD
- CSS
- Dreameaver
- EntityFramework
- HTML
- IOS
- jquery
- Linq
- Mysql
- Oracle
- PHP
- PHPMyAdmin
- Rational Rose
- silver light
- SQL Server
- Stimulsoft Reports
- Telerik
- UML
- VB.NET&VB6
- WPF
- Xml
- آموزش های پروژه محور
- اتوکد
- الگوریتم تقریبی
- امنیت
- اندروید
- اندروید استودیو
- بک ترک
- بیسیک فور اندروید
- پایتون
- جاوا
- جاوا اسکریپت
- جوملا
- دلفی
- دوره آموزش Go
- دوره های رایگان پیشنهادی
- زامارین
- سئو
- ساخت CMS
- سی شارپ
- شبکه و مجازی سازی
- طراحی الگوریتم
- طراحی بازی
- طراحی وب
- فتوشاپ
- فریم ورک codeigniter
- فلاتر
- کانستراکت
- کریستال ریپورت
- لاراول
- معماری کامپیوتر
- مهندسی اینترنت
- هوش مصنوعی
- یونیتی
- کتاب های آموزشی
- Android
- ASP.NET
- AVR
- LINQ
- php
- Workflow
- اچ تی ام ال
- بانک اطلاعاتی
- برنامه نویسی سوکت
- برنامه نویسی موبایل
- پاسکال
- پایان نامه
- پایتون
- جاوا
- جاوا اسکریپت
- جی کوئری
- داده کاوی
- دلفی
- رباتیک
- سئو
- سایر کتاب ها
- سخت افزار
- سی اس اس
- سی پلاس پلاس
- سی شارپ
- طراحی الگوریتم
- فتوشاپ
- مقاله
- مهندسی نرم افزار
- هک و امنیت
- هوش مصنوعی
- ویژوال بیسیک
- نرم افزار و ابزار برنامه نویسی
- وردپرس