البلوكتشين والعملات الرقمية الأدلة التقنية

التعدين Mining في Bitcoin: المكافأة والتنصيف Halving

ما الذي يحسبه جهاز التعدين، ومن أين يأتي دخله ولماذا ينقص للنصف، مع تعدين كتلة باليد على عقدة Bitcoin Core.

التعدين Mining في Bitcoin: المكافأة والتنصيف Halving

كل أربع سنوات تقريباً تقرأ عناوين عن «تنصيف» Bitcoin، وأن دخل المعدنين سوف ينقص إلى النصف، وتسمع أن أغلب المعدنين يعملون من خلال «مجمع» Pool بدلاً من أن يعدنوا وحدهم، فتسأل نفسك: ما الذي تحسبه هذه الأجهزة أصلاً؟ ولماذا ينقص دخلها بقرار مكتوب في الكود؟ وقد تصلك نفس الأسئلة بشكل عملي، فلو كنت تعمل في مركز بيانات وطلب عميل استضافة مئة جهاز تعدين، فسوف يسألك من حولك: لماذا يقول العميل إن دخله سوف «ينقص للنصف» بعد سنتين؟ ولماذا يشترك في مجمع؟ وهل يمكن أن تتعطل هذه الأجهزة عن العمل فجأة لأن أحداً غير قاعدة في الشبكة؟ وحتى تجيب بدقة، ومن غير أن تعد أحداً بأرباح أو تتوقع سعراً، تحتاج أن تفهم التعدين Mining من الداخل: ما الذي يحسبه الجهاز بالضبط، ومن أين يأتي دخله، ولماذا يتغير.

وفي مقال الإجماع شرحنا إثبات العمل من جهة الأمان: الهدف Target والصعوبة Difficulty وتعديلها كل 2016 كتلة واستهلاك الكهرباء وهجوم 51%، فلن نكرر ذلك. أما هنا فنأخذ جهة المعدن نفسه: سوف نعدن كتلة بأيدينا خطوة خطوة بكود Python على عقدة Bitcoin Core، ونرى ما ترفضه العقدة عندما نغش في المكافأة أو في الهاش، ونحسب جدول التنصيف Halving والسقف الكلي من نفس دالة Bitcoin Core، ونرى التنصيف يحدث فعلاً على شبكة regtest، ثم ننظر إلى الأجهزة والمجمعات والكهرباء. والمقال تعليمي تقني فقط، ولا يتضمن أي نصيحة استثمارية، ولا يتوقع سعراً أو ربحاً لأي جهاز.

وسوف نناقش في هذا المقال ما يلي:

  • ما الذي يفعله جهاز التعدين بالضبط، ولماذا تحولت الصناعة من المعالج إلى الأجهزة المتخصصة ASIC.
  • من أين يأتي دخل المعدن: المكافأة الأساسية Subsidy والرسوم Fees، وجدول التنصيف والسقف الكلي محسوبين من الكود.
  • تجربة: نرى التنصيف يحدث على regtest، ونعدن كتلة باليد من قالب getblocktemplate حتى submitblock.
  • نجرب العطل: ساتوشي واحد زيادة في المكافأة، وNonce لا يحقق الهدف، وما تقوله العقدة في كل حالة.
  • كم ينتظر جهاز واحد ليجد كتلة، وكيف يختار المعدن المعاملات.
  • المجمعات Mining Pools والحصص Shares، وما الذي يغيره بروتوكول Stratum V2.
  • من يقرر الترقيات: إشارات المعدنين أم العقد الكاملة.
  • الكهرباء والحرارة والتشغيل: ما الذي يعنيه استضافة هذه الأجهزة لمركز بيانات.
  • مستقبل الأمان عندما تقترب المكافأة الأساسية من الصفر، وقائمة أسئلة قبل قرار الاستضافة.

ما الذي يحسبه جهاز التعدين بالضبط؟

جهاز التعدين لا «يحل معادلات رياضية معقدة» كما يقال في الأخبار، وإنما يفعل شيئاً واحداً بسيطاً بسرعة هائلة: يأخذ رأس كتلة من 80 بايت، ويحسب له SHA-256 مرتين، ويقارن الناتج كرقم بالهدف، فإذا لم يكن أصغر غير بضعة بايتات في الرأس وأعاد الحساب. والبايتات التي يغيرها هي ال Nonce في الرأس، وهو 4 بايت فقط، أي قرابة 4.3 مليار قيمة، وهذا رقم يستنفده الجهاز الحديث في جزء من الثانية، لذلك يغير المعدن أيضاً جزءاً في معاملة المكافأة اسمه Extranonce، فيتغير جذر Merkle ويتغير الرأس كله، ويبدأ من جديد.

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

وفي السنتين الأوليين كان الناس يعدنون بالمعالج العادي CPU، ثم انتقلوا إلى بطاقات الرسوميات GPU لأنها تنفذ آلاف العمليات المتشابهة بالتوازي، ثم إلى الدوائر المتكاملة المصممة لغرض واحد ASIC، وهي شرائح لا تستطيع أن تفعل شيئاً إلا SHA-256 مرتين على رأس كتلة Bitcoin، ولكنها تفعله بكفاءة كهربائية لا يقترب منها أي معالج عام. والصورة التالية لجهاز Antminer S9، وهو من أشهر الأجهزة التي انتشرت في السنوات الماضية:

جهاز تعدين Antminer S9 فضي اللون بمروحة كبيرة في الأمام، وأسلاك طاقة كثيرة تخرج من أعلاه إلى مزود طاقة منفصل مكتوب عليه BITMAIN، وأنبوب تهوية معدني مرن متصل بالجهاز من الخلف
جهاز Antminer S9 في منزل صاحبه، الذي ذكر في وصف الصورة أن فيه 189 شريحة ASIC بتقنية 16nm ويستهلك قرابة 1.3 كيلوواط. الصورة: Steve Rainwater، رخصة CC BY-SA 2.0، المصدر: Wikimedia Commons (تم تصغيرها وتحويلها إلى WebP).

ولاحظ في الصورة أنبوب التهوية الكبير ومزود الطاقة المنفصل، فهذان هما ما يهمانك كمشغل مركز بيانات أكثر من أي شيء آخر: الجهاز يحول كل الكهرباء التي يستهلكها تقريباً إلى حرارة، ويحتاج تياراً ثابتاً وتبريداً مستمراً، وصوت المراوح فيه عال. وداخل الجهاز ألواح عليها الشرائح نفسها تسمى ألواح الهاش Hashboards، والصورة التالية لأحدها:

لوح إلكتروني أخضر عليه صفوف كثيرة من المشتتات الحرارية المعدنية الفضية التي تغطي شرائح ASIC، وعلى طرفه موصلات وملصق رقم تسلسلي
لوح هاش من جهاز Antminer، وتحت المشتتات المعدنية شرائح BM1387B المصممة لحساب SHA-256 فقط. الصورة: John McMaster، رخصة CC BY 4.0، المصدر: Wikimedia Commons (تم تصغيرها وتحويلها إلى WebP).

لماذا سمي «تعديناً»؟ ما تقوله الورقة الأصلية

الاسم نفسه جاء من ورقة Bitcoin. ففي القسم السادس بعنوان «Incentive» تقول الورقة إن أول معاملة في الكتلة بحسب الاتفاق معاملة خاصة تنشئ عملة جديدة يملكها من أنشأ الكتلة، وإن هذا يعطي العقد حافزاً لدعم الشبكة، ويوفر طريقة لتوزيع العملات أول مرة لأنه لا توجد جهة مركزية تصدرها، ثم تشبه إضافة كمية ثابتة من العملات الجديدة بعمال مناجم الذهب الذين يصرفون موارد ليضيفوا الذهب إلى التداول، وتقول إن المورد هنا هو وقت المعالج والكهرباء. وتضيف الورقة أن الحافز يمكن أن يأتي أيضاً من رسوم المعاملات، وأنه بعد أن يدخل عدد محدد من العملات إلى التداول يمكن أن ينتقل الحافز كله إلى الرسوم، وهذا هو الانتقال الذي سوف نناقشه في آخر المقال.

وفي القسم الرابع تصف الورقة إثبات العمل بأنه «صوت لكل معالج» One-CPU-One-Vote، في مقابل «صوت لكل عنوان IP» الذي يستطيع أي شخص أن يزوره بعناوين كثيرة. وهذا الوصف كان دقيقاً في السنة الأولى، أما اليوم فالصوت لكل وحدة كهرباء تصرف في شريحة ASIC، والفكرة نفسها لم تتغير: من يريد أن يؤثر في ترتيب السلسلة يجب أن يصرف شيئاً حقيقياً لا يمكن نسخه.

الكفاءة: الطاقة لكل وحدة هاش

عندما يقارن المعدنون الأجهزة لا ينظرون إلى السرعة وحدها، وإنما إلى الطاقة التي يصرفها الجهاز لكل وحدة هاش، وتقاس عادة بالجول لكل تيرا هاش J/TH. وبالأرقام التي ذكرها صاحب صورة جهاز S9، قرابة 1.3 كيلوواط مقابل قرابة 14 تيرا هاش في الثانية، تكون كفاءته قرابة 93 جول لكل تيرا هاش، أي أنه يصرف 93 جول من الكهرباء ليجرب ألف مليار هاش. وهذا الرقم هو ما يحدد عمر الجهاز الاقتصادي أكثر من أي شيء آخر: عندما تدخل أجهزة أحدث بكفاءة أعلى ترتفع الصعوبة، فينقص نصيب الجهاز القديم من الكتل، بينما فاتورة كهرباء الجهاز القديم لا تنقص، فيأتي يوم يكلف فيه الجهاز كهرباء أكثر مما يحصل عليه، ويتوقف صاحبه عن تشغيله.

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

من أين يأتي دخل المعدن؟

المعدن الذي يجد كتلة صالحة يكتب فيها أول معاملة بنفسه، وهي معاملة المكافأة Coinbase Transaction التي رأيناها في مقال كيف يعمل Bitcoin، ويدفع فيها لنفسه مجموع شيئين: المكافأة الأساسية Subsidy، وهي عملات جديدة تنشئها الكتلة من لا شيء بحسب جدول ثابت في قواعد الإجماع، ورسوم كل المعاملات التي وضعها في الكتلة، وهي ليست عملات جديدة وإنما ينقلها المرسلون إليه. ولا يستطيع المعدن أن يكتب أكثر من هذا المجموع ولو بساتوشي واحد، وهذا ما سوف نجربه بعد قليل.

والمكافأة الأساسية تحسبها في Bitcoin Core دالة قصيرة جداً اسمها GetBlockSubsidy في ملف validation.cpp: تقسم رقم الكتلة على فترة التنصيف، فيخرج عدد مرات التنصيف، ثم تبدأ بـ 50 وحدة وتزيح الرقم إلى اليمين بهذا العدد، أي تقسمه على 2 في كل مرة، وإذا وصل عدد التنصيفات إلى 64 أرجعت صفراً. وفترة التنصيف على الشبكة الرئيسية 210,000 كتلة، وهي القيمة nSubsidyHalvingInterval في chainparams.cpp، ومع كتلة كل عشر دقائق تقريباً يكون التنصيف كل أربع سنوات تقريباً، وهذا ما يقصده العميل في مثالنا: في التنصيف القادم تنقص المكافأة الأساسية لكل كتلة إلى النصف، فإذا بقيت الأشياء الأخرى كما هي نقص دخل الجهاز من هذا المصدر إلى النصف.

نحسب الجدول والسقف من نفس الدالة

الملف التالي يعيد كتابة نفس منطق الدالة بالساتوشي كأعداد صحيحة، ثم يجمع المكافآت حقبة بعد حقبة حتى تصبح صفراً. احفظه باسم supply.py:

# The supply schedule straight from GetBlockSubsidy() in Bitcoin Core's validation.cpp (integer satoshis).
COIN, INTERVAL = 100_000_000, 210_000
total, height = 0, 0
while True:
    halvings = height // INTERVAL
    subsidy = 0 if halvings >= 64 else (50 * COIN) >> halvings
    if subsidy == 0:
        break
    total += subsidy * INTERVAL
    if halvings < 6 or subsidy < 10:
        print(f"era {halvings:2}: blocks {height:>9,}-{height + INTERVAL - 1:>9,} subsidy {subsidy / COIN:>12.8f} BTC")
    height += INTERVAL
print(f"last block with a subsidy: {height - 1:,}")
print(f"total supply: {total:,} sat = {total / COIN:.8f} BTC")
docker run --rm --name lab-mine-py -v "$PWD:/lab" -w /lab python:3.13.16-slim python supply.py

والمخرج سوف يكون كما يلي:

era  0: blocks         0-  209,999 subsidy  50.00000000 BTC
era  1: blocks   210,000-  419,999 subsidy  25.00000000 BTC
era  2: blocks   420,000-  629,999 subsidy  12.50000000 BTC
era  3: blocks   630,000-  839,999 subsidy   6.25000000 BTC
era  4: blocks   840,000-1,049,999 subsidy   3.12500000 BTC
era  5: blocks 1,050,000-1,259,999 subsidy   1.56250000 BTC
era 29: blocks 6,090,000-6,299,999 subsidy   0.00000009 BTC
era 30: blocks 6,300,000-6,509,999 subsidy   0.00000004 BTC
era 31: blocks 6,510,000-6,719,999 subsidy   0.00000002 BTC
era 32: blocks 6,720,000-6,929,999 subsidy   0.00000001 BTC
last block with a subsidy: 6,929,999
total supply: 2,099,999,997,690,000 sat = 20999999.97690000 BTC

في الإعداد أعلاه لاحظ التالي:

  • الحقبة الحالية هي الحقبة 4، من الكتلة 840,000 التي جاءت في أبريل 2024 كما ذكرنا في مقال الإجماع، والمكافأة فيها 3.125 لكل كتلة، والتنصيف التالي عند الكتلة 1,050,000.
  • الإزاحة إلى اليمين على عدد صحيح من الساتوشي تقطع الكسور، فبعد الحقبة 32 تصبح المكافأة أقل من ساتوشي واحد، أي صفراً، وآخر كتلة فيها مكافأة هي 6,929,999.
  • السقف الذي يقال عنه «21 مليوناً» هو في الحقيقة 20,999,999.9769 بسبب هذا القطع، وفي الواقع أقل من ذلك أيضاً، لأن مكافأة كتلة التكوين لا يمكن صرفها كما رأينا في مقال التاريخ، ولأن بعض المعدنين في السنوات الأولى كتبوا لأنفسهم أقل من المسموح.
  • لم نخزن أي رقم في هذا الحساب: الجدول كله ينتج من سطرين في الكود وقيمة واحدة في الإعدادات، وأي عقدة في العالم تحسبه بنفس الطريقة، ولهذا لا يستطيع أحد أن يغيره دون أن يرفض باقي العقد كتله.

والصورة التالية ترسم الحقب:

أعمدة تتناقص للنصف: 50 من الكتلة 0، و25 من 210,000، و12.5 من 420,000، و6.25 من 630,000، و3.125 من 840,000 بلون أخضر للحقبة الحالية، و1.5625 من 1,050,000، ثم قيم أصغر حتى الكتلة 6,929,999، وتحتها ثلاث بطاقات: الحقبة الحالية منذ أبريل 2024، والسقف 2,099,999,997,690,000 ساتوشي، وفي التجربة شبكة regtest تنصف كل 150 كتلة
المكافأة الأساسية تنقص للنصف كل 210,000 كتلة، والسقف ينتج من الحساب نفسه

نرى التنصيف يحدث على regtest

الانتظار أربع سنوات حتى ترى تنصيفاً غير عملي، ولكن شبكة regtest تستخدم فترة تنصيف قدرها 150 كتلة فقط، وهي نفس القيمة nSubsidyHalvingInterval = 150 في chainparams.cpp. فنشغل العقدة، وننشئ محفظة، ونعدن 300 كتلة، ثم نسأل عن المكافأة في الكتل المحيطة بنقطتي التنصيف. ونفعل في هذه العقدة اسم مستخدم وكلمة مرور لواجهة RPC لأننا سنحتاجها في التجربة التالية من Container آخر، والقيم هنا للتجربة المحلية فقط:

docker run -d --name lab-mine-btc bitcoin/bitcoin:31.1 bitcoind -regtest -printtoconsole=0 \
  -rpcuser=lab -rpcpassword=lab-only -rpcbind=127.0.0.1 -rpcallowip=127.0.0.1
alias btc='docker exec --user bitcoin lab-mine-btc bitcoin-cli -regtest -rpcuser=lab -rpcpassword=lab-only'
btc createwallet miner
A=$(btc getnewaddress "" bech32); echo $A
btc generatetoaddress 300 $A > /dev/null
for h in 1 149 150 299 300; do echo -n "$h "; btc getblockstats $h '["subsidy"]' | grep subsidy; done

والمخرج سوف يكون كما يلي، بعد سطر اسم المحفظة:

bcrt1q8hc6glru0lj4s832aq7a0fx6wtpcfdyf57wmh5
1   "subsidy": 5000000000
149   "subsidy": 5000000000
150   "subsidy": 2500000000
299   "subsidy": 2500000000
300   "subsidy": 1250000000

الكتلة 149 آخر كتلة في الحقبة الأولى ومكافأتها 50 وحدة، أي 5,000,000,000 ساتوشي، والكتلة 150 أول كتلة في الحقبة الثانية ومكافأتها 25، والكتلة 300 بداية الحقبة الثالثة ومكافأتها 12.5. والتنصيف ليس حدثاً يعلنه أحد أو يقرره أحد، وإنما نتيجة القسمة الصحيحة في الدالة عندما يصل رقم الكتلة إلى مضاعف فترة التنصيف، وهذا بالضبط ما سوف يحدث على الشبكة الرئيسية عند الكتلة 1,050,000.

كم ينتظر جهاز واحد؟ حساب بالأرقام

حتى نفهم لماذا لا يعدن أحد وحده اليوم، نحسب احتمال أن يجد جهاز واحد كتلة. وفي مقال الإجماع حسبنا صعوبة الكتلة 840,000 من رأسها الحقيقي، فكانت 86,388,558,925,171، والعدد المتوقع من محاولات الهاش لكل كتلة يساوي الصعوبة ضرب 2 أس 32. ونأخذ جهازاً بسرعة 14 تيرا هاش في الثانية، وهو الرقم الذي ذكره صاحب صورة جهاز S9 في وصفها:

docker run --rm --name lab-mine-py python:3.13.16-slim python -c "
d = 86_388_558_925_171            # difficulty of block 840,000
hashes = d * 2**32                 # expected hashes per block
rate = 14e12                       # one device at 14 TH/s
sec = hashes / rate
print(f'expected hashes per block: {hashes:.3e}')
print(f'one 14 TH/s device: {sec:.3e} s = {sec/3600/24/365.25:,.0f} years on average')
print(f'chance per block (one device vs ~618 EH/s): {rate/618e18:.2e}')
print(f'time to try all 2**32 nonces: {2**32/rate*1000:.2f} ms')
"

والمخرج سوف يكون كما يلي:

expected hashes per block: 3.710e+23
one 14 TH/s device: 2.650e+10 s = 840 years on average
chance per block (one device vs ~618 EH/s): 2.27e-08
time to try all 2**32 nonces: 0.31 ms

في الإعداد أعلاه لاحظ التالي:

  • جهاز واحد بهذه السرعة يحتاج في المتوسط قرابة 840 سنة ليجد كتلة واحدة عند صعوبة الكتلة 840,000، وهذا متوسط وليس موعداً، فقد يجدها غداً وقد لا يجدها أبداً، لأن كل محاولة مستقلة عن التي قبلها.
  • الرقم 618 إكسا هاش في الثانية تقدير لقوة الشبكة كلها حسبناه في مقال الإجماع من نفس الصعوبة ومن وقت الكتلة المستهدف، وحصة الجهاز منها قرابة 2 من كل مئة مليون، وهي نفس احتمال أن يكون هو من يجد أي كتلة بعينها.
  • السطر الأخير يبين لماذا لا يكفي ال Nonce: الجهاز يجرب كل القيم الممكنة له، أي قرابة 4.3 مليار قيمة، في ثلث ملي ثانية، فيحتاج بعدها أن يغير شيئاً آخر في الكتلة، وهو ال Extranonce في معاملة المكافأة، فيتغير جذر Merkle ويحصل على مساحة بحث جديدة كاملة.

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

ماذا يعني التنصيف لمن لا يعدن؟

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

ومن جهة العرض، فالتنصيف يعني أن عدد العملات الجديدة التي تدخل التداول كل يوم ينقص للنصف، وهذا معروف مسبقاً لكل من يقرأ الكود منذ 2009، فلا يحمل أي معلومة جديدة عن المستقبل. ولن نناقش هنا أثره على الأسعار، لأن هذا خارج هدف المقال، ولأن أي توقع من هذا النوع ليس شيئاً يستطيع الكود أن يجيب عنه.

تجربة: نعدن كتلة بأيدينا

الأمر generatetoaddress الذي استخدمناه حتى الآن يخفي كل شيء، فالعقدة تبني الكتلة وتبحث عن ال Nonce وتضيفها بنفسها. أما المعدن الحقيقي فلا يعمل هكذا: العقدة تعطيه قالباً بالأمر getblocktemplate، وهو يبني معاملة المكافأة بنفسه، ويحسب جذر Merkle، ويبني الرأس، ويبحث عن ال Nonce، ثم يرسل الكتلة كاملة بالأمر submitblock. والملف التالي يفعل هذه الخطوات بالترتيب، ويتصل بالعقدة عبر RPC، احفظه باسم handmine.py:

# Mine one regtest block by hand: template -> coinbase -> merkle root -> header -> nonce search -> submitblock.
import hashlib, json, struct, sys, urllib.request, base64

def rpc(method, *params):
    req = urllib.request.Request("http://127.0.0.1:18443/", json.dumps({"jsonrpc": "1.0", "id": 1, "method": method, "params": list(params)}).encode(),
                                 {"Authorization": "Basic " + base64.b64encode(b"lab:lab-only").decode(), "Content-Type": "application/json"})
    try:
        return json.load(urllib.request.urlopen(req))["result"]
    except urllib.error.HTTPError as e:
        return json.load(e)["error"]

dsha = lambda b: hashlib.sha256(hashlib.sha256(b).digest()).digest()
def varint(n): return bytes([n]) if n < 0xfd else b"\xfd" + struct.pack("<H", n)
def push_int(n):                                          # BIP34: block height as a minimal script push
    b = n.to_bytes((n.bit_length() + 8) // 8, "little")
    return bytes([len(b)]) + b

tpl = rpc("getblocktemplate", {"rules": ["segwit"]})
print("height", tpl["height"], "| bits", tpl["bits"], "| coinbasevalue", tpl["coinbasevalue"], "| mempool txs", len(tpl["transactions"]))

extra = int(sys.argv[2]) if len(sys.argv) > 2 else 0      # how many satoshis to "steal" (to see the rule fail)
spk = bytes.fromhex(rpc("validateaddress", sys.argv[1])["scriptPubKey"])
script_sig = push_int(tpl["height"]) + b"/arabroot lab/"
coinbase = (struct.pack("<I", 2) + b"\x01" + b"\x00" * 32 + b"\xff\xff\xff\xff" + varint(len(script_sig)) + script_sig
            + b"\xff\xff\xff\xff" + b"\x01" + struct.pack("<q", tpl["coinbasevalue"] + extra) + varint(len(spk)) + spk + b"\x00\x00\x00\x00")
merkle = dsha(coinbase)                                   # one transaction: the root is its txid
target = int(tpl["target"], 16)
head = struct.pack("<I", tpl["version"]) + bytes.fromhex(tpl["previousblockhash"])[::-1] + merkle + struct.pack("<I", tpl["curtime"]) + bytes.fromhex(tpl["bits"])[::-1]

want_valid = not (len(sys.argv) > 3 and sys.argv[3] == "bad")   # "bad": submit a nonce that misses the target
nonce = 0
while True:
    h = dsha(head + struct.pack("<I", nonce))
    if (int.from_bytes(h, "little") <= target) == want_valid:
        break
    nonce += 1
print("nonce", nonce, "| block hash", h[::-1].hex())
block = head + struct.pack("<I", nonce) + varint(1) + coinbase
print("submitblock ->", rpc("submitblock", block.hex()))
print("coinbase text:", script_sig[len(push_int(tpl["height"])):].decode())

في الكود أعلاه لاحظ التالي:

  • الدالة push_int تكتب ارتفاع الكتلة في بداية scriptSig لمعاملة المكافأة، وهذا شرط إجماع منذ BIP34 كما ذكرنا في مقال كيف يعمل Bitcoin، وبعده نضع رسالة حرة /arabroot lab/، وهذه هي نفس المساحة التي وضع فيها Satoshi عنوان صحيفة The Times في كتلة التكوين.
  • معاملة المكافأة لها مدخل واحد يشير إلى «لا شيء»: 32 بايت أصفار ورقم ffffffff، ومخرج واحد بقيمة coinbasevalue من القالب إلى عنوان المعدن.
  • الكود يفترض أن الطابور فارغ، فالكتلة فيها معاملة المكافأة وحدها، لذلك جذر Merkle هو هاش هذه المعاملة نفسها، وأي معدن حقيقي يضيف معاملات القالب ويبني الشجرة كما فعلنا في مقال التشفير.
  • الحلقة تغير ال Nonce وتحسب SHA-256 مرتين للرأس، وتقارن الناتج كرقم بترتيب البايت الصغير أولاً مع الهدف، وهذا هو كل «التعدين».
  • المعاملان الاختياريان يسمحان لنا بأن نغش عمداً: الأول يضيف ساتوشيات إلى المكافأة، والثاني يختار Nonce لا يحقق الهدف.

نشغل الملف في Container يشارك شبكة Container العقدة، حتى يصل إلى RPC على 127.0.0.1 دون أن ننشر أي منفذ على الجهاز:

docker run --rm --name lab-mine-py --network container:lab-mine-btc -v "$PWD:/lab" -w /lab python:3.13.16-slim \
  python handmine.py bcrt1q8hc6glru0lj4s832aq7a0fx6wtpcfdyf57wmh5

والمخرج سوف يكون كما يلي:

height 302 | bits 207fffff | coinbasevalue 1250000000 | mempool txs 0
nonce 1 | block hash 072a5d33a0b61fe013b50896ec47f081cb9184c964c41a8b5c8f5d4b88b6b813
submitblock -> None
coinbase text: /arabroot lab/

الأمر submitblock يرجع None عندما يقبل الكتلة، ولا يرجع رسالة نجاح. والآن نتأكد من العقدة نفسها:

btc getblockcount
btc getblock $(btc getblockhash 302) 2 | python3 -c "
import json,sys;b=json.load(sys.stdin);cb=b['tx'][0];print(b['height'],b['nTx'],cb['vin'][0]['coinbase'],cb['vout'][0]['value'])"

والمخرج سوف يكون كما يلي:

302
302 1 022e012f61726162726f6f74206c61622f 12.5

الكتلة 302 دخلت السلسلة وفيها معاملة واحدة، ومدخل معاملة المكافأة يبدأ بـ 022e01، أي بايتان طولهما ثم الرقم 302 بترتيب البايت الصغير أولاً، ثم الرسالة /arabroot lab/ بترميز Hex، والمكافأة 12.5 لأننا في الحقبة الثالثة من regtest. ولاحظ أن ال Nonce الذي احتجناه هو 1 فقط، والسبب أن الهدف في regtest هو 7fffff…، أي أن نصف الهاشات تقريباً تحققه. والصورة التالية تلخص المراحل:

خمس مراحل: القالب من getblocktemplate بارتفاع 302 وcoinbasevalue 1250000000، ثم معاملة المكافأة بالارتفاع والرسالة arabroot lab ومخرج 12.5، ثم جذر Merkle الذي يساوي هاش معاملة المكافأة لأنها وحدها، ثم الرأس وال Nonce 1 والهاش 072a5d33، ثم submitblock يرجع None ويصبح عدد الكتل 302، وتحتها تجربتان للعطل: ساتوشي واحد زيادة يعطي bad-cb-amount، وNonce لا يحقق الهدف يعطي high-hash
التعدين خمس خطوات، والخطوة الرابعة وحدها هي التي تستهلك الكهرباء

نجرب العطل: ماذا لو غش المعدن؟

المعدن هو من يكتب معاملة المكافأة، فما الذي يمنعه من أن يكتب لنفسه أكثر قليلاً؟ ولماذا لا يرسل كتلة دون أن يحقق الهدف ويوفر الكهرباء؟ نجرب الاثنين: مرة نضيف ساتوشياً واحداً إلى المكافأة، ومرة نختار Nonce لا يحقق الهدف:

docker run --rm --name lab-mine-py --network container:lab-mine-btc -v "$PWD:/lab" -w /lab python:3.13.16-slim \
  python handmine.py bcrt1q8hc6glru0lj4s832aq7a0fx6wtpcfdyf57wmh5 1
docker run --rm --name lab-mine-py --network container:lab-mine-btc -v "$PWD:/lab" -w /lab python:3.13.16-slim \
  python handmine.py bcrt1q8hc6glru0lj4s832aq7a0fx6wtpcfdyf57wmh5 0 bad

والمخرج سوف يكون كما يلي:

height 303 | bits 207fffff | coinbasevalue 1250000000 | mempool txs 0
nonce 0 | block hash 31ddc19f84285cc968c46f53fa4301706c725d4ebd2daaf32c9e5ff496b79f01
submitblock -> bad-cb-amount
coinbase text: /arabroot lab/
height 303 | bits 207fffff | coinbasevalue 1250000000 | mempool txs 0
nonce 0 | block hash a0c322275dcd780d738f6f85b6c42f388ccfad505c2e80ade96d906ee5a9feb1
submitblock -> high-hash
coinbase text: /arabroot lab/

في الإعداد أعلاه لاحظ التالي:

  • في المحاولة الأولى كان الهاش صالحاً، أي أن الكتلة تحمل إثبات عمل حقيقياً، ومع ذلك رفضتها العقدة بالسبب bad-cb-amount، لأن مخرج معاملة المكافأة أكبر بساتوشي واحد من المكافأة الأساسية مع الرسوم. أي أن العمل لا يشتري حق مخالفة القواعد، والكهرباء التي صرفها المعدن على هذه الكتلة ضاعت كلها.
  • في المحاولة الثانية كانت المكافأة صحيحة، ولكن الهاش أكبر من الهدف، فرفضت العقدة الكتلة بالسبب high-hash، وهذا الفحص رخيص جداً على العقدة، هاش واحد، فلا يستطيع أحد أن يغرق الشبكة بكتل مزيفة دون أن يصرف العمل.
  • بعد المحاولتين بقي عدد الكتل 302، فلم تدخل أي منهما السلسلة، وكل عقدة كاملة في العالم كانت ستتصرف بنفس الطريقة، وهذا هو المعنى العملي لعبارة أن المعدنين لا يملكون قواعد الشبكة، وإنما يملكون ترتيب المعاملات فقط.
📌
في أغسطس 2010 أنشأت معاملة في الكتلة 74,638 أكثر من 184 مليار وحدة بسبب تجاوز في سعة العدد الصحيح عند جمع المخرجات، كما يذكر سجل الحادثة والثغرة CVE-2010-5139. والكتلة كانت تحمل إثبات عمل صحيحاً، ومع ذلك أصلح المطورون الكود خلال ساعات، وتبنت العقد سلسلة لا تحتوي تلك المعاملة. والدرس هو نفس درس التجربة: صحة الكتلة تأتي من قواعد يتحقق منها كل من يشغل عقدة، وليس من العمل وحده.

ماذا يوجد في القالب أيضاً؟

عندما يكون في الطابور معاملات يتغير القالب. أرسلنا معاملة واحدة برسوم 20 ساتوشي لكل vbyte، ثم طلبنا القالب وطبعنا أهم حقوله:

btc -named sendtoaddress address=$(btc getnewaddress) amount=1 fee_rate=20 > /dev/null
btc getblocktemplate '{"rules":["segwit"]}' | python3 -c "
import json,sys;t=json.load(sys.stdin)
for k in ['version','previousblockhash','height','curtime','bits','target','coinbasevalue','sigoplimit','weightlimit','default_witness_commitment']: print(k, t.get(k))
for x in t['transactions']: print('tx', x['txid'][:16], 'fee', x['fee'], 'weight', x['weight'])"
btc getmininginfo | grep -E '"(blocks|difficulty|networkhashps|chain)"'

والمخرج سوف يكون كما يلي:

version 805306368
previousblockhash 072a5d33a0b61fe013b50896ec47f081cb9184c964c41a8b5c8f5d4b88b6b813
height 303
curtime 1793151560
bits 207fffff
target 7fffff0000000000000000000000000000000000000000000000000000000000
coinbasevalue 1250002820
sigoplimit 80000
weightlimit 4000000
default_witness_commitment 6a24aa21a9ede8d8675071d87b7b92a926fd20d366b31abd3df1df2b81b5cab9211e6a258202
tx 177a9edbdfc80c7a fee 2820 weight 561
  "blocks": 302,
  "difficulty": 4.656542373906925e-10,
  "networkhashps": 5.581395348837209,
  "chain": "regtest",
    "difficulty": 4.656542373906925e-10,

في الإعداد أعلاه لاحظ التالي:

  • coinbasevalue أصبح 1,250,002,820، أي المكافأة الأساسية مع رسوم المعاملة 2,820 ساتوشي، وهي 141 vbyte ضرب 20، ولو استخدم handmine.py هذا القالب دون أن يضيف المعاملة إلى الكتلة لرفضت العقدة الكتلة بنفس السبب bad-cb-amount، لأنه يطلب رسوماً لم يضمها.
  • default_witness_commitment هو مخرج التزام الشاهد الذي رأيناه في مقال كيف يعمل Bitcoin، والقالب يحسبه للمعدن جاهزاً.
  • القيمة version تساوي 0x30000000، وبتات الإصدار تستخدم للإشارة إلى دعم الترقيات المقترحة كما حدث مع Taproot.
  • networkhashps تقدير لقوة الشبكة من سرعة الكتل الأخيرة وصعوبتها، وهو على regtest رقم صغير لا معنى له، وعلى الشبكة الرئيسية الرقم الذي تقارن به حصة أجهزتك.

كيف يختار المعدن المعاملات؟

القالب الذي أعطته العقدة فيه معاملة واحدة، ولكن في أوقات الازدحام يكون الطابور أكبر بكثير مما تتسع له كتلة واحدة، لذلك يرتب Bitcoin Core المعاملات في القالب بمعدل الرسوم لكل vbyte، مع حساب العائلات: المعاملة الابن التي تدفع عن أبيها تحسب مع أبيها كحزمة واحدة، كما رأينا في تجربة CPFP في مقال كيف يعمل Bitcoin. ثم يملأ الكتلة حتى حد الوزن weightlimit 4000000 الذي ظهر في القالب، مع حد آخر لعدد عمليات التوقيع sigoplimit، لأن التحقق من التوقيعات هو أغلى جزء على العقد.

والمعدن حر في أن يغير هذا الاختيار: يستطيع أن يضيف معاملات لم تصل إلى الطابور العام، أو أن يترك معاملات يدفع أصحابها رسوماً، ما دامت كل معاملة صالحة بقواعد الإجماع. وهذا الحرية هي بالضبط ما يجعل تركز المجمعات سؤالاً مهماً كما سوف نرى، لأن من يبني القالب هو من يقرر ما يدخل السلسلة الآن، وإن كان لا يستطيع أن يقرر ما هو صالح.

لماذا يشترك المعدنون في مجمعات Mining Pools؟

الآن نعود إلى السؤال الذي بدأنا به: لماذا يشترك العميل في مجمع؟ والإجابة في الاحتمالات. فإذا كانت أجهزته المئة تمثل جزءاً صغيراً جداً من قوة الشبكة، فاحتمال أن تجد كتلة في يوم معين ضئيل، ومتوسط الوقت بين كتلتين يجدهما قد يكون سنوات، والدخل الذي يأتي مرة كل بضع سنوات بمبلغ كبير لا يصلح لشركة تدفع فاتورة كهرباء كل شهر. والمجمع يحل هذه المشكلة بتقسيم البحث: يبني القالب ومعاملة المكافأة التي تدفع إلى عنوانه، ويعطي كل جهاز رأساً مختلفاً بقيمة Extranonce مختلفة حتى لا يكرر جهازان نفس المحاولات، وكل جهاز يرسل إلى المجمع أي هاش يحقق هدفاً أسهل بكثير من هدف الشبكة، ويسمى ذلك حصة Share.

والحصص لا قيمة لها في الشبكة، ولكنها دليل إحصائي على أن الجهاز يعمل فعلاً بالسرعة التي يدعيها، وبعدد الحصص يقسم المجمع المكافأة عندما يصادف أحد الأجهزة هاشاً يحقق هدف الشبكة نفسه. وبهذا الشكل يحصل العميل على دخل صغير منتظم بدلاً من دخل كبير نادر، ويدفع للمجمع نسبة مقابل ذلك. والصورة التالية تبين الآلية:

ثلاث خطوات: المجمع يوزع العمل ببناء القالب ومعاملة مكافأة لعنوانه وإرسال رأس بقيمة Extranonce مختلفة لكل جهاز، ثم الأجهزة ترسل حصصاً بهاشات أقل من هدف أسهل يحدده المجمع، ثم إحدى الحصص تكون كتلة فينشرها المجمع ويوزع المكافأة بحسب الحصص، وتحتها بطاقتان: الثمن تركز القرار لأن المجمع يختار المعاملات، وStratum V2 الذي يسمح للمعدنين ببناء قوالبهم ويشفر الاتصال
المجمع يحول دخلاً نادراً كبيراً إلى دخل صغير منتظم، والثمن أن المجمع يقرر ما يدخل الكتلة

ولكن لهذا الترتيب ثمن على الشبكة كلها. ففي البروتوكول التقليدي Stratum يختار المجمع وحده المعاملات التي تدخل القالب، والأجهزة تعمل على ما يرسله لها، فإذا سيطرت مجمعات قليلة على أغلب قوة الشبكة صارت جهات قليلة تقرر ما يدخل السلسلة، حتى لو كانت الأجهزة نفسها موزعة على آلاف المالكين. ولهذا السبب جاء بروتوكول Stratum V2 المفتوح، والذي يقول موقعه إنه يسمح للمعدنين ببناء قوالبهم بأنفسهم، ويشفر الاتصال بين الجهاز والمجمع ويوثقه حتى لا يستطيع وسيط أن يغير العمل أو يسرق الحصص، ويستخدم صيغة ثنائية بدلاً من JSON. وإذا كنت ستستضيف أجهزة، فاسأل العميل عن المجمع الذي يستخدمه والبروتوكول، لأن حركة الشبكة بين الأجهزة والمجمع تمر عبر بنيتك.

الكتل التي تخسر السباق، والتعدين الأناني

عندما يجد معدنان كتلتين في نفس الوقت تقريباً، تنتشر الكتلتان في الشبكة، وتبني العقد على التي وصلتها أولاً، حتى تأتي الكتلة التالية فوق إحداهما، فتصبح الأخرى كتلة خاسرة Stale Block، وتضيع مكافأتها كلها، وقد رأينا أثر ذلك على المعاملات في تجربة إعادة التنظيم في مقال كيف يعمل Bitcoin. لذلك تهتم المجمعات بسرعة نشر كتلها وباستلام كتل الآخرين بأسرع ما يمكن، وكل ثانية تأخير بين الجهاز والمجمع تعني عملاً قد يصرف على قالب قديم انتهى أمره، وهذا من أسباب اهتمام Stratum V2 بتقليل الحصص القديمة.

وفي سنة 2013 نشر Ittay Eyal وEmin Gün Sirer ورقة بعنوان Majority is not Enough: Bitcoin Mining is Vulnerable، تصف استراتيجية سموها التعدين الأناني Selfish Mining: مجمع يخفي الكتل التي يجدها ولا ينشرها فوراً، ويستمر في البناء عليها سراً، ثم ينشرها في اللحظة التي تجعل عمل الآخرين يضيع، فيحصل على نصيب من المكافآت أكبر من نصيبه من قوة التعدين. والفكرة المهمة في الورقة أن الأمان لا يحتاج فقط أن تكون الأغلبية شريفة، وإنما أن يكون السلوك الشريف هو الأربح أيضاً، وأن المجمع الكبير بما يكفي قد يجد حافزاً للانحراف قبل أن يصل إلى 51%. وهذا سبب آخر يجعل تركز قوة التعدين في مجمعات قليلة سؤالاً يتابعه كل من يهتم بأمان الشبكة.

الكهرباء والحرارة: ما الذي يعنيه استضافة هذه الأجهزة؟

من وجهة نظر مركز البيانات، جهاز التعدين حمل كهربائي ثابت يعمل بكامل طاقته 24 ساعة في اليوم، على عكس السيرفرات التي يتغير حملها، وكل واط يدخل الجهاز يخرج حرارة تقريباً. وجهاز واحد من نوع S9 في الصورة يستهلك بحسب وصف صاحبه قرابة 1.3 كيلوواط، فمئة جهاز من هذه الفئة حمل مستمر يقارب حمل عدد كبير من خزائن السيرفرات العادية، وهذا يغير حسابات التبريد وتوزيع الكهرباء في القاعة كلها. والصورة التالية من مزرعة تعدين، ولاحظ الصفوف المتلاصقة والأضواء الخضراء التي تعني أن كل جهاز يعمل:

قاعة واسعة مظلمة على يمينها رفوف عالية متلاصقة من أجهزة التعدين بأضواء خضراء صغيرة، وسقف معدني عال بإنارة قليلة
مزرعة تعدين Bitcoin في صورة التقطت في 14 يونيو 2014. الصورة: Marko Ahtisaari، رخصة CC BY 2.0، المصدر: Wikimedia Commons (تم تصغيرها وتحويلها إلى WebP).

والأسئلة التشغيلية التي يجب أن تجيب عنها قبل أي عقد استضافة:

  • الحمل الكهربائي المستمر: احسب القدرة الكلية بالكيلوواط من مواصفات الطراز الذي سيحضره العميل، وليس من متوسط تقديري، وتأكد أن خطوط التغذية والقواطع ومولدات الطوارئ تتحمل حملاً كاملاً دون توقف.
  • التبريد والهواء: الأجهزة تسحب هواء القاعة وتخرجه ساخناً جداً، فتحتاج فصلاً بين الممر الساخن والبارد، أو تبريداً بالغمر Immersion في بعض التصاميم، والسبب أن الجهاز الذي ترتفع حرارته يخفض سرعته أو يتوقف.
  • الضوضاء والغبار: المراوح تعمل بأقصى سرعة، والمكان يحتاج عزلاً عن مناطق العمل وتنظيفاً دورياً للمرشحات.
  • الشبكة: الأجهزة لا تحتاج سعة كبيرة، ولكنها تحتاج اتصالاً مستقراً بالمجمع، ويفضل أن تكون في شبكة منفصلة VLAN عن عملاء مركز البيانات الآخرين، لأن واجهات إدارة هذه الأجهزة كثيراً ما تأتي بكلمات مرور افتراضية.
  • المراقبة: راقب استهلاك كل خط كهرباء وحرارة الهواء الخارج من الصفوف، وليس حالة الأجهزة فقط، لأن الجهاز الذي يعمل بسرعة أقل من المعتاد بسبب الحرارة يظهر عند العميل كنقص في الدخل، وعندك كعلامة مبكرة على مشكلة تبريد قد تمتد إلى ما حوله. واتفق مع العميل مسبقاً على من يراقب ماذا، ومن يملك صلاحية إعادة تشغيل الأجهزة.
  • النظام والترخيص: نشاط التعدين واستهلاكه الكهربائي قد يخضعان لأنظمة وتراخيص خاصة، فاطلب من العميل والمستشار القانوني ما يثبت أن النشاط مسموح ومرخص من الجهات المختصة قبل توقيع العقد، ولا تعتمد على ما يقوله العميل وحده.

ولاحظ أن الحديث هنا عن مسؤوليتك كمشغل، وليس عن ربح العميل: دخل الجهاز يعتمد على حصته من قوة الشبكة، والمكافأة الأساسية في حقبتها، والرسوم، وسعر العملة، وتكلفة الكهرباء، وكلها تتغير، وبعضها لا يمكن توقعه، لذلك لا تبن أي جزء من عقدك على وعد بأرباح أو نقاط تعادل قدمها لك أحد.

من يقرر الترقيات: المعدنون أم العقد؟

والسؤال الأخير الذي بدأنا به: هل يمكن أن تتعطل هذه الأجهزة فجأة لأن أحداً غير قاعدة في الشبكة؟ والإجابة تبدأ من الحقل version الذي رأيناه في القالب. ففي الترقيات التي تضيف قواعد جديدة دون أن تجعل الكتل القديمة غير صالحة، وهي ما يسمى التفرع الناعم Soft Fork، استخدم Bitcoin طريقة تسمى بتات الإصدار Version Bits: المعدنون يشيرون في كل كتلة إلى استعدادهم لقاعدة جديدة، وعندما تصل الإشارة إلى نسبة محددة خلال فترة صعوبة كاملة تقفل الترقية ثم تفعل. وفي ترقية Taproot كانت النسبة 1815 كتلة من 2016، أي 90%، مع ارتفاع أدنى للتفعيل هو الكتلة 709,632، كما يذكر قسم التفعيل في BIP341.

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

ماذا يحدث عندما تقترب المكافأة من الصفر؟

كما رأينا في الجدول، المكافأة الأساسية تنقص للنصف في كل حقبة، وبعد الكتلة 6,929,999 تصبح صفراً، وعندها يكون دخل المعدن من الرسوم وحدها. وفي القالب الذي طبعناه كانت الرسوم 2,820 ساتوشي فقط مقابل 1,250,000,000 مكافأة أساسية، وهذا في شبكة تجريبية، ولكن النسبة بين المصدرين هي ما يهم على المدى البعيد. والصورة التالية تبين الفكرة:

ثلاثة أعمدة: في التجربة قالب فيه مكافأة أساسية 1,250,000,000 ساتوشي ورسوم صغيرة جداً، ثم مع كل تنصيف تزيد نسبة الرسوم إذا بقيت كما هي، ثم بعد الكتلة 6,929,999 الرسوم وحدها، وتحتها بطاقة تقول إن إثبات العمل يحمي السلسلة بقدر ما يصرفه المعدنون، وإن كفاية الرسوم وحدها سؤال مفتوح
المكافأة الأساسية تقترب من الصفر، والرسوم يجب أن تحمل الأمان وحدها في النهاية

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

أخطاء شائعة في فهم التعدين

  • «المعدنون يتحققون من المعاملات نيابة عن الجميع»: كل عقدة كاملة تتحقق من كل كتلة بنفسها كما رأينا مع bad-cb-amount، والمعدن يقترح الكتلة فقط، وإذا خالفت القواعد رفضتها العقد مهما كان عمله.
  • «التنصيف قرار يمكن تأجيله»: التنصيف نتيجة قسمة في قواعد الإجماع، وتغييره يحتاج أن تغير كل العقد كودها، وأي معدن يكتب لنفسه المكافأة القديمة بعد التنصيف ترفض كتلته.
  • «أجهزة أكثر تعني كتلاً أسرع»: تعديل الصعوبة كل 2016 كتلة يعيد الوقت إلى قرابة عشر دقائق، فالأجهزة الإضافية ترفع الصعوبة، وتقسم نفس المكافأة على قوة أكبر.
  • «الرسوم تذهب إلى الشبكة أو إلى المطورين»: الرسوم تذهب إلى من ينشئ الكتلة، وتظهر في معاملة المكافأة، وقد رأينا ذلك في coinbasevalue.
  • «الجهاز القديم بلا قيمة بعد التنصيف»: هذا يعتمد على كفاءته الكهربائية مقارنة بالأجهزة الأحدث وعلى تكلفة الكهرباء، ولهذا السبب يقيس المعدنون الأجهزة بالطاقة لكل وحدة هاش، وليس بالسرعة وحدها.

قائمة أسئلة قبل قرار الاستضافة

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

إزالة التجربة

docker rm -f -v lab-mine-btc
docker image rm bitcoin/bitcoin:31.1

تدريب عملي

  1. عدل handmine.py ليضيف معاملات القالب إلى الكتلة ويبني جذر Merkle منها، ثم أرسل معاملة إلى الطابور وعدن كتلة تحتويها دون أن ترى bad-cb-amount.
  2. غير الرسالة في معاملة المكافأة إلى نص من اختيارك، ثم اقرأها من الكتلة بالأمر getblock كما قرأنا رسالة كتلة التكوين.
  3. في supply.py غير فترة التنصيف إلى 150 كما في regtest، واحسب السقف الكلي لهذه الشبكة التجريبية.

الخلاصة

وصلنا لنهاية الموضوع، وأهم ما فيه:

  • جهاز التعدين يحسب SHA-256 مرتين لرأس كتلة من 80 بايت ويغير ال Nonce وال Extranonce حتى يصبح الهاش أقل من الهدف، والصناعة انتقلت إلى شرائح ASIC لا تفعل غير ذلك.
  • دخل المعدن مكافأة أساسية تنشئ عملات جديدة ورسوم ينقلها المرسلون، ويكتبهما في معاملة المكافأة، ولا يستطيع أن يزيد عليهما ساتوشياً واحداً.
  • المكافأة الأساسية تنصف كل 210,000 كتلة بحساب بسيط في GetBlockSubsidy، والحقبة الحالية 3.125 منذ الكتلة 840,000، والسقف 20,999,999.9769، وقد رأينا التنصيف يحدث على regtest كل 150 كتلة.
  • عدنا كتلة باليد من القالب حتى submitblock، ورفضت العقدة الغش في المكافأة بالسبب bad-cb-amount والهاش الضعيف بالسبب high-hash، فالعمل لا يشتري حق مخالفة القواعد.
  • المجمعات تحول الدخل النادر إلى دخل منتظم بالحصص، وثمنها تركز اختيار المعاملات، وStratum V2 يحاول إعادة هذا الاختيار للمعدنين.
  • استضافة أجهزة التعدين قرار كهرباء وتبريد ونظام قبل أن يكون قرار تقنية، ولا تبن أي عقد على وعد بأرباح.
دليلكيف تتفق شبكة البلوكتشين؟ إثبات العمل وإثبات الحصةكيف تتفق آلاف العقد التي لا يثق بعضها ببعض على سجل واحد، ولماذا يكلف الغش كهرباء في شبكة ومالاً محجوزاً في أخرى.دليلكيف يعمل Bitcoin؟ المعاملة والمخرجات غير المنفقة UTXOنبني معاملة Bitcoin بأيدينا ونتتبعها حتى الكتلة، لنفهم لماذا لا يوجد رصيد، وأين تذهب الرسوم، ومتى تصبح الدفعة دفعة فعلاً.دليلتاريخ العملات الرقمية: من Cypherpunks إلى Bitcoinكيف حاول المهندسون صنع نقد رقمي أربعين سنة، ولماذا تعثرت المحاولات قبل Bitcoin، وما الذي جمعه Bitcoin منها.دليلالتشفير في البلوكتشين: الهاش والمنحنيات والتوقيعاتكيف تصنع المفاتيح والعناوين والتوقيعات في Bitcoin وEthereum، ولماذا يكشف رقم مكرر واحد في التوقيع المفتاح الخاص.دليلتشغيل عقدة Bitcoin كاملة على سيرفرك مع Bitcoin Coreلماذا تشغل عقدة Bitcoin كاملة، وكيف تثبتها بـ Docker Compose وتؤمن واجهة RPC، وماذا يحدث في المزامنة الأولى والتقليم.

سجل التحديثات

  • أكتوبر 2026: كتابة المقال، واختبار التجارب على Docker Engine 29.8.0 مع Bitcoin Core v31.1.0 في وضع regtest وPython 3.13.16.
نشرة عرب رووت | ArabRoot

معرفة تستحق مكاناً في بريدك.

مقالات مختارة وأدوات مفيدة وأفكار لمشروعك القادم، في رسالة واحدة كل أسبوع.

يمكنك إلغاء الاشتراك متى شئت. الخصوصية

تم استلام طلبك. افتح بريدك واضغط رابط التأكيد لإتمام الاشتراك.