اكتشاف الأقران
تنضم عقدة بطلب اتصال بنقطة دخول وتجد بقية الشبكة بنفسها. يتبادل اكتشاف الأقران (OFS-1100) الأقران المعروفين عبر الاتصال نفسه الذي تستخدمه gossip بالفعل، فتتعلّم عقدة أقرانًا لم تُعطَ لها قط وتعلن العناوين التي تكون قابلةً للوصول عندها.
يستحق هذا القول بوضوح لأنه لم يكن صحيحًا دائمًا، وكان الفشل غير مرئي: خدمة الاكتشاف كانت منفَّذة بالكامل وقارَبت خمس عُقد في اختبارها الخاص، ولم تُنشئ عقدة قيد التشغيل واحدة قط. لم تعلن العُقد عنوانًا ولم تتعلّم قرينًا لم يُعطَ لها ثابتًا، بينما بدت صحيحةً تمامًا من كل فحص محلي. للعقدة سرب libp2p واحد، شيء واحد فقط يستطيع تشغيل حلقة أحداث ذلك السرب، وكانت gossip تملكها — فالخدمة التي لا تملك السرب لم تستلم شيئًا، إلى الأبد. كلاهما الآن يتشاركان اتصالًا واحدًا، وتُوجَّه الرسائل إلى إحداهما أو الأخرى برقم مواصفة OFS الخاص بالمظروف.
الاكتشاف ليس علمًا ولا يمكن إيقافه.
أول اتصال
لا شيء يستطيع إيجاد شبكة من العدم، فما زال --entrypoint هو كيف تبدأ
عقدة:
openfiat-node --entrypoint /dns4/openfiat.allenhark.com/udp/4001/quic-v1/p2p/12D3KooW...
كرّره لعدة. اسم مضيف يعمل ومفضَّل — تحلّه العقدة عند البدء عبر محلِّل
نظام التشغيل نفسه، فيبقى العنقود رغم تغيّر IP نقطة الدخول. أبقِ لاحقة
/p2p/<peer id>: DNS غير مصادَق عليه، ومعرّف القرين هو ما يجعل سجلًا
مختطَفًا يفشل المصافحة بدلًا من أن يصير بصمت قرينك الوحيد.
نقطة دخول لن تُحلَّل توقف العقدة عند البدء بدلًا من تخطّيها. عقدة تُسقط واحدةً بصمت ستأتي بلا أقران إطلاقًا وتبدو صحيحةً تمامًا بينما لا تتحدث مع أحد — وهو تحديدًا الفشل الذي افتتح به هذا القسم.
ابدأ بلا أي نقطة دخول وتقول العقدة ذلك، عند WARN. ذلك صحيح لأول عقدة
في عنقود جديد وخاطئ لكل من عداها.
ماذا تعلن عقدتك عن نفسها
كل عنوان تعرف العقدة أنها تستمع عليه، ناقص بدل الربط. 0.0.0.0 و::
تعليمات استماع تعني «كل واجهة محلية»، لا وِجهات — ولأن
--gossip-bind-address افتراضيًا ذلك بالضبط، فإعلانه بلا ترشيح هو
تحديدًا الخلل الذي يترك الأقران بلا ما يطلبونه.
نطاقات loopback والخاصة لا تُرشَّح عمدًا. عمليات على مضيف واحد تصل بعضها بعضًا عبر loopback، وعنقود docker-compose أو شبكة محلية يصل أقرانه بعنوان خاص فقط، وعنقود المضيف الواحد نشرٌ حقيقي لا أثر اختبار.
خلف NAT، في حاوية، أو على مضيف سحابي بـ IP معيَّن
العنوان الذي تربطه عقدتك ليس العنوان الذي يستطيع الأقران بلوغها عنده، ولا تستطيع العقدة استنتاج العام. ليس ذلك إغفالًا — فبالبناء، شيء وراء NAT فقط يستطيع رصد العنوان العام. لذا يعلنه المشغّل:
--external-addr /ip4/203.0.113.7/udp/4001/quic-v1
قابل للتكرار. تُعلَن العناوين المصرَّح بها قبل المربوطة، فقرين يجرّبها
بالترتيب يتصل من أول محاولة بدلًا من نفاد المهلة على 172.17.0.2. تُعلَن
العناوين المربوطة أيضًا — إسقاطها سيصلح الحالة البعيدة بكسر المحلية.
احذف العلم إن كانت عقدتك على واجهة عامة فعلًا. فعنوانها المربوط هو أصلًا عنوانها العام.
سؤال عقدة عمّا تعرفه
curl -s -X POST http://localhost:7080/rpc -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"getPeers","params":{}}' | jq
{
"self_peer_id": "12D3KooWK9hQ7TwbfvFiaAxUbRFCkdhS7iEpAJDnewNL1anyREQ1",
"announced_addresses": ["/ip4/203.0.113.7/udp/4001/quic-v1"],
"peers": [
{
"peer_id": "12D3KooW...",
"addresses": ["/ip4/198.51.100.4/udp/4001/quic-v1"],
"node_version": "openfiat/0.1.0",
"supported_ofs": [1000, 1100, 1200, 1300, 1400, 1500, 2000, 2100, 2200, 2300, 2400, 3000, 4000, 4300, 6000, 7000, 8200],
"roles": ["MerchantGateway", "OracleProvider", "NotificationGateway", "RiskIntelligenceProvider"],
"last_seen": 1753800000000,
"latency_ms": 42,
"successes": 17,
"failures": 0
}
]
}
ثلاثة أمور تستحق المعرفة عن تلك الاستجابة.
self_peer_id هو صيغة 12D3Koo… التي تدخل في نقطة الدخول التي تنشرها
لمشغّلين آخرين. عقدة لا تستطيع ذكر معرّف قرينها لا يمكن الانضمام إليها،
وتجميعه من سطر سجل هو كيف يُكتَب خطأً.
announced_addresses هو ما تخبر الأقران أن يطلبوه، بالترتيب الذي
سيجرّبونه به. «عقدتي لا تعلن شيئًا» كانت غير مرئية من الخارج ما دامت
صحيحة، ومشغّل يفحص ما إن سرى مفعول --external-addr عنده لا مكان آخر
لينظر فيه.
successes وfailures هما عدّ العقدة نفسها للتبادلات مع ذلك القرين.
عمدًا لا نسبة تشغيل ولا درجة صحة: طيّ العدّين في رقم سيعرض التجربة
المحلية لعقدة واحدة كحكم على مستوى الشبكة، وعقدتان أمينتان قد تختلفان على
كليهما.