মার্কল প্যাট্রিসিয়া ট্রাই
পৃষ্ঠাটি সর্বশেষ আপডেট করা হয়েছে: ১৪ ফেব্রুয়ারী, ২০২৬
ইথেরিয়ামের স্টেট (সমস্ত অ্যাকাউন্ট, ব্যালেন্স এবং স্মার্ট কন্ট্র্যাক্টের সমষ্টি), কম্পিউটার বিজ্ঞানে সাধারণত মার্কল ট্রি হিসাবে পরিচিত ডেটা স্ট্রাকচারের একটি বিশেষ সংস্করণে এনকোড করা হয়। এই কাঠামোটি ক্রিপ্টোগ্রাফির অনেক অ্যাপ্লিকেশনের জন্য দরকারী কারণ এটি ট্রিতে জড়িত ডেটার সমস্ত পৃথক অংশের মধ্যে একটি যাচাইযোগ্য সম্পর্ক তৈরি করে, যার ফলে একটি একক রুট মান পাওয়া যায় যা ডেটা সম্পর্কে বিভিন্ন বিষয় প্রমাণ করতে ব্যবহার করা যেতে পারে।
ইথেরিয়ামের ডেটা স্ট্রাকচারটি একটি 'মডিফায়েড মার্কল-প্যাট্রিসিয়া ট্রাই', এর এই নামকরণ করা হয়েছে কারণ এটি PATRICIA (প্র্যাকটিক্যাল অ্যালগরিদম টু রিট্রিভ ইনফরমেশন কোডেড ইন আলফানিউমেরিক) এর কিছু বৈশিষ্ট্য ধার করে, এবং কারণ এটি ইথেরিয়াম স্টেট গঠনকারী আইটেমগুলির কার্যকর ডেটা রিট্রিভালের জন্য ডিজাইন করা হয়েছে।
একটি মার্কল-প্যাট্রিসিয়া ট্রাই ডিটারমিনিস্টিক এবং ক্রিপ্টোগ্রাফিকভাবে যাচাইযোগ্য: একটি স্টেট রুট তৈরি করার একমাত্র উপায় হল স্টেটের প্রতিটি পৃথক অংশ থেকে এটি গণনা করা, এবং দুটি স্টেট যা অভিন্ন তা রুট হ্যাস এবং যে হ্যাসগুলি থেকে এটি তৈরি হয়েছে তা তুলনা করে সহজেই প্রমাণ করা যেতে পারে (একটি মার্কল প্রুফ)। বিপরীতভাবে, একই রুট হ্যাস দিয়ে দুটি ভিন্ন স্টেট তৈরি করার কোনো উপায় নেই, এবং ভিন্ন মান দিয়ে স্টেট পরিবর্তন করার যেকোনো প্রচেষ্টা একটি ভিন্ন স্টেট রুট হ্যাসের জন্ম দেবে। তাত্ত্বিকভাবে, এই কাঠামোটি সন্নিবেশ, সন্ধান এবং মুছে ফেলার জন্য O(log(n)) দক্ষতার 'হোলি গ্রেইল' প্রদান করে।
অদূর ভবিষ্যতে, ইথেরিয়াম একটি ভার্কল ট্রি কাঠামোতে স্থানান্তরিত করার পরিকল্পনা করছে, যা ভবিষ্যতের প্রোটোকল উন্নতির জন্য অনেক নতুন সম্ভাবনার দ্বার উন্মোচন করবে।
পূর্বশর্ত
এই পৃষ্ঠাটি আরও ভালভাবে বোঝার জন্য, হ্যাসopens in a new tab, মার্কল ট্রিopens in a new tab, ট্রাইopens in a new tab এবং সিরিয়ালাইজেশনopens in a new tab-এর প্রাথমিক জ্ঞান থাকা সহায়ক হবে। এই নিবন্ধটি একটি বেসিক রেডিক্স ট্রিopens in a new tab-এর বর্ণনা দিয়ে শুরু হয়েছে, তারপর ধীরে ধীরে ইথেরিয়ামের আরও অপ্টিমাইজড ডেটা স্ট্রাকচারের জন্য প্রয়োজনীয় পরিবর্তনগুলি উপস্থাপন করা হয়েছে।
বেসিক রেডিক্স ট্রাই
একটি বেসিক রেডিক্স ট্রাই-তে, প্রতিটি নোড নিম্নলিখিত রূপে দেখায়:
1 [i_0, i_1 ... i_n, value]যেখানে i_0 ... i_n বর্ণমালার প্রতীকগুলিকে (প্রায়শই বাইনারি বা হেক্স) প্রতিনিধিত্ব করে, value হল নোডের টার্মিনাল মান, এবং i_0, i_1 ...-এর মধ্যেকার মানগুলি। i_n স্লটগুলি হয় NULL অথবা অন্য নোডের পয়েন্টার (আমাদের ক্ষেত্রে, হ্যাস)। এটি একটি বেসিক (কী, মান) স্টোর গঠন করে।
ধরুন আপনি কী-মান জোড়ার একটি সেটের উপর একটি ক্রম বজায় রাখার জন্য একটি রেডিক্স ট্রি ডেটা স্ট্রাকচার ব্যবহার করতে চেয়েছিলেন। dog কী-এর সাথে ট্রাই-তে বর্তমানে ম্যাপ করা মানটি খুঁজে পেতে, আপনাকে প্রথমে dog-কে বর্ণমালার অক্ষরে রূপান্তর করতে হবে (যা 64 6f 67 দেবে), এবং তারপর সেই পথ অনুসরণ করে ট্রাই-এর গভীরে যেতে হবে যতক্ষণ না আপনি মানটি খুঁজে পান। অর্থাৎ, আপনি ট্রাই-এর রুট নোড খুঁজে পেতে একটি ফ্ল্যাট কী/মান DB-তে রুট হ্যাস সন্ধান করে শুরু করবেন। এটি অন্য নোডগুলিতে নির্দেশকারী কী-গুলির একটি অ্যারে হিসাবে উপস্থাপিত হয়। আপনি ইনডেক্স 6-এর মানটিকে কী হিসাবে ব্যবহার করবেন এবং এক স্তর নিচের নোডটি পেতে ফ্ল্যাট কী/মান DB-তে এটি সন্ধান করবেন। তারপর পরবর্তী মানটি দেখতে ইনডেক্স 4 বেছে নিন, তারপর ইনডেক্স 6, এবং এভাবেই চলতে থাকবে, যতক্ষণ না আপনি পথটি অনুসরণ করেন: root -> 6 -> 4 -> 6 -> 15 -> 6 -> 7, আপনি নোডের মান সন্ধান করবেন এবং ফলাফল ফেরত দেবেন।
'ট্রাই' এবং অন্তর্নিহিত ফ্ল্যাট কী/মান 'DB'-তে কিছু সন্ধান করার মধ্যে একটি পার্থক্য আছে। উভয়ই কী/মান বিন্যাস সংজ্ঞায়িত করে, কিন্তু অন্তর্নিহিত DB একটি কী-এর জন্য একটি ঐতিহ্যবাহী ১-ধাপের সন্ধান করতে পারে। ট্রাই-তে একটি কী সন্ধান করার জন্য উপরে বর্ণিত চূড়ান্ত মানটিতে পৌঁছাতে একাধিক অন্তর্নিহিত DB সন্ধানের প্রয়োজন হয়। আসুন অস্পষ্টতা দূর করতে পরেরটিকে পথ হিসাবে উল্লেখ করি।
রেডিক্স ট্রাই-এর জন্য আপডেট এবং ডিলিট অপারেশনগুলি নিম্নরূপ সংজ্ঞায়িত করা যেতে পারে:
1 def update(node_hash, path, value):2 curnode = db.get(node_hash) if node_hash else [NULL] * 173 newnode = curnode.copy()4 if path == "":5 newnode[-1] = value6 else:7 newindex = update(curnode[path[0]], path[1:], value)8 newnode[path[0]] = newindex9 db.put(hash(newnode), newnode)10 return hash(newnode)1112 def delete(node_hash, path):13 if node_hash is NULL:14 return NULL15 else:16 curnode = db.get(node_hash)17 newnode = curnode.copy()18 if path == "":19 newnode[-1] = NULL20 else:21 newindex = delete(curnode[path[0]], path[1:])22 newnode[path[0]] = newindex2324 if all(x is NULL for x in newnode):25 return NULL26 else:27 db.put(hash(newnode), newnode)28 return hash(newnode)সবকটি দেখুনএকটি "মার্কল" রেডিক্স ট্রি ডিটারমিনিস্টিকভাবে-জেনারেটেড ক্রিপ্টোগ্রাফিক হ্যাস ডাইজেস্ট ব্যবহার করে নোডগুলিকে লিঙ্ক করার মাধ্যমে নির্মিত হয়। এই কন্টেন্ট-অ্যাড্রেসিং (কী/মান DB-তে key == keccak256(rlp(value))) সঞ্চিত ডেটার একটি ক্রিপ্টোগ্রাফিক ইন্টিগ্রিটি গ্যারান্টি প্রদান করে। যদি একটি প্রদত্ত ট্রাই-এর রুট হ্যাস সর্বজনীনভাবে জানা থাকে, তবে অন্তর্নিহিত লিফ ডেটাতে অ্যাক্সেস আছে এমন যে কেউ একটি প্রমাণ তৈরি করতে পারে যে ট্রাইটি একটি নির্দিষ্ট পথে একটি প্রদত্ত মান অন্তর্ভুক্ত করে, যা প্রতিটি নোডের হ্যাস প্রদান করে যা একটি নির্দিষ্ট মানকে ট্রি রুটের সাথে যুক্ত করে।
একজন আক্রমণকারীর পক্ষে এমন একটি (পথ, মান) জোড়ার প্রমাণ দেওয়া অসম্ভব যার অস্তিত্ব নেই কারণ রুট হ্যাসটি চূড়ান্তভাবে এর নীচের সমস্ত হ্যাসের উপর ভিত্তি করে তৈরি। যেকোনো অন্তর্নিহিত পরিবর্তন রুট হ্যাস পরিবর্তন করবে। আপনি হ্যাসকে ডেটা সম্পর্কে কাঠামোগত তথ্যের একটি সংকুচিত উপস্থাপনা হিসাবে ভাবতে পারেন, যা হ্যাশিং ফাংশনের প্রি-ইমেজ সুরক্ষা দ্বারা সুরক্ষিত।
আমরা একটি রেডিক্স ট্রি-এর একটি পারমাণবিক একককে (যেমন, একটি একক হেক্স অক্ষর, বা ৪ বিট বাইনারি সংখ্যা) একটি "নিবল" হিসাবে উল্লেখ করব। উপরে বর্ণিত হিসাবে, একবারে একটি নিবল করে একটি পথ অতিক্রম করার সময়, নোডগুলি সর্বাধিক ১৬টি চাইল্ডকে উল্লেখ করতে পারে তবে একটি মান উপাদান অন্তর্ভুক্ত করে। তাই, আমরা সেগুলিকে ১৭ দৈর্ঘ্যের একটি অ্যারে হিসাবে উপস্থাপন করি। আমরা এই ১৭-উপাদান বিশিষ্ট অ্যারেগুলিকে "ব্রাঞ্চ নোড" বলি।
মার্কল প্যাট্রিসিয়া ট্রাই
রেডিক্স ট্রাই-এর একটি প্রধান সীমাবদ্ধতা রয়েছে: এগুলি অদক্ষ। আপনি যদি একটি (পথ, মান) বাইন্ডিং সঞ্চয় করতে চান যেখানে পথটি, ইথেরিয়ামের মতো, ৬৪ অক্ষর দীর্ঘ ( bytes32-তে নিবলের সংখ্যা), তাহলে প্রতি অক্ষরের জন্য একটি স্তর সঞ্চয় করতে আমাদের এক কিলোবাইটের বেশি অতিরিক্ত জায়গার প্রয়োজন হবে, এবং প্রতিটি সন্ধান বা মুছে ফেলার জন্য পুরো ৬৪টি ধাপ লাগবে। নিম্নলিখিত অংশে প্রবর্তিত প্যাট্রিসিয়া ট্রাই এই সমস্যার সমাধান করে।
অপ্টিমাইজেশান
মার্কল প্যাট্রিসিয়া ট্রাই-এর একটি নোড নিম্নলিখিতগুলির মধ্যে একটি:
NULL(খালি স্ট্রিং হিসাবে উপস্থাপিত)branchএকটি ১৭-আইটেম নোড[ v0 ...v15, vt ]leafএকটি ২-আইটেম নোড[ encodedPath, value ]extensionএকটি ২-আইটেম নোড[ encodedPath, key ]
৬৪ অক্ষরের পথগুলির সাথে এটি অনিবার্য যে ট্রাই-এর প্রথম কয়েকটি লেয়ার অতিক্রম করার পরে, আপনি এমন একটি নোডে পৌঁছাবেন যেখানে নিচের দিকের পথের অন্তত কিছু অংশের জন্য কোনো ভিন্ন পথ বিদ্যমান নেই। পথ বরাবর ১৫টি পর্যন্ত স্পার্স NULL নোড তৈরি করা এড়াতে, আমরা একটি [ encodedPath, key ] ফর্মের এক্সটেনশন নোড সেট আপ করে ডিসেন্টকে শর্টকাট করি, যেখানে encodedPath এগিয়ে যাওয়ার জন্য "আংশিক পথ" ধারণ করে (নিচে বর্ণিত একটি কমপ্যাক্ট এনকোডিং ব্যবহার করে), এবং key পরবর্তী DB অনুসন্ধানের জন্য ব্যবহৃত হয়।
লিফ নোডের জন্য, যা encodedPath-এর প্রথম নিবলে একটি ফ্ল্যাগ দ্বারা চিহ্নিত করা যেতে পারে, পথটি পূর্ববর্তী সমস্ত নোডের পথের খণ্ডাংশ এনকোড করে এবং আমরা সরাসরি মান সন্ধান করতে পারি।
তবে উপরের এই অপ্টিমাইজেশানটি অস্পষ্টতা তৈরি করে।
নিবলে পথ অতিক্রম করার সময়, আমরা বিজোড় সংখ্যক নিবল দিয়ে শেষ করতে পারি, কিন্তু কারণ সমস্ত ডেটা বাইট ফরম্যাটে সংরক্ষিত হয়। উদাহরণস্বরূপ, নিবল 1 এবং নিবল 01 এর মধ্যে পার্থক্য করা সম্ভব নয় (উভয়কেই <01> হিসাবে সংরক্ষণ করতে হবে)। বিজোড় দৈর্ঘ্য নির্দিষ্ট করতে, আংশিক পথের আগে একটি ফ্ল্যাগ যুক্ত করা হয়।
স্পেসিফিকেশন: ঐচ্ছিক টার্মিনেটর সহ হেক্স সিকোয়েন্সের কমপ্যাক্ট এনকোডিং
উপরে বর্ণিত বিজোড় বনাম জোড় অবশিষ্ট আংশিক পথের দৈর্ঘ্য এবং লিফ বনাম এক্সটেনশন নোড উভয়ের ফ্ল্যাগিং যেকোনো ২-আইটেম নোডের আংশিক পথের প্রথম নিবলে থাকে। এর ফলস্বরূপ নিম্নলিখিতগুলি ঘটে:
| হেক্স অক্ষর | বিট | নোডের প্রকার আংশিক | পথের দৈর্ঘ্য |
|---|---|---|---|
| 0 | 0000 | এক্সটেনশন | জোড় |
| 1 | 0001 | এক্সটেনশন | বিজোড় |
| 2 | 0010 | টার্মিনেটিং (লিফ) | জোড় |
| 3 | 0011 | টার্মিনেটিং (লিফ) | বিজোড় |
জোড় অবশিষ্ট পথের দৈর্ঘ্যের জন্য (0 বা 2), আরেকটি 0 "প্যাডিং" নিবল সর্বদা অনুসরণ করবে।
1 def compact_encode(hexarray):2 term = 1 if hexarray[-1] == 16 else 03 if term:4 hexarray = hexarray[:-1]5 oddlen = len(hexarray) % 26 flags = 2 * term + oddlen7 if oddlen:8 hexarray = [flags] + hexarray9 else:10 hexarray = [flags] + [0] + hexarray11 # hexarray now has an even length whose first nibble is the flags.12 o = ""13 for i in range(0, len(hexarray), 2):14 o += chr(16 * hexarray[i] + hexarray[i + 1])15 return oসবকটি দেখুনউদাহরণ:
1 > [1, 2, 3, 4, 5, ...]2 '11 23 45'3 > [0, 1, 2, 3, 4, 5, ...]4 '00 01 23 45'5 > [0, f, 1, c, b, 8, 10]6 '20 0f 1c b8'7 > [f, 1, c, b, 8, 10]8 '3f 1c b8'মার্কল প্যাট্রিসিয়া ট্রাই-তে একটি নোড পাওয়ার জন্য এখানে বর্ধিত কোড দেওয়া হলো:
1 def get_helper(node_hash, path):2 if path == []:3 return node_hash4 if node_hash == "":5 return ""6 curnode = rlp.decode(node_hash if len(node_hash) < 32 else db.get(node_hash))7 if len(curnode) == 2:8 (k2, v2) = curnode9 k2 = compact_decode(k2)10 if k2 == path[: len(k2)]:11 return get(v2, path[len(k2) :])12 else:13 return ""14 elif len(curnode) == 17:15 return get_helper(curnode[path[0]], path[1:])1617 def get(node_hash, path):18 path2 = []19 for i in range(len(path)):20 path2.push(int(ord(path[i]) / 16))21 path2.push(ord(path[i]) % 16)22 path2.push(16)23 return get_helper(node_hash, path2)সবকটি দেখুনউদাহরণ ট্রাই
ধরুন আমরা এমন একটি ট্রাই চাই যেখানে চারটি পথ/মান জোড়া রয়েছে: ('do', 'verb'), ('dog', 'puppy'), ('doge', 'coins'), ('horse', 'stallion')।
প্রথমে, আমরা পথ এবং মান উভয়কেই বাইট-এ রূপান্তর করি। নিচে, পথগুলির জন্য প্রকৃত বাইট উপস্থাপনা <> দ্বারা চিহ্নিত করা হয়েছে, যদিও মানগুলি এখনও স্ট্রিং হিসাবে '' দ্বারা দেখানো হয়েছে, সহজে বোঝার জন্য (এগুলিও আসলে বাইট হবে):
1 <64 6f> : 'verb'2 <64 6f 67> : 'puppy'3 <64 6f 67 65> : 'coins'4 <68 6f 72 73 65> : 'stallion'এখন, আমরা অন্তর্নিহিত DB-তে নিম্নলিখিত কী/মান জোড়া দিয়ে এমন একটি ট্রাই তৈরি করি:
1 rootHash: [ <16>, hashA ]2 hashA: [ <>, <>, <>, <>, hashB, <>, <>, <>, [ <20 6f 72 73 65>, 'stallion' ], <>, <>, <>, <>, <>, <>, <>, <> ]3 hashB: [ <00 6f>, hashC ]4 hashC: [ <>, <>, <>, <>, <>, <>, hashD, <>, <>, <>, <>, <>, <>, <>, <>, <>, 'verb' ]5 hashD: [ <17>, [ <>, <>, <>, <>, <>, <>, [ <35>, 'coins' ], <>, <>, <>, <>, <>, <>, <>, <>, <>, 'puppy' ] ]যখন একটি নোড অন্য নোডের ভিতরে রেফারেন্স করা হয়, তখন যা অন্তর্ভুক্ত করা হয় তা হলো keccak256(rlp.encode(node)), যদি len(rlp.encode(node)) >= 32 হয়, অন্যথায় node যেখানে rlp.encode হলো RLP এনকোডিং ফাংশন।
মনে রাখবেন যে একটি ট্রাই আপডেট করার সময়, একজনকে কী/মান জোড়া (keccak256(x), x) একটি পার্সিস্টেন্ট লুকআপ টেবিলে সংরক্ষণ করতে হবে যদি নতুন তৈরি নোডের দৈর্ঘ্য >= ৩২ হয়। তবে, যদি নোডটি তার চেয়ে ছোট হয়, তবে কিছু সংরক্ষণ করার প্রয়োজন নেই, যেহেতু f(x) = x ফাংশনটি বিপরীতমুখী।
ইথেরিয়ামে ট্রাই
ইথেরিয়ামের এক্সিকিউশন লেয়ারের সমস্ত মার্কল ট্রাই একটি মার্কল প্যাট্রিসিয়া ট্রাই ব্যবহার করে।
একটি ব্লক হেডার থেকে এই ট্রাইগুলির ৩টি থেকে ৩টি রুট থাকে।
- stateRoot
- transactionsRoot
- receiptsRoot
স্টেট ট্রাই
একটি গ্লোবাল স্টেট ট্রাই আছে, এবং যখনই কোনো ক্লায়েন্ট একটি ব্লক প্রসেস করে, এটি আপডেট করা হয়। এতে, একটি পথ সর্বদা: keccak256(ethereumAddress) এবং একটি মান সর্বদা: rlp(ethereumAccount)। আরও নির্দিষ্টভাবে একটি ইথেরিয়াম অ্যাকাউন্ট হল [nonce,balance,storageRoot,codeHash] এর একটি ৪-আইটেমের অ্যারে। এই মুহূর্তে, এটি উল্লেখ্য যে এই storageRoot অন্য একটি প্যাট্রিসিয়া ট্রাই-এর রুট:
স্টোরেজ ট্রাই
স্টোরেজ ট্রাই হল যেখানে সমস্ত কন্ট্র্যাক্ট ডেটা থাকে। প্রতিটি অ্যাকাউন্টের জন্য একটি পৃথক স্টোরেজ ট্রাই রয়েছে। একটি নির্দিষ্ট অ্যাড্রেসে নির্দিষ্ট স্টোরেজ পজিশনে মানগুলি পুনরুদ্ধার করতে স্টোরেজ অ্যাড্রেস, স্টোরেজে সঞ্চিত ডেটার পূর্ণসংখ্যার পজিশন এবং ব্লক আইডি প্রয়োজন। এগুলিকে তারপর JSON-RPC API-তে সংজ্ঞায়িত eth_getStorageAt-এ আর্গুমেন্ট হিসাবে পাস করা যেতে পারে, যেমন, 0x295a70b2de5e3953354a6a8344e616ed314d7251 অ্যাড্রেসের জন্য স্টোরেজ স্লট ০-এর ডেটা পুনরুদ্ধার করতে:
curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x0", "latest"], "id": 1}' localhost:8545{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000004d2"}স্টোরেজের অন্যান্য উপাদান পুনরুদ্ধার করা কিছুটা বেশি জড়িত কারণ স্টোরেজ ট্রাই-তে পজিশনটি প্রথমে গণনা করতে হবে। পজিশনটি অ্যাড্রেস এবং স্টোরেজ পজিশনের keccak256 হ্যাস হিসাবে গণনা করা হয়, উভয়ই ৩২ বাইট দৈর্ঘ্যে শূন্য দিয়ে বাম-প্যাড করা হয়। উদাহরণস্বরূপ, 0x391694e7e0b0cce554cb130d723a9d27458f9298 অ্যাড্রেসের জন্য স্টোরেজ স্লট ১-এ ডেটার পজিশন হল:
1keccak256(decodeHex("000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001"))একটি Geth কনসোলে, এটি নিম্নরূপে গণনা করা যেতে পারে:
1> var key = "000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298" + "0000000000000000000000000000000000000000000000000000000000000001"2undefined3> web3.sha3(key, {"encoding": "hex"})4"0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9"পথটি তাই keccak256(<6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9>)। এটি এখন আগের মতোই স্টোরেজ ট্রাই থেকে ডেটা পুনরুদ্ধার করতে ব্যবহার করা যেতে পারে:
curl -X POST --data '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9", "latest"], "id": 1}' localhost:8545{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000162e"}দ্রষ্টব্য: একটি ইথেরিয়াম অ্যাকাউন্টের জন্য storageRoot ডিফল্টরূপে খালি থাকে যদি এটি একটি কন্ট্র্যাক্ট অ্যাকাউন্ট না হয়।
ট্রানজ্যাকশন ট্রাই
প্রতিটি ব্লকের জন্য একটি পৃথক ট্রানজ্যাকশন ট্রাই রয়েছে, যা আবার (কী, মান) জোড়া সংরক্ষণ করে। এখানে একটি পথ হল: rlp(transactionIndex) যা একটি কী প্রতিনিধিত্ব করে যা একটি মান দ্বারা নির্ধারিত হয়:
1if legacyTx:2 value = rlp(tx)3else:4 value = TxType | encode(tx)এ সম্পর্কে আরও তথ্য EIP 2718opens in a new tab ডকুমেন্টেশনে পাওয়া যাবে।
রিসিপ্টস ট্রাই
প্রতিটি ব্লকের নিজস্ব রিসিপ্টস ট্রাই রয়েছে। এখানে একটি পথ হল: rlp(transactionIndex)। transactionIndex হল সেই ব্লকের মধ্যে তার ইনডেক্স যেখানে এটি অন্তর্ভুক্ত ছিল। রিসিপ্টস ট্রাই কখনও আপডেট করা হয় না। ট্রানজ্যাকশন ট্রাই-এর অনুরূপ, এখানে বর্তমান এবং লিগ্যাসি রিসিপ্ট রয়েছে। রিসিপ্টস ট্রাই-তে একটি নির্দিষ্ট রিসিপ্ট কোয়েরি করতে, তার ব্লকের মধ্যে ট্রানজ্যাকশনের ইনডেক্স, রিসিপ্ট পেলোড এবং ট্রানজ্যাকশনের প্রকার প্রয়োজন। প্রত্যাবর্তিত রিসিপ্ট রিসিপ্ট ধরনের হতে পারে যা TransactionType এবং ReceiptPayload-এর কনক্যাটেনেশন হিসাবে সংজ্ঞায়িত করা হয় অথবা এটি লিগ্যাসি রিসিপ্ট ধরনের হতে পারে যা rlp([status, cumulativeGasUsed, logsBloom, logs]) হিসাবে সংজ্ঞায়িত করা হয়।
এ সম্পর্কে আরও তথ্য EIP 2718opens in a new tab ডকুমেন্টেশনে পাওয়া যাবে।