زبان Solidity – آموزش زبان سالیدیتی برای برنامهنویسی بلاکچین
فهرست مطالب
مقدمه
زبان Solidity اتریوم یک زبان قراردادمحور سطح بالا با نحوه کدنویسی شبیه جاوا اسکریپت است. کد سالیدیتی ابزاری برای ایجاد کد در سطح ماشین برای اجرا در ایویام (EVM) یا ماشین مجازی اتریوم (Ethereum Virtual Machine) است. کامپایلر سالیدیتی کدهای سطح بالا را دریافت کرده و آنها را به دستورالعملهایی سادهتر خرد میکند. کدهای سالیدیتی در داخل قراردادها قرار میگیرند. قرارداد در زبان سالیدیتی در نهایت به یک قرارداد هوشمند (Smart Contract) تبدیل میشود که برای کاربران نامی آشناست.
قراردادها در زبان Solidity
کد هر پروژهای که با زبان Solidity کدنویسی شود، بعد از نسخه زبان، شامل تعریف قرارداد میشود. برای مثال، یک قرارداد خالی با عنوان MyFirst چیزی شبیه کد زیر است:
version pragma ^0.4.19;contract MyFirst{}
لایههای فایلهای زبان Solidity
فایلهای منبع در زبان سالیدیتی میتوانند شامل تعداد دلخواهی از قراردادهای تعریف، از جمله راهنما (Directives) و راهنماهای پراگما (Pragma Directives) باشد.
ورژن پراگما
ورژن پراگما شامل نسخهای از کامپایلر سالیدیتی است که برای اجرای یک کد خاص باید مورد استفاده قرار گیرد.
version pragma ^0.4.00;
نکته: کد بالا مشخص میکند که این کد با استفاده از کامپایلری قدیمیتر از نسخه 0.4.0 نمیتواند اجرا شود. همچنین با کامپایلری که نسخه 0.5.0 باشد نیز کار نمیکند.
ایمپورت فایلهای دیگر
زبان Solidity اتریوم از فرمانهای Import که خیلی شبیه آنهایی هستند که در جاوا اسکریپت استفاده میشود، پشتیبانی میکند. با این حال، این زبان مفهوم default export را نمیشناسد.
در یک سطح global میتوانید از فرمانهای import با ساختار زیر استفاده کنید:
import "filename";
دستور بالا تمام سیمبلهای عمومی از «filename» را در سطح global فعلی وارد میکند.
import * as symbolName from "filename";
این دستور یک سیمبل عمومی جدید با نام symbolName ایجاد میکند که اعضای آن ، تمام سیمبل های عمومی فایل “filename” هستند.
کامنتها در زبان Solidity
درست مثل هر زبان کدنویسی دیگری، کامنتهای یک خطی و چند خطی در زبان Solidity امکانپذیر میباشند. برای کامنتهای یک خطی از دو علامت اسلش (//) در ابتدای خط کامنت استفاده میشود. کامنتهای چند خطی با اسلش ستاره (/*) شروع و با ستاره اسلش (*/) تمام میشوند.
حالا قبل از اینکه بیشتر به اجزای زبان سالیدیتی بپردازیم، لازم است بدانید که این زبان سه محل برای ذخیره آیتمهای گوناگون دارد:
- Storage: جایی که تمام متغیرهای قرارداد در آن قرار میگیرند. هر قراردادی فضای ذخیره خاص خودش را دارد و در بین فراخوانی توابع پایدار است.
- Memory: مقادیر موقتی را نگه داشته و در بین فراخوانی توابع (خارجی) پاک می شود و استفاده از آن به به صرفهتر است.
- Stack: متغیرهای محلی کوچک را نگهداری میکند و تقریبا استفاده از آن رایگان است، اما فقط میتواند مقادیر محدودی متغیر را ذخیره کند.
در حالت عادی معمولا شما نمیتوانید مشخص کنید که متغیرها کجا ذخیره شوند؛ چون هر بار که از آنها استفاده کنید، کپی میشوند.
انواع متغیر در زبان Solidity
حالا که کمی با محلهای ذخیره در زبان سالیدیتی آشنا شدهاید، میتوانیم با انواع متغیرها در این زبان آشنا شویم.
متغیر بولی (Boolean)
Keyword: Bool
مقادیر ممکن در مقادیر بولی (Boolean) شامل دو نوع ثابت میشود: True و False. از این مقادیر در زبان Solidity که با عبارت Bool تعریف میشوند برای بررسی تکمیل شرایط اجرای یک کد استفاده میشود.
متغیر Integer
Keyword: int/uint (uint8 to uint256 in steps of 8 (unsigned of 8 up to 256 bits) and int8 to int256)
این متغیر، مقادیر عددی صحیح با طولهای مختلف را مشخص میکند. برای مثال به کد زیر توجه کنید:
contract MySample{uint UnsignedInt =50;}
در کد بالا یک متغیر از نوع unit ساختیم که با عنوان UnsignedInt شناخته میشود و مقدار اولیه آن 50 است.
آدرس (Address)
Keyword: address
اعضای مقادیر نوع آدرس: مانده و انتقال (Balance & Transfer)
امکان موجودی گرفتن از یک آدرس با استفاده از گزینۀ مانده یا بالانس (Balance) و امکان انتقال اتر به این آدرس با استفاده از کارکرد انتقال (Transfer) وجود دارد. به کد زیر توجه کنید:
address x = 0x123;address myAddress = this;if (x.balance < 10 && myAddress.balance > = 10)x.transfer(10);
استرینگها (Strings / رشته ها)
برای مشخص کردن مقادیر استرینگ میتوان از علامت نقل قول تک قلابی ‘ و نقل قول دو قلابی ” استفاده کرد. به عنوان مثال برای انتقال دادهای با طول دلخواه از کد زیر استفاده میشود:
string language = "Solidity";
این نوع مقادیر میتوانند در عبارتهایی که حاوی عملگر (operator) هستند با یکدیگر تعامل برقرار کنند.
به نظر میرسد بحث بعدی مشخص شده باشد. اجازه دهید عملگرهای مختلف در زبان Solidity را بشناسیم.
عملگرهای زبان Solidity
عملگرهای سالیدیتی همان عملگرهای مورد استفاده در زبان جاوا اسکریپت هستند. زبان Solidity چهار نوع از عملگر دارد:
عملگرهای حسابی (Arithmetic Operators)
عملگرهای حسابی در سالدیتی خیلی سرراست هستند. در این زبان هم مانند بیشتر زبانهای برنامهنویسی دیگر از آنها استفاده میشود. عملگرهای حسابی شامل موارد زیر است:
- جمع: +
- تفریق: –
- ضرب: *
- تقسیم: /
- باقیمانده: %
همچنین سالیدیتی به شما امکان استفاده از عملگر حسابی توان را هم میدهد. به کد زیر توجه کنید:
uint x = 10 ** 3; // equal to 10^3 = 1000
عملگرهای افزایشی (Incremental Operators)
عملگرهای افزایشی در زبان Solidity شامل موارد زیر میشود:
a++, a--, ++a, --a, a+=1, a=a+1
قواعد و نحوه استفاده از این عملگرها درست شبیه زبانهای برنامهنویسی دیگر است.
عملگرهای بیتی (Bitwise Operators)
عملگرهای بیتی نیز در سالیدیتی وجود دارند. از آنها در موارد زیر میتوان استفاده کرد:
عملگر AND با نماد ‘&’، عملگر OR با نماد ‘|’، عملگر XOR با نماد ‘^’، عملگر نقیض با نماد ‘~’، عملگر شیفت به راست با نماد ‘>>’ ، عملگر شیفت به چپ با نماد ‘<<’
عملگرهای منطقی (Logical Operators)
عملگرهای منطقی در سالیدیتی با نمادهای مشابه زبانهای برنامهنویسی دیگر کار میکنند. عملگرهای منطقی شامل این موارد میشوند: ! (نفی منطقی)، && (و منطقی)، || (یا منطقی)، == (تساوی، برابری)، و =! (نابرابری). برای درک بهتر مقادیر و عملگرها در زبان سالیدیتی به کد زیر توجه کنید:
contract operators {
// Arithmetic Operators
// +,-,*,/, %, **
// Incremental Operators
// a++, a--, a+=1, a=a+1,++a,--a;
a=10;
a= a++; //here, output will be 10, because the value is first returned and then then increment is done
a=++a;
//Logical Operators !, &&, ||, ==, !=
isOwner = true && false;
var orValue= 0x02 | 0x01; // output would be 0x03
//Bitwise Operators~,>>, <<;
function Operators() {
// Initialize state variables here}}
بعضی وقتها به انواع دادههای پیچیدهتری نیاز هست. برای همین زبان Solidity استراکتها (structs) یا ساختارهای اطلاعاتی را در اختیار کاربران میگذارد.
ساختارهای داده در زبان Solidity
زبان سالیدیتی سه نوع از ساختارهای داده ارائه میدهد که در ادامه آنها را معرفی میکنیم.
استراکتها (Structs)
زبان سالیدیتی روشی ارائه میدهد که از طریق آن میتوان انواع جدیدی از نوع داده را به صورت استراکت تعریف کرد. استراکتها انواعی از دادههای تعریفشدۀ اختصاصی (شخصی سازی شده) هستند که میتوانند چندین متغیر را در یک گروه قرار بدهند. برای درک بهتر کارکرد آنها به کد زیر توجه کنید:
pragma solidity ^0.4.0;contract Ballot {struct Voter { // Structuint weight1, weight2, weight3;bool voted;address delegate1, delegate2, delegate3, delegate4;string name;uint vote1, vote2, vote3, vote4, vote5;uint height1, height2, height3 } }
نکته: استراکتها فقط میتوانند 16 عضو داشته باشند. هنگامی که از این مقدار تجاوز شود، این خطا ممکن است رخ دهد: Stack too Deep.
استراکتها به شما این امکان را میدهند که انواع پیچیدهتری از داده را که چندین ویژگی دارند ایجاد کنید.
آرایهها (Arrays)
حالا اگر مجموعهای از اطلاعات، برای مثال آدرسها را داشته باشیم چطور؟ خب، درست مثل باقی زبانهای برنامهنویسی، سالیدیتی هم آرایه دارد. آرایهها در زبان Solidity میتوانند یک اندازه ثابت در زمان کامپایل داشته باشند و یا به شکل پویا (داینامیک) باشند. برای درک بهتر نحوه کار آرایهها به کد زیر توجه کنید:
uint[3] fixed; //array of fixed length 3uint[] dynamic; //a dynamic array has no fixed size, it can keep growing
همچنین میتوانید یک آرایه از استراکتها ایجاد کنید. با استفاده از استراکت قبلی که به نام Voter ساختیم، این کار به شکل زیر انجام میشود:
Voter[] voting;
نکته: ایجاد یک آرایه بصورت عمومی باعث ایجاد خودکار یک متد دریافت (getter) برای آن میشود:
Voter[] public voting;
نگاشتها (Mappings)
مپینگها را میتوان به عنوان جداول هشی در نظر گرفت که بصورت مجازی مقداردهی میشوند که هر کلید اجتماعی وجود دارد و به یک مقدار نگاشت یا نسبت داده میشود. مقادیری که مقدار بایتی آن فقط صفر است: یعنی مقدار پیش فرض یک نوع داده.
نگاشتها به شکل زیر در زبان Solidity مشخص میشوند:
Mapping(_Keytype => _ValueType )
مقدار _Keytype میتواند هر نوع داده بجز آرایه داینامیک، قرارداد (Contract)، enum و استراکت باشد. به مثال زیر توجه کنید:
contract MappingExample {mapping(address => uint) public balances;function update(uint newBalance) {balances[msg.sender] = newBalance; }}contract MappingUser {function f() returns (uint) {MappingExample m = new MappingExample();m.update(100);return m.balances(this);}}
ساختارهای کنترل (Control Structures)
بیشتر ساختارهای کنترل موجود در جاوا اسکریپت در داخل سالیدیتی نیز در دسترس هستند. تنها موارد استثنا دو ساختار سوییچ (switch) و goto هستند. به این ترتیب ساختارهای کنترل در سالیدیتی شامل موارد زیر میشوند به همراه مفاهیم شناخته شده در زبان C یا JavaScript:
if, else, while, do, for, break, continue, return, ?
نکته: سالیدیتی دارای گزینهای برای تبدیل دادههای غیربولی به دادههای بولی، به شکلی که در زبانهای C و جاوا اسکریپت وجود دارد، ارائه نمیدهد.
برای درک بهتر ساختار کنترل (Control Structure) به مثال زیر دقت کنید:
contract ControlStructure {address public a;function ControlStructure>){// if-else can be used like thisif(input1==2)a=1;elsea=0;// while can be used like thiswhile(input1>=0){if(input1==5)continue;input1=input1-1;a++;}// for loop can be used like thisfor(uint i=0;i<=50;i++) { a++; if(a==4) break; } //do while can be used like this do { a--; } (while a>0);// Conditional Operator can be used like thisbool IsTrue = (a == 1)?true: false;/*will show an error becausethere is no type conversion from non-boolean to boolean*/if(1){}
فانکشنها (توابع)
حال میتوانیم ببینیم واحدهای قابل اجرای کد در داخل یک قرارداد در زبان Solidity چطور عمل میکنند. به این واحدها فانکشن (Functions) گفته میشود. فانکشنها در سالیدیتی مانند کد زیر بیان میشوند:
function sampleFunc(string name, uint amount) {}
عبارت بالا یک فانکشن با بدنه خالی است که دو پارامتر دریافت میکند: یک string و یک integer.
میتوانید این فانکشن را بصورت زیر فراخوانی کنید:
sampleFunc("Shashank", 10000);
مفهوم فانکشن کاملا مشابه زبانهای دیگر برنامه نویسی است. حال به بررسی فانکشن مادیفایر (Function Modifier) میپردازیم.
فانکشن مادیفایر (Function Modifier)
این قابلیت برای تغییر رفتار فانکشن (تابع) استفاده میشود. این شرط قبل از اجرای تابع (Call Function) چک میشود زیرا قبل از تعریف تابع در قرارداد هوشمند (Smart Contract) تعریف شده است.
مثال زیر برای زمانی است که شما بخواهید یک تابع kill Contract (غیرفعال سازی قرارداد) را فقط از طریق سازنده (Creator) یا مالک (Owner) تابع فراخوانی کنید.
contract FunctionModifiers{address public creator;function FunctionModifiers() {creator = msg.sender;}Modifier onlyCreator() {if(msg.sender!=creator){throw; }_; //resumes the function wherever the access modifier is used}function killContract() onlyCreator{ //function will not execute if an exception occursself-destruct(creator); }}
ارث بری (Inheritance)
زبان سالیدیتی از ارث بری چندگانه با کپی کد که شامل پلیمورفیسم است، پشتیبانی میکند.
contract Owned {address Owner ;function owned() {owner = msg.sender;}}contract Mortal is Owned { // 'is' keyword is used for inheritancefunction kill(){self-destruct(owner); }}contract User is Owned, Mortal //Multiple inheritance{string public UserName;function User(string _name){UserName = _name;}}
سخن پایانی
در این مقاله با زبان سالیدیتی و سینتکس دستورات آن آشنا شدیم.
اگر شما تا حدی با زبانهای برنامه نویسی نزدیک به جاوا اسکریپت آشنا هستید، اکنون زمان ورود شما به دنیای سالیدیتی و برنامه نویسی قراردادهای هوشمند است.
دیدگاه خود را ثبت کنید
سلام من در قرارداد خود در بی ان بی اسکن در قسمت قرارداد قسمت نوشتن می خوام فی تراکنش ها رو انجام بدم که با این ارور مواجه شدم باید چکار کنم
( arg = ” AddValue ” , coderType = ” uint256 ” , value = ” 2 %)
سلام. روز به خیر. در یک قرارداد bep20 چجوری بفهمیم که قرارداد قابل تغییر هست یا خیر؟ مثلا امکان اضافه کردن توکن به ساپلای کل وجود داره یا خیر؟ آخه چند روزی پیش یک توکنی ساپلایش یهو ده برابر کرد و قیمتش هم یهو یک سوم شد!!!
ممنون میشم لطف کنید کامل جواب بدین
سلام. وقت بخیر
برای پیدا کردن این موارد باید وایت پیپر هر رمزارز را با دقت چک کنید. علاوه بر اون الگوریتم حاکمیت هر پروژه را باید بدونید اکثر قراردادها توسط افرادی که حاکمیت پروژه را در اختیار دارن قابل تغییر است، به همین دلیل ارزهایی که جامعه حاکمیتی غیر متمرکزتری دارن امکان تغییرات ناگهانی و عجیب غریب در اونها احتمال کمتری داره.
عالی بود هیلی ممنون از مقاله خوبتون