تابع بازگشتی Fallback Function در سالیدیتی Solidity
تابع بازگشتی در سالیدیتی چیست؟
یک تابع بازگشتی در سالیدیتی یا در اصل همان solidity fallback function، تابعی از نوع external و بدون هیچ نام، پارامتر یا return است. این تابع در یکی از موارد زیر اجرا میشود:
- اگر یک شناسه تابع با هیچکدام از توابع در دسترس در قرارداد هوشمند مطابق نشود.
- اگر هیچ دادهای در طی فراخوانی تابع تولید و ارائه نشده باشد.
- اگر قرارداد اتر، ساده و بدون داده باشد.
قبل از مطالعه کامل مقاله “تابع بازگشتی Fallback Function در سالیدیتی” پشنهاد میکنیم مقالات دیگر حوزه آموزش سالیدیتی را هم مطالعه کنید.
Mapping در قرارداد هوشمند Solidity
توسعه قرارداد هوشمند در محیط ریمیکس Remix
توابع modifiers در سالیدیتی solidity
حلقه های تکرار در سالیدیتی Solidity Loop
دستور Enums در برنامه نویسی سالیدیتی
رویدادها Events در برنامه نویسی Solidity
هر قرارداد هوشمند، تنها میتواند یک تابع بدون نام از نوع Fallback داشته باشد و هنگامی که درخواستی بدون مشخص کردن نام تابعی در اسمارت کانترکت، به قرارداد ما ارسال شود،(در اسمارت کانترکت ها، داده ها توسط msg.data دریافت خواهند شد)، این تابع اجرا میشود. حال در صورتی که درخواستی که برای اسمارت کانترکت ما ارسال میشود، حاوی دارایی(مثلاً اتر) باشد، باید تابعی داشته باشیم که با استفاده از آن، قرارداد هوشمند ما قابلیت دریافت اتر(و یا سایر کریپتوها) را پیدا کند.
پس در این زمان، باید به جای استفاده از fallback function، از یک تابع تحت عنوان receive استفاده کنیم(ابته در نظر داشته باشید که تابع receive را میتوان به عنوان یک زیرشاخه از تابع fallback در نظر گرفت). در صورتی که این چنین تابعی (یعنی تابع receive مورد بحث ما) تعریف نشده باشد، قرارداد قادر نخواهد بود اتر دریافت کند. این توابع را با استفاده از هر دو دستور زیر و در هر دو بدون استفاده از کلمه کلیدی function میتوان پیاده سازی کرد.
1 2 3 4 5 6 7 8 |
// تعریف شود External باید از نوع Fallback function تابع fallback() external payable { } // خالی باشد msg.data اگر مقدار ارسالی در // اجرا میشود Receive تابع receive() external payable { } |
این تابع یکی از توابع بسیار مهم و حیاتی برای ایجاد و اجرای قراردادهای هوشمند است که در زبان برنامهنویسی سالیدیتی وجود دارد، برای آشنایی بیشتر با fallback function در سالیدیتی با این مقاله در توکن خان همراه باشید.
قراردادها در سالیدیتی
contract در زبان برنامهنویسی سالیدیتی مشابه کلاس در سایر زبانهای برنامهنویسی شیگرا است. آنها دارای دادههای پایدار در state variable میباشند، و البته توابعی نیز قابل تعریف هستند که بتوانند مقادیر state variable را تغییر دهند.
فراخواندن یک تابع در قراردادهای هوشمند، EVM را اجرا خواهد کرد و بنابراین میتواند زمینه را طوری تغییر دهد که state variable در فراخوانی قرارداد غیرقابل دسترسی باشند. یک قرارداد و توابع آن باید برای هر اتفاقی فراخوانی شوند. هیچ مفهومی تحت عنوان cron (قابلیتی که توسط آن عملیاتی خاص در زمانی خاص به صورت اتوماتیک انجام شود) در اتریوم برای فراخوانی خودکار یک تابع در یک رویداد خاص وجود ندارد.
ایجاد قراردادها در سالیدیتی
قراردادها را میتوان از خارج از اسمارت کانترکت، و از طریق تراکنشهای اتریوم و یا از داخل قراردادهای سالیدیتی ایجاد کرد. IDEهایی مثل ریمیکس Remix، فرآیند ایجاد قراردادهای هوشمند را با استفاده از عناصر UI یکپارچه میکنند. یک روش برای ایجاد قراردادها برنامهنویسی اتریوم توسط زبان برنامهنویسی سالیدیتی است.
توسعه قرارداد هوشمند در محیط ریمیکس Remix IDE روشی مناسب و انعطافپذیر است که با چند مرحله ساده انجام این کار را برای شما آسان میکند. برای نوشتن قرارداد هوشمند و استقرار آن در شبکه بلاک چینی مانند اتریوم باید زبان برنامهنویسی سالیدیتی Solidity را بدانید، اطلاعاتی کامل در مورد اتریوم داشته باشید و علاوه بر این، اصول Remix IDE و اجزای مختلف آن را بیاموزید. یکی از این موضوعات در رابطه با زبان برنامهنویسی سالیدیتی توابع هستند که انواع مختلفی دارند یکی از مهمترین این توابع در قرارداد هوشمند سالیدیتی، تابعی تحت عنوان fallback است.
ویژگی های توابع بازگشتی در سالیدیتی
تابع بازگشتی در قرارداد هوشمند سالیدیتی به عنوان یکی از مهمترین توابع در زبان برنامهنویسی سالیدیتی ویژگیهایی دارد که به ترتیب زیر است:
- این تابع هیچ نامی ندارد.
- اگر این تابع در قرارداد هوشمند مورد نظر، به صورت payable تعریف نشود و بدون دریافت داده، مقداری اتر دریافت کند، خطا رخ خواهد داد و تراکنش مربوطه، revert خواهد شد. در نتیجه در صورت دریافت اتر، قرارداد آن را برای فرستنده برمیگرداند.
- با این تابع نمیتوان چیزی را پس داد.
- در هر قرارداد هوشمند تنها یک تابع fallback و یک تابع receive میتوان داشت.
- این تابع در صورتی اجرا میشود که کاربر قصد فراخوانی تابعی را داشته باشد که در دسترس نیست.
- fallback function الزاماً باید بصورت external تعریف شود.
- این تابع در زمانی که توسط تابع دیگری فراخوانی میشود به میزان گس 2300 نیاز خواهد داشت. این ویژگی تابع بازگشتی در قرارداد هوشمند سالیدیتی برای این است که فراخوانی این تابع تا حد ممکن ارزان باشد.
- تابع بازگشتی آرگومان ندارد.
- این تابع باید به عنوان قابل پرداخت payable علامتگذاری شود تا بتواند اتر دریافت کند.
تابع Fallback در قرارداد هوشمند سالیدیتی چیست؟
با توجه به ویژگیهایی که برای توابع بازگشتی در سالیدیتی مطرح شد، میتوان چنین نتیجهگیری کرد که یک قرارداد حداکثر میتواند یک تابع بازگشتی (Fallback Function) داشته باشد. این تابع هم همچون دیگر توابع تا هر زمان که گس به اندازه لازم به آن ارسال شود، میتواند تراکنشهای پیچیده را انجام دهد و میزان گس دریافتی آن حداکثر 2300 است. در نتیجه تراکنشهای پیچیدهای که بیشتر از این میزان گس را مصرف کند، نمیتواند انجام دهد.
در واقع تابع بازگشتی در قرارداد هوشمند سالیدیتی را میتوان به نوعی یک سوپاپ اطمینان دانست که توسعهدهندگان این زبان برنامهنویسی مثل یک گزینه پیشفرض برای آن طراحی کرده اند. این توابع از این جهت قابل توجه هستند که در حالتی که یک قرارداد، اتر را بدون هیچ دادهای مربوط با تراکنش دریافت کند، اجرا خواهند شد. این گزینه طراحی پیشفرض بسیار منطقی بوده و در نهایت از کاربران حفاظت میکند.
علاوه بر این، اینکه قرارداد هوشمند ساده، اتر را با استفاده از یک تابع بازگشتی در سالیدیتی دریافت کند دارای اهمیت است. علاوه بر این مسئلهف حتماً دقت داشته باشید که اگر مقداری اتر به قرارداد ارسال شود، و تابع receive درون قرارداد هوشمند ما تعبیه نشده باشد، در اینصورت قرارداد خطا داده و اتر را به فرستنده آن برمیگرداند.
یکی از ویژگیهای توابع بازگشتی که مطرح شد، این بود که این تابع به میزان گس 2300 محدود است که این میزان گس، فضای کمی ایجاد میکند که برای انجام عملیاتهای دیگر و یا یک عملیات پیچیده کافی نیست. به بیان دیگر با تابع بازگشتی در سالیدیتی عملیاتی همچون ایجاد قرارداد یا نوشتن آن در بلاک چین، فراخوانی توابع خارجی و فرستادن اتر را نمیتوان انجام داد پس این توابع بایستی ساده باشند و نه پیچیده.
مثال برای توابع بازگشتی در سالیدیتی
در ادامه میتوانید نمونهای از فراخوانی یک تابع در Solidity را در قطعه کد زیر مشاهده کنید.
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; // contract with fallback function contract Base { uint public number; event ShowMsg(string message); function setNumber(uint _number) external { number = _number; } fallback() external payable { number = 0; emit ShowMsg("Fallback a non-existing function called"); } receive() external payable { emit ShowMsg("Receive called"); } } // contract to interact with contract Base contract Caller { Base immutable a; constructor(address payable _a) { a = Base(_a); } function callBase_Fallback_1() public { // calling an existing function (bool success, ) = address(a).call(abi.encodeWithSignature("number()")); require(success); } function callBase_Fallback_2() public { // calling a non-existing function (bool success, ) = address(a).call(abi.encodeWithSignature("setter()")); require(success); } function callBase_Receive() public payable returns (bool) { // sending ether to contract B address payable payableBase = payable(address(a)); return (payableBase.send(msg.value)); } } |
توضیحات نمونه تابع Fallback Function به ترتیب زیر هستند که برای درک بهتر این مثال برای شما آورده شده است:
- در خط یک این مثال، بسته pragma را وارد میکنیم.
- در خط 5 تا 21 قراردادی با عنوان contract Base را ایجاد میکنیم که یک متغیر حالت number و یک event برای آن تعبیه کرده ایم. سپس یک تابع setNumber که یک مقدار عددی را میپذیرد و آن را در numer ذخیره میکند. در ادامه تابع fallback و receive را نیز بصورت payable تعریف کرده ایم که با آنها بهتر آشنا شوید.
- در خط 24 تا 48 نیز یک قرارداد دیگر با عنوان contract Caller ایجاد میکنیم که با contract Base در تعامل است. در ادامه تابعی موجود از contract Base را و سپس تابع ناموجودی از contract Base را فراخوانی میکنیم. در نهایت با تعریف تابعی با عنوان callBase_Receive، مقداری ETH(اتر) را به contract Base ارسال می کنیم.
جهت اجرا و تست این قرارداد هوشمند:
تابع payable در سالیدیتی چیست؟
تابع Payable یا تابع قابل پرداخت به منظور اطمینان از توانایی یک تابع، قرارداد، یا آدرس، برای دریافت توکن بومی(مثلاً اتر در شبکه اتریوم) یک شبکه میباشد. هر تابعی در زبان برنامه نویسی سالیدیتی به کمک این تابع این اطمینان را برای شما فراهم میکند که میتواند اتر را دریافت و ارسال کند. در نتیجه اگر تابعی را برای پردازش تراکنشها فراخوانی کرده اید اما کلمه کلیدی Payable را وارد نکرده اید، تراکنش خودبهخود رد شده یا اصطلاحا revert میشود.
توابع بازگشتی در سالیدیتی را ساده نگهدارید.
Fallback Functions زمانی که یک قرارداد، پیامی بدون هیچگونه آرگومانی را ارسال میکند، و یا زمانی که با هیچ تابعی مطابقت ندارد فراخوانی میشود. این تابع زمانی به 2300 گس دسترسی دارد که از یک.send() یا.transfer() فراخوانی شود. در نتیجه اگر میخواهید که اتر از یک.send() یا.transfer() قابل دریافت باشد بیشترین کاری که میتوانید انجام دهید گزارش یا ثبت یک رویداد (event) در یک تابع بازگشتی است. اما اگر به گس بیشتری نیاز دارید باید از یک تابع مناسب استفاده کنید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
contract x { mapping(address => uint) public balances; event LogDepositReceived(address sender); // bad fallback() external payable { balances[msg.sender] += msg.value; } // good function deposit() payable external { balances[msg.sender] += msg.value; } /* fallback() external payable { require(msg.data.length == 0); emit LogDepositReceived(msg.sender); } */ } |
بررسی طول داده در تابع بازگشتی
توابع بازگشتی در سالیدیتی تنها برای انتقال اتر ساده (بدون داده) فراخوانی نمیشوند و زمانی که هیچ تابعی دیگری مطابقت ندارد هم فراخوانی آنها انجام میشود. بنابراین شما باید طول داده را از لحاظ خالی بودن داده در مواقعی که تابع بازگشتی تنها برای ثبت اتر دریافتی استفاده میشود، بررسی کنید. در غیر اینصورت کسانی که فراخوانی را انجام داده اند اگر قرارداد شما اشتباه استفاده شود، متوجه نخواهند شد و توابعی فراخوانی میشوند که وجود ندارند.
1 2 3 4 5 6 |
// bad function() payable { emit LogDepositReceived(msg.sender); } // good function() payable { require(msg.data.length == 0); emit LogDepositReceived(msg.sender); } |
سخن آخر
توابع بازگشتی در سالیدیتی یکی از مهمترین توابع در زبان برنامهنویسی سالیدیتی هستند که هر قرارداد تنها میتواند یک تابع از این نوع را داشته باشد. یک تابع بازگشتی میتواند مجازی (virtual) باشد، میتواند نادیده گرفته شود (override) و میتواند اصلاح کننده (modifiers) داشته باشد.
اگر هیچ یک از توابع دیگر با امضای تابع داده شده مطابقت نداشته باشد، یا اگر اصلا دادهای ارائه نشده باشد و تابع اتر دریافتی وجود نداشته باشد، تابع بازگشتی در یک فراخوانی به قرارداد اجرا میشود. تابع بازگشتی همیشه دادهها را دریافت میکند، اما برای دریافت اتر نیز باید قابل پرداخت علامتگذاری شود. مانند هر تابعی، تابع بازگشتی میتواند عملیات پیچیده را تا زمانی که گس کافی به آن ارسال شده باشد، اجرا کند.
منابع معتبر مرتبط:
https://www.geeksforgeeks.org/solidity-fall-back-function
https://medium.datadriveninvestor.com/fall-back-function-in-solidity
مطالب زیر را حتما مطالعه کنید
بررسی رفتار توابع View و Pure در سالیدیتی Solidity
توابع Payable در قراردادهای هوشمند Solidity
سالیدیتی Solidity چیست؟
سطح دسترسی Visibility در سالیدیتی Solidity
توابع Function در سالیدیتی Solidity
انواع حافظه در قرارداد هوشمند سالیدیتی
7 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
حرف نداشت👌🏻
خیلی ممنون از توضیحات خوبتون
خیلی محتوای خوبی بود مهندس
منابع این مطلب کجاست؟
مطلب به درد بخوری بود
مطلب بی نظیری بود
واقعا ارزش وقت گذاشتن داشت