علاقمند به DLT
سالیدیتی ورژن 0.8.5
سالیدیتی ورژن 0.8.5
ورژن v0.8.5 سالیدیتی امکان تبدیل از bytes به مقادیر bytesNN را فراهم میکند، تابع verbatim را برای تزریق بایت کد (bytecode) دلخواه در Yul اضافه و چندین باگ کوچکتر را برطرف کردهاست.
سلام من سارا هستم و در این پست تغییرات جدیدی که زبان سالیدیتی ورژن 0.8.5 اعمال کرده و در بلاگ سالیدیتی گزارش داده رو ترجمه کردم. امیدوارم بتونید از این پست استفاده کنید و اگه ایرادی هست بهم اطلاع بدین، خوشحال میشم انتقادات و نظرات شما رو بدونم.
sarabavifard@gmail.com
پی نوشت سارا: حرف آ اول بعضی بولتها بخاطر این هستش که تمام بولتها راستچین بمونن.
فیچرهای های قابل توجه جدید
تبدیل بایت (Bytes Conversion)
داکیومنت کامل فیچرها را در اینجا میتوانید پیدا کنید.
این نسخه توانایی تبدیل بایتها و برشهای بایتها (bytes slices) به تایپهای fixed bytes مثل bytes1/… / bytes32 را معرفی می کند. در حالی که تبدیل بین تایپهای بایت با طول ثابت همیشه امکان پذیر بودهاست، اکنون امکان تبدیل تایپهای بایت با اندازه پویا به تایپهای بایت با طول ثابت نیز وجود دارد.
در صورتی که آرایه بایت از تایپِ بایتِ ثابتِ هدف طولانی تر باشد، در پایان کوتاه می شود:
function f(bytes calldatac) public view returns (bytes8) {
// If c is longer than 8 bytes, truncation happens
return bytes8(c);
}
فراخوانی ("12345678")f مقدار "12345678" را برمیگرداند، همانطور فراخوانی ("123456780")f. اگر آرایه از تایپِ ثابتِ هدف (target fixed type) کوتاهتر باشد، در صورت پایان با صفر پر میشود، بنابراین با فراخوانی ("1234")f مقدار "1234" برگرداننده خواهد شد.
یک مثال خوب برای استفاده از ویژگی تبدیل بایت، کاربرد آن در پروکسی ها است:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.5;
contract Proxy {
/// @dev Address of the client contract managed by this proxy
address client;
constructor(address _client) {
client = _client;
}
/// Forwards all calls to the client but performs additional checks for calls to "setOwner(address)".
function forward(bytes calldata _payload) external {
require(_payload.length >= 4);
bytes4 sig = bytes4(_payload[:4]);
if (sig == bytes4(keccak256("setOwner(address)"))) {
address owner = abi.decode(_payload[4:], (address));
require(owner != address(0), "Address of owner cannot be zero.");
}
(bool status,) = client.delegatecall(_payload);
require(status, "Forwarded call failed.");
}
}
قبلاً امکان انجام bytes4 sig = bytes4 (_payload [: 4]) وجود نداشت؛ در عوض مجبور بودید از موارد زیر استفاده کنید:
bytes4 sig =
_payload[0] |
(bytes4(_payload[1]) >> 8) |
(bytes4(_payload[2]) >> 16) |
(bytes4(_payload[3]) >> 24);
تابع Verbatim در Yul
داکیومنت کامل فیچرها را در اینجا پیدا کنید.
این نسخه مجموعهای از توابع verbatim را برای Yul معرفی میکند که به شما امکان میدهد بایت کد دلخواه را به باینری تزریق کنید. این کار در حال حاضر فقط از طریق pure Yul در دسترس است، یعنی از طریق اسمبلی درون خطی قابل دسترسی نیست.
اساساً دو مورد کاربردی (use-cases) وجود دارد (موارد بیشتر در زیر موجود است):
1. استفاده از آپکدهای ناشناخته برای Yul (بخاطر اینکه فقط پیشنهاد شده اند یا اینکه شما یک زنجیره ناسازگار با EVM را هدف قرار داده اید).
2. ایجاد توالی های خاص بایت کد (bytecode) که توسط بهینه ساز اصلاح نشده است.
توضیح آپکد
توابع verbatim<n>i_<m>o("<data>", ...) هستند، کجای که ...
- حرف n یک عدد دسیمال (decimal) بین 0 تا 99 است که تعداد اسلات ها / متغیرهای ورودی پشته را مشخص می کند،
- حرف m عدد دسیمال (decimal) بین 0 تا 99 است که تعداد اسلات ها / متغیرهای پشته خروجی را مشخص می کند،
- داده یا data یک رشته لیترال (string literal) است که شامل توالی بایت است.
توجه داشته باشید که هنگام استفاده از verbatim برخی از هشدارها وجود دارد. جزئیات مربوط به آن را می توان در داکیومنت یافت.
استفاده از آپکد جدید
به عنوان یک مثال عملی، می توان از این مثال برای تزریق آپکد EVM که به تازگی پیشنهاد شده است به باینری استفاده کرد. از آپکد BASEFEE پیشنهادی (در 0x48) استفاده کنید (به EIP-3198 و EIP-1559 مراجعه کنید) ، از آنجا که کامپایلر سالیدیتی در حال حاضر از این آپکد پشتیبانی نمی کند، می توان از verbatim برای اجرای آن در Yul استفاده کرد.
{
function basefee() -> out {
out := verbatim_0i_1o(hex"48")
}
sstore(0, basefee())
}
در اینجا مثال دیگری وجود دارد که دارای پارامتر ورودی برای verbatim است.
let x := calldataload(0)
// The hex"600202" corresponds to EVM instructions:
// PUSH 02 MUL
// That is, it multiplies x by 2.
let double := verbatim_1i_1o(hex"600202", x)
کد فوق منجر به آپکد dup1 برای بازیابی x می شود (بهینه ساز ممکن است مستقیماً از نتیجه آپکد calldataload استفاده کند) به طور مستقیم 600202 دنبال می شود. سپس کامپایلر کدی تولید می کند تا اسلات پشته ای را برای double اختصاص دهد و نتیجه را در آنجا ذخیره کند.
موردکاربردی برای Optimism
مورد کاربردی دوم می تواند برای راه حلهای لایه 2 مانند Optimism مفید باشد، اما همچنین راه حلهای دیگری مانند تجزیه و تحلیل بایت کد یا دیباگ کردن به ذهن خطور می کند. Optimism در حال حاضر از یک کامپایلر سالیدیتی سفارشی استفاده می کند، زیرا آنها یک قرارداد هوشمند را شبیه سازی می کنند که در آن هر تغییر در حالت (storage ، فراخوانی های خارجی و غیره) به طور مستقیم اجرا نمی شود، اما با فراخوانی مدیر قرارداد جایگزین می شود که تغییر را برای تأیید ذخیره می کند. مشکل در این مورد بررسی اینکه قرارداد با این محدودیت ها مطابقت دارد یا خیر (به عنوان مثال برای به طور دقیق با فراخوانی مدیر قرارداد برای هر تغییر)، خصوصاً اینکه این کار باید توسط مکانیزم تشخیص تقلب در زنجیره (the on-chain fraud detection mechanism) انجام شود. کاری که آنها انجام می دهند این است که بررسی می کنند هیچ یک از آپکدهای تغییر-حالت (state-changing opcodes) توسط قرارداد استفاده نشده باشد، به استثناء آپکدی که مدیر قرارداد را فراخوانی میکند. برای اینکه این استثناء به درستی تشخیص داده شود، توالی آپکدها منجر به این آپکدِ فراخوانی باید دارای فرم خاصی باشد و معمولاً بهینه ساز سالیدیتی (Solidity optimizer) مرتب سازی مجدد انجام می دهد و این فرم را از بین می برد. خوشبختانه، verbatim می تواند این مشکل را حل کند به گونه ای که Optimism دیگر نیازی به اتکا به یک کامپایلر سالیدیتی سفارشی ندارد و می تواند از تمام نسخه های بعدی کامپایلر سالیدیتی بدون تغییر استفاده کند.
کامپایلر optimism می تواند کدYul تولید شده توسط کامپایلر سالیدیتی را بگیرد، توابع کمکی Yul زیر را ضمیمه کرده و به صورت نوشتاری (syntactically) کلیهی تابع داخلی تغییر-حالت را که با ovm_-counterparts فراخوانی میشوند، جایگزین کند. به عنوان مثال، تمام فراخوانیهای sstore(x, y) با فراخوانی ovm_sstore(x, y)جایگذین میشود. پس از این جایگزینی، بهینه ساز Yul حتی می تواند دوباره اجرا شود. (این کد فقط sstore را نشان میدهد.)
/// Generic call to the manager contract.
function ovm_callManager(arguments, arguments_size, output_area, output_area_size) {
verbatim_4i_0o(
hex"336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b",
arguments,
arguments_size,
output_area,
output_area_size
)
}
// Call a manager function with two arguments
function ovm_kall_2i(signature, x, y) {
// Store touched memory in locals and restore it at the end.
let tmp_a := mload(0x00)
let tmp_b := mload(0x20)
let tmp_c := mload(0x40)
mstore(0, signature)
mstore(4, x)
mstore(0x24, y)
ovm_callManager(0, 0x44, 0, 0)
mstore(0x00, tmp_a)
mstore(0x20, tmp_b)
mstore(0x40, tmp_c)
}
// Replace all calls to ``sstore(x, y)`` by ``ovm_sstore(x, y)``
function ovm_sstore(x, y) {
// The hex code is the selector of
// the sstore function on the manager contract.
ovm_kall_2i(hex"22bd64c0", x, y)
}
گزارش کامل تغییرات
فیچرهای زبان:
اجازه تبدیل از bytes و bytes
slices به بایت bytes1 /… / bytes32.
- آ Yul: افزودن تابع داخل verbatim برای تزریق بایت کد دلخواه.
ویژگی های کامپایلر:
تولید کننده کد: قراردادن توابع کمکی برای panic codes به جای خطی کردن غیرشرطی (inlining unconditionally). اگر panics (checks) بیشتری قراردهید، این کار میتواند هزینهها را کاهش دهد. اما در جایی که panics کمتری استفاده شود هزینه ها افزایش پیدا میکند.
- آ EVM: نسخه پیش فرض EVM را روی "Berlin" تنظیم کنید.
- آ SMTChecker: تعریف تابع را می توان با برچسب سفارشی Natspec نوشت.
custom:smtchecker abstract-function-nondet
هنگامی که این تابع فراخوانی می شود با یک مقدار نامعین خلاصه میشود.
- استاندارد JSON / JSON ترکیبی: مصنوع جدید "functionDebugData" که حاوی آفستهای بایتکد از نقاط ورودی توابع و اطلاعات بیشتر در آینده.
- بهینه ساز Yul : ارزیابی keccak256(a, c) ، وقتی مقدار a در محل حافظه مِمُوری در زمان کامپایل مشخص شده باشد و c یک constant <= 32 باشد.
رفع باگها
- آ AST: اگر رشته UTF-8 معتبر نباشد، از مقدار Yul لیترال خروجی نمیگیرد.
- تولید کننده کد: خطای داخلی را هنگامی که تابع آرایه ها به متغییر های Storage اختصاص داده میشوند، برطرف میکند و نوع توابع میتواند به صورت ضمنی تبدیل شود اما یکسان نمیشوند.
- وقتی آرایه های تابع به متغیرهای storage اختصاص داده می شوند و اشکال داخلی را می توان ضمنی تبدیل کرد اما این تبدیل ها یکسان نیستند، خطای داخلی را برطرف میکند.
- گراف کنترل جریان: تصور میکند که اصلاح کننده های غیر اجرا شده از یک placeholder استفاده میکنند.
- گراف کنترل جریان: با توابعی که همیشه برای گزارش متغیرهای استفاده نشده یا متغیرهای unassigned به اکانت برمیگردند فراخوانی داخلی انجام میدهد.
- گراف فراخوانی تابع: خطای داخلی متصل به circular constant references را برطرف میکند.
- آ Name Resolver: در صورت عدم دسترسی مستقیم به shadowing name، هشدار shadowing صادر نمیکند.
- آ Natspec: اجازهی برچسب چندگانه return@ در متغیر حالت عمومی در داکیومت.
- آ SMTChecker: رفع خطای داخلی در تبدیل از بایت به بایت ثابت.
- آ SMTChecker: رفع خطای داخلی در فراخوانیهای های خارجی constructor.
- آ SMTChecker: رفع خطای داخلی struct constructor با عضو ثابت بایت که با رشته لیترال مقداردهی اولیه شدهاست.
- مکانهای منبع: تنظیم دقیق مکان منبعِ بلاکهای محدود شده
- استاندارد JSON : به طور دقیق اجازه تنظیمات درون خطی را تحت settings.optimizer.details میدهد.
- آ ype Checker: خطای کامپایلر داخلی مربوط به داشتن انواع mapping در پارامتر constructor را برای قراردادهای انتزاعی برطرف میکند.
- آ ype Checker: هنگام تلاش برای استفاده از یک نوع تابع خارجی نامعتبر در EVM های قبل از بیزانسی، خطای کامپایلر داخلی را برطرف میکند.
- تایپ Checker: خطای کامپایلر داخلی را در هنگام جایگزینی تابع دریافت (receive) اتر با یکی از پارامترهای مختلف در طول ارث بری برطرف میکند.
- تایپ Checker: ایجاد خطا در مورد نوع mapping (تودرتو) در پارامتر event یا error در خطاهای نوع fatal.
تغییرات AST:
- افزودن عضو hexValue برای رشته های Yul و لیترال hex.
سلام من سارا هستم و در این پست تغییرات جدیدی که زبان سالیدیتی ورژن 0.8.5 اعمال کرده و در بلاگ سالیدیتی گزارش داده رو ترجمه کردم. امیدوارم بتونید از این پست استفاده کنید و اگه ایرادی هست بهم اطلاع بدین، خوشحال میشم انتقادات و نظرات شما رو بدونم.
مطلبی دیگر از این انتشارات
ورژن 0.8.6 سالیدیتی
مطلبی دیگر از این انتشارات
تغییرات جدید ریمیکس برای سازگاری با هارد فورک لندن
مطلبی دیگر از این انتشارات
انواع مقدار تعریف شده توسط کاربر در سالیدیتی