Initializers वह तरीका हैं जिससे upgradeable contracts एक constructor का व्यवहार प्राप्त करते हैं।
Contracts को deploy करते समय, storage variables को initialize करने के लिए constructor को कॉल करना आम बात है। उदाहरण के लिए, एक constructor किसी टोकन का नाम या maximum supply सेट कर सकता है। एक upgradeable contract में, इस जानकारी को proxy के storage variables में स्टोर करने की आवश्यकता होती है, न कि implementation के storage variables में। Proxy में एक constructor जोड़ना जैसे कि:
constructor(
string memory name_,
string memory symbol_,
uint256 maxSupply_
) {
name = name_;
symbol = symbol_;
maxSupply = maxSupply_;
}
यह एक अच्छा समाधान नहीं है क्योंकि proxy और implementation के बीच storage variable की locations को align करना त्रुटिपूर्ण (error prone) हो सकता है। Implementation में एक constructor बनाना काम नहीं करेगा क्योंकि यह implementation में ही storage variables को सेट कर देगा।
Initializers कैसे काम करते हैं
उपरोक्त सभी समस्याओं का समाधान implementation में एक initializer() फ़ंक्शन बनाना है, जो storage variables को उसी तरह सेट करता है जैसे एक constructor करता है, और proxy द्वारा implementation को delegatecall initialize() करवाया जाता है। Implementation में initializer() रखने से यह सुनिश्चित होता है कि storage variable का alignment स्वचालित रूप से सही होगा। एक constructor की नकल करने के लिए, यह महत्वपूर्ण है कि इस फ़ंक्शन को proxy द्वारा केवल एक बार ही delegatecall किया जा सके।
OpenZeppelin के Initializable.sol कॉन्ट्रैक्ट का उद्देश्य इस initialization पैटर्न का एक मज़बूत implementation प्रदान करना है। वर्तमान में, Initializable.sol का उपयोग OpenZeppelin के upgradable contracts में किया जाता है, जैसे कि ERC20Upgradeable.sol।
इस लेख का उद्देश्य यह विस्तार से समझाना है कि Initializable.sol कैसे काम करता है। लेकिन उससे पहले, आइए दिखाते हैं कि इस पैटर्न को साधारण तरीके (naïvely) से कैसे लागू किया जा सकता है और क्यों यह साधारण implementation केवल सबसे सरल परिदृश्यों में ही काम करता है।
Initializer प्रक्रिया का एक हाई-लेवल उदाहरण नीचे दिए गए एनीमेशन में दिखाया गया है:
एक साधारण Implementation (Naïve Implementation)
नीचे दिए गए कॉन्ट्रैक्ट की तरह कुछ लिखने का मन हो सकता है, जहाँ एक फ़ंक्शन के निष्पादन (execution) को केवल एक बार तक सीमित करने के लिए एक modifier तैयार किया गया हो और फिर कभी नहीं।
contract NaiveInitialization {
// initialized indicates if the contract has been initialized
bool initialized = false;
// restricts the function to be executed only once
modifier initializer() {
require(initialized == false, "Already initialized");
initialized = true;
_;
}
// can be executed only once
function initialize() public initializer {
// Initialize necessary storage variables
}
}
उपरोक्त कोड इस विशिष्ट कॉन्ट्रैक्ट के लिए काम करता है, यह सुनिश्चित करते हुए कि initialize() फ़ंक्शन केवल एक बार निष्पादित (executed) किया जा सकता है। हालाँकि, जब इसका उपयोग inheritance के साथ किया जाता है तो यही पैटर्न विफल हो जाता है।
Initialize का विफल Implementation डेमो
उपरोक्त पैटर्न के साथ समस्या यह है कि यह उस स्थिति का समर्थन नहीं करता है जब contracts inheritance का उपयोग करते हैं और parent contracts को भी initialize करना पड़ता है। आइए निम्नलिखित कोड में इस समस्या के एक उदाहरण की जाँच करें।
contract Initializable {
// initialized indicates if the contract has been initialized
bool initialized = false;
// restricts the function to be executed only once
modifier initializer() {
require(initialized == false, "Already initialized");
initialized = true;
_;
}
}
contract ParentNaive is Initializable {
// initialize the Parent contract
function initializeParent() internal initializer {
// Initialize some state variables
}
}
contract ChildNaive is ParentNaive {
// initialize the Child contract
function initializeChild() public initializer {
super.initializeParent();
// Initialize other state variables
}
}
उपरोक्त कॉन्ट्रैक्ट का अपेक्षित निष्पादन क्रम (expected execution order) इस प्रकार है:
initializeChild()फ़ंक्शन को कॉल किया जाता है।initializermodifier के साथ, यहinitializedvariable कोtrueमें अपडेट कर देता है। इस variable का उपयोग inheritance chain के सभी contracts द्वारा किया जाता है।- इसके बाद,
initializeChild()के भीतरinitializeParent()फ़ंक्शन को कॉल किया जाता है।initializeParent()में भीinitializermodifier है, इसलिए इसेinitializedvariable केfalseहोने की आवश्यकता होती है। - लेकिन
initializedvariable को पहले हीtrueपर सेट कर दिया गया था जबinitializeChildचला था, इसलिए जबinitializeParent()को कॉल किया जाएगा तो transaction रिवर्ट (revert) हो जाएगा।
OpenZeppelin का Initializable.sol कॉन्ट्रैक्ट एक inheritance chain के भीतर सभी contracts के लिए initialization की अनुमति देकर इस समस्या का समाधान करता है, जबकि अभी भी initialization transaction के बाद initializers को कॉल किए जाने से रोकता है।
Initializable.sol को समझना
Initializable.sol के मुख्य भाग (core) में तीन modifiers होते हैं: initializer, reinitializer और onlyInitializing, और दो state variables होते हैं: _initializing और _initialized।
प्रत्येक modifier का उपयोग केवल एक विशिष्ट परिदृश्य (scenario) में किया जाता है और यह एक अलग उद्देश्य पूरा करता है। इनके उपयोग का अवलोकन इस प्रकार है:
initializermodifier का उपयोग upgradable contract के शुरुआती deployment के दौरान किया जाना चाहिए और विशेष रूप से childmost (सबसे निचले स्तर के) कॉन्ट्रैक्ट में किया जाना चाहिए।reinitializermodifier का उपयोग implementation contract के नए वर्ज़न्स को initialize करने के लिए किया जाना चाहिए, और यह भी केवल childmost contracts के भीतर।onlyInitializingmodifier का उपयोग parent initializers के साथ initialization के दौरान चलाने के लिए किया जाता है और यह उन initializers को बाद के transaction में कॉल किए जाने से रोकता है। यह पिछले भाग में बताई गई समस्या का समाधान करता है, जहाँ childmost initializer द्वारा उन्हें disable करने के कारण parent initializers नहीं चल सकते थे। इस स्कीम के साथ, सभी parent contracts के साथ-साथ childmost contract को initialize करना संभव है।
नीचे इन परिदृश्यों (scenarios) को दर्शाने वाला एक विज़ुअल आरेख (visual diagram) दिया गया है। इन modifiers के उपयोग की अधिक विस्तृत व्याख्या अगले अनुभागों में प्रदान की जाएगी।

Initializable.sol ERC-7201 पैटर्न को लागू करता है, जहाँ state variables को एक struct के भीतर घोषित किया जाता है। यदि आप इस पैटर्न से अवगत नहीं हैं, तो बस _initializing और _initialized को state variables मानें।
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
_initializing variable एक boolean है जो यह दर्शाता है कि क्या कॉन्ट्रैक्ट initialization की प्रक्रिया में है, जबकि _initialized variable कॉन्ट्रैक्ट के वर्तमान वर्ज़न को स्टोर करता है। यह वैल्यू 0 से शुरू होता है और पहले initialization के बाद 1 हो जाएगा। यह अधिक हो सकता है यदि डेवलपर्स एक नया implementation डिप्लॉय करना चुनते हैं और storage variables को नई वैल्यूज़ पर “reinitialize” करना चाहते हैं।
नीचे दिया गया वीडियो दर्शाता है कि ये हिस्से एक साथ कैसे काम करते हैं:
Initializer modifier
initializer modifier इस प्रकार है। कोड के कुछ हिस्सों को बाद में अधिक विस्तार से समझाया जाएगा।

उपरोक्त कोड पिछले वर्ज़न्स के साथ backward compatibility के मुद्दों को संबोधित करने की आवश्यकता के कारण सीधा (straightforward) नहीं है। हालाँकि, मुख्य विचार के दो पहलू हैं:
- फ़ंक्शन को फिर से निष्पादित (executed) होने से रोकने के लिए
_initializedvariable को1पर सेट करें (हरा बॉक्स)। - अस्थायी रूप से parent initializers, जिन्हें
onlyInitializingके साथ मॉडिफाई किया गया है, को चलने दें जब तक_initializingtrue है। जैसा कि उपरोक्त कोड में देखा जा सकता है,_initializingfalse होता है जब कॉन्ट्रैक्ट को initialize नहीं किया गया हो, true होता है जब initialization transaction चल रहा हो, और false होता है जब initialization transaction समाप्त हो जाता है।
चूंकि initializer के लिए _initializing का false होना आवश्यक है, इसका उपयोग inheritance chain के भीतर parent contracts में नहीं किया जा सकता है, क्योंकि जब ये निष्पादित (executing) हो रहे होते हैं तो _initializing true होता है। इसके बजाय, parent contracts के initialization फ़ंक्शंस को एक अलग modifier का उपयोग करना चाहिए, विशेष रूप से onlyInitializing, जो फ़ंक्शन को केवल तभी निष्पादित (execute) करने की अनुमति देता है जब _initializing true हो।
onlyInitializing modifier
onlyInitializing modifier को parent contracts में उपयोग के लिए डिज़ाइन किया गया है, क्योंकि यह केवल तभी निष्पादित होता है जब _initializing true होता है, जैसा कि नीचे दिखाया गया है।
modifier onlyInitializing() {
_checkInitializing();
_;
}
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing(); // reverts if _initializing is false
}
}
नीचे इस फ्लो का विज़ुअल प्रतिनिधित्व (visual representation) दिया गया है।

संक्षेप में कहें तो, parent initializers onlyInitializing modifier द्वारा सुरक्षित होते हैं जो उन्हें कॉल किए जाने से रोकता है जब तक कि childmost contract का initializer वर्तमान में निष्पादित न हो रहा हो।
reinitializer modifier
reinitializer modifier initializer के समान ही भूमिका निभाता है, लेकिन इसका उपयोग implementation contract के नए वर्ज़न्स को initialize करने के लिए किया जाना चाहिए यदि किसी नए वर्ज़न को initialization के समय storage variables को अपडेट करने की आवश्यकता है।
इस modifier में एक uint64 argument होता है जो एक कॉन्ट्रैक्ट वर्ज़न को इंगित करता है, जो वर्तमान वर्ज़न से अधिक होना चाहिए। यदि कोई भविष्य के reinitialization को रोकना चाहता है, तो वर्ज़न को या type(uint64).max पर सेट किया जा सकता है। Variable को uint64 बनाने से _initializing boolean variable को उसी स्लॉट में पैक (pack) किया जा सकता है, और वर्ज़न्स भविष्य के अपग्रेड के लिए पर्याप्त जगह छोड़ते हैं। यहाँ reinitializer modifier का कोड दिया गया है।
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
आइए एक उदाहरण के साथ इसके उपयोग को स्पष्ट करें। मान लीजिए कि एक ERC20Upgradeable कॉन्ट्रैक्ट के पहले अपग्रेड में, हम टोकन का नाम और सिंबल बदलना चाहते हैं। यह फ़ंक्शन इस प्रकार लिखा जाना चाहिए, जहाँ वैल्यू 2 यह इंगित करता है कि यह कॉन्ट्रैक्ट का दूसरा वर्ज़न है:
function initialize() reinitializer(2) public {
__ERC20_init("MyToken2", "MTK2");
}
अपग्रेड के साथ कैसे आगे बढ़ना है, इसे संक्षेप में बताने के लिए:
- आप किसी नए वर्ज़न पर
initializerका उपयोग नहीं कर सकते हैं। - आपको
reinitializerका उपयोग करना होगा यदि आप किसी initialization फ़ंक्शन में कोई state variables बदलना चाहते हैं। - वैकल्पिक रूप से, यदि आपको अपग्रेड के दौरान state में परिवर्तन करने की आवश्यकता नहीं है, तो आपके पास कोई initializer नहीं हो सकता है।
Uninitialized contracts vulnerability (भेद्यता)
Modifier initializer में, कोड की एक लाइन है जिसने शायद आपका ध्यान आकर्षित किया हो, लेकिन मैंने अपने शुरुआती स्पष्टीकरण में इसका उल्लेख नहीं किया। यह इस प्रकार है:
bool construction = initialized == 1 && address(this).code.length == 0;
व्यंजक (expression) address(this).code.length == 0 केवल कॉन्ट्रैक्ट डिप्लॉयमेंट के दौरान सत्य (true) होता है। इसलिए, construction variable केवल तभी true हो सकता है जब initializer modifier का उपयोग एक constructor में किया जा रहा हो।
वास्तव में, implementation contract के constructor में initializer modifier का उपयोग इसे “initialize” करने के लिए किया जा सकता है। यह उल्टा (counterintuitive) लग सकता है क्योंकि implementation contract के storage का कोई महत्व नहीं होना चाहिए। हालाँकि, जैसा कि हम देखेंगे, यह initialization एक सुरक्षा उपाय (security measure) के रूप में कार्य करता है।
Uninitialized contracts से जुड़ी UUPS vulnerability
महत्वपूर्ण बात यह है कि किसी कॉन्ट्रैक्ट का initialization फ़ंक्शन public होता है और इसे proxy के माध्यम से या सीधे किसी EOA या किसी अन्य कॉन्ट्रैक्ट से कॉल किया जा सकता है, जैसा कि नीचे दिए गए चित्र में दिखाया गया है। Upgradeable Ownable contracts में, owner को आमतौर पर initialize फ़ंक्शन में सेट किया जाता है।
- यदि
initializeको proxy से delegatecall के माध्यम से कॉल किया जाता है, तो owner को proxy के storage में स्टोर किया जाता है। - यदि
initializeको सीधे implementation पर कॉल किया जाता है, तो owner को implementation के storage में स्टोर किया जाता है।

Implementation contract का owner होने से कोई फर्क नहीं पड़ना चाहिए, क्योंकि implementation contract पर सीधे फ़ंक्शंस को निष्पादित करने से उसका अपना storage मॉडिफाई होता है, जो ‘असली’ (real) storage नहीं है। इसी कारण से, कई टीमों ने initialize फ़ंक्शन को सीधे implementation contract पर निष्पादित करने के बारे में विचार नहीं किया।
गंभीर समस्या यह है कि onlyOwner के रूप में परिभाषित कोई भी फ़ंक्शन फिर इस ‘अन्य’ (other) owner द्वारा implementation contract पर निष्पादित किया जा सकता है।
और ठीक इसी परिदृश्य ने v4.1.0 से लेकर v4.3.1 तक OpenZeppelin के UUPS contracts में एक भेद्यता (vulnerability) को उजागर किया। एक implementation contract से दूसरे में माइग्रेट करने के लिए ज़िम्मेदार फ़ंक्शन ने भी उस नए address पर एक delegatecall निष्पादित किया।

इस फ़ंक्शन को onlyOwner modifier द्वारा सुरक्षित किया गया था और इसका उद्देश्य केवल “सही owner” (rightful owner) द्वारा निष्पादित किया जाना था। हालाँकि, इसे implementation contract के owner द्वारा भी निष्पादित किया जा सकता था।
Implementation के storage को मॉडिफाई करना समस्या नहीं थी। हालाँकि, owner अब एक ऐसे कॉन्ट्रैक्ट को delegatecall कर सकता था जिसमें selfdestruct opcode शामिल हो। यह क्रिया implementation contract के कोड को मिटा देगी, जिससे proxy को एक नए implementation में माइग्रेट करने से रोका जा सकेगा। अनिवार्य रूप से, यह भेद्यता अनिश्चित काल के लिए proxy के भीतर लाखों डॉलर की संपत्ति (assets) को लॉक कर सकती थी।
UUPS के इन लाइब्रेरी वर्ज़न्स का उपयोग करने वाला कोई भी proxy, जिनके implementation contracts “initialized” नहीं थे, जोखिम में थे। कोई भी initialization फ़ंक्शन को निष्पादित कर सकता था, owner बन सकता था, और selfdestruct opcode वाले कॉन्ट्रैक्ट को delegatecall निष्पादित कर सकता था।
Uninitialized implementation contract का स्वामित्व लेने वाले हमलावरों के खिलाफ मूल उपाय (Original mitigation)
इस समस्या को कम करने के लिए, OpenZeppelin की इंजीनियरिंग टीम की पहली सिफारिश implementation contracts को हमेशा एक constructor और initializer modifier का उपयोग करके “initialize” करने की थी, जो इस प्रकार है।
constructor() initializer {}
यह एक हमलावर को owner बनने के लिए implementation में storage variables को initialize करने से रोकने के लिए केवल एक सुरक्षा उपाय था। यह modifier एक inheritance chain के सभी implementation contracts में constructors के अंदर रखा जाना था।
Childmost contracts के लिए, variable initialSetup हमेशा true होगा। हालाँकि, implementation contracts के parent contracts में, डिप्लॉयमेंट के दौरान, initialized 1 होगा और address(this).code.length == 0 होगा। इसी परिदृश्य के लिए construction variable मौजूद है—implementation contract के parent contracts के initialization को सक्षम करने के लिए।
दूसरे शब्दों में, जिस लाइन की बात हो रही है वह नीचे दिए गए कॉन्ट्रैक्ट स्कीमा (contract schema) जैसे मामलों को ध्यान में रखकर डिज़ाइन की गई है, जहाँ parent contracts को भी initialize करने की आवश्यकता होती है। initializer modifier का उपयोग किया जाना चाहिए; onlyInitializing modifier का उद्देश्य constructors को initialize करना नहीं है।
contract ImplementationParent is Initializable {
// here initialSetup will be false
// but construction will be true
constructor() initializer {}
}
contract ImplementationChild is Initializable, ImplementationParent {
// here initialSetup will be true
constructor() ImplementationParent() initializer {}
}
एक बार जब implementation contract “initialized” हो जाता है, तो किसी के लिए भी initialization फ़ंक्शन को निष्पादित करना और कॉन्ट्रैक्ट का owner बनना संभव नहीं रहता है।
अब यह अनुशंसित (recommended) उपाय नहीं है, एक हमलावर को implementation contract का owner बनने से रोकने का अनुशंसित समाधान अगले भाग में दिखाया गया है, लेकिन initializer modifier backward compatibility के कारणों से construction variable को रखता है। यह संभव है कि इसे इस कॉन्ट्रैक्ट के भविष्य के वर्ज़न में हटा दिया जाएगा।
_disableInitializers() फ़ंक्शन
Implementation contracts को “initialize” करने के लिए OpenZeppelin द्वारा प्रस्तावित सबसे ताज़ा और अनुशंसित तरीका __disableInitializers() फ़ंक्शन का उपयोग करना है।
कोड इस प्रकार है:
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max; // set initialized to its max value, preventing reinitializations
emit Initialized(type(uint64).max);
}
}
इसलिए, वर्तमान में, “uninitialized” contracts के कारण होने वाली vulnerabilities को रोकने का अनुशंसित तरीका सभी implementation contracts में निम्नलिखित constructor को शामिल करना है:
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
Implementation contracts को स्वयं कभी भी अपग्रेड नहीं किया जाता है, केवल proxy को किया जाता है। इसलिए वर्ज़न को type(uint64).max (implementation में _initialized) पर सेट करना यह सुनिश्चित करता है कि implementation contract कभी भी initialize नहीं होगा। Implementation में initializers को लॉक करना proxy को उन्हें delegatecall करने से नहीं रोकता है, क्योंकि _initialized storage जो delegatecall को रोकेगा वह proxy में है।
_init और _init_unchained फ़ंक्शंस
Upgradeable contracts को initialize करने वाले फ़ंक्शन का कोई भी नाम हो सकता है, लेकिन OpenZeppelin contracts एक मानक (standard) का पालन करते हैं। वास्तव में, उन सभी में दो initialization फ़ंक्शंस होते हैं, जो दो नामों का उपयोग करते हैं: <Contract Name>_init और <Contract Name>_init_unchained।
<Contract Name>_init_unchained फ़ंक्शन में वह सभी कोड शामिल होता है जिसे implementation contract को initialize करते समय निष्पादित किया जाना चाहिए। उदाहरण के लिए, एक ERC20 टोकन के मामले में, यह फ़ंक्शन टोकन का नाम और सिंबल सेट करता है।
function __ERC20_init_unchained(string memory name_, string memory symbol_)
internal
onlyInitializing
{
ERC20Storage storage $ = _getERC20Storage();
$._name = name_;
$._symbol = symbol_;
}
<Contract Name>_init फ़ंक्शन <Contract Name>_init_unchained के साथ-साथ अपने उन सभी parents के लिए <Parent Contract>_init_unchained निष्पादित करता है जिन्हें initialize किया जाना चाहिए।
आइए GovernorUpgradeable.sol v5 कॉन्ट्रैक्ट के मामले पर विचार करें, जिसे स्वयं को और अपने parent contracts में से एक, EIP712Upgradeable कॉन्ट्रैक्ट को initialize करने की आवश्यकता होती है।

सामान्य तौर पर, किसी कॉन्ट्रैक्ट के _init फ़ंक्शन को निष्पादित करना पर्याप्त होता है, जो parent contracts को भी initialize कर देता है। इस बात का ध्यान रखा जाना चाहिए कि एक ही कॉन्ट्रैक्ट को दो बार initialize न किया जाए, जो एक inheritance chain में हो सकता है जहाँ दो contracts एक ही parent साझा करते हैं।
यही कारण है कि दो फ़ंक्शंस हैं, _init और _init_unchained। यदि किसी को उसके parents को initialize किए बिना किसी कॉन्ट्रैक्ट को initialize करने की आवश्यकता है, तो _init_unchained फ़ंक्शन का उपयोग किया जाना चाहिए।
एक ERC20 Upgradeable contract को Initialize करना
Upgradeable contracts को कैसे initialize किया जाए, इसका एक उदाहरण नीचे दी गई छवि में देखा जा सकता है, जो OpenZeppelin Wizard द्वारा उत्पन्न एक upgradeable ERC20 टोकन कॉन्ट्रैक्ट दिखा रहा है।

ध्यान दें कि यह अपने parents पर __<Contract Name>_init कॉल करता है। Contracts को initialize करने के लिए उपयोग की जाने वाली स्कीम की परवाह किए बिना, यह सुनिश्चित करना आवश्यक है कि inheritance chain के सभी contracts ठीक से initialized हैं और किसी भी कॉन्ट्रैक्ट को दो बार initialize नहीं किया गया है या initializers idempotent हैं।
चेतावनियाँ और सिफ़ारिशें
इस लेख को समाप्त करने से पहले, Initializable.sol कॉन्ट्रैक्ट के सही उपयोग के लिए कुछ सिफ़ारिशें दी जानी चाहिए।
- OpenZeppelin की
openzeppelin-upgradesलाइब्रेरी में Initializable.sol नाम का एक और कॉन्ट्रैक्ट है। यह कॉन्ट्रैक्ट backward compatibility के कारणों से मौजूद है और इसे नए प्रोजेक्ट्स में उपयोग नहीं किया जाना चाहिए। इसे import करने का अनुशंसित तरीकाimport "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";के माध्यम से है। - चूंकि initialization फ़ंक्शन एक नियमित फ़ंक्शन (regular function) है, इसलिए किसी अन्य transaction द्वारा इसे frontrun किए जाने का जोखिम होता है। यदि ऐसा होता है, तो proxy contract को फिर से डिप्लॉय किया जाना चाहिए। इसे रोकने के लिए, ERC1967Proxy कॉन्ट्रैक्ट का constructor डिप्लॉय के समय implementation को कॉल करता है। Initialization कॉल इसी समय की जानी चाहिए, जिसे
_datavariable में एन्कोड किया गया हो। - जैसा कि पिछले भाग में बताया गया है, जब कॉन्ट्रैक्ट एक inheritance chain का हिस्सा होता है, तो मैन्युअल रूप से यह ध्यान रखा जाना चाहिए कि किसी parent initializer को दो बार कॉल (invoke) न किया जाए। स्कीमा (schema) ऐसी संभावित समस्याओं की पहचान नहीं करता है, इसलिए सत्यापन (verification) मैन्युअल रूप से किया जाना चाहिए। इसे हल करने का एक तरीका यह सुनिश्चित करना है कि सभी initialization फ़ंक्शंस idempotent हों, जिसका अर्थ है कि उनका प्रभाव समान होता है चाहे उन्हें कितनी भी बार निष्पादित किया जाए।
मूल रूप से 8 जुलाई को प्रकाशित