नोड चलाना
zycordd के लिए ऑपरेटर की मार्गदर्शिका। वह जो प्रोटोकॉल बोलता है वह वायर विशिष्टि है; यह पृष्ठ उसे चलाने के बारे में है।
एक पंक्ति में#
zycordd --devnet --dir ./devnet
यह एक पूर्ण नोड है: वह genesis से हर ब्लॉक का सत्यापन करता है, पीयर्स को सेवा देता है, और
127.0.0.1:9420 पर केवल-पठन RPC का उत्तर देता है। जो नेटवर्क वास्तव में चल रहा है उससे
जुड़ने के लिए सार्वजनिक testnet देखें — और ध्यान रखें कि उसके लिए
-randomx बाइनरी चाहिए।
नोड के पास क्या नहीं है#
नोड प्रक्रिया में कभी कोई कुंजी सामग्री नहीं होती। वह न कोई seed लेता है, न कोई
passphrase, न कोई कुंजी फ़ाइल। हस्ताक्षर zcd में होते हैं, और नोड का इकलौता लेखन
एंडपॉइंट — /submit — कोई अधिकार नहीं देता: जमा किया गया सर्टिफिकेट ठीक
वैसे ही सत्यापित होता है जैसे किसी अजनबी से आया हुआ।
यहाँ कोई विशेषाधिकार-प्राप्त एंडपॉइंट भी नहीं है, क्योंकि विशेषाधिकार देने को कुछ है ही नहीं। कोई कुंजी न रोक सकती है, न अपग्रेड कर सकती है, न सेंसर, न नई मुद्रा गढ़ सकती है, इसलिए उजागर करने को कोई कॉल नहीं है।
सीमक transport पीयर के आधार पर चलता है, कभी X-Forwarded-For के आधार पर नहीं: जो सीमक
क्लाइंट के सेट किए हेडर पर भरोसा करता है वह ऐसा सीमक है जिसे क्लाइंट बंद कर देता है। इसलिए प्रॉक्सी के पीछे हर
अनुरोध प्रॉक्सी के पते के साथ आता है, जिससे प्रति-क्लाइंट सीमा प्रति-क्लाइंट रहना बंद कर देती है और सबके लिए
एक साथ प्रति मिनट 600 की एक साझा बाल्टी बन जाती है — और एक अकेला कॉल करने वाला उसे सबके लिए ख़ाली कर
सकता है। यह दलील से कोई सीमा न होने से भी बुरा है, और प्रतिक्रिया में कुछ भी यह नहीं बताता: कॉल करने वालों को
सादा 429 मिलता है, चाहे वजह वे ख़ुद हों या कोई और।
केवल-पठन सतह#
जो कुछ भी चेन को बाहर से देखता है — कोई explorer, कोई मॉनिटर, कोई indexer — वह उसे यहीं से पढ़ता है। नोड बाइट्स सौंपता है, व्याख्या कभी नहीं।
| एंडपॉइंट | क्या बताता है |
|---|---|
/status, /head | शीर्ष की पहचान, ऊँचाई, state root |
/block?height=N या ?id=0x… | एक ब्लॉक JSON के रूप में, canonical, orphaned और confirmations सहित |
/block?…&format=ssz | वही ब्लॉक कैनोनिकल SSZ बाइट्स के रूप में, application/octet-stream |
/params | सक्रिय पैरामीटर सेट और उसका consensus root |
/cell, /balance | शीर्ष की स्टेट |
/fees | आधार शुल्क, और लागू लोचदार सीमाएँ |
/mempool | पूल के गणक; ?limit=N से 1000 तक लंबित id जुड़ती हैं, सबसे कम पहले |
/network, /metrics | कनेक्शन का आकार और गणक |
/submit | इकलौता लेखन, और वह कुछ नहीं देता |
श्वेतपत्र §8.1 ब्लॉक की बाइट, gas और सर्टिफिकेट सीमाओं को T का फलन बनाता है, यानी
अनुक्रमिक लक्ष्य का, और T वह consensus स्टेट है जिसे epoch नियंत्रक हिलाता है।
इसलिए /params केवल genesis के मान ढोता है —
block_byte_limit_genesis और उसके साथी — जो बताते हैं कि T कहाँ से शुरू होता है और
घटकर किस फ़र्श तक लौट सकता है, कभी वह सीमा नहीं जो लागू है। वे अंक हमेशा असली बने रहते हैं,
इसलिए उनमें से किसी को "ब्लॉक आकार सीमा" मानकर पढ़ना चुपचाप ग़लत होता है, और 2.5 MB के genesis मान तथा
8 MB की क्षमता-दीवार के बीच की पूरी दूरी तक ग़लत हो सकता है। /fees जीवित
T और उससे निकली चार सीमाएँ परोसता है, ताकि व्युत्पत्ति पर भरोसा करने के बजाय उसे जाँचा जा सके।
बाइट्स क्यों मायने रखते हैं#
blake3("zcd/block/v1" ‖ header_bytes) ही ब्लॉक id है, इसलिए जो प्रेक्षक अपने को
परोसी गई चीज़ से id दोबारा निकालता है वह या तो नेटवर्क से सहमत होता है या तुरंत पता लगा लेता है। प्रति-सर्टिफिकेट
परिणाम भी इसी तरह मिलते हैं: कोई सर्टिफिकेट लागू हुआ, skip होकर बिल हुआ, या drop हुआ, यह fold के
भीतर गणना होती है और कभी संग्रहीत नहीं होती, क्योंकि मेमोरी में रहने वाले भंडार में प्रति
सर्टिफिकेट एक पंक्ति, हमेशा के लिए, ऐसी चीज़ नहीं जिसे ढोने को नोड से कहा जा सके। जो प्रेक्षक परिणाम चाहता है
वह ब्लॉक को ख़ुद fold कर लेता है।
यहाँ क्या नहीं है, और न होगा#
- स्टेट पर कोई मनमाना पुनरावर्तन नहीं। न कोई पता सूची, न उपसर्ग स्कैन, न कोई rich list।
- कोई ऐतिहासिक स्टेट नहीं।
/cellऔर/balanceशीर्ष पढ़ते हैं; "ऊँचाई H पर शेष" का मतलब है सुरक्षित रखा गया इतिहास, जो नोड रखता ही नहीं। - कोई admin, reindex या debug कॉल नहीं, क्योंकि विशेषाधिकार देने को कुछ है ही नहीं।
समुच्चयन उसका काम है जो देख रहा है, जो उसे अपने डेटाबेस में लेते समय एक ही बार गणना कर ले।
स्थिति कोड#
पठन GET और HEAD का उत्तर देते हैं और बाक़ी हर क्रिया को
405 से मना कर देते हैं। सुगठित प्रश्न जिसका उत्तर नकारात्मक हो — ऐसी ऊँचाई जहाँ चेन नहीं
पहुँची, कोई अज्ञात id, किसी reorg में हारे ब्लॉक की बॉडी — वह 404 है; केवल
ख़राब गठन वाला अनुरोध 400 है। जो रिकॉर्ड नोड ने लिखा और अब वापस नहीं पढ़ सकता वह
500 है, 400 नहीं: दोष नोड की डिस्क का है, और कॉल करने वाले को यह बताना कि उसका
अनुरोध ख़राब था उसे ऐसा अनुरोध दोबारा भेजना छोड़ने पर उकसाता है जो हमेशा सुगठित था। किसी poller को अनुपस्थिति
और त्रुटि में, या अपने बग और नोड के बग में, फ़र्क़ करने के लिए कभी गद्य नहीं पढ़ना चाहिए।
Reorg#
ऊँचाई से खोज केवल canonical चेन के लिए उत्तर देती है। जो ब्लॉक किसी reorg में हारता है वह अपना हेडर
रखता है और अपनी बॉडी खो देता है, इसलिए उसकी id अब भी हल होती है, orphaned चिह्नित होकर लौटती
है, और fork बिंदु तक की parent कड़ी भी ढोती है — और यही id से खोज को इकलौता
reorg-सुरक्षित रास्ता बनाता है।
पहुँच-योग्यता, और यह दिखने से ज़्यादा क्यों मायने रखती है#
Zycord NAT traversal नहीं करता। जिस नोड पर --listen किसी पहुँच-योग्य पोर्ट पर हो वह ऐसी जगह
है जहाँ से दूसरे बूटस्ट्रैप कर सकें, और ऐसे नोड का अनुपात ही वह मिथ्याकरणीय शर्त है जिस पर
traversal न करने का पूरा निर्णय टिका है।
# periphery: nothing to configure
zycordd --testnet --dir ./testnet
# core: bind a port, and make sure it is actually reachable
zycordd --testnet --dir ./testnet \
--listen 0.0.0.0:9421 --advertise <public-address>:9421
--listen
0.0.0.0:9421 पीछे हटकर --listen पर चला जाता है, इसलिए बिना
--advertise के --advertise 0.0.0.0:9421 प्रकाशित करता है, जिसे
कोई डायल नहीं कर सकता। ग़लत पता पीयर आदान-प्रदान से फैलता है और उसे आज़माने वाले हर नोड को एक डायल की पड़ता
है। अगर आप कोई पोर्ट फ़ॉरवर्ड नहीं कर सकते, तो --listen बंद रहने दें और परिधि पर रहें।
यह जाँचना कि काम हुआ या नहीं#
curl -s localhost:9420/network
{"enabled":true,"peers":8,"listening":true,"inbound":5,"outbound":3,"reachable":true}
नोड के कुछ मिनट चलते रहने के बाद listening: true के साथ inbound: 0
का मतलब है कि पोर्ट वास्तव में पहुँच-योग्य नहीं है: प्रक्रिया बँधी हुई है और इंतज़ार कर रही है, और कुछ आ नहीं
रहा। बाक़ी हर दृश्य में यह स्वस्थ दिखता है, और इसीलिए यह एंडपॉइंट मौजूद है।
फ़ाइल से बूटस्ट्रैप पते#
zycordd --testnet --dir ./testnet --peers-file peers.txt
प्रति पंक्ति एक पता; # टिप्पणियाँ और ख़ाली पंक्तियाँ अनदेखी की जाती हैं, और सूची नेटवर्क के
अंतर्निहित seeds के साथ मिला दी जाती है। --peers वही चीज़ अल्पविराम से अलग किए तर्क के रूप में
लेता है, और --no-seeds अंतर्निहित seeds हटा देता है और बाक़ी दोनों रखता है।
वॉलेट इंटरफ़ेस, ssh टनल पर#
नोड कोई कुंजी नहीं रखता और कभी नहीं रखेगा। वॉलेट एक अलग प्रक्रिया है, और सर्वर पर वह है
zcd ui:
zcd ui --key wallet.json --no-open
वह एक URL छापता है और उसे 127.0.0.1:9430 पर परोसता है। वह loopback से बँधता है और
बाक़ी सब मना कर देता है, और इसे बदलने के लिए कोई फ़्लैग नहीं है। उस listener के पीछे की प्रक्रिया
एक अनलॉक निजी कुंजी रखती है और URL में मौजूद bearer टोकन से प्रमाणीकरण करती है, जो ऐसे सॉकेट के लिए पर्याप्त
है जिसे केवल स्थानीय मशीन खोल सकती है और किसी और चीज़ के लिए पर्याप्त नहीं। कहीं और से उस तक पहुँचना ssh का
काम है, और ssh इसमें इससे बेहतर है:
# on your own machine
ssh -L 9430:127.0.0.1:9430 <host>
फिर सर्वर द्वारा छापा गया URL खोलें। टोकन URL के fragment में सवार होता है,
इसलिए वह न सर्वर तक पहुँचता है, न किसी लॉग तक, न किसी Referer हेडर तक — URL को वही रहस्य
मानें जो वह है। हर बार चलाने पर वह नया होता है, और Ctrl-C कुंजी मिटा देता है और सेवा रोक देता है।
फ़ॉरवर्ड का स्थानीय सिरा पोर्ट 9430 ही हो, यह ज़रूरी नहीं: इंटरफ़ेस Host हेडर में
होस्टनाम जाँचता है और जानबूझकर पोर्ट नहीं। होस्टनाम ही मायने रखता है — वही DNS rebinding
रोकता है, जो loopback पर चल रहे सर्वर के विरुद्ध असली हमला है, क्योंकि आपके ब्राउज़र का कोई भी पृष्ठ
127.0.0.1 पर अनुरोध भेज सकता है और इकलौती चीज़ जो वह गढ़ नहीं सकता वह है वह नाम जिस पर वह पहुँचा।
zcd ui के आगे कोई रिवर्स प्रॉक्सी न लगाएँऊपर नोड की RPC के बारे में दी गई सलाह ऐसी सतह के बारे में है जो कोई कुंजी नहीं रखती और कोई अधिकार नहीं देती। यह वाली एक कुंजी रखती है। इसे उजागर करने का कोई भी रूप अच्छा विचार नहीं है, और टनल की क़ीमत बस एक फ़्लैग है।
दो और रूप जानने लायक हैं:
zcd ui --lockedटर्मिनल में passphrase पूछे बिना शुरू होता है; उसके बजाय ब्राउज़र पूछता है। जब टर्मिनल साझा हो या उसका लॉग रखा जाता हो तब उपयोगी।zcd ui --lock-after 5mनिष्क्रियता पर लगने वाला लॉक छोटा कर देता है, जो कुंजी को उसकी जगह पर ही मिटा देता है — seed पर ऊपर से लिखा जाता है, उसे केवल छोड़ा नहीं जाता।
पीयर पहचान और गुमनामी#
नोड हर बार शुरू होने पर एक नई Ed25519 पीयर कुंजी बनाता है और उसे कभी डिस्क पर नहीं लिखता। वह किसी चीज़ से व्युत्पन्न नहीं होती — न आपके वॉलेट से, न किसी seed से, न मशीन की किसी और चीज़ से। दोबारा शुरू करने पर वह बदल जाती है।
अगर आप नोड इस तरह चला रहे हैं कि यह आपके लिए मायने रखता है, तो आपकी गुमनामी कुंजी से नहीं टूटती। वह पते से टूटती है। आपसे जुड़े ढाँचे पर चलाया गया bootstrap नोड एक ऐसा गुमनामी-भंजक है जिसे कितनी भी कुंजी-स्वच्छता ठीक नहीं करती।
डेटा डायरेक्टरी#
data/
chain/ blocks, state, and the write-ahead log
peers.json the persisted peer store
पीयर स्टोर जानबूझकर स्थायी रखा जाता है: जो नोड हर बार पुनः शुरू होने पर कोरी स्लेट से शुरू होता है वह हमलावर को उसे भरने का नया मौक़ा देता है। उसे हटाना सुरक्षित है पर उससे यह लाभ चला जाता है।
नोड किसी भी क्षण मार दिए जाने से बच जाता है — write-ahead लॉग इसी के लिए है, और इसे नेटवर्क अफ़रा-तफ़री के बीच नोड को बेतरतीब मारकर परखा जाता है। वह अपनी डेटा डायरेक्टरी को नीचे से बदल दिए जाने से नहीं बचता: शुरू होने पर वह state root दोबारा गणना करता है और संग्रहीत मान से असहमति होने पर चलने से मना कर देता है।
नेटवर्क चुनना#
| फ़्लैग | नेटवर्क | Chain id | इंजन |
|---|---|---|---|
| (कोई नहीं) | mainnet | 1 | randomx-v1 |
--testnet | सार्वजनिक testnet | 2 | randomx-v1 |
--devnet | स्थानीय devnet | 1337 | विकास इंजन |
पैरामीटर बाइनरी में जड़े होते हैं, किसी पथ से पढ़े नहीं जाते। किसी सार्वजनिक नेटवर्क के
हर सहभागी को वही बाइट ढोने होते हैं वरना वे एक नेटवर्क पर हैं ही नहीं, और --params से दी गई
फ़ाइल ऐसी फ़ाइल है जो खिसकती है। अलग नेटवर्क अलग नेटवर्क होता है: दोनों हैंडशेक पर ही अलग हो जाते हैं, और
ग़लत चेन रखने वाली डेटा डायरेक्टरी को चुपचाप मिलाने के बजाय शुरुआत में ही अस्वीकार कर दिया जाता है।
क्षतिग्रस्त डेटा डायरेक्टरी की मरम्मत#
zycordd में ऐसी डेटा डायरेक्टरी के लिए एक मरम्मत मार्ग है जिसके विरुद्ध नोड शुरू
होने से इनकार कर देता है। पहले नोड रोकें — zycordd repair --dir ./data डायरेक्टरी
लॉक लेता है और जब तक कोई नोड उसे पकड़े हो तब तक चलने से इनकार करता है — और फिर कुछ भी बदलने
से पहले --dry-run से पूछें कि हुआ क्या। केवल एक क्षति-श्रेणी वहीं ठीक होती है; बाक़ी का
उपाय फिर से sync करना है, और आपके पास कौन-सी है यह यही ड्राई रन बताता है।