Solidity Bytecode and Opcode Basics

solidity bytecode

Solidity Bytecode and Opcode Basics

هرچه در نوشتن قراردادهای هوشمند عمیق تر می شویم، با اصطلاحاتی مانند “PUSH1″ ،”SSTORE” ،”CALLVALUE” و غیره مواجه خواهیم شد. آن ها چه هستند و آیا باید به آن ها اهمیت دهیم؟ برای دانستن و درک بهتر این دستورات، باید بیشتر به مفاهیم ماشین مجازی اتریوم (EVM) بپردازیم. در این مقاله، سعی خواهیم کرد برخی از اصول اولیه EVM را تا جای ممکن به صورت ساده توضیح دهیم.

مانند بسیاری از زبان های برنامه نویسی محبوب دیگر، Solidity یک زبان برنامه نویسی سطح بالا است. ما آن را درک می کنیم، اما ماشین توانایی درک آن را ندارد. کلاینت اتریوم مانند geth، با ماشین مجازی اتریوم همراه است. یک سیستم عامل سبک وزن که به طور ویژه برای اجرای قراردادهای هوشمند ایجاد شده است. وقتی کد solidity را با استفاده از کامپایلر solc کامپایل می کنیم، کد ما به یک بایت کد (bytecode) ترجمه می شود، چیزی که فقط EVM می تواند آن را درک کند.

اجازه دهید یک قرارداد بسیار ساده را به عنوان مثال در نظر بگیریم:

pragma solidity ^0.4.11;
contract MyContract {
    uint i = (10 + 2) * 2;
}

اگر این کد را در مرورگر ریمیکس اجرا کنیم و روی جزئیات قرارداد کلیک کنیم، اطلاعات زیادی را مشاهده می کنیم.

جزییات قرارداد هوشمند

در این حالت کد کامپایل شده به صورت زیر است:

60606040525b600080fd00a165627a7a7230582012c9bd00152fa1c480f6827f81515bb19c3e63bf7ed9ffbb5fda0265983ac7980029

این مقادیر طولانی نمایش هگزادسیمال قرارداد نهایی هستند که به بایت کد (bytecode) نیز معروف است. در بخش “Web3 Deploy” مرورگر ریمیکس، می بینیم:

...
{
from: web3.eth.accounts[0], 
data: '0x606060405260186000553415601357600080fd5b5b60368060216000396000f30060606040525b600080fd00a165627a7a7230582012c9bd00152fa1c480f6827f81515bb19c3e63bf7ed9ffbb5fda0265983ac7980029', 
gas: '4300000'
}, function (e, contract){
console.log(e, contract);
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
})

به زبان ساده، به این معنی است که وقتی قرارداد را مستقر می کنیم، به سادگی هگزادسیمال ها را در زیر data field با gas توصیه شده 4300000 مستقر می کنیم.

هرگاه بخواهیم در مورد EVM صحبت کنیم، باید به داده های هگزادسیمال فکر کنیم. آیا تا به حال فکر کرده اید که چرا جلوی آدرس کیف پول یا تراکنش شما یک “0x” وجود دارد؟ درست است، هر رشته کدی که با “0x” شروع شود، به این معنی است که در قالب هگزادسیمال است. داشتن “0x” در مقابل یک رشته هگزادسیمال اجباری نیست؛ زیرا EVM بدون در نظر گرفتن آن، هر مقداری را به عنوان هگزادسیمال در نظر می گیرد.

همچنین، کد عملیات که معروف به opcode است را در ادامه می توانیم مشاهده کنیم:

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

Opcodeها دستورالعمل های سطح پایین یک برنامۀ قابل خواندن توسط انسان هستند. همۀ Opcodeها معادلی متناظر با هگزادسیمال خود را دارند، به عنوان مثال، معادل «MSTORE» و « SSTORE » به ترتیب برابر با «0x52» و «0x55» است.

Pyethereum github repo و سپیدنامه قدیمی‌ تر Ethereum مرجع خوبی برای همۀ solidity opcode و مقادیر معادل هگزادسیمال آن ها هستند. همچنین، EVMیک ماشین پشته است. برای توضیح ساده، تصور کنید تکه‌ های نان را در مایکروویو روی هم چیده‌ اید، آخرین تکه‌ ای که در آن قرار می‌ دهید، اولین تکه‌ ای است که بیرون می‌ آورید. در اصطلاحات علم کامپیوتر، ما به آن LIFO می گوییم.

در محاسبات معمولی معادله خود را به این صورت می نویسیم:

// Answer is 14. we do multiplication before addition.
10 + 2 * 2

ماشین پشته ای، بر اساس اصل LIFO کار می کند:

2 2 * 10 +

به این معنی است که ابتدا “2” را در پشته قرار دهید، سپس “2” دیگر و سپس عمل ضرب را دنبال کنید. نتیجه، نشستن “4” در بالای پشته است. حالا یک عدد “10” را روی “4” اضافه کنید و در نهایت 2 عدد را با هم جمع کنید. مقدار نهایی پشته 14 می شود. به این نوع از محاسبات Postfix Notation یا Reverse Polish Notation می گویند.

عمل قرار دادن داده ها در پشته را دستور “PUSH” و عمل حذف داده ها از پشته را دستور “POP” می نامند. واضح است که رایج‌ ترین opcode که در مثال بالا می‌ بینیم «PUSH1» است که به معنای قرار دادن 1 بایت داده در پشته است.

بنابراین، این دستورالعمل:

PUSH1 0x60

کد بالا به معنای قرار دادن یک بایت مقدار “0x60” در پشته است. به صورت تصادفی، مقدار هگزادسیمال “PUSH1” نیز “0x60” است. با حذف “0x” غیر اجباری، می توانیم این منطق را در bytecode به عنوان “6060” بنویسیم.

بگذارید کمی جلوتر برویم:

PUSH1 0x60 PUSH1 0x40 MSTORE

با نگاهی دوباره به نمودار pyethereum opcode، مشاهده می کنیم که MSTORE (0x52) ،2 ورودی را دریافت می کند و هیچ خروجی تولید نمی کند. کدهای عملیاتی بالا به این معنی است:

PUSH1 (0x60): put 0x60 in the stack.
PUSH1 (0x40): put 0x40 in the stack.
MSTORE (0x52): allocate 0x60 of memory space and move to the 0x40 position.

bytecode حاصل به صورت زیر است:

6060604052

در واقع، ما همیشه این عدد جادویی “6060604052” را در ابتدای هر solidity bytecode می بینیم؛ زیرا این کد نشان می دهد قرارداد هوشمند چگونه bootstrap می شود.

توجه کنید که کدهای 0x40 یا 0x60 را نمی­ توان به عنوان عدد واقعی 40 یا 60 تفسیر کرد. از آنجایی که آن ها هگزادسیمال هستند، 40 در واقع معادل 64 (161x4) و 60 برابر با 96 (161x6) در واحد ده دهی دسیمال است.

به طور خلاصه، کاری که “PUSH1 0x60 PUSH1 0x40 MSTORE” انجام می دهد، اختصاص 96 بایت حافظه و انتقال نشانگر به ابتدای بایت 64 است. اکنون 64 بایت برای فضای scratch و 32 بایت برای ذخیره سازی موقت حافظه داریم.

در EVM، سه مکان برای ذخیره داده ها وجود دارد. اول، در پشته. ما فقط از اپکد “PUSH” برای ذخیره داده ها طبق مثال بالا استفاده کرده ایم. دوم، در حافظه (RAM) که در آن از اپکد “MSTORE” استفاده می کنیم و در آخر، در فضای ذخیره سازی دیسک که در آن از “SSTORE” برای ذخیره داده ها استفاده می کنیم. Gas مورد نیاز برای ذخیره داده ها در فضای storage گران ترین، و ذخیره سازی داده ها در stack ارزان ترین مبلغ است.

زبان اسمبلی

همچنین امکان نوشتن کل قرارداد هوشمند با استفاده از کدهای عملیاتی (opcodes) وجود دارد. اینجاست که زبان Solidity Assembly وارد می‌ شود. درک آن ممکن است بسیار سخت‌ تر باشد، اما اگر می‌ خواهید در مصرف gas صرفه‌ جویی کنید و کارهایی را انجام دهید که با solidity نمی‌ توان انجام داد، می‌ تواند مفید باشد.

coblocks-admin
ارسال دیدگاه

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