येलो पेपरच्या EVM तपशीलांना समजून घेणे
येलो पेपर (नवीन टॅबमध्ये उघडते) हा इथेरियमसाठी औपचारिक तपशील आहे. EIP प्रक्रियेद्वारे सुधारित केलेल्या भागांचा अपवाद वगळता, यात सर्वकाही कसे कार्य करते याचे अचूक वर्णन आहे. हे एका गणितीय पेपरच्या स्वरूपात लिहिलेले आहे, ज्यामध्ये अशी परिभाषिक शब्दावली समाविष्ट आहे जी प्रोग्रामर्सच्या परिचयाची नसू शकते. या पेपरमध्ये तुम्ही ते कसे वाचायचे हे शिकाल आणि त्या अनुषंगाने इतर संबंधित गणितीय पेपर्स कसे वाचायचे हे देखील शिकाल.
कोणता येलो पेपर?
इथेरियममधील इतर जवळजवळ प्रत्येक गोष्टीप्रमाणेच, येलो पेपर देखील काळानुसार विकसित होतो. एका विशिष्ट आवृत्तीचा संदर्भ घेता यावा यासाठी, मी लेखनाच्या वेळी असलेली वर्तमान आवृत्ती (नवीन टॅबमध्ये उघडते) अपलोड केली आहे. मी वापरलेले विभाग, पृष्ठ आणि समीकरण क्रमांक त्याच आवृत्तीचा संदर्भ देतील. हा दस्तऐवज वाचताना तो वेगळ्या विंडोमध्ये उघडा ठेवणे ही एक चांगली कल्पना आहे.
EVM का?
मूळ येलो पेपर इथेरियमच्या विकासाच्या अगदी सुरुवातीला लिहिला गेला होता. यात मूळ प्रूफ-ऑफ-वर्क (PoW) आधारित सहमती यंत्रणेचे वर्णन केले आहे जी मूळतः नेटवर्क सुरक्षित करण्यासाठी वापरली गेली होती. तथापि, इथेरियमने प्रूफ-ऑफ-वर्क बंद केले आणि सप्टेंबर 2022 मध्ये प्रूफ-ऑफ-स्टेक (PoS) आधारित एकमत वापरण्यास सुरुवात केली. हे ट्युटोरिअल इथेरियम व्हर्च्युअल मशीन (EVM) परिभाषित करणाऱ्या येलो पेपरच्या भागांवर लक्ष केंद्रित करेल. प्रूफ-ऑफ-स्टेकच्या संक्रमणामुळे EVM मध्ये कोणताही बदल झाला नाही (DIFFICULTY ऑपकोडच्या रिटर्न व्हॅल्यूचा अपवाद वगळता).
9 अंमलबजावणी मॉडेल
या विभागात (पृष्ठ 14-16) EVM च्या बहुतांश व्याख्येचा समावेश आहे.
सिस्टम स्थिती (system state) या संज्ञेमध्ये सिस्टम चालवण्यासाठी तुम्हाला त्याबद्दल माहित असणे आवश्यक असलेल्या प्रत्येक गोष्टीचा समावेश होतो. एका सामान्य संगणकामध्ये, याचा अर्थ मेमरी, रजिस्टर्समधील सामग्री इत्यादी असा होतो.
ट्युरिंग मशीन (Turing machine) (नवीन टॅबमध्ये उघडते) हे एक संगणकीय मॉडेल आहे. मूलत:, ही संगणकाची एक सोपी आवृत्ती आहे, ज्यामध्ये सामान्य संगणक करू शकणाऱ्या गणना चालवण्याची समान क्षमता असल्याचे सिद्ध झाले आहे (संगणक जे काही मोजू शकतो ते ट्युरिंग मशीन मोजू शकते आणि याउलट). हे मॉडेल काय मोजण्यायोग्य आहे आणि काय नाही याबद्दल विविध प्रमेये सिद्ध करणे सोपे करते.
ट्युरिंग-कंप्लीट (Turing-complete) (नवीन टॅबमध्ये उघडते) या संज्ञेचा अर्थ असा संगणक आहे जो ट्युरिंग मशीनप्रमाणेच गणना करू शकतो. ट्युरिंग मशीन्स अनंत लूपमध्ये (infinite loops) अडकू शकतात, आणि EVM तसे करू शकत नाही कारण त्याचा गॅस संपेल, त्यामुळे ते केवळ क्वासी-ट्युरिंग-कंप्लीट (quasi-Turing-complete) आहे.
9.1 मूलभूत गोष्टी
हा विभाग EVM च्या मूलभूत गोष्टी आणि इतर संगणकीय मॉडेल्सशी त्याची तुलना कशी होते हे सांगतो.
स्टॅक मशीन (stack machine) (नवीन टॅबमध्ये उघडते) हा असा संगणक आहे जो मध्यवर्ती डेटा रजिस्टर्समध्ये नाही, तर स्टॅक (stack) (नवीन टॅबमध्ये उघडते) मध्ये साठवतो). व्हर्च्युअल मशीन्ससाठी हे प्राधान्य दिलेले आर्किटेक्चर आहे कारण ते लागू करणे सोपे आहे, याचा अर्थ असा की बग्स आणि सुरक्षा भेद्यता (security vulnerabilities) असण्याची शक्यता खूपच कमी असते. स्टॅकमधील मेमरी 256-बिट शब्दांमध्ये विभागलेली असते. हे निवडले गेले कारण ते इथेरियमच्या मुख्य क्रिप्टोग्राफिक ऑपरेशन्ससाठी सोयीचे आहे जसे की केकाक-256 हॅशिंग आणि लंबवर्तुळाकार वक्र गणना. स्टॅकचा कमाल आकार 1024 आयटम्स (1024 x 256 बिट्स) आहे. जेव्हा ऑपकोड्स कार्यान्वित केले जातात तेव्हा ते सहसा त्यांचे पॅरामीटर्स स्टॅकमधून मिळवत असतात. स्टॅकमधील घटकांची पुनर्रचना करण्यासाठी विशेषतः ऑपकोड्स आहेत जसे की POP (स्टॅकच्या वरून आयटम काढून टाकते), DUP_N (स्टॅकमधील N वा आयटम डुप्लिकेट करते), इत्यादी.
EVM मध्ये मेमरी नावाची एक अस्थिर जागा (volatile space) देखील असते जी अंमलबजावणी दरम्यान डेटा साठवण्यासाठी वापरली जाते. ही मेमरी 32-बाइट शब्दांमध्ये आयोजित केली जाते. सर्व मेमरी लोकेशन्स शून्यावर इनिशियलाइज केली जातात. जर तुम्ही मेमरीमध्ये शब्द जोडण्यासाठी हा Yul (नवीन टॅबमध्ये उघडते) कोड कार्यान्वित केला, तर तो शब्दातील रिकाम्या जागेत शून्य भरून 32 बाइट्स मेमरी भरेल, म्हणजेच, तो एक शब्द तयार करतो - 0-29 लोकेशन्समध्ये शून्यांसह, 30 मध्ये 0x60, आणि 31 मध्ये 0xA7.
mstore(0, 0x60A7)
mstore हा EVM मेमरीशी संवाद साधण्यासाठी प्रदान करत असलेल्या तीन ऑपकोड्सपैकी एक आहे - तो मेमरीमध्ये एक शब्द लोड करतो. इतर दोन mstore8 आहेत जे मेमरीमध्ये एकच बाइट लोड करतात आणि mload जे मेमरीमधून स्टॅकमध्ये शब्द हलवतात.
EVM मध्ये एक वेगळे नॉन-व्होलॅटाइल स्टोरेज मॉडेल देखील आहे जे सिस्टम स्थितीचा भाग म्हणून राखले जाते - ही मेमरी वर्ड ॲरेमध्ये (स्टॅकमधील वर्ड-ॲड्रेसेबल बाइट ॲरेच्या विरूद्ध) आयोजित केली जाते. या स्टोरेजमध्ये कॉन्ट्रॅक्ट्स कायमस्वरूपी डेटा ठेवतात - कॉन्ट्रॅक्ट केवळ स्वतःच्या स्टोरेजशी संवाद साधू शकते. स्टोरेज की-व्हॅल्यू मॅपिंगमध्ये आयोजित केले जाते.
जरी येलो पेपरच्या या विभागात याचा उल्लेख केलेला नसला तरी, चौथ्या प्रकारची मेमरी आहे हे जाणून घेणे देखील उपयुक्त आहे. कॉल डेटा (Calldata) ही बाइट-ॲड्रेसेबल रीड-ओन्ली मेमरी आहे जी व्यवहाराच्या data पॅरामीटरसह पास केलेले मूल्य साठवण्यासाठी वापरली जाते. EVM मध्ये calldata व्यवस्थापित करण्यासाठी विशिष्ट ऑपकोड्स आहेत. calldatasize डेटाचा आकार परत करतो. calldataload डेटा स्टॅकमध्ये लोड करतो. calldatacopy डेटा मेमरीमध्ये कॉपी करतो.
प्रमाणित वॉन न्यूमन आर्किटेक्चर (Von Neumann architecture) (नवीन टॅबमध्ये उघडते) कोड आणि डेटा एकाच मेमरीमध्ये साठवते. सुरक्षेच्या कारणास्तव EVM या मानकाचे पालन करत नाही - अस्थिर मेमरी सामायिक केल्याने प्रोग्राम कोड बदलणे शक्य होते. त्याऐवजी, कोड स्टोरेजमध्ये सेव्ह केला जातो.
अशी फक्त दोन प्रकरणे आहेत ज्यामध्ये कोड मेमरीमधून कार्यान्वित केला जातो:
- जेव्हा एखादे कॉन्ट्रॅक्ट दुसरे कॉन्ट्रॅक्ट तयार करते (
CREATE(नवीन टॅबमध्ये उघडते) किंवाCREATE2(नवीन टॅबमध्ये उघडते) वापरून), तेव्हा कॉन्ट्रॅक्ट कन्स्ट्रक्टरसाठी कोड मेमरीमधून येतो. - कोणत्याही कॉन्ट्रॅक्टच्या निर्मितीदरम्यान, कन्स्ट्रक्टर कोड चालतो आणि नंतर वास्तविक कॉन्ट्रॅक्टच्या कोडसह परत येतो, तो देखील मेमरीमधूनच.
अपवादात्मक अंमलबजावणी (exceptional execution) या संज्ञेचा अर्थ असा अपवाद आहे ज्यामुळे वर्तमान कॉन्ट्रॅक्टची अंमलबजावणी थांबते.
9.2 शुल्काचे विहंगावलोकन
हा विभाग गॅस शुल्काची गणना कशी केली जाते हे स्पष्ट करतो. तीन खर्च आहेत:
ऑपकोड खर्च
विशिष्ट ऑपकोडचा अंतर्निहित खर्च. हे मूल्य मिळवण्यासाठी, परिशिष्ट H (पृष्ठ 29, समीकरण (329) च्या खाली) मध्ये ऑपकोडचा खर्च गट शोधा आणि समीकरण (326) मध्ये खर्च गट शोधा. हे तुम्हाला एक खर्च फंक्शन देते, जे बहुतांश प्रकरणांमध्ये परिशिष्ट G (पृष्ठ 28) मधील पॅरामीटर्स वापरते.
उदाहरणार्थ, CALLDATACOPY (नवीन टॅबमध्ये उघडते) हा ऑपकोड Wcopy गटाचा सदस्य आहे. त्या गटासाठी ऑपकोड खर्च Gverylow+Gcopy×⌈μs[2]÷32⌉ आहे. परिशिष्ट G पाहता, आपल्याला दिसते की दोन्ही स्थिरांक 3 आहेत, जे आपल्याला 3+3×⌈μs[2]÷32⌉ देते.
आपल्याला अजूनही ⌈μs[2]÷32⌉ या अभिव्यक्तीचा अर्थ उलगडण्याची आवश्यकता आहे. सर्वात बाहेरील भाग, ⌈ <value> ⌉ हे सीलिंग फंक्शन (ceiling function) आहे, एक असे फंक्शन जे दिलेले मूल्य दिल्यास सर्वात लहान पूर्णांक परत करते जो अद्याप मूल्यापेक्षा लहान नाही. उदाहरणार्थ, ⌈2.5⌉ = ⌈3⌉ = 3. आतील भाग μs[2]÷32 आहे. पृष्ठ 3 वरील विभाग 3 (Conventions) पाहता, μ ही मशीन स्थिती आहे. मशीन स्थिती पृष्ठ 15 वरील विभाग 9.4.1 मध्ये परिभाषित केली आहे. त्या विभागानुसार, मशीन स्थिती पॅरामीटर्सपैकी एक स्टॅकसाठी s आहे. हे सर्व एकत्र केल्यास, असे दिसते की μs[2] हे स्टॅकमधील स्थान #2 आहे. ऑपकोड (नवीन टॅबमध्ये उघडते) पाहता, स्टॅकमधील स्थान #2 हा बाइट्समधील डेटाचा आकार आहे. Wcopy गटातील इतर ऑपकोड्स, CODECOPY (नवीन टॅबमध्ये उघडते) आणि RETURNDATACOPY (नवीन टॅबमध्ये उघडते) पाहता, त्यांच्याकडे देखील त्याच स्थानावर डेटाचा आकार आहे. त्यामुळे ⌈μs[2]÷32⌉ ही कॉपी केल्या जाणाऱ्या डेटाला साठवण्यासाठी आवश्यक असलेल्या 32 बाइट शब्दांची संख्या आहे. सर्वकाही एकत्र केल्यास, CALLDATACOPY (नवीन टॅबमध्ये उघडते) चा अंतर्निहित खर्च 3 गॅस अधिक कॉपी केल्या जाणाऱ्या डेटाच्या प्रति शब्दासाठी 3 आहे.
रनिंग खर्च
आपण कॉल करत असलेला कोड चालवण्याचा खर्च.
CREATE(नवीन टॅबमध्ये उघडते) आणिCREATE2(नवीन टॅबमध्ये उघडते) च्या बाबतीत, नवीन कॉन्ट्रॅक्टसाठी कन्स्ट्रक्टर.CALL(नवीन टॅबमध्ये उघडते),CALLCODE(नवीन टॅबमध्ये उघडते),STATICCALL(नवीन टॅबमध्ये उघडते), किंवाDELEGATECALL(नवीन टॅबमध्ये उघडते) च्या बाबतीत, आपण कॉल करत असलेले कॉन्ट्रॅक्ट.
मेमरी विस्तार खर्च
मेमरी विस्तारण्याचा खर्च (आवश्यक असल्यास).
समीकरण 326 मध्ये, हे मूल्य Cmem(μi')-Cmem(μi) असे लिहिले आहे. पुन्हा विभाग 9.4.1 पाहता, आपल्याला दिसते की μi ही मेमरीमधील शब्दांची संख्या आहे. त्यामुळे μi ही ऑपकोडच्या आधी मेमरीमधील शब्दांची संख्या आहे आणि μi' ही ऑपकोडच्या नंतर मेमरीमधील शब्दांची संख्या आहे.
Cmem हे फंक्शन समीकरण 328 मध्ये परिभाषित केले आहे: Cmem(a) = Gmemory × a + ⌊a2 ÷ 512⌋. ⌊x⌋ हे फ्लोअर फंक्शन (floor function) आहे, एक असे फंक्शन जे दिलेले मूल्य दिल्यास सर्वात मोठा पूर्णांक परत करते जो अद्याप मूल्यापेक्षा मोठा नाही. उदाहरणार्थ, ⌊2.5⌋ = ⌊2⌋ = 2. जेव्हा a < √512, a2 < 512, आणि फ्लोअर फंक्शनचा परिणाम शून्य असतो. त्यामुळे पहिल्या 22 शब्दांसाठी (704 बाइट्स), आवश्यक असलेल्या मेमरी शब्दांच्या संख्येसह खर्च रेषीयपणे (linearly) वाढतो. त्या बिंदूच्या पलीकडे ⌊a2 ÷ 512⌋ सकारात्मक आहे. जेव्हा आवश्यक मेमरी पुरेशी जास्त असते तेव्हा गॅस खर्च मेमरीच्या प्रमाणाच्या वर्गाच्या प्रमाणात असतो.
लक्षात घ्या की हे घटक केवळ अंतर्निहित गॅस खर्चावर प्रभाव टाकतात - हे शुल्क बाजार किंवा व्हॅलिडेटर्सना दिल्या जाणाऱ्या टिप्स विचारात घेत नाही जे अंतिम वापरकर्त्याला किती पैसे द्यावे लागतील हे ठरवतात - हा फक्त EVM वर विशिष्ट ऑपरेशन चालवण्याचा कच्चा खर्च आहे.
9.3 अंमलबजावणी वातावरण
अंमलबजावणी वातावरण हे एक ट्यूपल (tuple), I आहे, ज्यामध्ये अशी माहिती समाविष्ट आहे जी ब्लॉकचेन स्थिती किंवा EVM चा भाग नाही.
| पॅरामीटर | डेटामध्ये प्रवेश करण्यासाठी ऑपकोड | डेटामध्ये प्रवेश करण्यासाठी Solidity कोड |
|---|---|---|
| Ia | ADDRESS (नवीन टॅबमध्ये उघडते) | address(this) |
| Io | ORIGIN (नवीन टॅबमध्ये उघडते) | tx.origin |
| Ip | GASPRICE (नवीन टॅबमध्ये उघडते) | tx.gasprice |
| Id | CALLDATALOAD (नवीन टॅबमध्ये उघडते), इत्यादी. | msg.data |
| Is | CALLER (नवीन टॅबमध्ये उघडते) | msg.sender |
| Iv | CALLVALUE (नवीन टॅबमध्ये उघडते) | msg.value |
| Ib | CODECOPY (नवीन टॅबमध्ये उघडते) | address(this).code |
| IH | ब्लॉक हेडर फील्ड्स, जसे की NUMBER (नवीन टॅबमध्ये उघडते) आणि DIFFICULTY (नवीन टॅबमध्ये उघडते) | block.number, block.difficulty, इत्यादी. |
| Ie | कॉन्ट्रॅक्ट्समधील कॉल्ससाठी कॉल स्टॅकची खोली (कॉन्ट्रॅक्ट निर्मितीसह) | |
| Iw | EVM ला स्थिती बदलण्याची परवानगी आहे का, किंवा ते स्टॅटिकली (statically) चालत आहे का |
विभाग 9 चा उर्वरित भाग समजून घेण्यासाठी इतर काही पॅरामीटर्स आवश्यक आहेत:
| पॅरामीटर | विभागात परिभाषित केले आहे | अर्थ |
|---|---|---|
| σ | 2 (पृष्ठ 2, समीकरण 1) | ब्लॉकचेनची स्थिती |
| g | 9.3 (पृष्ठ 14) | उर्वरित गॅस |
| A | 6.1 (पृष्ठ 9) | जमा झालेली उपस्थिती (accrued substate) (व्यवहार संपल्यावर नियोजित केलेले बदल) |
| o | 9.3 (पृष्ठ 14) | आउटपुट - अंतर्गत व्यवहाराच्या बाबतीत परत आलेला निकाल (जेव्हा एक कॉन्ट्रॅक्ट दुसऱ्याला कॉल करते) आणि व्ह्यू फंक्शन्सचे कॉल्स (जेव्हा तुम्ही फक्त माहिती विचारत असता, त्यामुळे व्यवहाराची वाट पाहण्याची गरज नसते) |
9.4 अंमलबजावणीचे विहंगावलोकन
आता आपल्याकडे सर्व प्राथमिक माहिती असल्याने, आपण शेवटी EVM कसे कार्य करते यावर काम सुरू करू शकतो.
समीकरणे 146-151 आपल्याला EVM चालवण्यासाठी प्रारंभिक अटी देतात:
| चिन्ह | प्रारंभिक मूल्य | अर्थ |
|---|---|---|
| μg | g | उर्वरित गॅस |
| μpc | 0 | प्रोग्राम काउंटर, कार्यान्वित करण्यासाठी पुढील सूचनेचा पत्ता |
| μm | (0, 0, ...) | मेमरी, सर्व शून्यांवर इनिशियलाइज केली आहे |
| μi | 0 | वापरलेले सर्वोच्च मेमरी स्थान |
| μs | () | स्टॅक, सुरुवातीला रिकामा |
| μo | ∅ | आउटपुट, जोपर्यंत आपण रिटर्न डेटासह (RETURN (नवीन टॅबमध्ये उघडते) किंवा REVERT (नवीन टॅबमध्ये उघडते)) किंवा त्याशिवाय (STOP (नवीन टॅबमध्ये उघडते) किंवा SELFDESTRUCT (नवीन टॅबमध्ये उघडते)) थांबत नाही तोपर्यंत रिकामा संच. |
समीकरण 152 आपल्याला सांगते की अंमलबजावणी दरम्यान प्रत्येक वेळी चार संभाव्य अटी असतात आणि त्यांचे काय करायचे:
Z(σ,μ,A,I). Z हे असे फंक्शन दर्शवते जे एखादे ऑपरेशन अवैध स्थिती संक्रमण (invalid state transition) तयार करते की नाही याची चाचणी करते (अपवादात्मक थांबणे (exceptional halting) पहा). जर त्याचे मूल्य True असेल, तर नवीन स्थिती जुन्या स्थितीसारखीच असते (गॅस जळतो हे वगळता) कारण बदल लागू केले गेले नाहीत.- जर कार्यान्वित केला जाणारा ऑपकोड
REVERT(नवीन टॅबमध्ये उघडते) असेल, तर नवीन स्थिती जुन्या स्थितीसारखीच असते, काही गॅस गमावला जातो. - जर ऑपरेशन्सचा क्रम पूर्ण झाला असेल, जसे की
RETURN(नवीन टॅबमध्ये उघडते) द्वारे दर्शविले जाते, तर स्थिती नवीन स्थितीमध्ये अद्यतनित केली जाते. - जर आपण 1-3 यापैकी कोणत्याही अंतिम अटीवर नसू, तर चालवणे सुरू ठेवा.
9.4.1 मशीन स्थिती
हा विभाग मशीन स्थिती अधिक तपशीलवार स्पष्ट करतो. हे निर्दिष्ट करते की w हा वर्तमान ऑपकोड आहे. जर μpc हे ||Ib|| पेक्षा कमी असेल, जी कोडची लांबी आहे, तर तो बाइट (Ib[μpc]) ऑपकोड आहे. अन्यथा, ऑपकोड STOP (नवीन टॅबमध्ये उघडते) म्हणून परिभाषित केला जातो.
हे एक स्टॅक मशीन (नवीन टॅबमध्ये उघडते) असल्याने, आपल्याला प्रत्येक ऑपकोडद्वारे पॉप आउट केलेल्या (δ) आणि पुश इन केलेल्या (α) आयटम्सच्या संख्येचा मागोवा ठेवणे आवश्यक आहे.
9.4.2 अपवादात्मक थांबणे
हा विभाग Z फंक्शन परिभाषित करतो, जे आपले असामान्य टर्मिनेशन (abnormal termination) कधी होते हे निर्दिष्ट करते. हे एक बुलियन (Boolean) (नवीन टॅबमध्ये उघडते) फंक्शन आहे, त्यामुळे ते लॉजिकल 'or' साठी ∨ (नवीन टॅबमध्ये उघडते) आणि लॉजिकल 'and' साठी ∧ (नवीन टॅबमध्ये उघडते) वापरते.
यापैकी कोणतीही अट खरी असल्यास आपले अपवादात्मक थांबणे होते:
-
μg < C(σ,μ,A,I) आपण विभाग 9.2 मध्ये पाहिल्याप्रमाणे, C हे फंक्शन आहे जे गॅस खर्च निर्दिष्ट करते. पुढील ऑपकोड कव्हर करण्यासाठी पुरेसा गॅस शिल्लक नाही.
-
δw=∅ जर ऑपकोडसाठी पॉप केलेल्या आयटम्सची संख्या अपरिभाषित असेल, तर ऑपकोड स्वतःच अपरिभाषित आहे.
-
|| μs || < δw स्टॅक अंडरफ्लो (Stack underflow), वर्तमान ऑपकोडसाठी स्टॅकमध्ये पुरेसे आयटम्स नाहीत.
-
w = JUMP ∧ μs[0]∉D(Ib) ऑपकोड
JUMP(नवीन टॅबमध्ये उघडते) आहे आणि पत्ताJUMPDEST(नवीन टॅबमध्ये उघडते) नाही. जंप्स (Jumps) केवळ तेव्हाच वैध असतात जेव्हा गंतव्यस्थानJUMPDEST(नवीन टॅबमध्ये उघडते) असते. -
w = JUMPI ∧ μs[1]≠0 ∧ μs[0] ∉ D(Ib) ऑपकोड
JUMPI(नवीन टॅबमध्ये उघडते) आहे, अट खरी आहे (शून्य नाही) त्यामुळे जंप व्हायला हवी, आणि पत्ताJUMPDEST(नवीन टॅबमध्ये उघडते) नाही. जंप्स केवळ तेव्हाच वैध असतात जेव्हा गंतव्यस्थानJUMPDEST(नवीन टॅबमध्ये उघडते) असते. -
w = RETURNDATACOPY ∧ μs[1]+μs[2]>|| μo || ऑपकोड
RETURNDATACOPY(नवीन टॅबमध्ये उघडते) आहे. या ऑपकोडमध्ये स्टॅक घटक μs[1] हा रिटर्न डेटा बफरमधून वाचण्यासाठी ऑफसेट आहे, आणि स्टॅक घटक μs[2] ही डेटाची लांबी आहे. जेव्हा तुम्ही रिटर्न डेटा बफरच्या शेवटी पलीकडे वाचण्याचा प्रयत्न करता तेव्हा ही अट उद्भवते. लक्षात घ्या की कॉल डेटा किंवा स्वतः कोडसाठी अशी कोणतीही अट नाही. जेव्हा तुम्ही त्या बफर्सच्या शेवटी पलीकडे वाचण्याचा प्रयत्न करता तेव्हा तुम्हाला फक्त शून्य मिळतात. -
|| μs || - δw + αw > 1024
स्टॅक ओव्हरफ्लो. जर ऑपकोड चालवल्याने 1024 पेक्षा जास्त आयटम्सचा स्टॅक तयार होईल, तर रद्द करा.
-
¬Iw ∧ W(w,μ) आपण स्टॅटिकली चालवत आहोत का (¬ हे निगेशन (negation) आहे (नवीन टॅबमध्ये उघडते) आणि जेव्हा आपल्याला ब्लॉकचेन स्थिती बदलण्याची परवानगी असते तेव्हा Iw खरे असते)? तसे असल्यास, आणि आपण स्थिती बदलण्याचे ऑपरेशन करण्याचा प्रयत्न करत असल्यास, ते होऊ शकत नाही.
W(w,μ) हे फंक्शन नंतर समीकरण 159 मध्ये परिभाषित केले आहे. यापैकी कोणतीही अट खरी असल्यास W(w,μ) खरे असते:
-
w ∈ {CREATE, CREATE2, SSTORE, SELFDESTRUCT} हे ऑपकोड्स नवीन कॉन्ट्रॅक्ट तयार करून, मूल्य साठवून किंवा वर्तमान कॉन्ट्रॅक्ट नष्ट करून स्थिती बदलतात.
-
LOG0≤w ∧ w≤LOG4 जर आपल्याला स्टॅटिकली कॉल केले असेल तर आपण लॉग नोंदी उत्सर्जित करू शकत नाही. लॉग ऑपकोड्स सर्व
LOG0(A0) (नवीन टॅबमध्ये उघडते) आणिLOG4(A4) (नवीन टॅबमध्ये उघडते) च्या दरम्यानच्या श्रेणीत आहेत. लॉग ऑपकोड नंतरची संख्या लॉग नोंदणीमध्ये किती विषय (topics) आहेत हे निर्दिष्ट करते. -
w=CALL ∧ μs[2]≠0 जेव्हा तुम्ही स्टॅटिक असता तेव्हा तुम्ही दुसऱ्या कॉन्ट्रॅक्टला कॉल करू शकता, परंतु तसे केल्यास तुम्ही त्याला ETH हस्तांतरित करू शकत नाही.
-
-
w = SSTORE ∧ μg ≤ Gcallstipend जोपर्यंत तुमच्याकडे Gcallstipend (परिशिष्ट G मध्ये 2300 म्हणून परिभाषित) पेक्षा जास्त गॅस नाही तोपर्यंत तुम्ही
SSTORE(नवीन टॅबमध्ये उघडते) चालवू शकत नाही.
9.4.3 जंप डेस्टिनेशनची वैधता
येथे आपण औपचारिकपणे JUMPDEST (नवीन टॅबमध्ये उघडते) ऑपकोड्स काय आहेत हे परिभाषित करतो. आपण फक्त 0x5B या बाइट मूल्याचा शोध घेऊ शकत नाही, कारण ते PUSH च्या आत असू शकते (आणि त्यामुळे तो डेटा असू शकतो, ऑपकोड नाही).
समीकरण (162) मध्ये आपण N(i,w) हे फंक्शन परिभाषित करतो. पहिला पॅरामीटर, i, हे ऑपकोडचे स्थान आहे. दुसरा, w, हा स्वतः ऑपकोड आहे. जर w∈[PUSH1, PUSH32] असेल तर याचा अर्थ ऑपकोड हा PUSH आहे (चौकोनी कंस एक श्रेणी परिभाषित करतात ज्यामध्ये अंतिम बिंदू समाविष्ट असतात). त्या बाबतीत पुढील ऑपकोड i+2+(w−PUSH1) वर असतो. PUSH1 (नवीन टॅबमध्ये उघडते) साठी आपल्याला दोन बाइट्सने पुढे जावे लागेल (स्वतः PUSH आणि एक बाइट मूल्य), PUSH2 (नवीन टॅबमध्ये उघडते) साठी आपल्याला तीन बाइट्सने पुढे जावे लागेल कारण ते दोन बाइट्सचे मूल्य आहे, इत्यादी. इतर सर्व EVM ऑपकोड्स फक्त एक बाइट लांबीचे असतात, त्यामुळे इतर सर्व प्रकरणांमध्ये N(i,w)=i+1 असते.
हे फंक्शन समीकरण (161) मध्ये DJ(c,i) परिभाषित करण्यासाठी वापरले जाते, जो कोड c मधील सर्व वैध जंप डेस्टिनेशन्सचा संच (नवीन टॅबमध्ये उघडते) आहे, ज्याची सुरुवात ऑपकोड स्थान i पासून होते. हे फंक्शन रिकर्सिव्हली (recursively) परिभाषित केले आहे. जर i≥||c|| असेल, तर याचा अर्थ आपण कोडच्या शेवटी किंवा त्यानंतर आहोत. आपल्याला आणखी कोणतेही जंप डेस्टिनेशन्स सापडणार नाहीत, त्यामुळे फक्त रिकामा संच परत करा.
इतर सर्व प्रकरणांमध्ये आपण पुढील ऑपकोडवर जाऊन आणि त्यापासून सुरू होणारा संच मिळवून उर्वरित कोड पाहतो. c[i] हा वर्तमान ऑपकोड आहे, त्यामुळे N(i,c[i]) हे पुढील ऑपकोडचे स्थान आहे. त्यामुळे DJ(c,N(i,c[i])) हा वैध जंप डेस्टिनेशन्सचा संच आहे जो पुढील ऑपकोडपासून सुरू होतो. जर वर्तमान ऑपकोड JUMPDEST नसेल, तर फक्त तो संच परत करा. जर तो JUMPDEST असेल, तर त्याचा परिणाम संचामध्ये समावेश करा आणि तो परत करा.
9.4.4 सामान्य थांबणे
थांबवणारे फंक्शन H, तीन प्रकारची मूल्ये परत करू शकते.
- जर आपण हॉल्ट ऑपकोडमध्ये नसू, तर ∅, रिकामा संच परत करा. परंपरेनुसार, या मूल्याचा अर्थ बुलियन फॉल्स (Boolean false) असा लावला जातो.
- जर आपल्याकडे असा हॉल्ट ऑपकोड असेल जो आउटपुट तयार करत नाही (
STOP(नवीन टॅबमध्ये उघडते) किंवाSELFDESTRUCT(नवीन टॅबमध्ये उघडते)), तर रिटर्न व्हॅल्यू म्हणून शून्य बाइट्स आकाराचा क्रम परत करा. लक्षात घ्या की हे रिकाम्या संचापेक्षा खूप वेगळे आहे. या मूल्याचा अर्थ असा आहे की EVM खरोखरच थांबले, फक्त वाचण्यासाठी कोणताही रिटर्न डेटा नाही. - जर आपल्याकडे असा हॉल्ट ऑपकोड असेल जो आउटपुट तयार करतो (
RETURN(नवीन टॅबमध्ये उघडते) किंवाREVERT(नवीन टॅबमध्ये उघडते)), तर त्या ऑपकोडद्वारे निर्दिष्ट केलेला बाइट्सचा क्रम परत करा. हा क्रम मेमरीमधून घेतला जातो, स्टॅकच्या शीर्षस्थानी असलेले मूल्य (μs[0]) हा पहिला बाइट आहे आणि त्यानंतरचे मूल्य (μs[1]) ही लांबी आहे.
H.2 सूचना संच
EVM च्या अंतिम उपविभाग, 9.5 कडे जाण्यापूर्वी, आपण स्वतः सूचनांवर एक नजर टाकूया. ते परिशिष्ट H.2 मध्ये परिभाषित केले आहेत जे पृष्ठ 30 वर सुरू होते. त्या विशिष्ट ऑपकोडसह बदलत असल्याचे निर्दिष्ट न केलेली कोणतीही गोष्ट तशीच राहणे अपेक्षित आहे. जे व्हेरिएबल्स बदलतात ते <something>′ म्हणून निर्दिष्ट केले जातात.
उदाहरणार्थ, आपण ADD (नवीन टॅबमध्ये उघडते) ऑपकोड पाहूया.
| मूल्य | नेमोनिक | δ | α | वर्णन |
|---|---|---|---|---|
| 0x01 | ADD | 2 | 1 | बेरीज क्रिया. |
| μ′s[0] ≡ μs[0] + μs[1] |
δ ही आपण स्टॅकमधून पॉप करत असलेल्या मूल्यांची संख्या आहे. या प्रकरणात दोन, कारण आपण शीर्षस्थानी असलेली दोन मूल्ये जोडत आहोत.
α ही आपण परत पुश करत असलेल्या मूल्यांची संख्या आहे. या प्रकरणात एक, बेरीज.
त्यामुळे नवीन स्टॅक टॉप (μ′s[0]) हा जुना स्टॅक टॉप (μs[0]) आणि त्याखालील जुने मूल्य (μs[1]) यांची बेरीज आहे.
कंटाळवाण्या यादीसह सर्व ऑपकोड्स पाहण्याऐवजी, हा लेख फक्त तेच ऑपकोड्स स्पष्ट करतो जे काहीतरी नवीन सादर करतात.
| मूल्य | नेमोनिक | δ | α | वर्णन |
|---|---|---|---|---|
| 0x20 | KECCAK256 | 2 | 1 | केकाक-256 हॅशची गणना करा. |
| μ′s[0] ≡ KEC(μm[μs[0] . . . (μs[0] + μs[1] − 1)]) | ||||
| μ′i ≡ M(μi,μs[0],μs[1]) |
हा पहिला ऑपकोड आहे जो मेमरीमध्ये प्रवेश करतो (या प्रकरणात, फक्त वाचण्यासाठी). तथापि, तो मेमरीच्या वर्तमान मर्यादेच्या पलीकडे विस्तारू शकतो, त्यामुळे आपल्याला μi अपडेट करणे आवश्यक आहे. आपण हे पृष्ठ 30 वरील समीकरण 330 मध्ये परिभाषित केलेल्या M फंक्शनचा वापर करून करतो.
| मूल्य | नेमोनिक | δ | α | वर्णन |
|---|---|---|---|---|
| 0x31 | BALANCE | 1 | 1 | दिलेल्या खात्याची शिल्लक मिळवा. |
| ... |
ज्या पत्त्याची शिल्लक आपल्याला शोधायची आहे तो μs[0] mod 2160 आहे. स्टॅकच्या शीर्षस्थानी पत्ता असतो, परंतु पत्ते फक्त 160 बिट्सचे असल्यामुळे, आपण 2160 चे मॉड्युलो (नवीन टॅबमध्ये उघडते) मूल्य मोजतो.
जर σ[μs[0] mod 2160] ≠ ∅ असेल, तर याचा अर्थ या पत्त्याबद्दल माहिती आहे. त्या प्रकरणात, σ[μs[0] mod 2160]b ही त्या पत्त्याची शिल्लक आहे. जर σ[μs[0] mod 2160] = ∅ असेल, तर याचा अर्थ हा पत्ता अनइनिशियलाइज्ड (uninitialized) आहे आणि शिल्लक शून्य आहे. तुम्ही पृष्ठ 4 वरील विभाग 4.1 मध्ये खाते माहिती फील्ड्सची यादी पाहू शकता.
दुसरे समीकरण, A'a ≡ Aa ∪ {μs[0] mod 2160}, हे वॉर्म स्टोरेज (असे स्टोरेज ज्यामध्ये अलीकडेच प्रवेश केला गेला आहे आणि जे कॅश (cached) असण्याची शक्यता आहे) आणि कोल्ड स्टोरेज (असे स्टोरेज ज्यामध्ये प्रवेश केला गेला नाही आणि जे धीम्या स्टोरेजमध्ये असण्याची शक्यता आहे जे पुनर्प्राप्त करण्यासाठी अधिक महाग आहे) मधील प्रवेशाच्या खर्चातील फरकाशी संबंधित आहे. Aa ही व्यवहाराद्वारे पूर्वी प्रवेश केलेल्या पत्त्यांची यादी आहे, ज्यामध्ये प्रवेश करणे त्यामुळे स्वस्त असावे, जसे की पृष्ठ 9 वरील विभाग 6.1 मध्ये परिभाषित केले आहे. तुम्ही या विषयाबद्दल EIP-2929 (नवीन टॅबमध्ये उघडते) मध्ये अधिक वाचू शकता.
| मूल्य | नेमोनिक | δ | α | वर्णन |
|---|---|---|---|---|
| 0x8F | DUP16 | 16 | 17 | 16 वा स्टॅक आयटम डुप्लिकेट करा. |
| μ′s[0] ≡ μs[15] |
लक्षात घ्या की कोणताही स्टॅक आयटम वापरण्यासाठी, आपल्याला तो पॉप करणे आवश्यक आहे, ज्याचा अर्थ असा आहे की आपल्याला त्याच्या वर असलेले सर्व स्टॅक आयटम्स देखील पॉप करणे आवश्यक आहे. DUP<n> (नवीन टॅबमध्ये उघडते) आणि SWAP<n> (नवीन टॅबमध्ये उघडते) च्या बाबतीत, याचा अर्थ सोळा मूल्यांपर्यंत पॉप करणे आणि नंतर पुश करणे असा होतो.
9.5 अंमलबजावणी चक्र
आता आपल्याकडे सर्व भाग असल्याने, आपण शेवटी EVM च्या अंमलबजावणी चक्राचे दस्तऐवजीकरण कसे केले जाते हे समजू शकतो.
समीकरण (164) सांगते की दिलेली स्थिती:
- σ (जागतिक ब्लॉकचेन स्थिती)
- μ (EVM स्थिती)
- A (उपस्थिती (substate), व्यवहार संपल्यावर होणारे बदल)
- I (अंमलबजावणी वातावरण)
नवीन स्थिती (σ', μ', A', I') आहे.
समीकरणे (165)-(167) स्टॅक आणि ऑपकोडमुळे (μs) त्यात होणारा बदल परिभाषित करतात. समीकरण (168) हा गॅसमधील बदल (μg) आहे. समीकरण (169) हा प्रोग्राम काउंटरमधील बदल (μpc) आहे. शेवटी, समीकरणे (170)-(173) निर्दिष्ट करतात की इतर पॅरामीटर्स तसेच राहतात, जोपर्यंत ऑपकोडद्वारे स्पष्टपणे बदलले जात नाहीत.
यासोबत EVM पूर्णपणे परिभाषित केले आहे.
निष्कर्ष
गणितीय नोटेशन अचूक आहे आणि त्याने येलो पेपरला इथेरियमचा प्रत्येक तपशील निर्दिष्ट करण्याची परवानगी दिली आहे. तथापि, यात काही त्रुटी आहेत:
- हे केवळ मानवांनाच समजू शकते, ज्याचा अर्थ असा आहे की अनुपालन चाचण्या (compliance tests) (नवीन टॅबमध्ये उघडते) मॅन्युअली लिहिल्या गेल्या पाहिजेत.
- प्रोग्रामर्सना संगणक कोड समजतो. त्यांना गणितीय नोटेशन समजू शकते किंवा नाही.
कदाचित याच कारणांमुळे, नवीन सहमती स्तर तपशील (नवीन टॅबमध्ये उघडते) Python मध्ये लिहिलेले आहेत. Python मध्ये अंमलबजावणी स्तर तपशील (नवीन टॅबमध्ये उघडते) आहेत, परंतु ते पूर्ण नाहीत. जोपर्यंत संपूर्ण येलो पेपर देखील Python किंवा तत्सम भाषेत अनुवादित होत नाही, तोपर्यंत येलो पेपर सेवेत राहील आणि तो वाचता येणे उपयुक्त आहे.