مقدمه ای بر Bytecode و Opcode در زبان Solidity ، به گزارش آکادمی ریبیز Reybiz ، هرچقدر که در Smart Contract ها عمیقتر میشویم بیشتر با اصطلاحاتی چون PUSH1 ، SSTORE ، MSTORE و … مواجه میشویم.
مقدمه ای بر Bytecode و Opcode در زبان Solidity
آکادمی ریبیز – یوسف فتحعلی زاده ؛
;pragma solidity ^0.4.11 |
} contract MyContract ;uint i = (10 + 2) * 2 { |
این بخش کامپایل شدهی کدهای Solidity است :
۶۰۶۰۶۰۴۰۵۲۵b600080fd00a165627a7a7230582012c9bd00152fa1c480f6827f81515bb19c3e63bf7
ed9ffbb5fda0265983ac7980029 |
این چیزی نیست جز یک عدد بر مبنای شانزده (هگزا)، که از کدهایی که در Contract نوشتیم بدست آمده است و به آن Bytecode گفته میشود.
در همین پنجره (details) در بخش Web3 Deploy چنین چیزی میبینیم :
… ۰۴۰۵۲۵b600080fd00a165627a7a7230582012c9bd00152fa1c480f6827f81515bb19 c3e63bf7ed9ffbb5fda0265983ac7980029′, |
حتما بخوانید : نحوه یادگیری زبان برنامهنویسی سالیدیتی (Solidity)
در نهایت چیزی که از Contract ما بر روی شبکه اِتِریوم قرار میگیرد همین عدد هگزا ای است که در فیلد data میبینید و برای این عمل به پرداخت ۴,۳۰۰,۰۰۰ gas نیاز دارد.
در واقع EVM با همه چیز به عنوان یک مقدار هگزا برخورد میکند. اگر تابحال برایتان سوال پیش آمده که چرا در ابتدای آدرس اَکانت های اِتِریوم یا هَشِ تراکنشها “۰x” را میبینیم، دلیل آن همین است.
در واقع “۰x” به این معنی است که مقداری که در جلوی آن قرار میگیرد، یک عدد بر مبنای شانزده است.
وجود “۰x” الزامی نیست، چراکه همانطور که گفته شد EVM با همه مقادیر به صورت هگزا برخورد می کند.
همینطور عباراتی به شکل زیر را میبینیم :
PUSH1 0x60 PUSH1 0x40 MSTORE PUSH1 0x18 PUSH1 0x0 SSTORE CALLVALUE ISZERO PUSH1 0x13 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST JUMPDEST PUSH1 0x36 DUP1 PUSH1 0x21 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x60 PUSH1 0x40 MSTORE JUMPDEST PUSH1 0x0 DUP1 REVERT STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 SLT 0xc9 0xbd STOP ISZERO 0x2f LOG1 0xc4 DUP1 0xf6 DUP3 PUSH32 0x81515BB19C3E63BF7ED9FFBB5FDA0265983AC798002900000000000000000000 |
به این بخش Operation Code یا همان Opcode گفته میشود.
این بخش برای انسان قابل خواندن است ولی درک آن بسیار مشکل می باشد. تمام این Operation ها در واقع معادلی در مبنای شانزده دارند. بطور مثال معادل MSTORE مقدار ۰x52 می باشد و یا SSTORE معادل ۰x55 میباشد. در ریپازیتوری گیتهاب اِتِریوم میتوانید لیست کامل Opcode ها را مشاهده نمایید.
ماشین EVM از نوع Stack Machine میباشد. برای درک سادهی اِستَکها تصور کنید قطعات نان را در فِر قرار میدهید. طبیعتا قطعه نان آخری که در فِر قرار دادهاید را، در هنگام خارج کردن نانها، اول از همه بیرون خواهید آورد. در علوم کامپیوتر به این فرآیند Last In First Out یا همان LIFO گفته میشود.
در محاسبات ریاضیاتی، ما چنین عمل میکنیم :
۱۰ + ۲ * ۲ ابتدا ۲ را در ۲ ضرب نموده و سپس با ۱۰ جمع میکنیم |
Stack Machine : 2 2 * 10 + |
به این معنی که : ابتدا ۲ را در اِستَک قرار بده، سپس عدد ۲ بعدی را قرار بده و بعد از آن عملیات ضرب را انجام بده. حاصل آن ۲ میشود که در راس اِستَک قرار میگیرد. سپس عدد ۱۰ را در اِستَک قرار بده (بعد از ۴) و این دو عدد را با هم جمع کن. مقدار نهایی استک ۱۴ خواهد بود.
عمل وارد کردن داده در استک PUSH و عمل خارج کردن داده POP نام دارد.
در Opcode ـی که بالا تر دیدم تعداد زیادی PUSH1 وجود دارد که به معنی قرار دادن ۱ بایت از داده ای مشخص در اِستَک می باشد. (در ادامه این مورد با مثالهای متعدد بیشتر توضیح داده میشود)
در نتیجه، این عبارت :
PUSH1 0x60 |
به معنی قرار دادن ۱ بایت با مقدار “۰x60” در اِستَک میباشد. تصادفا مقدار هگزایِ عملیات PUSH برابر با “۰x60” است که اگر عبارت غیر الزامی “۰x” را حذف کنیم، Bytecode بدست آمده برابر با “۶۰۶۰” میشود.
یک قدم پیش تر برویم :
PUSH1 0x60 PUSH1 0x40 MSTORE |
با نگاهی به لیست Opcode ها، میبینیم که MSTORE (هگزا : ۰x52) دو ورودی میگیرد و خروجیای ندارد.
Opcode بالا بدین معنی است :
PUSH1 0x60 .1
مقدار ۰x60 را وارد اِستَک کن
۲٫ PUSH1 0x40
مقدار ۰x40 را وارد اِستَک کن
۳٫ MSTORE 0x52
به مقدار ۰x60 از فضای حافظه را اختصاص بده و به نقطه ۰x40 برو
(در ادامه توضیح ساده تری از این Opcode میبینید)
نتیجه نهایی Bytecode اینچنین خواهد بود :
Result : 6060604052 |
در حقیقت ما همیشه مقدار “۶۰۶۰۶۰۴۰۵۲” را در ابتدای بایت کدهای Solidity میبینیم و دلیل این موضوع این است که Smart Contract ها با این Opcode راه اندازی (Bootstrap) میشوند.
در Opcode بالا، مقدار ۰x60 در مبنای ده برابر ۹۶ و مقدار ۰x40 در مبنای ده برابر ۶۴ است. در نتیجه Opcode بالا به این معنی است که :
۹۶ بایت از حافظه را تخصیص بده و مکان پوینتر را به ابتدای ۶۴ اُمین بایت تغییر بده.
در EVM دادهها در سه بخش میتوانند ذخیره شوند :
اِستَک : که نمونه آن PUSH میباشد و بالا تر مثال آن را دیدیم
حافظه تصادفی (RAM) : که نمونه آن MSTORE در Opcode ها میباشد
حافظه دیسک : که نمونه Opcode آن SSTORE است
در اِتِریوم برای ذخیره داده در حافظه دیسک باید gas پرداخت شود و به همین دلیل ذخیره داده در دیسک گرانترین و ذخیره داده در اِستَک ارزانترین است.
زبان Assembly
نوشتن کامل Smart Contract با Opcode ها امکان پذیر است و برای این منظور زبان اسمبلی Solidity ساخته شده است. طبیعتا نوشتن در این حالت بسیار سخت تر است، ولی برای نوشتن Contract هایی که در آنها باید در مصرف gas صرفه جویی شود و یا زمانی که کاری میخواهید انجام دهید که اجرای آن در Solidity امکان پذیر نیست، استفاده از زبان اسمبلی Solidity کارا خواهد بود.
در انتها
برای شروع به نوشتن Smart Contract ها نیازی به دانستن Opcode ها نداریم. اما دانستن آنها علاوه بر اینکه دانش ما را در این زمینه بالا میبرد، در هنگام Error Handling (که به خوبی در EVM انجام نمیشود) بسیار مفید می باشد.
هرگونه سوال و مشکلی نسبت به آموزش های داده شده داشتید با پشتیبانی سایت مطرح کنید.تیم ری بیز Reybiz بصورت ۲۴ ساعته جوابگوی سوالات شما است.
ممکن است به این مطالب نیز علاقهمند باشید
—————————-