मुख्य सामग्री पर जाएं
Change page

स्मार्ट अनुबंधों को अपग्रेड करना

इथेरियम पर स्मार्ट अनुबंध स्व-निष्पादित प्रोग्राम हैं जो इथेरियम वर्चुअल मशीन (EVM) में चलते हैं। ये प्रोग्राम डिज़ाइन के अनुसार अपरिवर्तनीय होते हैं, जो अनुबंध की तैनाती के बाद व्यावसायिक तर्क (business logic) में किसी भी अपडेट को रोकता है।

हालांकि स्मार्ट अनुबंधों की विश्वासहीनता, विकेंद्रीकरण और सुरक्षा के लिए अपरिवर्तनीयता आवश्यक है, लेकिन कुछ मामलों में यह एक कमी हो सकती है। उदाहरण के लिए, अपरिवर्तनीय कोड डेवलपर्स के लिए कमजोर अनुबंधों को ठीक करना असंभव बना सकता है।

हालाँकि, स्मार्ट अनुबंधों को बेहतर बनाने के लिए बढ़े हुए शोध ने कई अपग्रेड पैटर्न की शुरुआत की है। ये अपग्रेड पैटर्न डेवलपर्स को व्यावसायिक तर्क को अलग-अलग अनुबंधों में रखकर (अपरिवर्तनीयता को बनाए रखते हुए) स्मार्ट अनुबंधों को अपग्रेड करने में सक्षम बनाते हैं।

पूर्वापेक्षाएँ

आपको स्मार्ट अनुबंधों, स्मार्ट अनुबंध की संरचना, और इथेरियम वर्चुअल मशीन (EVM) की अच्छी समझ होनी चाहिए। यह मार्गदर्शिका यह भी मानती है कि पाठकों को स्मार्ट अनुबंधों की प्रोग्रामिंग की समझ है।

स्मार्ट अनुबंध अपग्रेड क्या है?

एक स्मार्ट अनुबंध अपग्रेड में अनुबंध की स्थिति को बनाए रखते हुए स्मार्ट अनुबंध के व्यावसायिक तर्क को बदलना शामिल है। यह स्पष्ट करना महत्वपूर्ण है कि अपग्रेड करने की क्षमता और परिवर्तनशीलता समान नहीं हैं, विशेष रूप से स्मार्ट अनुबंधों के संदर्भ में।

आप अभी भी इथेरियम नेटवर्क पर किसी पते पर तैनात प्रोग्राम को नहीं बदल सकते हैं। लेकिन आप उस कोड को बदल सकते हैं जो तब निष्पादित होता है जब उपयोगकर्ता स्मार्ट अनुबंध के साथ इंटरैक्ट करते हैं।

यह निम्नलिखित विधियों के माध्यम से किया जा सकता है:

  1. एक स्मार्ट अनुबंध के कई संस्करण बनाना और पुराने अनुबंध से अनुबंध के नए उदाहरण में स्थिति (यानी, डेटा) को माइग्रेट करना।

  2. व्यावसायिक तर्क और स्थिति को संग्रहीत करने के लिए अलग-अलग अनुबंध बनाना।

  3. एक अपरिवर्तनीय प्रॉक्सी कॉन्ट्रैक्ट से एक संशोधन योग्य लॉजिक अनुबंध में फ़ंक्शन कॉल को प्रत्यायोजित करने के लिए प्रॉक्सी पैटर्न का उपयोग करना।

  4. एक अपरिवर्तनीय मुख्य अनुबंध बनाना जो विशिष्ट कार्यों को निष्पादित करने के लिए लचीले सैटेलाइट अनुबंधों के साथ इंटरफेस करता है और उन पर निर्भर करता है।

  5. प्रॉक्सी कॉन्ट्रैक्ट से लॉजिक अनुबंधों में फ़ंक्शन कॉल को प्रत्यायोजित करने के लिए डायमंड पैटर्न का उपयोग करना।

अपग्रेड तंत्र #1: अनुबंध माइग्रेशन

अनुबंध माइग्रेशन वर्ज़निंग पर आधारित है—एक ही सॉफ़्टवेयर की अनूठी स्थितियों को बनाने और प्रबंधित करने का विचार। अनुबंध माइग्रेशन में मौजूदा स्मार्ट अनुबंध का एक नया उदाहरण तैनात करना और स्टोरेज और बैलेंस को नए अनुबंध में स्थानांतरित करना शामिल है।

नए तैनात अनुबंध में एक खाली स्टोरेज होगा, जिससे आप पुराने अनुबंध से डेटा पुनर्प्राप्त कर सकते हैं और इसे नए कार्यान्वयन में लिख सकते हैं। इसके बाद, आपको नए पते को दर्शाने के लिए उन सभी अनुबंधों को अपडेट करना होगा जो पुराने अनुबंध के साथ इंटरैक्ट करते थे।

अनुबंध माइग्रेशन में अंतिम चरण उपयोगकर्ताओं को नए अनुबंध का उपयोग करने के लिए स्विच करने के लिए मनाना है। नया अनुबंध संस्करण उपयोगकर्ता के बैलेंस और पतों को बनाए रखेगा, जो अपरिवर्तनीयता को सुरक्षित रखता है। यदि यह एक टोकन-आधारित अनुबंध है, तो आपको पुराने अनुबंध को त्यागने और नए अनुबंध का उपयोग करने के लिए एक्सचेंजों से भी संपर्क करना होगा।

उपयोगकर्ता इंटरैक्शन को तोड़े बिना स्मार्ट अनुबंधों को अपग्रेड करने के लिए अनुबंध माइग्रेशन एक अपेक्षाकृत सीधा और सुरक्षित उपाय है। हालाँकि, उपयोगकर्ता स्टोरेज और बैलेंस को मैन्युअल रूप से नए अनुबंध में माइग्रेट करने में समय लगता है और इसमें उच्च गैस लागत आ सकती है।

अनुबंध माइग्रेशन पर अधिक जानकारी। (opens in a new tab)

अपग्रेड तंत्र #2: डेटा पृथक्करण

स्मार्ट अनुबंधों को अपग्रेड करने का एक अन्य तरीका व्यावसायिक तर्क और डेटा स्टोरेज को अलग-अलग अनुबंधों में अलग करना है। इसका मतलब है कि उपयोगकर्ता लॉजिक अनुबंध के साथ इंटरैक्ट करते हैं, जबकि डेटा स्टोरेज अनुबंध में संग्रहीत होता है।

लॉजिक अनुबंध में वह कोड होता है जो तब निष्पादित होता है जब उपयोगकर्ता एप्लिकेशन के साथ इंटरैक्ट करते हैं। यह स्टोरेज अनुबंध का पता भी रखता है और डेटा प्राप्त करने और सेट करने के लिए इसके साथ इंटरैक्ट करता है।

इस बीच, स्टोरेज अनुबंध स्मार्ट अनुबंध से जुड़ी स्थिति रखता है, जैसे उपयोगकर्ता बैलेंस और पते। ध्यान दें कि स्टोरेज अनुबंध का स्वामित्व लॉजिक अनुबंध के पास होता है और तैनाती के समय इसे बाद वाले के पते के साथ कॉन्फ़िगर किया जाता है। यह अनधिकृत अनुबंधों को स्टोरेज अनुबंध को कॉल करने या उसके डेटा को अपडेट करने से रोकता है।

डिफ़ॉल्ट रूप से, स्टोरेज अनुबंध अपरिवर्तनीय है—लेकिन आप उस लॉजिक अनुबंध को बदल सकते हैं जिसे यह एक नए कार्यान्वयन के साथ इंगित करता है। यह EVM में चलने वाले कोड को बदल देगा, जबकि स्टोरेज और बैलेंस को बरकरार रखेगा।

इस अपग्रेड विधि का उपयोग करने के लिए स्टोरेज अनुबंध में लॉजिक अनुबंध के पते को अपडेट करने की आवश्यकता होती है। आपको पहले बताए गए कारणों से नए लॉजिक अनुबंध को स्टोरेज अनुबंध के पते के साथ भी कॉन्फ़िगर करना होगा।

अनुबंध माइग्रेशन की तुलना में डेटा पृथक्करण पैटर्न को लागू करना यकीनन आसान है। हालाँकि, आपको दुर्भावनापूर्ण अपग्रेड से स्मार्ट अनुबंधों की रक्षा करने के लिए कई अनुबंधों का प्रबंधन करना होगा और जटिल प्राधिकरण योजनाओं को लागू करना होगा।

अपग्रेड तंत्र #3: प्रॉक्सी पैटर्न

प्रॉक्सी पैटर्न व्यावसायिक तर्क और डेटा को अलग-अलग अनुबंधों में रखने के लिए डेटा पृथक्करण का भी उपयोग करता है। हालाँकि, प्रॉक्सी पैटर्न में, स्टोरेज अनुबंध (जिसे प्रॉक्सी कहा जाता है) कोड निष्पादन के दौरान लॉजिक अनुबंध को कॉल करता है। यह डेटा पृथक्करण विधि के विपरीत है, जहाँ लॉजिक अनुबंध स्टोरेज अनुबंध को कॉल करता है।

प्रॉक्सी पैटर्न में यह होता है:

  1. उपयोगकर्ता प्रॉक्सी कॉन्ट्रैक्ट के साथ इंटरैक्ट करते हैं, जो डेटा संग्रहीत करता है, लेकिन व्यावसायिक तर्क नहीं रखता है।

  2. प्रॉक्सी कॉन्ट्रैक्ट लॉजिक अनुबंध का पता संग्रहीत करता है और delegatecall फ़ंक्शन का उपयोग करके सभी फ़ंक्शन कॉल को लॉजिक अनुबंध (जो व्यावसायिक तर्क रखता है) को प्रत्यायोजित करता है।

  3. कॉल को लॉजिक अनुबंध पर अग्रेषित करने के बाद, लॉजिक अनुबंध से लौटाया गया डेटा पुनर्प्राप्त किया जाता है और उपयोगकर्ता को वापस कर दिया जाता है।

प्रॉक्सी पैटर्न का उपयोग करने के लिए delegatecall फ़ंक्शन की समझ की आवश्यकता होती है। मूल रूप से, delegatecall एक ऑपकोड है जो एक अनुबंध को दूसरे अनुबंध को कॉल करने की अनुमति देता है, जबकि वास्तविक कोड निष्पादन कॉलिंग अनुबंध के संदर्भ में होता है। प्रॉक्सी पैटर्न में delegatecall का उपयोग करने का एक निहितार्थ यह है कि प्रॉक्सी कॉन्ट्रैक्ट अपने स्टोरेज में पढ़ता और लिखता है और लॉजिक अनुबंध पर संग्रहीत तर्क को निष्पादित करता है जैसे कि किसी आंतरिक फ़ंक्शन को कॉल कर रहा हो।

Solidity दस्तावेज़ (opens in a new tab) से:

संदेश कॉल का एक विशेष प्रकार मौजूद है, जिसका नाम delegatecall है जो एक संदेश कॉल के समान है, इस तथ्य के अलावा कि लक्ष्य पते पर कोड कॉलिंग अनुबंध के संदर्भ (यानी, पते पर) में निष्पादित होता है और msg.sender और msg.value अपने मान नहीं बदलते हैं। इसका मतलब है कि एक अनुबंध रनटाइम पर एक अलग पते से गतिशील रूप से कोड लोड कर सकता है। स्टोरेज, वर्तमान पता और बैलेंस अभी भी कॉलिंग अनुबंध को संदर्भित करते हैं, केवल कोड कॉल किए गए पते से लिया जाता है।

प्रॉक्सी कॉन्ट्रैक्ट जानता है कि जब भी कोई उपयोगकर्ता किसी फ़ंक्शन को कॉल करता है तो delegatecall को कैसे लागू किया जाए क्योंकि इसमें एक fallback फ़ंक्शन अंतर्निहित होता है। Solidity प्रोग्रामिंग में फॉलबैक फ़ंक्शन (opens in a new tab) तब निष्पादित होता है जब कोई फ़ंक्शन कॉल अनुबंध में निर्दिष्ट फ़ंक्शंस से मेल नहीं खाता है।

प्रॉक्सी पैटर्न को काम करने के लिए एक कस्टम फॉलबैक फ़ंक्शन लिखने की आवश्यकता होती है जो यह निर्दिष्ट करता है कि प्रॉक्सी कॉन्ट्रैक्ट को उन फ़ंक्शन कॉल को कैसे संभालना चाहिए जिनका वह समर्थन नहीं करता है। इस मामले में प्रॉक्सी के फॉलबैक फ़ंक्शन को एक delegatecall शुरू करने और उपयोगकर्ता के अनुरोध को वर्तमान लॉजिक अनुबंध कार्यान्वयन में फिर से रूट करने के लिए प्रोग्राम किया गया है।

प्रॉक्सी कॉन्ट्रैक्ट डिफ़ॉल्ट रूप से अपरिवर्तनीय है, लेकिन अपडेट किए गए व्यावसायिक तर्क के साथ नए लॉजिक अनुबंध बनाए जा सकते हैं। अपग्रेड करना तब प्रॉक्सी कॉन्ट्रैक्ट में संदर्भित लॉजिक अनुबंध के पते को बदलने का मामला है।

प्रॉक्सी कॉन्ट्रैक्ट को एक नए लॉजिक अनुबंध की ओर इंगित करके, जब उपयोगकर्ता प्रॉक्सी कॉन्ट्रैक्ट फ़ंक्शन को कॉल करते हैं तो निष्पादित कोड बदल जाता है। यह हमें उपयोगकर्ताओं को एक नए अनुबंध के साथ इंटरैक्ट करने के लिए कहे बिना अनुबंध के तर्क को अपग्रेड करने की अनुमति देता है।

प्रॉक्सी पैटर्न स्मार्ट अनुबंधों को अपग्रेड करने के लिए एक लोकप्रिय तरीका है क्योंकि वे अनुबंध माइग्रेशन से जुड़ी कठिनाइयों को दूर करते हैं। हालाँकि, प्रॉक्सी पैटर्न का उपयोग करना अधिक जटिल है और यदि अनुचित तरीके से उपयोग किया जाता है, तो फ़ंक्शन चयनकर्ता टकराव (function selector clashes) (opens in a new tab) जैसी महत्वपूर्ण खामियाँ पेश कर सकते हैं।

प्रॉक्सी पैटर्न पर अधिक जानकारी (opens in a new tab)

अपग्रेड तंत्र #4: रणनीति पैटर्न

यह तकनीक रणनीति पैटर्न (opens in a new tab) से प्रभावित है, जो विशिष्ट सुविधाओं को लागू करने के लिए अन्य प्रोग्रामों के साथ इंटरफेस करने वाले सॉफ़्टवेयर प्रोग्राम बनाने को प्रोत्साहित करती है। इथेरियम विकास में रणनीति पैटर्न को लागू करने का मतलब एक स्मार्ट अनुबंध बनाना होगा जो अन्य अनुबंधों से फ़ंक्शंस को कॉल करता है।

इस मामले में मुख्य अनुबंध में मुख्य व्यावसायिक तर्क होता है, लेकिन कुछ कार्यों को निष्पादित करने के लिए अन्य स्मार्ट अनुबंधों ("सैटेलाइट अनुबंधों") के साथ इंटरफेस करता है। यह मुख्य अनुबंध प्रत्येक सैटेलाइट अनुबंध के लिए पता भी संग्रहीत करता है और सैटेलाइट अनुबंध के विभिन्न कार्यान्वयनों के बीच स्विच कर सकता है।

आप एक नया सैटेलाइट अनुबंध बना सकते हैं और नए पते के साथ मुख्य अनुबंध को कॉन्फ़िगर कर सकते हैं। यह आपको एक स्मार्ट अनुबंध के लिए रणनीतियों को बदलने (यानी, नया तर्क लागू करने) की अनुमति देता है।

हालांकि पहले चर्चा किए गए प्रॉक्सी पैटर्न के समान, रणनीति पैटर्न अलग है क्योंकि मुख्य अनुबंध, जिसके साथ उपयोगकर्ता इंटरैक्ट करते हैं, व्यावसायिक तर्क रखता है। इस पैटर्न का उपयोग करने से आपको मुख्य बुनियादी ढांचे को प्रभावित किए बिना स्मार्ट अनुबंध में सीमित बदलाव पेश करने का अवसर मिलता है।

मुख्य कमी यह है कि यह पैटर्न ज्यादातर मामूली अपग्रेड को रोल आउट करने के लिए उपयोगी है। इसके अलावा, यदि मुख्य अनुबंध से समझौता किया जाता है (उदा., हैक के माध्यम से), तो आप इस अपग्रेड विधि का उपयोग नहीं कर सकते हैं।

अपग्रेड तंत्र #5: डायमंड पैटर्न

डायमंड पैटर्न को प्रॉक्सी पैटर्न में सुधार माना जा सकता है। डायमंड पैटर्न प्रॉक्सी पैटर्न से भिन्न होते हैं क्योंकि डायमंड प्रॉक्सी कॉन्ट्रैक्ट एक से अधिक लॉजिक अनुबंधों में फ़ंक्शन कॉल को प्रत्यायोजित कर सकता है।

डायमंड पैटर्न में लॉजिक अनुबंधों को facets के रूप में जाना जाता है। डायमंड पैटर्न को काम करने के लिए, आपको प्रॉक्सी कॉन्ट्रैक्ट में एक मैपिंग बनाने की आवश्यकता है जो फ़ंक्शन चयनकर्ताओं (opens in a new tab) को विभिन्न facet पतों पर मैप करता है।

जब कोई उपयोगकर्ता फ़ंक्शन कॉल करता है, तो प्रॉक्सी कॉन्ट्रैक्ट उस फ़ंक्शन को निष्पादित करने के लिए जिम्मेदार facet को खोजने के लिए मैपिंग की जांच करता है। फिर यह delegatecall (फॉलबैक फ़ंक्शन का उपयोग करके) लागू करता है और कॉल को उपयुक्त लॉजिक अनुबंध पर पुनर्निर्देशित करता है।

पारंपरिक प्रॉक्सी अपग्रेड पैटर्न की तुलना में डायमंड अपग्रेड पैटर्न के कुछ फायदे हैं:

  1. यह आपको सभी कोड को बदले बिना अनुबंध के एक छोटे से हिस्से को अपग्रेड करने की अनुमति देता है। अपग्रेड के लिए प्रॉक्सी पैटर्न का उपयोग करने के लिए मामूली अपग्रेड के लिए भी पूरी तरह से नया लॉजिक अनुबंध बनाने की आवश्यकता होती है।

  2. सभी स्मार्ट अनुबंधों (प्रॉक्सी पैटर्न में उपयोग किए जाने वाले लॉजिक अनुबंधों सहित) की 24KB आकार सीमा होती है, जो एक सीमा हो सकती है—विशेष रूप से अधिक कार्यों की आवश्यकता वाले जटिल अनुबंधों के लिए। डायमंड पैटर्न कई लॉजिक अनुबंधों में कार्यों को विभाजित करके इस समस्या को हल करना आसान बनाता है।

  3. प्रॉक्सी पैटर्न एक्सेस नियंत्रण के लिए एक कैच-ऑल दृष्टिकोण अपनाते हैं। अपग्रेड फ़ंक्शंस तक पहुंच वाली एक इकाई संपूर्ण अनुबंध को बदल सकती है। लेकिन डायमंड पैटर्न एक मॉड्यूलर अनुमति दृष्टिकोण को सक्षम बनाता है, जहां आप संस्थाओं को स्मार्ट अनुबंध के भीतर कुछ कार्यों को अपग्रेड करने तक सीमित कर सकते हैं।

डायमंड पैटर्न पर अधिक जानकारी (opens in a new tab)

स्मार्ट अनुबंधों को अपग्रेड करने के फायदे और नुकसान

फायदेनुकसान
एक स्मार्ट अनुबंध अपग्रेड तैनाती के बाद के चरण में खोजी गई कमजोरियों को ठीक करना आसान बना सकता है।स्मार्ट अनुबंधों को अपग्रेड करना कोड अपरिवर्तनीयता के विचार को नकारता है, जिसका विकेंद्रीकरण और सुरक्षा पर प्रभाव पड़ता है।
डेवलपर्स विकेंद्रीकृत एप्लिकेशन में नई सुविधाएँ जोड़ने के लिए लॉजिक अपग्रेड का उपयोग कर सकते हैं।उपयोगकर्ताओं को डेवलपर्स पर भरोसा करना चाहिए कि वे मनमाने ढंग से स्मार्ट अनुबंधों को संशोधित नहीं करेंगे।
स्मार्ट अनुबंध अपग्रेड अंतिम-उपयोगकर्ताओं के लिए सुरक्षा में सुधार कर सकते हैं क्योंकि बग को जल्दी से ठीक किया जा सकता है।स्मार्ट अनुबंधों में अपग्रेड कार्यक्षमता की प्रोग्रामिंग जटिलता की एक और परत जोड़ती है और महत्वपूर्ण खामियों की संभावना को बढ़ाती है।
अनुबंध अपग्रेड डेवलपर्स को विभिन्न सुविधाओं के साथ प्रयोग करने और समय के साथ dapps को बेहतर बनाने के लिए अधिक जगह देते हैं।स्मार्ट अनुबंधों को अपग्रेड करने का अवसर डेवलपर्स को विकास के चरण के दौरान उचित परिश्रम किए बिना परियोजनाओं को तेजी से लॉन्च करने के लिए प्रोत्साहित कर सकता है।
स्मार्ट अनुबंधों में असुरक्षित एक्सेस नियंत्रण या केंद्रीकरण दुर्भावनापूर्ण अभिनेताओं के लिए अनधिकृत अपग्रेड करना आसान बना सकता है।

स्मार्ट अनुबंधों को अपग्रेड करने के लिए विचार

  1. अनधिकृत स्मार्ट अनुबंध अपग्रेड को रोकने के लिए सुरक्षित एक्सेस नियंत्रण/प्राधिकरण तंत्र का उपयोग करें, खासकर यदि प्रॉक्सी पैटर्न, रणनीति पैटर्न या डेटा पृथक्करण का उपयोग कर रहे हों। एक उदाहरण अपग्रेड फ़ंक्शन तक पहुंच को प्रतिबंधित करना है, ताकि केवल अनुबंध का मालिक ही इसे कॉल कर सके।

  2. स्मार्ट अनुबंधों को अपग्रेड करना एक जटिल गतिविधि है और कमजोरियों की शुरूआत को रोकने के लिए उच्च स्तर के परिश्रम की आवश्यकता होती है।

  3. अपग्रेड लागू करने की प्रक्रिया का विकेंद्रीकरण करके विश्वास मान्यताओं को कम करें। संभावित रणनीतियों में अपग्रेड को नियंत्रित करने के लिए मल्टी-सिग वॉलेट अनुबंध का उपयोग करना, या अपग्रेड को मंजूरी देने पर वोट करने के लिए DAO के सदस्यों की आवश्यकता शामिल है।

  4. अनुबंधों को अपग्रेड करने में शामिल लागतों से अवगत रहें। उदाहरण के लिए, अनुबंध माइग्रेशन के दौरान पुराने अनुबंध से नए अनुबंध में स्थिति (उदा., उपयोगकर्ता बैलेंस) की प्रतिलिपि बनाने के लिए एक से अधिक लेन-देन की आवश्यकता हो सकती है, जिसका अर्थ है अधिक गैस शुल्क।

  5. उपयोगकर्ताओं की सुरक्षा के लिए टाइमलॉक (timelocks) लागू करने पर विचार करें। टाइमलॉक एक सिस्टम में बदलाव पर लागू देरी को संदर्भित करता है। अपग्रेड को नियंत्रित करने के लिए टाइमलॉक को मल्टी-सिग शासन प्रणाली के साथ जोड़ा जा सकता है: यदि कोई प्रस्तावित कार्रवाई आवश्यक अनुमोदन सीमा तक पहुंचती है, तो यह तब तक निष्पादित नहीं होती जब तक कि पूर्वनिर्धारित देरी अवधि समाप्त न हो जाए।

टाइमलॉक उपयोगकर्ताओं को सिस्टम से निकास करने के लिए कुछ समय देते हैं यदि वे प्रस्तावित बदलाव (उदा., लॉजिक अपग्रेड या नई शुल्क योजनाएं) से असहमत हैं। टाइमलॉक के बिना, उपयोगकर्ताओं को डेवलपर्स पर भरोसा करने की आवश्यकता होती है कि वे पूर्व सूचना के बिना स्मार्ट अनुबंध में मनमाने बदलाव लागू नहीं करेंगे। यहाँ कमी यह है कि टाइमलॉक कमजोरियों को जल्दी से पैच करने की क्षमता को प्रतिबंधित करते हैं।

संसाधन

ओपनजेपेलिन अपग्रेड प्लगइन्स - अपग्रेड करने योग्य स्मार्ट अनुबंधों को तैनात करने और सुरक्षित करने के लिए उपकरणों का एक सूट।

ट्यूटोरियल

आगे की पढ़ाई