تقديم المحتوى
لا يحمل سجل بروتوكول ملفًا أبدًا. بل يحمل CID — تجزئةً ذاتية الوصف لمحتوى مخزَّن في مكان آخر — وهو ما يُبقي إيصالًا بحجم 10 ميغابايت خارج حمولة gossip يجب على كل عقدة تخزينها وإعادة تشغيلها، بينما يظل يتيح لمحكّم أن يثبت أن الصورة التي ينظر إليها هي التي وقّع عليها الطرف.
ما زال على أحدٍ أن يحمل البايتات. ذلك الأحد هو عقدتك، وهي تفعل ذلك بالفعل: تقديم المحتوى مفعَّل افتراضيًا ولا يحتاج تكوينًا.
لماذا هو في العقدة لا في خادم
ثبّت الإصدار الأول من هذا عبر خادم Kubo
منفصل، يُوصَل عبر --ipfs-api-url. نجح ذلك، وكلّف أكثر مما بدا: هوية
قرين ثانية على الشبكة، وزمن تشغيل Go وذاكرته المقيمة إلى جانب العقدة،
وواجهة تحكم /api/v0 غير مصادَق عليها على المنفذ 5001 تتيح لأي أحد يصل
إليها التثبيت وإلغاؤه وقراءة كل ما يحمله الخادم — لا يخفّفها إلا ربطها
بـ loopback.
المشكلة الأعمق كانت الافتراض. تشغيل خادم عمل، فالتثبيت كان اختياريًا، فكاد لا أحد يشغّله — وضمان متانة لا يختار أحد الدخول فيه ليس ضمانًا. تتحدث عقدة الآن bitswap داخل العملية، فوق هوية libp2p نفسها التي تعمل بها gossip بالفعل، وهو ما يتيح أن يكون السلوك مفعَّلًا افتراضيًا. وذلك بدوره ما يجعل علاوة المكافأة تقيس شيئًا حقيقيًا: مع تقديم الجميع، يفصل المضاعِف العُقد التي تحمل المحتوى وتجيب عنه فعلًا عن العُقد المنقطعة أو التي قلّمت، بدلًا من فصل المشغّلين الذين تكلّفوا تثبيت Go عمّن لم يفعلوا.
ماذا تحمل عقدتك، وماذا لا تحمل
تحمل المحتوى الذي تشير إليه سجلات مرفقات قبِلتها، داخل نافذة احتفاظها. لا تجلب كل CID تراه — عقدة تفعل ذلك ستخزّن ما يختار أي أحد توجيهها إليه.
ذلك الحد ليس وعدًا، بل حساب: يجب أن يسمّي مرفق تسويةً، وتحتاج تسوية إلى حجز حقيقي مقابل ضمان حقيقي. سقف ما يُطلَب من قرصك هو حجم تداول الشبكة الفعلي، لا صبر غريب.
كل ما يُسترجَع يُفحَص ضد CID الخاص به قبل الاحتفاظ به، سواء أتى من قرين أم من بوابة.
اسأل عقدتك عمّا تحمله:
curl -s -X POST http://localhost:7080/rpc -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"getHeldContent","params":{"cid":"bafkrei..."}}'
# {"jsonrpc":"2.0","id":1,"result":{"content":"<base64>"}} ← محمول
# {"jsonrpc":"2.0","id":1,"result":{"content":null}} ← غير محمول
من أين تأتي النسخة الأولى
يحرّك bitswap الكتل بين أقران يملكونها بالفعل؛ لا يُنشئ الأولى. يدخل المحتوى الشبكة عبر أي خدمة تثبيت رفعته إليها الواجهة، فأول عقدة تريد CID عليها جلبه من شبكة IPFS الأوسع، وفحص البايتات ضد الـ CID، وتقديمه لأقرانها من حينها.
--content-gateway https://ipfs.example.com # الافتراضي: https://ipfs.filebase.io
البوابة نقل غير موثوق، لا سلطة. يمكنها تقديم بايتات خاطئة، أو لا بايتات، أو تسجيل من طلب ماذا؛ ولا يمكنها تغيير أي محتوى يسمّيه CID، لأن الـ CID تجزئة لذلك المحتوى. البايتات التي ليست ما يسمّيه CID تُرفَض، وبوابة تستبدل أي شيء لا تُميَّز عن أخرى معطَّلة ببساطة.
الخصوصية هي الشيء الوحيد الذي لا يصلحه التحقق: من يشغّل البوابة يعرف أن عقدتك طلبت هذا الـ CID. لذلك يوجد العلم — وجّهه إلى بوابتك أنت — ولذلك هو احتياطي لا خيار أول. عقدتك تفضّل أقرانها.
إن كنت تشغّل Kubo أصلًا
--ipfs-api-url http://127.0.0.1:5001 ما زال يعمل ويعني الآن شيئًا أضيق
مما كان: يُثبَّت محتوى البروتوكول في خادمك أيضًا، واضعًا نسخةً في
مكان لا تحكمه نافذة احتفاظ عقدتك. لم يعد ذلك كيف تقدّم عقدة المحتوى.
إيقافه، وما يكلّفه ذلك
openfiat-node --no-content-serving
تلك العقدة لا تخزّن شيئًا ولا تستطيع الإجابة على تحدي استرجاع، فتكسب الحصة المخفَّضة. تلك هي النتيجة الأمينة — إنها تفعل أقل للشبكة — وهو العلم الصحيح إن كان القرص غير موجود فعلًا. ما زالت العقدة تتحدى أقرانها على أي حال: قياس من يقدّم المحتوى خدمة تؤديها عقدة سواء خزّنت هي شيئًا أم لا.
كيف يعمل التحدي
تختار عقدة CID تعرفه الشبكة، وتطلب من عقدة أخرى البايتات، وتجزّئ ما يعود. عنوان المحتوى هو تجزئة محتواه، فإعادة البايتات الصحيحة ليست شيئًا تستطيع عقدة فعله دون امتلاكها. هذه هي الإشارة الوحيدة لجودة العقدة التي تُفحَص لا تُصدَّق.
بعض معرّفات CID فقط تستطيع حسم السؤال. تجزئة CID بترميز raw تُؤخَذ على الملف نفسه؛ ويعنون CID بصيغة dag-pb جذر DAG مقسَّم، فقد يعيد قرين الملف الصحيح ومع ذلك يفشل فحص تجزئة ساذجًا. يبدّل المزوّدون بين الاثنين عند 262,144 بايتًا، فتأخذ التحديات عينات من ملفات عند 256 KiB أو دونها — الصور الرمزية دائمًا تقريبًا، والمرفقات أحيانًا. ذلك يكفي لفصل عقدة تثبّت كل شيء عن أخرى لا تثبّت شيئًا، وهو ما يحتاجه المضاعِف؛ وليس برهانًا على أن عقدة تحمل مرفقًا كبيرًا بعينه، ولا شيء يدّعي أنه كذلك.
ما هو المضاعِف
عقدة تجيب تحتفظ بحصتها الكاملة؛ عقدة لا تستطيع تُقاس إلى 0.7، فعقدة
تقدّم تكسب نحو 1.43× ما تكسبه عقدة متطابقة لولا ذلك لا تقدّم. كلا الرقمين
[PROPOSED — NEEDS SIGN-OFF] — انظر OFS-4100 §9.2 و
crates/rewards/src/params.rs.
تُعبَّر العلاوة كعقوبة لسبب ليس عرضيًا. الإصدار لكل حقبة ثابت، وهذه المضاعِفات تقرّر كيف يُقسَّم. مكافأة فوق 1.0 لن تدفع لعقدة تثبيت من العدم، بل ستسكّ إصدارًا لا يحتويه دلو البنية — وهو ما ترفضه معاملات المكافأة صراحةً. فتحتفظ عقدة التثبيت بحصتها الكاملة وتتنازل عقدة عدم التثبيت عن جزء من حصتها.
0.7 بدلًا من 0.4 لعقدة gossip فقط لأن التخزين معروف أصغر للشبكة من اتصال سلسلة: عقدة لا تثبّت ما زالت ترحّل وتتحقق وتقدّم كل شيء آخر.
كم يُحتفَظ بالمحتوى
ليس على كل عقدة أن تحمل التاريخ كله.
--retention 30 # الافتراضي: نافذة متجدّدة مدتها 30 يومًا
--retention 365 # نافذة أطول، ما زالت متجدّدة
--retention archival # احتفظ بكل شيء، للأبد — خيار صريح
30 يومًا هي أيضًا الحد الأدنى الذي تدين به كل عقدة للشبكة، فالقيم الأقصر تُرفَض بدلًا من رفعها بصمت — عقدة مكوَّنة لسبعة أيام لكنها عملت بصمت لثلاثين ستكون تفعل شيئًا غير ما طلبه مشغّلها.
ذلك الحد هو ما يتيح للطرد والمكافآت التعايش. لا تُسحَب التحديات إلا من المحتوى داخله، فعقدة متجدّدة طردت أدلة العام الماضي بشكل صحيح لا يُسأل عنها قط ولا تفقد حصتها لفعلها الصواب. وبالمثل، لا تستطيع عقدة تقليص ما يمكن أن تُسأل عنه بإعلان نافذة أصغر.