تخطي إلى المحتوى الرئيسي
Change page

خوارزمية إثبات العمل لـ Ethereum 1.0 ملف: مسرد

آخر تحديث للصفحة: 15 أبريل 2026

إيثاش كانت خوارزمية التعدين لإثبات العمل الخاصة بـ إيثريوم. لقد تم الآن إيقاف تشغيل إثبات العمل بالكامل، وتم تأمين إيثريوم الآن باستخدام إثبات الحصة بدلاً من ذلك. Read more on ذا ميرج, proof-of-stake and staking. Read more on ذا ميرج, proof-of-stake and staking!

إيثاش هي نسخة معدلة من خوارزمية Dagger-Hashimoto. إن إثبات عمل إيثاش صعب الذاكرة، وهو ما كان يُعتقد أنه يجعل خوارزمية مقاومة لـ ASIC (opens in a new tab). في نهاية المطاف، تم تطوير ASICs من إيثاش، ولكن التعدين باستخدام وحدة معالجة الرسوميات كان لا يزال خيارًا قابلاً للتطبيق حتى تم إيقاف تشغيل إثبات العمل. لا يزال يتم استخدام إيثاش لتعدين العملات الأخرى على شبكات إثبات العمل الأخرى غير إيثريوم.

كيف يعمل إيثاش؟

يتم تحقيق صلابة الذاكرة باستخدام خوارزمية إثبات العمل التي تتطلب اختيار مجموعات فرعية من مورد ثابت يعتمد على nonce ورأس الكتلة. يُطلق على هذا المورد (الذي يبلغ حجمه بضعة غيغابايت) اسم DAG. يتم تغيير DAG كل 30000 كتلة، وهي نافذة مدتها حوالي 125 ساعة تسمى العصر (حوالي 5.2 يوم) وتستغرق بعض الوقت لتوليدها. نظرًا لأن DAG يعتمد فقط على ارتفاع الكتلة، فمن الممكن إنشاؤه مسبقًا، ولكن إذا لم يكن الأمر كذلك، فيجب على العميل الانتظار حتى نهاية هذه العملية لإنتاج كتلة. إذا لم يقم العملاء بإنشاء DAGs وتخزينها مسبقًا، فقد تواجه الشبكة تأخيرًا هائلاً في الكتلة في كل انتقال عصر. لاحظ أن DAG لا يلزم إنشاؤه للتحقق من إثبات العمل، مما يسمح بالتحقق باستخدام وحدة معالجة مركزية منخفضة وذاكرة صغيرة.

المسار العام الذي تتبعه الخوارزمية هو كما يلي:

  1. توجد بذرة يمكن حسابها لكل كتلة عن طريق المسح عبر رؤوس الكتل حتى تلك النقطة.
  2. من البذرة، يمكن للمرء حساب ذاكرة تخزين مؤقت شبه عشوائية بحجم 16 ميجابايت. يخزن العملاء الخفيفون ذاكرة التخزين المؤقت.
  3. من ذاكرة التخزين المؤقت، يمكننا إنشاء مجموعة بيانات بحجم 1 جيجابايت، مع الخاصية التي تجعل كل عنصر في مجموعة البيانات يعتمد فقط على عدد صغير من العناصر من ذاكرة التخزين المؤقت. يقوم العملاء الكاملون والعاملون في المناجم بتخزين مجموعة البيانات. تنمو مجموعة البيانات بشكل خطي مع الوقت.
  4. يتضمن التعدين التقاط أجزاء عشوائية من مجموعة البيانات وتجزئتها معًا. يمكن إجراء التحقق باستخدام ذاكرة منخفضة باستخدام ذاكرة التخزين المؤقت لتجديد أجزاء معينة من مجموعة البيانات التي تحتاجها، وبالتالي لن تحتاج إلا إلى تخزين ذاكرة التخزين المؤقت.

يتم تحديث مجموعة البيانات الكبيرة مرة كل 30000 كتلة، وبالتالي فإن الغالبية العظمى من جهد عامل التعدين سيكون في قراءة مجموعة البيانات، وليس إجراء تغييرات عليها.

التعريفات

نحن نستخدم التعريفات التالية:

استخدام 'SHA3'

تزامن تطوير الإيثريوم مع تطوير معيار SHA3، وقد أدخلت عملية المعايير تغييرًا متأخرًا في حشو خوارزمية التجزئة النهائية، بحيث لا تُعتبر تجزئتا الإيثريوم "sha3_256" و"sha3_512" تجزئات sha3 قياسية، بل مُتغير يُشار إليه غالبًا باسم "Keccak-256" و"Keccak-512" في سياقات أخرى. انظر النقاش، على سبيل المثال، هنا (opens in a new tab)، وهنا (opens in a new tab)، أو هنا (opens in a new tab).

يرجى أخذ ذلك في الاعتبار حيث تتم الإشارة إلى تجزئات "sha3" في وصف الخوارزمية أدناه.

المعلمات

تعتمد معلمات ذاكرة التخزين المؤقت ومجموعة البيانات الخاصة بـ إيثاش على رقم الكتلة. تعتمد معلمات ذاكرة التخزين المؤقت ومجموعة البيانات الخاصة بـ إيثاش على رقم الكتلة. ينمو كل من حجم ذاكرة التخزين المؤقت وحجم مجموعة البيانات بشكل خطي؛ ومع ذلك، فإننا نأخذ دائمًا أعلى عدد أولي أقل من عتبة النمو الخطي من أجل تقليل مخاطر الانتظامات العرضية التي تؤدي إلى سلوك دوري.

يتم توفير جداول قيم حجم مجموعة البيانات والذاكرة المؤقتة في الملحق.

إنشاء ذاكرة التخزين المؤقت

Now, we specify the function for producing a cache:

تتضمن عملية إنتاج ذاكرة التخزين المؤقت أولاً ملء 32 ميجابايت من الذاكرة بالتسلسل، ثم إجراء تمريرين لخوارزمية RandMemoHash الخاصة بـ Sergio Demian Lerner من Strict Memory Hard Hashing Functions (2014) (opens in a new tab). النتيجة هي مجموعة من 524288 قيمة مكونة من 64 بايت.

دالة تجميع البيانات

نحن نستخدم خوارزمية مستوحاة من تجزئة FNV (opens in a new tab) في بعض الحالات كبديل غير ترابطي لـ XOR. لاحظ أننا نضرب العدد الأولي بالمدخلات الكاملة المكونة من 32 بت، على النقيض من مواصفات FNV-1 التي تضاعف العدد الأولي ببايت واحد (ثماني بتات) بدوره.

FNV_PRIME = 0x01000193

def fnv(v1, v2):
    return ((v1 * FNV_PRIME) ^ v2) % 2**32

لاحظ أننا نضرب العدد الأولي بالمدخلات الكاملة المكونة من 32 بت، على النقيض من مواصفات FNV-1 التي تضاعف العدد الأولي ببايت واحد (ثماني بتات) بدوره.

حساب مجموعة البيانات الكاملة

يتم حساب كل عنصر مكون من 64 بايت في مجموعة البيانات الكاملة بحجم 1 جيجابايت على النحو التالي:

في الأساس، نقوم بدمج البيانات من 256 عقدة تخزين مؤقت تم اختيارها عشوائيًا، ونقوم بتجزئتها لحساب عقدة مجموعة البيانات. يتم بعد ذلك إنشاء مجموعة البيانات بأكملها بواسطة:

def calc_dataset(full_size, cache):
    return [calc_dataset_item(cache, i) for i in range(full_size // HASH_BYTES)]

الحلقة الرئيسية

الآن، نقوم بتحديد الحلقة الرئيسية الشبيهة بـ "هاشيموتو"، حيث نقوم بتجميع البيانات من مجموعة البيانات الكاملة من أجل إنتاج القيمة النهائية لرأس معين ورقم عشوائي. في النص البرمجي أدناه، يمثل header التجزئة (هاش) SHA3-256 لتمثيل RLP لـ رأس كتلة مبتور، أي رأس يستثني حقلي mixHash و nonce. nonce هو ثمانية بايتات من عدد صحيح غير موقّع مكون من 64 بت بترتيب الطرف الكبير. لذا فإن nonce[::-1] هو التمثيل ذو الثمانية بايتات بترتيب الطرف الصغير لتلك القيمة:

بشكل أساسي، نحافظ على "مزيج" بعرض 128 بايت، ونجلب 128 بايت بشكل متكرر بالتسلسل من مجموعة البيانات الكاملة ونستخدم دالة fnv لدمجها مع المزيج. يتم استخدام 128 بايت من الوصول المتسلسل بحيث تقوم كل جولة من الخوارزمية دائمًا بجلب صفحة كاملة من ذاكرة الوصول العشوائي (RAM)، مما يقلل من أخطاء تخزين الترجمة الجانبية التي من الناحية النظرية تكون ASICs قادرة على تجنبها.

إذا كان ناتج هذه الخوارزمية أقل من الهدف المطلوب، فإن القيمة العشوائية تكون صالحة. لاحظ أن التطبيق الإضافي لـ sha3_256 في النهاية يضمن وجود nonce وسيط يمكن توفيره لإثبات أنه تم إنجاز قدر صغير على الأقل من العمل؛ يمكن استخدام التحقق السريع الخارجي من إثبات العمل (PoW) هذا لأغراض مكافحة هجمات الحرمان من الخدمة (DDoS). كما أنه يعمل على توفير ضمان إحصائي بأن النتيجة عبارة عن رقم غير متحيز يتكون من 256 بت.

التنقيب

يتم تعريف خوارزمية التعدين على النحو التالي:

def mine(full_size, dataset, header, difficulty):
    # ملء الهدف بالأصفار للمقارنة مع التجزئة (الهاش) على نفس الرقم
    target = zpad(encode_int(2**256 // difficulty), 64)[::-1]
    from random import randint
    nonce = randint(0, 2**64)
    while hashimoto_full(full_size, dataset, header, nonce) > target:
        nonce = (nonce + 1) % 2**64
    return nonce

تعريف تجزئة (هاش) البذرة

من أجل حساب تجزئة البذرة التي سيتم استخدامها للتعدين فوق كتلة معينة، نستخدم الخوارزمية التالية:

 def get_seedhash(block):
     s = '\x00' * 32
     for i in range(block.number // EPOCH_LENGTH):
         s = serialize_hash(sha3_256(s))
     return s

لاحظ أنه لتحقيق عملية تعدين وتحقق سلسة، نوصي بإجراء حساب مسبق لـ seedhashes ومجموعات البيانات المستقبلية في سلسلة منفصلة.

قراءة إضافية

هل تعرف أحد الموارد المجتمعية التي ساعدتك؟ عدّل هذه الصفحة وأضفه!

الملحق

يجب إضافة الكود التالي إذا كنت مهتمًا بتشغيل مواصفات بايثون أعلاه ككود.

أحجام البيانات

توفر جداول البحث التالية ما يقرب من 2048 حقبة مجدولة من أحجام البيانات وأحجام التخزين المؤقت.

هل كان هذا المقال مفيداً؟