پرش به محتوای اصلی
Change page

سریال سازی ساده

آخرین ویرایش: @sipbikardi(opens in a new tab), ۲۴ مرداد ۱۴۰۲

سریال سازی ساده (SSZ) روش سریال سازی مورد استفاده در زنجیره Beacon است. این سریال سازی، شیوه سریال سازی RLP مورد استفاده در لایه اجرایی در همه جای لایه اجماع، به جز پروتکل کشف همتا را جایگزین می‌کند. SSZ طوری طراحی شده است که قطعی باشد و همچنین به شکلی کارآمد به فرمت درخت مرکل تبدیل شود. SSZ را می‌توان سیستمی در نظر گرفت که دو جزء دارد: یک طرح سریال سازی و یک طرح مرکلازیسیون (طرح مرکلازیسیون پروسه تبدیل اطلاعات به فرمت درخت مرکل را تعریف می‌کند) که برای افزایش کارآیی هنگام کار با ساختار داده‌های سریالی (دنباله‌دار) طراحی شده است.

SSZ چگونه کار می‌کند؟

سریالی کردن

SSZ یک طرح ایجاد دنباله است که خود توصیف نیست - بلکه بر طرحی تکیه دارد که باید از قبل شناخته شده باشد. هدف سریال سازی SSZ، نمایش اشیاء (objectها) با پیچیدگی دلخواه به صورت رشته هایی از بایت است. این یک فرآیند بسیار ساده برای "انواع پایه" است. عنصر به سادگی به بایت های هگزادسیمال تبدیل می شود. انواع پایه عبارتند از:

  • اعداد صحیح بدون علامت
  • بولین ها

برای انواع پیچیده "کامپوزیت"، سریال سازی پیچیده تر است، زیرا نوع ترکیب حاوی عناصر متعددی است که ممکن است انواع مختلف یا اندازه های مختلف یا هر دو را داشته باشند. در جایی که این اشیاء همگی دارای طول‌های ثابت هستند (یعنی اندازه عناصر بدون در نظر گرفتن مقادیر واقعی آنها همیشه ثابت است) سریال‌سازی صرفاً تبدیل هر عنصر در نوع ترکیبی است که به رشته‌های بایت انددیایی کوچک مرتب شده‌اند. این رشته‌های بایت به هم پیوسته اند. شیء سریال‌سازی‌شده نمایش فهرست بایتی عناصر با طول ثابت را به همان ترتیبی که در شیء بی‌سریال‌شده ظاهر می‌شوند، دارد.

برای انواع با طول های متغیر، داده های واقعی با یک مقدار "افست" در موقعیت آن عنصر در شی سریال شده جایگزین می شوند. داده های واقعی به پشته ای در انتهای شیء سریال شده اضافه می شود. مقدار افست شاخصی برای شروع داده های واقعی در پشته است که به عنوان یک اشاره گر به بایت های مربوطه عمل می کند.

مثال زیر نحوه عملکرد آفستینگ برای ظرفی با عناصر دارای طول ثابت و متغیر را نشان می دهد:

1
2 struct Dummy {
3
4 number1: u64,
5 number2: u64,
6 vector: Vec<u8>,
7 number3: u64
8 }
9
10 dummy = Dummy{
11
12 number1: 37,
13 number2: 55,
14 vector: vec![1,2,3,4],
15 number3: 22,
16 }
17
18 serialized = ssz.serialize(dummy)
19
نمایش همه

serialized ساختار زیر را خواهد داشت (در اینجا فقط به 4 بیت اضافه می شود، در واقعیت به 32 بیت اضافه می شود و نمایش int را برای وضوح حفظ می کند):

1[37, 0, 0, 0, 55, 0, 0, 0, 16, 0, 0, 0, 22, 0, 0, 0, 1, 2, 3, 4]
2------------ ----------- ----------- ----------- ----------
3 | | | | |
4 number1 number2 offset for number 3 value for
5 vector vector
6

برای وضوح به خطوط تقسیم می شود:

1[
2 37, 0, 0, 0, # little-endian encoding of `number1`.
3 55, 0, 0, 0, # little-endian encoding of `number2`.
4 16, 0, 0, 0, # The "offset" that indicates where the value of `vector` starts (little-endian 16).
5 22, 0, 0, 0, # little-endian encoding of `number3`.
6 1, 2, 3, 4, # The actual values in `vector`.
7]

این هنوز یک ساده‌سازی است - اعداد صحیح و صفر در شماتیک‌های بالا در واقع به عنوان بایتلیست‌ها ذخیره می‌شوند، مانند این:

1[
2 10100101000000000000000000000000 # little-endian encoding of `number1`
3 10110111000000000000000000000000 # little-endian encoding of `number2`.
4 10010000000000000000000000000000 # The "offset" that indicates where the value of `vector` starts (little-endian 16).
5 10010110000000000000000000000000 # little-endian encoding of `number3`.
6 10000001100000101000001110000100 # The actual value of the `bytes` field.
7]

بنابراین مقادیر واقعی برای انواع با طول متغیر در یک پشته در انتهای شیء سریال‌سازی شده با آفست‌های آن‌ها در موقعیت‌های صحیح خود در فهرست مرتب شده فیلدها ذخیره می‌شوند.

برخی موارد خاص نیز وجود دارند که نیاز به فرایند خاصی دارند، مانند نوع BitList که نیاز به اضافه کردن یک درپوش طول در حین سریال‌سازی و حذف در حین جداسازی دارد. جزئیات کامل در مشخصات SSZ(opens in a new tab) موجود است.

غیرسریالی سازی

برای غیر سریالی کردن این شی به طرحواره نیاز است. این طرح، چیدمان دقیق داده‌های سریال‌سازی‌شده را تعریف می‌کند، طوری که هر عنصر خاص را می‌توان از یک لکه بایت به یک شی معنادار با عناصر دارای نوع، مقدار، اندازه و موقعیت مناسب غیرسریالی کرد. این طرح واره است که به غیرسریالی کننده می گوید که چه مقادیری مقادیر واقعی هستند و چه مقادیری افست هستند. همه نام‌های فیلد زمانی که یک شی سریالی می‌شود، ناپدید می‌شوند، اما طبق طرحواره، پس از سریال‌سازی مجدداً نمونه‌سازی می‌شوند.

برای توضیح تعاملی در این مورد به ssz.dev(opens in a new tab) مراجعه کنید.

مرکلیزیشن

این شیء سریالی SSZ سپس می تواند مرکلیزه شود - که به یک نمایش درخت مرکل از همان داده ها تبدیل می شود. ابتدا تعداد تکه های 32 بایتی در شیء سریالی شده تعیین می شود. اینها "برگ"های درخت هستند. تعداد کل برگ ها باید توان 2 باشد تا هش کردن برگ ها با هم در نهایت یک ریشه درخت هش ایجاد کند. اگر به طور طبیعی اینطور نباشد، برگ های اضافی حاوی 32 بایت صفر اضافه می شود. به صورت نموداری:

1 hash tree root
2 / \
3 / \
4 / \
5 / \
6 hash of leaves hash of leaves
7 1 and 2 3 and 4
8 / \ / \
9 / \ / \
10 / \ / \
11 leaf1 leaf2 leaf3 leaf4
نمایش همه

همچنین مواردی وجود دارد که برگ های درخت به طور طبیعی به روشی که در مثال بالا انجام می شود به طور یکنواخت توزیع نمی کنند. به عنوان مثال، برگ 4 می تواند ظرفی با عناصر متعدد باشد که نیاز به "عمق" اضافی برای افزودن به درخت مرکل دارد و یک درخت ناهموار ایجاد می کند.

به جای ارجاع به این عناصر درختی به عنوان برگ X، گره X و غیره، می‌توانیم به آنها شاخص‌های تعمیم‌یافته بدهیم که با ریشه = 1 شروع می‌شود و در امتداد هر سطح از چپ به راست می‌شماریم. این شاخص کلی است که در بالا توضیح داده شد. هر عنصر در فهرست سریال‌سازی شده دارای یک شاخص تعمیم‌یافته برابر با 2**عمق + idx است که در آن idx موقعیت صفر نمایه‌شده آن در شیء سریال‌سازی‌شده و عمق تعداد سطوح در درخت مرکل است، که می تواند به عنوان لگاریتم پایه دو تعداد عناصر (برگ) تعیین شود.

شاخص های تعمیم یافته

یک شاخص تعمیم‌یافته یک عدد صحیح است که نشان‌دهنده یک گره در درخت مرکل دوتایی است که در آن هر گره دارای یک شاخص تعمیم‌یافته 2 ** عمق + شاخص در ردیف است.

1 1 --depth = 0 2**0 + 0 = 1
2 2 3 --depth = 1 2**1 + 0 = 2, 2**1+1 = 3
3 4 5 6 7 --depth = 2 2**2 + 0 = 4, 2**2 + 1 = 5...
4

این نمایش یک شاخص گره برای هر قطعه داده در درخت مرکل به دست می دهد.

اثبات چندگانه

ارائه فهرستی از شاخص‌های تعمیم‌یافته که یک عنصر خاص را نشان می‌دهد به ما امکان می‌دهد آن را نسبت به ریشه درخت هش تأیید کنیم. این ریشه نسخه پذیرفته شده ما از واقعیت است. هر داده ای که ما ارائه می کنیم را می توان با قرار دادن آن در مکان مناسب در درخت مرکل (که توسط شاخص تعمیم یافته آن تعیین می شود) و مشاهده ثابت ماندن ریشه در برابر آن واقعیت تأیید کرد. توابعی در مشخصات اینجا(opens in a new tab) وجود دارد که نحوه محاسبه حداقل مجموعه گره های مورد نیاز برای تأیید محتویات یک مجموعه خاص از شاخص های تعمیم یافته را نشان می دهند.

به عنوان مثال، برای تأیید داده های شاخص 9 در درخت زیر، به هش داده ها در شاخص های 8، 9، 5، 3، 1 نیاز داریم. هش (8،9) باید برابر با هش (4) باشد که با 5 هش می شود تا 2 تولید شود و هش با 3 برای تولید ریشه درخت 1 است. اگر داده‌های نادرستی برای 9 ارائه شود، ریشه تغییر می‌کند - ما این را تشخیص می‌دهیم و نمی‌توانیم شعبه را تأیید کنیم.

1* = data required to generate proof
2
3 1*
4 2 3*
5 4 5* 6 7
68* 9* 10 11 12 13 14 15
7

بیشتر بخوانید

آیا این مقاله مفید بود؟