کامپایلر سالیدیتی هنگام تولید بایت کد مورد نیاز برای استقرار قرارداد هوشمند، بخشی از اطلاعات مربوط به کامپایل را نیز به انتهای بایت کد اضافه میکند. این اطلاعات تحت عنوان متادیتا (Metadata) شناخته میشوند. در این بخش، محتوای متادیتای موجود در بایت کد را بررسی میکنیم.
ساده ترین نمونه قرارداد هوشمند
برای شروع، بیایید خروجی کامپایل یکی از ساده ترین قراردادهای ممکن را در سالیدیتی بررسی کنیم:
1 2 3 4 5 6 |
//SPDX-License-Identifier: MIT pragma solidity 0.8.20; contract Empty { constructor() payable {} } |
1 |
solc --optimize-runs 1000 --bin C.sol |
1 2 3 |
======= C.sol:Empty ======= Binary: 6080604052603e80600f5f395ff3fe60806040525f80fdfea26469706673582212203082dbb4f4db7e5d53b235f44d3e38f839dc82075e2cda9df05b88e6585bca8164736f6c63430008140033 |
برای قراردادی که هیچ کاری انجام نمیدهد، این حجم از بایت کد زیاد به نظر میرسد. اما دلیل آن چیست؟ بیایید دقیقتر بررسی کنیم.
اگر همین کد را با استفاده از گزینه --no-cbor-metadata
کامپایل کنیم:
1 |
solc --optimize-runs 1000 --bin --no-cbor-metadata C.sol |
1 2 3 |
======= C.sol:Empty ======= Binary: 6080604052600880600f5f395ff3fe60806040525f80fd |
این تفاوت بهوضوح نشان میدهد که بخش قابل توجهی از بایتکد اولیه بهخاطر اطلاعات متادیتا اضافه شده است. متادیتای CBOR شامل جزئیاتی درباره نسخه کامپایلر، گزینههای بهینه سازی، و مسیرهای وارد شده (import paths) در زمان کامپایل میباشد.
در ادامه، دقیقتر بررسی میکنیم که این متادیتا دقیقاً چه اطلاعاتی را در بر میگیرد و چه نقشی در فرآیند اجرای قرارداد دارد.
متادیتا در سالیدیتی
کامپایلر سالیدیتی بهصورت پیشفرض، در انتهای «کد اولیه واقعی» (initcode)، یک بخش اضافه از اطلاعات را قرار میدهد که به آن متادیتا گفته میشود. این متادیتا هنگام پایان اجرای کانستراکتور، همراه با بایت کد روی بلاکچین ذخیره میشود. در ادامه، بخش اضافی کد را مشاهده میکنید:
1 |
fea26469706673582212203082dbb4f4db7e5d53b235f44d3e38f839dc82075e2cda9df05b88e6585bca8164736f6c63430008140033 |
دو بایت انتهایی یعنی 0033
به کامپایلر اعلام میکند که باید «به اندازه 0x33 بایت به عقب برگرد» این همان بخشی است که متادیتا در آن قرار دارد. بهعبارت دیگر، تمام کدهایی که بین fe
(که اپکدی نامعتبر است و بهعنوان نشانگر آغاز متادیتا استفاده میشود) و 0033
قرار دارند، متعلق به متادیتا هستند.
میتوانیم با محاسبه، این مقدار را تأیید کنیم:
1 2 3 |
# fe و 0033 شامل نمیشوند >>> hex(len('a26469706673582212203082dbb4f4db7e5d53b235f44d3e38f839dc82075e2cda9df05b88e6585bca8164736f6c6343000814') // 2) # خروجی: '0x33' |
پس این رشته 0x33 (یا به عبارتی 51 بایت) دقیقاً چیست؟
برای درک بهتر این متادیتا، کافی است یک تغییر بسیار کوچک و ظاهراً بیاهمیت در کد منبع ایجاد کنیم. مثلاً تنها افزودن یک کامنت ساده.
1 2 3 4 5 6 7 |
//SPDX-License-Identifier: MIT pragma solidity 0.8.20; contract Empty { // nothing constructor() payable {} } |
در تصویر خروجی کامپایل، قسمتهایی که تغییر کردهاند زیر خطدار شدهاند، در حالی که منطق اجرایی کد هیچ تفاوتی نکرده است. در بخش بعدی، دقیقاً بررسی خواهیم کرد که این اطلاعات چگونه ساختار یافتهاند و چه دادههایی را درباره کد در خود ذخیره میکنند.
رمزگشایی متادیتا
در نگاه اول، ممکن است به نظر برسد که داریم بخشهایی از رشته را بهصورت تصادفی و بدون منطق استخراج میکنیم. اما کمی صبر کنید، همه چیز روشن خواهد شد.
بیایید ابتدا بخش هگزادسیمال داخل کادر آبی را بررسی کنیم:
1 2 |
>>> bytes.fromhex("69706673").decode("ASCII") 'ipfs' |
نتیجه، واژه ipfs
است.
حالا نوبت به کادر قرمز میرسد:
1 2 |
>>> bytes.fromhex("736f6c63").decode("ASCII") 'solc' |
نتیجه این بخش نیز solc
است.
این دو خروجی به ما سرنخ میدهند که محتوای این دادهها چیست: یک هش مربوط به IPFS و نسخه کامپایلر سالیدیتی.
هش IPFS
بخشی از بایت کد که در تصویر با رنگ زرد زیرخطدار شده و در کنار آن کادر فیروزه ای قرار دارد، را میتوان با استفاده از اسکریپت پایتون زیر تحلیل کرد (توجه داشته باشید که این مثال بر اساس نسخهای از کد است که شامل کامنت // nothing
میباشد):
1 2 3 4 5 6 |
import base58 hex_ipfs_hash = "12206a68b6b8bcc01ba559ec3adf7a387b6c4210a5dc69a05d038e9d17cae3fa373b" bytes_str = bytes.fromhex(hex_ipfs_hash) print(base58.b58encode(bytes_str).decode("utf-8")) # QmVW2XyafSxDtiSqirJRauuT5SaQtGnQYsxxyYHrFmRTEa |
Qm...RTEa
در واقع هش IPFS متادیتای تولیدشده توسط کامپایلر سالیدیتی است.
بر خلاف بخشهای قبلی (مثل ipfs
یا solc
) که بهصورت ساده با کدگذاری ASCII قابل خواندن بودند، این بخش از داده ها (یعنی کادر زرد و فیروزهای) بهصورت Base58 رمزگذاری شدهاند.
بهطور دقیقتر، داده هگزادسیمال "1220...373b"
ابتدا به بایت تبدیل میشود و سپس با استفاده از استاندارد Base58 به شکل خوانایی مانند Qm...
در میآید. که فرمت شناختهشدهای برای هش های IPFS است.
اگر فایل JSON متادیتای خروجی کامپایلر سالیدیتی را مستقیماً روی IPFS بارگذاری کنید، دقیقاً همین هش QmVW2Xyaf...
را دریافت خواهید کرد. در ادامه، محتوای این فایل JSON را نیز بررسی خواهیم کرد.
میتوانیم فایل JSON مربوط به متادیتا را بهصورت یک فایل واقعی ذخیره کنیم و سپس بررسی کنیم که آیا هش تولیدشده با همان هشی که در پایتون بهدست آوردیم، مطابقت دارد یا نه. برای این کار، باید ابزار خط فرمان IPFS روی سیستم نصب شده باشد (راهنمای نصب در مستندات رسمی IPFS).
ابتدا پوشهای برای خروجی ایجاد میکنیم و سپس کد را کامپایل میکنیم:
1 2 3 |
mkdir out solc --optimize-runs 1000 --bin --metadata C.sol --output-dir out # Compiler run successful. Artifact(s) can be found in directory "out". |
1 2 |
ipfs add -qr --only-hash out/Empty_meta.json # QmVW2XyafSxDtiSqirJRauuT5SaQtGnQYsxxyYHrFmRTEa |
QmVW2Xyaf...
که در اسکریپت پایتون محاسبه کرده بودیم مطابقت دارد. این تطابق نشان میدهد که متادیتای قراردادی که روی بلاکچین ذخیره شده، دقیقاً به فایل JSON خروجی کامپایلر اشاره دارد—و از طریق IPFS میتوان به آن دسترسی پیدا کرد.
آیا این کار باعث ایجاد برخورد در هش (Hash Collisions) نمیشود؟
اگر دو قرارداد هوشمند با کد منبع کاملاً یکسان و تنظیمات یکسان در کامپایلر، سورس تاییدشده خود را روی IPFS قرار دهند، بله. هش های IPFS آنها دقیقاً یکسان خواهد بود. اما این نهتنها مشکلی ایجاد نمیکند، بلکه اتفاقی کاملاً مطلوب است.
در واقع، ماهیت IPFS دقیقاً بر پایه همین اصل بنا شده است:
هر فایل منحصراً بر اساس محتوای آن شناسایی میشود. اگر دو فایل محتوای یکسانی داشته باشند، تنها یک نسخه از آن در شبکه ذخیره میشود و این باعث صرفه جویی در فضای ذخیره سازی میشود.
از طرف دیگر، در بلاکچین، قراردادهای هوشمند بهطور یکتا با ترکیب شناسه شبکه (chain ID) و آدرس قرارداد شناسایی میشوند، نه با هش IPFS.
بنابراین، اگرچه هشهای IPFS میتوانند در موارد مشابه یکسان باشند، اما این بههیچوجه به معنای تداخل در شناسایی قراردادها نیست، چون آدرسهای آنها در شبکه بلاکچین متفاوت است. این طراحی نهتنها ایمن است، بلکه بسیار کارآمد نیز هست.
بهدست آوردن نسخه سالیدیتی از متادیتا
در نهایت، اگر بخش قرارگرفته در کادر نارنجی را بررسی کنیم، متوجه میشویم که این قسمت دقیقاً نسخه کامپایلر سالیدیتی را نشان میدهد.
با تبدیل این مقادیر هگزادسیمال به عدد، به نتیجه زیر میرسیم:
1 2 3 4 5 6 7 8 |
>>> 0x00 # عدد اول نشان میدهد نسخه سالیدیتی با عدد 0 شروع میشود 0 >>> 0x08 # عدد دوم نسخه اصلی (major version) را مشخص میکند 8 >>> 0x14 # عدد سوم نسخه فرعی (minor version) است 20 |
چرا متادیتا در قراردادهای هوشمند وجود دارد؟
افزودن متادیتا به قرارداد هوشمند، حدود ۵۳ بایت اضافی به اندازه بایت کد اضافه میکند. این افزایش، هزینه استقرار قرارداد را بیشتر میکند:
-
۱۰,۶۰۰ گس برای ذخیره سازی بایت کد اضافی (۲۰۰ گس برای هر بایت)
-
بهعلاوه هزینه calldata:
-
۱۶ گس برای هر بایت غیرصفر
-
۴ گس برای هر بایت صفر
که مجموعاً تا حدود ۸۴۸ گس دیگر بهصورت تقریبی اضافه میشود.
-
با وجود این افزایش هزینه، چرا همچنان متادیتا را اضافه میکنند؟
متادیتایی که کامپایلر تولید میکند، شامل یک فایل JSON است که در آن هش کد منبع قرارداد ذخیره شده. این ساختار درک بهتری از فرآیند استقرار ایجاد میکند و برای افرادی که در مسیر یادگیری آموزش برنامه نویسی و توسعه قراردادهای هوشمند هستند، اهمیت زیادی دارد؛ چون اجازه میدهد کد مستقرشده را با سورسکد اصلی مطابقت دهند و بهصورت دقیق آن را تأیید کنند.
اگر حتی یک کاراکتر از کد منبع تغییر کند، مثلاً فقط یک کامنت یا فاصله، هش فایل JSON تغییر میکند و در نتیجه هش IPFS آن نیز متفاوت خواهد بود.
بهاینترتیب، متادیتا ابزاری ضروری برای ایجاد شفافیت و تضمین صحت و اصالت سورس کد قرارداد هوشمند در محیطی غیرقابلتغییر مانند بلاکچین است. این سازوکار، پایهگذار مفهوم «کد تأییدشده» (Verified Source Code) در پلتفرمهایی مانند Etherscan میباشد.
یک ترفند عجیب برای کاهش گس با استفاده از هش IPFS
یکی از روشهای واضح برای کاهش هزینه گس هنگام استقرار قرارداد، استفاده از گزینه --no-cbor-metadata
در کامپایلر سالیدیتی است. این گزینه باعث میشود متادیتا در انتهای بایتکد قرار نگیرد و در نتیجه اندازه بایت کد و هزینه گس کمتر شود.
اما اگر به متادیتا نیاز دارید—مثلاً برای تأیید رسمی قرارداد (Contract Verification)—باز هم میتوانید هزینه گس را کاهش دهید، آن هم با استفاده از یک ترفند کمتر شناختهشده: معدنکاوی (Mining) برای هش های IPFS بهینه از نظر گس.
چطور این ترفند کار میکند؟
وقتی قرارداد را استقرار میدهید، متادیتا (که شامل هش IPFS است) به انتهای بایت کد اضافه میشود و در قالب کال دیتا (calldata) به شبکه ارسال میشود. در این کال دیتا:
-
هر بایت صفر فقط ۴ گس مصرف میکند
-
اما هر بایت غیرصفر برابر با ۱۶ گس هزینه دارد
بنابراین اگر بتوانید کاری کنید که هش IPFS شما تعداد زیادی بایت صفر در خروجی هگزادسیمال داشته باشد، میتوانید هزینه گس را کاهش دهید.
چطور به چنین هشی برسیم؟
از آنجایی که هش IPFS به صورت غیرمستقیم از سورسکد (همراه با کامنتها) محاسبه میشود، میتوان با تغییر محتویات کامنتها، مثل افزودن یا تغییر جملات بیتأثیر در منطق، سعی کرد به هشی برسید که مقدار زیادی صفر در خروجی هگزادسیمال خود دارد.
نکته مهم: ما به دنبال صفر در نمایش هگزادسیمال هش هستیم، نه در نسخه Base58 آن (مثل Qm...
). زیرا آن چیزی که روی بلاکچین ثبت میشود، نسخه هگزادسیمال است.
راستی! برای دریافت مطالب جدید در کانال تلگرام یا پیج اینستاگرام سورس باران عضو شوید.
- انتشار: ۵ مرداد ۱۴۰۴
دسته بندی موضوعات
- آموزش ارز دیجیتال
- آموزش برنامه نویسی
- آموزش متنی برنامه نویسی
- اطلاعیه و سایر مطالب
- پروژه برنامه نویسی
- دوره های تخصصی برنامه نویسی
- رپورتاژ
- فیلم های آموزشی
- ++C
- ADO.NET
- Adobe Flash
- Ajax
- AngularJS
- apache
- ARM
- Asp.Net
- ASP.NET MVC
- AVR
- Bootstrap
- CCNA
- CCNP
- CMD
- CSS
- Dreameaver
- EntityFramework
- HTML
- IOS
- jquery
- Linq
- Mysql
- Oracle
- PHP
- PHPMyAdmin
- Rational Rose
- silver light
- SQL Server
- Stimulsoft Reports
- Telerik
- UML
- VB.NET&VB6
- WPF
- Xml
- آموزش های پروژه محور
- اتوکد
- الگوریتم تقریبی
- امنیت
- اندروید
- اندروید استودیو
- بک ترک
- بیسیک فور اندروید
- پایتون
- جاوا
- جاوا اسکریپت
- جوملا
- دلفی
- دوره آموزش Go
- دوره های رایگان پیشنهادی
- زامارین
- سئو
- ساخت CMS
- سی شارپ
- شبکه و مجازی سازی
- طراحی الگوریتم
- طراحی بازی
- طراحی وب
- فتوشاپ
- فریم ورک codeigniter
- فلاتر
- کانستراکت
- کریستال ریپورت
- لاراول
- معماری کامپیوتر
- مهندسی اینترنت
- هوش مصنوعی
- یونیتی
- کتاب های آموزشی
- Android
- ASP.NET
- AVR
- LINQ
- php
- Workflow
- اچ تی ام ال
- بانک اطلاعاتی
- برنامه نویسی سوکت
- برنامه نویسی موبایل
- پاسکال
- پایان نامه
- پایتون
- جاوا
- جاوا اسکریپت
- جی کوئری
- داده کاوی
- دلفی
- رباتیک
- سئو
- سایر کتاب ها
- سخت افزار
- سی اس اس
- سی پلاس پلاس
- سی شارپ
- طراحی الگوریتم
- فتوشاپ
- مقاله
- مهندسی نرم افزار
- هک و امنیت
- هوش مصنوعی
- ویژوال بیسیک
- نرم افزار و ابزار برنامه نویسی
- وردپرس