• تهران -خیابان شریعتی - بالاتر از سه راه ملک - روبروی آتش نشانی - آرتارسانه
  • تلفن تماس: 02191303424

آموزش برنامه نویسی سالیدیتی رایگان درس هفتم

آموزش برنامه نویسی سالیدیتی رایگان درس هفتم

واحدها و متغیرهای جهانی در دسترس

واحدهای اتر

یک عدد لیترال می‌تواند پسوند  wei،gwei  یا ether را برای تعیین زیرمجموعه اتر انتخاب کند، جایی که اعداد اتر بدون پسوند Wei فرض می‌شوند

;assert(1 wei == 1)

;assert(1 gwei == 1e9)

;assert(1 ether == 1e18)

 

تنها اثر پسوند فرعی ضرب در توان ده است.

عنوان‌های finney و szabo در نسخه 0.7.0 حذف شده اند.

واحدهای زمان

پسوندهایی مانند seconds، minutes، hours، days و weeks بعد از اعداد لیترال را می‌توان برای تعیین واحدهای زمانی که ثانیه‌ها واحد پایه هستند و واحدها به روش زیر در نظر گرفته می شوند استفاده کرد:

1 == 1 seconds

1 minutes == 60 seconds

1 hours == 60 minutes

1 days == 24 hours

1 weeks == 7 days

در صورت انجام محاسبات تقویم با استفاده از این واحدها مراقب باشید، زیرا نه هر سال برابر با 365 روز است و نه حتی هر روز به دلیل پرش ثانیه‌ها (leap seconds )، 24 ساعت دارد. با توجه به این واقعیت که نمی‌توان پرش ثانیه‌ها (leap seconds ) را پیش بینی کرد، یک کتابخانه تقویم دقیق باید توسط یک اوراکل خارجی به روز شود.

توجه داشته باشید

پسوند سال در نسخه 0.5.0 به دلایل بالا حذف شده است.

این پسوندها را نمی‌توان برای متغیرها اعمال کرد. به عنوان مثال، اگر می‌خواهید یک پارامتر تابع را در روز تفسیر کنید، می‌توانید به روش زیر عمل کنید:

function f(uint start, uint daysAfter) public {    if (block.timestamp >= start + daysAfter * 1 days) {      // …    }}

متغیرها و توابع ویژه

 متغیرها و توابع خاصی وجود دارند که همیشه در global namespace وجود دارند و عمدتاً برای ارائه اطلاعات در مورد بلاک چین یا توابع کاربردی عمومی استفاده می شوند.

ویژگی‌های بلوک و معاملات

  • blockhash(uint blockNumber) returns (bytes32): هش بلوک داده شده زمانی که blockNumber یکی از 256 بلوک اخیر باشد. در غیر این صورت صفر را برمی گرداند.
  • basefee (uint): هزینه پایه بلوک فعلی (EIP-3198 و EIP-1559)
  • chainid (uint): شناسه زنجیره فعلی
  • coinbase (addresspayable): آدرس فعلی ماینر بلاک
  • difficulty (uint): مشکل بلوک فعلی
  • block.gaslimit (uint) : حد گس بلوک فعلی
  • number (uint): شماره بلوک فعلی
  • timestamp (uint): مُهر زمان بلوک فعلی به عنوان ثانیه از زمان یونیکس
  • gasleft() returns (uint256): گس باقی مانده
  • msg.data (bytes calldata): مکمل calldata
  • msg.sender (address): فرستنده پیام (فراخوانی فعلی)
  • (msg.sig (bytes4: چهار بایت اول calldata (یعنی شناسه تابع)
  • (msg.value (uint: تعداد wei ارسال شده همراه با پیام
  • tx.gasprice (uint): قیمت گس معامله
  • tx.origin (address): فرستنده تراکنش (زنجیره فراخوانی کامل)

توجه داشته باشید

مقادیر همه اعضای msg، از جمله msg.sender و msg.value می توانند برای هر فراخوانی تابع خارجی تغییر کنند. این فراخوانی شامل به عملکردهای کتابخانه می شود.

توجه داشته باشید

وقتی قراردادها خارج از زنجیره ارزیابی می شوند و نه در زمینه تراکنش موجود در یک بلوک، نباید آن *.block را در نظر بگیرید. و *.tx به مقادیر هر بلوک یا تراکنش خاصی اشاره دارد. این مقادیر توسط پیاده‌سازی EVM که قرارداد را اجرا می کند ارائه می‌شود و می‌تواند دلخواه باشد.

توجه داشته باشید

به block.timestamp یا blockhash به عنوان منبع تصادفی اعتماد نکنید، مگر اینکه بدانید چه کاری انجام می‌دهید. هم timestamp و هم block hash می‌توانند تا حدی تحت تاثیر ماینرها قرار بگیرند. بازیگران بد در جامعه ماینینگ می‌توانند برای مثال یک تابع پرداخت کازینو را روی یک هش انتخابی اجرا کنند و اگر پولی دریافت نکردند، فقط یک هش دیگر را دوباره امتحان کنند. timestamp بلوک فعلی باید خیلی بزرگتر از timestamp آخرین بلوک باشد، اما تنها تضمین این است که جایی بین timestamp دو بلوک متوالی در زنجیره متعارف باشد.

توجه داشته باشید

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

توجه داشته باشید

تابع blockhash قبلاً با نام block.blockhash شناخته می شد که در نسخه 0.4.22 منسوخ و در نسخه 0.5.0 حذف شد.

توجه داشته باشید

تابع gasleft قبلاً با نام msg.gas شناخته می شد که در نسخه 0.4.21 منسوخ و در نسخه 0.5.0 حذف شد.

توجه داشته باشید

در نسخه 0.7.0، نام مستعار now (برای block.timestamp) حذف شد.

 

توابع رمزگذاری و رمزگشایی ABI

  • (…) decode(bytes memory encodedData, (…)) returns

ABI داده های داده شده را رمزگشایی می کند، تا زمانی‌ که که types در پرانتز به عنوان آرگومان دوم آورده شده باشد. مانند : (uinta, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))

  • encode(…) returns (bytes memory)

ABI آرگومان های داده شده را رمزگذاری می کند.

  • encodePacked(…) returns (bytes memory) 

رمزگذاری بسته بندی شده آرگومان های داده شده را انجام می دهد. توجه داشته باشید که رمزگذاری بسته بندی شده می‌تواند مبهم باشد!

  • encodeWithSelector(bytes4 selector, …) returns (bytes memory)

ABI آرگومان های داده شده را با شروع از دومی رمزگذاری می‌کند و انتخابگر چهار بایت داده شده را پیشاپیش قرار می‌دهد.

  • encodeWithSignature(stringmemory signature, …) returns (bytes memory)

معادل است با  abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), …)

  • encodeCall(functionfunctionPointer, (…)) returns (bytes memory)

ABI، فراخوانی به functionPointer را با آرگومان های موجود در تاپل کدگذاری می کند. یک بررسی کامل  type-check انجام می‌دهد تا اطمینان حاصل شود که typesبا امضای تابع مطابقت دارند. نتیجه برابر است با  ((…),abi.encodeWithSelector(functionPointer.selector

توجه داشته باشید

این توابع رمزگذاری را می توان برای ایجاد داده برای فراخوانی عملکرد خارجی بدون فراخوانی یک تابع خارجی استفاده کرد. علاوه بر این، ((keccak256(abi.encodePacked(a,b راهی برای محاسبه هش داده‌های ساختار‌یافته است (اگرچه توجه داشته باشید که می‌توان یک «هش تصادفی» با استفاده از انواع مختلف پارامتر تابع ایجاد کرد).

برای جزئیات بیشتر در مورد رمزگذاری، به مستندات مربوط به ABI و رمزگذاری محکم بسته بندی شده مراجعه کنید.

اعضای بایت ها

  • bytes.concat(…) returns (bytes memory) : تعداد متغیر بایت ها و آرگومان های bytes1, …, bytes32 را به یک آرایه بایتی الحاق می‌کند.

اعضای رشته

  • string.concat(…) returns (string memory) : تعدادی متغیر از آرگومان های رشته را به یک آرایه رشته الحاق می‌کند.

رسیدگی به خطا

برای جزئیات بیشتر در مورد رسیدگی به خطا و زمان استفاده از این تابع، بخش اختصاص داده شده به آن را ببینید.

assert(bool condition)

باعث خطای Panic می شود و در نتیجه در صورت عدم رعایت شرایط، بازگشت تغییر حالت – برای خطاهای داخلی استفاده می شود.

require(bool condition)

اگر شرط برآورده نشود، برمی گردد – برای خطا در ورودی ها یا اجزای خارجی استفاده می شود.

require(bool condition, string memory message)

اگر شرط برآورده نشود، برمی گردد – برای خطا در ورودی ها یا اجزای خارجی استفاده می شود. همچنین یک پیغام خطا ارائه می دهد.

()revert

لغو اجرا و برگرداندن تغییرات حالت

(revert(string memory reason

لغو اجرا و برگرداندن تغییرات حالت، ارائه یک رشته توضیحی

توابع ریاضی و رمزی

addmod(uint x, uint y, uint k) returns (uint)

محاسبه (x + y) % k که در آن جمع با دقت دلخواه انجام می شود و در  256**2 قرار  نمی‌گیرد. ثابت کنید که k != 0 از نسخه 0.5.0 شروع می شود.

mulmod(uint x, uint y, uint k) returns (uint)

محاسبه x * y) % k ) که در آن ضرب با دقت دلخواه انجام می شود و در 2**256 قرار نمی گیرد. ثابت کنید که k != 0 از نسخه 0.5.0 شروع می شود.

keccak256(bytes memory) returns (bytes32)

هش Keccak-256 ورودی را محاسبه کنید.

توجه داشته باشید

قبلا یک نام مستعار برای keccak256 به نام sha3 وجود داشت که در نسخه 0.5.0 حذف شد.

sha256(bytes memory) returns (bytes32)

هش SHA-256 ورودی را محاسبه کنید.

ripemd160(bytes memory) returns (bytes20)

هش RIPEMD-160 ورودی را محاسبه کنید.

ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)

آدرس مرتبط با کلید عمومی را از امضای منحنی بیضی بازیابی کنید یا در صورت خطا، صفر را برگردانید. پارامترهای تابع با مقادیر ECDSA امضا مطابقت دارد:

  • r : یعنی 32 بایت اول امضا
  • s : یعنی 32 بایت دوم امضا
  • V : یعنی 1 بایت نهاییامضا

ecrecover یک address را برمی گرداند و نه یک address payable. در صورت نیاز به انتقال وجه به آدرس بازیابی شده به آدرس قابل پرداخت برای تبدیل مراجعه کنید.

برای جزئیات بیشتر، نمونه استفاده شده را بخوانید.

هشدار

اگر از ecrecover استفاده می‌کنید، توجه داشته باشید که یک امضای معتبر می‌تواند بدون نیاز به دانش کلید خصوصی مربوطه به امضای معتبر دیگری تبدیل شود. در هارد فورک Homestead، این مشکل برای امضاهای _transaction_ برطرف شد (به EIP-2 مراجعه کنید)، اما عملکرد ecrecover بدون تغییر باقی ماند. این معمولاً مشکلی پیش نمی‌آورد مگر اینکه نیاز به امضاهایی داشته باشید که منحصر به فرد باشند یا از آنها برای شناسایی موارد استفاده کنید. OpenZeppelin یک کتابخانه کمکی ECDSA دارد که می‌توانید بدون این مشکل به عنوان یک پوشش برای ecrecover استفاده کنید.

توجه داشته باشید

هنگام اجرای sha256، ripemd160 یا ecrecover روی یک بلاک چین، ممکن است با Out-of-Gas مواجه شوید. این به این دلیل است که این توابع به عنوان “قراردادهای از پیش کامپایل شده” پیاده سازی می شوند و فقط پس از دریافت اولین پیام واقعاً وجود دارند (اگرچه کد قرارداد آنها هاردکد است). پیام‌های قراردادهای موجود گران‌تر هستند و بنابراین ممکن است اجرا با خطای خارج از گس مواجه شود. یک راه حل برای این مشکل این است که ابتدا Wei (به عنوان مثال 1) را به هر یک از قراردادها قبل از استفاده از آنها در قراردادهای واقعی خود بفرستید. این یک مشکل در شبکه اصلی یا آزمایشی نیست.

اعضای انواع آدرس

(uint256) address>.balance>

موجودی آدرس در Wei

(bytes memory) address>.code>

کد در آدرس (می تواند خالی باشد)

(bytes32) address>.codehash>

کد هش آدرس

address payable>.transfer(uint256 amount)>

مقدار داده شده Wei را به آدرس بفرستید، در صورت خرابی برمی‌گردد، 2300 هزینه گس را فوروارد می‌کند، قابل تنظیم نیست.

address payable>.send(uint256 amount) returns (bool)>

مقدار داده شده Wei را به آدرس ارسال کنید، در صورت خرابی، false را برمی‌گرداند، 2300 هزینه گس را فوروارد می‌کند، قابل تنظیم نیست.

address.call (bytes memory) returns (bool, bytes memory)

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

address .delegatecall (bytes memory) returns (bool, bytes memory)

موضوع DELEGATECALL سطح پایین با ظرفیت ترابری داده شده، شرایط موفقیت و بازگشت داده‌ها، فوروارد تمام گس موجود، قابل تنظیم است.

address.staticcall (bytes memory) returns (bool, bytes memory)

موضوع STATICCALL سطح پایین با ظرفیت ترابری داده شده، شرایط موفقیت و بازگشت داده‌ها، انتقال تمام گازهای موجود، قابل تنظیم است.

برای اطلاعات بیشتر به بخش آدرس مراجعه کنید.

هشدار

هنگام اجرای تابع قرارداد دیگر، باید از استفاده از ()call. اجتناب کنید زیرا بررسی نوع، بررسی وجود تابع و بسته بندی آرگومان را دور می زند.

هشدار

برخی از خطرات در استفاده از send وجود دارد: اگر عمق stack فراخوانی در 1024 باشد، انتقال با شکست مواجه می شود (این امر همیشه می تواند توسط تماس گیرنده انجام شود) و همچنین اگر گس گیرنده تمام شود، با شکست مواجه می شود. بنابراین به منظور انجام انتقال ایمن اتر، همیشه ارزش برگشتی send را بررسی کنید، از transfer استفاده کنید یا حتی بهتر: از الگویی استفاده کنید که گیرنده پول را برداشت کند.

هشدار

با توجه به این واقعیت که EVM فراخوانی به یک قرارداد غیرموجود را همیشه موفق می‌داند، Solidity شامل یک بررسی اضافی با استفاده از کد extcodesize هنگام انجام فراخوانی خارجی است. این تضمین می کند که قراردادی که در شرف فراخوانی است یا واقعاً وجود دارد (شامل کد است) یا استثنایی ایجاد می شود.

فراخوانی‌های سطح پایین که بر روی آدرس‌ها به جای نمونه‌های قرارداد کار می‌کنند (.call().delegatecall().staticcall().send() and .transfer()) شامل این بررسی نمی‌شوند، از نظر گس آنها را ارزان‌تر می‌کند. اما ایمنی کمتری نیز دارد.

توجه داشته باشید

قبل از نسخه 0.5.0، Solidity اجازه دسترسی به اعضای آدرس را توسط یک نمونه قرارداد، به عنوان مثال this.balance می‌داد. این کار در حال حاضر ممنوع است و یک تبدیل صریح به آدرس باید انجام شود: address(this).balance.

توجه داشته باشید

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

توجه داشته باشید

قبل از نسخه 0.5.0، call ، .delegatecall. و staticcall. فقط شرط موفقیت را برمی‌گرداند و نه داده‌های بازگشتی را.

توجه داشته باشید

قبل از نسخه 0.5.0، عضوی به نام callcode با معنایی مشابه اما کمی متفاوت از delegatecall وجود داشت.

مربوط به قرارداد(Contract Related)

 this (نوع قرارداد فعلی)

قرارداد فعلی، به صراحت قابل تبدیل به آدرس

(selfdestruct(address payable recipient

قرارداد فعلی را از بین ببرید، وجوه آن را به آدرس داده شده ارسال کنید و به اجرا خاتمه دهید. توجه داشته باشید که selfdestruct دارای برخی ویژگی‌های به ارث رسیده از EVM است:

  • تابع دریافت قرارداد دریافت کننده اجرا نمی شود.
  • قرارداد فقط در پایان معامله واقعاً از بین می‌رود و revert ممکن است تخریب را «لغو» کند.

علاوه بر این، تمام عملکردهای قرارداد جاری به طور مستقیم از جمله تابع فعلی قابل فراخوانی هستند.

توجه داشته باشید

قبل از نسخه 0.5.0، تابعی به نام (suicide) خودکشی با معنایی مشابه خودتخریبی (selfdestruct) وجود داشت.

نوع اطلاعات

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

ویژگی‌های زیر برای قرارداد نوع C موجود است:

type(C).name

نام قرارداد.

type(C).creationCode

آرایه بایت حافظه که حاوی بایت کد ایجاد قرارداد است. این را می توان در اسمبلی درون خطی برای ساخت روال های ایجاد سفارشی، به ویژه با استفاده از کد opcode create2 استفاده کرد. این دارایی در خود قرارداد یا هر قرارداد مشتق شده قابل دسترسی نیست. باعث می شود که بایت کد در بایت کد سایت تماس قرار گیرد و بنابراین ارجاعات دایره ای مانند آن امکان پذیر نیست.

type(C).runtimeCode

آرایه بایت حافظه که حاوی بایت کد زمان اجرا قرارداد است. این کدی است که معمولاً توسط سازنده C مستقر می‌شود. اگر C سازنده‌ای داشته باشد که از اسمبلی درون خطی استفاده می‌کند، ممکن است با بایت کد مستقر واقعی متفاوت باشد. همچنین توجه داشته باشید که کتابخانه ها بایت کد زمان اجرا خود را در زمان استقرار تغییر می دهند تا از تماس های معمولی محافظت کنند. محدودیت‌های مشابه با creationCode. برای این ویژگی نیز اعمال می‌شود.

علاوه بر ویژگی های بالا، ویژگی های زیر برای یک رابط نوع I موجود است:

type(I).interfaceId

یک مقدار bytes4 حاوی شناسه رابط EIP-165 رابط I داده شده است. این شناسه به عنوان XOR همه انتخابگرهای تابع تعریف شده در خود رابط – به استثنای همه توابع به ارث برده شده، تعریف می شود.

ویژگی های زیر برای یک عدد صحیح نوع T موجود است:

type(T).min

بزرگترین مقدار قابل نمایش با نوع T

کلمات کلیدی رزرو شده

این کلمات کلیدی در Solidity رزرو شده اند. آنها ممکن است در آینده بخشی از syntax  شوند:

afteraliasapplyautobytecasecopyofdefaultdefinefinalimplementsininline,

 letmacromatchmutablenullofpartialpromisereferencerelocatablesealedsizeof,

 .staticsupportsswitchtypedeftypeofvar