येलो पेपरच्या EVM तपशीलांना समजून घेणे
येलो पेपर (opens in a new tab) हा इथेरियमसाठी औपचारिक तपशील आहे. EIP प्रक्रियेद्वारे सुधारित केलेल्या भागांचा अपवाद वगळता, यात सर्वकाही कसे कार्य करते याचे अचूक वर्णन आहे. हे एका गणितीय पेपरच्या स्वरूपात लिहिलेले आहे, ज्यामध्ये अशी परिभाषिक शब्दावली समाविष्ट आहे जी प्रोग्रामर्सच्या परिचयाची नसू शकते. या पेपरमध्ये तुम्ही ते कसे वाचायचे हे शिकाल आणि त्या अनुषंगाने इतर संबंधित गणितीय पेपर्स कसे वाचायचे हे देखील शिकाल.
कोणता येलो पेपर?
इथेरियममधील इतर जवळजवळ प्रत्येक गोष्टीप्रमाणेच, येलो पेपर देखील काळानुसार विकसित होतो. एका विशिष्ट आवृत्तीचा संदर्भ घेता यावा यासाठी, मी लेखनाच्या वेळी असलेली वर्तमान आवृत्ती अपलोड केली आहे. मी वापरलेले विभाग, पृष्ठ आणि समीकरण क्रमांक त्याच आवृत्तीचा संदर्भ देतील. हा दस्तऐवज वाचताना तो वेगळ्या विंडोमध्ये उघडा ठेवणे ही एक चांगली कल्पना आहे.
EVM का?
मूळ येलो पेपर इथेरियमच्या विकासाच्या अगदी सुरुवातीला लिहिला गेला होता. यात मूळ प्रूफ-ऑफ-वर्क (PoW) आधारित सहमती यंत्रणेचे वर्णन केले आहे जी मूळतः नेटवर्क सुरक्षित करण्यासाठी वापरली गेली होती. तथापि, इथेरियमने प्रूफ-ऑफ-वर्क बंद केले आणि सप्टेंबर 2022 मध्ये प्रूफ-ऑफ-स्टेक (PoS) आधारित एकमत वापरण्यास सुरुवात केली. हे ट्युटोरिअल इथेरियम व्हर्च्युअल मशीन (EVM) परिभाषित करणाऱ्या येलो पेपरच्या भागांवर लक्ष केंद्रित करेल. प्रूफ-ऑफ-स्टेकच्या संक्रमणामुळे EVM मध्ये कोणताही बदल झाला नाही (DIFFICULTY ऑपकोडच्या रिटर्न व्हॅल्यूचा अपवाद वगळता).
9 अंमलबजावणी मॉडेल
या विभागात (पृष्ठ 12-14) EVM च्या बहुतांश व्याख्येचा समावेश आहे.
सिस्टम स्थिती (system state) या संज्ञेमध्ये सिस्टम चालवण्यासाठी तुम्हाला त्याबद्दल माहित असणे आवश्यक असलेल्या प्रत्येक गोष्टीचा समावेश होतो. एका सामान्य संगणकामध्ये, याचा अर्थ मेमरी, रजिस्टर्समधील सामग्री इत्यादी असा होतो.
ट्युरिंग मशीन (Turing machine) (opens in a new tab) हे एक संगणकीय मॉडेल आहे. मूलत:, ही संगणकाची एक सोपी आवृत्ती आहे, ज्यामध्ये सामान्य संगणकाप्रमाणेच गणना चालवण्याची क्षमता असल्याचे सिद्ध झाले आहे (संगणक जे काही मोजू शकतो ते ट्युरिंग मशीन मोजू शकते आणि याउलट). हे मॉडेल काय मोजण्यायोग्य आहे आणि काय नाही याबद्दल विविध प्रमेये सिद्ध करणे सोपे करते.
ट्युरिंग-कंप्लीट (Turing-complete) (opens in a new tab) या संज्ञेचा अर्थ असा संगणक जो ट्युरिंग मशीनप्रमाणेच गणना चालवू शकतो. ट्युरिंग मशीन्स अनंत लूपमध्ये (infinite loops) अडकू शकतात, आणि EVM तसे करू शकत नाही कारण त्याचा गॅस संपेल, त्यामुळे ते केवळ क्वासी-ट्युरिंग-कंप्लीट (quasi-Turing-complete) आहे.
9.1 मूलभूत गोष्टी
हा विभाग EVM च्या मूलभूत गोष्टी आणि इतर संगणकीय मॉडेल्सशी त्याची तुलना कशी होते हे सांगतो.
स्टॅक मशीन (stack machine) (opens in a new tab) हा असा संगणक आहे जो मध्यवर्ती डेटा रजिस्टर्समध्ये नाही, तर स्टॅक (stack) (opens in a new tab) मध्ये साठवतो). व्हर्च्युअल मशीन्ससाठी हे प्राधान्य दिलेले आर्किटेक्चर आहे कारण ते लागू करणे सोपे आहे, याचा अर्थ असा की बग्स आणि सुरक्षा भेद्यता (security vulnerabilities) असण्याची शक्यता खूपच कमी असते. स्टॅकमधील मेमरी 256-बिट शब्दांमध्ये विभागलेली असते. हे निवडले गेले कारण ते इथेरियमच्या मुख्य क्रिप्टोग्राफिक ऑपरेशन्ससाठी सोयीचे आहे जसे की केकाक-256 हॅशिंग आणि लंबवर्तुळाकार वक्र गणना. स्टॅकचा कमाल आकार 1024 आयटम्स (1024 x 256 बिट्स) आहे. जेव्हा ऑपकोड्स कार्यान्वित केले जातात तेव्हा ते सहसा त्यांचे पॅरामीटर्स स्टॅकमधून मिळवत असतात. स्टॅकमधील घटकांची पुनर्रचना करण्यासाठी विशेषतः ऑपकोड्स आहेत जसे की POP (स्टॅकच्या वरून आयटम काढून टाकते), DUP_N (स्टॅकमधील N वा आयटम डुप्लिकेट करते), इत्यादी.
EVM मध्ये मेमरी नावाची एक अस्थिर जागा (volatile space) देखील असते जी अंमलबजावणी दरम्यान डेटा साठवण्यासाठी वापरली जाते. ही मेमरी 32-बाइट शब्दांमध्ये आयोजित केली जाते. सर्व मेमरी लोकेशन्स शून्यावर इनिशियलाइज केली जातात. जर तुम्ही मेमरीमध्ये शब्द जोडण्यासाठी हा Yul (opens in a new tab) कोड कार्यान्वित केला, तर तो शब्दातील रिकाम्या जागेत शून्य भरून 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) (opens in a new tab) कोड आणि डेटा एकाच मेमरीमध्ये साठवते. सुरक्षेच्या कारणास्तव EVM या मानकाचे पालन करत नाही - अस्थिर मेमरी सामायिक केल्याने प्रोग्राम कोड बदलणे शक्य होते. त्याऐवजी, कोड स्टोरेजमध्ये सेव्ह केला जातो.
अशी फक्त दोन प्रकरणे आहेत ज्यामध्ये कोड मेमरीमधून कार्यान्वित केला जातो:
- जेव्हा एखादे कॉन्ट्रॅक्ट दुसरे कॉन्ट्रॅक्ट तयार करते (
CREATE(opens in a new tab) किंवाCREATE2(opens in a new tab) वापरून), तेव्हा कॉन्ट्रॅक्ट कन्स्ट्रक्टरसाठी कोड मेमरीमधून येतो. - कोणत्याही कॉन्ट्रॅक्टच्या निर्मितीदरम्यान, कन्स्ट्रक्टर कोड चालतो आणि नंतर वास्तविक कॉन्ट्रॅक्टच्या कोडसह परत येतो, तो देखील मेमरीमधूनच.
अपवादात्मक अंमलबजावणी (exceptional execution) या संज्ञेचा अर्थ असा अपवाद आहे ज्यामुळे वर्तमान कॉन्ट्रॅक्टची अंमलबजावणी थांबते.
9.2 शुल्काचे विहंगावलोकन
हा विभाग गॅस शुल्काची गणना कशी केली जाते हे स्पष्ट करतो. तीन खर्च आहेत:
ऑपकोड खर्च
विशिष्ट ऑपकोडचा अंतर्निहित खर्च. हे मूल्य मिळवण्यासाठी, परिशिष्ट H (पृष्ठ 28, समीकरण (327) अंतर्गत) मध्ये ऑपकोडचा खर्च गट शोधा आणि समीकरण (324) मध्ये खर्च गट शोधा. हे तुम्हाला एक खर्च कार्य (cost function) देते, जे बहुतांश प्रकरणांमध्ये परिशिष्ट G (पृष्ठ 27) मधील पॅरामीटर्स वापरते.
उदाहरणार्थ, CALLDATACOPY (opens in a new tab) ऑपकोड हा 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) पाहता, μ ही मशीन स्थिती आहे. मशीन स्थिती पृष्ठ 13 वरील विभाग 9.4.1 मध्ये परिभाषित केली आहे. त्या विभागानुसार, मशीन स्थिती पॅरामीटर्सपैकी एक स्टॅकसाठी s आहे. हे सर्व एकत्र केल्यावर, असे दिसते की μs[2] हे स्टॅकमधील लोकेशन #2 आहे. ऑपकोड (opens in a new tab) पाहता, स्टॅकमधील लोकेशन #2 हा बाइट्समधील डेटाचा आकार आहे. Wcopy गटातील इतर ऑपकोड्स, CODECOPY (opens in a new tab) आणि RETURNDATACOPY (opens in a new tab) पाहता, त्यांच्याकडे देखील त्याच लोकेशनमध्ये डेटाचा आकार आहे. त्यामुळे ⌈μs[2]÷32⌉ ही कॉपी केल्या जाणाऱ्या डेटाला साठवण्यासाठी आवश्यक असलेल्या 32 बाइट शब्दांची संख्या आहे. सर्वकाही एकत्र केल्यावर, CALLDATACOPY (opens in a new tab) चा अंतर्निहित खर्च 3 गॅस अधिक कॉपी केल्या जाणाऱ्या डेटाच्या प्रति शब्दासाठी 3 आहे.
रनिंग खर्च
आपण कॉल करत असलेला कोड चालवण्याचा खर्च.
CREATE(opens in a new tab) आणिCREATE2(opens in a new tab) च्या बाबतीत, नवीन कॉन्ट्रॅक्टसाठी कन्स्ट्रक्टर.CALL(opens in a new tab),CALLCODE(opens in a new tab),STATICCALL(opens in a new tab), किंवाDELEGATECALL(opens in a new tab) च्या बाबतीत, आपण कॉल करत असलेले कॉन्ट्रॅक्ट.
मेमरी विस्तार खर्च
मेमरी विस्तारण्याचा खर्च (आवश्यक असल्यास).
समीकरण 324 मध्ये, हे मूल्य Cmem(μi')-Cmem(μi) असे लिहिले आहे. पुन्हा विभाग 9.4.1 पाहता, आपल्याला दिसते की μi ही मेमरीमधील शब्दांची संख्या आहे. त्यामुळे μi ही ऑपकोडच्या आधी मेमरीमधील शब्दांची संख्या आहे आणि μi' ही ऑपकोडनंतर मेमरीमधील शब्दांची संख्या आहे.
Cmem फंक्शन समीकरण 326 मध्ये परिभाषित केले आहे: 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 (opens in a new tab) | address(this) |
| Io | ORIGIN (opens in a new tab) | tx.origin |
| Ip | GASPRICE (opens in a new tab) | tx.gasprice |
| Id | CALLDATALOAD (opens in a new tab), इत्यादी. | msg.data |
| Is | CALLER (opens in a new tab) | msg.sender |
| Iv | CALLVALUE (opens in a new tab) | msg.value |
| Ib | CODECOPY (opens in a new tab) | address(this).code |
| IH | ब्लॉक हेडर फील्ड्स, जसे की NUMBER (opens in a new tab) आणि DIFFICULTY (opens in a new tab) | block.number, block.difficulty, इत्यादी. |
| Ie | कॉन्ट्रॅक्ट्समधील कॉल्ससाठी कॉल स्टॅकची खोली (कॉन्ट्रॅक्ट निर्मितीसह) | |
| Iw | EVM ला स्थिती बदलण्याची परवानगी आहे का, की ते स्टॅटिकली चालत आहे |
विभाग 9 चा उर्वरित भाग समजून घेण्यासाठी आणखी काही पॅरामीटर्स आवश्यक आहेत:
| पॅरामीटर | विभागात परिभाषित | अर्थ |
|---|---|---|
| σ | 2 (पृष्ठ 2, समीकरण 1) | ब्लॉकचेनची स्थिती |
| g | 9.3 (पृष्ठ 13) | उर्वरित गॅस |
| A | 6.1 (पृष्ठ 8) | जमा झालेली उपस्थिती (व्यवहार संपल्यावर होणारे बदल) |
| o | 9.3 (पृष्ठ 13) | आउटपुट - अंतर्गत व्यवहाराच्या बाबतीत परत आलेला निकाल (जेव्हा एक कॉन्ट्रॅक्ट दुसऱ्याला कॉल करते) आणि व्ह्यू फंक्शन्सना कॉल्स (जेव्हा तुम्ही फक्त माहिती विचारत असता, त्यामुळे व्यवहाराची वाट पाहण्याची गरज नसते) |
9.4 अंमलबजावणी विहंगावलोकन
आता आपल्याकडे सर्व प्राथमिक माहिती असल्याने, आपण शेवटी EVM कसे कार्य करते यावर काम सुरू करू शकतो.
समीकरणे 137-142 आपल्याला EVM चालवण्यासाठी प्रारंभिक अटी देतात:
| प्रतीक | प्रारंभिक मूल्य | अर्थ |
|---|---|---|
| μg | g | उर्वरित गॅस |
| μpc | 0 | प्रोग्राम काउंटर, कार्यान्वित करण्यासाठी पुढील सूचनेचा पत्ता |
| μm | (0, 0, ...) | मेमरी, सर्व शून्यांवर इनिशियलाइज केलेली |
| μi | 0 | वापरलेले सर्वोच्च मेमरी लोकेशन |
| μs | () | स्टॅक, सुरुवातीला रिकामा |
| μo | ∅ | आउटपुट, जोपर्यंत आपण रिटर्न डेटासह (RETURN (opens in a new tab) किंवा REVERT (opens in a new tab)) किंवा त्याशिवाय (STOP (opens in a new tab) किंवा SELFDESTRUCT (opens in a new tab)) थांबत नाही तोपर्यंत रिकामा संच. |
समीकरण 143 आपल्याला सांगते की अंमलबजावणी दरम्यान प्रत्येक वेळी चार संभाव्य अटी असतात आणि त्यांचे काय करायचे:
Z(σ,μ,A,I). Z हे एक फंक्शन दर्शवते जे ऑपरेशन अवैध स्थिती संक्रमण (invalid state transition) तयार करते की नाही याची चाचणी करते (अपवादात्मक थांबणे (exceptional halting) पहा). जर ते True म्हणून मूल्यमापन करत असेल, तर नवीन स्थिती जुन्या स्थितीसारखीच असते (गॅस जळतो तो वगळता) कारण बदल लागू केले गेले नाहीत.- जर कार्यान्वित केला जाणारा ऑपकोड
REVERT(opens in a new tab) असेल, तर नवीन स्थिती जुन्या स्थितीसारखीच असते, काही गॅस गमावला जातो. - जर ऑपरेशन्सचा क्रम पूर्ण झाला असेल, जसे की
RETURN(opens in a new tab) द्वारे दर्शविले जाते), तर स्थिती नवीन स्थितीमध्ये अद्यतनित केली जाते. - जर आपण 1-3 पैकी एका अंतिम अटीवर नसू, तर चालवणे सुरू ठेवा.
9.4.1 मशीन स्थिती
हा विभाग मशीन स्थिती अधिक तपशीलवार स्पष्ट करतो. हे निर्दिष्ट करते की w हा वर्तमान ऑपकोड आहे. जर μpc हे ||Ib|| पेक्षा कमी असेल, जी कोडची लांबी आहे, तर तो बाइट (Ib[μpc]) ऑपकोड आहे. अन्यथा, ऑपकोड STOP (opens in a new tab) म्हणून परिभाषित केला जातो.
हे एक स्टॅक मशीन (opens in a new tab) असल्याने, आपल्याला प्रत्येक ऑपकोडद्वारे पॉप आउट केलेल्या (δ) आणि पुश इन केलेल्या (α) आयटम्सच्या संख्येचा मागोवा ठेवणे आवश्यक आहे.
9.4.2 अपवादात्मक थांबणे
हा विभाग Z फंक्शन परिभाषित करतो, जे आपण असामान्य समाप्ती (abnormal termination) कधी करतो हे निर्दिष्ट करते. हे एक बुलियन (Boolean) (opens in a new tab) फंक्शन आहे, त्यामुळे ते लॉजिकल or साठी ∨ (opens in a new tab) आणि लॉजिकल and साठी ∧ (opens in a new tab) वापरते.
यापैकी कोणतीही अट सत्य असल्यास आपले अपवादात्मक थांबणे होते:
-
μg < C(σ,μ,A,I) आपण विभाग 9.2 मध्ये पाहिल्याप्रमाणे, C हे फंक्शन आहे जे गॅस खर्च निर्दिष्ट करते. पुढील ऑपकोड कव्हर करण्यासाठी पुरेसा गॅस शिल्लक नाही.
-
δw=∅ जर ऑपकोडसाठी पॉप केलेल्या आयटम्सची संख्या अनिर्दिष्ट असेल, तर ऑपकोड स्वतःच अनिर्दिष्ट आहे.
-
|| μs || < δw स्टॅक अंडरफ्लो, वर्तमान ऑपकोडसाठी स्टॅकमध्ये पुरेसे आयटम्स नाहीत.
-
w = JUMP ∧ μs[0]∉D(Ib) ऑपकोड
JUMP(opens in a new tab) आहे आणि पत्ताJUMPDEST(opens in a new tab) नाही. जंप्स केवळ तेव्हाच वैध असतात जेव्हा गंतव्यस्थानJUMPDEST(opens in a new tab) असते. -
w = JUMPI ∧ μs[1]≠0 ∧ μs[0] ∉ D(Ib) ऑपकोड
JUMPI(opens in a new tab) आहे, अट सत्य आहे (शून्य नसलेली) त्यामुळे जंप व्हायला हवी, आणि पत्ताJUMPDEST(opens in a new tab) नाही. जंप्स केवळ तेव्हाच वैध असतात जेव्हा गंतव्यस्थानJUMPDEST(opens in a new tab) असते. -
w = RETURNDATACOPY ∧ μs[1]+μs[2]>|| μo || ऑपकोड
RETURNDATACOPY(opens in a new tab) आहे. या ऑपकोडमध्ये स्टॅक घटक μs[1] हा रिटर्न डेटा बफरमधून वाचण्यासाठी ऑफसेट आहे आणि स्टॅक घटक μs[2] ही डेटाची लांबी आहे. जेव्हा तुम्ही रिटर्न डेटा बफरच्या शेवटी पलीकडे वाचण्याचा प्रयत्न करता तेव्हा ही स्थिती उद्भवते. लक्षात घ्या की कॉल डेटा किंवा स्वतः कोडसाठी अशी कोणतीही समान अट नाही. जेव्हा तुम्ही त्या बफर्सच्या शेवटी पलीकडे वाचण्याचा प्रयत्न करता तेव्हा तुम्हाला फक्त शून्य मिळतात. -
|| μs || - δw + αw > 1024
स्टॅक ओव्हरफ्लो. जर ऑपकोड चालवल्याने 1024 पेक्षा जास्त आयटम्सचा स्टॅक तयार होत असेल, तर रद्द करा.
-
¬Iw ∧ W(w,μ) आपण स्टॅटिकली चालवत आहोत का (¬ हे निगेशन (negation) आहे (opens in a new tab) आणि जेव्हा आपल्याला ब्लॉकचेन स्थिती बदलण्याची परवानगी असते तेव्हा Iw सत्य असते)? तसे असल्यास, आणि आपण स्थिती बदलण्याचा प्रयत्न करत असल्यास, ते होऊ शकत नाही.
W(w,μ) फंक्शन नंतर समीकरण 150 मध्ये परिभाषित केले आहे. यापैकी एक अट सत्य असल्यास W(w,μ) सत्य आहे:
-
w ∈ {CREATE, CREATE2, SSTORE, SELFDESTRUCT} हे ऑपकोड्स नवीन कॉन्ट्रॅक्ट तयार करून, मूल्य साठवून किंवा वर्तमान कॉन्ट्रॅक्ट नष्ट करून स्थिती बदलतात.
-
LOG0≤w ∧ w≤LOG4 जर आपल्याला स्टॅटिकली कॉल केले गेले असेल तर आपण लॉग नोंदी उत्सर्जित करू शकत नाही. लॉग ऑपकोड्स सर्व
LOG0(A0) (opens in a new tab) आणिLOG4(A4) (opens in a new tab) च्या दरम्यानच्या श्रेणीत आहेत. लॉग ऑपकोड नंतरची संख्या लॉग नोंदणीमध्ये किती विषय आहेत हे निर्दिष्ट करते. -
w=CALL ∧ μs[2]≠0 जेव्हा तुम्ही स्टॅटिक असता तेव्हा तुम्ही दुसऱ्या कॉन्ट्रॅक्टला कॉल करू शकता, परंतु तसे केल्यास तुम्ही त्याला ETH हस्तांतरित करू शकत नाही.
-
-
w = SSTORE ∧ μg ≤ Gcallstipend जोपर्यंत तुमच्याकडे Gcallstipend (परिशिष्ट G मध्ये 2300 म्हणून परिभाषित) पेक्षा जास्त गॅस नाही तोपर्यंत तुम्ही
SSTORE(opens in a new tab) चालवू शकत नाही.
9.4.3 जंप गंतव्यस्थानाची वैधता
येथे आपण औपचारिकपणे JUMPDEST (opens in a new tab) ऑपकोड्स काय आहेत हे परिभाषित करतो. आपण फक्त बाइट मूल्य 0x5B शोधू शकत नाही, कारण ते PUSH च्या आत असू शकते (आणि म्हणून डेटा असू शकतो आणि ऑपकोड नाही).
समीकरण (153) मध्ये आपण एक फंक्शन, N(i,w) परिभाषित करतो. पहिला पॅरामीटर, i, ऑपकोडचे लोकेशन आहे. दुसरा, w, स्वतः ऑपकोड आहे. जर w∈[PUSH1, PUSH32] असेल तर याचा अर्थ ऑपकोड PUSH आहे (चौकोनी कंस एक श्रेणी परिभाषित करतात ज्यामध्ये अंतिम बिंदू समाविष्ट असतात). त्या बाबतीत पुढील ऑपकोड i+2+(w−PUSH1) वर आहे. PUSH1 (opens in a new tab) साठी आपल्याला दोन बाइट्सने पुढे जावे लागेल (स्वतः PUSH आणि एक बाइट मूल्य), PUSH2 (opens in a new tab) साठी आपल्याला तीन बाइट्सने पुढे जावे लागेल कारण ते दोन बाइट मूल्य आहे, इत्यादी. इतर सर्व EVM ऑपकोड्स फक्त एक बाइट लांब आहेत, त्यामुळे इतर सर्व प्रकरणांमध्ये N(i,w)=i+1.
हे फंक्शन समीकरण (152) मध्ये DJ(c,i) परिभाषित करण्यासाठी वापरले जाते, जो कोड c मधील सर्व वैध जंप गंतव्यस्थानांचा संच (set) (opens in a new tab) आहे, जो ऑपकोड लोकेशन 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(opens in a new tab) किंवाSELFDESTRUCT(opens in a new tab)), तर रिटर्न व्हॅल्यू म्हणून शून्य बाइट्स आकाराचा क्रम परत करा. लक्षात घ्या की हे रिकाम्या संचापेक्षा खूप वेगळे आहे. या मूल्याचा अर्थ असा आहे की EVM खरोखरच थांबले, फक्त वाचण्यासाठी कोणताही रिटर्न डेटा नाही. - जर आपल्याकडे असा हॉल्ट ऑपकोड असेल जो आउटपुट तयार करतो (
RETURN(opens in a new tab) किंवाREVERT(opens in a new tab)), तर त्या ऑपकोडद्वारे निर्दिष्ट केलेला बाइट्सचा क्रम परत करा. हा क्रम मेमरीमधून घेतला जातो, स्टॅकच्या शीर्षस्थानी असलेले मूल्य (μs[0]) हा पहिला बाइट आहे आणि त्यानंतरचे मूल्य (μs[1]) ही लांबी आहे.
H.2 सूचना संच
आपण EVM च्या अंतिम उपविभाग, 9.5 कडे जाण्यापूर्वी, आपण स्वतः सूचना पाहूया. त्या परिशिष्ट H.2 मध्ये परिभाषित केल्या आहेत जे पृष्ठ 29 वर सुरू होते. त्या विशिष्ट ऑपकोडसह बदलत असल्याचे निर्दिष्ट न केलेली कोणतीही गोष्ट तशीच राहणे अपेक्षित आहे. जे व्हेरिएबल्स बदलतात ते <something>′ म्हणून निर्दिष्ट केले जातात.
उदाहरणार्थ, आपण ADD (opens in a new tab) ऑपकोड पाहूया.
| मूल्य | नेमोनिक | δ | α | वर्णन |
|---|---|---|---|---|
| 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 अद्यतनित करणे आवश्यक आहे. आपण हे पृष्ठ 29 वरील समीकरण 328 मध्ये परिभाषित केलेले M फंक्शन वापरून करतो.
| मूल्य | नेमोनिक | δ | α | वर्णन |
|---|---|---|---|---|
| 0x31 | BALANCE | 1 | 1 | दिलेल्या खात्याची शिल्लक मिळवा. |
| ... |
ज्या पत्त्याची शिल्लक आपल्याला शोधायची आहे तो μs[0] mod 2160 आहे. स्टॅकच्या शीर्षस्थानी पत्ता आहे, परंतु पत्ते केवळ 160 बिट्सचे असल्याने, आपण मॉड्युलो (modulo) (opens in a new tab) 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}, हे वॉर्म स्टोरेज (warm storage - असे स्टोरेज जे अलीकडेच ॲक्सेस केले गेले आहे आणि कॅशे (cached) असण्याची शक्यता आहे) आणि कोल्ड स्टोरेज (cold storage - असे स्टोरेज जे ॲक्सेस केले गेले नाही आणि जे धीम्या स्टोरेजमध्ये असण्याची शक्यता आहे जे पुनर्प्राप्त करण्यासाठी अधिक महाग आहे) यांच्या ॲक्सेसमधील खर्चाच्या फरकाशी संबंधित आहे. Aa ही व्यवहाराद्वारे पूर्वी ॲक्सेस केलेल्या पत्त्यांची यादी आहे, जी पृष्ठ 8 वरील विभाग 6.1 मध्ये परिभाषित केल्यानुसार ॲक्सेस करण्यासाठी स्वस्त असावी. तुम्ही या विषयाबद्दल EIP-2929 (opens in a new tab) मध्ये अधिक वाचू शकता.
| मूल्य | नेमोनिक | δ | α | वर्णन |
|---|---|---|---|---|
| 0x8F | DUP16 | 16 | 17 | 16 वा स्टॅक आयटम डुप्लिकेट करा. |
| μ′s[0] ≡ μs[15] |
लक्षात घ्या की कोणताही स्टॅक आयटम वापरण्यासाठी, आपल्याला तो पॉप करणे आवश्यक आहे, ज्याचा अर्थ असा आहे की आपल्याला त्याच्या वरचे सर्व स्टॅक आयटम्स देखील पॉप करणे आवश्यक आहे. DUP<n> (opens in a new tab) आणि SWAP<n> (opens in a new tab) च्या बाबतीत, याचा अर्थ सोळा मूल्यांपर्यंत पॉप करणे आणि नंतर पुश करणे असा होतो.
9.5 अंमलबजावणी चक्र
आता आपल्याकडे सर्व भाग असल्याने, आपण शेवटी EVM चे अंमलबजावणी चक्र कसे दस्तऐवजीकरण केले आहे हे समजू शकतो.
समीकरण (155) सांगते की दिलेली स्थिती:
- σ (जागतिक ब्लॉकचेन स्थिती)
- μ (EVM स्थिती)
- A (उपस्थिती, व्यवहार संपल्यावर होणारे बदल)
- I (अंमलबजावणी वातावरण)
नवीन स्थिती (σ', μ', A', I') आहे.
समीकरणे (156)-(158) स्टॅक आणि ऑपकोडमुळे (μs) त्यात होणारा बदल परिभाषित करतात. समीकरण (159) हा गॅसमधील बदल (μg) आहे. समीकरण (160) हा प्रोग्राम काउंटरमधील बदल (μpc) आहे. शेवटी, समीकरणे (161)-(164) निर्दिष्ट करतात की इतर पॅरामीटर्स तसेच राहतात, जोपर्यंत ऑपकोडद्वारे स्पष्टपणे बदलले जात नाहीत.
यासह EVM पूर्णपणे परिभाषित केले आहे.
निष्कर्ष
गणितीय नोटेशन अचूक आहे आणि त्याने येलो पेपरला इथेरियमचा प्रत्येक तपशील निर्दिष्ट करण्याची परवानगी दिली आहे. तथापि, यात काही त्रुटी आहेत:
- हे केवळ मानवांनाच समजू शकते, ज्याचा अर्थ असा आहे की अनुपालन चाचण्या (compliance tests) (opens in a new tab) मॅन्युअली लिहिल्या गेल्या पाहिजेत.
- प्रोग्रामर्सना संगणक कोड समजतो. त्यांना गणितीय नोटेशन समजू शकते किंवा नाही.
कदाचित याच कारणांमुळे, नवीन सहमती स्तर तपशील (opens in a new tab) Python मध्ये लिहिलेले आहेत. Python मध्ये अंमलबजावणी स्तर तपशील (opens in a new tab) आहेत, परंतु ते पूर्ण नाहीत. जोपर्यंत संपूर्ण येलो पेपर देखील Python किंवा तत्सम भाषेत अनुवादित होत नाही, तोपर्यंत येलो पेपर सेवेत राहील आणि तो वाचता येणे उपयुक्त आहे.