زبان سالیدیتی برای اتریوم

در این راهنما، قصد داریم در مورد زبان سالیدیتی برای توسعه قراردادهای هوشمند اتریوم صحبت کنیم. در این مقاله به توضیح پلتفرم اتریوم نمی پردازیم چراکه از محدوده بحث ما خارج است.
در اینجا برخی از ویژگی های کلیدی این زبان جدید را مشاهده می کنید.
- سطح بالا بودن
- مشابه جاوا اسکریپت
- “کلاس ها” در دنیای اتریوم قرارداد نامیده می شوند
- می تواند عملکردهایی داشته باشد
- می تواند رویداد داشته باشد
به یاد داشته باشید که می توانید قرارداد را در مرورگر تست کنید. و آنها را در کیف پول رسمی قرار دهید.
قراردادها در زبان سالیدیتی
در داخل یک فایل سالیدیتی، میتوانید به تعداد مورد نیاز قرارداد داشته باشید، فقط، همانطور که اکنون میبینید، آنها را مانند یکدیگر یادداشت کنید.
contract SimpleDapp {
}
contract SimpleDappNew {
}
همچنین، همانند زبان های دیگر ما سازندههایی داریم که پس از اجرای قرارداد فراخوانی میشوند. برای ایجاد یک قرارداد، کافی است تابعی را با نام همان قرارداد فراخوانی کنید. می توانید متغیرها را به سازنده و همه چیز اضافه کنید، نگران نباشید!
در زبان سالیدیتی، امکان تعامل از یک قرارداد به قرارداد دیگر وجود دارد، برای انجام این کار، ما باید امکان:
1- برقراری ارتباط با نمونه دیگری از قرارداد.
2-ایجاد یک نمونه جدید از یک قرارداد را داشته باشیم.
می توانید هر دو گزینه را در کد زیر مشاهده کنید:
contract SomeOtherSimpleDapp{
//This will be a reference form the other instance of the class
SimpleDapp simpleDapp;
//This will be a NEW instance of the contract
SimpleDapp newInstanceOfSimpleDapp;
function SomeOtherSimpleDapp(address whereIsMyOtherContract){
simpleDapp = SimpleDapp(whereIsMyOtherContract);
newInstanceOfSimpleDapp = new SimpleDapp();
}
function getSimpleDappSomeVar() constant returns (uint) {
return simpleDapp.getSomeVar();
}
function getNewInstanceOfSimpleDappSomeVar() constant returns (uint) {
return newInstanceOfSimpleDapp.getSomeVar();
}
}
همانطور که می بینید، در بالا از توابع استفاده کردیم، این کار ما را به نقطه بعدی هدایت می کند: توابع.
توابع در زبان سالیدیتی
ما دو نوع تابع اصلی در سالیدیتی داریم، توابع ثابت و آنهایی که زنجیره را اصلاح می کنند. توابع ثابت به ما امکان می دهد بدون نیاز به پرداخت اضافی، داده ها را بررسی کنیم، برای انجام این کار، فقط باید کلمه ثابت را، همانطور که در زیر می بینید، به تابع اضافه کنیم.
//This is not a constant function, so we will pay for it.
function setSomeVar(uint myVar){
someVar = myVar;
}
//This is a constant function.
function getSomeVar() constant returns (uint){
return someVar;
}
همانطور که می بینید، شما باید نوع متغیری را که برمی گردانید اضافه کنید، ولی این عملکرد همانند جاوا اسکریپت نیست. شما میتوانید توابع را در داخل توابع دیگر فراخوانی کنید، اما اگر آنها ثابت نباشند، باید هزینه آن را بپردازید. به عنوان مثال:
contract Child{
uint8 public age = 1;
function birthDay() { <-- gas used: 26933
age = age + 1;
}
function nextYearIllBe() constant returns (uint8){ <-- gas used: 0
return age + 1;
}
function newBirthDay() { <-- gas used 26991
age = nextYearIllBe();
}
}
ساختارهای کنترلی
ساختارهای کنترلی تفاوت چندانی با جاوا اسکریپت ندارند و ساختارهای معمولی نیز دقیقاً به همین صورت هستند. در صورتی که اطلاعات بیشتری نیاز داشته باشید، می توانید سند را در اینجا بخوانید: ساختارهای کنترل
وراثت در زبان سالیدیتی
با توجه به مستندات قابل مشاهده، وراثت در سالیدیتی بسیار شبیه به نحوه استفاده پایتون از آن است . هنگامی که چندین قرارداد را می توان در یک قرارداد واحد به ارث برد، تنها یک قرارداد منفرد بر روی بلاک چین ایجاد می شود و کد تمام قراردادهای پایه در قرارداد ایجاد شده کپی می شود.
contract owned {
function owned() { owner = msg.sender; }
address owner;
}
// Use "is" to derive from another contract. Derived
// contracts can access all non-private members including
// internal functions and state variables. These cannot be
// accessed externally via `this`, though.
contract mortal is owned {
function kill() {
if (msg.sender == owner) selfdestruct(owner);
}
}
وراثت چندگانه نیز ممکن است، فقط مقادیر جداشده با کاما را که پدر خوانده می شود، بنویسید. اگر یک قرارداد بیش از یک بار از قراردادهای مختلف به ارث برده شود ، فقط یک شیء برای هر دو مصداق می یابد.
علاوه بر این، ما میتوانیم رابطها را نیز به راحتی پیادهسازی کنیم. هر قرارداد با یک تابع بدون بدنه، توسط کامپایلر یک رابط در نظر گرفته می شود. شما می توانید یک تابع را فقط دوباره در قرارداد فرزند بنویسید.
contract PriceFeed is owned, mortal, named("GoldFeed") {}
اگر یک سازنده آرگومان را بگیرد، باید در هدر ارائه شود:
کتابخانه ها
کتابخانه ها شبیه قراردادها هستند، اما هدف آنها این است که فقط یک بار در یک آدرس خاص قرار گیرند و کد آنها دوباره در قراردادها استفاده می شود. آنها در صورتی می توانند به متغیرهای حالت قرارداد فراخوان دسترسی داشته باشد که به شکل شفاف ارائه شده باشند.
انواع متغیر های سالیدیتی
این بخش حتی زمانی که از جاوا اسکریپت آمده اید آسان خواهد بود. سالیدیتی راه ایجاد متغیرها را تغییر می دهد تا بیان ایمنی از آنها داشته باشد. داده های اصلی عبارتند از:
- bool
- unint
- uint8 تا uint256
- bytes
- bytes32
- string
خبر بد این است که Fixed Point Numbers هنوز به طور کامل اجرا نشده است، همانطور که ویکی پدیا نوشته است: «عدد ممیز ثابت هنوز به طور کامل توسط سالیدیتی پشتیبانی نمی شوند. آنها را می توان بیان کرد، اما نمی توان به آنها ارجاع داد یا گرفت”.
داده های مختلف دیگری نیز وجود دارد که در سالیدیتی بسیار مفید هستند، یکی از آنها آدرسی است که یک byte var با طول 20 است. همچنین این آدرس باید دارای اعضای زیر باشد:
Balance: مقدار پولی که آدرس دارد را نشان می دهد.
Send(): به ما امکان می دهد پول را به آن مسیر بفرستیم. شما باید یک عدد صحیح را در داخل تابع ارسال کنید که تابع بداند چه مقدار باید ارسال کند. همیشه باید مقداری را که send() برمی گرداند بررسی کنید، چراکه می تواند False را برگرداند و در این صورت عملیات انجام نمی شود. ممکن است این مورد به این دلیل اتفاق بیفتد که مثلاً بنزینش تمام شود.
کار با Enums بسیار آسان است و به ما این امکان را می دهد که var هایی ایجاد کنیم که دارای مقادیر خاصی هستند. در داخل، آنها به عنوان اعداد صحیح کار می کنند، بنابراین کار زیادی برای برنامه مصرف نمی کنند. همچنین به همین دلیل وقتی تابعی را مینویسید که یک enum برمیگرداند، به uint تبدیل میشود و عدد را به شما برمیگرداند. قسمت خوب قضیه این هست که شما مجبور نیستید برای آن زحمت زیادی بکشید، چراکه enum ها در داخل اعداد صحیح هستند و به خوبی کار می کنند.
به عنوان مثال:
enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
ActionChoices choice;
ActionChoices constant defaultChoice = ActionChoices.GoStraight;
مکان داده های سالیدیتی
احتمالا به این فکر کرده اید که ما انواع داده را خیلی سریع به پایان رساندیم، بله درست است، به این دلیل که قبل از رفتن به داده های پیچیده باید موارد دیگری را توضیح دهیم.
هر نوع داده پیچیده، مثلا آرایش و ساختارها، دارای یک حاشیه نویسی اضافی به نام “موقعیت داده” است در مورد اینکه آیا در موری ذخیره شود یا در استوریج.
هنگامی که چیزی را از یک تابع برمی گردانیم، از متغیرهای مموری و زمانی که یک متغیر عادی در برنامه ایجاد می کنیم، از متغیرهای استوریج استفاده خواهیم کرد.
برای درک سریع تفاوت آنها، می توانیم بگوییم که وقتی از متغیرهای استوریج و مموری با هم در یک انتساب استفاده می کنیم، یک کپی از var مموری ایجاد می کند که به متغیر استوریج اختصاص می یابد. اما وقتی یک متغیر استوریج را به یک متغیر استوریج دیگر اختصاص میدهیم، نسخه دیگری ایجاد نمیکنیم بلکه فقط مرجع آن را ارسال میکنیم.
به طور پیش فرض، انتساب توسط کامپایلر انجام می شود، اما در صورت تمایل می توانیم نوع مکان داده را به صورت دستی تغییر دهیم. بنابراین اگر بخواهیم مرجع یک متغیر را در یک تابع برگردانیم می توانیم:
function g(uint[] storage storageArray) internal {}
Arrays
آرایه ها می توانند در زمان کامپایل اندازه ثابت یا پویا داشته باشند. در آرایههای استوریج، نوع عنصر میتواند دلخواه باشد (یعنی سایر آرایهها، نگاشتها یا ساختارها). در آرایه های مموری، نمی تواند یک نگاشت باشد و اگر آرگومان یک تابع قابل مشاهده عمومی باشد باید از نوع ABI باشد.
ایجاد آرایه هایی با طول متغیر در مموری با استفاده از کلمه کلیدی جدید قابل انجام است و امکان تغییر اندازه آرایه های حافظه وجود ندارد.
//In memory arrays
uint[] memory a = new uint[](7);
bytes memory b = new bytes(len);
//In storage array
uint[] x;
آرایه ها در زبان سالیدیتی دو عضو دارند :
length: می تواند اندازه آرایه را تغییر دهد.
push: برای اضافه کردن عناصر به انتهای آرایه، و طول جدید آن را برمی گرداند.
–
Structs
این داده دقیقاً مانند سایر زبان ها عمل می کنند و به ما کمک می کنند تا داده های جدیدی را برای قراردادهای خود تعریف کنیم. تعریف یکی از آنها:
struct Campaign {
address beneficiary;
uint fundingGoal;
uint numFunders;
uint amount;
متغیرهای جهانی در زبان سالیدیتی
وقتی در مورد اترها صحبت می کنیم، گاهی اوقات یک واحد بزرگ برای ارسال یا کار با آن وجود دارد، به همین دلیل، سالیدیتی واحدهای دیگری مانند Wei یا Szabo را در اختیار ما قرار می دهد.
بنابراین می توانید از آن واحدها در قراردادهای خود استفاده کنید تا کار برای شما آسان ترشود.
علاوه بر این، میتوانید از ثابتهای زمانی دیگر مانند سال، هفته، دقیقه، ثانیه استفاده کنید.
همچنین برخی از توابع دیگر مانند:
• block.blockhash(uint blockNumber) returns (bytes32): هش بلاک داده شده — تنها در 256 بلوک اخیر، به استثنای بلاک فعلی، کار می کند.
• block.coinbase (address): آدرس فعلی ماینر بلاک
• block.difficulty (uint): دشواری بلاک فعلی
• block.gaslimit (uint): محدودیت گاز بلاک فعلی
• block.number (uint): شماره بلاک فعلی
• block.timestamp (uint): زمان بلاک فعلی به عنوان ثانیه ای از زمان یونیکس
• msg.data (bytes): calldata کامل
• msg.gas (uint): گاز باقی مانده
• msg.sender (address): فرستنده پیام (تماس فعلی)
• msg.sig (bytes4): چهار بایت اول calldata (یعنی شناسه تابع)
• msg.value (uint): تعداد wei ارسال شده همراه با پیام
• now (uint): زمان بلوک فعلی (مستعار block.timestamp)
• tx.gasprice (uint): قیمت گاز معامله
• tx.origin (address): فرستنده تراکنش (زنجیره تماس کامل)
از بین تمامی ان توابع، موردی که من بیشتر استفاده می کنم msg است.
این پایان یکی از راهنمای سالیدیی است که در آن چیزهای زیادی در مورد سالیدیتی یاد گرفتید، اما برای یادگیری کامل بهتر است که ابتدا دوره آموزش مقدماتی سالیدیتی و همچنین دوره های دیگر از جمله دوره یادگیری سالیدیتی در 30 را مطالعه کنید. در مقالات بعدی نمونه های دیگر را بررسی خواهیم کرد.
دیدگاه ها