مقدمه ای بر Bytecode و Opcode در زبان Solidity

مقدمه ای بر Bytecode و Opcode در زبان Solidity
  • مقدمه ای بر Bytecode و Opcode در زبان Solidity ، به گزارش آکادمی ریبیز Reybiz ، هرچقدر که در Smart Contract ها عمیق‌تر می‌شویم بیشتر با اصطلاحاتی چون PUSH1 ، SSTORE ، MSTORE و … مواجه می‌شویم.

    این‌ها دقیقا چه هستند و آیا ما باید به آنها اهمیت دهیم ؟
    برای درک درست این اصطلاحات باید در Ethereum Virtual‌ Machine یا همان EVM عمیق‌تر شویم.

    مقدمه ای بر Bytecode و Opcode در زبان Solidity

    صرافی تبدیل

    آکادمی ریبیز – یوسف فتحعلی زاده ؛ 

    زبان Solidity از نوع زبان‌های High Level Language است. ما آن را می‌فهمیم ولی ماشین آن را نمی‌فهمد. زمانی که ما یکی از کلاینت‌های اِتِریوم مانند geth را نصب می‌کنیم، EVM خودکار با آن نصب می‌شود.
    در واقع EVM یک سیستم عامل سبک می‌باشد که اختصاصا برای اجرای Smart Contract ها ساخته شده است.
    وقتی ما کدهای Solidity را کامپایل می‌کنیم، کدها به Bytecode تبدیل می‌شوند و این همان چیزیست که ماشین می‌فهمد.
    این یک نمونه Smart Contract بسیار ساده است :
    ;pragma solidity ^0.4.11

    }  contract MyContract

    ;uint i = (10 + 2) * 2

    {

    مقدمه ای بر Bytecode و Opcode در زبان Solidity

    این بخش کامپایل شده‌ی کدهای Solidity است :

    ۶۰۶۰۶۰۴۰۵۲۵b600080fd00a165627a7a7230582012c9bd00152fa1c480f6827f81515bb19c3e63bf7

    ed9ffbb5fda0265983ac7980029

    این چیزی نیست جز یک عدد بر مبنای شانزده (هگزا)، که از کدهایی که در Contract نوشتیم بدست آمده است و به آن Bytecode گفته می‌شود.

    در همین پنجره (details) در بخش Web3 Deploy چنین چیزی می‌بینیم :


    {
    from: web3.eth.accounts[0],
    data: ‘0x606060405260186000553415601357600080fd5b5b60368060216000396000f30060606

    ۰۴۰۵۲۵b600080fd00a165627a7a7230582012c9bd00152fa1c480f6827f81515bb19

    c3e63bf7ed9ffbb5fda0265983ac7980029′,
    gas: ‘4300000’
    }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== ‘undefined’) {
    console.log(‘Contract mined! address: ‘ + contract.address + ‘ transactionHash: ‘ + contract.transactionHash);
    }
    })

     حتما بخوانید : نحوه یادگیری زبان برنامه‌نویسی سالیدیتی (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 اصول 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_telegram و پیج اینستای ما@REYBIZ بپیوندید.

    هرگونه سوال و مشکلی نسبت به آموزش های داده شده داشتید با پشتیبانی سایت مطرح کنید.تیم ری بیز Reybiz بصورت ۲۴ ساعته جوابگوی سوالات شما است.

    ممکن است به این مطالب نیز علاقه‌مند باشید

    —————————-

    میانگین امتیازات ۵ از ۵
    از مجموع ۵ رای

    دیدگاهتان را بنویسید

    نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *