From 99eb9196d0a88feba09efe3c70adda3af09b207a Mon Sep 17 00:00:00 2001 From: German Nikolishin Date: Tue, 2 Aug 2022 01:46:41 +0100 Subject: [PATCH] docs and readme --- README.md | 70 +++++++++++++++++++++++---- assets/q-voting.png | Bin 0 -> 21905 bytes pallets/slashing-voting/src/lib.rs | 59 ++++++++++++++-------- pallets/slashing-voting/src/types.rs | 4 +- 4 files changed, 102 insertions(+), 31 deletions(-) create mode 100644 assets/q-voting.png diff --git a/README.md b/README.md index da853c1..216d479 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,41 @@ # Vote Pray Love +[![Check Set-Up & Build](https://github.com/SkymanOne/vote-pray-love/actions/workflows/check.yml/badge.svg)](https://github.com/SkymanOne/vote-pray-love/actions/workflows/check.yml) Polkadot Blockchain Academy 2022 Cohort Final Exam Project. -## Milestones -- [x] Basic quadratic voting system -- [x] Anonymous quadratic system (commit-reveal) -- [x] Staking -- [x] Slashing -- [x] Caching-out -- [ ] Tests & Mocks +## Summary +This is a pallet quadratic voting pallet based off substrate [collective pallet](https://marketplace.substrate.io/pallets/pallet-collective/). +The additional feature is the slashing mechanism which provides an incentive for voters to collaborate in the decision making process. + +**NOTE**: *This is an experimental pallet, no research has not conducted to actually prove economic costs of this governance system.* -## Potential idea for anonymous voting +## Idea + +The idea behind is to introduce the quadratic voting, make it anonymous and slash-reward the voters. Let's break it down. +* Any account with identity can join a voting council to be a part of governance +* When the user joins the council, fixed amount of voting tokens is allocated the account +* The user must reserve some currency to have skin in a game +* When the proposal is created, the length in blocks is specified +* The voters submits votes anonymously. The votes are measured on a quadratic scale +* When the voting is over, the reveal phase begins +* Voters have limited time to reveal their actual votes +* Votes are calculated and the result is deduced +* If the voter is in minority (i.e. on the losing side). 10% of their stake is slashed and deposited to the *"pot"* +* If the voter is in majority, they receive even proportion of the reward from the *"pot"* +* If the vote is a tie, both parties get slashed and the money go to proposer +* Once the voter has finished all proposal, they can leave the organisation and *cash out* + +## Motivation +The classical voting system has very little incentive for voters. The average vote turn-up does not exceed 10%. These ratio can not provide the true representation of opinion of the population. Therefore, the additional incentive has to be provided. I was interested in running this sort of system as a game theory experiment to see +how voters behave under such incentive. + +Anonymous voting ensures that voters make choice motivated by personal choice and rationally and not profit-seeking. +The slashing ans reward system incentives voters to actually participate in the voting process while quadratic voting system has benefits of allowing voters to express strong preference of their choice. Quadratic voting has a linear dependency and not tied to the economic influence of particular entity. +![](assets/q-voting.png) + +Different solution for anonymous voting have been considered. Here is the summary of the main two: + +### Shared public key 1. Author creates a proposal and generates a keypair for this proposal 2. The public key of the proposer is distributed to voters @@ -22,12 +47,39 @@ If the proposer reveals results before the timeout -> slashing If the proposer tries to inside-trade the intermediate vote results -> no solution, might be worth using nominating random voters to generate keypairs and use multi-sigs to collectively reveal the results -## Potential idea for anonymous voting 2 +### Commit and Reveal 1. Author publishes a proposal 2. The voters commit their decision 3. Once timeout is out, the voters have some time to reveal their choices 4. If the voters does not reveal their results -> slashing +While the first approach may seem more convenient for the voter since they only need to submit a single transaction to represent a vote, it harm the global integrity of a governance protocol. The voter can simply inside-trade the actual votes and give away votes of other voters before the end of voting phase. The *commit and reveal* approach ensures trustlessness of a solution, hence, a suitable solution. + +While it may seem a burden for user and proposer, the economic incentive actually motivates any voter to end the *commit* phase and *reveal* phase ASAP to potentially collect reward from voting. + +## Objectives +A summary of what has been implemented and what's planned: +- [x] Basic quadratic voting system +- [x] Anonymous quadratic system (commit-reveal) +- [x] Staking +- [x] Slashing +- [x] Caching-out +- [x] Docs +- [ ] Tests & Mocks + +## Running +Simply run script `build-run.sh` script to build a chain in release mode and run a dev node. +Otherwise, `/scripts` contains additional scripts to run your chain in docker. + +Refer to [substrate setup instructions](docs/substrate-setup.md) to start hacking + +### Account commit signatures for voting +* Alice - Yes - salt: `10` - `f26b35c9565f76a01b06ac1dd80832027a59306de8ac31b1019dff75890ec76c3376fb11985323f75788750a9c9ec0e17fc26440a49914d00ff2b7ef2d1a588f` +* Bob - No - salt: `10` - `b67cec01fabdc17233dc1080f09c4ffb86d0f19077f6c4f601f951a7f5a851175d127bb64142a24074596e2496388a9f01b00cd3a9db21a458e76757deda8585` + +[Gist for generating signatures](https://gist.github.com/SkymanOne/b74096c4845e0af69b17fefb25eabf92) + ## Resources +[Quadratic voting](https://www.economist.com/interactive/2021/12/18/quadratic-voting) [Commit - reveal](https://karl.tech/learning-solidity-part-2-voting/) diff --git a/assets/q-voting.png b/assets/q-voting.png new file mode 100644 index 0000000000000000000000000000000000000000..0d5779244b5cd7175ed0938c9086583ea9d56aba GIT binary patch literal 21905 zcmc$`XH-*N*EYHn0t65Vpdh^oCU@qxdQ5bW6l2tl|6{4jza@O2yv zA_Bi*g!gdp|9(mY!x8=WZx}VPqtZez4UvvP5%(w+A}?fxd=Fn1UKR zMNH9;QAKvx=(#7sv3=CaX&ii+xnW$tPgKp@*#-YB%wMT~N6TPmK*obBn-t_=a}f=$P3f&1g0YcdU{W@bObAs7-3!BH3p z!4CdJJVmcJ55z?%{NK00r}2;iBo6=Qg8#V|t^#qe-=oy_=J?n5F{oylf4zjT7-}>U zX&k0!@$W~lBOX!x>xpRgdk7R9J~XXQ|NpE4e2j#R6a9BlgsYL4U{5d@QHjCu|19)B zcTj-#|NRp2|HHDd<>W9@);bdsO2(PPIuq7l{x+rIpx(F~{#gn3=n(6e@skm(?&sCr zsW*d?A5|>v{|;q(Z2PjmNpN}7s!(+Hs!GTC*3VOp0bbG%e=H+w99D&wX`^pfSLMW- z4!<@%Wmy+?stD@6rP@@L?fl@87@}5z{rc3fMIJP7{{%Bhe=AVvvDkH5tv4uCfO>Sp z2U9w>TUSWanz#prn#P22JsOA$`GE+{l)p`frMZFho(3E!Jgki2r6pe^SMb=*s>{CH zYYhsIn6b@tmY`K4kB#}^j%oACXGxCLJFIT7><;>K^VcXOM}*=JsN9q#GVah!~Rwr49>_aw72)Sqnp!E>7!^Xg-~`{E=IKQf;CG z`?b5&w}l^1v1yL&n=`tw(xl61n-9I3{iViAV_c?B*PiCFTtPP1o)cocR_7Gk6^g$} z>Urc{eqXCCP{1oaFf{S3udj=DE_MA{6fA2$WASHnUS7uDZhIL=rJVAS{Yl`^F;(e#fmY;ri z^(}wN`Avp{;Hqy%RS}UKFxl% zUuS2sDInAK=A+gZPp$eB>t3=P=||IAt5glto&0gGGl9;}>J?`_ztb4(4fzC~c2iZX z`)*tHow?}kVW&)~1?%+WbXeDFEQfmhJC-hK|I|Ah8j-4OonsTsOt5%(CKffa72fYY zcG*BXHXx;z`<~>Dh=c^#ChKm)h>zAE-=Ak|GAvDLdvZZ~fmtp#M_Sd_`cAondINuG z{YodBh@6z2+o8~zx_PKP|H1CnDih0gw9zxQG)=}|Tau@owG9f3b-mxfWUZax?vAx`_4in$UJCt;ODfOQ)ply!Cp;LdcJI-I+aPQ^gE^R(1Qi zKa5PJ_oDC(>;6XE0hWGKvD#9uwb@!W$BCzFES{G;e;$u7`e~E;{Mz!LihLIkkoatS zPu4*y^-XTN`jO}Jx4dk@tfOAcA=+jEJ!A>rf*ZrPy_-@*q}+%y_LDX|8x+lsXZ)f? zVWgH*aqrv9)GhY~X&P%T&U-@e9e0h>Bg`pzR zYrWy`R{IOrTB>$$#g=DUlL0;N&FHdA4ty)Ft>ShQdCIhEY>$`wA}Q9ZMPI9CA!0|8 z!|i!aJ!;(a=Dq7r&H}j}j4~K=<;k%nV`Vl*qE}w7T1R)Zmj9$rksK%9;&O2JygaP? zaOvUpF{i(ExI+*3t!-(u)tI`D2fJbRbieYCXDog9{7TICqmE~`P%XvQ&C+m@1@!e-mkIKBTM)bRAe)gw1bX5{+dR!_$S*c zcuD)q8JS6bul`RfN+X>b+M5&xaew8xW8~JIbBL|imUH*NIhi=F{K%XPeK9$FXWeXD zQ^<7byXrY#A?iCnX2N;`oA^(KvV$f==+!5pB-fi=(i)>}j+UQw1@_mMB|M#aqb+6O zpKw0iUs<2gG?$1!{l@wXzis6!-&6-@a+~v23ikSO9!yGtoQ7ybz%_(d)yF$5B0SWA zf0FO#v&001r1&&89?(!qDX{$2KHiElw#}^gzW-=$@C!|%ZK8Z@KX265+N;s@&oP!4SW_j4 z3LZ(tMvr`s+}1sp^Fu)U-RIufZF|-0rRS)VJ9B{+#W=q|&3&@3U;DcAx*Db|_9 zx8af_A;0R&&BeahRa0NER`hC8YjA7L{u4wc<14kNKELmm@#%Dsx>K?DqeK|B*5z?t zW_el5T9#K9c9*;)E=i%9#(#CZKny>+1h?RbSqUC$*!Py$AMs7t55CWvEttS>uhR5a zVSRZ){oBG;_>^1KORan7hr>gXvZlOe=+kd82wyv5S*VXrQ`Zi>UplWTKJ|emo&Ogs z=pb$U?agOqRf6T%K+4$1oOl}!cBh!M@}&;fBR_h<66qMFm8CAs=dqqv>0#!;W$zaS zZ!QUqpF3`NS1`L_SrD1;HT^y`p%X5=+|b=clmGO+**guY#LJS#bwN4i?|S_nzYq`4 z{T!M0PIOu7JtB9_-875J@_XA=9luqKxaV(w?RzEXm~0|06--22^-YB!_lZ{N^^)MYbHa)U8I<}276lm0C6)5~FAVta%a}n;p z-Kbqt`L06f&U#$QL_q1~?1_(ciAmy3eG1Xuld3oOwvv_-`rzuNcX|F6EwA@~779$y z+m_K#G^E@l*{}$19Od*WrhGm8%4$0t?H)~GO**M)*Dr@9*ReCAX=B zQpqQ8UTx=@MrCMp6=KguzQL-`XWv><F;vLNAaiPDQaWUQXNp6P>+wW89y2fqIhHGUMSfPkk_w=pWabw}8G;Y0`-`ML|wOHV}^Ahclg5-^dO^+T@gRvdu6JiqI}KUOBR^Gk zI^~?6vTzvh)fL++regPq#^i79oEtiSYtPNT&;9i(%NL_(B-bfy zu|1XnTG-leSL=}@8~fyJ@zH(oV2Rt`r|B}(CTX6R=hTJg)Ldtks5V~H-xe0_j&vH{ zpulh6rJ8saOa7GPU{d+Fim^9yk7Ty0cGE#(|SxdZljs>{$VOtZ&v&6FDcbe%Q4o&=SR+*(i1ilz1{adIWu_raL}|z?^h`H zNcW-En0h#^Jgt_qS^Cb@G($yt(`VL~C4z_Q=T{Bq_GA)jLL{~54_fP^6?=<&rrOR^ zS5THPIe9HxEF~h6_G^C9IS!|z;?43v_D5d=JQd9DUj5+NwLRUm?7>N#@+Owsa zaTX947EL4dw99y_+{5EcYqeFRkfx=*S#B$nZe(mC*%Ck3{>I)BOb@pwNkZkJh(I!L>^NQ%Uyb&@GJ?nVnb1UA5Rl*U%_Enz9kGw~eEl>1ix)jjMH% zz2#gd=k|LBw|*&C^EC&CKhQGEP)~WPy8ps>Tjtn9%-LZl$u=~SPye>n%67k*>zkh6 z(t@Is>13$q+^E`K&$GrM>!kfJ!E=J%&nRyOD>`gcsqY+1y*nnD=v@}a^i212PiS&-7rnME82ir&My!y}%+Z82ax-}*2DvrZ zG@9r4I?hi_6p1|&=6*eo2w0rV@wZfoAcY}kxM8Bw$KtVWUcL6>*9&G+6dwG1`IdL? zlS-So7APYN3TGNs!s;_+_8+8(RoDgQ(8Pug5fm_FRyd~T8V8g`Y^Ou>Nv!`StLm4? zlFTkxz-!Xse;RYlIx?$+x!u=17X_MfYzsT8t*i5rTuG+t{c_e1Pe4l?BMeU@nms4O zp!lywo?RSqgS3;<*W=$kG`a`Lj+ps>Ux|Wyd`UC^cY6=+iG)ci>a_m5FK?#=efjt! zUZa1v_%kmd1#}Po&CP#P1|EulG7ul{xcKijUy=)hiV@ziJ@+pb0y~aEBisMKS|)al z*3WYvmM3FAe2S>10Zf7j_BVPsy))-+bN;s!&47k1Cv^BZMj^B|v+R|k#W$D!S@aX+ zie-~d`swOz$>0;+nuBbUdstvsydB&Tepji|Yw_;k$-LZk)mO~wn-SA#dwVJC9Y^z( z9U9TaZ-?S5r(w8OVpU9t#Um}c19(+sdFRk<-R$8rL-oMGx|PwBrw;?%9j0siVEEz& zk>`r+H-QzuJ{-47PEMYQH*<}(`g=57>i$P%Un15K9_6jIhAr*9E3S=zAF5$O(xQtL zlBBpwoL8Mo=N1L}#~70x8GMF1ggk!drCHD=PAv{&A2{(PlYsNOiVoWNOlr42*sHVQOD~cA2mZia2&D#{{W-B2;1E@@lp=Yz;qO6G8D}SRS zCvR^ht(<>k#8Z3iQ5(3kvj^We5x8?&bKvo6mEEtF@c!}fYc4J>TWxY@cj5)ihB^#B zADayJ@3tvi=P8m&#!OETh3nfKd2>|I*|`Xpo&7Xwj!eyMH8^zDI_zXgpa*scB;b6y9vd)~(fk zPw&H{N`0Fa-bX6^MfM?_qLrRt_?}=KC4#<7!*`bJooUD~DB>mxVI!ZMq6^NVi{Eb>j1#vb1Qi6*ZZpi^L4PL;wlLK$XUPky71!~31 z)ySKsDB8y>MnM~mOb%+w8C#c)Hfaf043M!SvU(zf-=K206N%oDslg*M2z=jV4!kwV zY2DD;+Yiyobg+zDEh}(a5x{7wHxs@H+#LzCP-!LJL=O0OVUNz;tE=^UDM13F6(sG~fTO35btH4)N^ZzQ@2TYAaT1d@&g2yDElWojCx`O_Egwd;vQHCLV!NISJ8 zOfn>J{6%V*zB?v1Y*h^B2;Eg_e}TfF=|Lv)g3;yh@aTq${J!#X0!!oho1TzZJ|PAW zj`K@0tyIlY`@EvCWX}l^O^i9G64;s-EgGpN-UnspylSbZ2s5EYHK$adqK%292jy1a0{XuD!Kv2q3;ly!(`prfIM&_VhSW z9k-jN12JsSKReSOg0hsN-w?J25}_LDH%v~SF5&>GhYpMu;cD8TGV~LyBXB7!O-+p!WqPS_4xI~s94x0Bh(xo? zVl7mNN<2Dv9*CMfcG6Y7Hy?VhHqMBFk`D&5IyxSBnJq&#TUnU`+R>r}EVzuPIXX%+ z4eZ607BByI&mgdn>jrPEo(g5WiIJ89^a!&-2G*Je);bh>eEmx{N!g8&hu%5w#+~3N zMygK0@MxSgVj#M+@@?^$a&ymaPL!N-PmM?EJ@^dj7cCssP7G3~x$eG6x}_Gnow?oN zVwM!)P-@lh<%|+L9?~v%pLcqP(3aW0EV+L4z`g}Ri*x0i6#~1_0>pDaLMXRmK|$P` zF8f_>b=8Fgy8oWdG>xOHQ|v0(@5u|wwNH8jRLz5WDCj>0 zrRY^Y!Pl?vx?W`y;Wq$}4^X@J%!H_9uh(osUpwQ*z#3eCu((A=1wpWrAlVJ;?}Tp` zxvqO_VMs2*BQ&Z%1mO$yff*NgV8J|V=BLT^CvCf8#NO$-jF{2kT&^3MnA#U_zXMaA zL*4rt56hLmeV1jbTqL}*j$iQVYtC&|0*8-Mf(x`F9G4@E>;^N$Y6jT?RN4_pShF(d zs8H>+Ae{aCQQ@ZNCN8SEScw{Y;)GoD6kIeqDPhQ+ml#)~+O_Lu$`vq175xk+5y+kr z3V{Mh;tPN$za%`By705Qz9?+1Wtyh!#w9KEBgTwm07>G}k()#%p1Z8W2sNtnGJh^7 zc`H-Gp?xH9@hV{Dt;z@FnfGd?b@lx2Ke|Z~Mv>Wfg&TY(1}_pQD&3tm0^Ek#xX80; z78+B;cvJuX*r^fd2kljKS4+0at130hfNMCyMp$y28DoBfhsto41kbYaL%BxxC~GNV zj$l^`uB_gvH78&R_8;J>LRus9i&Y|3&+}VE7m_iPtws>RO)*ns3!XZskVGByAb5~^ zWHe!z9Xe>(%wt0Y0pD-trA#Vt8entwDibW`yEt(^nxJVk_aeq#GGrw~-;Q9qATKxb z$r+{9%0qBjP7G=~v$advVCj`u^=K*4)5ynQ+tW7iS_*vUx0I}gqKP4ogK7?sGs+(y z%Im+jRb)F676FpoL6LHqdB#!ZuIsC}!JAJOTiD?+6IxET-8Yi# zG%WP|*NNn!Z%s5wNE&;es5m>O&Iq zOC3n4<^c@>T=px06r#l*mi*H9{v+j#Qk*qz5^PzA?4iYGe&O+Vu_~WT9?Gg$&7FNv zwI-n~gsVdwxEntO+-_T}o6t6E+;mG0e+=H2xjcOU+Yp2sg7uML94x4Qc}N1kp(ps% zdj|3{RJV%O$({s8~6a75RCDTjDAnk{n|cgBiW0C8Wgu6 zWlT;=ak6mT+f7$0Q&Gqhx6;om{*QZr8d_k2sQ1|95tp<;1ntef`JZ$KlLP5&!=}JK zPup8{c_NkXm=jTbgRp#Jd9)17&42Nt$zSuYRLzcHu}@8iFg|7M$uSCq7-R=!p2$zW zseDaM37NYTjY91lV~-SZF-T)rvme~D;&K)YKhdqtB(BucU>^}zI^oVC%54Xnq?T~x zDbv-OS&fx_-)30|jjFA}8O$ubK3LdTbGLG+uf`uuCBNwJ&+1au2PzL*@! zH|yV=Tpzmo_UR7#15mux&>lwxdIAaTP`u&j)|RUc{6Zg;DjRYIj&5G3$fv^MfN79U z-}g%T8i(Vtcd^8ENi?FkrA0>57h@IiJ-(#171-htpVfX$}NWWymth(}KIz2Uk;Y!_V z0$+l31!36<`?M~|dDjy~*~)ySknBpq0E?(DaTbhU9jxcUMv%1lC<-qoJV1+@ z7!^&4!2qDtPKyybDip|{&1rZ6xK`_^c0neY?t1bSclh*`fkP<=$@j0H&+R1nI4Tmzxt_X*v<@=$Ir zJdP5DNjZ-#+Eb#Va@lDAqnmqO27wYwrYglTJ&3q)aX`RD7;DD%h6l{W6jTmaPsab=I9FOJAnG8rPO1=h9gkYhB1m;j@UvB8FxZO zIMD!<+=BRh2)kq;teI_P8U;055TXyq1frxCCa{n&z(!F-s(b!oux=CSX$bBN)h+^? zAn^iG(q&~!UE%~~_ZEru;g1$#iSw->`y%kN_6JI&Y;LRj)aQrKl-eiNFNU0VhVAl8Fq7 zcVyFZ!7)6pr;xc6H7&0EHP20Ovd_U9ACD}_6nd`y3J@pO-xMS#e1nm!JgMlp0fd+1 zO%)ARa-_%I=3!&z0mubFM?p~J*IrX>czdgICSz`|xDy5O>Utw>pJG13Ktbc=L37qp zE)??fs;gfuF6z?dH2@ECMEE6>6n*=lJ5`&>s)e?qoBaU0N{IRUa3^?HBxYESX_>TH z0{GRmEWxb+YD2;vC^Dozsdt9s5r~`#&{CAjvkxI0ySidM_UajL!5oNW{lOiuoH6d} zd;$UjTWo(f*-Bj}r07?QswVlGjwjZ~*GFHij8$mJZYTBHN}E~D4BIn@53*4t5iJU` z%s!-Eiu74^;$9fG;BGxkqt+#T;{3OCFd3?-EPo+u)sq;M+;t-ay1j9GlA*EuM7v3w zLWKs4{)}qRzBRIp?RdlceQl!dLrsmz$ELG@!0w-JO#<_2 zzUdcl?Yt8UKJw!CS{bj=o9jyAQha*uQ_shc!|zs|XQ#)rPnld}`Z87NH8W>Rag-I* zY_PYdd>$qjwtDnHzkkam@s?n`6x{6ZirDDJ$@!`{klCt2piaKq6E;d7fHX>z-kUjx z)ue8(=3&3{*?WCH<7_9#r*a<9Hzg-44svgNr-Fyik5Bo}vmAE2g>Ze37kE=!D|NW) z7P=geJNUWLiMq41)3!fLeQUQkbb_2*YQ(A`prU?n%(?Xb7m}1Bax!V3m6)82kg;s< z?QZe!Cx_bvhKN8o1vZe=QQg`=zqj_d^%Na<6}1erUf6gW(k+8$fiqc&ylTEx2Sp{_ zRG2fDHpowOTsYrTZl&0yEq#~f3EC3X9>Ieq-Lg9BPq1yqz$*Kt)H1|elG8ex=FP}3N97gsBD|omFmANW;d{DFU{-dvinhcr z#BmN|IIwBmyku+}Td28U-HH%{*u%s^t0qg!&{J;)Vf&X2hQ0oCNe-!chbvFeiWW+= zn5t>*dxs|uM-{zH5)^}alo&y{j}NT>nyL<~;Ezcw0p)MXCRbo4UjgmaM)OM=aiYP_ zuYfr}=G|)PuqGO`=9%I7V(DBM$*DdQ9tgeah9AwZ+O)m8*r2V2weL#g;O6FD6V*2F zy)HnR7a_Wq^($+16-4VFnz-w0J`j+B)z3$WVEPTJiO{UCahNyndf&?*#oCov{`$EAzVoVoZ#7&}W)U?RzB?K7x`8BVN#TPUzPU9w0LED*fH zc+>ic^ZBf>5YhD{Y2T06tQyVJgZE5omhua1PYyN>CH$6)s%FC2PH;QR!#W}%KeWWv z*C#prl^u3P838CH5-U8+Kl&2Cmf@=IZ|XJ^eZCy}f*` zaIDj1eKov@*Sk;I!tTGnW?k~?{`~t}u1l~Z?^gWl8;Gq} z=0?|jna=H5lr12(qQZd9<(1ugnAMf7&IG$!K4e+m_e)&o4=2_`hQ~(Q3R;aCw=VX{c|+N!h0Kwg@WP5N?fgC z%-XdqX>CW{=oa3Lpi+GUgVAL#>Q91FA%CL8S0tC@jjNP@ScH>Mu|BL~9IR&b?QgG( z|1OVBPD%bC@UYG7y#o4EO;*32;;{-$qoEbfDyJ|?D^sr>2s z=Bi${adh*rg>Tw|0{iZDoY_k!){Mh02PHNS#*mXgY>{h>S*&5AAK~G^RF5%hN15>O zBf*1TRH0X@rb6lj=BYw9hz?uD8}G}|&TH7r)-nssg-?$4J4N0xHH<*TER%HHJ=7Wj?=V{=zr|VT|PUh8uy4KROoD- z3|EI;hwkKyvj^YJf(@98&8oCr>o-*n+f`+)t4>djr~V2CAMJbseMg|q?&W%?LB3@( zbkkJu{)A6p?_hz^_ljXlezv~{ZL6A%8bPOZ2jvU$++=Az1ckAxC^ zUDTU;>UiFvQSIc|awm8_x1k>Usb~G>5+rvAKb5*YurvQkdaWc|dWpffI~bJr5AWZ% z9Fgm8GpE%Ij|PcK_v;Muq@2*Ft66-(Mf-(6)s{isO!j> z9K9B`f)LOt-IAIoUj6Zr4CxHN-5IgE#wu@v+Bxbch!$`}`|Sri+@1;rVarX+sJ!pklWhYwlD(Zlno)#^~w*Rs52D=uk|ADdWO3MQC)yx3(l z*VD6cINse~E^e9}J1)q%XF-Jv^PQLC6|g{`R1^nm+4rPg%~Xjh&6Wi_>Zw1QwL1Iu zkwf=>3zI$?FA85$HvaKL6k1X@{_eisus=4XAEQf~4dBvGQL@S97m-RuWcThr!nu;= zP)TK&`tz=xW?7LgRW9h7>=KnccwozfcUOTV_LHx&^!!1Gpf>g_a+E%`?MR=Fz5Bw8 zI8kQ5!5WqzXu-EUTwL{7!8aL2^~73+xM`!^>4BSb!qTWir{(CfUqoBwB{4-ibi^GR~7XZK>bEssLgNmz(8AI0`ll(`O5Ksa#R-X)C ztjGP$AGIKfEl(lZtyf#r`K8Eq6tlqg&H>@|IfGLF~01y3JV}tK_V409g1J=EU$dhHqt)2WnANzNe!>8QBRj#6-f%%lmM$!E8*H% zzE>qz(Hjc)7eIXdnXOkv8vOeOFA827yd-s*z) z)^3MRNIy;R;cUX}cdN6~UB<#X#Nv6`!2Pw0-sIWRWT(qbX9d9R)1Qfk5WstJ$SyxW z>SR9jET=0)T<2r`*6q=f`(fTZ+1hO)P0=AcnL|{~!o9a_s@M#uz7P;msOe26(NE6s zmN|4S5AGH!-gcDTY{MU4OwmYIrw_9rDgm{62$9>3BywVv@R?If0uXE<6#1DAu`qn* zsOkj6+9FE%5RUR7cSsx#RW)*3o&2V!P2OEd{|fvzU1ojMA>-o2aA@CqQp;qGt#PE zCuED3DO%h!_M9O;)LDcgOms&q{qapw@}miqMd*>Y2vt*vbFNFAfrglg!#!=5wysML zP9dOrNtd&%|s z?ZW+E(V-`Q-k%X^OD$er-ZhdTF8FeDqR9SdrHcnh*P{%fGNG+68H5~qn5DOi-3NK< zw>tTUs4(^ib18174mM#Vlo2U%q?u%wB>An++ls=t`*=45@W5uD9nZX5&!(K=`ZDvH zNqc8xkD=+_y&S9KGK;*62xhp+Fd{d{aeYIK5OGwspL*dg3h)x=(UysCiM71Dc%kMF#8hB zn4UJ8NnBgM3}^XtmkQR*F>;tA?s~X(+Gm58hIB*&dX3v$4qx+D@4&58F4UWnpRm zd))N5ZkMz0aWl}2hu;0tFTmBIf&iFF0DY!u5r&+Yf?hBV+`>!?>qIK@(O!w~-pflj zTLS3UVlI*XrosC>K)O-q|AaUZU%y=#3EOf0E7m{`)si$9z;tz*`JfHv4YxYyZs32e zR!*eY!hmx_;VMhz%g$EE$+;6vzA9FvNk=k!KOS(-SBFH?58E(W|0p5-(k8kl(|aiJ zwig$8PWH&P=$2nEXQUJUD$#81PeFBJrg;PgWd5nB`k+3NQBd^@>!9vh>(@>ETB}b& zy0swKU)uIso@R#TKw{|IN>KEvS8}uDn#?d$^nTsGalKcnO^}cF^vEx%{j3Pthg3@~ z?A9QYo%(X+vOyCh1E3g-GCPYvZ>}@XH+A04tOm~D{^=14-pCPSz%l)mRwphxc*W*p zLzCMT5*#PsXC_PycMH7!C;@c7Hzk7~z(3T)h<)F?80&4CPY_q?O9w(PW~;Cu@x{{Y zzX0i?3i1eASvh>+qui4gu17160M)$mOc>YV{JHCGVn~`~WsO=*#Rr4>I%ts*_o+;U zQT3ka$5t`=SI{ z3xJ1w6BsrTR%ySG3488fxtOj*5bOZGNg#ATi<-ESn+Iln?ye^1Xtt9_0CpeWKkkIU z2$TlfeMLC_K6L1qp=d3oh_PZ!3Lwxz8vw9xG_xlsqE~;J?yCaY2aq@$#Mrs)_*@rs z?8jJt#^CH&n-iyY3ACt@ry1f;<|1dQ%iO z#`!aT-G`zWjyZy%|I77FO9N7-(Ye1%|H^G7D4_Q2Z}<>^W8?pGYzxhr8;W4=7rL0;g4c_S*FI(Yt&P8(E_|FI8e z#=ec)G=22$A3_p{Vz*X<$Ez3fO;10y_n`eKwCN4{vFJ5qp{O(TUK7(Lh!z%1Nvwm% z0$%igEm3Q?+x6Y|K1B7k=V%-r`ArfK2CinyYRZbA5DqY$XS^!qxAGN$%DUl6(X7-Ju2M>V(7`>2JDGA2OS zAZ{F!sAh^Z$DePC$aaa}Exou;f?FlF_aFVL;uS^G!2o(W%Ij{WeYC@QPZRUln@!h@ z+B?E`qjl`8&rOiE1=E8yOHE91SDFQ85?0!qe2tB~f)m7k!-X9Xi(zO;%dGN$;SJ%S}cMo)I#*9xdk(r&(uPzq2&KAFZL?#~#B#&}2P!bkjt{ zE7dY!Z-v%Y?xfI*2B0pe$KE@j*|Psx4Y)%abNmlL;*2Kj;+n4 z1l>g)()bk8445)TVDur6SJ%nPMJgi7T8q}*4TR3dg|n)k_$FUxO1b@kpc8UyewN7_ zL_$Y7^4+8xml?+cvB~r#u#02Ew;Ggviu}6;HnJ$%+T$qN`a&%@l^(0%_SC`_IQ=Q# z2J-{pbk|BR$Ob7j|w|TY55kF!c5NVvMlP{34;O>@taKvM6V2%Y}H1DpF z7CQ1KS--9|oh}E$3l5t57&~}v_&Oud-+o4bL6M0=hsP!x#x|8OWvJc5CdR^&Rsy7c zGubYz`2{7oCb&^^RL1Q=GqW*Z5Z4c_Ez|nB?&lGuifCV{zTn;lMojW{@9X4kAR}dh zE*FAxz*k*XJ!U4J^Wb`$`S57=4TPTt;*3u1JiF8V5))co+dW2Ja9s^A-pNPO#D)$g z4Mzjg(C$4olJMk=jlV7Jf9*aMU;-Nc_wJJ`*%nvX~z)W#C?^ z&o7n?c}pk}#1ai4LKK^pnlQ^jPJ6=lD{sQUXbxcnLT$QTT6H4qRA*rs(Ch5&1S)*| z=<2|Pd*S<>c%%62N5nZ`ElHR0##5L1Uy|YZovl2}?#Mx+^J(GxdI?Bsq!R7M+PNnv zRQFT2&p`S^jaTaA%|+Qyxl`7TloY~&-#MltfXbu0eQOYsc-8C`rM;UfY&*tHD-_4o zq0r2RI3FkiBO=}3R{fAm4CXn2S_yz{h<~t4SdsPhMebPxyO3hR-7xedO|Eo)2qabu z$I$5mzZYSIfaVjE+I&Ac8Usrt;(qq67)wx_60_GVl`TBk%LXNqF>5zx_>ens7$-;{ z^0S+e70X$kh$G`H0WX~xg!mwbX3RTUsZW_+yq&SBT zFi@AQ(imQF7efSS<31A`RiyVu~8vnGg@75GuC6PJ~BKn-8y#+hw@v@E@P8%hK{ZvhM+ zeuMzxf+*Z+XbB0M4etD4M19ID>XAC@3!)^%?HB8S&gzxH3!h20yRH>nS(JA&CkLai zx6uxQg9yjArG`D4isKAiBxXMKf$!37QI?)C2%+R?Q^;GBLjpZ35P_MR%6OsE49fia@h zeU}V%Vc~;k`eHX>D&8+f5oZZwT<=!pFDe-{MKo_iU{Fj85Nd`DwCoP_>=hR2L4C$a z9(~oC4q8X34Q|+=f?yVHL8x@vTsN?Kvgjemp025c8JG|_ zfIZz}xL8rhY2V641RAvGWd}}zmjO}7>0}8~-_nNf51CiyvpT>!XAg(V2bM;DnTn^~ z29SY*lOQiy1ZMJ}>%{BVc#6vY4gztJ%-&CsmJ_wWhXu5A0U3TdLIbE;ozdH;T0o?l zTK$e(O&A}t53s^n!Dd)5DP@u|2d^gv;(9TBgh@(51I$x)Jk-f+ zKvdGJ_3&t%Oz1Nba;hXKp1_$Kx*vM4B4M>WAmrwC)jx|963CCZ#bUM7*cfsHJ$o(m z(cx?BM`XFYYZvoj#%wfDL>I1UuD-00LATg)#hhkbIxIOS1^s4|ditR5ssO({ZH#Mk zmJuG@h`jbt$jEQPaCIbBN<2*Vbd+--93VLvb{r3y-hP3@-E5$v%?)9F3hfAzOTw8#dmNh#-X5XZ*O9qgvV$!T@ZK&5 zbscp)@6nPxU=ZUEN&E21Do7wrr6hX>J;R3Y%?~wklYUo&52KfDd$XHrzoiCj`rU!y zzMfM9iZ$9ExKQy>H+q<;F`?HESVS9HL#~9JU-3$d9T>3D#!`4@fm16NC8*+;qwf;fs!iZuY*oE*!T( z2CalobC-HJk&qndlrheNV)y!*g%9#bU#Ch*)U@x~i52clwMZu6w9@Hz(mkxuy; zTAoI?cwcpD8wqRM=Wh?tbwt{}2CWItBAw${k$}rb6z+VK@mFIUr8;PXa6^e;)b>xn zXx(A4YdRkU8a6^@3WguCI^U=pe}L~OjA$%$`5wX_W77yySNlF)r~IKlEq=i91d)g{ z#Y}!{@YE$QeS*G^auf?zX2AmdQdXP`G@^#UAHL+77q5PpLN1*5?bhOm^6@vwTX;eT z%J*|{!l>>rx2Na=ch{`P7?R*eTN~w94oI=*5lhjcPqZ)!jL^ko-X!JbT1qfzLu$^9 zK@TBClDY*e0qm<`Zz*;se?FBVm~#pYf25+CnXmAUbd)!PDZLBEVRo6-`DBlV z5sAbG*Ut5jcyEC*yozVbQDk@$_Y)`=XKo_`{jrbYi{sPPMjoVNl8Gdp;e1E>i4`t| zWE;VmdY}JO8HD~?;g(^{X17I2TjKlwx@c4Caq0S&TUs8Sn)3Gd&p0 zQID~!CI*CW_e{2>kfl?X;Xi386uHpc6q&vkTDlq;xQ(IP7wQrG#cP}x!h90U;I*aUY2_rze_N+%@E;pPc;zFi@c4vnP{IorA3> zLq4Rxp3JhKPC&@|#dQz*{~*p%q< zf|c3JHzhzEh+#apV}l|1O^kFhc- zlaDlR?Ec;q>T!f3Uh3U|14#sM#ubK+;$}oFQjbPt{HLcw2s;Cr_v5jsTeaXgb;F1D zp4ZEoHCBH?K24I(W7HibmP$>&j)=cz!ujPHRYKi*quJj2)OGMrQ4a5x*Ym47d#3ET zFkUNOA94F`XnxmL3j-qjYAt&rXx9n4UlF$#XF&z`PFKN-Sx*l-@BW`cX6knDrnSMb zF(;n^ZZ8#FUY^NW@Y#e=;GBP2T5|kU8iQZjV7ooOhIbhrYXL?;MIfMhCEFc@?cw`z&!&e-{`6x72eeUl+&*-*=+-phI||*@sUVIoQ9cxVgH< z*2(%8pOc>aE7n4(wY$}6<*R0~O>MIKf7&_IxF*hTk0*r^WC>Rh5s*UBLXpj)krISR zL1mGMLI8D1q2GR&@CDzXz`)>+Ivfr+36Pf3 z4GbUQv^V>kCI>O{Dv z@V@y?t${wbuGblJ7`|na>9rr`Wr17+z(oWso$5JvGlqn-~;>e-%6P*x?rT&P8rmc|+3yBw>#k-xS zzOj-OCV<5!=ElYz)+NY>yk`6mOT-$k819rx$hc0l=;UB6 zk$#3M5r+V|x9wG3DA4otS{>5+ebnL1h<%27*IvpM`cqjf)sFOmJa+hKps_vh3((oE?8 zIBC$Ow56r6y4AONQ$R%xb(6dg=NO?RGbdh4@v2ddUrVYEeg2ZwWcc_E^|sNCrCRv& z-srIoi_y#l>gK1Op`qOOMH9uIo}LEuPp_sY*~=rptVyI5=S#2aF{X8s+bp9*fqlfB zmCtb0wUuTaf4!Ne5=Rc2qR3^aRyjU56U~uaZ_(u>NE>x)Cl30hzBXsljbn;FcEh1C z^ebg$Wg&HQnHnk0JwDow8=@qF6Oy^E6ng2^jn$;Cn@4$ z1>sEqh$L-LEQT<)n4_58KW|i^ub7;Ahp%e2uex!g8zwUZj5~e7wx=$_kij z`|T74^PSGdhs2A#GK@J0RXIOixqIm2Ggb3*&*ZT%7yCsMQ`4G@uH(}@Pd^s<>ezMI zu;FtEs(c zj9fIH4xmSSj6^T{oZLVl5FzjDrt4=oD{p>b5=U*UlK99GQm@NhaZi^`^jeZagpNdT zjBuJBHEWoc*pC_R+tOR?Qbnn*=(CO(eH=Y69`Zm(Y^+Y3OaORlAmj|0hhc`zdt+yrlWE!*q^K9I*YU+(W3_;h%9q903Co8oh*)YUf6$LEI0Ph!8$ zDtRj<|ArOtQ7S=Lyiav!yj1h(Wz6sg=R*fue+BCVcj6qCZ*5YYlB%$Rrjwhbv{KuE zLGocrkE6j05JKl6Zm`S9iGnzL8t*b5UsW|8m0}@y*VuV^?jukT?WCX?gR@b;yxpSm zr+5V=DR(195vy`zm`wA$=_1FBcMl$gGCNzqb63iY{uCA|WpTi&EMejbRwcbCNyY;} zjc96V(VUT#SuyfHKkB}}ol7dIsk~~{+pNRxM%o2i*f4UZhe@J27s^s4=}Vmb*3xOW zQNR@mmbB54s5z5%yHtD*x#ratos}logQky5!$j=QcC4K&7RzIWYg?U#X@8LKzW;8O z09jQ@cq7X@8ffjVcvnRhv5>6pF7tbpSjzEToL4(1qNwFo&%4VMJ$(t}#z+f|iYmB> zr6jdFL6U9eXIjSEX&F+q-i%t0Q+w*ZvtHEWOo%jlymGD_!(B5Xnl$wLAuQrw0z|5p z!46jkY(-)41aJk`@_S`(PRp*=;kBTfbH-KYI~M`})>K>;hb3|~ezrc=Vbhms2kS*< zRLVFpN|SsGWt_Di&Js2I8VwFwYd0cedQp7Gw`52TG1Fb3l#j>AcaKe8Fe}B4CIlbQ+ zWHBQA0ySgw?Af9U#bUI&;NR<~9umOOxQEE~r=Mz|1{4G*Z zl89Qj?L=)-tlBBdufwr&VW)EA&$rZ*)5cvK9H=e#v$94CID=!0V zGJ=2`nVf50n)ds8{=Pu2 zF4k1r0WUd^fbVr(2Tk9#n##N#f*8MmIo=+Jjy!kg?$fTldOY3xrMG>{y`iipo)s}d zZovcIK|chzp%Id_d@Bb2 ziZljL+Bv0K_+bWn$s5mM#2sOY`~O`iBd7E*7lK&jYMpQ)_L=&sry^}(NyvwMXm#;D zMNi)PQ5OeNbWCo~{nDh|l>2qb8#8CU=6U3$GwQ1N98xet-vT+%H-YAo$icHpPZ2~D zhJrCtR|0$=e`C9L=IokGMV_g<$CIWlxP-#D2%Jq3xyQB~r+&bs!+EaYIm;N?&Il7D z2lzQrJbOV2{1Q2>T!zrmoTH7Jdr6ixTIni1wA1n+QTtgro0H`dC*=R30Q1&Y+efla$R*9Z@#kHm z0CKzLRke@k&IlHFs%S`yZ~|dz)nRC2A$iEOripVDB; zWW7Z?6)i6SYGWT~k+v{!{Q_E{yW==!p!*05>EJQ$q<+*2{2ArA`K&qZ5g+<^Xg0u{ zGNCn^M%|dE*8EhUfGyK@!f0i_2)P|L4x+ZfWveyvxr6KJqrj7rhZC>S?zk}hyj0U} zrF2nybBG9yo*W#_(X_fCOk8H$eLC!QjeG68;{jZa@PI57ZKkF89^TH~s;FVRWaT;P zC?x6YXUnD_L>W9k!a;W?`YmRFR6DYP%g9)C6dC2l*kAY&{zXa)rEfd?^TQKbSvV9a)U8XDomqdS&7V{6Bv9$lGv5VTIsV=aItfAZWcAObJO0@Rk=+Km zMIG!DCjP!|FzW|HXgq{|(3ltd#qh&=;EIx4gLnONi=dAah(u$(3HQ9e9PS_$D7R{) z*nMG*rvK8j+!enZo(u{_d-R&Gd})o9Oi)7qe`Ef&Z2yZfH&Fh&o>(1- = <::Currency as Currency<::AccountId>>::Balance; - - // type ProposalOf = Box< - // Proposal<::AccountId, ::BlockNumber>, - // >; - pub trait IdentityProvider { fn check_existence(account: &AccountId) -> bool; } @@ -180,23 +176,21 @@ pub mod pallet { #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] pub struct Pallet(_); - - + /// Collection of all proposals hashes #[pallet::storage] pub type Proposals = StorageValue<_, BoundedVec, ValueQuery>; - + /// The actual data of proposal #[pallet::storage] pub type ProposalData = StorageMap<_, Identity, T::Hash, Proposal>>; - + /// The list of council member with their voting tokens #[pallet::storage] pub type Members = CountedStorageMap<_, Identity, T::AccountId, VoteToken, ValueQuery>; - + /// Vote commits submitted by voters #[pallet::storage] pub type Commits = StorageDoubleMap<_, Identity, T::AccountId, Identity, T::Hash, Commit>; - #[pallet::hooks] impl Hooks> for Pallet {} @@ -213,7 +207,7 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - // Create Treasury account + // Create pot account let account_id = >::account_id(); let min = T::Currency::minimum_balance(); if T::Currency::free_balance(&account_id) < min { @@ -259,6 +253,7 @@ pub mod pallet { //check if signer has identity | tested ensure!(T::IdentityProvider::check_existence(&signer), Error::::NoIdentity); + // ensure that user is not in the middle of voting process let active_votes = >::iter_prefix_values(signer.clone()).count(); ensure!(active_votes == 0, Error::::InMotion); @@ -290,6 +285,7 @@ pub mod pallet { //check if signer is a member already | tested ensure!(Self::is_member(&signer), Error::::NotMember); + // ensure that we don't have too many proposal let length_res = >::decode_len(); if let Some(length) = length_res { if length == T::MaxProposals::get() as usize { @@ -297,17 +293,21 @@ pub mod pallet { } } + // ensure that proposal exists let proposal_hash = T::Hashing::hash_of(&proposal_text); let (exist, _) = Self::proposal_exist(&proposal_hash); ensure!(!exist, Error::::DuplicateProposal); + // try to append, if error happens, this is probably we have too many proposals ensure!( >::try_append(proposal_hash).is_ok(), Error::::TooManyProposals ); + // calculate the end block of proposal let end = duration + frame_system::Pallet::::block_number(); + // construct the proposal object let proposal = Proposal { title: *proposal_text, proposer: signer.clone(), @@ -321,7 +321,6 @@ pub mod pallet { }; >::insert(proposal_hash, proposal); - Self::deposit_event(Event::::Proposed { account: signer, proposal_hash }); Ok(()) @@ -335,15 +334,21 @@ pub mod pallet { //check if signer is a member already | tested ensure!(Self::is_member(&signer), Error::::NotMember); + //ensure that proposal data exists let proposal_data = >::get(&proposal); ensure!(proposal_data.is_some(), Error::::ProposalMissing); + //if we are here, then we know that data exists and we can unwrap it let mut proposal_data = proposal_data.unwrap(); + + // if reveal end is set, then we know that voting phase ended ensure!(proposal_data.reveal_end.is_none(), Error::::VoteAlreadyEnded); + //make sure that we don't close voting phase too early let current_block = frame_system::Pallet::::block_number(); ensure!(proposal_data.poll_end <= current_block, Error::::TooEarly); + // set the end of reveal phase let current_block = frame_system::Pallet::::block_number(); proposal_data.reveal_end = Some(current_block + T::RevealLength::get()); @@ -360,10 +365,14 @@ pub mod pallet { //check if signer is a member already | tested ensure!(Self::is_member(&signer), Error::::NotMember); + //ensure that proposal data exists let proposal_data = >::get(&proposal); ensure!(proposal_data.is_some(), Error::::ProposalMissing); + //if we are here, then we know that data exists and we can unwrap it let mut proposal_data = proposal_data.unwrap(); + + //if reveal phase end is not set, that means that we did not start it ensure!(proposal_data.reveal_end.is_some(), Error::::RevealNotStarted); let reveal_end = proposal_data.reveal_end.unwrap(); @@ -376,7 +385,7 @@ pub mod pallet { Self::deposit_votes(account, amount); } - //deduce winning side + //deduce winning side, slash and reward voters let result = proposal_data.ayes.cmp(&proposal_data.nays); let pot_address = Self::account_id(); let amount: BalanceOf; @@ -424,6 +433,8 @@ pub mod pallet { )?; }, } + + //set the amount that was slashed and paid proposal_data.payout = amount; >::insert(&proposal, proposal_data); @@ -444,7 +455,9 @@ pub mod pallet { ensure!(commit.is_some(), Error::::NoCommit); let commit = commit.unwrap(); + //get the data that supposed to be signed let data = (vote.clone(), commit.salt).encode(); + //and check signature validity let valid_sign = commit.signature.verify(data.as_slice(), &signer); ensure!(valid_sign, Error::::SignatureInvalid); @@ -479,7 +492,9 @@ pub mod pallet { Vote::No => proposal_data.nays += commit.number as u32, } + //push the vote counters proposal_data.votes.push((signer.clone(), commit.number, vote)); + //update the list of voters that revealed their choices proposal_data.revealed.push(signer.clone()); >::insert(proposal, proposal_data); @@ -506,24 +521,26 @@ pub mod pallet { ensure!(false, Error::::InvalidArgument); } + //make sure that vote has not been committed before let committed = Self::already_committed_and_exist(&signer, &proposal); ensure!(!committed, Error::::DuplicateVote); + //ensure that proposal data exists let proposal_data = >::get(&proposal); ensure!(proposal_data.is_some(), Error::::ProposalMissing); let proposal_data = proposal_data.unwrap(); + //ensure that we don't commit to finished proposal let current_block = frame_system::Pallet::::block_number(); ensure!(current_block < proposal_data.poll_end, Error::::VoteEnded); - let mut tokens_to_take: u8 = number; - if number > 1 { - tokens_to_take = number.pow(2); - } - - let enough_tokens = Self::decrease_votes(&signer, tokens_to_take); + //subtract voting tokens based on quadratic scale + //i.e. tokens=vote^2 + //make sure that voter has enough voting tokens + let enough_tokens = Self::decrease_votes(&signer, number.pow(2)); ensure!(enough_tokens, Error::::NotEnoughVotingTokens); + //create commit instance let commit = Commit { signature: data, salt, number }; >::insert(signer.clone(), proposal, commit); @@ -620,7 +637,7 @@ impl Pallet { Ok(()) } - /// Intermediate + /// get voting pot address to deposit slashed tokens to and take rewards from pub fn account_id() -> T::AccountId { T::PalletId::get().into_account_truncating() } diff --git a/pallets/slashing-voting/src/types.rs b/pallets/slashing-voting/src/types.rs index 96cc052..ca508cd 100644 --- a/pallets/slashing-voting/src/types.rs +++ b/pallets/slashing-voting/src/types.rs @@ -28,7 +28,9 @@ pub struct Proposal { /// The number of votes each voter gave pub votes: Vec<(AccountId, u8, Vote)>, /// Users who revealed their choices. - /// Allows to verify who did not reveal on time + /// Allows to verify who did not reveal on time. + /// This may look as data duplication, but it will reduce runtime + /// otherwise we need to parse `votes` vector and compose vector of required format pub revealed: Vec, /// The amount that was slashed and distributed pub payout: Balance