5 मिनट
सबग्राफ सर्वोत्तम प्रथा 4 - eth_calls से बचकर अनुक्रमण गति में सुधार करें
TLDR
eth_calls वे कॉल हैं जो एक Subgraph से Ethereum नोड पर किया जा सकता है। ये कॉल डेटा लौटाने में महत्वपूर्ण समय लेते हैं, जिससे indexing धीमी हो जाती है। यदि संभव हो, तो smart contract को इस तरह से डिजाइन करें कि वे सभी आवश्यक डेटा उत्पन्न करें ताकि आपको eth_calls का उपयोग न करना पड़े।
Eth_calls से बचना एक सर्वोत्तम अभ्यास क्यों है
सबग्राफ स्मार्ट contract द्वारा उत्सर्जित इवेंट डेटा को इंडेक्स करने के लिए ऑप्टिमाइज़ किए गए हैं। एक सबग्राफ eth_call
से आने वाले डेटा को भी इंडेक्स कर सकता है, लेकिन यह सबग्राफ indexing को काफी धीमा कर सकता है क्योंकि eth_calls के लिए स्मार्ट कॉन्ट्रैक्ट्स को एक्सटर्नल कॉल करने की आवश्यकता होती है। इन कॉल्स की प्रतिक्रियाशीलता सबग्राफ पर नहीं, बल्कि उस Ethereum नोड की कनेक्टिविटी और प्रतिक्रियाशीलता पर निर्भर करती है, जिससे क्वेरी की जा रही है। यदि हम अपने सबग्राफ में eth_calls
को कम या समाप्त कर देते हैं, तो हम अपनी indexing स्पीड को काफी हद तक सुधार सकते हैं।
एक eth_call कैसा दिखता है?
eth_calls
अक्सर आवश्यक होते हैं जब किसी सबग्राफ के लिए आवश्यक डेटा उत्सर्जित घटनाओं के माध्यम से उपलब्ध नहीं होता है। उदाहरण के लिए, एक स्थिति पर विचार करें जहां एक सबग्राफ को यह पहचानने की आवश्यकता होती है कि कोई ERC20 टोकन किसी विशेष पूल का हिस्सा है या नहीं, लेकिन अनुबंध केवल एक बुनियादी Transfer
आयोजन उत्सर्जित करता है और वह घटना उत्सर्जित नहीं करता है जिसमें हमारे लिए आवश्यक डेटा हो।
1इवेंट Transfer(address indexed from, address indexed to, uint256 value);
मान लें कि टोकन्स की पूल सदस्यता एक state वेरिएबल getPoolInfo द्वारा निर्धारित होती है। इस मामले में, हमें इस डेटा को क्वेरी करने के लिए एक eth_call का उपयोग करना होगा:
1import { Address } from '@graphprotocol/graph-ts'2import { ERC20, Transfer } from '../generated/ERC20/ERC20'3import { TokenTransaction } from '../generated/schema'45export function handleTransfer(event: Transfer): void {6 let transaction = new TokenTransaction(event.transaction.hash.toHex())78 // दिए गए पते पर ERC20 कॉन्ट्रैक्ट इंस्टेंस को बाइंड करें:9 let instance = ERC20.bind(event.address)1011 // eth_call के जरिए पूल जानकारी प्राप्त करें12 let poolInfo = instance.getPoolInfo(event.params.to)1314 transaction.pool = poolInfo.toHexString()15 transaction.from = event.params.from.toHexString()16 transaction.to = event.params.to.toHexString()17 transaction.value = event.params.value1819 transaction.save()20}
यह कार्यशील है, हालांकि यह हमारे सबग्राफ की indexing को धीमा कर देता है।
Eth_calls को कैसे समाप्त करें
आदर्श रूप से, स्मार्ट कॉन्ट्रैक्ट को सभी आवश्यक डेटा को इवेंट्स के भीतर प्रकट करने के लिए अपडेट किया जाना चाहिए। उदाहरण के लिए, स्मार्ट कॉन्ट्रैक्ट में इवेंट में पूल जानकारी शामिल करने के लिए संशोधन करने से eth_calls की आवश्यकता को समाप्त किया जा सकता है:
1event TransferWithPool(address indexed from, address indexed to, uint256 value, bytes32 indexed poolInfo);
इस अपडेट के साथ, सबग्राफ बाहरी कॉल किए बिना सीधे आवश्यक डेटा को इंडेक्स कर सकता है।
1import { Address } from '@graphprotocol/graph-ts'2import { ERC20, TransferWithPool } from '../generated/ERC20/ERC20'3import { TokenTransaction } from '../generated/schema'45export function handleTransferWithPool(event: TransferWithPool): void {6 let transaction = new TokenTransaction(event.transaction.hash.toHex())78 transaction.pool = event.params.poolInfo.toHexString()9 transaction.from = event.params.from.toHexString()10 transaction.to = event.params.to.toHexString()11 transaction.value = event.params.value1213 transaction.save()14}
यह बहुत अधिक प्रदर्शनकारी है क्योंकि इसने eth_calls की आवश्यकता को समाप्त कर दिया है।
Eth_calls को ऑप्टिमाइज़ करने का तरीका
यदि स्मार्ट कॉन्ट्रैक्ट में परिवर्तन करना संभव नहीं है और eth_calls की आवश्यकता है, तो विभिन्न रणनीतियों को सीखने के लिए Improve Subgraph Indexing Performance Easily: Reduce eth_calls पढ़ें जो eth_calls को ऑप्टिमाइज़ करने के तरीके बताती है।
Eth_calls के रनटाइम ओवरहेड को कम करना
जिन eth_calls को समाप्त नहीं किया जा सकता है, उनके द्वारा उत्पन्न रनटाइम ओवरहेड को मैनिफेस्ट में घोषित करके कम किया जा सकता है। जब graph-node एक ब्लॉक को प्रोसेस करता है, तो यह हैंडलर्स के चलने से पहले सभी घोषित eth_calls को समानांतर में प्रदर्शन करता है। जो कॉल घोषित नहीं हैं, वे हैंडलर्स के चलने के समय अनुक्रमिक रूप से निष्पादित होते हैं। रनटाइम में सुधार समानांतर में कॉल्स को करने से आता है, न कि अनुक्रमिक रूप से - यह कुल समय को कम करने में मदद करता है, लेकिन इसे पूरी तरह से समाप्त नहीं करता है।
वर्तमान में, eth_calls को केवल event handlers के लिए घोषित किया जा सकता है। मैनिफेस्ट में, लिखें
1इवेंट: TransferWithPool(address indexed, address indexed, uint256, bytes32 indexed)2हैंडलर: handleTransferWithPool3कॉल्स:4 ERC20.poolInfo: ERC20[event.address].getPoolInfo(event.params.to)
पीले रंग में हाइलाइट किया गया हिस्सा कॉल डिक्लेरेशन है। कॉल के पहले वाले हिस्से में जो टेक्स्ट लेबल है, वह केवल त्रुटि संदेशों के लिए उपयोग किया जाता है। कॉल के बाद वाला हिस्सा Contract[address].function(params) के रूप में होता है। address और params के लिए मान event.address
और event.params.<name>
अनुमेय हैं।
Handler स्वयं इस eth_call के परिणाम तक ठीक उसी तरह पहुंचता है जैसे पिछले अनुभाग में, अनुबंध से बाइंडिंग करके और कॉल करके। graph-node घोषित eth_calls के परिणामों को मेमोरी में कैश करता है और हैंडलर से कॉल इस मेमोरी कैश से परिणाम प्राप्त करेगा, बजाय इसके कि एक वास्तविक RPC कॉल की जाए।
घोषित eth_calls केवल उन सबग्राफ में किए जा सकते हैं जिनका specVersion >= 1.2.0 है।
निष्कर्ष
आप अपने सबग्राफ में eth_calls
को कम या समाप्त करके Indexing प्रदर्शन को काफी हद तक सुधार सकते हैं।