From eb79dd022f9d5f1eda15d6942dbde7fbdd5ee07b Mon Sep 17 00:00:00 2001 From: MD Aleem <72057206+aleem1314@users.noreply.github.com> Date: Thu, 5 Aug 2021 22:30:28 +0530 Subject: [PATCH 1/2] feat!: change Coin storage model (#9832) ## Description Closes: #9361 --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [x] added `!` to the type prefix if API or client breaking change - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [x] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [x] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [x] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [x] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- CHANGELOG.md | 2 ++ contrib/rosetta/configuration/bootstrap.json | 2 +- contrib/rosetta/node/data.tar.gz | Bin 38887 -> 35581 bytes types/query/filtered_pagination_test.go | 22 +++++++------- types/query/pagination_test.go | 6 ++-- x/bank/keeper/grpc_query.go | 11 ++++--- x/bank/keeper/send.go | 14 ++++++--- x/bank/keeper/view.go | 29 +++++++++++-------- x/bank/migrations/v044/store.go | 15 ++++++++++ x/bank/migrations/v044/store_test.go | 9 ++++++ x/bank/types/key.go | 17 +++++------ x/bank/types/key_test.go | 3 +- 12 files changed, 83 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2880158a22f3..bf41a596bc69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#9576](https://github.com/cosmos/cosmos-sdk/pull/9576) Add debug error message to `sdkerrors.QueryResult` when enabled * [\#9650](https://github.com/cosmos/cosmos-sdk/pull/9650) Removed deprecated message handler implementation from the SDK modules. * (x/capability) [\#9836](https://github.com/cosmos/cosmos-sdk/pull/9836) Removed `InitializeAndSeal(ctx sdk.Context)` and replaced with `Seal()`. App must add x/capability to begin blockers which will assure that the x/capability keeper is properly initialized. The x/capability begin blocker must be run before any other module which uses x/capability. +* (x/bank) [\#9832] (https://github.com/cosmos/cosmos-sdk/pull/9832) `AddressFromBalancesStore` renamed to `AddressAndDenomFromBalancesStore`. ### Client Breaking Changes @@ -101,6 +102,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/bank) [\#9611](https://github.com/cosmos/cosmos-sdk/pull/9611) Introduce a new index to act as a reverse index between a denomination and address allowing to query for token holders of a specific denomination. `DenomOwners` is updated to use the new reverse index. +* (x/bank) [\#9832] (https://github.com/cosmos/cosmos-sdk/pull/9832) Account balance is stored as `sdk.Int` rather than `sdk.Coin`. ## [v0.43.0-rc0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.43.0-rc0) - 2021-06-25 diff --git a/contrib/rosetta/configuration/bootstrap.json b/contrib/rosetta/configuration/bootstrap.json index e014a1043261..6fbfac1a509a 100644 --- a/contrib/rosetta/configuration/bootstrap.json +++ b/contrib/rosetta/configuration/bootstrap.json @@ -1,7 +1,7 @@ [ { "account_identifier": { - "address":"cosmos1kezmr2chzy7w00nhh7qxhpqphdwum3j0mgdaw0" + "address":"cosmos1y3awd3vl7g29q44uvz0yrevcduf2exvkwxk3uq" }, "currency":{ "symbol":"stake", diff --git a/contrib/rosetta/node/data.tar.gz b/contrib/rosetta/node/data.tar.gz index 81ad29831d2ba70a0d4e5a11a8ac615cb2e2fc2e..b3b890e1153840cf0c97bc1f79158916062c0595 100644 GIT binary patch literal 35581 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

d5&;nl{mDeeqvIk}!76vE26wQRLpZMsfn&pQYS zP-K;rF~)})6Z|MzKYMAj&{}CPy$p)N*`|exaKks-@e5b#S+NfZ@1wOudy5Zl=P1Vk zjp0EdkxHGXYS+UE0yG3m648d%LR*UxNY&A%9lFFq>#yxlUKn{20JTv;Yy-uN_7?Ju z4}DAgtT}V@D%;G8qjyF|s#CQ!bSp$tp1Z(FfDQs-s(@w0&BJF^@BpZTN-)J++1}{3 zMNkjVU?2C|+gj3OpZx4|uTCTfE}zf=xDq$ODhMqkXgT+Yjg{UMdbg3hGQ2g=Ma41L z;vCk-n?b6Z@M@!^d8t*JNopCOK~_KjKe|0u?mHejF2{?i*U-gLMQWr zWB}Ad9avx8B(LUDll@5CBVPxHN%2YIj;UQA%an3T5KszB>`B6z}@Jq2BvESmv?$|0c+4j0<;NfNM-*knrA_u}U ze31Rx4|@PKK&5Eb-(?g%=o^yGEz9jXH1c}n6t|>&hm0_V`H6*_SF+XGpDBhYw}*i6 zGb02b|DA*xX+BTMkE6mlY={c*&zm5fs4{2iccvWbi#)p?ckrX zc2apG`?mYxC-t^ak>GA5=s9Wh=J8^3aH`?$8QBAX#;5~B4eR6+Dn0_S22ZCOio{9d z2R^OObX+q@U3avqzi-iqIg#o#O-> zIP(^W4q-(Sgk`Z@&k~m70BDBFE0fLr+Tx_offhIMIsF5@7iNlwazAQRzvg!3NDd7W z!8^j6a+Gv~ux1ko%V_i1+R9P@G)HB3B@=htC-hE*^*z_P%sEtN_5&2UPwnYJg(nhR$U%NT+q=$oL!ON-!|7s3mK*8G?SiyrqIIdBJ5tdpLgJ%!Cp`C9qC)59p0#;>Nht4TPtPI` zqEzE2@5qGK(d^2#5m76@i5kC}oqHHULs)V{ScYx(71)vjwFh*5!+;iiALBcnwj2U785sxE=B4x_y_E}|r_2#yBO z8hu61>Fs)HXF@SKQvM>kUM6MitL{JU?%dIoQ%afv%dQTo!pLiXs~ZuO=Fa`49|gPuCq9Xv-d za1MkOa}bvO(?JOXi&P-?QUGulD!63=yLj%vvYeBF&1(eO{m3G`A6|#bTHH}B zT`ia)>q^{=l;ppGBc~PzkxA4rDn68kx}cW@&M2Et0It#PQBjB9X{oMR&MmJbl&@xT zY^!T<fjZ^c;j0pb(b*E1kYSgn7E4XMJ`|?s3)VlGB+*{pI>OENS|M z=UVbM4jnn%^|ZfyM934aO)#?_!kX0}EIB%X?~ZT{<%-HvD&g7Vp^t;#pXD~@<;Kft zO7-l~s1#=_khUBruoSA~I4*|JsuT#T{(`VXFciAPQVoE3RCe{dI;FNHAFxxmQW@~z z325!i96I|_?vX}CNugu?-yRvXclsPi98&SVzG3v+e8X}6L6m?XBw1vo6%_uQHsRc% zdIb;yy(qpOv`ZG81dm)2OrTO+e!q^vP!U-HN6*4lgBz*|kNX}zd#jzH?(uww${S5L zl5j$?r3g`8cI3iQu9(H0Oi0zhiC7R!LB2Jk-?ly+NB`@;1 zASb6NFN=Hn{YM1>012oF_e|c69hTUcY8=+){;V&%bC2uBw`m2c!8UtJrsdouWyO)G zp&{r|@V+}}U!EXqozjAaRk)rQW{G3~^hCu9Ufi@}MHH~&#(+7Kn%MKp9d@gmy5DW- zGw^TYWy@;!qdhJ80}H~G0Ly~*L3??)9wMUBTC~hTAkJok8_vtn)Iu$3XTJaIdu2Hv z$#*Z5==E7@YS8MTg(5>(K?7mg%b}f9LIglBRAyN{9s+}A*<%Y+}(uT#~R%w38 z8Z5ipwYlI^?OJC^WI?1cGnngYVoWbZ7E~g#IFELoRv3+hiYBr}g2`1h>shB1ll5N? z0kX|8seYz>YUP$b%T)t))H4{Nk;t^dXJIhh(vKX6mrZX}H1?&?BI31ySBBRWCa;^b zw{rPLn-_GFZcRczhHbXI*)5q7 zngoD;sAId2N`2>L>-a&jdb;;k>{K%E_R=dR6ZN9fk;m;DH#|zQf|dSbYzRvP2#fH2 zZfxYi{$@=kglsUs$hbl9K6+IA^ z(WL6W3OGI~sQg~OaQ!+}m%rW_SJe<%yxx7eX5lFnz84=vf_4Vz{y4wh7OqMb<{pGK znLt=}i(L}y@BzTxsKkuP-Y)Bo-m&=mNta?D$Hb2`4(3`#efde(Bkw)&(JgJVaHy=A z``B1Un-W5%lKcpUc#^O7>?4pBIHlhf@YgZf{s8EYiU_8)tGjf)U+VZ^{~PC+HUev_ z(DM_gx@sA9hVJf{DN2nUfRiAW}R!1JUniR?iM;bmMngpIWdW&&UUDy~ej zqL;?q@1^ybo*jXlHfJ(KUf8`I?T+#C@%j4w)=4Wo9Jv363t>qGVOi#N&z{#600U7e ziXK``K72^ymUPmo`mxK(`<}nQ9dxt((52K+_H*0MNjr-ECJmh*eHEcoWI?thI9|Px zf8dQV6&1$g6z6`!vZ7_x2P$G&Qr3;BK59$fUOQmj@^+}&%L~R?DpyyX%rs;jyMH^|kO!=a-W5 zGeOq&p0FD*!67WAAS@eiBnD)`;S!9>({jzO2EmA?jh&aIi<~YNNJ38(w6r$!+9Oz=KEc)AQj9p0dOUuUw5o2}xt*F|?Djy`Q^ z$sbtRGKf!FvgA_gniX-h<$S^L5SAbi7HuaN4lQQ@+=EK&3oiOb&E%Hd2|XJ%I<(@C z&YUOgZwYd7IJvs?o=kemUfP@1Ib!N;ZXRCEh)Y^tD_0Fs9!lqMnGmGAjo-dO@h&Y+KP$na{9)4 zM10_R(kgvoQ&Cfgt*R%kwo^!|ChSFnKkj~|Cl^JBr-*fLStWl zk_A6q+?fi&+c32`cpj=A&=hJ8d*aM%Mt&W>;^LBxT5p;fDY{wmCgI)BShcwvwILus zARtQyPk(4Z!9`$#o7FZ`zevuy*~YgqxiwQjV(o=(xib>$$Wl^e+)@1ct5~(396gPI z!Uq8vewR?6mJY#@nBW-CNK+DzC-NeT!|{~#$JdjjKRESkb{Z+%6t{dkpK#fkz&}C% zLO|mN0y5scSJN#Ug12J=yz*7=(OR#iPjcsm-gd5-ofs-yH$%a!C{?p8WZ2!!f!~c+ z7&PW0ps57`d0|ljclRL(-hqj7ZGx4;aB&m=PB_V;TJ3X*q#sUU4zD$t1R< zyAovpSsen(SP_sXu2_0>q6_#aOpq!CYKcCqT;rg5%+<0aC}))^Z>@J?*`Jl^?p zR;p#F5t`G5iKtn=DmD0_=r}npaV_=k1=qh4nN_hQJP}7xtQJ;zx&wk^v4zb!+f#a` zRf$kv6+LfFqLbqdqbn+3Tvvqoe$cda(*95#}D&qcSL z{S+J1qOMT9UyEn58izTglpc|f6` zRXxdBBLWHq1Z0kYn3oL-Z#Oo)>;>yn56ivJrE-T0P7ym+IG2H^x?Q(!y=!iH?qjN! z1gmP7bFd+xK7)X4|MbXNnE}BG*zkHIb~gR})--OaNw0G&PG;xsh^u!^m5i-!y3akQ zZ+mE&Dl^F+I}k|}z8^hZeT~5L<3)PeF0~RK`(9eF^Wup8`eECpgAlw2TeFFMK%$03 zeW806!-(tpyxxYbg#Qs)SmYAUD4akr; z@5RA;v8_(~8usnO+Vf}Yb)!q}POH5(%Pu)=-M}m}qmszRiMKWM@7XqV$7fc@1ajZ0czdt(h=M&3$7C+%1hoj@ ze4*(7@liW9eHBj>1ntJoFRLtD3Ue!NJlg^5XLZZV}PK^&hG#jfG4} z-TrvOKN=Mf&)^dUHj9i|97%pa*I2=Cwxt8`488zHk*qlH9DB^E}M4JF2mDM&{kn6rTV;B^9cY z|2kzCI^El!7D#jVcMlFwaZ~YI@3z^~LwSq8nx8ir(kGQ?XFzbu1h7udyc9>?m7KDk zU+R{ZlrOLUOEJSw(EZRQdY+d~Ka|sQV#4C$2q=R)Cmw$_9q);$n#$$ zhaPE}CY#{U>396p&ei=+Mi!g-xwI>LS?LOAgb2v#2*`ZlOFHDG5S+%2PxL2zKY|1V z^!f1tO<4#&FizGO4H(;@K1;K$J(duBkiD%uvn{K-)VJ_@>tNX$1Iw`L-ZQmY&PP`^ zy4+lGaHg4Ng+`-JVPQ6NM~VQkHunU+52cFAbk%_)X^Y(If2{4g!k+uCM2N=q{W+}t{|R&raR1Atwg^aS+z6c>0U)4Nx2bcaN@6E0sKCRdCbY~aDw103_TI8 zrv=Ky10Gv>COaQm$&h%^lirWd4*g@dWAA;I-s`#i+Ib8{kehP_4Mb~}0d`?R~+wgsfru_N9A|;pJpEPiC1Pu9b=jxyuj$mjg zty`~ZO?&5ky0Q`>Fn0CibQGU_c;D75>_YjYJTsvKKWX3;3ow*2<=9{7oRW*7;hKH5 zX-4lx3U|t9_rzOPv7*n?+M$fyneWfY&3PPN3(b`ciEOE@2loZA{n?OdzQR(3_q%9DHo_0VW|b%*9Zk zWO4JtBn2YRD2W$I2K^Pt-$j~FIDvO@&B{h=h^d=8@+?8_i6&jjjv4nBt z2~e)cd}1suoTMuj5b?~;Ino-`FPZYky5QvHGrPk`Yfw)hk%)pm?mo_J?;m0Y4;s58 z0zhF4^D-1RxG>)mju(an847*@n|$3p-Mu_K0~wH*A&$-s!^hc!nr)~c9Z|uTMDq2~ zLRJj#T;}X}?;~aQ?kV}XO%273(pp9&bg00y4;3^Dg-%tY)2S5N_o0GDRa2!XQ<&Gw z&{P#wX*7zeB28HhR{ySsy}F3?FUToCuW=Z3a0tklm7i!a=r~b6;W&Woo> zPqB;P$nu8+juKDXc7>Jmz^6wanD%`bWHHE;+PBcIUD&|qELCbSUB>;J*{1e42{qFz zmVZX3ErGej405k&R$4pQEvEY8CQjlQMC&wPXa>1C)+*lhPT#ig+2Q8+uBM}@)|V?!#ECyHvq3Z6_w^?S0uhfv=?1a@ zNa@A~BlJKRmzPk__F?_^^tBmPtG5wq)Ld8HF**3s>xAT^R6hwcUN|#c@v=#IKO??E z`u;kDCxdo1L*BvgLFumb5vvtfs$6|Bga2_yo*nvXe~-=zgpUnGV^VuzRoAYMLk#7& z?@aoSFW)aBU>$aoE2w8G@8<`4whnk+{O@vCfed7W;hgk3r8e7HcZp$Xdib-|A@ds# zuh5b>%KcdQWcCFpA<%)BgvTJN0>uOZG7+Ya!5BA307&0rd%fF~c512ySH00k9a% zaKK!iYGb*D48cw8(l{`f;UJZJYfeog!p)<9VDgi5VylVHxtTHBF6#Nls&f=iq06s* z#icFcRW)wZ6}NZCFS^k>hn3YK#F<2H*4mgPqNYSuV?Qgz`r#xx&+xp4smlyJw_4^t zt-iGcYPhm7@7;cWmpq}G>+K6^l1$N9bY`3c&bi`4KT&^@l)l;6X8!FXD+ga?b9v4- zclSTBplwy-%~nHnB!*!GWD)`b#!0t!YL{NmuvzNauewr4O}JmyAF8+6+oHO@+sjy~ z*oNMxi5i1JdqpN9W6l#}Uf8Ed8TSE=lST=_+0#1N#&8M_}^gX#$Rg-WGT6n_nLAsi>2tG*i7R(&~qv$`yRzU0csPM(fwhZxyz4HDEU+eG2O zQyNU2oT;;HYSCZ4}d z%muQR6CgXoaNM-hZ*~XdlWVgS!j@&fwpqFTOL35NaKILiuXT_cK@bmO;R3}r0tR#DxeXOPqko4~KvTz75>b$$Aj{ zfDIML(qJ5L$JY95Nv#zD?jC)BdAr)LHLmA$EWRE1L^D%S%#YNUEj}7+cdtA**Mhci z4srFq5+zm&^B=9E0hI>*0kr4 zqcbDmF){SKztn#Fj3AzZ))RA& z4(CcRV#L(1HdNM)Y|@$q_%pmJ7F2EulV9C*yVWL>Zt2~1D~Fa(SE0qlC?_i+!k6~# zxx2%ZKKQ4|LE(rUzEn2>6WyVsN0qGxDz`np(W#Djv`EBczq3#NSa!|av0%;iV1`W+ zHOf7MxbAE3rA(T`|5PaXuzqF-$(O{bHE$2kqkJv;M!D z?!T*=?w3Gr^0#_FU?5v{QmJDTFQF_Y#uQR?D{^{K$vAY^e6Y&@3L&XJ@|zM0B|kgz*36S~rk!uqHdEapOGb0~YWL z7eGF!6c1Rd2ape{NCcKFaxVPCA)uF+pLI$`0tY`CeSmot>#y}|HapWgJS6`x>$1zP zPs|wZTJ}0P{aj_mpZQVB3HbJqejDbBi*wV8*>ZV3{7M0Z0Mpb1U$BEJo2E z4gvW!f9iojSu~Mi&tW(h{o$ZzBFCqs6L15ge_&pF$6gi!n@ZXnigN{TGq*P=h>mrWYGkcyJmPyOR8MVg!K7yfHNLwom)q4~or z(VTjtpjCf@#g~7#ckb~}rF{UOnZuBKV%rd>aY?zXnPJ=ty>dwxDwSvfehPv03yCfx zDl3(uMQ%~)B8pIQi?nW~mI`@OSz47_DTFB1hNQOMqpWw#jPo0I|9C&|$N8s!e&=_2 zp65LC`#rz!BXvv(NciauVScQNC(YAT7hqQLxtX22^vNbZLrlcW$eQZ)cJY@v9$K?C zRw{l|%&o8VRq^1p(GkF!g5|T6>Y}UWFWnIE6NL6?6rXGTE#8Tbj5};7G45}&JeQb3|q3k6JHrm5D7Ps|C9Pt?&*FI6xAvZNh2Zmi}PVbMTsZa8uxU8_5 z+B#$5>aq_4&e%}ns)PA6$YWM_5F>A^sT)2gnywFcwl=Fy=g1TO4{g*Kb5WIn#hD@6 z(j%hdHvc1|oAgRn;YkO@J>lbl4GxUb&rYuWe&~hlig>H;^6SftN=8J-wfhG0e~`zl z?)aXQSC;C@P!S`l+txNTGIz9F{*oie9X;VdZ0hfnrFp9Ts={0(6F>JI0@1wak8 zE@~<~h46uN5uObYO@svSl!Hh(B!H(J;)g-N7*9DwPlI?ho^pto1(8}j?f=s7am&FTnqA7 zZJGfaTRvDM*PBi8oYwc}6(9dycVhQ4@)8~MwwEVh1v&X2F33ro1^Il3mXnD_9?_ng z)p9#h>JMstve|t5s$oxw*1dag9{4L^1vz=tf*gooyahSwuYbXc9}<8JK+6tXm!lNq z2nvnsCVoE~Y=@NK*daLza)b~mPf$1JCr%!c6(x);$QM?2r_AR&awthBOr+5BI5oJx z*Dvx&&Wo})=ZX2Tr6pKFPG&F28B|?;DyxzN3Vn5l)&rT-ttNMB&h#DsV{=Nz^Lp*i z;rk2Tiq{%;W0fTtx3Yx17*l0Apm9c`cyIGjm%t9u{Q7Lmf(24`ayA-4pByTGpZuUe z9;+$`bOK z)tet>X`2kA-OVVG?#E=hmkSXL1iL!(^HWtSr##iNXVhVpB^kG}gr*CH;$`)w(d~9< zw@GaNOa2No@?D8-0Uj^u!J8M#=q5OZB*|Od#mWIPemMZeGoEr__#*{t4M+e_Ias1Y z0(i>7(-ueoPdRjU03R;kD2I+o;Byol<FQ1=gID{av_wy)uOX`?nCaO3@n+Q=wT>nOYp zY3XU}>FZL5FLp3=soD&!!Mhy{Z7PjMr|D3sbX{#O7dwW>4a$GP1ewdl4g`gQS(j&; zYC<4VSjUayVg~}|)_f5=MduTUimYn5UhF`?tebqU<}>Dz5{E~um?;A0$$HJLP-6fUJC#<>B8^3r3fteh-K=<)-W&gKH^Q&WeUr{6K zEwEo#A`yjRLLtYv+0Hp=KebWz>~CvZdSdLquQ4b*a-c!Qd6T+QRD8>)#6@y*2lHr{ zGi7M$=;%;+!gK?!1)ph3)V&rEL;U!|d-Jv0=?+V_yRY-8FqafvadO?+ZCJEp;!L3s z#>JV+@B6nGtv2)4!p5ZR9G|1h8cw=AYyQ(mAfeFjm*|_O->u;j9Bo`sXg*PB2)H?< z^kte7bN!RvRjW#F8%^JJpqrljsNG3Z!D5}jW5vRDXXC+%f;m$iZEbyh27`T}bLUJ; z`!QzG~-S(l`oI#r~XUctXa5LCaf3Z1M7Iiqe z(m%HA_`bQhA@A#Ke2a2Aqo_anTQeVjt*1ueOrZfnp=h`{MDl1|zGL^Pq&IaM2DdNC zNG}hQPL9=VNnd|V-ahkrm)aUEu^%^Q3PsEHf6cXckYTXYwoldj+3cfXDF(9w__vx; z-I{Xb-d(nz+XGLF#6{%}Vw_}>4V??diBLoY?|&uhGK+tXM+Py@frdE-Nn8C> z?n>*X$2ZwZ?YR1byHCV}N>NYi)a6l&Uw^|mUotIk^aSqP>qA$PI#_n1=Ca9AU)PvG zpQP|x7mU?bG||vE*=c$EBUG((*J?M3N0aQ*mLX zS-0-xS(n~j8|#XiY4u@_4q2C?1_ri8#mzo(V}UbTsLm%dKUt%!RqqC7q5m}se-Y+BTYExGqC zv3v_##~`JNLSF=%-P6wu&(Un3FI{yu{H&kT`vOYUyRLgr8G8TPUKtk?W=6Ec(khfqQo#lbal!9o{7N%G&uN1@=jI%G_}I!qcm z$Ybl(@u+{Ojf_b{2VVGXWMr&uWMnLDWMmv|WMph@WM0OLvyF_s1?4ZeZDeGuZDi~P hXxXy1U=fZM?8GziOgt0M#Pk35{0G~JOrQW#0stcErG)?h literal 38887 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≈?wVO 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 Ly-MhL0FnX#JW~%Z diff --git a/types/query/filtered_pagination_test.go b/types/query/filtered_pagination_test.go index 7f462a603947..01228571b59a 100644 --- a/types/query/filtered_pagination_test.go +++ b/types/query/filtered_pagination_test.go @@ -171,7 +171,7 @@ func (s *paginationTestSuite) TestReverseFilteredPaginations() { } func ExampleFilteredPaginate() { - app, ctx, appCodec := setupTest() + app, ctx, _ := setupTest() var balances sdk.Coins for i := 0; i < numBalances; i++ { @@ -200,16 +200,16 @@ func ExampleFilteredPaginate() { var balResult sdk.Coins pageRes, err := query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { - var bal sdk.Coin - err := appCodec.Unmarshal(value, &bal) + var amount sdk.Int + err := amount.Unmarshal(value) if err != nil { return false, err } - // filter balances with amount greater than 100 - if bal.Amount.Int64() > int64(100) { + // filter amount greater than 100 + if amount.Int64() > int64(100) { if accumulate { - balResult = append(balResult, bal) + balResult = append(balResult, sdk.NewCoin(string(key), amount)) } return true, nil @@ -232,16 +232,16 @@ func execFilterPaginate(store sdk.KVStore, pageReq *query.PageRequest, appCodec var balResult sdk.Coins res, err = query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { - var bal sdk.Coin - err := appCodec.Unmarshal(value, &bal) + var amount sdk.Int + err := amount.Unmarshal(value) if err != nil { return false, err } - // filter balances with amount greater than 100 - if bal.Amount.Int64() > int64(100) { + // filter amount greater than 100 + if amount.Int64() > int64(100) { if accumulate { - balResult = append(balResult, bal) + balResult = append(balResult, sdk.NewCoin(string(key), amount)) } return true, nil diff --git a/types/query/pagination_test.go b/types/query/pagination_test.go index 98097642a1a4..efbb0fca16fa 100644 --- a/types/query/pagination_test.go +++ b/types/query/pagination_test.go @@ -319,12 +319,12 @@ func ExamplePaginate() { balancesStore := prefix.NewStore(authStore, types.BalancesPrefix) accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1)) pageRes, err := query.Paginate(accountStore, request.Pagination, func(key []byte, value []byte) error { - var tempRes sdk.Coin - err := app.AppCodec().Unmarshal(value, &tempRes) + var amount sdk.Int + err := amount.Unmarshal(value) if err != nil { return err } - balResult = append(balResult, tempRes) + balResult = append(balResult, sdk.NewCoin(string(key), amount)) return nil }) if err != nil { // should return no error diff --git a/x/bank/keeper/grpc_query.go b/x/bank/keeper/grpc_query.go index 6f53b5abba1b..70c780dcf5e6 100644 --- a/x/bank/keeper/grpc_query.go +++ b/x/bank/keeper/grpc_query.go @@ -59,13 +59,12 @@ func (k BaseKeeper) AllBalances(ctx context.Context, req *types.QueryAllBalances balances := sdk.NewCoins() accountStore := k.getAccountStore(sdkCtx, addr) - pageRes, err := query.Paginate(accountStore, req.Pagination, func(_, value []byte) error { - var result sdk.Coin - err := k.cdc.Unmarshal(value, &result) - if err != nil { + pageRes, err := query.Paginate(accountStore, req.Pagination, func(key, value []byte) error { + var amount sdk.Int + if err := amount.Unmarshal(value); err != nil { return err } - balances = append(balances, result) + balances = append(balances, sdk.NewCoin(string(key), amount)) return nil }) @@ -187,7 +186,7 @@ func (k BaseKeeper) DenomOwners( req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { if accumulate { - address, err := types.AddressFromBalancesStore(key) + address, _, err := types.AddressAndDenomFromBalancesStore(key) if err != nil { return false, err } diff --git a/x/bank/keeper/send.go b/x/bank/keeper/send.go index 1d43d1a0e1d3..17427cabba7c 100644 --- a/x/bank/keeper/send.go +++ b/x/bank/keeper/send.go @@ -243,8 +243,11 @@ func (k BaseSendKeeper) initBalances(ctx sdk.Context, addr sdk.AccAddress, balan // x/bank invariants prohibit persistence of zero balances if !balance.IsZero() { - bz := k.cdc.MustMarshal(&balance) - accountStore.Set([]byte(balance.Denom), bz) + amount, err := balance.Amount.Marshal() + if err != nil { + return err + } + accountStore.Set([]byte(balance.Denom), amount) denomPrefixStore, ok := denomPrefixStores[balance.Denom] if !ok { @@ -278,8 +281,11 @@ func (k BaseSendKeeper) setBalance(ctx sdk.Context, addr sdk.AccAddress, balance accountStore.Delete([]byte(balance.Denom)) denomPrefixStore.Delete(address.MustLengthPrefix(addr)) } else { - bz := k.cdc.MustMarshal(&balance) - accountStore.Set([]byte(balance.Denom), bz) + amount, err := balance.Amount.Marshal() + if err != nil { + return err + } + accountStore.Set([]byte(balance.Denom), amount) // Store a reverse index from denomination to account address with a // sentinel value. diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index 73334ef37035..62fed93c8747 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -98,16 +98,17 @@ func (k BaseViewKeeper) GetAccountsBalances(ctx sdk.Context) []types.Balance { // by address. func (k BaseViewKeeper) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { accountStore := k.getAccountStore(ctx, addr) - + amount := sdk.ZeroInt() bz := accountStore.Get([]byte(denom)) if bz == nil { - return sdk.NewCoin(denom, sdk.ZeroInt()) + return sdk.NewCoin(denom, amount) } - var balance sdk.Coin - k.cdc.MustUnmarshal(bz, &balance) + if err := amount.Unmarshal(bz); err != nil { + panic(err) + } - return balance + return sdk.NewCoin(denom, amount) } // IterateAccountBalances iterates over the balances of a single account and @@ -120,10 +121,12 @@ func (k BaseViewKeeper) IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddr defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - var balance sdk.Coin - k.cdc.MustUnmarshal(iterator.Value(), &balance) + var amount sdk.Int + if err := amount.Unmarshal(iterator.Value()); err != nil { + panic(err) + } - if cb(balance) { + if cb(sdk.NewCoin(string(iterator.Key()), amount)) { break } } @@ -140,7 +143,7 @@ func (k BaseViewKeeper) IterateAllBalances(ctx sdk.Context, cb func(sdk.AccAddre defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - address, err := types.AddressFromBalancesStore(iterator.Key()) + address, denom, err := types.AddressAndDenomFromBalancesStore(iterator.Key()) if err != nil { k.Logger(ctx).With("key", iterator.Key(), "err", err).Error("failed to get address from balances store") // TODO: revisit, for now, panic here to keep same behavior as in 0.42 @@ -148,10 +151,12 @@ func (k BaseViewKeeper) IterateAllBalances(ctx sdk.Context, cb func(sdk.AccAddre panic(err) } - var balance sdk.Coin - k.cdc.MustUnmarshal(iterator.Value(), &balance) + var amount sdk.Int + if err := amount.Unmarshal(iterator.Value()); err != nil { + panic(err) + } - if cb(address, balance) { + if cb(address, sdk.NewCoin(denom, amount)) { break } } diff --git a/x/bank/migrations/v044/store.go b/x/bank/migrations/v044/store.go index 58966450f189..faaa07a9068a 100644 --- a/x/bank/migrations/v044/store.go +++ b/x/bank/migrations/v044/store.go @@ -6,11 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" v043 "github.com/cosmos/cosmos-sdk/x/bank/migrations/v043" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) // MigrateStore performs in-place store migrations from v0.43 to v0.44. The // migration includes: // +// - Migrate coin storage to save only amount. // - Add an additional reverse index from denomination to address. func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec) error { store := ctx.KVStore(storeKey) @@ -36,6 +38,19 @@ func addDenomReverseIndex(store sdk.KVStore, cdc codec.BinaryCodec) error { return err } + var coin sdk.DecCoin + if err := cdc.Unmarshal(oldBalancesIter.Value(), &coin); err != nil { + return err + } + + bz, err := coin.Amount.Marshal() + if err != nil { + return err + } + + newStore := prefix.NewStore(store, types.CreateAccountBalancesPrefix(addr)) + newStore.Set([]byte(coin.Denom), bz) + denomPrefixStore, ok := denomPrefixStores[balance.Denom] if !ok { denomPrefixStore = prefix.NewStore(store, CreateAddressDenomPrefix(balance.Denom)) diff --git a/x/bank/migrations/v044/store_test.go b/x/bank/migrations/v044/store_test.go index ac0958869f3e..61028e389440 100644 --- a/x/bank/migrations/v044/store_test.go +++ b/x/bank/migrations/v044/store_test.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/address" v043 "github.com/cosmos/cosmos-sdk/x/bank/migrations/v043" v044 "github.com/cosmos/cosmos-sdk/x/bank/migrations/v044" + "github.com/cosmos/cosmos-sdk/x/bank/types" ) func TestMigrateStore(t *testing.T) { @@ -37,6 +38,14 @@ func TestMigrateStore(t *testing.T) { require.NoError(t, v044.MigrateStore(ctx, bankKey, encCfg.Codec)) + for _, b := range balances { + addrPrefixStore := prefix.NewStore(store, types.CreateAccountBalancesPrefix(addr)) + bz := addrPrefixStore.Get([]byte(b.Denom)) + var expected sdk.Int + require.NoError(t, expected.Unmarshal(bz)) + require.Equal(t, expected, b.Amount) + } + for _, b := range balances { denomPrefixStore := prefix.NewStore(store, v044.CreateAddressDenomPrefix(b.Denom)) bz := denomPrefixStore.Get(address.MustLengthPrefix(addr)) diff --git a/x/bank/types/key.go b/x/bank/types/key.go index be8f43f9aebe..e3b6aa87afa3 100644 --- a/x/bank/types/key.go +++ b/x/bank/types/key.go @@ -37,26 +37,25 @@ func DenomMetadataKey(denom string) []byte { return append(DenomMetadataPrefix, d...) } -// AddressFromBalancesStore returns an account address from a balances prefix +// AddressAndDenomFromBalancesStore returns an account address and denom from a balances prefix // store. The key must not contain the prefix BalancesPrefix as the prefix store // iterator discards the actual prefix. // -// If invalid key is passed, AddressFromBalancesStore returns ErrInvalidKey. -func AddressFromBalancesStore(key []byte) (sdk.AccAddress, error) { +// If invalid key is passed, AddressAndDenomFromBalancesStore returns ErrInvalidKey. +func AddressAndDenomFromBalancesStore(key []byte) (sdk.AccAddress, string, error) { if len(key) == 0 { - return nil, ErrInvalidKey + return nil, "", ErrInvalidKey } kv.AssertKeyAtLeastLength(key, 1) - addrLen := key[0] - bound := int(addrLen) + addrBound := int(key[0]) - if len(key)-1 < bound { - return nil, ErrInvalidKey + if len(key)-1 < addrBound { + return nil, "", ErrInvalidKey } - return key[1 : bound+1], nil + return key[1 : addrBound+1], string(key[addrBound+1:]), nil } // CreateAccountBalancesPrefix creates the prefix for an account's balances. diff --git a/x/bank/types/key_test.go b/x/bank/types/key_test.go index 9a7f457e45bd..fadadd022097 100644 --- a/x/bank/types/key_test.go +++ b/x/bank/types/key_test.go @@ -42,7 +42,7 @@ func TestAddressFromBalancesStore(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() - addr, err := types.AddressFromBalancesStore(tc.key) + addr, denom, err := types.AddressAndDenomFromBalancesStore(tc.key) if tc.wantErr { assert.Error(t, err) assert.True(t, errors.Is(types.ErrInvalidKey, err)) @@ -51,6 +51,7 @@ func TestAddressFromBalancesStore(t *testing.T) { } if len(tc.expectedKey) > 0 { assert.Equal(t, tc.expectedKey, addr) + assert.Equal(t, "stake", denom) } }) } From 5a47154f6c05e2783a109678c7d3b3c1a00b24df Mon Sep 17 00:00:00 2001 From: Anil Kumar Kammari Date: Fri, 6 Aug 2021 01:30:08 +0530 Subject: [PATCH 2/2] feat: Add backup option for cosmovisor (#9652) ## Description Ref: https://github.com/cosmos/cosmos-sdk/issues/9616#issuecomment-873051972 depends: #8590 This PR adds a full backup option for cosmovisor. `UNSAFE_SKIP_BACKUP` is an `env` setting introduced newly. - if `false` (default, **recommended**), cosmovisor will try to take backup and then upgrade. In case of failure while taking backup, it will just halt the process there and won't try the upgrade. - If `true`, the cosmovisor will try to upgrade without any backup. This setting makes it hard to recover from a failed upgrade. Node operators either need to sync from a healthy node or use a snapshot from others. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [x] included comments for [documenting Go code](https://blog.golang.org/godoc) - [x] updated the relevant documentation or specification - [x] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- cosmovisor/README.md | 1 + cosmovisor/args.go | 3 ++ cosmovisor/cmd/cosmovisor/main.go | 1 + cosmovisor/process.go | 53 +++++++++++++++++++++++++++++++ cosmovisor/process_test.go | 4 +-- 5 files changed, 60 insertions(+), 2 deletions(-) diff --git a/cosmovisor/README.md b/cosmovisor/README.md index e263966a49a0..5b3aa5d2cb11 100644 --- a/cosmovisor/README.md +++ b/cosmovisor/README.md @@ -22,6 +22,7 @@ All arguments passed to `cosmovisor` will be passed to the application binary (a * `DAEMON_NAME` is the name of the binary itself (e.g. `gaiad`, `regend`, `simd`, etc.). * `DAEMON_ALLOW_DOWNLOAD_BINARIES` (*optional*), if set to `true`, will enable auto-downloading of new binaries (for security reasons, this is intended for full nodes rather than validators). By default, `cosmovisor` will not auto-download new binaries. * `DAEMON_RESTART_AFTER_UPGRADE` (*optional*), if set to `true`, will restart the subprocess with the same command-line arguments and flags (but with the new binary) after a successful upgrade. By default, `cosmovisor` stops running after an upgrade and requires the system administrator to manually restart it. Note that `cosmovisor` will not auto-restart the subprocess if there was an error. +* `UNSAFE_SKIP_BACKUP` (defaults to `false`), if set to `false`, will backup the data before trying the upgrade. Otherwise it will upgrade directly without doing any backup. This is useful (and recommended) in case of failures and when needed to rollback. It is advised to use backup option, i.e., `UNSAFE_SKIP_BACKUP=false` ## Folder Layout diff --git a/cosmovisor/args.go b/cosmovisor/args.go index 60cbb7d60167..c5b4d71af58c 100644 --- a/cosmovisor/args.go +++ b/cosmovisor/args.go @@ -24,6 +24,7 @@ type Config struct { AllowDownloadBinaries bool RestartAfterUpgrade bool LogBufferSize int + UnsafeSkipBackup bool } // Root returns the root directory where all info lives @@ -113,6 +114,8 @@ func GetConfigFromEnv() (*Config, error) { cfg.LogBufferSize = bufio.MaxScanTokenSize } + cfg.UnsafeSkipBackup = os.Getenv("UNSAFE_SKIP_BACKUP") == "true" + if err := cfg.validate(); err != nil { return nil, err } diff --git a/cosmovisor/cmd/cosmovisor/main.go b/cosmovisor/cmd/cosmovisor/main.go index a165acab38f6..f02f1190d522 100644 --- a/cosmovisor/cmd/cosmovisor/main.go +++ b/cosmovisor/cmd/cosmovisor/main.go @@ -22,6 +22,7 @@ func Run(args []string) error { } doUpgrade, err := cosmovisor.LaunchProcess(cfg, args, os.Stdout, os.Stderr) + // if RestartAfterUpgrade, we launch after a successful upgrade (only condition LaunchProcess returns nil) for cfg.RestartAfterUpgrade && err == nil && doUpgrade { doUpgrade, err = cosmovisor.LaunchProcess(cfg, args, os.Stdout, os.Stderr) diff --git a/cosmovisor/process.go b/cosmovisor/process.go index 6a67f65e162e..2058c72f4384 100644 --- a/cosmovisor/process.go +++ b/cosmovisor/process.go @@ -2,15 +2,21 @@ package cosmovisor import ( "bufio" + "encoding/json" "fmt" "io" + "io/ioutil" "log" "os" "os/exec" "os/signal" + "path/filepath" "strings" "sync" "syscall" + "time" + + "github.com/otiai10/copy" ) // LaunchProcess runs a subprocess and returns when the subprocess exits, @@ -70,12 +76,59 @@ func LaunchProcess(cfg *Config, args []string, stdout, stderr io.Writer) (bool, } if upgradeInfo != nil { + if err := doBackup(cfg); err != nil { + return false, err + } + return true, DoUpgrade(cfg, upgradeInfo) } return false, nil } +func doBackup(cfg *Config) error { + // take backup if `UNSAFE_SKIP_BACKUP` is not set. + if !cfg.UnsafeSkipBackup { + // check if upgrade-info.json is not empty. + var uInfo UpgradeInfo + upgradeInfoFile, err := ioutil.ReadFile(filepath.Join(cfg.Home, "data", "upgrade-info.json")) + if err != nil { + return fmt.Errorf("error while reading upgrade-info.json: %w", err) + } + + err = json.Unmarshal(upgradeInfoFile, &uInfo) + if err != nil { + return err + } + + if uInfo.Name == "" { + return fmt.Errorf("upgrade-info.json is empty") + } + + // a destination directory, Format YYYY-MM-DD + st := time.Now() + stStr := fmt.Sprintf("%d-%d-%d", st.Year(), st.Month(), st.Day()) + dst := filepath.Join(cfg.Home, fmt.Sprintf("data"+"-backup-%s", stStr)) + + fmt.Printf("starting to take backup of data directory at time %s", st) + + // copy the $DAEMON_HOME/data to a backup dir + err = copy.Copy(filepath.Join(cfg.Home, "data"), dst) + + if err != nil { + return fmt.Errorf("error while taking data backup: %w", err) + } + + // backup is done, lets check endtime to calculate total time taken for backup process + et := time.Now() + timeTaken := et.Sub(st) + fmt.Printf("backup saved at location: %s, completed at time: %s\n"+ + "time taken to complete the backup: %s", dst, et, timeTaken) + } + + return nil +} + // WaitResult is used to wrap feedback on cmd state with some mutex logic. // This is needed as multiple go-routines can affect this - two read pipes that can trigger upgrade // As well as the command, which can fail diff --git a/cosmovisor/process_test.go b/cosmovisor/process_test.go index 6dc964f21ee0..0b966b22bc64 100644 --- a/cosmovisor/process_test.go +++ b/cosmovisor/process_test.go @@ -23,7 +23,7 @@ func TestProcessTestSuite(t *testing.T) { // and args are passed through func (s *processTestSuite) TestLaunchProcess() { home := copyTestData(s.T(), "validate") - cfg := &cosmovisor.Config{Home: home, Name: "dummyd"} + cfg := &cosmovisor.Config{Home: home, Name: "dummyd", UnsafeSkipBackup: true} // should run the genesis binary and produce expected output var stdout, stderr bytes.Buffer @@ -65,7 +65,7 @@ func (s *processTestSuite) TestLaunchProcessWithDownloads() { // zip_binary -> "chain3" = ref_zipped -> zip_directory // zip_directory no upgrade home := copyTestData(s.T(), "download") - cfg := &cosmovisor.Config{Home: home, Name: "autod", AllowDownloadBinaries: true} + cfg := &cosmovisor.Config{Home: home, Name: "autod", AllowDownloadBinaries: true, UnsafeSkipBackup: true} // should run the genesis binary and produce expected output var stdout, stderr bytes.Buffer