آزمایش قرارداد هوشمند
آخرین ویرایش: @mahdigachloo33(opens in a new tab), ۲۶ خرداد ۱۴۰۳
بلاک چین های عمومی مانند اتریوم تغییر ناپذیر هستند و تغییر کد قراردادهای هوشمند پس از استقرار را دشوار می کند. الگوهای ارتقای قرارداد برای انجام "ارتقای مجازی" وجود دارد، اما اجرای آنها دشوار است و نیاز به اجماع اجتماعی دارد. علاوه بر این، یک ارتقا فقط میتواند یک خطا را پس از کشف آن برطرف کند - اگر مهاجم ابتدا آسیبپذیری را کشف کند، قرارداد هوشمند شما در معرض خطر سوء استفاده قرار میگیرد. الگوهای ارتقای قرارداد برای انجام "ارتقای مجازی" وجود دارد، اما اجرای آنها دشوار است و نیاز به اجماع اجتماعی دارد. علاوه بر آن، بروزرسانی، فقط میتواند خطا راپس از کشف شدن آن تصحیح کند - اگر یک مهاجم، زودتر از تصحیح آن خطا، خطا را پیدا کند، قرارداد هوشمند مربوطه در معرض سوء استفاده واقع میشود.
به همین علت است که تست کردن قراردادهای هوشمند پیش از دیپلوی بر روی شبکه اصلی، به عنوان حداقل میزان رعایت ایمنی تلقی می شود. برای تست و ارزیابی میزان صحت کدهای قراردادهای هوشمند، تکنیک های مختلفی وجود دارد؛ این که انتخاب شما کدام تکنیک و به چه صورت باشد به نیازمندی و خواست خود شما بر میگردد. ضمناً، مجموعه های تستی که متشکل از ابزارها و نگرش های مختلف باشند به عنوان گزینه ای ایدهآل برای کشف و عیب یابی نواقص امنیتی کم اهمیت و پر اهمیت در کد کانترکت می باشند.
پیشنیازها
در این صفحه به بررسی چگونگه تست قراردادهای هوشمند پیش از دیپلوی روی شبکه اتریوم می پردازیم. فرض بر این است که با قراردادهای هوشمند آشنا هستید.
تست کردن قرارداد هوشمند چیست؟
تست کردن قرارداد هوشمند پروسه ای است که با استفاده از آن می توانیم از صحت عملکرد کد قرارداد هوشمند به نسبت نحوه عملکرد آن کد اطمینان حاصل کنیم. در زمانی که بخواهیم از قابل اطمینان بودن، قابل استفاده بودن، و ایمنی قرارداد هوشمند مطمئن شویم، تست کردن بسیار کاربردی و مفید است.
اگرچه که رویکردهای مختلفی وجود دارند، بیشتر روش های تست کردن مبنی بر اجرای یک قراردادهای هوشمند با نمونه کوچکی از داده هایی که انتظار اجرا شدن کدها با آن را داریم، میباشد. اگر کانترکت در ازای این داده های نمونه، جواب صحیح برگرداند، به معنای صحت عملکرد کد مربوطه است. بیشتر ابزارهای تست کردن، به منظور چک کردن تطابق نتایج حاصله با نتایج عملیاتی کانترکت، منابعی را به منظور نوشتن و اجرا کردن موارد تست(opens in a new tab) فراهم می کنند.
علت اهمیت تست قراردادهای هوشمند چیست؟
قراردادهای هوشمند به طور معمول حجم زیادی از دارایی های مالی را مدیریت میکنند، کوچکترین اشتباه برنامه نویسی می تواند باعث خسارت هنگفت به کاربران(opens in a new tab) شود. تست دقیق، می تواند در یافتن عیب ها و مشکلات کد یک قرارداد هوشمند در مراحل اولیه، و تصحیح آنها پیش از عرضه کانترکت مربوطه، به شما کمک کند.
اگرچه در صورتی که یک خطا یا باگ در قرارداد هوشمند کشف شود، امکان آپدیت و ارتقای آن وجود دارد، اما آپدیت کردن آن می تواند امری پیچیده بوده و در صورتی که به خطای مربوطه به درستی رسیدگی نشود، خود باعث خطاهای دیگر(opens in a new tab) شود. علاوه بر آن، بروزرسانی یک کانترکت ناقض اصل تغییرناپذیری بوده و مفروضات اعتمادی اضافه ای را بر کاربران تحمیل می کند. برعکس، یک برنامه جامع برای آزمایش و تست قرارداد شما خطرات امنیتی قرارداد هوشمند را کاهش میدهد و نیاز به انجام ارتقاء منطقی پیچیده پس از استقرار یا دپلوی را کاهش میدهد.
روشهای تست قراردادهای هوشمند
روشهای تست قراردادهای هوشمند اتریوم در دو دسته کلی قرار میگیرند: تست خودکار و تست دستی. تست خودکار و تست دستی مزایا و بخشهای منحصر به فردی را ارائه میدهند، اما میتوانید هر دو را برای ایجاد یک برنامه قوی برای تجزیه و تحلیل قراردادهای خود ترکیب کنید.
تست خودکار
تست خودکار از ابزارهایی استفاده میکند که به طور خودکار کد قراردادهای هوشمند را برای خطا در اجرا بررسی میکند. مزیت تست خودکار برای استفاده از اسکریپتها(opens in a new tab) برای راهنمایی ارزیابی عملکردهای قرارداد ناشی میشود. تست اسکریپتشده را میتوان برای اجرای مکرر با حداقل مداخله انسانی برنامهریزی کرد و تست خودکار را کارآمدتر از روشهای دستی برای تست کردن میکند.
تست خودکار به ویژه زمانی مفید است که تستها تکراری و وقت گیر باشند. انجام تست دستی دشوار است؛ مستعد خطای انسانی؛ یا شامل ارزیابی عملکردهای مهم قرارداد میشود. اما ابزارهای تست خودکار میتوانند اشکالاتی داشته باشند—ممکن است برخی از اشکالات را از دست بدهند و فضای مثبت کاذب(opens in a new tab) زیادی ایجاد کنند. از این رو، جفت کردن تست خودکار با تست دستی برای قراردادهای هوشمند ایدهآل است.
تست دستی
تست دستی به کمک انسان است و شامل اجرای هر یک از موارد تستی در مجموعه آزمایشی شما هنگام تجزیه و تحلیل صحت قراردادهای هوشمند است. این مورد برخلاف تست خودکار است که در آن میتوانید به طور همزمان چندین تست مجزا را روی یک قرارداد اجرا کرده و گزارشی دریافت کنید که تمام تستهای شکست خورده و قبولی را نشان میدهد.
تست دستی میتواند توسط یک فرد به دنبال یک برنامه آزمون کتبی که سناریوهای مختلف آزمون را پوشش میدهد، انجام شود. همچنین میتوانید چندین فرد یا گروه را به عنوان بخشی از تست دستی و تعامل با یک قرارداد هوشمند در یک دوره مشخص بخواهید. تستکنندگان رفتار واقعی قرارداد را با رفتار مورد انتظار مقایسه کرده و هر تفاوتی را بهعنوان یک اشکال یا باگ علامتگذاری میکنند.
تست دستی مؤثر به منابع قابلتوجهی (مهارت، زمان، پول و تلاش) نیاز دارد و ممکن است - به دلیل خطای انسانی - خطاهای خاصی را در حین اجرای تستها از دست داد. اما تست دستی نیز میتواند سودمند باشد - برای مثال، یک تستکننده انسانی (مثلاً یک حسابرس یا آدیتور) ممکن است از شهود برای تشخیص موارد که ابزار تست خودکار از دست میدهد استفاده کند.
تست خودکار برای قراردادهای هوشمند
تست واحد
تست واحد عملکردهای قرارداد را به طور جداگانه ارزیابی و بررسی کرده که هر جزء به درستی کار میکند. تستهای واحد مطلوب باید ساده، سریع اجرا شوند و ایده روشنی از اینکه در صورت شکست تستها چه اشتباهی رخ داده است، ارائه دهند.
تستهای واحد برای بررسی اینکه آیا توابع مقادیر مورد انتظار را برمیگردانند و اینکه ذخیرهسازی قرارداد بهدرستی پس از اجرای تابع بهروز شده است مفید هستند. علاوه بر این، اجرای تستهای واحد پس از ایجاد تغییرات در پایگاه کد قراردادها، تضمین میکند که افزودن منطق جدید باعث ایجاد خطا نمیشود. در زیر چند دستورالعمل برای اجرای تستهای واحد مؤثر آورده شده است:
راهنماهایی برای تست واحد قراردادهای هوشمند
1. منطق تجاری و گردش کار قراردادهای خود را درک کنید
قبل از نوشتن تستهای واحد، دانستن اینکه یک قرارداد هوشمند چه ویژگیهایی را ارائه میدهد و کاربران چگونه به آن عملکردها دسترسی خواهند داشت و از آنها استفاده میکنند، کمک میکند. این مورد به ویژه برای اجرای تستهای مسیر درست(opens in a new tab) مفید است که تعیین میکند آیا توابع در قرارداد، خروجی صحیح را برای ورودیهای معتبر کاربر برمیگردانند یا خیر. ما این مفهوم را با استفاده از این مثال (مختلف) از یک قرارداد مزایده(opens in a new tab) توضیح خواهیم داد.
1constructor(2 uint biddingTime,3 address payable beneficiaryAddress4 ) {5 beneficiary = beneficiaryAddress;6 auctionEndTime = block.timestamp + biddingTime;7 }89function bid() external payable {1011 if (block.timestamp > auctionEndTime)12 revert AuctionAlreadyEnded();1314 if (msg.value <= highestBid)15 revert BidNotHighEnough(highestBid);1617 if (highestBid != 0) {18 pendingReturns[highestBidder] += highestBid;19 }20 highestBidder = msg.sender;21 highestBid = msg.value;22 emit HighestBidIncreased(msg.sender, msg.value);23 }2425 function withdraw() external returns (bool) {26 uint amount = pendingReturns[msg.sender];27 if (amount > 0) {28 pendingReturns[msg.sender] = 0;2930 if (!payable(msg.sender).send(amount)) {31 pendingReturns[msg.sender] = amount;32 return false;33 }34 }35 return true;36 }3738function auctionEnd() external {39 if (block.timestamp < auctionEndTime)40 revert AuctionNotYetEnded();41 if (ended)42 revert AuctionEndAlreadyCalled();4344 ended = true;45 emit AuctionEnded(highestBidder, highestBid);4647 beneficiary.transfer(highestBid);48 }49}نمایش همه
این یک قرارداد مزایده ساده است که برای دریافت پیشنهادها در طول دوره مناقصه طراحی شده است. اگر این مورد highestBid
افزایش یابد، بالاترین پیشنهاد قبلی پول خود را دریافت میکند. پس از پایان دوره مناقصه، ذینفع
قرارداد را فراخوانی میکند تا پول خود را دریافت کند.
تستهای واحد برای قراردادی مانند این، عملکردهای مختلفی را که کاربر ممکن است هنگام تعامل با قرارداد فراخوانی کند، پوشش میدهد. یک مثال برای تست واحد این است که بررسی میکند آیا کاربر میتواند در حین انجام مزایده پیشنهادی ارائه دهد (یعنی تماسهای قیمتگذاری()
موفقیتآمیز است) یا آزمایشی که بررسی میکند آیا کاربر میتواند پیشنهاد بالاتری از پیشنهاد فعلی ارائه دهد یا خیر. highestBid
.
همچنین درک گردش کار عملیاتی قراردادها به نوشتن تستهای واحد کمک میکند تا بررسی کند که آیا اجرا با الزامات مطابقت دارد یا خیر. برای مثال، قرارداد مزایده مشخص میکند که کاربران نمیتوانند پس از پایان حراج، پیشنهاد بدهند (یعنی زمانی که زمان مزایده یا حراج تمام شود
کمتر از block.timestamp
است). بنابراین، یک توسعهدهنده ممکن است تست واحدی را اجرا کند که بررسی میکند آیا فراخوانیهای تابع bid()
موفق میشوند یا شکست میخورند پس از پایان حراج (یعنی وقتی auctionEndTime
> block.timestamp
).
2. کلیه مفروضات مربوط به اجرای قرارداد را ارزیابی کنید
ثبت هرگونه فرضی در مورد اجرای قرارداد و نوشتن تستهای واحد برای تأیید صحت آن مفروضات مهم است. جدا از ارائه محافظت در برابر اجرای غیرمنتظره، اظهارات تست شما را مجبور میکند به عملیاتی فکر کنید که میتواند مدل امنیتی قراردادهای هوشمند را شکست دهد. یک نکته مفید این است که فراتر از "تستهای کاربر" بروید و تستهای منفی بنویسید که بررسی میکند آیا یک تابع برای ورودیهای اشتباه ناموفق است یا خیر.
بسیاری از فریم ورکهای تست واحد به شما اجازه میدهند تا اظهارات را ایجاد کنید - عبارتهای سادهای که بیان میکند قرارداد چه کاری میتواند انجام دهد و چه کاری نمیتواند انجام دهد - و تستهایی را برای مشاهده اینکه آیا این ادعاها در حال اجرا هستند یا خیر، اجرا کنید. توسعهدهندهای که روی قرارداد حراج که قبلاً توضیح داده شد کار میکند، میتواند پیش از اجرای تستهای منفی، در مورد رفتار خود اظهارات زیر را بیان کند:
وقتی مزایده تمام شده یا شروع نشده است، کاربران نمیتوانند پیشنهاد دهند.
اگر پیشنهادی کمتر از آستانه قابل قبول باشد، قرارداد مزایده لغو میشود.
کاربرانی که موفق به برنده شدن در مناقصه نشوند با وجوه خود اعتبار داده میشوند
نکته: روش دیگری برای تست مفروضات، نوشتن تستهایی است که مادیفایر یا اصلاحکننده تابع(opens in a new tab) را راهاندازی میکنند در یک قرارداد، به خصوص عبارتهای require
، assert
و if…else
.
3. پوشش کد را اندازهگیری کنید (code coverage)
پوشش کد(opens in a new tab) یک معیار آزمایشی است که تعداد شاخهها، خطوط و عبارات کد شما را که در طول تستها اجرا میشوند، ردیابی میکند. تستها باید پوشش کد خوبی داشته باشند، در غیر این صورت ممکن است "منفی کاذب" دریافت کنید و زمانی اتفاق میافتد که یک قرارداد همه تستها را با موفقیت پشت سر میگذارد، اما آسیب پذیریها همچنان در کد وجود دارد. با این حال، ثبت پوشش بالای کد این اطمینان را به شما میدهد که تمام عبارات/عملکردهای یک قرارداد هوشمند به اندازه کافی برای صحت تست شدهاند.
4. از فریم ورکهای آزمایشی توسعه یافته استفاده کنید
کیفیت ابزارهای مورد استفاده در اجرای تستهای واحد برای قراردادهای هوشمند شما بسیار مهم است. یک فریم ورک تست ایده آل، فریم ورکی است که به طور منظم نگهداری شود. ویژگیهای مفیدی را ارائه میدهد (به عنوان مثال، قابلیتهای ثبت و گزارش). و باید به طور گسترده توسط توسعه دهندگان دیگر مورد استفاده و بررسی قرار گرفته باشد.
فریم ورکهای تست واحد برای قراردادهای هوشمند سالیدیتی به زبانهای مختلف (عمدتاً جاوا اسکریپت، پایتون و Rust) ارائه میشوند. برخی از راهنماهای زیر را برای اطلاع از نحوه شروع اجرای تستهای واحد با فریم ورکهای تست مختلف مشاهده کنید:
- اجرای تست واحد با Brownie(opens in a new tab)
- اجرای تست واحد با فوندری(opens in a new tab)
- اجرای تست واحد با وافل(opens in a new tab)
- اجرای تست واحد با ریمیکس(opens in a new tab)
- اجرای تست واحد با ایپ(opens in a new tab)
- اجرای تستهای واحد با هاردهات(opens in a new tab)
- اجرای تستهای واحد با Wake(opens in a new tab)
تست یکپارچهسازی
در حالی که تست واحد عملکردهای قرارداد را به صورت مجزا اشکال زدایی میکند، تستهای یکپارچهسازی اجزای یک قرارداد هوشمند را به عنوان یک کل ارزیابی میکنند. تست یکپارچه سازی میتواند مشکلات ناشی از فراخوانیهای قراردادی متقابل یا تعامل بین عملکردهای مختلف در یک قرارداد هوشمند را شناسایی کند. به عنوان مثال، تستهای یکپارچهسازی میتوانند به بررسی اینکه آیا مواردی مانند ارثبری(opens in a new tab) و وابستگی به درستی کار میکنند یا خیر کمک میکند.
تست یکپارچهسازی در صورتی مفید است که قرارداد شما در طول اجرا از معماری مدولار استفاده کند یا با سایر قراردادهای زنجیرهای ارتباط برقرار کند. یکی از راههای اجرای تستهای یکپارچهسازی این است که را در یک ارتفاع خاص (با استفاده از ابزاری مانند Forge(opens in a new tab) فورک کنید. یا هاردهت(opens in a new tab) و تعاملات بین قرارداد شما و قراردادهای مستقر را شبیهسازی کنید.
بلاک چین فورک شده مشابه شبکه اصلی رفتار خواهد کرد و دارای حسابهایی با وضعیتها و موجودیهای مرتبط است. اما فقط به عنوان یک محیط توسعه محلی سندباکس شده عمل میکند، به این معنی که برای تراکنشها به ETH واقعی نیاز نخواهید داشت، همچنین تغییرات شما بر پروتکل واقعی اتریوم تأثیر نمیگذارد.
تست مبتنی بر مشخصات
تست مبتنی بر دارایی فرآیند بررسی این است که آیا قرارداد هوشمند برخی از ویژگیهای تعریف شده را برآورده میکند یا خیر. ویژگیها حقایقی را در مورد رفتار قرارداد بیان میکنند که انتظار میرود در سناریوهای مختلف درست باقی بماند - نمونهای از ویژگی قرارداد هوشمند میتواند "عملیات حسابی در قرارداد هرگز اورفلو یا آندرفلو" نباشد
تحلیل استاتیک و تحلیل دینامیکی دو تکنیک رایج برای اجرای تست مبتنی بر ویژگی هستند و هر دو میتوانند تأیید کنند که کد یک برنامه (یک قرارداد هوشمند در این مورد) برخی از ویژگیهای از پیش تعریف شده را برآورده میکند. برخی از ابزارهای تست مبتنی بر دارایی با قوانین از پیش تعریف شده در مورد ویژگیهای قرارداد مورد انتظار ارائه میشوند و کد را در برابر آن قوانین بررسی میکنند، در حالی که برخی دیگر به شما امکان میدهند ویژگیهای سفارشی را برای یک قرارداد هوشمند ایجاد کنید.
تجزیه و تحلیل استاتیک
یک آنالایزر استاتیک کد منبع یک قرارداد هوشمند را به عنوان ورودی دریافت کرده و نتایج را با اعلام اینکه آیا قرارداد یک ویژگی را برآورده میکند یا نه، خروجی میگیرد. بر خلاف تحلیل پویا، تحلیل استاتیک شامل اجرای قرارداد برای تجزیه و تحلیل آن برای صحت نیست. تجزیه و تحلیل استاتیک در عوض درباره تمام مسیرهای احتمالی که یک قرارداد هوشمند میتواند در طول اجرا طی کند (به عنوان مثال، با بررسی ساختار کد منبع برای تعیین معنای آن برای عملیات قراردادها در زمان اجرا) استدلال میکند.
Linting(opens in a new tab) و تست استاتیک(opens in a new tab) روشهای رایج برای اجرای تحلیل استاتیک در قراردادها هستند. هر دو نیازمند تجزیه و تحلیل نمایشهای سطح پایین اجرای قرارداد هستند، مانند درخت نحو انتزاعی(opens in a new tab) و کنترل نمودارهای جریان(opens in a new tab) خروجی توسط کامپایلر.
در بیشتر موارد، تجزیه و تحلیل استاتیک برای تشخیص مسائل ایمنی مانند استفاده از ساختارهای ناامن، خطاهای نحوی یا نقض استانداردهای کدگذاری در کد قرارداد مفید است. با این حال، آنالایزرهای استاتیک به طور کلی در تشخیص آسیبپذیریهای عمیقتر نامطلوب هستند و ممکن است مثبت کاذب بیش از حد تولید کنند.
تحلیل دینامیک
تحلیل پویا ورودیهای نمادین (مثلاً در اجرای نمادین(opens in a new tab)) یا ورودیهای مشخص (مثلاً در fuzzing(opens in a new tab)) به یک قرارداد هوشمند عمل میکند تا ببیند آیا هر رد یا تریس(های) اجرایی خاصیت خاصی را نقض میکند یا خیر. این شکل از تست مبتنی بر ویژگی با تستهای واحد متفاوت است، زیرا موارد تست سناریوهای متعددی را پوشش میدهند و یک برنامه تولید موارد تست را انجام میدهد.
Fuzzing(opens in a new tab) نمونهای از تکنیک تحلیل پویا برای تأیید ویژگیهای دلخواه در قراردادهای هوشمند است. یک فازر توابع را در یک قرارداد هدف با تغییرات تصادفی یا به شکل نادرست یک مقدار ورودی تعریف شده فراخوانی میکند. اگر قرارداد هوشمند وارد یک حالت خطا شود (به عنوان مثال، وضعیتی که یک ادعا با شکست مواجه شود)، مشکل علامتگذاری میشود و ورودیهایی که اجرا را به سمت مسیر آسیبپذیر هدایت میکند در یک گزارش تولید میشود.
فازینگ برای ارزیابی مکانیزم اعتبارسنجی ورودی قراردادهای هوشمند مفید است زیرا مدیریت نادرست ورودیهای غیرمنتظره ممکن است منجر به اجرای ناخواسته و ایجاد اثرات خطرناک شود. این شکل از تست مبتنی بر ویژگی میتواند به دلایل زیادی ایدهآل باشد:
نوشتن موارد تست برای پوشش دادن بسیاری از سناریوها دشوار است. تست ویژگی فقط مستلزم آن است که یک رفتار و طیف وسیعی از دادهها را برای تست رفتار تعریف کنید—برنامه به طور خودکار تست را تولید میکند و موارد بر اساس ویژگی تعریف شده است.
مجموعه تست شما ممکن است به اندازه کافی تمام مسیرهای ممکن در برنامه را پوشش ندهد. حتی با پوشش ۱۰۰٪، ممکن است موارد حیاتی را از دست بدهید.
تستهای واحد ثابت میکنند که یک قرارداد برای دادههای نمونه به درستی اجرا میشود، اما اینکه آیا قرارداد برای ورودیهای خارج از نمونه به درستی اجرا میشود یا خیر، ناشناخته باقی میماند. تستهای ویژگی، یک قرارداد هدف را با تغییرات چندگانه یک قرارداد اجرا میکنند. مقدار ورودی داده شده برای یافتن آثار اجرایی که باعث شکست ادعا میشوند. بنابراین، یک تست ویژگی تضمینهای بیشتری برای اجرای صحیح قرارداد برای یک کلاس وسیع از دادههای ورودی ارائه میدهد.
دستورالعملهایی برای اجرای تست مبتنی بر اموال برای قراردادهای هوشمند
اجرای تست مبتنی بر ویژگی معمولاً با تعریف یک ویژگی (به عنوان مثال، عدم وجود اورفلو عدد صحیح(opens in a new tab)) یا مجموعهای از ویژگیهایی که میخواهید در یک قرارداد هوشمند تأیید کنید، میباشد. همچنین ممکن است لازم باشد محدودهای از مقادیر را تعریف کنید که در آن برنامه میتواند دادههایی را برای ورودیهای تراکنش هنگام نوشتن تستهای ویژگی تولید کند.
هنگامی که به درستی پیکربندی شد، ابزار تست، توابع قراردادهای هوشمند شما را با ورودیهای تولید شده بهطور تصادفی اجرا میکند. در صورت وجود هرگونه تخلف ادعایی، باید گزارشی با دادههای ورودی مشخص دریافت کنید که دارایی تحت ارزیابی را نقض میکند. برای شروع تست مبتنی بر ویژگی با ابزارهای مختلف، برخی از راهنماهای زیر را ببینید:
- تجزیه و تحلیل استاتیک قراردادهای هوشمند با اسلیتر (Slither)(opens in a new tab)
- تجزیه و تحلیل استاتیک قراردادهای هوشمند با Wake(opens in a new tab)
- تست مبتنی بر ویژگی با Brownie(opens in a new tab)
- قراردادهای فازی با فاندری (Foundry)(opens in a new tab)
- قراردادهای فازی با Echidna(opens in a new tab)
- قراردادهای فازی با ویک(opens in a new tab)
- اجرای نمادین قراردادهای هوشمند با مانتیکر (Manticore)(opens in a new tab)
- اجرای نمادین قراردادهای هوشمند با Mythril(opens in a new tab)
تست دستی برای قراردادهای هوشمند
تست دستی قراردادهای هوشمند اغلب بعد از اجرای تستهای خودکار در چرخه توسعه انجام میشود. این شکل از تست قرارداد هوشمند را به عنوان یک محصول کاملاً یکپارچه ارزیابی میکند تا ببیند آیا مطابق با الزامات فنی مشخص شده است یا خیر.
تست قراردادها بر روی یک بلاک چین لوکال
در حالی که تست خودکار انجام شده در یک محیط توسعه محلی یا لوکال میتواند اطلاعات مفیدی برای اشکال زدایی یا دیباگ کردن ارائه دهد، شما باید بدانید که قرارداد هوشمند شما در یک محیط تولید چگونه رفتار میکند. با این حال، استقرار یا دپلوی در زنجیره اصلی اتریوم مستلزم هزینههای گس است – ناگفته نماند که اگر قرارداد هوشمند شما همچنان دارای اشکال یا باگ باشد، شما یا کاربرانتان میتوانید پول واقعی خود را از دست بدهید.
تست قرارداد خود بر روی یک بلاک چین محلی (همچنین به عنوان شبکه توسعه نیز شناخته می شود) جایگزین توصیه شده برای آزمایش در شبکه اصلی است. یک بلاک چین محلی یک کپی از بلاک چین اتریوم است که به صورت محلی روی رایانه شما اجرا میشود و رفتار لایه اجرایی اتریوم را شبیهسازی میکند. به این ترتیب، میتوانید تراکنشها را طوری برنامهریزی کنید که با یک قرارداد تعامل داشته باشند، بدون اینکه هزینههای بیشتر قابلتوجهی را متحمل شوند.
اجرای قراردادها بر روی یک بلاک چین محلی میتواند به عنوان نوعی تست ادغام دستی مفید باشد. قراردادهای هوشمند بسیار قابل ترکیب هستند، به شما امکان میدهد با پروتکلهای موجود ادغام کنید—اما همچنان باید اطمینان حاصل کنید که چنین بخش پیچیدهای در زنجیره فعل و انفعالات نتایج صحیح را ایجاد میکند.
اطلاعات بیشتر در مورد شبکههای توسعه.
تست قراردادها بر روی تست نتها یا شبکه آزمایشی
یک شبکه آزمایشی دقیقاً مانند شبکه اصلی اتریوم کار میکند، با این تفاوت که از اتر (ETH) بدون ارزش واقعی استفاده میکند. استقرار قرارداد خود در یک شبکه آزمایشی به این معنی است که هر کسی میتواند با آن تعامل داشته باشد (مثلاً از طریق فرانتاند برنامه غیرمتمرکز) بدون اینکه سرمایهای را در معرض خطر قرار دهد.
این شکل از تست دستی برای ارزیابی جریان انتها به انتها برنامه شما از دیدگاه کاربر مفید است. در اینجا، آزمایشکنندههای بتا میتوانند اجرای آزمایشی را نیز انجام دهند و هرگونه مشکل در منطق تجاری و عملکرد کلی قرارداد را گزارش کنند.
استقرار یا دپلوی در یک شبکه آزمایشی پس از تست بر روی یک بلاک چین محلی ایدهآل است زیرا مورد اول به رفتار ماشین مجازی اتریوم نزدیکتر است. بنابراین، برای بسیاری از پروژههای بومی اتریوم، استفاده از برنامههای غیرمتمرکز در شبکههای آزمایشی برای ارزیابی عملیات قراردادهای هوشمند در شرایط دنیای واقعی رایج است.
اطلاعات بیشتر در مورد شبکههای آزمایشی اتریوم.
تست در مقابل تأیید رسمی
در حالی که تست کمک میکند تا تأیید شود که یک قرارداد نتایج مورد انتظار را برای برخی از ورودیهای داده برمیگرداند یا خیر، ولی نمیتواند به طور قطعی همان را برای ورودیهایی که در طول تست استفاده نشدهاند ثابت کند. بنابراین، تست یک قرارداد هوشمند نمیتواند «صحت عملکردی» را تضمین کند (یعنی نمیتواند نشان دهد که یک برنامه برای همه مجموعههای مقادیر ورودی، آنطور که لازم است رفتار میکند).
تأیید رسمی رویکردی برای ارزیابی صحت نرمافزار با بررسی اینکه آیا مدل رسمی برنامه با مشخصات رسمی مطابقت دارد یا خیر. یک مدل رسمی یک نمایش ریاضی انتزاعی از یک برنامه است، در حالی که یک مشخصات رسمی ویژگیهای یک برنامه را تعریف میکند (یعنی ادعاهای منطقی در مورد اجرای برنامه).
از آنجایی که ویژگیها به صورت ریاضی نوشته شدهاند، میتوان تأیید کرد که یک مدل رسمی (ریاضی) سیستم با استفاده از قوانین منطقی استنتاج، مشخصاتی را برآورده میکند یا خیر. بنابراین، گفته میشود که ابزارهای تأیید رسمی «اثبات ریاضی» درستی یک سیستم را ارائه میدهند.
برخلاف تست، تأیید رسمی میتواند برای تأیید اینکه اجرای قراردادهای هوشمند دارای مشخصات رسمی برای همه اجراها است (یعنی بدون باگ) بدون نیاز به اجرای آن با نمونه دادهها استفاده شود. این مورد نه تنها زمان صرف شده برای اجرای دهها تست واحد را کاهش میدهد، بلکه در شناسایی آسیبپذیریهای پنهان نیز موثرتر است. گفتنی است، تکنیکهای تأیید رسمی بسته به دشواری اجرا و مفید بودنشان در طیفی قرار دارند.
بیشتر در مورد تأیید رسمی برای قراردادهای هوشمند.
تست در مقابل ممیزی یا آدیت و پاداش باگ
همانطور که ذکر شد، تست دقیق به ندرت میتواند عدم وجود اشکال یا باگ در قرارداد را تضمین کند. رویکردهای تأیید رسمی میتوانند تضمینهای قویتری از صحت ارائه دهند، اما در حال حاضر استفاده از آنها دشوار است و هزینههای قابل توجهی را متحمل میشود.
با این وجود، میتوانید با بررسی کد مستقل، امکان شناسایی آسیبپذیریهای قرارداد را بیشتر کنید. ممیزی یا آدیت قراردادهای هوشمند(opens in a new tab) و پاداشهای باگ(opens in a new tab) دو راه برای ترغیب دیگران به تجزیه و تحلیل قراردادهای شما هستند.
ممیزیها توسط حسابرسان با تجربه در یافتن موارد نقص امنیتی و شیوههای توسعه ضعیف در قراردادهای هوشمند انجام میشود. ممیزی معمولاً شامل تست (و احتمالاً تأیید رسمی) و همچنین بررسی دستی کل پایگاه کد است.
برعکس، برنامه پاداش باگ معمولاً شامل ارائه پاداش مالی به یک فرد است (که معمولاً به عنوان هکرهای کلاه سفید(opens in a new tab) توصیف میشود) یک آسیبپذیری را در یک قرارداد هوشمند کشف کرده و آن را برای توسعهدهندگان فاش میکند. پاداش باگ مشابه ممیزی یا آدیت است زیرا شامل درخواست از دیگران برای کمک به یافتن نقص در قراردادهای هوشمند است.
تفاوت عمده این است که برنامههای پاداش باگ برای جامعه توسعهدهندگان/هکرهای گستردهتر باز است و طبقه وسیعی از هکرهای اخلاقی و متخصصان امنیتی مستقل را با مهارتها و تجربههای منحصربهفرد جذب میکنند. این مورد ممکن است یک مزیت نسبت به ممیزی یا آدیت قراردادهای هوشمند باشد که عمدتاً به تیمهایی متکی است که ممکن است تخصص محدودی داشته باشند.
کتابخانهها و ابزارهای آزمایش
ابزار تست واحد
کاورج یا پوشش سالیدیتی(opens in a new tab) - ابزار پوشش کد برای قراردادهای هوشمند نوشته شده در سالیدیتی است.
وافل(opens in a new tab) - چارچوبی برای توسعه و تست قراردادهای هوشمند پیشرفته (بر اساس ethers.js) است.
تستهای ریمیکس(opens in a new tab) - ابزاری برای آزمایش قراردادهای هوشمند سالیدیتی است. در زیر پلاگین ریمیکس "Solidity Unit Testing" کار میکند که برای نوشتن و اجرای موارد تست برای قرارداد استفاده میشود.
کمککننده تست اوپن زپلین(opens in a new tab) - کتابخانه ازرشن برای تست قرارداد هوشمند اتریوم. مطمئن شوید که قراردادهای شما مطابق انتظار عمل می کند!
فریم ورک تست واحد براونی(opens in a new tab) - براونی از Pytest استفاده میکند، یک فریم ورک تستی غنی از ویژگیها که به شما امکان میدهد تستهای کوچک را با حداقل کد بنویسید و برای پروژههای بزرگ مقیاسپذیری خوبی دارد و بسیار قابل توسعه است.
تستهای فاندری (opens in a new tab) - Foundry Forge را ارائه میکند، یک فریم ورک آزمایشی سریع و انعطافپذیر اتریوم که قادر به اجرای آزمایشهای واحد ساده، بررسیهای بهینهسازی گس و فازبندی قرارداد است.
تستهای هاردهت(opens in a new tab) - چارچوبی برای آزمایش قراردادهای هوشمند مبتنی بر ethers.js، موکا و چای است.
ایپ ورکس(opens in a new tab) - چارچوب توسعه و آزمایش مبتنی بر پایتون برای قراردادهای هوشمند با هدف قرار دادن ماشین مجازی اتریوم است.
ویک(opens in a new tab) - چارچوب مبتنی بر پایتون برای آزمایش واحد و فازی کردن با قابلیتهای اشکالزدایی قوی و پشتیبانی از آزمایش زنجیرهای متقابل، استفاده از pytest و Anvil برای بهترین تجربه و عملکرد کاربر است.
ابزارهای تست مبتنی بر ویژگی
ابزارهای تحلیل استاتیکی
Slither(opens in a new tab) - Python- فریم ورک تجزیه و تحلیل استاتیک سالیدیتی برای یافتن آسیبپذیریها، بهبود درک کد و نوشتن تحلیلهای سفارشی برای قراردادهای هوشمند.
Ethlint(opens in a new tab) - دریچهای برای اعمال بهترین شیوهها و شیوههای امنیتی برای زبان برنامه نویسی قرارداد هوشمند سالیدیتی است.
سایفرین آدرین(opens in a new tab) - تحلیلگر استاتیک مبتنی بر استاتیک که به طور خاص برای امنیت و توسعه قراردادهای هوشمند وب3 طراحی شده است.
ویک(opens in a new tab) - چارچوب تحلیل استاتیک مبتنی بر پایتون با آشکارسازهای آسیبپذیری و کیفیت کد، چاپگرهایی برای استخراج اطلاعات مفید از کد و پشتیبانی برای نوشتن زیرماژولهای سفارشی.
ابزارهای تحلیل پویا
اکیدنا(opens in a new tab) - فازر سریع قرارداد برای شناسایی آسیبپذیریها در قراردادهای هوشمند از طریق تست مبتنی بر دارایی است.
Diligence Fuzzing(opens in a new tab) - ابزار فازینگ خودکار برای تشخیص تخلفات دارایی در کد قرارداد هوشمند مفید است.
مانتیکر(opens in a new tab) - فریم ورک اجرای نمادین پویا برای تجزیه و تحلیل بایت کد ماشین مجازی اتریوم است.
میثریل (Mythril)(opens in a new tab) - ابزار ارزیابی بایت کد ماشین مجازی اتریوم برای شناسایی آسیبپذیریهای قرارداد با استفاده از تجزیه و تحلیل تینت، تجزیه و تحلیل کونکولیک، و بررسی جریان کنترل است.
Diligence Scribble(opens in a new tab) - Scribble یک زبان مشخصات و ابزار تأیید زمان اجرا است که به شما امکان میدهد قراردادهای هوشمند را با ویژگیهایی حاشیه نویسی کنید که به شما امکان میدهد به طور خودکار قراردادها را با ابزارهایی مانند Diligence Fuzzing یا MythX تست کنید.
آموزشهای مرتبط
- نمای کلی و مقایسه محصولات تست مختلف _
- نحوه استفاده از Echidna برای آزمایش قراردادهای هوشمند
- نحوه استفاده از Manticore برای یافتن اشکالات قرارداد هوشمند
- نحوه استفاده از Slither برای یافتن اشکالات قرارداد هوشمند
- چگونه قراردادهای Solidity را برای آزمایش شبیه سازی کنیم
- نحوه اجرای تست های واحد در سالیدیتی با استفاده از Foundry(opens in a new tab)