یلو پیپر کی EVM خصوصیات کو سمجھنا
یلو پیپر (opens in a new tab) ایتھیریم کے لیے باضابطہ تصریح (specification) ہے۔ سوائے ان جگہوں کے جہاں EIP عمل کے ذریعے ترمیم کی گئی ہو، اس میں ہر چیز کے کام کرنے کے طریقے کی بالکل درست وضاحت موجود ہے۔ یہ ایک ریاضیاتی مقالے کے طور پر لکھا گیا ہے، جس میں ایسی اصطلاحات شامل ہیں جن سے پروگرامرز شاید واقف نہ ہوں۔ اس مقالے میں آپ اسے پڑھنا سیکھیں گے، اور اس کے ساتھ دیگر متعلقہ ریاضیاتی مقالے بھی۔
کون سا یلو پیپر؟
ایتھیریم کی تقریباً ہر دوسری چیز کی طرح، یلو پیپر بھی وقت کے ساتھ ساتھ ارتقاء پذیر ہوتا ہے۔ کسی مخصوص ورژن کا حوالہ دینے کے قابل ہونے کے لیے، میں نے لکھتے وقت کا موجودہ ورژن اپ لوڈ کر دیا ہے۔ میں جو سیکشن، صفحہ، اور مساوات کے نمبر استعمال کروں گا وہ اسی ورژن کا حوالہ دیں گے۔ اس دستاویز کو پڑھتے وقت اسے کسی دوسری ونڈو میں کھلا رکھنا ایک اچھا خیال ہے۔
EVM کیوں؟
اصل یلو پیپر ایتھیریم کی ڈیولپمنٹ کے بالکل آغاز میں لکھا گیا تھا۔ یہ اصل پروف-آف-ورک (proof-of-work) پر مبنی اتفاق رائے کے طریقہ کار کو بیان کرتا ہے جو اصل میں نیٹ ورک کو محفوظ بنانے کے لیے استعمال کیا گیا تھا۔ تاہم، ایتھیریم نے پروف-آف-ورک کو بند کر دیا اور ستمبر 2022 میں پروف-آف-اسٹیک (proof-of-stake) پر مبنی اتفاق رائے کا استعمال شروع کر دیا۔ یہ ٹیوٹوریل یلو پیپر کے ان حصوں پر توجہ مرکوز کرے گا جو ایتھیریم ورچوئل مشین (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) میں اسٹور کرتا ہے۔ یہ ورچوئل مشینوں کے لیے ترجیحی فن تعمیر (architecture) ہے کیونکہ اسے نافذ کرنا آسان ہے جس کا مطلب ہے کہ بگز اور سیکیورٹی کمزوریوں کا امکان بہت کم ہوتا ہے۔ اسٹیک میں میموری کو 256-بٹ ورڈز (words) میں تقسیم کیا گیا ہے۔ اسے اس لیے منتخب کیا گیا کیونکہ یہ ایتھیریم کے بنیادی کرپٹوگرافک آپریشنز جیسے Keccak-256 ہیشنگ اور ایلپٹک کرو (elliptic curve) کمپیوٹیشنز کے لیے آسان ہے۔ اسٹیک کا زیادہ سے زیادہ سائز 1024 آئٹمز (1024 x 256 بٹس) ہے۔ جب اوپ کوڈز (opcodes) کو ایگزیکیوٹ کیا جاتا ہے تو وہ عام طور پر اپنے پیرامیٹرز اسٹیک سے حاصل کر رہے ہوتے ہیں۔ اسٹیک میں عناصر کو دوبارہ ترتیب دینے کے لیے خاص طور پر اوپ کوڈز موجود ہیں جیسے POP (اسٹیک کے اوپری حصے سے آئٹم کو ہٹاتا ہے)، DUP_N (اسٹیک میں Nویں آئٹم کی نقل بناتا ہے)، وغیرہ۔
EVM میں ایک غیر مستقل (volatile) جگہ بھی ہوتی ہے جسے میموری کہا جاتا ہے جو ایگزیکیوشن کے دوران ڈیٹا کو اسٹور کرنے کے لیے استعمال ہوتی ہے۔ یہ میموری 32-بائٹ ورڈز میں منظم ہوتی ہے۔ تمام میموری لوکیشنز کو صفر پر انیشلائز کیا جاتا ہے۔ اگر آپ میموری میں ایک ورڈ شامل کرنے کے لیے اس Yul (opens in a new tab) کوڈ کو ایگزیکیوٹ کرتے ہیں، تو یہ ورڈ میں خالی جگہ کو صفر سے بھر کر میموری کے 32 بائٹس کو پُر کر دے گا، یعنی، یہ ایک ورڈ بناتا ہے - جس میں 0-29 لوکیشنز پر صفر، 30 پر 0x60، اور 31 پر 0xA7 ہوتا ہے۔
1mstore(0, 0x60A7)mstore ان تین اوپ کوڈز میں سے ایک ہے جو EVM میموری کے ساتھ تعامل کے لیے فراہم کرتا ہے - یہ میموری میں ایک ورڈ لوڈ کرتا ہے۔ دیگر دو mstore8 ہیں جو میموری میں ایک بائٹ لوڈ کرتا ہے، اور mload جو میموری سے اسٹیک میں ایک ورڈ منتقل کرتا ہے۔
EVM میں ایک الگ غیر متزلزل (non-volatile) اسٹوریج ماڈل بھی ہے جسے سسٹم اسٹیٹ کے حصے کے طور پر برقرار رکھا جاتا ہے - یہ میموری ورڈ ایریز (word arrays) میں منظم ہوتی ہے (اسٹیک میں ورڈ-ایڈریس ایبل بائٹ ایریز کے برعکس)۔ یہ اسٹوریج وہ جگہ ہے جہاں کنٹریکٹس مستقل ڈیٹا رکھتے ہیں - ایک کنٹریکٹ صرف اپنے اسٹوریج کے ساتھ تعامل کر سکتا ہے۔ اسٹوریج کو کلید-قدر (key-value) میپنگز میں منظم کیا جاتا ہے۔
اگرچہ یلو پیپر کے اس حصے میں اس کا ذکر نہیں کیا گیا ہے، لیکن یہ جاننا بھی مفید ہے کہ میموری کی ایک چوتھی قسم بھی ہے۔ کال ڈیٹا (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) کی اصطلاح کا مطلب ایک ایسی استثنا (exception) ہے جو موجودہ کنٹریکٹ کی ایگزیکیوشن کو روکنے کا سبب بنتی ہے۔
9.2 فیس کا جائزہ
یہ سیکشن بتاتا ہے کہ گیس فیس کا حساب کیسے لگایا جاتا ہے۔ اس کی تین لاگتیں ہیں:
اوپ کوڈ کی لاگت
مخصوص اوپ کوڈ کی موروثی لاگت۔ یہ ویلیو حاصل کرنے کے لیے، ضمیمہ H (صفحہ 28، مساوات (327) کے تحت) میں اوپ کوڈ کا کاسٹ گروپ تلاش کریں، اور مساوات (324) میں کاسٹ گروپ تلاش کریں۔ یہ آپ کو ایک کاسٹ فنکشن دیتا ہے، جو زیادہ تر معاملات میں ضمیمہ G (صفحہ 27) سے پیرامیٹرز استعمال کرتا ہے۔
مثال کے طور پر، اوپ کوڈ CALLDATACOPY (opens in a new tab) گروپ Wcopy کا رکن ہے۔ اس گروپ کے لیے اوپ کوڈ کی لاگت Gverylow+Gcopy×⌈μs[2]÷32⌉ ہے۔ ضمیمہ G کو دیکھتے ہوئے، ہم دیکھتے ہیں کہ دونوں مستقل (constants) 3 ہیں، جو ہمیں 3+3×⌈μs[2]÷32⌉ دیتا ہے۔
ہمیں ابھی بھی ⌈μs[2]÷32⌉ کے اظہار کو سمجھنے کی ضرورت ہے۔ سب سے بیرونی حصہ، ⌈ <value> ⌉ سیلنگ فنکشن (ceiling function) ہے، ایک ایسا فنکشن جو دی گئی ویلیو پر سب سے چھوٹا عدد (integer) واپس کرتا ہے جو اس ویلیو سے چھوٹا نہیں ہوتا۔ مثال کے طور پر، ⌈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⌋ مثبت ہوتا ہے۔ جب درکار میموری کافی زیادہ ہو تو گیس کی لاگت میموری کی مقدار کے مربع (square) کے متناسب ہوتی ہے۔
نوٹ کریں کہ یہ عوامل صرف موروثی گیس کی لاگت کو متاثر کرتے ہیں - یہ فیس مارکیٹ یا ویلیڈیٹرز کو دی جانے والی ٹپس کو مدنظر نہیں رکھتا جو یہ طے کرتے ہیں کہ آخری صارف کو کتنی ادائیگی کرنی ہے - یہ صرف 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), etc. | 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, etc. |
| Ie | کنٹریکٹس کے درمیان کالز کے لیے کال اسٹیک کی گہرائی (بشمول کنٹریکٹ کی تخلیق) | |
| Iw | کیا EVM کو اسٹیٹ تبدیل کرنے کی اجازت ہے، یا یہ جامد (statically) طور پر چل رہی ہے |
سیکشن 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 ایک ایسے فنکشن کی نمائندگی کرتا ہے جو یہ جانچتا ہے کہ آیا کوئی آپریشن ایک غلط اسٹیٹ ٹرانزیشن بناتا ہے (دیکھیں غیر معمولی ہالٹنگ)۔ اگر یہ درست (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) ہے، اس لیے ہمیں ہر اوپ کوڈ کے ذریعے نکالے گئے (popped out) (δ) اور ڈالے گئے (pushed in) (α) آئٹمز کی تعداد کا ٹریک رکھنے کی ضرورت ہے۔
9.4.2 غیر معمولی ہالٹنگ
یہ سیکشن Z فنکشن کی تعریف کرتا ہے، جو یہ بتاتا ہے کہ کب ہمارے پاس غیر معمولی برطرفی (abnormal termination) ہوتی ہے۔ یہ ایک بولین (Boolean) (opens in a new tab) فنکشن ہے، اس لیے یہ منطقی OR کے لیے ∨ (opens in a new tab) اور منطقی AND کے لیے ∧ (opens in a new tab) کا استعمال کرتا ہے۔
ہمارے پاس ایک غیر معمولی ہالٹ (exceptional halt) ہوتا ہے اگر ان میں سے کوئی بھی شرط درست ہو:
-
μg < C(σ,μ,A,I) جیسا کہ ہم نے سیکشن 9.2 میں دیکھا، C وہ فنکشن ہے جو گیس کی لاگت بتاتا ہے۔ اگلے اوپ کوڈ کو کور کرنے کے لیے کافی گیس نہیں بچی ہے۔
-
δw=∅ اگر کسی اوپ کوڈ کے لیے نکالے گئے آئٹمز کی تعداد غیر متعین (undefined) ہے، تو اوپ کوڈ خود غیر متعین ہے۔
-
|| μs || < δw اسٹیک انڈر فلو (Stack underflow)، موجودہ اوپ کوڈ کے لیے اسٹیک میں کافی آئٹمز نہیں ہیں۔
-
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] ریٹرن ڈیٹا بفر میں پڑھنے کے لیے آفسیٹ (offset) ہے، اور اسٹیک عنصر μs[2] ڈیٹا کی لمبائی ہے۔ یہ شرط اس وقت پیش آتی ہے جب آپ ریٹرن ڈیٹا بفر کے اختتام سے آگے پڑھنے کی کوشش کرتے ہیں۔ نوٹ کریں کہ کال ڈیٹا یا خود کوڈ کے لیے ایسی کوئی شرط نہیں ہے۔ جب آپ ان بفرز کے اختتام سے آگے پڑھنے کی کوشش کرتے ہیں تو آپ کو صرف صفر ملتے ہیں۔ -
|| μs || - δw + αw > 1024 اسٹیک اوور فلو (Stack overflow)۔ اگر اوپ کوڈ چلانے کے نتیجے میں 1024 سے زیادہ آئٹمز کا اسٹیک بنتا ہے، تو منسوخ (abort) کر دیں۔
-
¬Iw ∧ W(w,μ) کیا ہم جامد (statically) طور پر چل رہے ہیں (¬ نفی (negation) ہے (opens in a new tab) اور Iw اس وقت درست ہوتا ہے جب ہمیں بلاک چین اسٹیٹ کو تبدیل کرنے کی اجازت ہوتی ہے)؟ اگر ایسا ہے، اور ہم اسٹیٹ تبدیل کرنے والے آپریشن کی کوشش کر رہے ہیں، تو یہ نہیں ہو سکتا۔
فنکشن W(w,μ) کی تعریف بعد میں مساوات 150 میں کی گئی ہے۔ W(w,μ) درست ہے اگر ان میں سے کوئی ایک شرط درست ہو:
-
w ∈ {CREATE, CREATE2, SSTORE, SELFDESTRUCT} یہ اوپ کوڈز اسٹیٹ کو تبدیل کرتے ہیں، یا تو نیا کنٹریکٹ بنا کر، کوئی ویلیو اسٹور کر کے، یا موجودہ کنٹریکٹ کو تباہ کر کے۔
-
LOG0≤w ∧ w≤LOG4 اگر ہمیں جامد طور پر کال کیا جاتا ہے تو ہم لاگ (log) اندراجات خارج نہیں کر سکتے۔ لاگ اوپ کوڈز تمام
LOG0(A0) (opens in a new tab) اورLOG4(A4) (opens in a new tab) کے درمیان کی رینج میں ہیں۔ لاگ اوپ کوڈ کے بعد کا نمبر بتاتا ہے کہ لاگ اندراج میں کتنے عنوانات (topics) شامل ہیں۔ -
w=CALL ∧ μs[2]≠0 جب آپ جامد ہوں تو آپ کسی دوسرے کنٹریکٹ کو کال کر سکتے ہیں، لیکن اگر آپ ایسا کرتے ہیں تو آپ اسے ETH منتقل نہیں کر سکتے۔
-
-
w = SSTORE ∧ μg ≤ Gcallstipend آپ
SSTORE(opens in a new tab) نہیں چلا سکتے جب تک کہ آپ کے پاس Gcallstipend (ضمیمہ G میں 2300 کے طور پر بیان کیا گیا ہے) سے زیادہ گیس نہ ہو۔
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 میں تمام درست جمپ منزلوں کا سیٹ (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 سے شروع ہوتا ہے۔ کوئی بھی چیز جس کے بارے میں یہ نہیں بتایا گیا کہ وہ اس مخصوص اوپ کوڈ کے ساتھ تبدیل ہو رہی ہے، اس کے ویسے ہی رہنے کی توقع کی جاتی ہے۔ جو متغیرات (variables) تبدیل ہوتے ہیں انہیں <something>′ کے طور پر بیان کیا جاتا ہے۔
مثال کے طور پر، آئیے ADD (opens in a new tab) اوپ کوڈ کو دیکھیں۔
| ویلیو | یادداشت (Mnemonic) | δ | α | تفصیل |
|---|---|---|---|---|
| 0x01 | ADD | 2 | 1 | اضافے کا آپریشن۔ |
| μ′s[0] ≡ μs[0] + μs[1] |
δ ان ویلیوز کی تعداد ہے جو ہم اسٹیک سے نکالتے ہیں۔ اس صورت میں دو، کیونکہ ہم اوپر کی دو ویلیوز کو جوڑ رہے ہیں۔
α ان ویلیوز کی تعداد ہے جو ہم واپس ڈالتے ہیں۔ اس صورت میں ایک، جو کہ مجموعہ (sum) ہے۔
لہذا نیا اسٹیک ٹاپ (μ′s[0]) پرانے اسٹیک ٹاپ (μs[0]) اور اس کے نیچے پرانی ویلیو (μs[1]) کا مجموعہ ہے۔
ایک طویل اور بورنگ فہرست کے ساتھ تمام اوپ کوڈز پر جانے کے بجائے، یہ مضمون صرف ان اوپ کوڈز کی وضاحت کرتا ہے جو کچھ نیا متعارف کراتے ہیں۔
| ویلیو | یادداشت (Mnemonic) | δ | α | تفصیل |
|---|---|---|---|---|
| 0x20 | KECCAK256 | 2 | 1 | Keccak-256 ہیش کا حساب لگائیں۔ |
| μ′s[0] ≡ KEC(μm[μs[0] . . . (μs[0] + μs[1] − 1)]) | ||||
| μ′i ≡ M(μi,μs[0],μs[1]) |
یہ پہلا اوپ کوڈ ہے جو میموری تک رسائی حاصل کرتا ہے (اس صورت میں، صرف پڑھنے کے لیے)۔ تاہم، یہ میموری کی موجودہ حدود سے آگے بڑھ سکتا ہے، اس لیے ہمیں μi کو اپ ڈیٹ کرنے کی ضرورت ہے۔ ہم یہ صفحہ 29 پر مساوات 328 میں بیان کردہ M فنکشن کا استعمال کرتے ہوئے کرتے ہیں۔
| ویلیو | یادداشت (Mnemonic) | δ | α | تفصیل |
|---|---|---|---|---|
| 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}، وارم اسٹوریج (وہ اسٹوریج جس تک حال ہی میں رسائی حاصل کی گئی ہو اور جس کے کیش (cached) ہونے کا امکان ہو) اور کولڈ اسٹوریج (وہ اسٹوریج جس تک رسائی حاصل نہ کی گئی ہو اور جس کے سست اسٹوریج میں ہونے کا امکان ہو جسے بازیافت کرنا زیادہ مہنگا ہو) تک رسائی کے درمیان لاگت کے فرق سے متعلق ہے۔ Aa ان پتوں کی فہرست ہے جن تک ٹرانزیکشن کے ذریعے پہلے رسائی حاصل کی گئی تھی، اس لیے ان تک رسائی سستی ہونی چاہیے، جیسا کہ صفحہ 8 پر سیکشن 6.1 میں بیان کیا گیا ہے۔ آپ اس موضوع کے بارے میں EIP-2929 (opens in a new tab) میں مزید پڑھ سکتے ہیں۔
| ویلیو | یادداشت (Mnemonic) | δ | α | تفصیل |
|---|---|---|---|---|
| 0x8F | DUP16 | 16 | 17 | 16ویں اسٹیک آئٹم کی نقل بنائیں۔ |
| μ′s[0] ≡ μs[15] |
نوٹ کریں کہ کسی بھی اسٹیک آئٹم کو استعمال کرنے کے لیے، ہمیں اسے نکالنا (pop) ہوگا، جس کا مطلب ہے کہ ہمیں اس کے اوپر موجود تمام اسٹیک آئٹمز کو بھی نکالنا ہوگا۔ DUP<n> (opens in a new tab) اور SWAP<n> (opens in a new tab) کے معاملے میں، اس کا مطلب ہے کہ سولہ ویلیوز تک کو نکالنا اور پھر ڈالنا (push) پڑتا ہے۔
9.5 ایگزیکیوشن سائیکل
اب جب کہ ہمارے پاس تمام حصے موجود ہیں، ہم بالآخر سمجھ سکتے ہیں کہ EVM کے ایگزیکیوشن سائیکل کو کیسے دستاویزی شکل دی گئی ہے۔
مساوات (155) کہتی ہے کہ دی گئی اسٹیٹ کے مطابق:
- σ (عالمی بلاک چین اسٹیٹ)
- μ (EVM اسٹیٹ)
- A (ذیلی اسٹیٹ، ٹرانزیکشن ختم ہونے پر ہونے والی تبدیلیاں)
- I (ایگزیکیوشن کا ماحول)
نئی اسٹیٹ (σ', μ', A', I') ہے۔
مساوات (156)-(158) اسٹیک اور اوپ کوڈ (μs) کی وجہ سے اس میں ہونے والی تبدیلی کی وضاحت کرتی ہیں۔ مساوات (159) گیس (μg) میں تبدیلی ہے۔ مساوات (160) پروگرام کاؤنٹر (μpc) میں تبدیلی ہے۔ آخر میں، مساوات (161)-(164) بتاتی ہیں کہ دیگر پیرامیٹرز ویسے ہی رہتے ہیں، جب تک کہ اوپ کوڈ کے ذریعے واضح طور پر تبدیل نہ کیے جائیں۔
اس کے ساتھ EVM کی مکمل تعریف ہو جاتی ہے۔
نتیجہ
ریاضیاتی اشارے (Mathematical notation) قطعی ہوتے ہیں اور انہوں نے یلو پیپر کو ایتھیریم کی ہر تفصیل بتانے کی اجازت دی ہے۔ تاہم، اس کی کچھ خامیاں بھی ہیں:
- اسے صرف انسان ہی سمجھ سکتے ہیں، جس کا مطلب ہے کہ تعمیل کے ٹیسٹ (compliance tests) (opens in a new tab) دستی طور پر لکھے جانے چاہئیں۔
- پروگرامرز کمپیوٹر کوڈ کو سمجھتے ہیں۔ وہ ریاضیاتی اشارے سمجھ بھی سکتے ہیں اور نہیں بھی۔
شاید انہی وجوہات کی بنا پر، نئی کنسینسس لیئر کی خصوصیات (consensus layer specs) (opens in a new tab) Python میں لکھی گئی ہیں۔ ایگزیکیوشن لیئر کی خصوصیات Python میں (opens in a new tab) موجود ہیں، لیکن وہ مکمل نہیں ہیں۔ جب تک کہ پورا یلو پیپر بھی Python یا اس جیسی کسی زبان میں ترجمہ نہیں ہو جاتا، یلو پیپر سروس میں رہے گا، اور اسے پڑھنے کے قابل ہونا مددگار ہے۔
صفحہ کی آخری اپ ڈیٹ: 3 مارچ، 2026