मर्केल पॅट्रिशिया ट्राई
पृष्ठ अखेरचे अद्यतन: २२ ऑक्टोबर, २०२५
Ethereum ची स्टेट (सर्व अकाउंट्स, बॅलन्स आणि स्मार्ट कॉन्ट्रॅक्ट्सची एकूणता), डेटा स्ट्रक्चरच्या एका विशेष आवृत्तीमध्ये एन्कोड केली जाते, जी संगणक विज्ञानात सामान्यतः मर्केल ट्री म्हणून ओळखली जाते. ही रचना क्रिप्टोग्राफीमधील अनेक ॲप्लिकेशन्ससाठी उपयुक्त आहे कारण ती ट्रीमध्ये गुंतलेल्या डेटाच्या सर्व वैयक्तिक भागांमध्ये एक सत्यापित करण्यायोग्य संबंध तयार करते, ज्यामुळे एकच रूट व्हॅल्यू तयार होते ज्याचा वापर डेटाबद्दल गोष्टी सिद्ध करण्यासाठी केला जाऊ शकतो.
Ethereum ची डेटा स्ट्रक्चर एक 'मॉडिफाइड मर्केल-पॅट्रिशिया ट्राई' आहे, ज्याला हे नाव दिले गेले आहे कारण ते PATRICIA (प्रॅक्टिकल अल्गोरिदम टू रिट्रीव्ह इन्फॉर्मेशन कोडेड इन अल्फान्यूमेरिक) चे काही वैशिष्ट्ये घेते आणि कारण ते Ethereum स्टेट तयार करणाऱ्या आयटम्सच्या कार्यक्षम डेटा रिट्राईव्हलसाठी डिझाइन केलेले आहे.
मर्केल-पॅट्रिशिया ट्राई ही निश्चित (deterministic) आणि क्रिप्टोग्राफिकदृष्ट्या सत्यापित करण्यायोग्य आहे: स्टेट रूट तयार करण्याचा एकमेव मार्ग म्हणजे स्टेटच्या प्रत्येक वैयक्तिक भागातून त्याची गणना करणे आणि दोन सारख्याच स्टेट्सची रूट हॅश आणि त्यापर्यंत पोहोचलेल्या हॅशेसची तुलना करून सहजपणे सिद्ध करता येते (एक मर्केल प्रूफ). याउलट, एकाच रूट हॅशसह दोन भिन्न स्टेट्स तयार करण्याचा कोणताही मार्ग नाही आणि भिन्न मूल्यांसह स्टेटमध्ये बदल करण्याचा कोणताही प्रयत्न केल्यास भिन्न स्टेट रूट हॅश मिळेल. सैद्धांतिकदृष्ट्या, ही रचना इन्सर्ट, लुकअप आणि डिलीटसाठी O(log(n)) कार्यक्षमतेचे 'होली ग्रेल' प्रदान करते.
नजीकच्या भविष्यात, Ethereum Verkle Tree रचनेमध्ये स्थलांतरित करण्याची योजना आखत आहे, ज्यामुळे भविष्यातील प्रोटोकॉल सुधारणांसाठी अनेक नवीन शक्यता उघडल्या जातील.
पूर्वतयारी
हे पृष्ठ अधिक चांगल्या प्रकारे समजून घेण्यासाठी, हॅशेस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 च्या वर्णनाने सुरू होतो, नंतर हळूहळू Ethereum च्या अधिक ऑप्टिमाइझ केलेल्या डेटा स्ट्रक्चरसाठी आवश्यक बदल सादर करतो.
मूलभूत रॅडिक्स ट्राईज
मूलभूत रॅडिक्स ट्राईमध्ये, प्रत्येक नोड खालीलप्रमाणे दिसतो:
1 [i_0, i_1 ... i_n, value]जिथे i_0 ... i_n वर्णमालेची चिन्हे दर्शवतात (बहुतेकदा बायनरी किंवा हेक्स), व्हॅल्यू नोडमधील टर्मिनल व्हॅल्यू आहे, आणि i_0, i_1 ... मधील व्हॅल्यूज i_nस्लॉट एकतरNULLकिंवा इतर नोड्सचे पॉइंटर्स (आमच्या बाबतीत, हॅश) असतात. हे एक मूलभूत(की, व्हॅल्यू)` स्टोअर तयार करते.
समजा तुम्हाला की-व्हॅल्यू जोड्यांच्या सेटवर ऑर्डर कायम ठेवण्यासाठी रॅडिक्स ट्री डेटा स्ट्रक्चर वापरायचे आहे. ट्राईमध्ये सध्या dog की शी मॅप केलेली व्हॅल्यू शोधण्यासाठी, तुम्ही प्रथम dog ला वर्णमालेच्या अक्षरांमध्ये रूपांतरित कराल ( 64 6f 67 देऊन), आणि नंतर तुम्हाला व्हॅल्यू मिळेपर्यंत त्या मार्गावरून ट्राईमध्ये खाली जाल. म्हणजे, तुम्ही ट्राईचा रूट नोड शोधण्यासाठी फ्लॅट की/व्हॅल्यू DB मध्ये रूट हॅश शोधून सुरुवात करता. ते इतर नोड्सना पॉइंट करणाऱ्या कीजच्या ॲरे म्हणून दर्शविले जाते. तुम्ही इंडेक्स 6 वरील व्हॅल्यूचा की म्हणून वापर कराल आणि एका लेव्हल खालील नोड मिळवण्यासाठी फ्लॅट की/व्हॅल्यू DB मध्ये शोधाल. नंतर पुढील व्हॅल्यू शोधण्यासाठी इंडेक्स 4 निवडा, नंतर इंडेक्स 6 निवडा, आणि असेच, जोपर्यंत तुम्ही मार्ग: रूट -> 6 -> 4 -> 6 -> 15 -> 6 -> 7 फॉलो करत नाही, तोपर्यंत तुम्ही नोडची व्हॅल्यू शोधून निकाल परत कराल.
'ट्राई' मध्ये काहीतरी शोधणे आणि अंतर्निहित फ्लॅट की/व्हॅल्यू 'DB' मध्ये शोधणे यात फरक आहे. ते दोघेही की/व्हॅल्यू व्यवस्था परिभाषित करतात, परंतु अंतर्निहित DB की चा पारंपरिक 1-स्टेप लुकअप करू शकतो. ट्राईमध्ये की शोधण्यासाठी वर वर्णन केलेल्या अंतिम व्हॅल्यूपर्यंत पोहोचण्यासाठी अनेक अंतर्निहित 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 मध्ये की == keccak256(rlp(व्हॅल्यू))) संग्रहित डेटाची क्रिप्टोग्राफिक अखंडतेची हमी देते. जर दिलेल्या ट्राईचा रूट हॅश सार्वजनिकरित्या ज्ञात असेल, तर अंतर्निहित लीफ डेटामध्ये प्रवेश असलेला कोणीही विशिष्ट व्हॅल्यूला ट्री रूटशी जोडणाऱ्या प्रत्येक नोडचे हॅश प्रदान करून, ट्राईमध्ये विशिष्ट मार्गावर विशिष्ट व्हॅल्यू समाविष्ट असल्याचा पुरावा तयार करू शकतो.
आक्रमणकर्त्यासाठी अस्तित्वात नसलेल्या (पाथ, व्हॅल्यू) जोडीचा पुरावा देणे अशक्य आहे कारण रूट हॅश शेवटी त्याच्या खालील सर्व हॅशवर आधारित असतो. कोणत्याही अंतर्निहित बदलामुळे रूट हॅश बदलेल. आपण हॅशला डेटाच्या संरचनात्मक माहितीचे संकुचित प्रतिनिधित्व म्हणून विचार करू शकता, जे हॅशिंग फंक्शनच्या प्री-इमेज संरक्षणाद्वारे सुरक्षित केलेले आहे.
आपण रॅडिक्स ट्रीच्या अणु एककाला (उदा., एकच हेक्स कॅरॅक्टर किंवा 4 बिट बायनरी संख्या) "निबल" म्हणू. वर वर्णन केल्याप्रमाणे, एका वेळी एक निबल मार्गक्रमण करताना, नोड्स जास्तीत जास्त 16 चिल्ड्रेनचा संदर्भ घेऊ शकतात परंतु त्यात व्हॅल्यू घटक समाविष्ट असतो. म्हणून, आम्ही त्यांना 17 लांबीच्या ॲरे म्हणून दर्शवितो. आम्ही या 17-घटक ॲरेला "ब्रांच नोड्स" म्हणतो.
मर्केल पॅट्रिशिया ट्राई
रॅडिक्स ट्राईजची एक मोठी मर्यादा आहे: त्या अकार्यक्षम आहेत. जर तुम्हाला एक (पाथ, व्हॅल्यू) बाइंडिंग साठवायचे असेल जिथे पाथ, Ethereum प्रमाणे, 64 कॅरॅक्टर लांब आहे (bytes32 मधील निबल्सची संख्या), तर आम्हाला प्रत्येक कॅरॅक्टरसाठी एक लेव्हल साठवण्यासाठी एक किलोबाइटपेक्षा जास्त अतिरिक्त जागेची आवश्यकता असेल, आणि प्रत्येक लुकअप किंवा डिलीटसाठी पूर्ण 64 स्टेप्स लागतील. खालीलप्रमाणे सादर केलेली पॅट्रिशिया ट्राई ही समस्या सोडवते.
ऑप्टिमायझेशन
मर्केल पॅट्रिशिया ट्राईमधील नोड खालीलपैकी एक असतो:
NULL(रिकाम्या स्ट्रिंगने दर्शविलेले)ब्रांचएक 17-आयटम नोड[ v0 ... v15, vt ]लीफएक 2-आयटम नोड[ एन्कोडेडपाथ, व्हॅल्यू ]एक्सटेन्शनएक 2-आयटम नोड[ एन्कोडेडपाथ, की ]
64 कॅरॅक्टर पाथसह, ट्राईच्या पहिल्या काही लेयर्समधून गेल्यानंतर, तुम्ही अशा नोडवर पोहोचणारच आहात जिथे किमान काही मार्गासाठी कोणताही भिन्न मार्ग अस्तित्वात नाही. मार्गावर 15 पर्यंत विरळ NULL नोड्स तयार करणे टाळण्यासाठी, आम्ही [ एन्कोडेडपाथ, की ] स्वरूपाचा एक एक्सटेन्शन नोड सेट करून उतरण लहान करतो, जिथे एन्कोडेडपाथ मध्ये पुढे जाण्यासाठी "आंशिक मार्ग" असतो (खाली वर्णन केलेल्या कॉम्पॅक्ट एन्कोडिंगचा वापर करून), आणि की पुढील DB लुकअपसाठी असते.
लीफ नोडसाठी, जे एन्कोडेडपाथच्या पहिल्या निबलमधील ध्वजाद्वारे चिन्हांकित केले जाऊ शकते, पाथमध्ये मागील सर्व नोडच्या पाथच्या तुकड्यांचे एन्कोडिंग असते आणि आम्ही थेट व्हॅल्यू शोधू शकतो.
तथापि, वरील ऑप्टिमायझेशनमुळे संदिग्धता निर्माण होते.
निबल्समध्ये पाथक्रमण करताना, आपल्याला विषम संख्येने निबल्सचा सामना करावा लागू शकतो, परंतु सर्व डेटा बाइट्स स्वरूपात संग्रहित असल्यामुळे. उदाहरणार्थ, निबल 1 आणि निबल्स 01 मध्ये फरक करणे शक्य नाही (दोन्ही <01> म्हणून संग्रहित करणे आवश्यक आहे). विषम लांबी निर्दिष्ट करण्यासाठी, आंशिक मार्गाच्या आधी एक ध्वज लावला जातो.
स्पेसिफिकेशन: पर्यायी टर्मिनेटरसह हेक्स सीक्वेन्सचे कॉम्पॅक्ट एन्कोडिंग
वर वर्णन केल्याप्रमाणे विषम विरुद्ध सम उर्वरित आंशिक मार्गाची लांबी आणि लीफ विरुद्ध एक्सटेन्शन नोड या दोन्हींचे ध्वजांकन कोणत्याही 2-आयटम नोडच्या आंशिक मार्गाच्या पहिल्या निबलमध्ये असते. त्यांचे परिणाम खालीलप्रमाणे आहेत:
| हेक्स कॅरॅक्टर | बिट्स | नोड प्रकार आंशिक | पाथची लांबी |
|---|---|---|---|
| 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> : 'क्रियापद'2 <64 6f 67> : 'पिल्लू'3 <64 6f 67 65> : 'नाणी'4 <68 6f 72 73 65> : 'घोडा'आता, आपण अंतर्निहित DB मध्ये खालील की/व्हॅल्यू जोड्यांसह अशी ट्राई तयार करू:
1 rootHash: [ <16>, hashA ]2 hashA: [ <>, <>, <>, <>, hashB, <>, <>, <>, [ <20 6f 72 73 65>, 'घोडा' ], <>, <>, <>, <>, <>, <>, <>, <> ]3 hashB: [ <00 6f>, hashC ]4 hashC: [ <>, <>, <>, <>, <>, <>, hashD, <>, <>, <>, <>, <>, <>, <>, <>, <>, 'क्रियापद' ]5 hashD: [ <17>, [ <>, <>, <>, <>, <>, <>, [ <35>, 'नाणी' ], <>, <>, <>, <>, <>, <>, <>, <>, <>, 'पिल्लू' ] ]जेव्हा एका नोडचा दुसऱ्या नोडमध्ये संदर्भ दिला जातो, तेव्हा keccak256(rlp.encode(node)) समाविष्ट केले जाते, जर len(rlp.encode(node)) >= 32 असेल तर, अन्यथा node समाविष्ट केले जाते जिथे rlp.encode हे RLP एन्कोडिंग फंक्शन आहे.
लक्षात घ्या की ट्राई अपडेट करताना, जर नव्याने तयार केलेला नोड 32 किंवा त्यापेक्षा जास्त लांबीचा असेल तर, की/व्हॅल्यू जोडी (keccak256(x), x) एका पर्सिस्टंट लुकअप टेबलमध्ये साठवणे आवश्यक आहे. तथापि, जर नोड त्यापेक्षा लहान असेल, तर काहीही साठवण्याची गरज नाही, कारण f(x) = x हे फंक्शन उलट करता येण्याजोगे आहे.
Ethereum मधील ट्राईज
Ethereum च्या एक्झिक्युशन लेअरमधील सर्व मर्केल ट्राईज मर्केल पॅट्रिशिया ट्राई वापरतात.
ब्लॉक हेडरमधून यापैकी 3 ट्राईजचे 3 रूट्स असतात.
- स्टेटरूट
- ट्रान्झॅक्शन्सरूट
- रीसीट्सरूट
स्टेट ट्राई
एक जागतिक स्टेट ट्राई आहे, आणि जेव्हा एखादा क्लायंट ब्लॉकवर प्रक्रिया करतो तेव्हा ती प्रत्येक वेळी अपडेट केली जाते. त्यात, एक पाथ नेहमी असतो: keccak256(ethereumAddress) आणि एक व्हॅल्यू नेहमी असते: rlp(ethereumAccount). अधिक विशेषतः, एक Ethereum अकाउंट [nonce,balance,storageRoot,codeHash] या 4 आयटमचा ॲरे आहे. या टप्प्यावर, हे लक्षात घेण्यासारखे आहे की हा storageRoot दुसऱ्या पॅट्रिशिया ट्राईचा रूट आहे:
स्टोरेज ट्राई
स्टोरेज ट्राई हे असे ठिकाण आहे जिथे सर्व कॉन्ट्रॅक्ट डेटा राहतो. प्रत्येक अकाउंटसाठी स्वतंत्र स्टोरेज ट्राई असते. विशिष्ट ॲड्रेसवर विशिष्ट स्टोरेज पोझिशनवरील व्हॅल्यूज मिळवण्यासाठी स्टोरेज ॲड्रेस, स्टोरेजमध्ये संग्रहित डेटाची पूर्णांक पोझिशन आणि ब्लॉक आयडी आवश्यक आहेत. त्यानंतर JSON-RPC API मध्ये परिभाषित eth_getStorageAt ला आर्गुमेंट्स म्हणून पास केले जाऊ शकते, उदा., ॲड्रेस 0x295a70b2de5e3953354a6a8344e616ed314d7251 साठी स्टोरेज स्लॉट 0 मधील डेटा मिळवण्यासाठी:
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 हॅश म्हणून केली जाते, दोन्ही 32 बाइट्सच्या लांबीपर्यंत शून्यांसह डावीकडे पॅड केलेले असतात. उदाहरणार्थ, ॲड्रेस 0x391694e7e0b0cce554cb130d723a9d27458f9298 साठी स्टोरेज स्लॉट 1 मधील डेटाची पोझिशन आहे:
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"}टीप: जर ते कॉन्ट्रॅक्ट अकाउंट नसेल तर Ethereum अकाउंटसाठी storageRoot डिफॉल्टनुसार रिकामा असतो.
ट्रान्झॅक्शन ट्राई
प्रत्येक ब्लॉकसाठी एक वेगळी ट्रान्झॅक्शन ट्राई असते, जी पुन्हा (की, व्हॅल्यू) जोड्या साठवते. येथे एक पाथ आहे: rlp(transactionIndex) जो एका व्हॅल्यूशी संबंधित की दर्शवितो, जी याद्वारे निर्धारित केली जाते:
1if legacyTx:2 value = rlp(tx)3else:4 value = TxType | encode(tx)याबद्दल अधिक माहिती EIP 2718opens in a new tab डॉक्युमेंटेशनमध्ये आढळू शकते.
रीसीट्स ट्राई
प्रत्येक ब्लॉकची स्वतःची रीसीट्स ट्राई असते. येथे एक पाथ आहे: rlp(transactionIndex). transactionIndex हा ज्या ब्लॉक मध्ये त्याचा समावेश आहे त्यातील त्याचा इंडेक्स आहे. रीसीट्स ट्राई कधीही अपडेट केली जात नाही. ट्रान्झॅक्शन ट्राई प्रमाणेच, सध्याच्या आणि लेगसी रीसीट्स आहेत. रीसीट्स ट्राईमध्ये विशिष्ट रीसीट क्वेरी करण्यासाठी, त्याच्या ब्लॉकमधील ट्रान्झॅक्शनचा इंडेक्स, रीसीट पेलोड आणि ट्रान्झॅक्शन प्रकार आवश्यक आहे. परत आलेली रीसीट Receipt प्रकाराची असू शकते जी TransactionType आणि ReceiptPayload चे एकत्रीकरण म्हणून परिभाषित केली आहे किंवा ती LegacyReceipt प्रकाराची असू शकते जी rlp([status, cumulativeGasUsed, logsBloom, logs]) म्हणून परिभाषित केली आहे.
याबद्दल अधिक माहिती EIP 2718opens in a new tab डॉक्युमेंटेशनमध्ये आढळू शकते.