ZYCORD दस्तावेज़
हिन्दी
Zycordदस्तावेज़वायर प्रोटोकॉल

वायर प्रोटोकॉल

Zycord नोड आपस में क्या कहते हैं, और वे नियम जो किसी पीयर प्रोटोकॉल को एम्प्लिफ़ायर बनने से रोकते हैं। यह मानक विशिष्टि की मार्गदर्शिका है, उसका विकल्प नहीं।

यह पृष्ठ एक मार्गदर्शिका है, विशिष्टि नहीं

विशिष्टि spec/ है: पैरामीटर फ़ाइलें और वेक्टर संग्रह। जहाँ यह पृष्ठ और ट्री असहमत हों, ट्री सही है — कोई कार्यान्वयन तब अनुरूप है जब वह genesis id दोबारा बनाए और वेक्टर पास कर ले, और यहाँ लिखी कोई बात इसे नहीं बदलती। आगे जो है वह इस बात का नक़्शा है कि आवश्यकताएँ कहाँ हैं।

ट्रांसपोर्ट#

TCP, फिर TLS 1.3। पीयर पहचान एक Ed25519 कुंजी है जो स्व-हस्ताक्षरित X.509 प्रमाणपत्र में ढोई जाती है, और दोनों पक्ष उसे प्रस्तुत करते हैं। प्रमाणपत्र श्रृंखलाओं का सत्यापन नहीं होता — यहाँ कोई प्रमाणपत्र प्राधिकारी नहीं है और उसके लिए गवाही देने को कुछ नहीं — इसलिए सत्यापन के लिए ठीक एक प्रमाणपत्र चाहिए, उसकी सार्वजनिक कुंजी का Ed25519 होना ज़रूरी है, और वही कुंजी पीयर की पहचान के रूप में निकाली जाती है।

जो गुण मिलता है वह है किसी कुंजी से चैनल का बंधन, प्राधिकार नहीं: TLS यह गारंटी देता है कि जिसने भी हैंडशेक पूरा किया उसके पास प्रस्तुत पहचान की निजी कुंजी है, और यह कि धारा को रास्ते में पढ़ा या बदला नहीं जा सकता। यह इस बारे में कुछ नहीं कहता कि वह पीयर ईमानदार है या नहीं। प्रोटोकॉल में कुछ भी पहचान के आधार पर अधिकार नहीं देता।

प्रमाणपत्र की वैधता तिथियाँ जानबूझकर वर्तमान समय के इर्द-गिर्द की खिड़की के बजाय नियत स्थिरांक हैं: सापेक्ष खिड़की प्रमाणपत्र की स्वीकृति को घड़ियों की सहमति पर निर्भर बना देती है, और जो नेटवर्क घड़ी के अंतर पर बँटता है वह ऐसे कारण से बँटता है जिसका consensus से कोई संबंध नहीं।

कार्यान्वयन को किसी अन्य परत की कुंजी को पीयर पहचान के रूप में दोबारा इस्तेमाल नहीं करना चाहिए। नोड हर बार शुरू होने पर एक नई कुंजी बनाता है और उसे कभी डिस्क पर नहीं लिखता।

फ़्रेमिंग#

offset  size  field
0       4     length   uint32, little-endian - payload length, excluding this header
4       1     kind     uint8  - see below
5       n     payload
  • length को किसी भी आवंटन से पहले MaxMessageBytes = 8 MiB के विरुद्ध, और अपने प्रकार की अपनी सीमा के विरुद्ध, जाँचा जाना चाहिए। जो प्राप्तकर्ता दावा की गई लंबाई पर आवंटन कर देता है उसमें एक दूरस्थ मेमोरी-क्षय बग है, चाहे आगे कुछ भी हो।
  • kind 0 अस्वीकार किया जाता है। किसी बिल्ड को ज्ञात सबसे ऊँचे प्रकार से ऊपर का प्रकार वह है जिसे किसी नए बिल्ड ने जोड़ा है: कनेक्शन बंद करने के बजाय उसका payload MaxUnknownPayloadBytes = 64 KiB के भीतर, प्रति पीयर एक सीमित दर पर, पढ़कर त्याग दिया जाता है। उस दर से आगे उसे अत्यधिक अनुरोध के रूप में अंकित किया जाता है।

संदेश प्रकार#

माननामदिशापेलोड
1helloदोनों, सबसे पहलेहैंडशेक
2certificategossipssz(Certificate)
3block-announcegossipहेडर और क्रमबद्ध सर्टिफिकेट exemplar हैश
4get-blockअनुरोध32-बाइट ब्लॉक id ‖ u32 chunk इंडेक्स
5blockप्रतिक्रियाssz(Block) का एक chunk
6get-headersअनुरोधLocator
7headersप्रतिक्रियाहेडर शृंखला
8get-peersअनुरोधख़ाली
9peersप्रतिक्रियापता सूची
10service-cardgossip, capability के अनुसारएक हस्ताक्षरित सेवा घोषणा
11block-unavailableप्रतिक्रियाब्लॉक id ‖ कारण: भेजने वाले के body floor से नीचे, या कभी रखा ही नहीं गया
12open-intentgossip, capability के अनुसारforced path के लिए एक open intent

किसी consensus वस्तु का कोई नेटवर्क-विशिष्ट एन्कोडिंग नहीं है, और यही "जो मुझे मिला उसकी id" को एक जाँचने योग्य कथन बनाता है।

प्रोटोकॉल संस्करण 3 है, और हैंडशेक के लिए सटीक मिलान आवश्यक है। hello इसे नेटवर्क id के साथ ढोता है — यानी genesis id, जो हर consensus पैरामीटर के प्रति प्रतिबद्ध है — साथ ही भेजने वाले की ऊँचाई और work, उसका listen पता, एक capability शब्द, और उसका body floor, यानी वह सबसे निचली ऊँचाई जिसका ब्लॉक body वह परोसता है। जो प्रकार किसी capability से नियंत्रित है वह कभी ऐसे पीयर को नहीं भेजा जाता जिसने उसका विज्ञापन न किया हो, और जिस capability बिट को कोई बिल्ड परिभाषित नहीं करता उसे अनदेखा किया जाता है, कभी अस्वीकार नहीं। जिस get-block को प्राप्तकर्ता नहीं परोसेगा उसका उत्तर अनुरोधकर्ता की समय-सीमा पर छोड़ देने के बजाय block-unavailable से दिया जाता है।

open-intent forced path का एकमात्र ट्रैफ़िक है: किसी उपयोगकर्ता का ऐसा intent जिसमें किसी sequencer का नाम न हो, जिसे कोई भी producer अपने ब्लॉक के अंत में निष्पादित कर सकता है। जो forced सर्टिफिकेट बनता है उसे कभी सर्टिफिकेट के रूप में gossip नहीं किया जाता; वह ब्लॉक में जन्म लेता है, और हर नोड उसे वहीं जाँचता है।

हर इनबाउंड संदेश की क़ीमत उसका भेजने वाला चुकाता है#

विशिष्टि का यही हिस्सा पूरा पढ़ने लायक सबसे ज़्यादा है, क्योंकि यहीं पीयर प्रोटोकॉल आमतौर पर रिसते हैं। इसे दो नियम संचालित करते हैं।

लागत-क्रम का नियम#

काम लागत के बढ़ते क्रम में किया जाता है, और संदेश का हिसाब उसके बाद आने वाले महँगे चरण से पहले लगाया जाता है। जो प्राप्तकर्ता पहले सत्यापन करता है और अंक बाद में देता है उसने एक एम्प्लिफ़ायर बना लिया है: जो भेजने में सस्ता है वही जाँचने में महँगा है।

हर परिणाम की क़ीमत तय है#

कोई बिना नाम वाला Free नहीं है। हर संदेश प्रकार, उसके हर संभावित परिणाम के साथ, एक तालिका में अंक सहित दर्ज है। जो परिणाम बिना हिसाब लगे तालिका से फिसल जाए वही वह खामी है जिसे रोकने के लिए यह नियम मौजूद है — और व्यवहार में उस तक बिना-क़ीमत वाली पंक्ति से भी सँकरे रास्तों से पहुँचा गया है: एक कार्यान्वयन ने ख़राब फ़्रेम को उसके इकलौते अंकदाता से हटा दिया, जिससे वह फ़्रेम तब तक मुफ़्त रहा जब तक कोई अनुरोध बकाया था, और किसी तालिका में एक भी पंक्ति नहीं जुड़ी।

सेवा देने का हिसाब भी लगता है। ब्लॉक बाइट्स ही वह इकलौती प्रतिक्रिया है जो उसे माँगने वाले अनुरोध से परिमाण की कोटियों में बड़ी होती है, इसलिए वे अनुरोध की गिनती के ऊपर अपना अलग बाइट बजट ढोते हैं।

अंक पीयर की पहचान से जुड़ते हैं: एक अमान्य संदेश की क़ीमत 20 है, एक प्रोटोकॉल उल्लंघन की 50, एक न परोसे गए body की 10 और एक अत्यधिक अनुरोध की 5; एक उपयोगी संदेश 1 कमाता है, और कोई पीयर −100 पर प्रतिबंधित कर दिया जाता है। महँगी जाँचें — key epochs और proof-of-work मूल्यांकन — प्रति पीयर बजट में बँधी हैं और ब्लॉक के उपयोगी साबित होने पर लौटा दी जाती हैं, ताकि कहीं न ले जाने वाली घोषणा किसी नोड से work न घिसवा सके।

रिले और सिंक#

रिले हैश-प्रथम है। सर्टिफिकेट अपने आप gossip होते हैं और पहुँचने पर उनकी वैधता की जाँच होती है, स्टेट के बिना और समानांतर में; किसी रिले को स्पैम छाँटने के लिए किसी स्टेट की ज़रूरत नहीं। ब्लॉक एक हेडर और क्रमबद्ध exemplar हैश के रूप में यात्रा करते हैं, प्राप्तकर्ता के mempool के विरुद्ध, और प्राप्तकर्ता कोई भी body लाने से पहले हेडर के work का सत्यापन करता है। body 4 MiB के chunks में यात्रा करता है, हर chunk अपना अलग अनुरोध और उत्तर, ताकि फ़्रेम सीमा किसी संदेश को बाँधे और कभी किसी ब्लॉक को नहीं। bodies चेन डेटा हैं: कोई ब्लॉक तभी valid है जब उसके bodies प्राप्त किए जा सकें, और जो नोड छँटाई (prune) करता है वह हैंडशेक में बताता है कि उसका floor कहाँ है।

Sync सत्यापित work के आधार पर चुनता है। Bodies लाए जाने से पहले headers को एक चेन के रूप में validate किया जाता है, और एक नोड उस peer को पसंद करता है जिसके headers ने सबसे अधिक work सिद्ध किया है, उसकी तुलना में जो सबसे बड़ी ऊँचाई का दावा करता है। एक प्रतिस्पर्धी शाखा केवल तब अपनाई जाती है जब वह 1,024-ब्लॉक undo horizon के भीतर जुड़ती है और अधिक work रखती है। रिलीज़ में pinned checkpoints, जो केवल कम से कम एक epoch पुराने ब्लॉकों के लिए स्वीकार किए जाते हैं, किसी विरोधी चेन को अस्वीकार करते हैं चाहे वह कितनी भी भारी हो; एक ऑपरेटर flag द्वारा एक pin जोड़ सकता है। Era 2 में proof of stake पर switch से, चुनाव इसके बजाय लंबाई के आधार पर होता है: जो चेन सबसे अधिक slots घेरती है वह जीतती है (श्वेतपत्र §11), और undo horizon और pins बने रहते हैं, उन कुंजियों से पुनर्लेखन के विरुद्ध बचाव के रूप में जो तब से unbond हो चुकी हैं।

कनेक्शन प्रबंधन, और eclipse बचाव#

यह अनुभाग किसी भी अन्य से ज़्यादा मापी हुई विफलताएँ ढोता है, और नीचे दी गई हर अपेक्षा इसलिए मौजूद है क्योंकि उसके बिना बना कोई कार्यान्वयन किसी माप में eclipse हो गया था।

  • बाहर जाने वाले लक्ष्य पते की विविधता के साथ चुने जाने चाहिए, ताकि कोई एक होस्टिंग रेंज किसी नोड के आउटबाउंड slot न भर सके।
  • बाहर जाने वाले लक्ष्यों की प्रति gossip स्रोत सीमा भी होनी चाहिए। अकेली पता-विविधता काफ़ी नहीं है, और इसका कारण निर्णय नहीं बल्कि अंकगणित है: पता समूह उस पते का गुण है जिसका हमलावर स्वामी है, पर जो पता कोई पीयर दावा करता है वह उसके गढ़े हुए बाइट हैं, और कोई भी चार बाइट एक valid IPv4 होस्ट हैं। जिस हमलावर के पास एक भी पता न हो वह एक फ़्रेम की क़ीमत पर प्रति स्ट्रिंग एक नया विविधता समूह गढ़ लेता है। जो वह नहीं गढ़ सकता वह है वह कनेक्शन जिस पर दावा आया।
  • जिस सॉकेट पर कोई इनबाउंड कनेक्शन आया वह आउटबाउंड लक्ष्य नहीं बनना चाहिए। वह पीयर का स्रोत पता है — एक क्षणिक पोर्ट जो उसके OS ने चुना, ऐसा कुछ नहीं जिस पर वह सुनता हो — इसलिए उसे डायल करने में ख़र्च हुआ slot एक ऐसे पते पर ख़र्च हुआ slot है जो उत्तर दे ही नहीं सकता।
  • दोनों सीमाएँ उन कनेक्शनों के विरुद्ध गिनी जानी चाहिए जो नोड थामे हुए है, न कि किसी एक चयन कॉल के विरुद्ध। वरना जो डायल लूप पहले से जुड़े पीयर को छोड़ देता है वह हर दौर में दोनों बजट फिर से पूरे भर देता है, और सीमा हमलावर को बाँधने के बजाय प्रति छूट एक दौर भर टालती है। मापा गया: एक ही बताने वाले ने चार दौरों में 8 में से पहले 2, फिर 4, फिर 6, फिर 8 आउटबाउंड slot ले लिए।
  • पीयर स्टोर स्थायी होना चाहिए, और सीमित होना चाहिए। जो नोड हर बार पुनः शुरू होने पर ख़ाली शुरू होता है वह हमलावर को हर बार नया मौक़ा देता है; और जो हमलावर की सूची के साथ शुरू होता है वह उसे वही मौक़ा स्थायी रूप से दे देता है।
  • सीमित स्टोर को किसी सुगठित पते को इसलिए मना नहीं करना चाहिए कि वह भरा हुआ है; उसे उसके लिए जगह ख़ाली करनी चाहिए। कभी संपर्क न किया गया ईमानदार पता कभी संपर्क न किए गए गढ़े हुए पते से बेहतर नहीं होता, इसलिए जो हमलावर स्टोर पहले भर देता है वह उसे बाद में दी गई हर चीज़ के लिए बंद कर देता है — ऑपरेटर की अपनी बूटस्ट्रैप सूची समेत।
  • निष्कासन क्या चुनता है यह इस बात से ज़्यादा मायने रखता है कि वह होता है। "सबसे बड़ी आबादी से शिकार लो" ऐसा पढ़ा जाता है मानो बाढ़ ख़ुद को ही विस्थापित करती है, और यह तभी तक सच है जब तक बाढ़ स्टोर की सबसे बड़ी चीज़ हो। जो नोड एक मददगार पीयर से बूटस्ट्रैप हुआ हो, उस पर सबसे बड़ी आबादी उसी पीयर की पता-पुस्तिका है। इसी क्रम वाले कार्यान्वयन पर मापा गया: एक ही स्रोत से आए 200 गढ़े हुए पतों ने 200 ईमानदार पते हटा दिए, और हमलावर को कोई क़ीमत नहीं पड़ी।
  • अभेद्य प्रविष्टियों के बीच अंतिम बराबरी-भंजक ऐसा कुछ नहीं होना चाहिए जिसे gossip करने वाला पीयर चुनता हो — पता भी नहीं — और यह चयन पर ठीक वैसे ही लागू होता है जैसे निष्कासन पर। जिस कार्यान्वयन का चयनकर्ता आख़िर में पता स्ट्रिंग पर आ गिरा उस पर मापा गया: 8 ईमानदार पतों के मुक़ाबले 8 गढ़े हुए पतों ने 8 में से 8 गढ़े हुए लौटाए, और दस दौरों में शून्य ईमानदार आउटबाउंड कनेक्शन।

जानबूझकर क्या अनुपस्थित है#

अनुपस्थितक्यों
NAT traversalलागत बता दी गई है और दोबारा खोलने की शर्त मान लेने के बजाय मापी जाती है: सार्वजनिक testnet पर dialable नोड का अनुपात इस निर्णय को दोबारा खोलने की पहली शर्त है।
संपीड़नहमलावर के नियंत्रण वाली धारा पर लगा compressor एक हमला-सतह है, और वह भी ऐसी बैंडविड्थ बचत के लिए जिसकी ज़रूरत किसी ने मापी ही नहीं।
संदेश-स्तरीय हस्ताक्षरट्रांसपोर्ट चैनल को प्रमाणित करता है; consensus वस्तुएँ अपने हस्ताक्षर ख़ुद ढोती हैं। तीसरी परत relay को प्रमाणित करती, और किसी निर्णय की उस पर निर्भरता नहीं है।
अनुरोध idअनुरोध और प्रतिक्रिया कनेक्शन और क्रम से मिलाए जाते हैं, इसलिए sync अपने ही कनेक्शन पर चलता है — जिससे एक स्टेट मशीन हट जाती है। जहाँ पीयर dialable न हो, वहाँ sync किसी मौजूदा gossip कनेक्शन पर चल सकता है और तब उसे प्रतिक्रियाएँ सामग्री से मिलानी होंगी।
संस्करण पर बातचीतहैंडशेक के लिए सटीक प्रोटोकॉल संस्करण आवश्यक है और बेमेल होने पर कनेक्शन टूट जाता है। जो संस्करण बढ़ाए बिना विकसित होता है वह संकीर्ण और सीमित है: capability बिट के पीछे एक नया संदेश प्रकार, जिसे पुराना बिल्ड 64 KiB के भीतर सीमित दर पर पढ़कर त्याग देता है।

सर्टिफिकेट id किसे शामिल नहीं करती#

यहाँ दोबारा कहने लायक है क्योंकि इससे एक relay नियम तय होता है। किसी सर्टिफिकेट की id उसी के प्रति प्रतिबद्ध होती है जिसे वह अधिकृत करता है, कभी उसके प्रति नहीं जिसे वह केवल प्रदर्शित करता है, इसलिए हस्ताक्षर id के preimage से बाहर रहते हैं। इससे साक्ष्य ऐसी चीज़ बन जाता है जिसे रास्ते में कोई भी बदल सकता है: एक सर्टिफिकेट लो, उसके हस्ताक्षर की जगह कचरा रख दो, और आगे बढ़ा दो — वही id, पर अब अमान्य exemplar।

दो नियम इसे बंद करते हैं। एक ब्लॉक उस साक्ष्य के प्रति प्रतिबद्ध होता है जिसे वह ढोता है, id के बजाय exemplar हैश पर बने एक root के ज़रिए। और relay exemplar से निपटता है, id से नहीं: जो नोड ऐसा exemplar पाता है जिसका साक्ष्य सत्यापन में विफल हो, वह उसी exemplar को id के प्रति बिना पूर्वाग्रह के त्याग देता है — id न चिह्नित होती है, न अमान्य के रूप में कैश होती है, और बाद में आया जो exemplar सत्यापित हो जाए वह सामान्य रूप से relay होता है। बिगाड़ी गई प्रति बिगाड़ने वाले को उसे भेजने की बैंडविड्थ की पड़ती है और सर्टिफिकेट को कुछ नहीं।

इसे शून्य से लागू करना#

जो स्वतंत्र कार्यान्वयन golden vectors पास कर ले वह एक पीयर है, fork नहीं — इसे इस तरह निर्दिष्ट करने का पूरा मक़सद यही है। consensus वस्तुओं के लिए spec/README.md से शुरू करें, और फिर अपने काम की जाँच zcd vectors से करें।