https://www.preethikasireddy.com/post/how-does-ethereum-work-anyway
هدف المقال هو شرح كيفية عمل Ethereum على المستوى الفني ، بدون حسابات معقدة أو معادلات رياضيه مخيفة. حتى لو لم تكن مبرمجًا ، آمل أن تكون على دراية أفضل بالتكنولوجيا على الأقل بعد قرائته. إذا كانت بعض الأجزاء تقنية للغاية ويصعب فهمها ، فلا بأس بذلك تمامًا! ليست هناك حاجة حقًا لفهم كل التفاصيل الصغيرة. أوصي فقط بالتركيز على فهم الأشياء على مستوى واسع.
العديد من الموضوعات التي تم تناولها في هذا المقال عبارة عن تفصيل للمفاهيم التي تمت مناقشتها في الورقة الصفراء. لقد أضفت التفسيرات والمخططات الخاصة بي لتسهيل فهم Ethereum. أولئك الشجعان بما يكفي لمواجهة التحدي التقني يمكنهم أيضًا قراءة ورقة Ethereum الصفراء.
هيا بنا نبدأ!
تعريف Blockchain
blockchain عبارة عن “آلة مفردة للمعاملات آمنة من الناحية المشفرة وذات حالة مشتركة.” [1] دعونا نكسرها.
- تعني عبارة “آمن من الناحية المشفرة” أن إنشاء العملة الرقمية مؤمن بواسطة خوارزميات رياضية معقدة يصعب كسرها. فكر في جدار حماية من نوع ما. إنها تجعل من المستحيل تقريبًا خداع النظام (على سبيل المثال ، إنشاء معاملات وهمية ، ومحو المعاملات ، وما إلى ذلك)
- تعني “الآلة المنفردة للمعاملات” أن هناك مثيل أساسي واحد للجهاز المسؤول عن جميع المعاملات التي يتم إنشاؤها في النظام. بعبارة أخرى ، هناك حقيقة عالمية واحدة يؤمن بها الجميع.
- تعني عبارة “وذات الحالة المشتركة” أن الحالة المخزنة على هذا الجهاز مشتركة ومفتوحة للجميع.
تطبق Ethereum نموذج blockchain هذا.
شرح نموذج Ethereum blockchain
سلسلة Ethereum blockchain هي في الأساس آلة حاله قائمة على المعاملات. في علوم الكمبيوتر ، تشير آلة الحالة إلى شيء يقرأ سلسلة من المدخلات ، وبناءً على تلك المدخلات ، سينتقل إلى حالة جديدة.
مع آلة حاله Ethereum ، نبدأ بـ “حالة التكوين”. هذا مشابه للجدول الفارغ ، قبل حدوث أي معاملات على الشبكة. عند تنفيذ المعاملات ، تنتقل حالة التكوين هذه إلى حالة نهائية. في أي وقت ، تمثل هذه الحالة النهائية الحالة الحالية لـ Ethereum.
حالة Ethereum لديها ملايين المعاملات. يتم تجميع هذه المعاملات في “كتل”. تحتوي الكتلة على سلسلة من المعاملات ، ويتم ربط كل كتلة مع كتلتها السابقة.
لإحداث انتقال من حالة إلى أخرى ، يجب أن تكون المعاملة صالحة. لكي تعتبر المعاملة صالحة ، يجب أن تخضع لعملية التحقق من الصحة المعروفة باسم التعدين. يحدث التعدين عندما تنفق مجموعة من العقد (أي أجهزة الكمبيوتر) مواردها الحسابية لإنشاء كتلة من المعاملات الصالحة.
يمكن لأي عقدة على الشبكة تعلن عن نفسها كعامل منجم أن تحاول إنشاء كتلة والتحقق من صحتها. يحاول الكثير من عمال المناجم من جميع أنحاء العالم إنشاء كتل والتحقق من صحتها في نفس الوقت. يقدم كل عامل منجم “إثباتًا” رياضيًا عند إرسال كتلة إلى blockchain ، ويعمل هذا الإثبات كضمان: إذا كان الدليل موجودًا ، فيجب أن تكون الكتلة صالحة.
من أجل إضافة كتلة إلى blockchain الرئيسية ، يجب على المُعدِّن إثبات ذلك بشكل أسرع من أي عامل منجم منافس آخر. تُعرف عملية التحقق من صحة كل كتلة من خلال تقديم عامل منجم لإثبات رياضي باسم “إثبات العمل”.
يكافأ عامل المنجم الذي يتحقق من كتلة جديدة بقدر معين من القيمة للقيام بهذا العمل. ما هذه القيمة؟ يستخدم blockchain Ethereum رمزًا رقميًا جوهريًا يسمى “Ether”. في كل مرة يثبت فيها عامل منجم كتلة ، يتم إنشاء رموز إيثر جديدة ومنحها.
قد تتساءل: ما الذي يضمن أن يتمسك الجميع بسلسلة واحدة من الكتل؟ كيف يمكننا التأكد من عدم وجود مجموعة فرعية من المعدنين الذين سيقررون إنشاء سلسلة الكتل الخاصة بهم؟
في وقت سابق ، قمنا بتعريف blockchain على أنه آلة فردية للمعاملات ذات حالة مشتركة. باستخدام هذا التعريف ، يمكننا أن نفهم أن الحالة الحالية الصحيحة هي حقيقة عالمية واحدة ، يجب على الجميع قبولها. إن وجود حالات (أو سلاسل) متعددة من شأنه أن يدمر النظام بأكمله ، لأنه سيكون من المستحيل الاتفاق على الحالة الصحيحة. إذا اختلفت السلاسل ، فقد تمتلك 10 عملات في سلسلة واحدة ، و 20 في سلسلة أخرى ، و 40 في سلسلة أخرى. في هذا السيناريو، لن تكون هناك طريقة لتحديد السلسلة الأكثر “صلاحية”.
عندما يتم إنشاء مسارات متعددة ، يحدث “تشعب (Fork)”. نريد عادة تجنب التشعبات، لأنها تعطل النظام وتجبر الناس على اختيار السلسلة التي “يؤمنون” بها.
لتحديد المسار الأكثر صحة ومنع السلاسل المتعددة ، يستخدم Ethereum آلية تسمى “بروتوكول الشبح”.
“بروتوكول الشبح” = “الشجرة الفرعية الملاحظة الأشجع و الأثقل”
بروتوكل الشبح و الذيح يعني (“GHOST” = “Greedy Heaviest Observed Subtree”
) بعبارات بسيطة ، ينص بروتوكول الشبح على أنه يجب علينا اختيار المسار الذي تم إجراء معظم العمليات الحسابية عليه. تتمثل إحدى طرق تحديد هذا المسار في استخدام رقم الكتلة لأحدث كتلة (“كتلة الورقة (leaf block) “) ، والتي تمثل العدد الإجمالي للكتل في المسار الحالي (بدون حساب كتلة التكوين). كلما زاد رقم الكتلة ، زاد طول المسار وزاد جهد التعدين الذي يجب أن يكون قد بذل في الوصول إلى هذه الورقة. يتيح لنا استخدام هذا المنطق الاتفاق على النسخة الأساسية للحالة الحالية.
الآن بعد أن حصلت على نظرة عامة جويه لماهية blockchain ، دعنا نتعمق أكثر في المكونات الرئيسية التي يتكون منها نظام Ethereum:
- حسابات
- حالة
- الغاز والرسوم
- المعاملات
- كتل
- تنفيذ الصفقة
- التعدين
- إثبات العمل
ملاحظة واحدة قبل البدء: عندما أقول “تجزئة” X ، فإنني أشير إلى تجزئة KECCAK-256 ، التي يستخدمها Ethereum.
الحسابات
تتكون “الحالة المشتركة” العالمية لـ Ethereum من العديد من الكائنات الصغيرة (“الحسابات”) التي يمكنها التفاعل مع بعضها البعض من خلال إطار عمل لتمرير الرسائل. كل حساب له حالة مرتبطة به وعنوان من 20 بايت. العنوان في Ethereum هو معرف 160 بت يستخدم لتحديد أي حساب.
هناك نوعان من الحسابات:
- الحسابات المملوكة خارجيًا (Externally owned accounts) ، والتي يتم التحكم فيها بواسطة مفاتيح خاصة وليس لها كود مرتبط بها.
- حسابات العقود (Contract accounts) ، التي يتم التحكم فيها من خلال كود العقد الخاص بها و لها كود مرتبط بها.
الحسابات المملوكة خارجيًا مقابل حسابات العقود
من المهم فهم الاختلاف الأساسي بين الحسابات المملوكة خارجيًا وحسابات العقود. يمكن للحساب المملوك خارجيًا إرسال رسائل إلى حسابات أخرى مملوكة خارجيًا أو إلى حسابات عقود أخرى عن طريق إنشاء معاملة وتوقيعها باستخدام مفتاحها الخاص. الرسالة بين حسابين مملوكين خارجيًا هي مجرد تحويل للقيمة. لكن رسالة من حساب مملوك خارجيًا إلى حساب عقد تنشط كود حساب العقد ، مما يسمح له بتنفيذ إجراءات مختلفة (على سبيل المثال ، نقل الرموز ، والكتابة إلى وحدة التخزين الداخلية ، وصك الرموز الجديدة ، وإجراء بعض العمليات الحسابية ، وإنشاء عقود جديدة ، وما إلى ذلك).
على عكس الحسابات المملوكة خارجيًا ، لا يمكن لحسابات العقود بدء معاملات جديدة من تلقاء نفسها. بدلاً من ذلك ، لا يمكن لحسابات العقود إطلاق المعاملات إلا استجابةً للمعاملات الأخرى التي تلقوها (من حساب مملوك خارجيًا أو من حساب عقد آخر). سنتعرف على المزيد حول المكالمات التعاقدية في قسم “المعاملات والرسائل”.
لذلك ، يتم دائمًا تحريك أي إجراء يحدث على Ethereum blockchain من خلال المعاملات التي يتم إطلاقها من الحسابات التي يتم التحكم فيها خارجيًا.
حالة الحساب
تتكون حالة الحساب من أربعة مكونات موجودة بغض النظر عن نوع الحساب:
- nonce: إذا كان الحساب مملوكًا خارجيًا ، فإن هذا الرقم يمثل عدد المعاملات المرسلة من عنوان الحساب. إذا كان الحساب عبارة عن حساب عقد ، فإن nonce هو عدد العقود التي تم إنشاؤها بواسطة الحساب.
- balance: عدد Wei المملوك لهذا العنوان. هناك 1e + 18 Wei لكل إيثر.
- StorageRoot: تجزئة (hash) العقدة الجذرية لشجرة Merkle Patricia (سنشرح أشجار Merkle لاحقًا). تقوم هذه الشجرة بترميز تجزئة محتويات التخزين لهذا الحساب ، وهي فارغة افتراضيًا.
- codeHash: تجزئة رمز EVM (جهاز Ethereum Virtual Machine – المزيد حول هذا لاحقًا) لهذا الحساب. بالنسبة لحسابات العقود ، هذا هو الرمز الذي يتم تجزئته وتخزينه ككود تجزئة. بالنسبة للحسابات المملوكة خارجيًا ، فإن الحقل codeHash هو تجزئة السلسلة الفارغة.
حاله عالمية
حسنًا ، نحن نعلم أن حالة Ethereum العالمية تتكون من تعيين بين عناوين الحساب وحالات الحساب. يتم تخزين هذا التعيين في بنية بيانات تُعرف باسم شجرة Merkle Patricia.
شجرة Merkle (أو يشار إليها أيضًا باسم “Merkle trie”) هي شجرة ثنائية (binary tree ) تتكون من مجموعة من العقد مع:
- عدد كبير من العقد الطرفية في الجزء السفلي من الشجرة التي تحتوي على البيانات الأساسية
- مجموعة من العقد الوسيطة ، حيث تكون كل عقدة هي تجزئة عقدتها الفرعية
- عقدة جذريه واحدة ، تتكون أيضًا من تجزئة عقدتيها الفرعيتين ، والتي تمثل الجزء العلوي من الشجرة.
يتم إنشاء البيانات الموجودة في الجزء السفلي من الشجرة عن طريق تقسيم البيانات التي نريد تخزينها إلى أجزاء ، ثم تقسيم الأجزاء إلى مجموعات ، ثم أخذ تجزئة كل مجموعة وتكرار نفس العملية حتى يصبح العدد الإجمالي للتجزئة المتبقية واحد فقط: تجزئة الجذر.
هذه الشجرة مطلوبة للحصول على مفتاح لكل قيمة مخزنة بداخلها. بدءًا من العقدة الجذرية للشجرة ، يجب أن يخبرك المفتاح بالعقدة الفرعية التي يجب اتباعها للوصول إلى القيمة المقابلة ، والتي يتم تخزينها في العُقد الطرفية. في حالة Ethereum ، يكون تعيين المفتاح / القيمة لشجرة الحالة بين العناوين والحسابات المرتبطة بها ، بما في ذلك balance ، و nonce ، و codeHash ، و storageRoot لكل حساب (حيث يكون storageRoot بحد ذاته شجرة).
المصدر: ورقة بيضاء Ethereum
يستخدم هذا الهيكل الثلاثي أيضًا لتخزين المعاملات والإيصالات. وبشكل أكثر تحديدًا ، تحتوي كل كتلة على “header” يخزن تجزئة العقدة الجذرية لثلاثة هياكل مختلفة من Merkle trie ، بما في ذلك:
- شجرة الحالة (State trie)
- شجرة المعاملات (Transactions trie)
- شجرة الإيصالات (Receipts trie)
تعد القدرة على تخزين كل هذه المعلومات بكفاءة في شجرة Merkle مفيدة بشكل لا يصدق في Ethereum لما نسميه “العملاء الخفيفيين (light clients) ” أو “العقد الخفيفة”. تذكر أن blockchain يتم الحفاظ عليه بواسطة مجموعة من العقد. بشكل عام ، هناك نوعان من العقد: العقد الكاملة والعقد الخفيفة.
تقوم عقدة أرشيف كاملة بمزامنة blockchain عن طريق تنزيل السلسلة الكاملة ، من كتلة التكوين إلى كتلة الرأس الحالية ، وتنفيذ جميع المعاملات المضمنة فيها. عادةً ما يقوم عمال المناجم بتخزين عقدة الأرشيف الكاملة ، لأنهم مطالبون بالقيام بذلك في عملية التعدين. من الممكن أيضًا تنزيل عُقدة كاملة دون تنفيذ كل معاملة. بغض النظر ، أي عقدة كاملة تحتوي على السلسلة بأكملها.
ولكن ما لم تحتاج العقدة إلى تنفيذ كل معاملة أو الاستعلام بسهولة عن البيانات التاريخية ، فلا داعي حقًا لتخزين السلسلة بأكملها. هذا هو المكان الذي يأتي فيه مفهوم العقدة الخفيفة. بدلاً من تنزيل السلسلة الكاملة وتخزينها وتنفيذ جميع المعاملات ، تقوم العقد الخفيفة بتنزيل سلسلة الرؤوس فقط ، من كتلة التكوين إلى الرأس الحالي ، دون تنفيذ أي معاملات أو استرداد أي حالة مرتبطة. نظرًا لأن العقد الخفيفة يمكنها الوصول إلى رؤوس الكتل ، التي تحتوي على تجزئات لثلاث شجرات، فلا يزال بإمكانها إنشاء وتلقي إجابات يمكن التحقق منها حول المعاملات والأحداث والأرصدة وما إلى ذلك.
سبب نجاح هذا الأمر هو انتشار التجزئة في شجرة Merkle لأعلى – إذا حاول مستخدم ضار تبديل معاملة زائفة في أسفل شجرة Merkle ، فسيؤدي هذا التغيير إلى تغيير تجزئة العقدة أعلاه ، مما سيؤدي إلى تغيير تجزئة العقدة فوق ذلك ، وهكذا ، حتى يغير جذر الشجرة في النهاية.
يمكن لأي عقدة تريد التحقق من جزء من البيانات أن تستخدم شيئًا يسمى “إثبات ميركل” للقيام بذلك. يتكون ثبات ميركل من:
- قطعة من البيانات ليتم التحقق منها وتجزئتها
- تجزئة جذر الشجرة
- “الفرع” (كل تجزئات الشريك الصاعده على طول المسار من قطعة البيانات إلى الجذر)
يمكن لأي شخص أن يقرأ الدليل و التحقق من أن تجزئة هذا الفرع متسقة على طول الشجرة ، وبالتالي فإن القطعة المحددة موجودة بالفعل في هذا الموضع في الشجرة.
باختصار ، تتمثل فائدة استخدام شجرة Merkle Patricia في أن العقدة الجذرية لهذا الهيكل تعتمد بشكل مشفر على البيانات المخزنة في الشجرة ، وبالتالي يمكن استخدام تجزئة العقدة الجذرية كهوية آمنة لهذه البيانات. نظرًا لأن رأس الكتلة يتضمن تجزئة الجذر للحالة والمعاملات والإيصالات ، يمكن لأي عقدة التحقق من صحة جزء صغير من حالة Ethereum دون الحاجة إلى تخزين الحالة بأكملها ، والتي يمكن أن تكون غير محدودة في الحجم.
الغاز والدفع
أحد المفاهيم المهمة جدًا في Ethereum هو مفهوم الرسوم. كل حساب يحدث نتيجة لمعاملة على شبكة Ethereum يتحمل رسومًا – لا يوجد غداء مجاني! يتم دفع هذه الرسوم بفئة تسمى “الغاز”.
الغاز هو الوحدة المستخدمة لقياس الرسوم المطلوبة لحساب معين. سعر الغاز هو مقدار الإيثر الذي ترغب في إنفاقه على كل وحدة من الغاز ، ويُقاس بـ “gwei”. “Wei” هي أصغر وحدة في Ether ، حيث تمثل 1⁰¹⁸ Wei ما يعادل 1 Ether . واحد gwei هو 1،000،000،000 وي.
مع كل معاملة ، يحدد المرسل حدًا للغاز و سعرًا للغاز. يمثل مجموع سعر الغاز و حد الغاز الحد الأقصى لمبلغ Wei الذي يرغب المرسل في دفعه مقابل تنفيذ معاملة.
على سبيل المثال ، لنفترض أن المرسل حدَّد حد الغاز على 50000 وسعر الغاز على 20 gwei. هذا يعني أن المرسل على استعداد لإنفاق 50000 × 20 gwei على الأكثر gwei = 1,000,000,000,000,000 Wei = 0.001 Ether لتنفيذ هذه المعاملة.
تذكر أن حد الغاز يمثل الحد الأقصى من الغاز الذي يرغب المرسل في إنفاق الأموال عليه. إذا كان لديهم ما يكفي من إيثر في رصيد حسابهم لتغطية هذا الحد الأقصى ، فوضعهم جيد . يتم رد أموال المرسل عن أي غاز غير مستخدم في نهاية المعاملة ، ويتم استبداله بسعر الصرف الأصلي.
في حالة عدم قيام المرسل بتوفير الغاز اللازم لتنفيذ المعاملة ، فإن حاله المعاملة تتحول إلى “نفد الغاز” وتعتبر غير صالحة. في هذه الحالة ، يتم إلغاء معالجة المعاملة ويتم عكس أي تغييرات حدثت في الحالة ، بحيث ينتهي بنا المطاف مرة أخرى في حالة Ethereum قبل المعاملة. بالإضافة إلى ذلك ، يتم تسجيل فشل المعاملة و حفظها ، مما يوضح المعاملة التي تمت محاولة تنفيذها وأين فشلت. ونظرًا لأن الآلة قد بذلت جهدًا بالفعل لتشغيل الحسابات قبل نفاد الغاز ، فمن المنطقي أن لا يتم إرجاع أي من الغاز إلى المرسل.
أين بالضبط تذهب أموال الغاز هذه؟ يتم إرسال جميع الأموال التي ينفقها المرسل على الغاز إلى عنوان “المستفيد” ، والذي يكون عادةً عنوان المُعدِّن. نظرًا لأن المعدنين يبذلون الجهد لتشغيل الحسابات والتحقق من صحة المعاملات ، فإن عمال المناجم يتلقون رسوم الغاز كمكافأة.
عادة ، كلما ارتفع سعر الغاز الذي يرغب المرسل في دفعه ، زادت القيمة التي يحصل عليها عامل التعدين من المعاملة. وبالتالي ، سيكون من المرجح أن يختاره عمال المناجم. وبهذه الطريقة ، فإن المعدنين أحرار في اختيار المعاملات التي يريدون التحقق من صحتها أو تجاهلها. من أجل إرشاد المرسلين بشأن سعر الغاز الذي يجب تعيينه ، يتوفر لعمال المناجم خيار الإعلان عن الحد الأدنى لسعر الغاز الذي سينفذون المعاملات من أجله.
هناك رسوم للتخزين أيضًا
لا يتم استخدام الغاز فقط للدفع مقابل خطوات الحساب ، بل يتم استخدامه أيضًا للدفع مقابل استخدام التخزين. يتناسب إجمالي رسوم التخزين مع أصغر مضاعف لـ 32 بايت مستخدم.
رسوم التخزين لها بعض الجوانب الدقيقة. على سبيل المثال ، نظرًا لأن زيادة التخزين تزيد من حجم قاعدة بيانات حالة Ethereum على جميع العقد ، فهناك حافز للحفاظ على حجم البيانات المخزنة صغيرًا. لهذا السبب ، إذا كانت المعاملة تحتوي على خطوة تمسح إدخالًا في التخزين ، فسيتم التنازل عن رسوم تنفيذ هذه العملية ، ويتم رد الأموال لتحرير مساحة التخزين.
ما هو الغرض من الرسوم؟
أحد الجوانب المهمة للطريقة التي يعمل بها Ethereum هو أن كل عملية تنفذها الشبكة تتأثر في نفس الوقت بكل عقدة كاملة. ومع ذلك ، فإن الخطوات الحسابية على جهاز Ethereum Virtual Machine باهظة الثمن. لذلك ، من الأفضل استخدام عقود Ethereum الذكية للمهام البسيطة ، مثل تشغيل منطق عمل بسيط أو التحقق من التوقيعات وكائنات التشفير الأخرى ، بدلاً من الاستخدامات الأكثر تعقيدًا ، مثل تخزين الملفات أو البريد الإلكتروني أو تعلم الآلة ، والتي يمكن أن تضع ضغطًا على الشبكة. فرض الرسوم يمنع المستخدمين من إرهاق الشبكة.
Ethereum هي لغة تورينج كاملة. (باختصار ، آلة تورينج هي آلة يمكنها محاكاة أي خوارزمية كمبيوتر (لأولئك الذين ليسوا على دراية بآلات تورينج ، تحقق من هذا وهذا). هذا يسمح بالتكرار ويجعل Ethereum عرضة لمشكلة التوقف ، وهي المشكلة التي لا يمكن تحديد ما إذا كان البرنامج سيعمل للأبد أم لا. إذا لم تكن هناك رسوم ، يمكن للمستخدم الخبيث أن يحاول بسهولة تعطيل الشبكة عن طريق تنفيذ حلقة لا نهائية داخل معاملة ، دون أي تداعيات. وبالتالي ، تحمي الرسوم الشبكة من الهجمات المتعمدة.
قد تفكر ، “لماذا يتعين علينا أيضًا الدفع مقابل التخزين؟” حسنًا ، تمامًا مثل الحساب ، يعد التخزين على شبكة Ethereum تكلفة يجب على الشبكة بأكملها تحمل عبءها.
المعاملات والرسائل
لاحظنا سابقًا أن Ethereum هي آلة حاله قائمة على المعاملات. بعبارة أخرى ، فإن المعاملات التي تحدث بين الحسابات المختلفة هي التي تنقل حالة Ethereum العالمية من حالة إلى أخرى.
مما يعني ، فإن المعاملة عبارة عن جزء من التعليمات الموقعة بالتشفير والتي يتم إنشاؤها بواسطة حساب مملوك خارجيًا ، ومتسلسلة ، ثم يتم إرسالها إلى blockchain.
هناك نوعان من المعاملات: مكالمات الرسائل وإنشاء العقود (أي المعاملات التي تنشئ عقود Ethereum جديدة).
تحتوي جميع المعاملات على المكونات التالية ، بغض النظر عن نوعها:
- nonce: عدد المعاملات التي أرسلها المرسل.
- gasPrice: كمية وي الذي يرغب المرسل في دفعه لكل وحدة غاز مطلوبة لتنفيذ المعاملة.
- gasLimit: الحد الأقصى من الغاز الذي يرغب المرسل في دفعه مقابل تنفيذ هذه المعاملة. يتم تعيين هذا المبلغ ودفعه مقدمًا ، قبل إجراء أي حساب.
- to: عنوان المستلم. في معاملة إنشاء العقد ، لا يوجد عنوان حساب العقد حتى الآن ، ولذلك يتم استخدام قيمة فارغة.
- value: مقدار Wei المراد تحويله من المرسل إلى المستلم. في معاملة إنشاء العقد ، تعمل هذه القيمة كرصيد البداية داخل حساب العقد الذي تم إنشاؤه حديثًا.
- v ، r ، s: تُستخدم لإنشاء التوقيع الذي يحدد مرسل المعاملة.
- init (موجودة فقط لمعاملات إنشاء العقد): جزء من كود EVM يُستخدم لتهيئة حساب العقد الجديد. يتم تشغيل init مرة واحدة فقط ، ثم يتم التخلص منها. عند تشغيل init لأول مرة ، فإنها تقوم بإرجاع نص كود الحساب ، وهو جزء من الكود مرتبط بشكل دائم بحساب العقد.
- data (حقل اختياري موجود فقط لمكالمات الرسائل): بيانات الإدخال (أي المعلمات) لمكالمة الرسائل. على سبيل المثال ، إذا كان العقد الذكي بمثابة خدمة تسجيل دومين ، فقد يتوقع الاتصال بهذا العقد حقول الإدخال مثل الدومين وعنوان IP.
لقد تعلمنا في قسم “الحسابات” أن المعاملات – كل من مكالمات الرسائل ومعاملات إنشاء العقود – يتم بدؤها دائمًا بواسطة حسابات مملوكة خارجيًا ويتم إرسالها إلى blockchain. هناك طريقة أخرى للتفكير في الأمر وهي أن المعاملات هي التي تربط العالم الخارجي بالحالة الداخلية لـ Ethereum.
لكن هذا لا يعني أن العقود لا يمكنها التحدث إلى عقود أخرى. يمكن للعقود الموجودة ضمن النطاق العالمي لحاله Ethereum التحدث إلى عقود أخرى ضمن نفس النطاق. الطريقة التي يفعلون بها ذلك هي عبر “الرسائل” أو “المعاملات الداخلية” لعقود أخرى. يمكننا أن نفكر في الرسائل أو المعاملات الداخلية على أنها تشبه المعاملات ، مع وجود اختلاف كبير في أنها لم يتم إنشاؤها بواسطة حسابات مملوكة خارجيًا. بدلاً من ذلك ، يتم إنشاؤها بواسطة العقود. إنها كائنات افتراضية ، على عكس المعاملات ، ليست متسلسلة ولا توجد إلا في بيئة تنفيذ Ethereum.
عندما يرسل أحد العقود معاملة داخلية إلى عقد آخر ، يتم تنفيذ الكود المرتبط الموجود في حساب عقد المستلم.
من الأمور المهمة التي يجب ملاحظتها أن المعاملات أو الرسائل الداخلية لا تحتوي على حد الغاز. هذا بسبب تحديد حد الغاز من قبل المنشئ الخارجي للمعاملة الأصلية (أي بعض الحسابات المملوكة خارجيًا). يجب أن يكون حد الغاز الذي يحدده الحساب المملوك خارجيًا مرتفعًا بما يكفي لتنفيذ المعاملة ، بما في ذلك أي عمليات تنفيذ فرعية تحدث نتيجة لتلك المعاملة ، مثل رسائل عقد إلى عقد. إذا في سلسلة تنفيذ المعاملات والرسائل قامت معاملة بتنفيذ الأمر نفد الغاز “out of gas” ، فسيتم إرجاع تنفيذ هذه الرسالة ، إلى جانب أي رسائل لاحقة تم تشغيلها بواسطة التنفيذ. و لكن ، ليس هناك ضرورة إلا إرجاع التنفيذ السابق لأصله .
الكتل
يتم تجميع جميع المعاملات معًا في “كتل”. يحتوي blockchain على سلسلة من هذه الكتل المرتبطة ببعضها البعض.
في Ethereum ، تتكون الكتلة من:
- رأس الكتلة
- معلومات حول مجموعة المعاملات المدرجة في تلك الكتلة
- مجموعة من رؤوس الكتل الأخرى لأوامر الكتلة الحالية.
توضيح Ommers
ما هو “أومر”؟ ommer عبارة عن كتلة يكون والدها مساويًا لوالد والد الكتله الحاليه. دعنا نلقي نظرة سريعة على لماذا يتم استخدام ommers ولماذا تحتوي الكتلة على رؤوس الكتلة الخاصة بـ ommers.
نظرًا للطريقة التي تم بها إنشاء Ethereum ، فأوقات الكتلة أقل بكثير (حوالي 15 ثانية) من تلك الموجودة في سلاسل الكتل الأخرى ، مثل Bitcoin (حوالي 10 دقائق). هذا يتيح معالجة المعاملات بشكل أسرع. ومع ذلك ، فإن أحد الجوانب السلبية لأوقات الكتل الأقصر هو العثور على المزيد من حلول الكتل المتنافسة بواسطة المعدنين. يشار إلى هذه الكتل المتنافسة أيضًا باسم “الكتل اليتيمه” (أي الكتل التي لا تدخل في السلسلة الرئيسية).
الغرض من ommers هو المساعدة في مكافأة عمال المناجم لتضمين هذه الكتل اليتيمة. يجب أن تكون كتل ommers التي يضيفها المنجمون “صالحه” ، أي ضمن الجيل السادس أو أصغر من الكتلة الحالية. بعد ستة أجيال، لا يكون من الممكن الإشاره إلى الكتل اليتيمه (لأن تضمين المعاملات القديمة من شأنه أن يعقد الأمور قليلاً).
تتلقى كتل ommers مكافأة أصغر من الكتلة الكاملة. ومع ذلك ، لا يزال هناك بعض الحوافز لعمال المناجم لتضمين هذه الكتل اليتيمه وجني المكافآت.
رأس الكتلة (Block header)
دعونا نعود إلى الكتل للحظة. ذكرنا سابقًا أن كل كتلة بها “رأس” ، ولكن ما هذا بالضبط؟
رأس الكتلة هو جزء من الكتلة يتكون من:
- parentHash: تجزئة لرأس الكتلة الأصل (وهذا ما يجعل الكتلة جزء من “سلسلة”)
- ommersHash: تجزئة لقائمة ommers للكتلة الحالية
- beneficiary: عنوان الحساب الذي يتلقى رسوم تعدين هذه الكتلة
- stateRoot: تجزئة العقدة الجذرية لشجرة ماركيل للحالة (تذكر كيف علمنا أن شجرة ماركيل تخزن في الرأس ويسهل على العملاء الخفيفين التحقق من أي شيء يتعلق بالحالة)
- transactionsRoot: تجزئة العقدة الجذرية للشجرة التي تحتوي على جميع المعاملات المدرجة في هذه الكتلة
- إreceiptsRoot: تجزئة العقدة الجذرية للشجرة التي تحتوي على إيصالات جميع المعاملات المدرجة في هذه الكتلة
- logsBloom: مرشح Bloom (بنية البيانات) يتكون من معلومات السجل
- difficulty: مستوى الصعوبة لهذه الكتلة
- number: عدد الكتلة الحالية (تحتوي كتلة التكوين على رقم كتلة يساوي صفر ؛ يزيد رقم الكتلة بمقدار 1 لكل كتلة لاحقة)
- gasLimit: حد الغاز الحالي لكل كتلة
- gasUsed: مجموع الغاز الإجمالي المستخدم في المعاملات في هذه الكتلة
- timestamp: الطابع الزمني لنظام التشغيل الموحد لبدء هذه الكتلة
- extraData: بيانات إضافية متعلقة بهذه الكتلة
- mixHash: تجزئة تثبت ، عند دمجها مع nonce ، أن هذه الكتلة قد نفذت حسابًا كافيًا
- nonce: تجزئة تثبت ، عند دمجها مع mixHash ، أن هذه الكتلة قد نفذت حسابًا كافيًا
لاحظ كيف يحتوي كل رأس كتلة على ثلاثة هياكل شجرية من أجل:
- حالة (stateRoot)
- المعاملات (transactionsRoot)
- إيصالات (receiptsRoot)
هذه الهياكل الشجريه هي ليست سوى هياكل شجرة Merkle Patricia التي ناقشناها سابقًا.
بالإضافة إلى ذلك ، هناك بعض المصطلحات من الوصف أعلاه التي تستحق التوضيح. لنلقي نظرة.
السجلات
يسمح Ethereum للسجلات بتتبع المعاملات والرسائل المختلفة. يمكن أن ينشئ العقد سجلًا صريحًا عن طريق تحديد “الأحداث” التي يريد تسجيلها.
يحتوي إدخال السجل على:
- عنوان حساب المسجل ،
- سلسلة من الموضوعات التي تمثل الأحداث المختلفة التي نفذتها هذه الصفقة ، و
- أي بيانات مرتبطة بهذه الأحداث.
يتم تخزين السجلات في مرشح bloom ، والذي يخزن بيانات السجل اللانهائية بطريقة فعالة.
إيصال الحوالة
تأتي السجلات المخزنة في الرأس من معلومات السجل الموجودة في إيصال المعاملة. تمامًا كما تتلقى إيصالًا عند شراء شيء ما من متجر ، تنشئ Ethereum إيصالًا لكل معاملة. كما كنت تتوقع ، يحتوي كل إيصال على معلومات معينة حول المعاملة. يتضمن هذا الإيصال عناصر مثل:
- رقم الكتلة
- تجزئة الكتلة
- تجزئة المعاملة
- الغاز المستخدم في المعاملة الحالية
- الغاز التراكمي المستخدم في الكتلة الحالية بعد تنفيذ المعاملة الحالية
- السجلات التي تم إنشاؤها عند تنفيذ المعاملة الحالية
- ..وما إلى ذلك وهلم جرا
صعوبة الكتلة
يتم استخدام “صعوبة” الكتلة لفرض الاتساق في الوقت المستغرق للتحقق من صحة الكتل. صعوبة كتلة التكوين هي 131،072 ، ويتم استخدام صيغة خاصة لحساب صعوبة كل كتلة بعد ذلك. إذا تم التحقق من كتلة معينة بسرعة أكبر من الكتلة السابقة ، فإن بروتوكول Ethereum يزيد من صعوبة تلك الكتلة.
تؤثر صعوبة الكتلة على nonce ، وهي عبارة عن تجزئة يجب حسابها عند تعدين كتلة ، باستخدام خوارزمية إثبات العمل.
تمت صياغة العلاقة بين صعوبة الكتلة و nonce رياضيًا على النحو التالي:
حيث HD هي الصعوبة.
الطريقة الوحيدة للعثور على رقم nonce يلبي حد الصعوبة هو استخدام خوارزمية إثبات العمل لتعداد جميع الاحتمالات. يتناسب الوقت المتوقع لإيجاد حل مع الصعوبة – فكلما زادت الصعوبة ، أصبح من الصعب العثور على nonce ، وبالتالي يصعب التحقق من صحة الكتلة ، مما يؤدي بدوره إلى زيادة الوقت الذي يستغرقه التحقق من صحة كتلة جديدة. لذلك ، من خلال ضبط صعوبة الكتلة ، يمكن للبروتوكول ضبط الوقت الذي يستغرقه التحقق من صحة الكتلة.
من ناحية أخرى ، إذا كان وقت التحقق من الصحة أبطأ ، فإن البروتوكول يقلل من الصعوبة. بهذه الطريقة ، يتم ضبط وقت التحقق ذاتيًا للحفاظ على معدل ثابت – في المتوسط ، كتلة واحدة كل 15 ثانية.
تنفيذ المعاملة
لقد وصلنا إلى أحد أكثر الأجزاء تعقيدًا في بروتوكول Ethereum: تنفيذ المعاملة. لنفترض أنك ترسل معاملة إلى شبكة Ethereum لتتم معالجتها. ماذا يحدث لتحويل حالة Ethereum لتشمل معاملتك؟
أولاً ، يجب أن تفي جميع المعاملات بمجموعة أولية من المتطلبات حتى يتم تنفيذها. وتشمل هذه:
- يجب أن تكون المعاملة منسقة بتنسق RLP بشكل صحيح. يرمز “RLP” إلى “بادئة طول متكررة (Recursive Length Prefix) ” وهو تنسيق بيانات يُستخدم لتشفير المصفوفات المتداخلة للبيانات الثنائية. RLP هو التنسيق الذي يستخدمه Ethereum لتسلسل الكائنات.
- توقيع صحيح للمعاملة.
- nonce معاملة صالحة. تذكر أن nonce للحساب هو عدد المعاملات المرسلة من هذا الحساب. لكي تكون صالحة ، يجب أن تكون nonce المعاملة مساوية لـ nonce لحساب المرسل.
- يجب أن يكون حد الغاز للمعاملة مساويًا للغاز الداخلي المستخدم في المعاملة أو أكبر منه. يشمل الغاز الداخلي:
- تكلفة محددة مسبقًا تبلغ 21000 غاز لتنفيذ المعامله
- رسم غاز للبيانات المرسلة مع المعاملة (4 غاز لكل بايت من البيانات أو كود يساوي صفرًا ، و 68 غازًا لكل بايت غير صفري من البيانات أو الكود)
- إذا كانت المعاملة عبارة عن معاملة إنشاء عقد ، يتم إضافة 32000 غاز إضافي
- يجب أن يحتوي رصيد حساب المرسل على ما يكفي من إيثر لتغطية تكاليف الغاز “مقدماً” التي يجب على المرسل دفعها. يعد حساب تكلفة الغاز مقدمًا أمرًا بسيطًا: أولاً ، يتم ضرب حد الغاز للمعاملة في سعر الغاز للمعاملة لتحديد التكلفة القصوى للغاز. بعد ذلك ، يتم إضافة هذا الحد الأقصى للتكلفة إلى إجمالي القيمة التي يتم نقلها من المرسل إلى المستلم.
إذا كانت المعاملة تفي بجميع متطلبات الصلاحية المذكورة أعلاه ، فإننا ننتقل إلى الخطوة التالية.
أولاً ، نخصم التكلفة الأولية للتنفيذ من رصيد المرسل ، ونزيد من قيمة nonce لحساب المرسل بمقدار 1 لحساب المعاملة الحالية. في هذه المرحلة ، يمكننا حساب الغاز المتبقي باعتباره الحد الإجمالي للغاز للمعاملة مطروحًا منه الغاز الداخلي المستخدم.
بعد ذلك ، تبدأ المعاملة في التنفيذ. طوال تنفيذ المعاملة ، تتعقب Ethereum “الحالة الفرعية”. هذه الحالة الفرعية هي طريقة لتسجيل المعلومات المتراكمة أثناء المعاملة والتي ستكون مطلوبة فور اكتمال المعاملة. على وجه التحديد ، يحتوي على:
- Self-destruct set:: مجموعة من الحسابات (إن وجدت) التي سيتم التخلص منها بعد اكتمال المعاملة.
- Log series: نقاط التحقق المؤرشفة والقابلة للفهرسة للكود الذي قام جهاز إيثيريوم الإفتراضي بتنفيذه.
- Refund balance: المبلغ المراد رده إلى حساب المرسل بعد المعاملة. تذكر كيف ذكرنا أن التخزين في Ethereum يكلف أموالًا ، وأن المرسل يحصل على إرجاع مبلغ الرسوم مقابل مسح التخزين؟ يتتبع Ethereum هذا باستخدام عداد الاسترداد. يبدأ عداد الاسترداد من الصفر ويزيد في كل مرة يحذف فيها العقد شيئًا ما في المخزن.
بعد ذلك ، تتم معالجة الحسابات المختلفة التي تتطلبها المعاملة.
بمجرد معالجة جميع الخطوات التي تتطلبها المعاملة ، وبافتراض عدم وجود حالة غير صالحة ، يتم الانتهاء من الحالة من خلال تحديد مقدار الغاز غير المستخدم الذي سيتم رده إلى المرسل. بالإضافة إلى الغاز غير المستخدم ، يحصل المرسل أيضًا على بعض المبالغ من “رصيد الاسترداد” الذي وصفناه أعلاه.
بمجرد حصول المرسل على إسترداد لرسومه إن وجدت :
- يتم إعطاء الأثير للغاز لعمال المناجم
- تتم إضافة الغاز المستخدم من خلال المعاملة إلى عداد غاز الكتلة (الذي يتتبع إجمالي الغاز المستخدم في جميع المعاملات في الكتلة ، ويكون مفيدًا عند التحقق من صحة الكتلة)
- يتم حذف جميع الحسابات الموجودة في مجموعة التدمير الذاتي (إن وجدت)
أخيرًا ، نحصل على الحالة الجديدة ومجموعة السجلات التي تم إنشاؤها بواسطة المعاملة.
الآن بعد أن غطينا أساسيات تنفيذ المعاملات ، دعنا نلقي نظرة على بعض الاختلافات بين معاملات إنشاء العقود ومكالمات الرسائل.
إنشاء العقد
تذكر أنه في Ethereum ، هناك نوعان من الحسابات: حسابات العقود والحسابات المملوكة خارجيًا. عندما نقول أن المعاملة هي “إنشاء عقد” ، فإننا نعني أن الغرض من المعاملة هو إنشاء حساب عقد جديد.
من أجل إنشاء حساب عقد جديد ، نعلن أولاً عن عنوان الحساب الجديد باستخدام صيغة خاصة. ثم نقوم بتهيئة الحساب الجديد من خلال:
- تعيين nonce على الصفر
- إذا أرسل المرسل مبلغًا من إيثر كقيمة مع المعاملة ، فاضبط رصيد الحساب على تلك القيمة
- خصم القيمة المضافة إلى رصيد هذا الحساب الجديد من رصيد المرسل
- ضبط التخزين كفارغ
- تعيين codeHash العقد كتجزئة لسلسلة فارغة
بمجرد أن نهيئ الحساب ، يمكننا بالفعل إنشاء الحساب ، باستخدام init code المرسل مع المعاملة (راجع قسم “المعاملات والرسائل” للحصول على معلومات حول init code). ما يحدث أثناء تنفيذ كود التهية هذا متنوع. اعتمادًا على مُنشئ العقد ، قد يقوم بتحديث تخزين الحساب ، وإنشاء حسابات عقد أخرى ، وإجراء مكالمات رسائل أخرى ، وما إلى ذلك.
عندما يتم تنفيذ الكود الخاص بتهيئة العقد ، فإنه يستخدم الغاز. لا يسمح للمعاملة باستخدام غاز أكثر من الغاز المتبقي. إذا حدث ذلك ، فسيصطدم التنفيذ باستثناء نفذ الغاز (OOG) و يخرج. إذا خرجت المعاملة بسبب استثناء نفذ الغاز ، فعندئذٍ يتم إرجاع الحالة إلى النقطة السابقة للمعاملة مباشرة. لا يعاد إلى المرسل الغاز الذي تم إنفاقه قبل نفاذه.
ومع ذلك ، إذا أرسل المرسل أي قيمة إيثر مع المعاملة ، فسيتم رد قيمة إيثر حتى إذا فشل إنشاء العقد!
إذا تم تنفيذ كود التهيئة بنجاح ، يتم دفع تكلفة إنشاء العقد النهائي. هذه تكلفة تخزين ، وتتناسب مع حجم رمز العقد الذي تم إنشاؤه (مرة أخرى ، لا توجد وجبة غداء مجانية!) إذا لم يكن هناك ما يكفي من الغاز لدفع هذه التكلفة النهائية ، فإن المعاملة تعلن مرة أخرى استثناء نفاد الغاز و تخرج.
إذا سارت الأمور على ما يرام ووصلنا إلى هذا الحد دون استثناءات ، فسيتم رد أي غاز متبقي غير مستخدم إلى المرسل الأصلي للمعاملة ، ويُسمح الآن بإستمرار الحالة المتغيرة!
استدعاء الرسائل
يشبه تنفيذ إستدعاء الرسائل تنفيذ إنشاء العقد ، مع بعض الاختلافات.
لا يتضمن تنفيذ استدعاء الرسائل أي كود تهيئة ، حيث لا يتم إنشاء حسابات جديدة. ومع ذلك ، يمكن أن تحتوي على بيانات إدخال ، إذا تم توفير هذه البيانات من قبل مرسل المعاملة. بمجرد التنفيذ ، تحتوي استدعاء الرسائل أيضًا على مكون إضافي يحتوي على بيانات الإخراج ، والذي يتم استخدامه إذا كان التنفيذ اللاحق يحتاج إلى هذه البيانات.
كما هو الحال مع إنشاء العقد ، إذا خرج تنفيذ استدعاء الرسالة بسبب نفاد الغاز أو لأن المعاملة غير صالحة (على سبيل المثال ، تجاوز سعة المكدس أو وجهة قفزة غير صالحة أو تعليمات غير صالحة) ، فلن يتم رد أي من الغاز المستخدم إلى المتصل الأصلي . بدلاً من ذلك ، يتم استهلاك كل الغاز المتبقي غير المستخدم ، وتتم إعادة تعيين الحالة إلى النقطة التي تسبق تحويل الرصيد مباشرةً.
حتى آخر تحديث لـ Ethereum ، لم تكن هناك طريقة لإيقاف أو التراجع عن تنفيذ معاملة دون أن يستهلك النظام كل الغاز الذي قدمته. على سبيل المثال ، لنفترض أنك قمت بتأليف عقد تسبب في حدوث خطأ عندما لم يكن المتصل مفوضًا لإجراء بعض المعاملات. في الإصدارات السابقة من Ethereum ، سيستمر استهلاك الغاز المتبقي ، ولن يتم رد أي غاز إلى المرسل. لكن تحديث بيزنطة يتضمن رمز “رجوع” جديد يسمح للعقد بإيقاف التنفيذ وعودة تغييرات الحالة ، دون استهلاك الغاز المتبقي ، مع القدرة على إرجاع سبب المعاملة الفاشلة. إذا خرجت معاملة بسبب التراجع ، فسيتم إعادة الغاز غير المستخدم إلى المرسل.
نموذج التنفيذ
لقد تعلمنا حتى الآن عن سلسلة الخطوات التي يجب أن تحدث حتى يتم تنفيذ المعاملة من البداية إلى النهاية. الآن ، سنلقي نظرة على كيفية تنفيذ المعاملة فعليًا داخل الجهاز الإفتراضي.
جزء البروتوكول الذي يتعامل بالفعل مع معالجة المعاملات هو الجهاز الإفتراضي الخاص بـ Ethereum ، والمعروف باسم Ethereum Virtual Machine (EVM).
EVM هو جهاز إفتراضي Turing كامل ، كما هو ذكرمنا سابقًا. القيد الوحيد على جهاز EVM و الذي لا تعاني من أي آلة Turing الكاملة هو أن EVM مرتبط جوهريًا بالغاز. وبالتالي ، فإن المقدار الإجمالي للحساب الذي يمكن إجراؤه محدود جوهريًا بكمية الغاز المقدمة.
علاوة على ذلك ، فإن EVM لديها معمارية قائمة على التكديس (stack-based architecture) . آلة التكديس هي جهاز كمبيوتر يستخدم الكدسه الأخيرة المُدخلة و الأولى المُخرجه (last-in, first-out stack) للاحتفاظ بالقيم المؤقتة.
حجم كل عنصر مكدس في EVM هو 256 بت ، ويبلغ أقصى حجم للمكدس 1024.
يحتوي EVM على ذاكرة ، حيث يتم تخزين العناصر كمصفوفات بايت معنونة بالكلمات. الذاكرة متقلبة ، مما يعني أنها ليست دائمة.
يحتوي جهاز EVM أيضًا على مساحة تخزين. على عكس الذاكرة ، فإن التخزين غير متقلبه ويتم الاحتفاظ به كجزء من حالة النظام. يقوم EVM بتخزين رمز البرنامج بشكل منفصل ، في ذاكرة ROM افتراضية لا يمكن الوصول إليها إلا من خلال تعليمات خاصة. بهذه الطريقة ، يختلف EVM عن بنية von Neumann النموذجية ، حيث يتم تخزين رمز البرنامج في الذاكرة أو التخزين.
ولجهاز EVM أيضًا لغته الخاصة: “EVM bytecode”. عندما يكتب مبرمج مثلك أو مثلي عقودًا ذكية تعمل على Ethereum ، فإننا نكتب عادةً تعليمات برمجية بلغة ذات مستوى أعلى مثل Solidity. يمكننا بعد ذلك تجميع ذلك وصولاً إلى EVM bytecode الذي يمكن لـ EVM فهمه.
حسنًا ، الآن إلى التنفيذ.
قبل تنفيذ عملية حسابية معينة ، يتأكد المعالج من أن المعلومات التالية متاحة وصالحة:
- حالة النظام
- الغاز المتبقي للحساب
- عنوان الحساب الذي يمتلك الكود الذي يتم تنفيذه
- عنوان مرسل المعاملة التي أدت إلى هذا التنفيذ
- عنوان الحساب الذي تسبب في تنفيذ الرمز (قد يكون مختلفًا عن المرسل الأصلي)
- سعر الغاز للمعاملة التي أدت إلى هذا التنفيذ
- بيانات الإدخال لهذا التنفيذ
- القيمة (في Wei) الممررة إلى هذا الحساب كجزء من التنفيذ الحالي
- كود الجهاز ليتم تنفيذه
- رأس كتلة الكتلة الحالية
- عمق مكالمة الرسالة الحالية أو مكدس إنشاء العقد
في بداية التنفيذ ، تكون الذاكرة والمكدس فارغين وعداد البرنامج صفر.
PC: 0 STACK: [] MEM: [], STORAGE: {}
ثم ينفذ EVM المعاملة بشكل متكرر ، ويحسب حالة النظام وحالة الجهاز لكل حلقة. حالة النظام هي ببساطة حالة Ethereum العالمية. تتكون حالة الآلة من:
- الغاز متاح
- عداد البرنامج
- محتويات الذاكرة
- عدد الكلمات النشط في الذاكرة
- محتويات المكدس.
تتم إضافة عناصر المكدس أو إزالتها من الجزء الأيسر من السلسلة.
في كل دورة ، يتم تقليل كمية الغاز المناسبة من الغاز المتبقي وزيادات عداد البرنامج.
في نهاية كل حلقة ، هناك ثلاثة احتمالات:
- يصل الجهاز إلى حالة استثنائية (على سبيل المثال ، غاز غير كافٍ ، أو تعليمات غير صالحة ، أو عناصر تكديس غير كافية ، أو عناصر تكديس تتجاوز 1024 ، وجهة JUMP / JUMPI غير صالحة ، وما إلى ذلك) ولذا يجب إيقافها ، مع تجاهل أي تغييرات
- يستمر التسلسل في المعالجة في الحلقة التالية
- وصول الجهاز لحالة توقف مبرمجه (نهاية عملية التنفيذ)
بافتراض أن التنفيذ لا يصل إلى حالة استثنائية ويصل إلى توقف “متحكم فيه” أو عادي ، فإن الجهاز يولد الحالة الناتجة ، والغاز المتبقي بعد هذا التنفيذ ، الحالة الفرعية المستحقة ، والمخرجات الناتجة.
. لقد مررنا بأحد أكثر أجزاء Ethereum تعقيدًا. حتى لو لم تكن قد استوعبت هذا الجزء تمامًا ، فلا بأس بذلك. لا تحتاج حقًا إلى فهم تفاصيل التنفيذ الدقيقة إلا إذا كنت تعمل على مستوى عميق جدًا.
كيف يتم إنهاء كتلة
أخيرًا ، دعنا نلقي نظرة على كيفية إنهاء كتلة تحتوي العديد من المعاملات.
عندما نقول “انتهى” ، يمكن أن يعني شيئين مختلفين ، اعتمادًا على ما إذا كانت الكتلة جديدة أو موجودة. إذا كانت كتلة جديدة ، فإننا نشير إلى العملية المطلوبة لتعدين هذه الكتلة. إذا كانت كتلة موجودة ، فإننا نتحدث عن عملية التحقق من صحة الكتلة. في كلتا الحالتين ، هناك أربعة متطلبات “إنهاء” للكتلة:
1) التحقق من صحة (أو تحديد التعدين في حالة)
يجب أن تكون كل كتلة ommer داخل رأس الكتلة رأسًا صالحًا وأن تكون ضمن الجيل السادس من الكتلة الحالية.
2) التحقق من صحة المعاملات (أو تحديدها في حالة التنقيب)
يجب أن يكون الرقم المستخدم على الكتلة يساوي الغاز التراكمي المستخدم في المعاملات المدرجة في الكتلة. (تذكر أنه عند تنفيذ أي معاملة ، فإننا نتتبع عداد غاز الكتلة ، الذي يتتبع إجمالي الغاز المستخدم في جميع المعاملات في الكتلة).
3) تطبيق المكافآت (فقط في حالة التعدين)
يتم منح عنوان المستفيد 5 إيثر لتعدين الكتلة. (بموجب اقتراح Ethereum EIP-649 ، سيتم تخفيض مكافأة 5 ETH هذه قريبًا إلى 3 ETH). بالإضافة إلى ذلك ، لكل مستخدم ، يتم منح المستفيد من الكتلة الحالية 1/32 إضافية من مكافأة الكتلة الحالية. أخيرًا ، يحصل المستفيد من كتلة (كتل) ommer أيضًا على مبلغ معين (هناك صيغة خاصة لكيفية حساب ذلك).
4) تحقق من (أو ، إذا كان التعدين ، احسب حالة صالحة) من حالة و nonce
تأكد من تطبيق جميع المعاملات وتغييرات الحالة الناتجة ، ثم حدد الكتلة الجديدة كالحالة بعد تطبيق مكافأة الكتلة على الحالة الناتجة للمعاملة النهائية. يحدث التحقق عن طريق التحقق من هذه الحالة النهائية مقابل شجرة الحالة المخزن في الرأس.
إثبات العمل للتعدين
تناول قسم “الكتل” بإيجاز مفهوم صعوبة الكتلة. تسمى الخوارزمية التي تعطي معنى لصعوبة الكتل إثبات العمل (PoW).
تسمى خوارزمية إثبات العمل في Ethereum “Ethash” (المعروفة سابقًا باسم Dagger-Hashimoto).
يتم تعريف الخوارزمية رسميًا على النحو التالي:
حيث m هو mixHash بينما n هو nonce أما Hn هو رأس الكتلة الجديدة (باستثناء مكونات nonce و mixHash ، التي يجب حسابها) ، Hn هو nonce لرأس الكتلة ، و d هو DAG ، وهو مجموعة بيانات كبيرة.
في قسم “الكتل” ، تحدثنا عن العناصر المختلفة الموجودة في رأس الكتلة. تم استدعاء اثنين من هذه المكونات mixHash و nonce. كما قد تتذكر:
- mixHash هو تجزئة تثبت ، عند دمجها مع nonce ، أن هذه الكتلة قد نفذت عمليات حسابية كافية
- nonce هي تجزئة تثبت ، عند دمجها مع mixHash ، أن هذه الكتلة قد نفذت عمليات حسابية كافية
تُستخدم وظيفة إثبات العمل (PoW) لتقييم هذين العنصرين.
كيف يتم حساب mixHash و nonce بالضبط باستخدام وظيفة PoW هو أمر معقد إلى حد ما ، وهو شيء يمكننا التعمق فيه في مقال منفصل. لكن على مستوى عالٍ ، تعمل على النحو التالي:
يتم حساب “بذرة” لكل كتلة. تختلف هذه البذرة في كل “حقبة” ، حيث يبلغ طول كل حقبة 30000 كتله . بالنسبة للحقبة الأولى ، فإن البذرة هي تجزئة سلسلة من 32 بايت من الأصفار. لكل حقبة لاحقة ، إنها تجزئة تجزئة البذور السابقة. باستخدام هذه البذرة ، يمكن للعقدة حساب “ذاكرة التخزين المؤقت” العشوائية الزائفة.
تعد ذاكرة التخزين المؤقت هذه مفيدة بشكل لا يصدق لأنها تتيح مفهوم “العقد الخفيفة” ، والذي ناقشناه سابقًا في هذا المقال. الغرض من العقد الخفيفة هو منح عقد معينة القدرة على التحقق بكفاءة من المعاملة دون عبء تخزين مجموعة بيانات blockchain بأكملها. يمكن للعقدة الخفيفة التحقق من صحة المعاملة بناءً على ذاكرة التخزين المؤقت هذه فقط ، لأن ذاكرة التخزين المؤقت يمكنها إعادة إنشاء الكتلة المحددة التي تحتاج إلى التحقق منها.
باستخدام ذاكرة التخزين المؤقت (cache)، يمكن للعقدة إنشاء “مجموعة بيانات” DAG ، حيث يعتمد كل عنصر في مجموعة البيانات على عدد صغير من العناصر الزائفة المختارة عشوائيًا من ذاكرة التخزين المؤقت. لكي تكون عامل منجم ، يجب عليك إنشاء مجموعة البيانات الكاملة هذه ؛ يقوم جميع العملاء وعمال المناجم الكاملين بتخزين مجموعة البيانات هذه ، وتنمو مجموعة البيانات خطيًا بمرور الوقت.
يمكن للمعدنين بعد ذلك أخذ شرائح عشوائية من مجموعة البيانات ووضعها في دالة رياضية لتجزئةها معًا في “mixHash”. سيقوم عامل المنجم بشكل متكرر بإنشاء mixHash حتى يصبح الناتج أقل من الرقم المطلوب المستهدف. عندما يفي الإخراج بهذا المطلب ، يعتبر هذا nonce صالحًا ويمكن إضافة الكتلة إلى السلسلة.
التعدين كآلية أمنية
بشكل عام ، الغرض من إثبات العمل هو إثبات ، بطريقة آمنة من الناحية المشفرة ، أن قدرًا معينًا من الحساب قد تم إنفاقه لتوليد بعض المخرجات (أي nonce). هذا لأنه لا توجد طريقة أفضل للعثور على nonce أقل من الحد المطلوب بخلاف تعداد جميع الاحتمالات. نواتج التطبيق المتكرر لوظيفة التجزئة لها توزيع موحد ، ولذا يمكننا أن نطمئن ، في المتوسط ، أن الوقت اللازم للعثور على مثل هذا nonce يعتمد على عتبة الصعوبة. كلما زادت الصعوبة ، زاد الوقت الذي يستغرقه حل مشكلة nonce. بهذه الطريقة ، تعطي خوارزمية إثبات العمل معنى لمفهوم الصعوبة ، والذي يستخدم لفرض أمان blockchain.
ماذا نعني بأمن blockchain؟ الأمر بسيط: نريد إنشاء blockchain يثق به الجميع. كما ناقشنا سابقًا في هذا المقال، في حالة وجود أكثر من سلسلة واحدة ، سيفقد المستخدمون الثقة ، لأنهم لن يتمكنوا من تحديد السلسلة “الصالحة” بشكل معقول. لكي تقبل مجموعة من المستخدمين الحالة الأساسية المخزنة على blockchain ، نحتاج إلى blockchain واحد أساسي تؤمن به مجموعة من الأشخاص.
هذا هو بالضبط ما تفعله خوارزمية إثبات العمل: فهي تضمن بقاء سلسلة بلوكشين معينة أساسية في المستقبل ، مما يجعلها صعبة بشكل لا يصدق على المهاجم إنشاء كتل جديدة تحل محل جزء معين من السجل (على سبيل المثال ، عن طريق محو المعاملات أو إنشاء معاملات وهمية) أو الحفاظ على تشعب (Fork). لكي يتم التحقق من صحة الكتلة الخاصة بهم أولاً ، سيحتاج المهاجم إلى حل المشكلة باستمرار بشكل أسرع من أي شخص آخر في الشبكة ، بحيث تعتقد الشبكة أن سلسلته هي أثقل سلسلة (بناءً على مبادئ بروتوكول GHOST التي ذكرناها سابقًا). سيكون هذا مستحيلًا ما لم يمتلك المهاجم أكثر من نصف طاقة تعدين الشبكة ، وهو السيناريو المعروف باسم هجوم الأغلبية بنسبة 51٪.
التعدين كآلية لتوزيع الثروة
بالإضافة إلى توفير blockchain آمن ، PoW هي أيضًا طريقة لتوزيع الثروة على أولئك الذين ينفقون حساباتهم لتوفير هذا الأمان. تذكر أن المُعَدِّن يتلقى مكافأة مقابل تعدين كتلة ، بما في ذلك:
- مكافأة الكتلة الثابتة بمقدار 5 إيثر للكتلة “الرابحة” (سيتم تغييرها قريبًا إلى 3 إيثر)
- تكلفة الغاز المنفق داخل الكتلة من خلال المعاملات المدرجة في الكتلة
- مكافأة إضافية لإدراج ommers كجزء من الكتلة
من أجل ضمان أن يكون استخدام آلية إجماع إثبات العمل للأمن وتوزيع الثروة مستدامًا على المدى الطويل ، تسعى Ethereum جاهدة لغرس هاتين الخاصيتين:
- اجعله في متناول أكبر عدد ممكن من الناس. بعبارة أخرى ، يجب ألا يحتاج الأشخاص إلى أجهزة متخصصة أو غير شائعة لتشغيل الخوارزمية. والغرض من ذلك هو جعل نموذج توزيع الثروة مفتوحًا قدر الإمكان بحيث يمكن لأي شخص توفير أي قدر من القوة الحسابية مقابل إيثر.
- قلل من احتمالية أن تحقق أي عقدة مفردة (أو مجموعة صغيرة) مبلغًا غير متناسب من الربح. أي عقدة يمكن أن تحقق ربحًا غير متناسب تعني أن العقدة لها تأثير كبير على تحديد blockchain الأساسي. هذا أمر مزعج لأنه يقلل من أمان الشبكة.
في شبكة Bitcoin blockchain ، إحدى المشكلات التي تنشأ فيما يتعلق بالخاصيتين المذكورتين أعلاه هي أن خوارزمية PoW هي دالة تجزئة SHA256. يتمثل الضعف في هذا النوع من الوظائف في أنه يمكن حلها بشكل أكثر كفاءة باستخدام أجهزة متخصصة ، تُعرف أيضًا باسم ASICs.
من أجل التخفيف من هذه المشكلة ، اختارت Ethereum أن تجعل خوارزمية إثبات العمل (Ethhash) صلبة الذاكرة بشكل تسلسلي. هذا يعني أن الخوارزمية مصممة بحيث يتطلب حساب nonce قدرًا كبيرًا من الذاكرة و النطاق الترددي العالي. تجعل متطلبات الذاكرة الكبيرة من الصعب على الكمبيوتر استخدام ذاكرته بالتوازي لاكتشاف عدة أرقام غير محدودة في وقت واحد ، كما أن متطلبات النطاق الترددي العالي تجعل من الصعب حتى على جهاز كمبيوتر فائق السرعة اكتشاف العديد من الرموز في نفس الوقت. هذا يقلل من مخاطر المركزية ويخلق مجالًا أكثر تكافؤًا للعقد التي تقوم بالتحقق.
شيء واحد يجب ملاحظته هو أن Ethereum تنتقل من آلية إجماع PoW إلى شيء يسمى “إثبات الحصة”. هذا موضوع وحشي خاص به ونأمل أن نستكشفه في منشور مستقبلي. ☺️
الخلاصة
لقد وصلت إلى النهاية. آمل؟
هناك الكثير لاستيعابها في هذا المقال ، أعلم. إذا استغرق الأمر عدة قراءات لفهم ما يحدث تمامًا ، فلا بأس بذلك تمامًا. لقد قرأت شخصيًا ورقة Ethereum الصفراء والورقة البيضاء وأجزاء مختلفة من قاعدة الكود عدة مرات قبل التذمر مما كان يحدث.
ومع ذلك ، آمل أن تكون قد وجدت هذه النظرة العامة مفيدة. إذا وجدت أي أخطاء أو أخطاء ، فأنا أحب أن تكتب ملاحظة خاصة أو تنشرها مباشرة في التعليقات. أنا أنظر إليهم جميعًا ، أعدك ؛)
وتذكر ، أنا إنسان (نعم ، هذا صحيح) وأرتكب أخطاء. لقد أخذت الوقت الكافي لكتابة هذا المنشور لصالح المجتمع مجانًا. لذا يرجى أن تكون بنّاءً في ملاحظاتك ، دون تقريع لا داعي له.
إضافة تعليق