6 सितंबर, 2017
May 27, 2025

देव डायरी I: सॉलिडिटी में PLCR वोटिंग का पूर्वाभ्यास

AdChain रजिस्ट्री देव टीम के नियमित देव डायरी सदस्यों की श्रृंखला में यह पहली प्रविष्टि है, जिसे आने वाले महीनों में प्रकाशित किया जाएगा। यह पहली प्रविष्टि AdChain रजिस्ट्री के आंशिक-लॉक कमिट/रिवील वोटिंग सिस्टम के बारे में है, और इसे किसके द्वारा लिखा गया था माइक गोल्डिन ConsenSys की।

AdChain रजिस्ट्री में डोमेन स्वीकार करना है या नहीं, इस पर वोट करना AdChain के प्रोत्साहन खेल का केंद्र है। इसका समर्थन करने के लिए हमने एक जेनेरिक, Apache-2 लाइसेंस प्राप्त जेनेरिक विकसित और ओपन-सोर्स किया है आंशिक-लॉक कमिट/रिवील (PLCR) वोटिंग का कार्यान्वयन, सॉलिडिटी में लिखा गया है। PLCR वोटिंग टोकन-वेटेड वोटिंग के लिए एक कुशल प्रणाली है जो उपयोगकर्ता को पोल के भीतर टोकन के दोहरे मतदान को रोकते हुए अपने टोकन के साथ एक साथ कई चुनावों में भाग लेने में सक्षम बनाती है। महत्वपूर्ण बात यह है कि यह उपयोगकर्ताओं को किसी भी समय वोटिंग के लिए सक्रिय रूप से उपयोग नहीं किए जा रहे टोकन की अधिकतम संख्या को वापस लेने की अनुमति देता है।

मूल रूप से PLCR वोटिंग का वर्णन किया गया था एरोन फिशर द्वारा एक ब्लॉग पोस्ट में के लिए लेखन कॉलोनी प्रोजेक्टऐलेना दिमित्रोवाइस कार्यान्वयन के निर्माण में इस विषय पर ब्लॉग पोस्ट को भारी रूप से संदर्भित किया गया था। हम उनके मूल कार्य के लिए उनके आभारी हैं!

PLCR वोटिंग क्यों?

सॉलिडिटी में PLCR वोटिंग को लागू करना मामूली नहीं है, तो परेशान क्यों हों? कमिट/रिवील (जो वोटिंग प्रक्रिया को वोट परिणामों को प्रभावित करने से रोकने के लिए वांछनीय है) का उपयोग करके मतदान पूरा होने से पहले वोटों की संख्या को अस्पष्ट करने के अलावा, PLCR वोटिंग दो चीजों को सक्षम बनाता है:

  1. यह उपयोगकर्ता को एक साथ कई चुनावों में भाग लेने में सक्षम बनाता है, जबकि पोल के भीतर टोकन के दोहरे मतदान को रोकता है।
  2. यह उपयोगकर्ताओं को किसी भी समय वोटिंग के लिए सक्रिय रूप से उपयोग नहीं किए जाने वाले टोकन की अधिकतम संख्या को वापस लेने की अनुमति देता है।

उदाहरण के तौर पर: एक उपयोगकर्ता PLCR वोटिंग कॉन्ट्रैक्ट में 10 टोकन लोड करता है। इसके बाद उपयोगकर्ता पोल A में 10 टोकन और पोल B में छह टोकन देता है, पोल A में खुलासा करने के बाद, छह टोकन पोल B में बंद रहते हैं लेकिन उपयोगकर्ता चार टोकन वापस ले सकता है।

एक बेवकूफ गैर-PLCR मतदान प्रणाली में, एक उपयोगकर्ता एकल पोल का वर्णन करने वाले स्मार्ट कॉन्ट्रैक्ट में टोकन लॉक कर सकता है। यह एक आदर्श समाधान नहीं है क्योंकि यह उपयोगकर्ता को एक ही टोकन के साथ एक साथ कई चुनावों में भाग लेने से रोकता है। यदि उपयोगकर्ता के टोकन किसी स्मार्ट कॉन्ट्रैक्ट में लॉक किए गए हैं, तो कोई अन्य स्मार्ट कॉन्ट्रैक्ट यूज़र से उन्हें स्वयं लॉक करने के लिए `ट्रांसफर` नहीं कर सकता है।

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

टोकन लिक्विडिटी को अधिकतम करने के लिए डेवलपर को कम से कम सॉलिडिटी में काफी जटिलता का सामना करना पड़ता है। उपयोग करना मिनीएमई टोकन है एक दृष्टिकोण। PLCR वोटिंग उन टोकन का समर्थन करती है जो MiniMe टोकन नहीं हैं।

PLC Rvoting.sol

plcrvoting.sol का एक तैनात उदाहरण एक टोकन निर्दिष्ट करता है जिसके लिए वोटिंग अधिकारों का विभाजन किया जा सकता है। उस टोकन का उपयोग करके किए जाने वाले किसी भी टोकन-भारित वोट को उसी तैनात PLCR वोटिंग कॉन्ट्रैक्ट का उपयोग करके बनाया जा सकता है, और ये पोल एक दूसरे के साथ हस्तक्षेप नहीं करेंगे। उपयोग किए जाने वाले टोकन को कंस्ट्रक्टर के लिए एकमात्र तर्क के रूप में निर्दिष्ट किया गया है।

पोल बनाना

startPoll फ़ंक्शन का उपयोग नए पोल बनाने के लिए किया जाता है। इसमें तीन तर्क लगते हैं और एक यूनिट लौटाता है। तर्क इस प्रकार हैं:

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

प्रतिबद्ध होने की अवधि: कमिट अवधि की अवधि, सेकंड में।

अवधि प्रकट करें: प्रकट अवधि की अवधि, सेकंड में।

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

function startPoll(uint _voteQuorum, uint _commitDuration, uint _revealDuration) public returns (uint pollID) {
  pollNonce = pollNonce + 1;

  pollMap[pollNonce] = Poll({
    voteQuorum: _voteQuorum,
    commitEndDate: block.timestamp + _commitDuration,
    revealEndDate: block.timestamp + _commitDuration + _revealDuration,
    votesFor: 0,
    votesAgainst: 0
  });

  PollCreated(pollNonce);
  return pollNonce;
}

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

अंत में हम PollNonce के साथ एक pollnOnce ईवेंट को सक्रिय करते हैं, और PollnOnce को बाद में इस पोल के pollID के रूप में उपयोग करने के लिए वापस करते हैं। बहुत आसान है!

अगली तार्किक बात जो पोल बनने के बाद हो सकती है, वह यह है कि कोई व्यक्ति उस पोल में वोट करना पसंद कर सकता है। इस प्रक्रिया के कुछ चरण हैं, जो RequestVotingRights से शुरू होते हैं।

वोटिंग के अधिकार का अनुरोध करना

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

function requestVotingRights(uint numTokens) external {
  require(token.balanceOf(msg.sender) >= numTokens);
  require(token.transferFrom(msg.sender, this, numTokens));
  voteTokenBalance[msg.sender] += numTokens;
}

में पहली पंक्ति फ़ंक्शन बॉडी के बारे में हम जांचते हैं कि संदेश प्रेषक का वास्तविक टोकन बैलेंस प्रदान किए गए numTokens तर्क के सापेक्ष पर्याप्त है। द निम्नलिखित पंक्ति TransferFrom को कॉल करता है, NumTokens को संदेश प्रेषक के संतुलन से PLCR अनुबंध के संतुलन में ले जाता है। पहली लाइन एक निरर्थक जाँच है: दूसरी आवश्यकता कथन किसी भी स्थिति में त्रुटि उत्पन्न करेगा जहाँ पहली बार किया गया था। यह सिर्फ रक्षात्मक प्रोग्रामिंग है, क्योंकि लोग इस अनुबंध का उपयोग बग्गी ERC-20 कार्यान्वयन के साथ कर सकते हैं (हालांकि ऐसा करने का कोई बहाना नहीं है जब अच्छा कार्यान्वयन मौजूद हैं)।

यह भी ध्यान दें कि यदि उपयोगकर्ता ने RequestVotingRights को कॉल करने से पहले NumTokens को स्थानांतरित करने के लिए PLCR अनुबंध को मंजूरी नहीं दी है, तो TransferFrom विफल हो जाएगा। यह दुखद है और “अनुमोदन और कॉल” पैटर्न में सुधार करने के प्रस्ताव हैं, लेकिन वे अभी तक व्यापक रूप से लागू नहीं हुए हैं।

अंत में, यदि पहली दो पंक्तियाँ सफल होती हैं, तो हम NumTokens द्वारा संदेश प्रेषक के voteTokenBalance को बढ़ाएं। वाह। हम अभी वोट कर सकते हैं। हम अब सब कुछ वापस भी ले सकते हैं, क्योंकि प्रबंधित किए गए किसी भी टोकन को अभी तक पोल में लॉक नहीं किया गया है।

वोट देना

कमिट-रिवील एक पैटर्न है जिसका इस्तेमाल ईएनएस में बोलियों को छुपाने के लिए किया जाता है, और इसका इस्तेमाल गुप्त बैलेटिंग के लिए भी किया जा सकता है। प्रतिबद्ध वोट एक ऐसा वोट होता है नमकीन हैश उपयोगकर्ता के वोट का, जिसका अर्थ है कि उपयोगकर्ता की प्राथमिकता (हाँ या नहीं) को हैश और प्रतिबद्ध होने से पहले कुछ यादृच्छिकता (नमक) के साथ जोड़ा जाता है। कमिटवोट निम्नलिखित तर्क लेता है:

पोल आईडी: वोट किए जा रहे पोल की आईडी (मूल रूप से StartPoll के किसी आमंत्रण में लौटाई गई)

सीक्रेट हैश: मतदाता की पसंद का keccak256 हैश और नमक (कसकर पैक किया हुआ और क्रम में)

NumTokens: इस वोट के लिए मतदान के लिए प्रतिबद्ध टोकन की संख्या

पिछला:पोल आईडी: पोल का आईडी जिसके लिए उपयोगकर्ता के पास वर्तमान में प्रतिबद्ध NumTokens से कम या उसके बराबर टोकन की सबसे बड़ी संख्या है (हम इसके बारे में बाद में बात करेंगे)।

ठीक है, आइए फंक्शन बॉडी को देखें। सबसे पहले हम कुछ जाँचें करने जा रहे हैं। हम यह सुनिश्चित करने के लिए एक सहायक फ़ंक्शन को कॉल करेंगे कि प्रदान किए गए polid के लिए प्रतिबद्ध अवधि सक्रिय है, कि संदेश भेजने वाले का voteTokenBalance कम से कम पास किया गया NumTokens मान है, और यह कि प्रदान किया गया polID शून्य नहीं है।

विषयांतर: हम पोलआईडी शून्य के लिए पोल को विशेष रूप से क्यों मानते हैं? हमने पहले उल्लेख किया था कि StartPoll में PollnOnce zero के लिए कभी भी PollID नहीं होगा, और यहाँ हम विशेष रूप से जाँच करते हैं कि PollnOnce शून्य पर मतदान के लिए वोट प्रतिबद्ध नहीं किए जा रहे हैं। EVM में, सभी डेटा को शून्य पर इनिशियलाइज़ किया जाता है। यदि आप एक uint x घोषित करते हैं और इसे इनिशियलाइज़ नहीं करते हैं, तो (x == 0 && x == false) सही होगा। PLCR वोटिंग कॉन्ट्रैक्ट के साथ इंटरफेस करने वाले स्मार्ट कॉन्ट्रैक्ट के लिए, ID शून्य पर पोल को एक प्रकार के शून्य मान के रूप में संदर्भित करना उपयोगी हो सकता है। उदाहरण के लिए, AdChain रजिस्ट्री में, पोलिड को उन सूचियों के साथ संग्रहीत किया जाता है जिन्हें चुनौती दी गई है। डिफ़ॉल्ट रूप से इन्हें शून्य पर इनिशियलाइज़ किया जाएगा। अगर हम यह जान सकें कि पोलआईडी शून्य वाली लिस्टिंग में एक अलग बूलियन को स्टोर करने के बजाय कोई सक्रिय चुनौती नहीं है, तो यह कारगर है। इस कारण से हम इंडेक्स 0 पर पोल को अप्रयुक्त रखना चाहते हैं।

ठीक है, इसलिए हमने अपने चेक खत्म कर दिए। अब हम कुछ मजेदार करने जा रहे हैं और अपनी डबल लिंक की गई सूची पेश करेंगे।

द डबली लिंक्ड-लिस्ट

PLCR वोटिंग कॉन्ट्रैक्ट उपयोग करता है डबली-लिंक्ड सूचियां यह ट्रैक करने के लिए कि उपयोगकर्ताओं ने किन चुनावों में टोकन प्रतिबद्ध किए हैं। डबली-लिंक्ड सूची को लागू करना कंप्यूटर विज्ञान की बड़ी कंपनियों के लिए एक नए साल का होमवर्क असाइनमेंट है, लेकिन सॉलिडिटी में इसे लागू करना पायथन में ऐसा करने की तुलना में अधिक चुनौतीपूर्ण है, क्योंकि सॉलिडिटी एक ऐसी निम्न-स्तरीय भाषा है। डबल-लिंक्ड सूची वह है जो हमें उन यूज़र के लिए अधिकतम संभव टोकन को कुशलतापूर्वक रिलीज़ करने की सुविधा देती है, जो अपने वोटिंग अधिकारों को वापस लेना चाहते हैं और जिनके पास कई चुनावों में टोकन प्रतिबद्ध हैं, उनके पास कुल टोकन से कम टोकन हैं, जिनके लिए उनके पास वोटिंग अधिकार हैं।

library DLL {
	struct Node {
		uint next;
		uint prev;
	}

	struct Data {
		mapping(uint => Node) dll;
	}

	function getNext(Data storage self, uint curr) returns (uint) {
		return self.dll[curr].next;
	}

	function getPrev(Data storage self, uint curr) returns (uint) {
		return self.dll[curr].prev;
	}

	function insert(Data storage self, uint prev, uint curr, uint next) {
		self.dll[curr].prev = prev;
		self.dll[curr].next = next;

		self.dll[prev].next = curr;
		self.dll[next].prev = curr;
	}

	function remove(Data storage self, uint curr) {
		uint next = getNext(self, curr);
		uint prev = getPrev(self, curr);

		self.dll[next].prev = prev;
		self.dll[prev].next = next;

		self.dll[curr].next = curr;
		self.dll[curr].prev = curr;
	}
}

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

PLCR वोटिंग में प्रति उपयोगकर्ता एक डबल-लिंक्ड सूची होती है, उपयोगकर्ता के msg.sender पते का उपयोग करके संबोधित किया गया। उपयोगकर्ता DLL में एक नोड एक polID से मेल खाता है। DLL को हमेशा नोड्स के अनुरूप पोल के लिए उपयोगकर्ता द्वारा किए गए टोकन की संख्या के आधार पर क्रमबद्ध किया जाता है। डेटा को स्वयं नोड्स से अलग संग्रहीत किया जाता है और इसका उपयोग करके इसका समाधान किया जाता है उपयोगकर्ता पते और नोड आईडी का हैशेड कॉन्सटेनेशन पूर्णांकों की स्ट्रिंग-कीड मैपिंग में अनुक्रमित करने के लिए जिसे एक कहा जाता है एट्रिब्यूटस्टोर

library AttributeStore {
    struct Data {
        mapping(bytes32 => uint) store;
    }

    function getAttribute(Data storage self, bytes32 UUID, string attrName) returns (uint) {
        bytes32 key = sha3(UUID, attrName);
        return self.store[key];
    }

    function attachAttribute(Data storage self, bytes32 UUID, string attrName, uint attrVal) {
        bytes32 key = sha3(UUID, attrName);
        self.store[key] = attrVal;
    }
}

स्पष्ट करने के लिए: एक उपयोगकर्ता पता एक विशिष्ट DLL को संबोधित करता है। एक NodeID एक DLL में एक विशिष्ट नोड को संबोधित करता है, लेकिन क्योंकि NodeIds polliDS के अनुरूप होते हैं, इसलिए कई DLL में समान NodeID वाले नोड हो सकते हैं। एक उपयोगकर्ता पते को NodeID और हैशिंग के साथ जोड़कर, हमें स्मृति में एक अद्वितीय स्थान मिलता है जहाँ हम डेटा ढूंढ सकते हैं। डेटा को नोड्स से अलग स्टोर करने का कारण यह है कि हमें सभी नोड्स के लिए केवल एक मैपिंग स्टोर करने की आवश्यकता होती है, जबकि प्रति नोड एक मैपिंग के विपरीत। मैपिंग की घोषणा, भले ही मैपिंग खाली हो, स्टोरेज का उपयोग करती है।

DLL कैसे काम करता है इसका मूल अवलोकन यही है। आइए देखें कि CommitVote कैसे काम करता है और देखें कि हम व्यवहार में DLL का उपयोग कैसे करते हैं।

वोट देना, जारी रखा

ऑन लाइन 102 हमने getNext विधि के परिणाम के लिए nextPolliD नामक एक यूंट सेट किया है, जो msg.sender के DLL की एक विधि है, जो एक तर्क prevPollID लेता है। prevPolliD नोड की आईडी है जो हमारे द्वारा डाले जा रहे नए नोड का पिछला नोड होगा। nextPolliD तब हमारे द्वारा डाले जा रहे नए नोड का अगला नोड होगा, क्योंकि यह prevPollID के बाद जाएगा और इसलिए इससे पहले नेक्स्टपोल आईडी।

function commitVote(uint pollID, bytes32 secretHash, uint numTokens, uint prevPollID) external {
  require(commitPeriodActive(pollID));
  require(voteTokenBalance[msg.sender] >= numTokens); // prevent user from overspending
  require(pollID != 0);                // prevent user from committing to zero node placerholder

  uint nextPollID = dllMap[msg.sender].getNext(prevPollID);

  require(validPosition(prevPollID, nextPollID, msg.sender, numTokens));
  dllMap[msg.sender].insert(prevPollID, pollID, nextPollID);

  bytes32 UUID = attrUUID(msg.sender, pollID);

  store.attachAttribute(UUID, "numTokens", numTokens);
  store.attachAttribute(UUID, "commitHash", uint(secretHash));
}

हम उपयोगकर्ता को prevpolid मान प्रदान करने के लिए क्यों कहते हैं? हम सकता है सही PrevPolid खोजने के लिए सूची के माध्यम से खोजें, लेकिन बहुत लंबी सूचियों में हम ऐसा करने से गैस की सीमा को समाप्त कर सकते हैं। बेहतर होगा कि यूज़र को कॉल में ऑफ-चेन करने दें और फिर उसे प्रदान करें ताकि ट्रांजेक्शन निरंतर समय में चल सके।

लाइन 104 निरंतर समय में जाँच करता है कि क्या प्रदान किया गया PrevPolid नए पोल में किए जा रहे टोकन की संख्या को देखते हुए वैध था या नहीं। सूची को अनसॉर्ट किया जाना संभव नहीं होना चाहिए। यदि चेक पास हो जाता है, तो चालू लाइन 105 हम नया नोड डालते हैं!

हमने एक नोड डाला है, लेकिन ध्यान दें कि हमने वास्तव में अभी तक डेटा नहीं जोड़ा है। चालू है लाइन 107 हम एक सहायक का उपयोग करेंगे फंक्शन एट्रीयूआईडी एक नई सार्वभौमिक रूप से अद्वितीय आईडी बनाने के लिए जो उपयोगकर्ता पते और नोडआईडी का sha3 हैश है। आखिरकार हम पोल के लिए प्रतिबद्ध टोकन की संख्या और हमारे वोट के सीक्रेट हैश को स्टोर करते हैं।

वाह, यह मुश्किल था!

वोट का खुलासा करना

अब जब हम जानते हैं कि कमिट कैसे काम करता है, तो खुलासा करना वास्तव में अपेक्षाकृत आसान होगा। हमने इस बिंदु पर सभी कठिन चीजें सीख ली हैं, तो चलिए इस पर एक नज़र डालते हैं वोट प्रकट करें! RevealVote में तीन तर्क होते हैं:

पोल आईडी: पोल आईडी के लिए पोल आईडी का खुलासा किया जा रहा है।

वोट का विकल्प: पोल में उपयोगकर्ता की पसंद। 1 वोट के लिए है, 0 के खिलाफ वोट है।

नमक: कमिटवोट से सीक्रेटहैश का उत्पादन करने के लिए VoteOption से जुड़ी यादृच्छिक संख्या।

आप इस समय ब्लॉक के आसपास रहे हैं, इसलिए आप जानते हैं कि हम पहले क्या करेंगे: जाँचें। हम जांच करेंगे कि प्रदान किए गए पोलआईडी की प्रकट अवधि सक्रिय है, जिसे उपयोगकर्ता ने इस पोल के लिए पहले से प्रकट नहीं किया है, और हम यह सुनिश्चित करेंगे कि प्रदान किया गया वोट विकल्प और नमक वास्तव में सीक्रेटहैश से मेल खाते हैं, जो दो वस्तुओं के sha3 हैश की गणना करके और परिणाम की तुलना उपयोगकर्ता के DLL में संग्रहीत SecretHash से करके किया गया था।

function revealVote(uint pollID, uint voteOption, uint salt) external {
  // Make sure the reveal period is active
  require(revealPeriodActive(pollID));
  require(!hasBeenRevealed(msg.sender, pollID));                        // prevent user from revealing multiple times
  require(sha3(voteOption, salt) == getCommitHash(msg.sender, pollID)); // compare resultant hash from inputs to original commitHash

  uint numTokens = getNumTokens(msg.sender, pollID); 

  if (voteOption == 1) // apply numTokens to appropriate poll choice
    pollMap[pollID].votesFor += numTokens;
  else
    pollMap[pollID].votesAgainst += numTokens;

  dllMap[msg.sender].remove(pollID); // remove the node referring to this vote upon reveal
}

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

अंत में चालू लाइन 147 हम करेंगे नोड को हटा दें उपयोगकर्ता के DLL में इस पोल के लिए

वाह, यह आसान था!

कौन जीता?

ठीक है, तो एक पोल के प्रकट होने की अवधि समाप्त हो गई है और हम जानना चाहते हैं कि यह कैसा रहा। यह बहुत आसान है। द ISPassed फ़ंक्शन एक तर्क के रूप में एक polID लेता है और सही लौटाता है अगर के खिलाफ वोटों के सापेक्ष कोरम की आवश्यकता को पूरा करने के लिए वोटों की संख्या। एक समय में पोल पास नहीं होता है। ध्यान दें कि कोरम की आवश्यकता कुल टोकनों का कोरम नहीं है, जो ज़रूरी वोट, यह केवल टोकन का एक कोरम है किया था वोट।

हमारे टोकनों को बाहर ले जाना

यह वह हिस्सा है जिसके लिए हमने बहुत मेहनत की है। मान लें कि हमारे पास 10 टोकन के लिए वोटिंग अधिकार हैं, लेकिन वर्तमान में उनमें से केवल सात ही पोल के लिए प्रतिबद्ध हैं। उपयोग करना वोटिंग अधिकार वापस लें हमें तीन को बाहर निकालने में सक्षम होना चाहिए। WithdrawVotingRights एक तर्क के रूप में लेता है कि हम कितने टोकन वापस लेना चाहते हैं।

function withdrawVotingRights(uint numTokens) external {
  uint availableTokens = voteTokenBalance[msg.sender] - getLockedTokens(msg.sender);
  require(availableTokens >= numTokens);
  require(token.transfer(msg.sender, numTokens));
  voteTokenBalance[msg.sender] -= numTokens;
}

जादू चालू रहता है लाइन 69। हम उपयोगकर्ता के VoteTokenBalance के परिणाम को घटाकर वापस लेने के लिए उपलब्ध टोकन की गणना करते हैं हेल्पर फंक्शन getLockedTokens उपयोगकर्ता पते को एक तर्क के रूप में लेना यह दूसरे को लपेटता है सहायक फ़ंक्शन getNumTokens जो तर्क के रूप में हमारे उपयोगकर्ता पते और किसी अन्य के परिणाम को लेता है हेल्पर फंक्शन getLastNode

अब इस बारे में सोचें: हमारा DLL हमेशा पोल के लिए प्रतिबद्ध टोकन की संख्या के आधार पर सॉर्ट किया जाता है। getLastNode उपयोगकर्ता के DLL के लिए नोड शून्य (रूट नोड) को अनुक्रमित करता है और पिछला नोड प्राप्त करता है, जो वह पोल होना चाहिए जिसके लिए उपयोगकर्ता के पास सबसे बड़ी संख्या में टोकन लॉक किए गए हैं। उपयोगकर्ता द्वारा PLCR अनुबंध में लोड किए गए टोकन की कुल संख्या से उस संख्या को घटाकर, हम जानते हैं कि वे कितने निकाल सकते हैं।

DLL के साथ हमने जो भी मेहनत की, हमने उसके लिए की।

बैक इन विदड्रॉल वोटिंग राइट्स, यह सब बहीखाता है: हम उपयोगकर्ता को टोकन वापस भेजते हैं और उनके voteTokenBalance को घटाते हैं।

और बस इतना ही!

उम्मीद है कि यह पूर्वाभ्यास आपकी यह समझने में मददगार रहा होगा कि हमारा PLCR वोटिंग कॉन्ट्रैक्ट कैसे काम करता है! अपनी सभी टोकन-वोटिंग ज़रूरतों के लिए इसका इस्तेमाल करने में संकोच न करें!

ConsenSys 2017 इंटर्न के लिए बड़े पैमाने पर प्रॉप्स योर्क रोड्स, केम ओज़र और एस्पिन पैलेटनिक PLCR वोटिंग के सपने को हकीकत बनाने के लिए इस गर्मी में इतनी मेहनत करने के लिए।