OUT_OF_ENERGY: TRON की वह ग़लती जो फ़ीस ख़र्च कर देती है और भेजती कुछ नहीं
एक USDT ट्रांसफ़र निकलता है, वॉलेट पर फ़ीस कटी हुई दिखती है, और प्राप्तकर्ता के पास कुछ नहीं पहुँचता। लेन-देन किसी ब्लॉक में है — उसे लौटाया नहीं गया और कोई नोड बैठा भी नहीं था — और जहाँ पूरे हुए ट्रांसफ़र पर SUCCESS लिखा होता है, वहाँ इस पर OUT_OF_ENERGY लिखा है। TRON पर इस ग़लती का मतलब वही है जो वह कहती है: कॉल बीच रास्ते में ऊर्जा ख़त्म कर बैठा और रुक गया। यहाँ उसका तंत्र है, वे तीन रास्ते जिनसे भुगतान का काम उसमें जा गिरता है, और उपाय — सबसे तेज़ वाले से लेकर उस वाले तक जो सचमुच सबसे कम में पड़ता है।
नतीजा असल में कहता क्या है
USDT भेजना एक स्मार्ट-कॉन्ट्रैक्ट में किया गया कॉल है, और TRON पर अनुबंध चलने का हिसाब किसी एकमुश्त फ़ीस से नहीं, ऊर्जा में रखा जाता है (ऊर्जा है क्या)। पहले भेजने वाले की अपनी ऊर्जा ख़र्च होती है। जब वह पूरे कॉल के लिए कम पड़ती है, नेटवर्क वहीं नहीं रुकता — बची हुई ज़रूरत वह भेजने वाले का TRX जलाकर ख़रीद लेता है, प्रोटोकॉल की दर पर, हर इकाई के लिए 100 sun, पर सिर्फ़ उतनी दूर तक जितनी उस लेन-देन का अपना fee_limit इजाज़त देता है। वह फ़ील्ड कोई फ़ीस नहीं है जो कोई वसूलता हो। वह इस बात की छत है कि यह एक कॉल भेजने वाले का कितना TRX जला सकता है।
छत तक पहुँच जाइए और कॉल अधूरा हो, तो चलना वहीं रुक जाता है। उसने अब तक जो भी बदला था वह सब पलट दिया जाता है, इसलिए कोई टोकन नहीं हिलता, और नेटवर्क अपना फ़ैसला लेन-देन पर ठीक उसी जगह लिख देता है जहाँ पूरे हुए कॉल पर SUCCESS होता। वही फ़ैसला वह शब्द है जो कोई एक्सप्लोरर नाकाम लेन-देन के आगे दिखाता है, और वही फ़ील्ड है जिसे नोड contractRet के रूप में लौटाता है। लेन-देन के बारे में यह कहीं नहीं लिखा कि वह नेटवर्क तक पहुँच ही न पाया हो। वह नेटवर्क तक पहुँचा और तब तक चला, जब तक उसके लिए पैसा था।
TRX दोनों हाल में ख़र्च होता है
पलटाव ट्रांसफ़र को रद्द कर देता है। वह जलने को रद्द नहीं करता: जो ऊर्जा ख़र्च हो गई उसका पैसा दिया जा चुका है, और भेजने वाले के पास उतना कम रह जाता है जितना छत तक पहुँचने की उस कोशिश ने जला दिया — कोई टोकन हिला नहीं, और हाथ में एक लेन-देन हैश है जिसे मिलान की कोई स्क्रिप्ट ख़ुशी-ख़ुशी भुगतान मान लेगी।
इसी से आदतन दोबारा भेजना सबसे महँगा क़दम बन जाता है। वही ट्रांसफ़र उसी छत के साथ उतना ही TRX उसी नतीजे के लिए ख़र्च करता है, और भुगतान का जो लूप अपनी नाकामियों पर अपने आप दोबारा कोशिश करता है वह किसी आदमी के नतीजा पढ़ने से पहले यह कई बार कर चुका होता है। भुगतान करने वाली टीम जिन नाकामियों से टकराती है उनमें से ज़्यादातर चुपचाप पैसा ले जाती हैं। यह वाली शोर मचाकर ले जाती है और फिर भी छूट जाती है, क्योंकि वॉलेट फ़ीस दिखा रहा होता है और पैसा कहीं नहीं होता।
कल तक चलती रही छत आज क्यों रुक जाती है
प्राप्तकर्ता बदल गया और छत नहीं बदली। भुगतान का काम सबसे पहले इसी से टकराता है। जिस पते पर पहले से USDT है उस पर ट्रांसफ़र लगभग 65,000 इकाई ऊर्जा लेता है; जिसने कभी USDT रखा ही नहीं, उस पर ट्रांसफ़र को पहले प्राप्तकर्ता का टोकन खाता भी बनाना पड़ता है, और वह लगभग 131,000 है — उतने ही पैसे को हिलाने के लिए दुगनी भूख। पहले वाले पर प्रोटोकॉल की दर से जलने का ख़र्च 6.5 TRX है, दूसरे पर 13.1 TRX। आम हालत के नाप की छत किसी नए ग्राहक को पहली बार पैसा भेजते ही आधी पड़ जाती है, और बैच में कुछ अलग दिखता भी नहीं: यह प्राप्तकर्ता का गुण है, ट्रांसफ़र का नहीं।
ऊर्जा थी और अब नहीं है। ऊर्जा एक तय अवधि के लिए एक तय मात्रा में सौंपी जाती है, यह कोई सब्सक्रिप्शन नहीं। पहला ट्रांसफ़र जो ख़र्च कर देता है वह दूसरे के लिए बचता नहीं, और अवधि ख़त्म होते ही बाक़ी अपने मालिक के पास लौट जाती है। जिस वॉलेट ने उसी अवधि में एक बार भेज दिया है उसके पास उतना नहीं है जितना सौंपी गई मात्रा का आँकड़ा दिखाता है, और रुकता बाद वाला ट्रांसफ़र है — जो बाहर से यूँ दिखता है जैसे वही ट्रांसफ़र बेवजह नाकाम हो रहा हो।
छत शून्य है। जहाँ ऊर्जा पक्की है वहाँ शून्य ही सही मान है, और mode B में — जहाँ ऊर्जा हम पहुँचाते हैं और लेन-देन भी हम ही प्रसारित करते हैं — हम आपसे fee_limit ख़ाली छोड़ने को कहते हैं: वहाँ कोई छत रखने का मतलब बस इतना होगा कि कुछ गड़बड़ होने पर भेजने वाले का TRX जलाने की खड़ी-खड़ी इजाज़त पड़ी रहे। यह सख़्त रुकावट भी है। शून्य इजाज़त का मतलब है कि एक इकाई भी कम पड़ने पर कॉल उसके लिए पैसा देने के बजाय रुक जाएगा, इसलिए शून्य पर छोड़ी हुई छत उतनी ही देर तक टिकने वाला फ़ैसला है जितनी देर ऊर्जा टिकती है।
लेन-देन पर हस्ताक्षर से पहले ही इसे देख लेना
पहले कारण के पीछे का सवाल — इस प्राप्तकर्ता पर कितनी ऊर्जा लगेगी — कुछ भी हस्ताक्षर होने से पहले दो ऐसे कॉल से पूछा जा सकता है जो न कुछ रोकते हैं न कुछ काटते हैं।
GET /v1/address-check एक पते के बारे में जवाब देता है: activated, holds_usdt, blacklisted, is_contract, और इन्हीं से निकलता expected_kind। कॉल का आकार holds_usdt तय करता है।
curl -s -H "Authorization: Bearer $KEY" \ "https://api.nrg.market/v1/address-check?address=TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9" # expected_kind "single", "double" या "custom" होता है
POST /v1/estimate पूरे बैच के बारे में जवाब देता है — एक कॉल में 500 तक प्राप्तकर्ता, हर एक के साथ उसका kind, उसके पीछे की energy_units और कोई भी warnings। single आम ट्रांसफ़र है और double वह जो टोकन खाता खोलता है। custom वह आइटम है जिस पर कोई मोटा नियम नहीं चलता: प्राप्तकर्ता ख़ुद एक अनुबंध निकलता है जिसका अपना transfer तर्क है, इसलिए दोनों में से कोई मानक आँकड़ा लागू नहीं होता और energy_units असली कॉल के ड्राई-रन से आती है। छत एक-एक करके इन्हीं आइटमों के नाप से तय करनी होती है, और उनके साथ खड़ी contract_recipient चेतावनी अक्सर पहला संकेत होती है कि भुगतान का कोई पता वॉलेट है ही नहीं।
उपाय, सबसे आसान से शुरू
छत बढ़ा दीजिए। एक फ़ील्ड, कोई ढाँचा नहीं, और रुकावट ख़त्म: कॉल पूरा होता है और नेटवर्क जितना चाहिए उतना ले लेता है। ख़र्च उसके साथ ख़त्म नहीं होता। छत जलाने की इजाज़त है, इसलिए खुली छत खुला जलना है — जो ट्रांसफ़र पहले रुक जाता था वह अब 13.1 TRX पर पूरा होता है। भुगतान के काम के नीचे फ़र्श की तरह यह ठीक है, योजना की तरह ग़लत।
भेजने वाले पर ऊर्जा रख दीजिए। फिर छत को इजाज़त देने लायक़ कुछ बचता ही नहीं। ऊर्जा या तो TRX स्टेक करने से आती है — यानी चालू पूँजी बाँधकर एक संसाधन-बजट पर नज़र रखने से — या फिर उतने ही मिनटों के लिए ऊर्जा किराए पर लेने से, जितने ट्रांसफ़र को चाहिए (वह अभी कितने में पड़ती है)। दोनों ही हाल में कॉल का दाम ऊर्जा में चुकता है और जलना होता ही नहीं।
अवधि के भीतर भेजिए। किराए की ऊर्जा वॉलेट पर एक तय अवधि के लिए रहती है, और ऑर्डर के जवाब में send_before आता है — वह पल जिस पर डिलीवरी की अवधि बंद होती है, ख़रीदी हुई अवधि से तीन सेकंड पहले। ready शब्द के बजाय उसी फ़ील्ड के आने पर नज़र रखिए: ऑर्डर ऊर्जा पहुँचाने से पूरा होता है, इसलिए completed उसके फ़ौरन बाद आ जाता है। send_before के बाद भेजना ट्रांसफ़र को नेटवर्क में तब डालना है जब ऊर्जा शायद अपने घर लौट चुकी हो — यानी ठीक वही कमी, जिस पर यह पोस्ट है।
हस्ताक्षरित लेन-देन हमें सौंप दीजिए। mode B अवधि की चिंता आपकी तरफ़ से पूरी तरह हटा देता है: आप पहले से हस्ताक्षर किया हुआ ट्रांसफ़र भेज देते हैं, हम उसे रोके रखते हैं, और ऊर्जा के on-chain पक्की होते ही प्रसारित कर देते हैं। हमारा प्रसारित किया हुआ लेन-देन फिर भी किसी ब्लॉक तक पहुँचकर चला न हो, तो वह हिस्सा failed होकर transaction_reverted के साथ बंद होता है और रोकी गई पूरी राशि छूट जाती है — और इस कारण का, बाक़ी हर कारण की तरह, कभी पैसा नहीं लिया जाता। नाम को उतना ही पढ़िए जितना वह है: transaction_reverted हमारा शब्द है इस बात के लिए कि “वह किसी ब्लॉक तक पहुँचा और चला नहीं”, नेटवर्क ने उस अस्वीकार को जो भी नाम दिया हो — इसलिए एक OUT_OF_ENERGY और किसी अनुबंध का अपना REVERT, दोनों एक ही स्थिति के नीचे आते हैं। ऐसा लेन-देन उस फ़ैसले तक पहुँचने में जो TRX जला देता है वह भेजने वाले का है, हमारा नहीं — और यही इस हिस्से के ऊपर वाले अनुमान के पक्ष में दलील है, नीचे वाले दोबारा-कोशिश के लूप के पक्ष में नहीं।