সিম্পল সিরিয়ালাইজ
পেজ সর্বশেষ আপডেট: 1 ফেব্রুয়ারী, 2026
সিম্পল সিরিয়ালাইজ (SSZ) হলো বিকন চেইন-এ ব্যবহৃত সিরিয়ালাইজেশন পদ্ধতি। এটি পিয়ার ডিসকভারি প্রটোকল ছাড়া কনসেন্সাস লেয়ার-এর সর্বত্র এক্সিকিউশন লেয়ার-এ ব্যবহৃত RLP সিরিয়ালাইজেশনকে প্রতিস্থাপন করে। RLP সিরিয়ালাইজেশন সম্পর্কে আরও জানতে, রিকার্সিভ-লেংথ প্রিফিক্স (RLP) দেখুন। SSZ-কে ডিটারমিনিস্টিক এবং কার্যকরভাবে মার্কেলিজ (Merkleize) করার জন্য ডিজাইন করা হয়েছে। SSZ-এর দুটি উপাদান আছে বলে ধরে নেওয়া যেতে পারে: একটি সিরিয়ালাইজেশন স্কিম এবং একটি মার্কেলাইজেশন স্কিম যা সিরিয়ালাইজড ডেটা স্ট্রাকচারের সাথে কার্যকরভাবে কাজ করার জন্য ডিজাইন করা হয়েছে।
SSZ কীভাবে কাজ করে?
সিরিয়ালাইজেশন
SSZ হলো এমন একটি সিরিয়ালাইজেশন স্কিম যা সেলফ-ডেসক্রাইবিং নয় - বরং এটি এমন একটি স্কিমার উপর নির্ভর করে যা আগে থেকেই জানা থাকতে হবে। SSZ সিরিয়ালাইজেশনের লক্ষ্য হলো যেকোনো জটিলতার অবজেক্টকে বাইটের স্ট্রিং হিসেবে উপস্থাপন করা। "বেসিক টাইপ"-এর জন্য এটি একটি খুব সাধারণ প্রক্রিয়া। উপাদানটিকে কেবল হেক্সাডেসিমাল বাইটে রূপান্তর করা হয়। বেসিক টাইপগুলোর মধ্যে রয়েছে:
- আনসাইনড ইন্টিজার
- বুলিয়ান
জটিল "কম্পোজিট" টাইপের ক্ষেত্রে, সিরিয়ালাইজেশন আরও জটিল কারণ কম্পোজিট টাইপে একাধিক উপাদান থাকে যেগুলোর ধরন বা আকার ভিন্ন হতে পারে, অথবা উভয়ই হতে পারে। যেখানে এই অবজেক্টগুলোর সবগুলোর নির্দিষ্ট দৈর্ঘ্য থাকে (অর্থাৎ, উপাদানগুলোর আকার তাদের প্রকৃত মান নির্বিশেষে সর্বদা স্থির থাকবে) সেখানে সিরিয়ালাইজেশন হলো কম্পোজিট টাইপের প্রতিটি উপাদানকে লিটল-এন্ডিয়ান বাইটস্ট্রিংয়ে ক্রমানুসারে রূপান্তর করা। এই বাইটস্ট্রিংগুলো একসাথে যুক্ত করা হয়। সিরিয়ালাইজড অবজেক্টে ফিক্সড-লেংথ উপাদানগুলোর বাইটলিস্ট রিপ্রেজেন্টেশন থাকে ঠিক সেই ক্রমেই যেভাবে সেগুলো ডিসিরিয়ালাইজড অবজেক্টে উপস্থিত থাকে।
পরিবর্তনশীল দৈর্ঘ্যের (variable lengths) টাইপগুলোর জন্য, সিরিয়ালাইজড অবজেক্টে সেই উপাদানের অবস্থানে প্রকৃত ডেটা একটি "অফসেট" মান দ্বারা প্রতিস্থাপিত হয়। প্রকৃত ডেটা সিরিয়ালাইজড অবজেক্টের শেষে একটি হিপে (heap) যুক্ত হয়। অফসেট মান হলো হিপে প্রকৃত ডেটা শুরু হওয়ার ইনডেক্স, যা প্রাসঙ্গিক বাইটগুলোর পয়েন্টার হিসেবে কাজ করে।
নিচের উদাহরণটি দেখায় যে কীভাবে ফিক্সড এবং ভেরিয়েবল-লেংথ উভয় উপাদানযুক্ত একটি কন্টেইনারের জন্য অফসেটিং কাজ করে:
1
2 struct Dummy {3
4 number1: u64,5 number2: u64,6 vector: Vec<u8>,7 number3: u648 }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 for5 vector vector6
স্পষ্টতার জন্য লাইনে ভাগ করা হয়েছে:
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-বাইট চাঙ্কের সংখ্যা নির্ধারণ করা হয়। এগুলো হলো ট্রির "পাতা" (leaves)। পাতার মোট সংখ্যা অবশ্যই 2-এর পাওয়ার হতে হবে যাতে পাতাগুলোকে একসাথে হ্যাস করলে শেষ পর্যন্ত একটি একক হ্যাস-ট্রি-রুট তৈরি হয়। যদি স্বাভাবিকভাবে এমনটা না হয়, তবে 32 বাইট শূন্য ধারণকারী অতিরিক্ত পাতা যোগ করা হয়। ডায়াগ্রামের মাধ্যমে:
1 hash tree root2 / \3 / \4 / \5 / \6 hash of leaves hash of leaves7 1 and 2 3 and 48 / \ / \9 / \ / \10 / \ / \11 leaf1 leaf2 leaf3 leaf4এমন কিছু ক্ষেত্রও রয়েছে যেখানে ট্রির পাতাগুলো উপরের উদাহরণের মতো স্বাভাবিকভাবে সমানভাবে বণ্টিত হয় না। উদাহরণস্বরূপ, পাতা 4 এমন একটি কন্টেইনার হতে পারে যেখানে একাধিক উপাদান রয়েছে যার জন্য মার্কেল ট্রিতে অতিরিক্ত "গভীরতা" (depth) যোগ করার প্রয়োজন হয়, যা একটি অসম ট্রি তৈরি করে।
এই ট্রি উপাদানগুলোকে পাতা X, নোড X ইত্যাদি হিসেবে উল্লেখ করার পরিবর্তে, আমরা সেগুলোকে জেনারেলাইজড ইনডেক্স দিতে পারি, যা রুট = 1 দিয়ে শুরু হয় এবং প্রতিটি লেভেল বরাবর বাম থেকে ডানে গণনা করা হয়। এটিই উপরে ব্যাখ্যা করা জেনারেলাইজড ইনডেক্স। সিরিয়ালাইজড তালিকার প্রতিটি উপাদানের একটি জেনারেলাইজড ইনডেক্স থাকে যা 2**depth + idx-এর সমান, যেখানে idx হলো সিরিয়ালাইজড অবজেক্টে এর জিরো-ইনডেক্সড অবস্থান এবং depth হলো মার্কেল ট্রির লেভেলের সংখ্যা, যা উপাদান (পাতা) সংখ্যার বেস-টু লগারিদম হিসেবে নির্ধারণ করা যেতে পারে।
জেনারেলাইজড ইনডেক্স
জেনারেলাইজড ইনডেক্স হলো একটি ইন্টিজার যা একটি বাইনারি মার্কেল ট্রিতে একটি নোডকে উপস্থাপন করে যেখানে প্রতিটি নোডের একটি জেনারেলাইজড ইনডেক্স 2 ** depth + index in row থাকে।
1 1 --depth = 0 2**0 + 0 = 12 2 3 --depth = 1 2**1 + 0 = 2, 2**1+1 = 33 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 proof2
3 1*4 2 3*5 4 5* 6 768* 9* 10 11 12 13 14 157