From fb5c19e8064262a086f12595ff45f041468f220b Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Wed, 17 Jul 2024 10:05:46 +0100 Subject: [PATCH 1/6] CSDK/implement_account_put_transaction Implement account_put_deploy RPC method --- casper/types.go | 2 +- rpc/client.go | 1 + rpc/request.go | 5 + rpc/response.go | 19 +- rpc/rpc_client.go | 16 + tests/data/keys/docker-nctl-rc3-secret.pem | 3 + tests/data/wasm/cep18-rc3.wasm | Bin 0 -> 348211 bytes tests/rpc/integration/put_deploy_test.go | 4 +- tests/rpc/integration/put_transaction_test.go | 90 +++++ tests/types/deploy_make_test.go | 4 +- types/addressable_entity.go | 14 + types/args.go | 22 +- types/deploy.go | 23 +- types/executable_deploy_item.go | 5 +- types/pricing_mode.go | 62 +++ types/transaction.go | 369 ++++-------------- types/transaction_entrypoint.go | 171 ++++++++ types/transaction_scheduling.go | 116 ++++++ types/transaction_target.go | 256 ++++++++++++ types/transfer.go | 14 + 20 files changed, 878 insertions(+), 318 deletions(-) create mode 100644 tests/data/keys/docker-nctl-rc3-secret.pem create mode 100644 tests/data/wasm/cep18-rc3.wasm create mode 100644 tests/rpc/integration/put_transaction_test.go create mode 100644 types/pricing_mode.go create mode 100644 types/transaction_entrypoint.go create mode 100644 types/transaction_scheduling.go create mode 100644 types/transaction_target.go diff --git a/casper/types.go b/casper/types.go index f1ef0b9..23331ba 100644 --- a/casper/types.go +++ b/casper/types.go @@ -43,7 +43,7 @@ type ( ) var ( - DefaultHeader = types.DefaultHeader + DefaultHeader = types.DefaultDeployHeader MakeDeploy = types.MakeDeploy StandardPayment = types.StandardPayment ) diff --git a/rpc/client.go b/rpc/client.go index 63dcb67..f23f566 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -163,6 +163,7 @@ type ClientInformational interface { // the only means by which users can send their compiled Wasm (as part of a Deploy) to a node on a Casper network. type ClientTransactional interface { PutDeploy(ctx context.Context, deploy types.Deploy) (PutDeployResult, error) + PutTransaction(ctx context.Context, transaction types.TransactionV1) (PutTransactionResult, error) } // Client interface represent full RPC client that includes all possible queries. diff --git a/rpc/request.go b/rpc/request.go index 4a723a8..77b3469 100644 --- a/rpc/request.go +++ b/rpc/request.go @@ -49,6 +49,7 @@ const ( MethodGetStatus Method = "info_get_status" MethodGetPeers Method = "info_get_peers" MethodPutDeploy Method = "account_put_deploy" + MethodPutTransaction Method = "account_put_transaction" MethodSpeculativeExec Method = "speculative_exec" MethodQueryBalance Method = "query_balance" MethodQueryBalanceDetails Method = "query_balance_details" @@ -148,6 +149,10 @@ type PutDeployRequest struct { Deploy types.Deploy `json:"deploy"` } +type PutTransactionRequest struct { + Transaction types.TransactionWrapper `json:"transaction"` +} + type BlockIdentifier struct { Hash *string `json:"Hash,omitempty"` Height *uint64 `json:"Height,omitempty"` diff --git a/rpc/response.go b/rpc/response.go index ca61041..b66308f 100644 --- a/rpc/response.go +++ b/rpc/response.go @@ -439,10 +439,6 @@ type InfoGetStatusResult struct { rawJSON json.RawMessage } -func (b PutDeployResult) GetRawJSON() json.RawMessage { - return b.rawJSON -} - // NodeNextUpgrade contains the information about the next protocol upgrade. type NodeNextUpgrade struct { //The first era to which the associated protocol version applies. @@ -458,6 +454,21 @@ type PutDeployResult struct { rawJSON json.RawMessage } +func (p PutDeployResult) GetRawJSON() json.RawMessage { + return p.rawJSON +} + +type PutTransactionResult struct { + ApiVersion string `json:"api_version"` + TransactionHash types.TransactionHash `json:"transaction_hash"` + + rawJSON json.RawMessage +} + +func (p PutTransactionResult) GetRawJSON() json.RawMessage { + return p.rawJSON +} + func (b InfoGetStatusResult) GetRawJSON() json.RawMessage { return b.rawJSON } diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index 9bfcdda..e8b6604 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -639,6 +639,22 @@ func (c *client) PutDeploy(ctx context.Context, deploy types.Deploy) (PutDeployR return result, nil } +func (c *client) PutTransaction(ctx context.Context, transaction types.TransactionV1) (PutTransactionResult, error) { + var result PutTransactionResult + + resp, err := c.processRequest(ctx, MethodPutTransaction, map[string]interface{}{ + "transaction": map[string]interface{}{ + "Version1": transaction, + }, + }, &result) + if err != nil { + return PutTransactionResult{}, err + } + + result.rawJSON = resp.Result + return result, nil +} + func (c *client) QueryLatestBalance(ctx context.Context, identifier PurseIdentifier) (QueryBalanceResult, error) { var result QueryBalanceResult diff --git a/tests/data/keys/docker-nctl-rc3-secret.pem b/tests/data/keys/docker-nctl-rc3-secret.pem new file mode 100644 index 0000000..4321f94 --- /dev/null +++ b/tests/data/keys/docker-nctl-rc3-secret.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIHRZr1HEgKVbgchuatwA7dCWDWB7QZe+bpDb5dguIyLE +-----END PRIVATE KEY----- diff --git a/tests/data/wasm/cep18-rc3.wasm b/tests/data/wasm/cep18-rc3.wasm new file mode 100644 index 0000000000000000000000000000000000000000..84c3198c135ac633270cff9b9340441b89d2a974 GIT binary patch literal 348211 zcmeFa3%q4lUFW$U=XuXL_nxY{^+>89`Oe_ zDNJrv9`&GvHl%JKVj8h6HA;jiWe^Pl3W|y}N~v^%)5t`n+xU^8>w_7MicU>8@?p9& zX1>4wTKjR%J?GZFNfpHYP|3M_@3q%nkNifZ?QCsO-L)JSE+44E+i&rO zT^4fOdi${huRDCO0NQ@KdW;VETrUi{ZaI4J!0}3^yARxQNCh4^zW=rZ$8PhDo(Y+c z((f6yVsnuItZuvO*zx_Zd&BErPa6&Jc^}pGLkHjFL6s*`swGBMXaF=zw5~rt6n^+F z3io~AfBT)Uzw7872ZR7$$A*yU;2pOg&!OOZc4>HX;MQCB=e^0h-chAF(u9~2setzb z$@`O9RFB%-c6+AQi)Nb5nQp5#)12X7tKFQb&D7fMX0z6el+tWA+s&xf<{kgH+WdvL z_m+^nbiczij7v58huh7a>MI_W(md$6W&CH~&sM)GDn=ws_ zYSB!)-L7?Ow5{Ey#3s$D@!YNcYuiJu+iUSS-LUYh03^jNQ`GnW%Fza)0}2e?6yb^GnH=#vKRmxa;Vf zlBgy&jlL8&j=kxQ*WGnEdLnM!dhnLp?>KPySoD9z-Q#y1KX7>eu{Yd(_u)51e-Y2T z?!e&#ciwVv|6Q+-{xWXE1b2O(o}(w@=7GEKK6=-QgVA5b>nQ;mJ_gAa8U8w6fBT)w zQvW7yAwBLqCOZ9c+{^Fxzy9c5cSL_1*Y3Fe&g0SF#kJSH;pm;w{~gzEzw`Fv(Ybi; zmfH^82}c||c*`5$&o@Q?IlknM+rRgy*yat#5KVbAA@yU?e~Gt_yet|e`aTwYCGO|1 zDbJ_$yfPVb_9Z%=0S@4xlH@dNu0-g#>pclPhU z?cjmCsr%T$G->}t97ith{EID@e)oab-50<9*ulHL?_d6}ClCL8@@w%gB&U-{lb?mQ zA5MNT`9SiM$-9#O`OQZ^8z2AvHy*iX@q6yRKYnX`(+|Y&Odd+!oxCUck>ru&eaQ!t zpH6-zc_9A5_}-`EkH@b)72o#5@o&VtZ~u|_O#F`cL&+OX-29{QZ^ldU+vAVLZ(2(3 zOWuuv(7FatyYymo;Ao~{J&`YI?~1!VO} z6rOqtufEGtQF!WUFlUPvM4MJ9JY9*x)3UBCT}I&oc(rt+aFsqn;Z(2^g;T%?!090X zPsMrgmz%x#guWWMn`EiNc3iSl-(3jFQj|AAvRq6;&x9_7U?T9>-27_6zk-yRK=g>l zAl8%B5`D4)(O2I=GtZjni}Jp1L=Vjit7tEQKgy|pMoJ=b>vf4;f6;5(PK~F|7iw|q zWU@CC1c!AA@;RXDPA(1_VyQ!eCSNAU2dxy9Nj}KDHH=++L=pu3J7^>9Q_}h9-Xm0- z=c)~7+&xEzZ527_kcr~jS$k)MRdQtOpo3ObVG)Iqtt*KXyF|ryvo5OIrAM+h>aC_+ zzOX^tz8FX&XKj5!ffS*vD#etcat~(mjI?Wp*H#R9bQkflYSQ&-p{%v9M|o-v!Ulk^GebrYTa_h$P*X~1jHR*`L|deqR? zB4k6C>XBQjbw1yS+b3OZ5F4bh=Dd-Xan~A}F5<2>Kxq!@{2GDO8tNHe zWeG&s7$hD#6e4v>Gj-ztZe-b-YG=*8@yMVFIYQ2-`-249J-Mh1K%nM?to)tcPy6v* zQ=n(W)}a@JCTOQJ8gfXAQ73iT+?^g@=fb%Q3l;r88pW{MdasJ`9v; z{p=P7o9%YY*wg<@+G(xcXt$c}jvEe|-B!o7xiqO~XVjwK?#bW8vbUZ$yA7YI-f@W= zT8^z`u65j}Blmj%40=&Q+Ht=NR=P>Yy~xrjO6ka$D?paXvH{>8B%^K3pH$FIvzJV3 z>WsCu?c3T8ZM|7-{aVr1wr^{@TekJ)t?){mv7W9|3mm#r-or<>C4_g3lgrP3N=6TMNnb z-%5P;N3C%_`%H73&mL=4`OLmp1)n|MS~H)~#Z~dy^sWjFR>l-Q`+U>00BkmqXpPMt zk5ilf8N}cw_DyZ|UCxo?V0lK&<>YUzHfnfr5UNmBS=wc8fk`qxX z1LAy=^M8rZk7mehkvj(swj-&@$co$+Ih3}E7iG!doYM3B;*P|Out+u?iZMLTb=(J+ z&i?Ve{nK9luH%dT@9Vz*R-f`4ow$?xxlYH2hV|{FFQM^e?=*6KRK4m|OO^-rQcD_5 zreR~y%9?|jbT1e&TcrAh?la`<`IK+RONEZ4LW_>b5=W;!THvDN1w$tn3?UP?dMO)} zMpa7l;-OQBhe~!+ZV-FRJsx4aV0yM0C}4@B&t|YPXmA^aHf+(&c%VMED2D7OU)@96 z6doxTXRZDtg4nS0iXQF84!t(I5^cD!=ny^~x8=mObR&|%FPnK6Iq)AWD5Gngcv-ZQ zyXNlXYF4MLe<5~Tx=%=u6 zj~`_;GQe?|wPZ3s91q(P0oD>s`~J`QLKl)Am-=%9h!CviXMQpGjc1V=F~>+ao9_*~W)$n@06 zW!QFGUfGj>rM)}31_Q7oZ|LWvqRPRoyx&CYrn5kUy<>6md+4bia~31a1wH`=;8x|{;|YRm2< zD=D1XgQNRFQ67eA@N{1zwl;T&@Xsp|W!23s`f=9PYbtJT4ar018ocwU;Nnpzz>MWj zjZnKoqi9OuD(<;vg=)pD>P23s$QaJ;m}k>>Fx#Ej!6PW?a+Z9k{rG2EnWx4JDSPhE4pbD5ip9fbus^AxE(bgvELf@zYvJNZhQSCy=3*=74CU zK%Gd0Ryi&9oJ0LEhoMhw4Ppd-32nn;vNzf5=Xiw7u_+}LAsiO4x7?ai!qp~fufBs$ zrU0&RxOp+yyOq}%u9L!kV5At%tsSsf&ftp0%!sPiU1r# zLoPg;Bb8j4USMSATsjcrm6?qKMM3u-84AqF-ts@A;vs@M62qD&4L?vc#7TwY6R?=q zm2@U_%oiG?M*Zjh6{cC%FfW%bmWdRUCs35LuwlMLH6GNc9@;@o@*Y_q~dvo+F4THVO8kd-tOPLH$rFqE^@hZdIl@G;UCBA6^d>oSq0y!7pH^PbXS z-47e?^pdPQ{^rW4>6K9su*J779yC#98gS@By;WiBEAU#X2}DXQMIUIpzNW@WZ5&|0 z6%9n-i^=4>m-3@&LEBMhGmB*hMz1 zq87FQ9*9K)3=M+|DJcRLVQ?*_q#jI4HaroTl#EL$`LT-3FWHc~YYeKTOKozw)&Ibf z7saF@Ra8w1@x=x4!A)T*!8CB{30D>egs~8{cSn~%&D*5OyWU*a8yIAsWK6)C+cHS` zsqbzx(+)LwO*v==qe<>0P5HXO$On@VYcS0*k_!#%!;tVWT54>WUQZvE`XFDdg+<7? z7HDJO=NwIsYQY*dDV%?p0X$8v(*z;)o_(StFuCZ^to>gRXiP`pt}(4tM>b}4`YHtr zp2#U>AajoQ(CMKp(Lhy2$SRmn1fsZ+2?x9lLshE~#Pb2#*wAU((jztvf&_D~u$l8A z7(#%^qeecKjgXa8!5j{d3sXF=+}!p%_ihr6q&&yMvS54iPr*5mJVx5`pa9gXX zm*%OLR#Pv@Q!lBeZpl-(R8u$Sshg{*oAT66)zpo7>c(p7e4aXAP2G^EZm6cN&r{b| zQ`hCG>#C{!Jhfj5R^tK$@nY`tFGo2{qbc#tnwa=1VNX`gOT8R z8yQyBp$?g8=1j0}BrDCRy*ii**NLn0QOOI4z#jG>lQXC|~I% zzB5#4KyxKem=6oOpr7$uVwuD#Lf_^Lv6jsx0qpTp$^1jZOL)aW{*!zq;S4GoDQ~6g zEe4sYfCea*&oE&i2w%#uc7t3!DyaW9S(h1l6R4|VeyC6tDjOu|QMutM5rrmyXTv4T zM^j;Ak^A_>uz6_Ef|z37F)ESzZn}SX`st^eN0@CUozAGN;fy-d!FQ^*4r@HAxixu$ zH6X#7a`zrvtmMPDxGZ0)S@e`B4Msb3Qe8vq*+?P9;tjds@)(9o7*$p9Rm&yt%O!&rlKan`S%N07 z7Vr>>8oSjHzx??WLBscn?n1D15W)<5uHNlG6UvZb3(3oe8iM2awlWNYklMHqX0}4Z zaPrGbTNT2Dut@M!-@)M^jNzBM+zcOy-Rc$-+saiUH z@}*Z0W))n$0!&N_R|?I55iqG|k*qzKuP$p*Q-#GdrlO__i)UnmrV7Kex*-{w4{SVE zlD*ddVXNeKD$SUY;LLi?oLDHz^nun>VGQ(UO4T*;%C^KpviSycF6E@ALwrddSJpp=cQ;h3K2f-AdW$QhTGqlt;MribG%Wy-EV7Q8m z<;-I3s_1z(v54_E4{+6J7?pB{>osJvZbg*oM}54QA2evzLed{@lp3AqT^O*@m~8#x za6Rp#lnv_NJRRDQ51Nhrlm4%YGSt-hpmM;zz$K>lSRR2#j$lTpz@tIy!p!180)@Un z=!OPpof&dQPKNDW9z<9Arv)yx9m&;u(k+(RO3BCg<}t;5px}HKbZ2ypfr5TsJ&Zi? zBuG?Y|D)CcUUiv)!G4*``avbmF&C5d^9ee&1nk}Dn;@|Wii~*rzvhcDLb6%j0VusH z+BeuF(7t@IL6=viN2v1dFxW|0R>nQ6TQeE(~Rm~i1 zrQU+edg8L4q)}ck03vI_Yvw5yJ{mbbWaJ<|X5CGT!&x(%sIJ9qFBc3Ks~iHti6Ekv zWBY3loHGhf^c9dG3wXCzUW0czdY+yXWUqRh+$n(Fg=EbybTR~!b z4xjoCiYwodS3bOHXdsumJeHr(8(wsW zX4O-QCdKiF9$u+l9Ka)$D!QCl4x6*61&s+;V%0F)b20mg6*;k={bl_W4@!wY>wcP* zBj5XIKgE*5xpkTd=ZlEkY)YrIX`SBwtUE0m%6jKJeIa^R`m#nzS9YP%`55VLnbx~) z_)k0oh;(uEtW3JWVU$;@p$fgjpCKvgjXk8l_#jZQtoXt-zu=s@Yf5)_P3!K}&l;K7 zfL||UE==j&!nEGW8TRau={Yo>JfnrYp=?pY&KMr4IEbE4Hu z?ZqS7&lJjNj7e{t*3nl#>yFAeJ%k0j1cgUHR(Aad)oCJ9W`=MG5_k4tN0 zppEgwP16AI+GkA?RRFAtBrXI6Xf!oy{&|~|A<<+2e8;j6f-&}8LxPdabd~02(qm=K zt<|+YyIHy#)>Q$}4cZ$Q(=wqzJq1rtPj{3xWV+!}rgXP764LtjiAHH*uAyqexMxz$%*AFMB5|V}R62yz5{HzQ!hRw|og>oR73OtrY?(r?7YyWNMr#pZ> zoiM1XqF~y+p=Ne-G0_<`}U8unY#a*@Rfm z1O-pe$**y~Pi(evZJ#8Xj9c3$#F(x16Pu`9TP^jq*Mi@0tqp6g{gc+(KWVT1lbN-D zV)LqN19ErmwQL&u#P#r17-3oz7_>aoWgYJ9XzD9_EmCt5&U1n-KO-Heo`~ByUwo>m zV5A`v&4slfNiv9h8Hmb5nwSv2iFpd1S~WxS*~UV6m2Jw^GK{j&r21{nTLZ4}vFocP zs*^^V>lyK)@X?hzv8<4F6ANjst&sH;qF6VJ^c{tD6@tqu-!QTAWNnqtj~61C0Hpwv zZXTLqBtUZz=5qRvA{KGBQRP&qGXsT^&4eloV`FrX1-T?T5ET@We*O#Gyh{n8ec*!D zLE`Yjz-54Srzt`Tmp?6_vQeX%sY&wGWoC-ApBI&LQ1F0i~Q+`gz|2vcn@ z>>#sz-WNzv`P=OsHy3U%@3?-r9d_Kha69O@_2D+_xDDa7=hg()9Y!A1y9ruE8+v~U&hTCq(y(rwWhsMruJJWIB5^fRh zSA|>L$GgHU9@cLSw`>OSl5mR)^4r2K4y>!gE$)w(hFd%YyTh#lF8zPlJPP3EPtBrf z+!6~Vu!{ey!lh&$KgCVrUhF^2BIX51{09`3#HOkl)=F$9W(K0o0W+eP!(T;MO47a%H3Y3z)z$uTKmN$chydpyH`^<(EefKLL zm~%rky4t=TkqPb|g@Cc-FVcb-!ug0Xka?jd`USSJW8_bqyDbaQEzy?>8B+#sXF#qH z+~wCx_xcwCeE$>W%t`3NtQO`*3g`JsLani5)^*1HaWU;mM?aem=jen!_)I$N6ZkV+ z=PXzoTjSd3R*=fRWj9;UT5qxZR$$I-!=w#^^;vf?PgCZvia*yJZq&-w0g+P7WzS2A zrOKL8$Hu`XMRIIH5ArT`kFvp&T4kP&{%@)IgUwL9)@vu(W)aSCvqj}~vdypP;fGwW zWy$M_9-+>83QE}FC~Q_R-$jv@#Hg4HGsxZwMJe8hu+}B_d56k6C z|7>F@XD~X)c+5Uzh$c$d8x7|z#Ay8Wx{giC^A_r?(O9b1$1QH>i$J3|V^^|s$%?fL z)A`p{wZM)PjG6vsDagx!Ii#?GdusYjleu+l%{~`uV;8GzlPc|ItOO=3M#$8(_WWYj zBKRPW+~{T)caLdP8`X5TKqR=a@?s&mZE%S$w+=2XShoorWZb4|LZ1sUTC_2{MD0qmOVzH_w<{fMm)syiGxoEn;;rg!p~?vwy37ZSc&r>%pSfso`&d7A)S6()Gs)H zAsuWruyOx*I$Uo&CGJ^20XTvKjfa=CnmoW`JR@KJA^llzy+TYF)ZitLbFK!y^&T(l zJzmy(ysYFQv!mxK9)*q?TkK?4mKK9Yz`t_L<1Z_LWu&)un9rl)HYh#ddxKK4`#{p z*;c6`sQCyHY@4o%*%@Y&-sJyj&oGnT#?)#y(sMa)oA8Eja!e8Fg>>JPZImdO7bz*| zOAC3_!m@4p!UJX&z7k{0RxqB1$Apx1RT^HgBm@3tg?MkK(BbB6U5?AmnMy~6pcF{= z3IgXPnWZZ-RNL_istVp#TX?U}GQ!s+tTrk}n-I7*-Lv*7GYdqAXd;;J;kd8IaPh7CaL4;SUMIKtrAZY-k3ra-5Ko(q{^O9zjC3LAk^l)P_tKJ zYYDXZLZ~@rL%u9|hQ@hPS6@WVCZ_N(8C^WsEIJYu85>sVXT>s29Hu4?H|3O5RN$V322uxN4aMbqtC$8@gQ#4f zLbA+56NAm-0U=ey|CCk_Y-H${xXA1xq|V}SlZq5dhz50U_9y`d0l`$7zq@z*9psU} zJ30RDoPW1TU;+0Kn-xer;35Jf$u`~qsx6Lny&4Slp$FcKd1V%rpvT)l`Bg&p#X-MxUche6Qf(gQ80=<}0@U95K*{q3;K}4BsT4!=6=!T76 z?f~<($eoQ|8Emc6&59*0lRH~;>Nua=**YqB#)M6htrJm0Lr_W(I}uMoS6x`KBiZHa z|3-@)37u)yL{NsdwCC*)onaXF(tLx#Y3h*y1EU?Jkhh_{0vcD5846ay+N;RwfPrBA zQ~5qmL~`~46GPRrT4)`a{m0dq0Xy4x%?xa${03=OXx-BwJQ8wGq(%4%X$D_2lm0cXO8*M&L$BlK4*Ypa8EMs0xSmVUW`0O!Y}x;vT!7y!;lZG|+XZouW@+XS z0j(ifO60Q%2*xJbNl7dI<)6iPRi(B~!P?uZ0BbhfU}SBv*^F~ft3~XtP->S9g z6+N`fpe}Xc|Fee7)}uJtn&QRu4Ik|5F_3iENq;mKuZm!CStP`g#qLt8GUXZB62U9i z=x#@}eowk!4V8bvvGm!{u}G|3mu*;!f3k=Cp1;mc%au%IW0m*Meh=R%Q;>ei*l%ZT( z9yaW%j13o%uw!3O_NoEBQ#4P|Oa*EK`h2K0G$x(}1K;gyyCPJ!LB;QghB*f6IOJ_3 z7^aj(Tg;P+@N9oBkgBD>@eJt@|{=iial>MqN{4$XUlC*Jj@F4F;l zdU1exMv8|`m%OUCxun?5v?_FFUEm^tDpF@AFp$CAK;Rg+#?FJ-ntQ39Hxx}#k8*S~ zSYtvWH0Bb|N}h$1EfKDNy-D0~Ur%JMFt)s4F^r=6i;^wjPb|Sx5>*>c!S3GWjO1CT z-rZta=LOVkq!c6W0K*G?r7y7WBzJTN-3?iq@d8g>Mr6Z5JK3w}>t~ZoBW6yRSHf+9 z%St8urX(f}{4|8h8s3HIe;g!KG}8?oL)~4t-ch)9$v!-I}crGpBITM$n43RBVEuu&0 zis*4%Mco$xQR_!d(>MXO&oBBpn>=sZ^9|^ikw)y5mMsSXYM383XOk$t96k1m-oRSp zaWXXEChUg2uQvqwg#LKhv$J4kOC!cSb}uc{eiBbo>|SOGCU)iZHleky%%n8?@RBm^ zYX-+bA+Lpk7wk!wuxNDK-jm);>whaqqu=w=h}F#Ur|*okLqC`81I&P((dAw!rA)0b zETU(b?-~1pzp6I~J$unUI-I%(tikNSs+~7P=BF%yEn4#g-z87x>XMpMvz8_9UwCoF z&KyS2Ly^}4^;@G-?UNsAUAedz(NmFF=3Jq$9rSPy#uz(2Y7u^v5n%CRF3300As7$x z>gGMHqmN+h0vUyX+M1`KKy#r5*Qbt_?}&pGBlb=&%80CiF7h9O4l#s4`>xmBh{U_?<>&W&e6Ujic#?0%f?H1{z&TyIJ|hRNA!(C z?s+41+eTRz3v16CuY21_-K^igc>UfsUia3Kx)C)OukNkmbzeGC_e@SPV}b%TJ%+1G zM!vI?R77dx-(52P-IkH>Y{+)8aEv`ON?)5t>SplhxnsP|o5#P~H1eHI>`m(Hrt$AK zmI+=g&5sn+znF-|2{_vM4P}CFjOIV^f#r5b;xNC+Bdxc0kJ;%J)gtlfRV4CN+QOXo zk+;Y(H480)L1o5hVSQt9nYro{y8ZEH*eX<63~~U;f>2})EBmmdyrqR4U{ERz{jFT6 z9!;AO9I3Gb0bgA%kgeK;9{`N9*$O53HT*)8HU?+WGo4MD-L!_j#2znaYXEy($49@9 zVoj=pUd%fZDx+S86%I7$rxC88HlmZ;o$FcdZ-!^$uAmA=t=IcQXEc_$;x*c%A^*fT z%N7GNGE+rNXa`BeSVsdijR14=_ljJTFuwHTIe;&dJ!-}wkJ z?S^txo7#=1rqCywlNW@VW?o1UOL&(L7S>YCZ$~W}ZohKiCuq->H1?{h^OWr*z zg4wA4d5W-n>;i?$@%&Ay-_V;?z8z_cr6I8{jqhY>V&l8ES~<8Vd#fp@c|)(entZJr zh(23IyV^t+uO=Ux(Q}&8`TIF{1F=N~F8e=5tdovVBbe%j9=i#YuO^_`@~yj}$2Jf- zG4y}DC}8~!Z1qsSc(8b};Rb>}$`?OTyqLd%jRVRTKUus`gsR%2o!t!ioVyih+uE>6 zZuIiQcNQOR*35PJ;-T=O*7;(}xp9}{4ql2FrWC8kD^WlYaKnZ9-*d5-6xc!6de)%h1n~vLipqd9V=mSf!@L%G!o(zoSSo+xzG+TSqXy zxs3}t@g^>`nb)@>S{P6kp75sY^gkE;`Cqbmj)i=l19$j4by`or?}y9X0fJldBGI%1Z(>V_LSgvlU3M}nmkqAOW&Vfay}mC>tm!Js>=!=EVuWC@~%PwF~kPZ2zIzbO(s zryS9Ngz{CNZ8FbRoVG`Pa@#3o{`)-Bif2lt;EL6A4Nd6jGYJ}O7`}xhKjSOVY$({v zYFop+n>IAWC?~%r^aOkBA(9)sF!RKz7J2`O9>%WK&L53Di7pp#@Y_9Wc?)=_16uy* zZ`5yXVBE0CCAIR%Aob0n-_VvqXvkn2f$_ zYTy{7CR(Ar&FH)&7I!#g(Po}d!fA~491_5ZvoFXh^l|`>oyN!zsyK@gB%eLsp<}jL zk4g}F8R{sA8iFps29EqBCo&x~K>UZnk)H|(1aj(eEx&zG{)z>l#lFmE%Gph?>24Mv z{C`v{tf4DL0=H`x6kPX#+f1V(+seRgeJLKf*@Fovytv!L;v(X9i?RYIyQC$ZUObhNU5f^DYEI#9Lmla8y*^};>u zm#wcWAHiaIRzS+YR*;2C0k1n#kz2KV#<-mLE+@mGjK0h^LZx4}=< z?+i^?;LjB~*iJ`=_Z>A6phx5~;^tKh z(cnu~8gjrzd`L!x#AOAMsnk8z%9i79%Nv+KjBb=x$+X^3$5>$Wy{4BSIJgDCfDLhD zhh7|YOZUCy{x=>$s%ajR`dGf8)omRMWM0Y!ExYM!dTsK5$hK2Ij{&VFAh2fBC{Az% zq%uo@;l5tNn7_rZ&1y>B`d2ggE1i8hF}bq1}CVl+ED=z%Uup60QwpeX*n2P-K%>{odvS=r$C$cwdgZnHnmm?MPP=kXZX(F zf@8FO27W$tf7ZTVhe<@HHPQX1zYG?_t5@4lCK@tOm5>6}#U{xOh>9pS(!-w167g5$Y**<7xe`t%QP5K5k$TWn;?-OtP;ztw@GAtgn;;fO ziiiraQGE0FH4_d=K19+GI1P|8$-Xy-6d0B^J@ZVo>E2aoQ`Ka(Ox38^Edo~JGWKBg zCJL>>`{x_RQVbWlEK3gcKl&Chsc;~z}6wgp_AtzZ^0tzRwVDB@2Dq^w=!iwWKL1fMaG2e*J1YFYBYSqNu%`JX z-*)v&cSDn`{Y?4Q_|^F}_%->lcZX~9o8i~t*X7saH_LC1U!UJPe(U*d;5W~2Bfm}j zHuKxU?-G8O^1}t|w()x&zvuJ2j9(Sy@1~f`MrqWg2tPMWR}GqEg$}C z_2H@N!#~&qNIKzIgUcsw2fr)$y_nyX{C4vD7JgUp+r{r&`MpE|vPtLH>uF0q`Kp91 z>0RO}_Gg;rcoqHb)mc*fW0%}W=}LRK)|xFOH$r@T)xW=@tMVaDUBe1SHgeZkE-S15 z@0HaTTg!{JvR>||Q1TjXROAzSnP`#*q>s}GIg6Iz+3zQt+4Q?F8Q-U5ZL5&AK3UqF z?OVfk&WZD~R&z4=&w`+^ROFJpHGk++5kZ!Ulua~aMb6=jBqJ^XiP(-rEShrfpi2h& zFEPhStwo7SqDT&q4WiEHLfmm)uP=x)1WH7%oWYtB%X-E4#0AxhFKIm_{P9|8#xpZ&Hsh9u$qtUv47ErzcxumT3d*FVi__2lEMzISC+qy2MKfuz!}f#1V6I7RL>9$lc0s|Cu2&^)a4}NE-&bVrnT}1 z7(U89nuwVS27uAEQ4EG`pOVTMaQ`ixL`9`Wh9+!5vJjg%eD4pOIkO}$k$~;m>a{Gd z1SpT3_W)th7?CnFCH9Rd5n&|pLS-3tam6%Uno|C&#lUMuRy>2EK}yeF47Sl zMeEJp)mQKo0L{Fg-$w_O1N}Ra#qM{OQ=|y-R zQ;8CG%Ozo{5)nV95*r#eY=bEExT)2f5Yit@4u zH|1E%NvIe;JEN;7lSQ=!^xC&z=}e)gtr6R&18pz{F`5$ev=~^Nz-lUj!A{tNSP7<< zw^U3m6Tm-ZVl#^Yg!M%N0Aw5BiNo1F+;RUt!C9<*wOBjZYhW8rW^O<%EW^>p+hA*y zw_m!ORRL70#dpRDVgXZ6@Ig3^20|ENZ6u0i3OkM#tSufmFLNu?YMC4Od%GU?Sq&F{ zxixB%oSPE-6PV&KLc26iZ!|jf=BeLzTiadVSE20EK)rF?Ks_7`RO}Ed#*QRQwEAn5 zIZ6X{VFd#v=as zUV4S_%|N{|7^oA$lAEY`slK9O5(_~OnajhmAe)~e`tLRRWiZPYWgcE?)k1Z6mO!%@ zg9$tkG?B&u(azn`fC7n<%zU}q$ifIx4g?jiXbU{eRh?)fHvD3&vO!FxVu_!tz( ztSp_`K8XTLFLK^_@5)XxO1M$-Yq9V`o6op(AmdGL*~%NTMsa2i4Glg@{(=H6+Cmeq zVKZd1$t?|4A_8s91Xj#RV%jO!@`+_zWZoTT%=DQ!lD+jB+Q$V~O(z@$xal<9?$Hc;v}rH#Q?X2Lh6 z4XWYmB5gjHFm)7yUb7;m*~T0gpW3|xZN#}t@FbpA4syc>w$7{_uQxS)^k-DMiz4 z(G7mS-=3sZIZ;nJaWXNf$Mep}&JMHzo{r_Ku~V^i0NFe5PQMrF>(C%0T~O4sy?*~A zlU~~i&kUo37dY))WN6{!8HLvU$KdrySh&srPi(Xa85wpg^rPcwnrHGj*^V2HOQT6z8 ze#Xinpm+RB)ylRFmJ?6Mwb52=r^b$Ceh*?fbzc#AaJn#wsoM&Y*sDsfTYDJWbBz>F zq{u~W)D)3>355vJPaJR@=5y%=duday;JEEaPlbX^7(H-*@!~lpj6T_nd$~bX5ygNr0xXR7;k%TMS@dh6 z0|h8TVuvQ`hQ!PFhpj?67`{_^PvsOb`N*ZsZzkis^ei1%kYc(wiS*qIjB;QBU|p zVnw`g3v=#_W)GQBX=xl{%$CyR)7l1ISpP~^E)=L~aF#V#xG#aYbxG(MpKr$JQ{Qw=MD<__5f z%Gy4AC@YG=2^|N}ErC^(i~)bCuY01?0Ruru`?d}=u`5)XuJEv4-3LTa_p;8RVV4FG zMoV>d(S>H75moNo`^1C)Nnp017t(wb5ac%o%@phhh!X46=BWZz(|a?Xz-?I)KrzOAD@*XzQx(Sa$&U&0_ALE;r9B3JB8>2XdHCnhS6t4pfVHfviqNlj{-9INoxs4s zWEBst^j{XwE;QosFR8_Gnm<&pZ9OzWM{JA-jzLjlAM4^1wn~PI6rt>vYA=gtY-%z_ z&$%x=$-a#d8zD}3^@P2e_|+He6&PGz;K%Hh;;fg|bymBK*$k>%N;m_iF(J?AEDxKU zvH8|<+o~XO1J(l!{0b}t57x*DLTt5B({cBXUj-|Yd*sHs$jKBqCBY82uiA=pkjxOb z9$9vtu&_Xc4;?`Xws|4T{RAHi)2CB6aZtjTt#YaL( zvdxv;8c$|uLUMOJS>f)4VvHxlNF>jXCo4F=p;(Rh==Zwh#1ORA+<&tsX%U$F`_MY_ zXdedNL%Y7gv>r#c3TYGU;MCcK9u-;Qgz=XA0r+KlQ|cSS6J!=$3{HarXgHtL*#XYO-A@B zYX-iA=}C-mS2KyxO81%^vIFd!$P!tEt$|ta_${Da1=m`ZrWUEje9SsoslaBwNELhX zY}3>|p+#gsR5tS^s`hTBWtV(cE>T5<`N?#oSd=d~jm)M)vQZYh7c<)>X{9wc%ENB{ zYzsgs{4H0PN{(xMZ4FN)H(3iLwN1+^>q|M9jtCY4=N1Eiw7#@Wrx~>!8OpXotw&VN zkd!VmXKq;~JhhYwnT$O{_O@%n-FdzhyQ?x-k;|ABFwqwp1-4K;T9U3InmyST!{&wu zv-m#lmtDgxgWMm`ZU4{pS35Gwf}r^g3Zf)g^s%h78ny%ttIM>c7o;>K12hK8M^!vj z$3Q0Sa#GC*f6o`L_McE)QRkj=0J^L6&ic`>pD}>waKpM!JaR@JDqOLI2AjwAZ7ShI z*Jp3DE_~>I+dr231$t~pt=N$dTSy^r4_ zXd25_?lG1w?nnF8`C2Whm7YIZUiXErpt2FzvN}{nu&m5-l0ht6hZ35Ga$cLK1R~BoCEIyTBL0zi zUA5c|cZeqctSp>*a)&f`%0F@?cWpTb@sF?=Jrgy_$Gy&g7r`#LIkMb4qKECJN6(i3 zWjV1-1q`t^2@s1iFka1YO18)$(?m zRkU^}G10jSC{erIL%^x15AX|4x#x2fPU2KGA1MOYsTXu;g1@Ms*{D;C;F=F&eoq;L z4^j$@JX3xu5Y8y^BK;H9qZ2cj5;ox=ixeIvuM06e#eikq8TNN zFdvz$KM-V<0Y}tX59#v_|7UUkuT)&;uaheOR6OT2zD8BBO5xGuSt+U&=xx)&T4B`! z<^iC-5R7x@CfaI*yu86d3HAYFup)oXSEKonXsTvl>yu3>cxQQiWoJ3B&F{$7#J^Vb z%UMoY!C786zLK-Nxw5ky=Xuqg$V1hg==XboEpuM+`(*_Oqc*}q_ngTm{;Qn9z$&A;Vu!%fLo~R>I#+%b+7Y zM92SmS_bwHvkYIg3`opzK>5>-I5WjEOn@Zks96b5Ppg8R`z*s-e?Z7u=F^N>p@yLF z?oTWLpZOh@dAvO%K2PKg^DjPVDo7YFUTmgx5KFjp2N7&a^(;Gp!7H;ZtYwMGV<|oM zD97YP#v$q0a7iBU3lXD4*!$E+*k=)Hhl;b_gWD>S~+ z6`E6Y1?3jH67sLq6*i)q(3PK@h{E%A}jF`xi*LxjTqzZ9XNEO%=q*^aX zm9gIWNVU#J8_T=$*=N+1x39h{=Ht%MgYj1B3KUXwg>h^UATkKazmfpa;pNM_@<-38 zD?haQuGr8e?+V6$r7NZof>P)?Ml?y$F2Djl%Nc3WqAK1(s5Q^mCs^Z zH?v{}hP5k~z#PKL8E}EEoI%5zmD&Kl3Lg+d+1tx;bj9HVqe)hUFeOcb{jSX-x7^2m zOnujg!{&|A^nMn3WX||+gh~``rKYI!L&->0-R)#rimb62Skp}vnw;*er3koF(S=>pV-`Ex{gjzL=DADNB_t6$N&w6aSwiB8!e(-$tV@ z(`G@@w?+{r`QLgF%XJEo^9}A@ze!t`4mnV;4qoPt@a?XnS?YA$N9tzwZIydk&TF}= zWcz4PbOKDVog#CLHnFgZ;`XenG^xCryH68vT$kd)T^+mk+5k{HO5LYbG4bM|{@;ZT z*_79sKND3i<$H56cKP!pP4Kf6gWb|cb5 zw7K#?hH7xxQB56MF()z7(&bH9bT7)%96Pck3YS9K`D&d_7sa>RXt!u7V>Y@OTA;DE zWBgAwmXg?``8|mnI^s91qCB>~Qa(99XMB_HIWmw}!&1NqYZ95F9d?;x*S=DV$b~rH zWJ(W7^&u@D@Q-Q}Cs<)d^Gi&v%7JPV_gyQsD3F{ga?r(d3M8=N$lb~~4V1XI7i0f? z3jWwS@ZAuDnlAv?DPnerSVC?Mku{W^^nd9s$TYZA6Hv^^mY%ISA(*T+_EKP_L4-nj zCMB@TB;yt667K-i!+CUaZNjn{+fZ1Ma_41wKecT%;E?*;vQP+iHD#$1&JKXEOD*mP zj~CTo{MZOe2Um~vhx|ars*<0tFN6twDty>2yxnTqur*stqBz1`Cl5#0X9VOY0_1ha zM5J~~^*~{(EA?OtC{afgX(5yqEhTaw>rQDYK^h~tz-ex6Cx0HF>j^I13r1{_Et3dY za~}iL(1HoYTje2B=ijg3MH6DpbeMN*^`haWp6W#_j4X69O!F+9Y$%M1T24C;C6l~5 zULVT>u+Uo@*Ur2DXhy)S)KXPdhXID-B$ov&Jz@5ODAi)i!f5KRELDewG3@x79zrCS zS)$!RqRF4fbr+EGq@`-e z2U5WyzL$&kPT0K5lySIUn z8Rs)9k5vu%9qASs**nrc(+oQKAV0ee^zz7dpw~y=*~9qrmzuw%-(hpGE@Gj*-+&Jh ztgR_qSR-DBNJY9QITEGq{ts*>6eEEuwyBX8=QGI2IN?n4Mo$cu>h`4b6u%>D`duBE z5NADNe$PV0uD_42XPc+H`ScWlM^*rTslESRnKc1<3b~D=0fc{pQT!RsCboi?nocfDg{7xI`)u!6b)ovlok01tJJg(R*@Zh9S5jMw1HX`=(k!$C#pL2$Q*$HxiUT`~M zwT^-ZO)PX*)`qwZO!rN66nx;niy)NKEW(27Fs@@8P*j6ZPWKm*=|8@k8ievL4bvI1 zYFGv5V;!HG8xKNxNF#%oQY;9?zJLMF7ld-Uuh<0}b*(lCg)T}K(M5(tD+HlT@2bFH zWlRi0`EXnbLUG;0i|)ZWBW)HFBf;D|B#DiX+z;#a8xe={4PW^7udU~m*|6vGGQqXj z7pK;4Uz7`5{?XYNs~v27WX*$(_u5!XL3z^#8xzBs&K4m|k^4+>KRWX3d}89@(JN=9 z$uQj+AsW1n{WEi`FS8d-$4Xi;c*Fsq$-6K+{GTR%aK3rS9~tL|uB-($fw?!@l4|Uz zMYF2dKapxv2$ru{G#e%n_##XqXlT!qoa_1AFb@^mSEif2&L;>)Uu(5NW#}E97kWr{ zwt&zw2phIe0iYd}iy`)`A$R|B$T1H0kV|RA)Ny#2fFUm!RCCMOB)+OZkCA&7dOVCl z&tB)y8-2ZOapQj5)L~4R1X*&-C$Z02fo#S;BJ6HFyezT*U!J3;m+>l6!!{>eOPIy#Qh;E zmLZ?QVsA1Cngj5m*kq9YC@_}sVTg>4?CkPl1GFUH0F7@QZTq=1p{9g>y1uiTw5r9H zp5A8?$8Td+ZuWGFa18rS0$Mnf6OH)Y{-er{ltEaBJ=3@=b8~7h&um?)i;@+g$WB40 zSn@Hw;z8<6{1@e9w8ReKWyr0WiCT(WV`f8h9E^(5Xv_kQFY91wjuxj>R;EZ^;?LI9 zmn|GQ6WKDCgb+I&l4U`YucdQ(6tHsKoST4~AFbd9UUhS)w}m-{i%5KM&Sd)2 z3WYJciNtJL&3FOm&kjcZ#?arH3Fvv&^tXAO{)md4L>p%(RQ}`7l>RndWZJ;fHc>Y9 zr_#p!g`f>PfchIl8%saETs%B$+F*B_QQ1Vi>m=HEctYjRSZ)w9JE@LOT*x{$Tx9yw zu_2Rmpy(<%zbZt+dCfGr4^`=yJm4bW!JKlg=Hz(vXm{$Qu@nM zT4O1tB}9KFSwau|%teqk>&CIY?jmD*VG5TnOvUz<7XsTv^#9|+_M;aA+l(4UbqmWB zCdvIzO{n}C>lQ+0E`&`wRerEd@kF`5Ybr%ueIY0c(Ea10s4q`I>a*4swuq!Ul44!P zMaA|tQ?Px_RBT^&A+W6t)W>zhb6Q(G_@0ZPEo_}l729FG%(z44qZ2BB@R^QVST}MZ zC~BHR1&_lNlG;0!q+Wg@3`bxmSJXGcsq*;=_<7c%097)oTyUR)xYlgiXtr1@FiFw; z-09_1`V-HTP{J~jabo<`ggSomnbr~3cZ}EZ#DqHD`Aq8|_A`go{X`yL0DsO@-TBxw z+W(HJwEtZfLYxA|W#V+)AdcMbF%y~a-eoBl#vD)FKi!?Y(T^pLV@~iS2Qiy1dq3dM zmSma)2XU2Of*%k!rhBM@_50)1`;Emscgr_P7~}$b4VAvhDXjC+N}F=0wYiR;iPKtp zTbVQ(b&Nkgp^kS|I=CkPr|n_E5|+2x#x;oov$?e)AltLN)ovcOK&ycr7DdpOdDa!e zrQ_~)a0rp5J!F~6o#zRLir63?zxD)P5gJR!`%M+UJ3~(1(FOK^TOwM*``xtzi}z&S zRCT*+EANmSBf9E(zj4_I!SnfQ&nOfV2B|lNG3vyMb!?(ApVykv5Q`A6WsO0U?ga!k zPoPk=nzoI?|32<@XYOi(*PWg8w%ki%O&y#sPy09ZNpHC3BWlhE;ennYc_KNh`PuOA>DEqBI4 zii!=+qsrzwz>~?%nLMnJwJT|OnK}ZjuVmgYW6KTAO>j#`IBY;`ShsWGDf5Z!#A~}w zC&dht+Rz`?eGAxiPeK1AwFWW3PLEqmt2RUAA5-K^UYI945;hXy!**u0!@M-jo!JBw zq4V62Y~f)sbrH2|S5zis)&a34;s9u))W0f|6~K%MQ9tZ&V$rj-V_tzwnhdQUXR=SB zQ)ZLDaD{huU+>1Cs-2&Jd zz!o=XmqMV(x*LO1W*~)MieiMbF{DB%>W-ury`|@@E6WKs?wl`JUAyFlVD+z9_{w@? zka9tWBFz0_zX>Y{e&)x|ENQ1@wmj8c2v&c8NVQ<~r^*-4sbKXr0Okn;%(5-0R|lAn zmi>1lfcaGU;yDGFdDz^G4^&mH|27m-)HwxpoeX@TX>CqhnZ-c2D$? z)Oy*K{D2~xS!}C{bjuIk7_gUE#LES-I72uG)%K_kPROmIW0R+pgN0F@FjAbs zA~Vm4Ej3SlYpHQ8%>3uplAHaK$-8xFl~r?FRL#Aw+MoYAUbPn8h0W5aoa5cK#wpRZ ztqOT&ZJSopv2Ck_nBUgXB797D$ub&=%#kkuG-(+Ye5y@U$r2-f(nWXAkztKptdLk* z)RzK$^!k9MWn`$mlKoMI9v(?xNhM1gd2D+z(iVou*5+g#HOChBv8u9I!iRjVEbc?t z7H`lG>`BF*|k|MA#*k?ZHe*2q@Sq0$<8v zyK~JWis1)3S!zKBHPJICVjgqN6EwVW;;6gtE%&#MXv^@{v=_B$FW4w-LQ$HL=V(|r2Ar@%M1ca6-Ya~#Z^u1_oxl!uc1oSd z*P31{n@(x$sG^M^31ynnR8`q?K-n_2#G+PAt1L$AN^4NA=+7vqp>@yLZb!m$Q?!6z zMry?8ZR{>W0ArM9Zt<6{|HEG{Hst?ArMclNWn=9YN7pD$AC~ ze{+@BvNiQ$mFnX7B15Kg`ag-3p?m@+p?pbA*)C@R7T}VpetL9lUstq ze!?5el4zSsh5IJ9F&&k@@rX%B&_w)RoE1w2)F5p;3j^7^6~i1kyCe)0*kA@amlU8G zSH*wii}2Ktu@ETVkrN%m(VL$>vn0a+{#RtIm0`V%hV0gRWXSe~q+S&h21zeMAsXWh z+cK)rYktQ~0SMcdRoCdsB&1_OJ8c53-N?hI_DY&)#`m6!Wg?}k5dlKwNH)VE)T{=h zOldF`ZJ#mprI$)YV4zf}1+|eLu_LRMjT037M;abT?y2$E2H}nq$kiAm#0;7JQP&cJ zGdmG>+8~lbd82am;S89FDO-jKVbE9v4fjCXJ&rZ9)wTK`H}Am1HfU3GIK3qT@)}wi zP)(a6Zvqk!yc$zT(RxFxPM2dJUL6Yr>~CthR-~PPcaEDaa5dzqdrAujEz(` zR*{CMe2d}Cb$c@6YSY7RG zXRDROz*ymKr$P1E^0Yu{B)=AhffIVjwQ$T<2FxGvKDe40vs62Hbps&49CBfK3zuXW6HB z`j1XeF#|s5wLw(`_{9!u5&`Vo{Y??jaHm@CEW_nBn*pC|uEq>F+mxa;_w6z>K+Xj- z1H2PBS9ws(s2PA?*qZ?}6*FKu-Pl&?RT1zkb^9mtPf$yW1?! zMAZLvS!yU&b}P5rPKRxI(07UzCuj1peGe#j?p64^JwmnvLzBm1Urk24zX(ZDHF6yd<$M z_3zZc^t)(emUezDX49M%yKj9Q#Ma+I07jO~rcoT=K!#}$SnDgD#+i1$gRQ-%H%X^G z+I&%#9OZTrd};zCe{S6BN8fKx;ubh(iuK9(uz{4b9FJRi)|;e?$~A-6eR^WUrCEK7r^{ zkV%S4&^}kdL{2JZg>;GeI>U|Uf&1Bb1Qru1p8CC?MVD_VEXK*YgoW?T2jJg(a{|_u z9`LU&>352MziaDId#H=W46|J5O_taWB|xc)(2{2O#&}A+V#VP?2*vsR^;Y=M=yAe_ za*}l(O%3!y&s0&P(OFKX15c-eaXKCP-f&qZZZybWnNABzo=T@VC5ukI$Qc)ZC2mBF zzL&A@LOkAu#CL(qD!WiL@Ita0)4iTawvRE%eS>&5pR_(#KQyduM>8!2;pb(8|7+an z526yU$x}igfZL)2uq?Dyej7X_^+7vjdz-7`clC!e%#j}+XlUMbCkMUYT;yCoITvRJ zJ*0_<6#oblv9tZ(Qq99T&C7_r2Xoo1)=CU#kprqo^C2PE05Zc%&G~?M<(Y^da6qNL z<7-U_aK7U!bZQ+-zBr7A;j3IX@>t{72xFRd*T%CrKq*6Wt6`#=5~vCqkmogQKTZ#d z04KO73{rO|r)z?ZdjPL60`oLmA^qiVo>__B7u~~g|KqX(F3sZWMJ)Y2ZN> zknemNO>{j?7y(2~%dn)M6Ca@w$VHwrA)BcQU_=pYb298XdTxG5kDQ)1J{k7Z`Sdii zB>@f*A5_2tcGx7Twg&(!!otE3_#Vda1Q_;w?t^W?ez>lH{$Q@kow~={#>rd}?coqG z&Ch)Q;%t(n_!QMfZOk(8&OR~D5Kp6RTBnPL;pnH zI*V;iMErO{d2iBTqMwNeZPyss@nzu^6Mv-D2MIq(q-@Tp`Z0+13mk$QzMm7ufx_d- zV*g#5`p)JSk}uc&fug#9vOesX(CdMMj+mvy)ujTN0JfM(Y*j!to{?OqVW5tnVK4|V z<#P{Icvpz(ctmwPq9AG!9SSS(npNY0Kv`ofNn=klZD1%>mqg07qwW(qTN?~~w>@mg zEI_gt_^h1@yxRb?93Ym`)^HJB7$~l7l$jW0=sUZpLOVttu#$Sx_C0C)p0E|EdeWW% zzqY{-!V|rjX36R8859WJdbaHvyt@YPnJTsA8H}%|Q(FRj1E9|b*PLQJwP@OaFP^BQ zWVoJ1EW&A~<&4TadP=Mq9GO?ZRjL__4zvnU<=7kaxrH{}2hoL0sax*ZOxx&67vn57 zL@3!_bqyh@7Z`T@Z4aQE+-O(ihS#vEF5072C_swLS`o-GNgE`jFs4&&izejyL0^bt z5gw4UcCdpslzYzLtz)T>eCmf7US(4pr?E0+T4jR7m(sLl+$e{RUVw=@2vZ0t~As;Dfo;-uOr=D&qOs6JmZZMnfrOC6H8Y)@X zlR5Whk3ISnXo0%(clVCJgOc)hC&%A?*uO(K8<{|UR^Y72VHSc;Z;%Znn&_y(5Gr)~ zW>AH}f?-7icq?XtNlKdMODhg?s?t1|;7i0FG@lsFkIK+~DgKsGSZ%etwj3CE|oiSQ7`G+qPn9pWysVK%^;%{KSoaXeogjzB#)RL(}EmgT= zLT$w=OsEA7grEo&jtI46OsHY3d2t$qn!XA`O$AL5YK7_Rg;|ht00HunSnJ>(_8=jc z8B9s6DR5x2SOc{I#kn}DinR)giHDZnki=K}#>E0Z=`t1kJx_ zdp5%JWePy=p03N`-$eR`N0F&rqwhKQ`MRWq*nyGYj^wj-4d#Rls|t1(M=L-Pw}1ke zEJh(BoN{UDjeMoS(z*JgcPrqr`;~VJj=OR=0?J>laU{Xz%FkD6aWH5J1_VSo<~|d9 zrQpZC3F>CjsJmQ9cZMMQClyx$5)(h_CTPizx*6k_ud#87usc3vfG>zK{PAxY+VdhG zb=&SlXW|uWM^;Dq*H*Q*CqgumY|_uXm4uF(@L?w}h3+t8dW--x!>V;xZ#3hN^Bn1?~^)})>=SO-?*M*6p2hqW>eJE>c7^`Ceya>c9lIpYJ zJUp&JhoUqolsBlkFwUnbzG1XL@XlL=4Ez`xG;v=`$_6Am(sRk4^uuw+;C43v<|>cT z?&MRtRSBU&gY;(!@W@!u@tK%cOKCwUG@z4j;p@I+M6*yKnm?^sg?nm1^hw`7sKj zIZzPEMnS}V8u1XtC*o1~B{Sm{;*r;D8u1vOInqKVGAC_RiD#xlJf;sJFcA<(E{K3; z4rMGyAXpX>vJn_Zr&I{2ZUofkl?X_*nG+DrnM^=UBcNu5fH>BnAfUQ+Qnbr()tUnP zWi2#mmPnk{%@kK#g2h2IvD=Mm8L)`z222mhno4nxfNS#o|Lnbeu%y*}-}$_B-|pMD z``(^mfGY;cPq(S~jury)$_xcc?L1SKkV>kOoYEicmb}X!t}SYY+5&k@kqv^egb0?A zmt?VxZAqDxkcDMQCSKOTmTX^3I3}_zk7Z;Nhh!%S8?#xw8O3;)swmNZzQ1$M^PH#q z>ArV{0Wsduh}+%gInR0hy}z6z&cORdy)akWdeXX5E3o<%EAOzo?y-$PpMhKtwm_&s za<2woEaul{fG=)Q1K(Z)d{-8OFXI?40qyVXuT8R#WmO`P_QU-%e~3#IOE4PkMNYPgz*Td{~YVal)b#1DQY6 zJxn#BDpn+A43$qN0h1ClPMOJ-3RX*ZZJq4d(oz>G-PUo#t>ZWVP5lXyn4NIV>HBN7 zzOPNy$&3@@v9N+Q3B#!jz+}0oI~`GOCPI@qWcEc^po&JiUJny!FbEOTu@!B~vuGHuaIyy>A^|~52bHO`bOwJ!549YDVrj)?1++A*o0%P2>lz2~lX0>_JS@BJ zo|LCl)P-1d9eU)I4e&?8%LZ-0+$jCpZ46PXAHjFoDX-l>d0EPB;h{Q`qt#=zBWC(ND#8W7DW&~O8 zAcPq`%m!)CZ|3HH!p-nyiJawT077p-;PsWH3gw0UDS`9 z@@li2d88q!T*_MBbqGM&5>o^s>o) zNtyu2`Gh`Q69L;F=d9RI1R4ij8yJ)s6d_JHsAVl#8po$vKn4DOj3XYi3q2Zn$(tvu*%TJmKgmtK%vv{Ooq0`Gr%J}lcBBg?6iA^ z2xboeHiH<8-~bH4c(!^?8@;LlBaT9vFth=L@?f%hJoS(t1F~z*m~{=vUd)RCxxpFM zYgBhUF@lACz>N0m9OiFUW3+nA_V&fP(0O1_+`U8*HlNO%h9^;Hq`+H7lDuG zhPuCJ&SJKdKN7h(LTA zVzGRpRTu>f-#VT`V;q4NNG8EZBHb4BQav!nzupR(AS<*DpRA*8stk6UF#i-s|i1z{P9YV@t>w?tAEs) zwmOFDIyB;{Bmrh*>N4RGF~Z12Fm*{$ApMf!pjnxbi%uD^7BTcD2}NgwkfVNWb}QS4 zCEyl5RF@`R;UHxoiyNV8$S6jsMiPbK&UD??%m@)5VjPwcr zY}xJFbj3j}GrJvIuBxZ(_MG90hb?xio0j$*%vPacP! z)oOmLZM&O>C@h(VthuM`ecSGVdVou+2?sQ8Z;4LPcC%;F7rjl>Oj7FEFJstmv?a_= zCR3ZR+-i1`w5gr~H;BwmX1|EdPIBv0PkU=-C+LKkomh~iW~Uzk5`ndw`4H&(shH8} zR%dg%g^z)OAx5|w_|D$)^pl&}kjwGBExx{g*-@D6Pytl~LM29z2?hyi-s463rH$(M#x#v8?Yv7p|a)`k*-<_TQP41J_uM~l&Zh05KCxS_~lWD{q#k`2q?54%+kJeb`o?AimVc7%Xt zZ@0pYs#-9EV$Gko?`&1u8GNGujaLV&)PfwbP9P}OCC(ALh>J}9MgakYJmdz4_ScR~|| zSf)I<@UM?BbI~}-8IUxDPwDFHgu-X>le} zv=yJ0uVlc6a8uD}$mnL2*6!0WrAK8&b_$|IUjJA_^5fJ1QD!>eBgzF*_D9ko=lE26 zQ+CP+(po^!*$#e^2CEE0hI1xwh>qe1L?Vj38HgmB>N?D662gJwZ3q-~YMXZ1vCat7 zUDTNb_(o@c2W`SS8_KS(=_rgs{k_Ze_nx{x5k#s*{kd_X@qa|Y0&Cym+UWa# zZ1j!wbSpdLI{m@A)2}rKDJBkUAV~!&~Bt($K8Nu+W(lqLcTh6EC_s zbSdx$LOWL-l9+}C>N!(Rzc%G`L{OD)&Pua6^2?wf8u27mf-$h9&cD8{xLgbAHIofm znBJj;4Ui?aLM)1+x`@aS$ElhYdqYGL81t2FkCY+S+8`N0+UoI+c2ZagUnFG68DOk0 ziP$p0*g8ufQ^OB3a69lvYldol11sWyLP_!fm^RxcN0c<<8Ob5jb@mr^SrE3!DSNIB zZ+~H=)(mVyL+Nt}fm+uDv}1HoJ#p3-n_BZpctOUO_yue)eL^ElC0`4+7jp;q=?FaT zm-~?0RwhH~(C$Gwqy!w|zrN@tF{Umu76OVd-eEw+8^$Nh%_%*{4!fe??lipy3QA%zD0S#-c+Kw)A`9%s^j$?oZ6-*A z>!!u*z>_NgCq4=?+p+`MCJcgK`=%A~wrr0pfe&bPMZ;;-#9fFMKIBT&Gf|hAO~vbc z650>=zIB9-DByWOhgD!-K$_rF;K%yt16k1^+*2RPK+fpE=H7^0X^;=9b{wh_yf0J* zJ*_Ph&%hhwMj!#r*4BmI+SniaF>7U@*D8Wy;rB>cNN74M!x@2VPpqV?AuOj>1)Rud zq7$U8UY1G%-l7eLcj9+U0=`l#sl3`G;438oZ#7RctyR@432f3kUIG>k)NvozW}A*Z zmj7z6wX%7nOmWE8LbO@+E!JX_rRH_(QrR__JH>0`XUK?nc}7YZ=oC0sO=*YOz` zfHoI(hk97GSM< zLX@l{G!!V3@6a|1%>wkwHxK5JZew5OZ?Y(*cN>uRjv^`o@Y1s+FNDYqedpY`naB;h zuTWZ}WJ%FI@d|uPhDijW2(j1=1#ZZ#qQDLQhQJLpgfWn*epG%F-0`|y;w;-?1p_8ycut?a0K8WQ|IsDgV z&szQzu4VSp#dENDh=AlF3D6~076Y*v=eQm*73iD78_A#Z0@Oe{HF-MHsYmG4cu-kO z09l!J+yu{;N~hk?ucO7regct`8w>uRQxhR;I`w*`QN zAR{V>Gy+-0$m`TPHe7vr(kp{&51NZlMs9kWdzT4Woq?0Bg~IjoW@Jbw=-pR};F2%z zsLpjp0-oe#D2lm^p;KPjBs)3{55y&}?mCj_1KA-Q%-4OAc=Jm6)=_@*^%*V?hDbxM z6`4k%+SiqfyH%1~+@}uZBT3OhDSt}As>U)#3I#!I7l=yW#ME4;k4btmNiVNKwvmOW za12iawFu!K3}->iha}+PtDv&s6Rjf$)%&7J zP+`0qHiuBCaC6(54Y>%IzvI#yev)j>2CYcXU^6#nC#=&O9ekmVf&yA7z!QD-U_O>^ z5KYcv+mQvX&E71yzE%?pa2#f&-vc9w<_(sz!~`}hJEy>33&{X4wV8}mo0%!OMyEzL zHgn)Nlc%<$^=4YEzDzPoV_d$OP!KK1y4FP~H$PKMvtebbNozCM726Z#Zu0ZJkS;#n z1F>Rd-a=LrzpjJD1udJ#3oRpa^WE4vmSHjT@j*m9BZ;CiE6jewB}!@iME)`nOaKA1 zjtC12^+4v5_$pN4fH@X#%^{4>jRN45Q#q*haE@OC3oyWHIY*+ovWk#o&37GqhE5=5 zQEG=9P+BuuGvdwd zg@-ceia5Bo15$Sb%gsyx7uH@pN?gg7YF(8J< z14Cpf`5>;ygD8@{T;uPj0!6w>sZKzeNl6f2pi%$}Lot}BNPV}4hmpvYWhlvfQl+>?7~+w_(#EbB63LIFW!JkZcYMJ5mrdu;zdWHD~5cwF6+{(iLE? z8DPq~UvV&u`W7ucmbu66vOz+FczYPAh_~N-{a&$28qrXs5!;!|lIJOhBSJ=fTna5? zlr@3GUs)4C5*uleGd3g6fsi;uPy{ndw4w1mGN{wYQ5+=v+#5LEOoK+%)(Wewwu`!= zC{%zZX6y-nR8VOlo1H(|)8P{Sqe#&?gqWMRpIV%Es;y6Of`!Fp?GwHS{J0 zNnTFyaq94O3>eRWl98EGB&AaEKz^NyO;wa9lD^e^2Lk%^Imv9wPUYkcysjpeo9Tv8#JsqFp%_H&X1oZ3nuS!sF1K4W)h45 zu7+ehtj$%>a3@ZR8wZ?#42hY(49gL4uMQr*N z)Yj_rA-bRoS28(1uaNwmEDvn?LXWE;zSk=9N)@%_HUo>*PjM1;M0YBKp+|{FzHA1= z!cgL*RQGn2s4a%Tl5YM7qyeh$D7#eLg8G;S7Cc_9DB9q~CAfcj$caIGQ ztoT=WI*6VYYZW#)yztAP9fD2lU|gIkgF_fmh2@xW0sDicc2uD{*!*gYFu;fgum~TT z*x;;aCTq*E$G~KEH;W{ipe&M7Zh}Qp-{&ooP%~X#kfYDoQRZ(ISak>2il( zLdx1ANxAS2r2)KSUJfz)HDb=;Y7-}ySt&6JEXp){=?!(7*-6sOS}l|gd(A#6f-qfC zc$9Ow>M(c6BEeQB^&=)%2RI=#i?gia3dOL2X~Lb;g*eT|@`mJGSbUUf2HSrdB8n_x zJ;~~Zq6$~0KTe`D+0q|K-Ur{!R5(;CGLzc*UFdTz)l9y^HG0-{aY{8a*AKQ-{jz+t zw;|r}eT;0+M}GqLRo)%5B6?o^Olq{~XP}cX{Aa+%`P0381P`qE8M0>VMPspcx))2r zGQg}Fj~N$^++$!^A})(C;a+CcJP2&oJVMW;<+9!<;;wPqQgOJ9!Td$vkVS|d2s1-C zmoePpdDs9+V(QGodRTJNB|C@6PWP%)%^G$^bEdA9Pb=`P#yxnhiA`U#cz(T)z-eoX zA609+$4Mvk-(ZNG&r#7fD{@cSnm_>FQRzE&B312_E%s>az>b#Aj;W#w-J<4I12=vk zD5Cx#7 zWyu?0s$Fx?vQq6y7&8@_t!6&3*;r6gh>$_N7i@v?GFlJZ{$SKGVP6(Z3^Wyx@YRLR z0GxwaSTaBcP32wp_(rbUb0O&0nMmt(u|uhV0bK@ZHd59^NXp-6F|5Qm8Kyc9U(O!K zkyNY-0}_<=-7LTg&7$vSfdNFbz^!fns2;Qv8aYJ}0VRU<54G$u0JV@U%Y*eEk?tML-;*B3z0w>%g&Yyt_-g zP)i6}GRF%x+%aP~$?BbCRpIgx8AS&&GO9oUxEyagb1SvfP=+<78(UKd;Sv$CLGn=V zI7M7bgIRXq%(6D{U`vq;%jT~ap2bNxLX43@3t|v7by8GyXzap#hu(Ir5F5;21nt&# zSq(_JInRYgyj_-|T04x(x8n@6nu6ewF6u|lGHbJ&d88q!T&CH^E7)eS3h)HAtqQ=h zxC@f-{rP@SQ5{HS=ll6bBBKhx5*fAg{fNlAHhWsZ7GV2HeKKB}2;}2yB)|P)prz1H zLa_i%1HGYx*J8w4`arBEfElZOmf?#$%UVacr*Yz0jIC&5=?Od-)dx>k2M};8+ zbtAQ`-4m6UxtHBDzJLfaQs3d3?7fX=KvH-ngKy*6^X{1)?ZpF&I8*36nk#gQ#Nr!) z3OkT$paDyWl(AU>U4Xn6m8Tv_Vwh)RXwHJYY<&14)Q-uh5zIHZ(nd}FoYB_+#{pQ) zk0Q|W^r{82j4_4ts5}`X@6D8d8(Ee6JhA*nyQI3y8gf0R1G@22eB3d32}LsuyjVj6su;NXt>vd0&}-$W)E!3NMods#&XPe$xq%8Q;MkGZH;A$o zv=XjlIA*6&fn)J$RLB8BUW00o&cEIY-4JPr)6h6}r+nNTKx&>?x&vh3AIwOoF^vaw zHWfz+c&QZEmeZ&fB;(o4VanM0)Rja8>u~BVzTy#v14FZQJfk?`z_N7+q|qo13VrNA z{tQ>0^HoeGp~o%hT>c1 z)X@02tLiCw`P^w&JX93R%wbozEbTcMV?)CWGyGtovl)IcMw<_P&ZhYBKxezKf*ntL zWG0$1!#d;ZwyEjR##ZYqZTp0uyw&tpzUg(Jvt{ZD@#-?I-o}HIQL@(ZOu?^5nSv3dR5sOb^k;0U z^I-EynJ*TBO>ImK`&U~p;!MHnDPS{~DQI9bcf!>z<+7fG!7?=5mMJKGz|a_R-G?|< z5Hp`C$Q(VyOLIx)Zp_5%Dt&g_L!5tDoB97%U0V z-Ef5^$vBU#D&$)l3>DU7SnQU4#k;!qkzB2kDlYnu2C7S}>@~W`xom}Zv2dMWpme|u zOdP03MpL-m&k{F4c;?1cCGb{ezzp%Aq&6OGyjlX9tEyQjtgD=orR}bkjXlyY;}RV{KsP`k_^(-k06nuedB&2$sU0PS z+q5#-q4IN%PRI)kklUe{pIx1k z6h5mYYUX2-!YLgFa4OgZc>ry4lENcqJ6R|xoZMMbP}_hLAD-stC5%X$uyLTEUa6aX7bh5%w_C4~xNBq=O{ z7~5P+uv#D~IEZo7%*mIi$@7weLCs18HC=<6g_1%W)QI;A^lGRvNx?x4k^*yFCMiJt zDoH`#&qPvq6j@1pp5EN)p-Vi=oaK|at)dUADuF57!}_zHia%>V9ZlYRwrLn=MgKW8{r)D zpx8bRa2W`ZdhA>@Bp$|o`Rzxs6y|oCR#F*?Q?n1+Nf-bWwgKI5sHK2q!mjNw9aw^Y z6l}#>_2wi0O0!UwL5cJ_$&T5SIX(v^e3rj+oDh@pzYM1cmoM7y@2h^#oH9%U*bxyh z?A%kW4bhfbfJu_uI@)k&`o@f?b;OJ)a|beri@bxB*HJX(FZ{R$QXOafr@eF(B4?Ju z`mi0=_cdWXfOiAt9WVmZ8q?s2AV)^j0D=gp0zu~?!;)Kr5a}om#7Pl}fDlWI1Hv^m zHN^7Lb3kaAGzW+drI4_WIA9$>xGnp*chupLp$|$G7kv4s4_Y*3EBuCUFnYr^LkS0) z2#~A%18BpMjtW(>H8~0{;MW_&E@WCloMGAr3`2r2*x(VmilC8I8Z#(H_PQt z7-2aKiBemzrHK8Dy>z?)u>~|0I%~DfI96e@$g0`1sOHZ^Cb-@~8vZCwh{6D=XN*zCz0l)gU7J5*oudrPjsRHiY=PVkn`aJ9hGd&Z{-bw9vUwxMX;e8%G}+@2(MY>L&C?pG5=~q?1U371 zLZ*qDvM%aJA=QM&W*!NaIh5HPnqXl43gC>(i6`Py4*zghX?G1DzK*6Vt}CauFn^lD z>N}2J+G@!s?5P-y1k2E6S~D$>Vp9{XhJI5Ou$ zuGWMgEO=G*e*iU(np>V7=A(lftI^|OjxAx7X$v=Ih!rIc428fymJ*dZ!r5FpUP zrIr>@ZJ8(%%}GjC%y57CLt?mZtO&#mr~kx8x;NnIc75WyC+vo9=ow`p{S$c#d!vxrAs#%n98Ewot`+9<2CXJ}J#El996Df0-g?zM-DG58krQ%uHgM3xUvI<4}0sPBj%STPDYnO|-*7AOLo5f&IRp z<(B>8F3}c^hVRE!hSldzeK2S*1PZ7ry*Fim)+|!78>mDs{y)@k^YSH(5b5}{=1w>L zWyS7+EYf$5Oe$AhcsOzAiin{0_;XelD$ETIBF6g&EFr_j2KYG*hJin#PX>O1Pgz<% zrr!+qVSO^JhwPKv)mV{hvqv>ZKRC#&79k!YsZ$K`m({I0S}D33o18lQ;bA=@tnC^R zfrl6$%a4ChK=o5;1y!>J^om=K_!z}rIGv^Ft9SI2j@-JoQN$F0RKp3_Eq9ZvE?HVf zE0I=cWXlI0&?3Pz>?Yai1$XDypxG=YS{d*~yfffQ*WcwF?Mi{;D}o=cB9U z_BlqVC?)L?l-S+f5yac6e>1!U zWU|8~LBXx$b=M~UHSIqOqU6NaZzajKiKye8D4mrl(2V*>y@)aG+?Za$DlWGZ1pP<& zfS%t>E8D?Oj)nX=rJW>ed!e2M+SB+m?l(pMJWca^%2Y;8EQB0BNevU{GY+h%s4c{r z(|PnZ-*7z?{RJ>n8O6RQ%+)n$DuYrXCU?sKKA|z}7H0ApA@1=G4OL26X zUSVGu8A>|wdV+quGi5UVf|wSoPZ1YaL2dc(o%>1P!gx~l?b|&+T7J(Ra-Q)zqhvbf zG+}5;M@ZEq3%{>Sb;+xhZnE+4J~gL%J;uMHPIz0A4~wbKVb!yK;A>+0-T1wms5s)r zy!K3*c3<997zf;PKgb2a6$36G{*6CcdqKxv;OSNv`l9(Gru#h?0NGy5lBcrjZtv+UKG**@^na9Mx) z4SnTJ4T$5;!gda4_N#TouS6kGXP^fVG2XUyYAN)Sn5j)z1beroo!c@vYk9M^ z4>bokto?&5t&SZVSCNG{=MoOTu?P+n>hj@xw~r?!7BQScz|9_r#qmV&pOwk=3F&l2 zetk0J15HoCV{H4U?UgR=d`{oS|ICDwFZog>Ta-`M57g9E$#9Yw;o++S<`W$r2Ea~I zEEWJ|>PmumhCSh`-% zS`*Pp#>q!#B5DZzP_IvZQoYVKD$2mx$lc$)9^|*R=?K~-66NJ7xIv04!AdLsLkq$m zd?a=_Jz~4f%#h_GV+Gc1pO1KQ|(N1_H$AM$ic_DW<1BHv+Yi zE*Ettf}ydgFT@8sH-ewl*rlGy&}T}CmAlrDZ)0C{=SEluoEE%jNhTn$x(IC+ED@9> zD^WjLs-U$kUG&AR+jX4H4x$Ce47j@mHzKrP!Q*G=V!^BSS{7VN<;z}hbo0i7ql&ZO zopZF{KIA>x(P+WlIYqmGa11LB>RKQ?es(SvylU^2T5xu(vEVEb3y!+$kkK^QyyWtS z*8;p-h-(Fd@$wU}i-IC0z1kWvykl5Cj06Nq;o_}B#(XM^#$p1a(;j?#2*a}k#u-uS z)*%wE^#*~VgJlHfm4$a7fp_-sZVO()V9SEX&(6hySM9x03r>bn1KwF8;Jv$h0<(mk zw=hsMkg@(8gRu*GZp)3Ku!3P@w_>0kzT;=-V!5mKUa94tW1y_IA&!ifLKo1uC6AltLbX^U$&Ze zx+|;w-s)O8#Z=p0D_8kYbO(|(UV!rCZy+_vEKl)@tJEdeubf(q{gh$}{=KC9iUTGU zVCep`s$E?sKTd4che4|%iZX5Kf0SWx>MEYayPmhk5?Go&HD+Q zk4I+(ZghD(IxDx)@vxF*!q`w}U;=~y`RqL}+c_mq+8qv)yxhD)eknHD-GX3DL%9I` zJ8qCph$)!Jzh9JeDdBfhA{$Byc3Fya1xjjlXzQv3(+jyHS0}G4`^Vm2~40~%llO}iQ% zksI~!==wnB4kDM-Zklz-9h6@jrgwcJY_TO38fiR|Ew$UiwdfJ3rOMP`Kw3Av3(hB@ zb*L=x|31%G;?u}$WHZ`{IG_IyO@w35zr+9ju3XfLA0hBUR4?3gO<8^`DY!iC8cvw2 zY)SwFk+vwZtRjAs!IDA*amBO1BqU8Bs#{7LP_yJqG>zfWw~OAM$0jID9F#B6qNs{yWW>)M{y?dp*S|8Hk1MOw*YKa zwL^yRf^yc7f*L8dhz3p`qA;rpq4V5OCcz1N8C^;DA1bn=Gk#J-r70~sZ!uU$$5v;hJ^T6YAa+w=ErAIBnN?Upa<$N0CkG|5`|MSFBr2r7tNUIv6;*8qS6 zf*z}bo$md6YORWH`Cm8k?mfM`agRa5Y&+6&Kak8%9nCJDS^oFBLkNcP&izE^x~v^6 zrP-leW{At66h1(syqRmynA8gJL}4zkGasRAXg+~0D+Q21#LIz%O*?$uebd3=>+kK?f8TWN@N~WoIKd$}N7T?z4UO6w!f#Ie%;DqzIsee% zt^4k!w>Q($e|7t8hius}>TtcSLkQpM;r{);8s9hd{oB0{-OKkazS9ZcuDk!ja3>OU=rZj2;zl+pKJ2Vg{vS@*H zIPZcj#&6Jyd>G67v&uP#$;@2sVG+L42f`NRG+S(;zt$l`QxmLt_ zgNEITSo{4r0%8r8z}jVtm-6*I0x4S&3x)?V+*G7V@0~DU#YaOI1MMqshM{?KEYjKj zuYh+#Z}Z!xdyY=`DtLvX=%B(zXmf?Wb<4ZnNh*nmF$_>=EWz_SCEQnMPv!3%$q+B$ z%~9Dd1Qj}z-O(g>@MH^m5xphSaF!av#`QS0$BK=C8Lr&%{+4=BS1f|ZsNA`u+_-(d z$_o5kfp9B@ro)=-!6wQ@jvb;3;q+liG@n@V-$Mbnu2k?TW9|%G@0ogqiee-7!h{CT+tuI z-gphOzohlIFamxw#Z|Ir9j0R+A9ya&M>2h2x-0 z-ioBWRMwFUQBZ=Wz9Dk#E5Be;z^qfJ;m2{#9SQiXg7Z*(T=K;DPxW__O0FMHlFSP+ zIo(7~8#IfQI#$AZNHU$s^+D*ey*cui!^nkYejFrH)z{!od%Zt19cs-R#S=Q z@kN`58Ec}dJI&)0yPpS2T|Ey*Zu4NyHWQW;Z z13icSuc_sW@OqDwO>y^KBD z;w}xOQPXhvamd99=kiY_y!VKjR;@ANo_uhRp<*dP6G3iu3M+d88KP^tm{+}Q44G5C z7LLI^;OLg4>W6Vi!_qj6vYxYXh-xcCJy+vg{6Ro#H~LAM@QVMb53UQ+Y+co2e7{y> z{EzjQOAqCE&ih~ez;e3LiXuS4~IUFUjA%I(B0 zJ?h?*Y%H6b=7$`n>o4R*4^U5B1xfGll0vGsM#FXh4L(4zBf{T-Vwa!&X}+iU2rzTdY^ud-(f<&x-*qmYzPi=JbnN5$$u-gqa5B*p3<-P*{>B7b?xyF zLk(p>vGVZFe`mk;-cg=zeWz+N)c;`u_+)g^A_*#>oj|Z#^y`j{ANz5(f*yckBf8Qj zbSi_6oCgx^)q*0f>#Yvnv272kwQG0iv@$8=m7a{_w$96I%;AUa7ci4hy{m61ZcL z$x?xmEy$-_m)RxM5DU-2dn+!{n`B?r!l_z`2E+RL9|*co4p~93`;lcMwuqW&6=&gY#M?2*ej0UQ1GSH+v0Dc33FxJ$Yy-m-V{&$ zo7e(G4vp1(*_A0iJOeD@!;!1WJ#fyT;A+D1d2M#n!v5GpqhRU`TRidx#3>p)vI4vI zzVWvNbOGP#Rx2SywyLhj$o*uUc9yKugcjm{%ncx05#`voomGvovGPj3a687HVV|VR z@A0lye*B;|)U&@8u|FhUZ^`{&0cdm-MDhO<{MmthFOo%5cf= zE$^1y_m_WM(v_bN!MMD~WoE8fWGe zkoo3JaP`dao)-hvy0= zq&S|Stu+w`>TjFuNwAf|6M*RkPw<^ryg;453|_#?TpcRHC5l;*e|SNVs4Te7M&l00 zC&bXLjOPd>l-C@g!P)0nYs4RZf3=g{)8V$xmAm~$oTyU(%lp2Gd=pTG-k_c1U(C>jOo5)i>N->cBbkY6(~Dy>>u(_ztnFYAX=@&S_3 z_;~Ndu6Q#sS*5Uk&5BPT0-4;;7yBqG^_4j^WM{K;8 zcgYnl)~RbR9#ZDi2PW%A#5U~3@?Sj-AQY7UH-_N#@ApCz*NYAR!CN%JHO~3Xe5~nk zK$7te=I`NyS$yDN{&uFSqh4&nX+7cFND}VdHDws@on(%D9>{MYt+Ia?^XO^*+2_r6 zg!M0_;(I<%!CkU9FxNYId*v=_S8sa=4DVPwc+!}%y;X3PgS~k?<<;(8p!dwH<-f5h z!#t&>hhNN=GfD2kD7L~lk-mX^gX&`CV17bS)jOC!tWPHYpguPa=J)d{sAq$n1JU3; z&@(`x3EDw!=Vj>GQw~I316H%5Y4TfgggKa_&y&^*DWoUGh#YAEtCRr*fH$OmjU_lU z8)Fg5HPGzkjOBjV=?-IY1cr?$PlUXuqO)8kng`jO zmA>$U(uhfB7SP@dGBm*q=^CyCo8@KK<)JD@B7Vjm#)6r9sVSJH;^5;&-HEV;z6@yL z+q6=R9e$q$Aq-H`sEDrgJFN5)TyMDB76myI-v5v`U0lFD|Um)qwhT_;1I z`|bO`zx==b^2!-)-{9=F?}Z2hOOdTzVV}Kqo?@Sk{S3Bm$)ZHqXRTJ)hgy(ao&51f zpiws@PM}ZzP`?^my3)W%l!6(Iys)JW`n{N-z6x7<__?os^!NYd^AG>pUz&--$f>9* z;WZIeC6IGw4;4Ff7F6|gjFz%J?FudJt@9KuZR}@&mP-~TLQ8A4LQ6$}Z6#m*NsoxI z-vh~)^-CtKYD>AmFxpbW<7c*%WcgQgOY2Z`80Cd6HQ{fPSJIQ)QVTYZ#FE^?`>sxY zUE3*|%L@mRe^hPmjNp0PnF3AlEIHw8clc#*Mfl|sEp{Pv(*8oBGk%6d__Br0s=cPr zX=6VF{93Xo5q?>#4!@$!m=*JlK3|);)n39+O?j#|+TMy*+htiSUv1OAEP!xU#CP`+ zV0^510`CH=jea62E-V|-5R?boD{36rzEH#`3Nf@t6k-VT2W=~k6t_;fYdx~FS_khc zmn@1rb?PLvDr+HvvqCUL&3-FTGpcPRUktyp5;C=k;Zz<}z{-f0%RX{SfSA`ukpA)L zirT@at^f%TIiPljrFPl>?m5Wa@~M0K%yolZ@4NiF%~?kKem<#o)xN`9cB30C+jpOD zQ0+U5#J+bAzxdpT|MJ(q{?C5(KZtED!McydG>$vBcSqywt@CvCZR}@2sth~*y)z;0CXJAq2hg8r^IW2uC^ z8%E_qDBBnn2WTqztzs-9a9wFe2%zHYLB-Ma7u`rRf*dcF8kB|QnPSmx)r{iSO=?i< z4XJ?+mTN`}BxFTpV1BI_71g$qMU0A0#IkBe_4gu1)uucxVpMw1Gb*o4p>v^31;@(S zF{*PTR-R8PR3%pKQiVDfVpepX`T|D#`RV&w%!WzqkJt-6S)fvw1E?<&uwMzw3& zc!5ztWoEqP?N*}(qY{<8D*3ko^o>#d>kEvkA=*m4eFYhn6O$`h!5CE~E0{(F5AhmR z&8S@2;Sa-b9^>-Y$jT>{3|{JtAylUY8kID$CZj@?5~DI3ArTm7rBS^Ud#uR)qP_Mo zj)q2MZ=I(am5u!jtW8T6C9;25tM0bC2wQbxy=0nSkyz>68**kHNIs(i@hViT1Ia%O zzh>pk3!Li$=aSFhy!CfPxNt$maxT&T|EXC2V2*R`JqIe*1*KSW>!$;+ zGS2nU@aqESx?mhMdsHwxS(NVu&Xp|@sV^7@TNL2elyUHt;avWNUKdxRe576JT+Q=& z&#%yV8~YjPTuT-u(z&eF7M-hWD%PI`bD%M*Z-!s9jOvLv+~VThhFjQMkpg@^d9iHl zXRsMd7G;95*Si$0)g8kvE*J;RRcWSJ1*|npvA8XkJ5I3mH5|AWQr1wh&d4~pYbQm6 zQQ2D&=$}tstjbBTOXJ`&Cq>PutW|gAe6$%|3vG>JUwGkM#J=dF=_VXRo6*}vK9${6 z&Bb8zu`gUoDVJjWj1x34K5%olT#CUrsN)t_B9|iZBa2;%cEhymt5|7uDaNfEW~lWB zX3)WM%%F(|W-v$Gp*l~n;Zmep!=-qVTs0s3BCDtWDx19j`sO251k9X07xOD+JKA$g z+=>KahQOGQq6}Zt2;Srt#sU$5@|T&@wQIRT@f6j9U63oBU8ZJbPOe~)03kwfO`7=X z1KwauwFAjl!mld(V55gB7g6h3vGCkj-p?lo{&``)Xn3Jan2ea;ZiH|(P)Ek{aurJU>PF$(*ahbK z?xJv)*byR)$XadDh-Sn>`rJxhzR!561AjMSp&F=!ibhEEU%x2aSn%+9+&adyA)f3M zj4RjiOfc@QT*vqFUNac?Wkum$U`jh#-p__9{lzza-BSNAFr_FV>jG1%Z@KZQac~SY zvY2h0v(%6aOzC(ymA_3rzQB~)GDKb@OvzGOF%y_Pr{gNF8@6CZv8rQootgJANBTtJxD+ZJ7n3*Uqr(fraetxKseInZ{&Nu2 zWYjkx>Joz8Oh>l2E^x73a50W9C3ya)WxjQJBZ|*GkbE@Qa|0Lqa9zOT|0FoNkXfR$ zEY1ssY^h=DLJFj_61F>!FL1HfKz#12$HnCOY9^Ju?i_HjT{|Kh=KKqe$k{WqoFkG& zl0~e#dpz){Pc(Sc&xBtWG_4Cf>aTAkuJf2&(6mA*4(G+U#?+wyREGdqOwGAY(|`4N zl#L_;(sdMoN|eGnc9`nOpwdE(^^mklEPi`7$Ui}ohzOw`3($e zTqdoi?50Y0B{#PUaOY`uDCd^FtJD9`ovxO{TM6L0hYLn}%A^^&DF_3 zm+wd#p6GfIu0$Ob1MYj{jc$4D$b{~=^bDiWJ=j1;%$$85^1($ReBmmh-_}T`BmFvB zjP_55WpZP|pSSBP*MGB%Lw{W**LA*?t55peVmj#)AUoim&m-lFT`lOOhv|(Cf9t46 z#A$Vd#E_da{3Tbq5s8~Lii9Dr#G-r_Ov8s{Z`{hB`CS1^c7K{3Du0tLqm=6*_`5xG zse)IWxR&z%^ji1Y(C!rKI6E1JBdMt8)0!kH60?dhFEPUtY^)=l_ zI4HS3zQf1gMU0o-AYKsi_L zvWMYO$z73o*#(2T4o|YfLh_Sz_COjcIk<2@HhxHJq0RVQrW=aDGQK~WO-F`~y5<#3 zxi)*T!zb%{TA%!Wp`(=@l`nCI-$;n6RSqk)=oMZ$|4nf?V*sTGy;R>F!H%C{j^K&dE6dC?CvEvRa0Iyyxn; z-OE`kE2n)|?smBFaQsT4S;ZK z%>s%p&+d^G+HQ*IUf0~vMZ3QUS{Pp|bhSXEAhv=HA+bYXxFRqT!;09NUDn6=4fv;A zVdL?D{WnT3&|opRF)Tp;bj@G4W?;j@aU)c~fayl#8Mj9 zv@W<@1t+3{D^&1kRB)vV9*YXztOD+Yb3@SjaNU~bLHB9VJ<9#?H5qRk^q`)T?!$r| zB1naK^lE&jz3IK~j$72yUD_ zG9A5pvfHB#@^RT?G1dFZ&iw=UtzzG(N<76tX(veUh;lj9032%8Ol;IHGK4zdOEL@uP6u-1lRhB5<(cP7>&tOiu!F2H~X9c^CU!74)rDeOK$?NJFf ztb5eROE6(v{QwL0RzJXiebo=3|B}#}_WC91CI+V5JZQj>3k;ZL%1|{(HXZJ2LZn0; z71sFC7+ySsIoXl%#(i^uWi+bBcpEcm%rTyQy+nEWZM)kPU}S6+cr&lI`Bn3p4s2#3 zn1V+UsBeF#cl!kGL%Qu`09>;s+>Kt+vY-jEul#_6CcwwTCVhuzch5cpvct1`W}n^b zo`HM@(QJb?I1qS(K}C8aP^v)r=|~$Pooqz!x_cfJ)LnkIO{f9X0<&X0bWMVfF&>gy zF6fK!Fe_hz;ZzK@5&?ywPEJG|;|55EB>9vdd-zdFffwpb) zlnIn~f*~u`kO^@nw3*x+Jy5X1K%f_x#;rV#noir;KT_|zCuG}L)U zv$->)Iagy|%uP0HbQ3q3;Ub-)CyD}w)%+w0{6wf$_GCUC@yksn`j{2$4<$E+i8>!r(D@wFnY0H@S+FKncc0kZ$)DL6+TD z1j+T1q9Lc=IU}YPIkI^rrm|jGfY81mYqb$gWl)2%Q$DgX{-j2(7){A4aNQS08WShG zNV7xQz{n+PgZszRQ+`^pEMu~Un9vK4F1g>=WFF6MUyvEpIH2(_Cw?M7!RwI70n&;t zc3Nc8j_5%wlXgTCVwtofx)95x9npqZChdqmL^7!`$#G_l6^Y6e$>*W`iB_d=6Y67T z8-L90X!)x@s~x^3?C|(Aey4M1=0%=x_A+O+y7xuSV$9y}h%-IipDwkzVNOBij|^_u zuTnGhBHDS8!R>*K6FW)n?IiY_^#%RCfn!$BoYzCq2V*-C9ERVK9cfFy9j7rNsHrI@ zX6(UqEP!BYX8p?8LMf}U@oL)fEX^L$sC4XUH!h^-oSvt{xRBxLj_v6nE<{(=M5d#- z5WcF}P94i*1$A35xT8G?%Yie~b6Vzt8OU>5exQrgwjA9|TP*>aRXu;?1ZJjod51mf zn|=$8<@=_ybn@-;5_w_#X#s^{|JG#as$A)={~b>9{17FYgvUfy56I>RuXe+$`S@|Q z!K2Hi7h?D37H*03uC*&%hr?2o`0`uBTUufFqN{cdMrN8he&>%O5@%+%EK@ASHncZS zkcl<=>)g-=VQA5~jPEzbW#;Z^JQ9&4&`I1uSPe5T9}Bk#uRYdDvtaVy#^j$~p&`MY z+WwX1y(rhlU$x6+zmwj+-pSLfldN&u@WX$6cXXRQ@R5{{X3p4unQh|u_x0A0o2cP= z*JhXV@ug30%iO(5lr7rs6_or#_5S(8#eGHc`FjuMT-Zn97{XQX2`LgZjQ>Cl@zvz2 zbo})&n)0BoC&w+(v0H2P4I)uwVd5gMwbKbpH~vXm_DsOpQv0#AS^FofHb5w^(fFtI zON+BzLCoLpru_gh$J5$Ll!1)}yE1-K@5JCEFy5LnO*|@$?+S?Sk*U7D8O8G|cWpcu z=;)E-3))1ym4ygf(^uS(e!n%H z_YWpNz&8$CeiI+7*C*HT3N%jB_t%y)-9FP5BHj76k=@eH+EY5z3^@tK-WcC2P#^ze z{e=L4Ow*+7vP9HP1j!nU8m6`J@2i%5r4rxOu$lLU!ER*@Pwi-zE+dC5B~p*%!%rOi zqm1Cw%7#Ps_N^nGk6k?)nl%FAGgvFr37beYRFXU(G-@D)v?q^N${u@4LOa^CGWkWqmD4v%J$?>An8){f0tV;|!?~Dm_^&Clhvi z{-21&qv`tQ>T0sOny!ZbWvgm$wclG^E2k4t(sGp#+>Gf}$zy=~vGVk9_;sZmN26*% zLb7t|s_f@?XRZ9br2Go|xs^SZsstz8m)T%!Ipz1+1GT0H$jon?K-|*_KwR)fc^u5` zjQ>y=exzJyy4o1Lh3^`DPc5>tPq`OWv$u}kB=P~0KEyo? z<|9a7fNEuj5PsSE@`W|g|5Izt>*ayLq_o+*fDgTnArqkQ)}LX!*Un2=8p|u5j3qF@xO)X><2o*Q`#>o;_Y4c zh>satQ*lc;KB?UkK5Ie8zh>PfBY3c1VBpjfGQjHenrf0jw#FGyR2AX5l&XKZb_6O@ zZXPSrtCMf7mHlJyFOv7m#Gu;SP?w|n^5WVwd3Tr|#5Y+sJxFrE3|61Ya0$(aHr@!T@Z)bA<2eoGDH*RyTvGure&(xwkzPjPu7I}o` znC~nd+McCDPrdf&&^`y=4o;WTp^K>0hPSUdIuz!#107Pew)wm^>CnY)qt1#BT`pXF zIQMkuWE#ms$V3*(BfcO16J9)=??8)kCllpfCORQQZ24eCi*iSc@<=8+k?+Sj9Lq$m z#L=QWmWkX0qeYU9%S(LFQ9Me0*GNzAG}0OA?Ij!OiE5-RRP!Z9+LYd0Nek6<51Lfd zSQ6I_;YbMrTqM1{ei7BY`mCttx80>OUV20CaInJP<}?$2T}dT}hyT~f;jJBV}Z zLWcDq&Y68s8h9k$T{0`)U2+EE-Idi2fOgBt>K>}Lk)c$9v*KMnr_(cYGPxO% zwG#2LBel*cJ8KaSS+zyPs|3~-Ay4--?I5s*8STI*RIP1?9HVFvS>@L4xgZ#mE+vjO zAk$=GC&9jwvg=h23eSpX>=#vd9uuI@qCCA@p7DI=%y`CWd6CPdx{ESJJ{W+=Eu0@$gE`GuVSC_}TY1 zfQW@$zKDhV&9h=5J^{qD5O)&7ZVUi*3P@=#6EPglGmcqE(O@A}-UV#?iZ&Lqr0w>K-6UxflGxOmpZ*sRv8oz z8GtK`0S1v7ma>1ArR+ZgmU6%$v%|{eEM=WaZ3OEz$5QG!ZFie&GO(1&3L-aE+niu2 zwH2hY8gyf;LAT!0*lLi8r4URQTMdX_J2M-I++wv|r#lKWYO)k+HElY>1+(d%(QG0a z2Tk@Bolk$cO-Ivi+nsh@Dvx(3uXm?qKA3mo{mIYTs&iFB>&ACu>&_e9_MH`nyiA1l z8M6zX35R@UWe2`9qg9<+5#Kpk@tqb9d1_^rL%Na{4(T53jzd1y+hL?L9P$Z8d6uWD zk+yKiCwj9S(v`GuNcW(XL*9>nJ7`tx!K3_a;gI_mamcH_TO4vLn5Jep;+9r(@+hdkLA-#K0JofZyxvOmiqT}cavbPs9{xp#>Ud17^kkzvBWFSiY59p9lX-00EghzTyA%?_nh64_&8^G zL`062#%mfZ(O&R&$2YgJ#3g;lN~5(SyCd_({MS$#KU=fJf$4~k#T;-?tRwDi6ERHMPH=)nqRc~z(wSQU}J3{uOvXrPbn6y!8B(kCp)>9J)) zeS*lP$f3trT}jJe-2*?`l0z(5J&hTPct7z4l?F!;6ZUciIlZpIt}-9wgsuO-h}jiE zI2PnYu+#D&r`@~B>T~iGl*ATc9XpYeqhEQoseLWSOhsObCcy| z5?*j_G6utZ^WY{^z#9zaw*tFTcAg6UiDy?lc5bq-tH4D)W#tk#nHi@rj1iT~S&W41 z5;5+go-#aSG*`LFEI?AevdT@i0%A-#oxq}?c#$ZmWo|N-BC?j{qr&|r4(S(LB8GY) z21lLy?v{GBl$a1LX#J1raXWm3Xk+7jW$(4FW zR6WxfNld6`v{LVol9?O3MDzK1a&wATIYj}wkw-6cv9~Xm4i*wqV6(au8z8+ zmnD&EX4ABB$2QH0+rlLpTedJ_?NSlehX>AcQ9d8y17RvjD^mgT9vd4tQYVKJ7 zpXXDNv(M?1-=|t5XQ4RM-g3-Ao@T92gRm>CkTAgG$@u5=*VM2X+U|59PK2T@RiEK1 z?^(!I-n$c5ndux6%j2tOXS#8M3BxOb5@cNE z1O0P8miGBNmKHeoTtiMWI<7ora+2{o;woKbBEZ(4cj58kDw|8RqFMZYJ*x=~<1dih zpjp&x`eF7{sSU@GxxH8E6i9niuhpD|>54Edn=XE(2**XmG#l1zF0!_UMuzhI?`d(x z%?!3?qq2#t_7j`g-Wk}6qO!SLm6ud~CM^5y4cM|byn_9%HrOI1d{O5yY*{-MY{4*- zb2C55gf#?5^V?oDzeDqH`1$=H5{`j^lgPky3p-ytzig)Gg3*9GS#)~bi=q|C4hjTD zP@_e+T0Z)F4njpNIGfGr)0DHG%GBcjL4!F86=M6LV4_e3SuzrLZBKh5)SGv3w0@Z= zdc6v`wSa$BF8g=f00-eKQ+{bM<>b0=`>|2|+eD;)Dw4cBji>{8lr<*Ru6Lv@{9NJM zhEk2Vb5<+j=SV0zw9q6JGJh1r6SxY4lFxEVpw5Cw?LNb|%)C{0Q;nP+OpTKB^~Hgm zmk))XNOwT(SHZ!1UYOH9?N`K5aTjf+w={yrISf1zz0mg0X(k<^kG7+6gG*?SU z98NS1t}kJVti4s$u?{+G>7E}wLKHpK*UFxouGL#QUA4h<6I&+cV&Q`#x1{?b_TJj0 zxVG|iz=p-P4mNWMTn*d{kip(jz1aXSOIvuv0j*_ipjKJd1||TG3e@=q5r8RftO;Nw zW>={IZN%wup$EI}Z(Tge^1y$RIi5;@(}8?rKO8nW-%P}7*A+d`Np=iqGdo@bV<1N zy0A~+&8sA|StKJYAI&*=<+&I-;(|QKwS+rs3F4x3EKgiS4IL@8g#2m?J%Z+iZW}A_ zzTLQzsI_etJ4MqTNH}p)6o1SmakaPr|3B-&~KoE$T)%)Z+)dsV%ZK!EG(QQv9Kx?@3JHo z-joz&nW@7|0E9`V33vG*y(Q;^=<*C8;g<*Z-lz#C^^Uqc!c zS}3b}msrLIHiQI|B)CXvvEj^hW%OuCceY_OLwB>~*tGW9KD>CgA3NjO&MupLJObA8 z5>yotuLH>g%7Jwu4|~mE_VcblkDUeWp-_O0!RsngOL$)CCi78#mQ22R#Cv$s@-hiC zyu!CiWr>l>r2|S<10h{HV3|7Yy2y;!iI*C)8UKpFUa6!}T43e;;6bbEg1Kd-yi6?$ zU|^kOh$$f1NsO1hT9L?Ro1j-Cm=z%srK$;0TQ=Q7LWI>G0+5zIW>Rasgc=YP#4;*l zz#onQ8FK_syG_}2r1NCJBpuA0KWv2OV{4OjL3%Oz%ya-M7D0^c73&iYc9?YXL#1<9 zAXv`-v&7^btRb26SY+n00I(!iL(d-kO`y|6y39E(vdU@UD(#2T)_x1h;AJXvHj%7$ zUDVahD&k~`*|D-RSSV>?htW110_CYB4EIDe+&TA!uhn!5sL%$S`vKRfK1uXKa1Klm z6(;UT$Ci;}iQIYQD{h@v+&XjcqF?C8s*$g_gk%>QGp@o(%r;)XA)d@u_m-mXSG=g;!Bnm#QR+FG~xwW1en#Q3&Y{|qev^#l0{ z5rlw74&v*fXZT}Q5RVF}31#Z+o`y)nBh!ts?&O1fqBDtIo9>#|>=Vu%bXUZei#_N0 z5}&fJJ)utsjc`llNXpA=x$y~aU;9#R zUyFH`=Sh~)tbN%zGW~J{O?F0X>+*_ii9vl4Rflz5EE1V5MgoKYpX_~^QCJ-Qo?_Io zqEzn?QfGW}07u{Y>N7T~`|BO5Uhx9a1Ad28?gb)bm?hnZ9jY1%JET*QURcvXMrMc% z{K+3~luG_FDQUyo<(OQQ)30Ba(+_rFF=W?Jj2#Uq#6miOg>*a%>Azwu{m`1j>~&aYy*^(MyB&RPl{305_4?K6bUtzsdiDqA6jK*oUW?P zV<#~?Z>tCxe6c3GxHU-JkWw#Al>>vNut%p($c!Nma&76C${xIVjw-}|MIo@lVR10C z&N^lUPLnz^QTil=1*zD)TZA~7#XxbEaWeB`)1vMiAk&bE zLx4;*x;biQ0Wz^Pyrlq{7E#z&^m4EyO8)CC8s(1BF&!sTc6_jrkB+Iv*>Un@r;;bH zN)+d#byqF)t>LYqa!udn zQ?C2AARN+)VU(S{8uKK(_2=&BqVci!Pi$A!3FR74ZAi_EA=mo!tsL{8j$D<#uRB)w zKrlN7os6xkveIuMvQCqug%7**jJYaAdQO^8%SE?Fv?$jjQa*j5E%KHnTf{ugUwvpmb``(|pRQ0G&rjpK;?oqe?J3 zF*u$IN4}}AOy_fJ(>>h#qqiOBdzR70oDW5(>2BdQk2P~R({m~LY>lx#zm^(RV=bQv zZoH@0rrwPgttPH3&L-vbY;pQFz<|Xe9T$59t90~8ZQ*@%?OeL?PK*Jv1#Y|(W3Fyl z_#f{rbmRT}c-D>g;D&VGb>W?N<2^i%-FWuKF5Gx0?BvsSH=YhlH8-9)KUXJ7Zf-oL zC>NYOe$I`DuOhhdhLIa@@l>@8)<)BfS1yt-|M4@(HK@^(qD@R~)U%``f-AClUqAD=z zrD20%F83)`J(r?+b`DNaQ%OeU{Vm_t64X9e85g``5wVy@#4R*T3-uX;QtzD)R)@@L z{NILP0k=E(U@hR&T*=PO>fHF|gY7vVZ1fNk-;)ov=e(kx-pUfu2K83VSiPOAW$g}p*c(F|MZ1$mJ53i6+G~AT`YOgSlw_I#yw=S#{7@75)nSy0Q#cRtTP2ElE&qRP5_dQl@`NVV%T28 z_e&LIF54OBU$&@%i>O!0Tx;TEG+M0H&^)Ne&?~qHv1bd;2U44kMIN}SW|Z7Qk99F9 zbcP%>cg8PSt(Y>ruJ6H=q}n}QYn1DuNg-R;043I+9wHxw$N%+BELG3 z4B?iA*=k$mXYaC*7^}sKboWz6i^zoChD<0?i8~$5Hw=J>YJ#c8`1n)tOMv>q>?P<7Ntr7#u0P^@H^=p2EjHRuPi5JOE zejOsd&1Qo2GJQ9~8XiY<44CGF)v2Jj+QJ&3I;Yi;k$*=-#unD#CiAeDL)S}IH9pCE z!yn`AG!n>x1z)jEEEAj>qm&?rf&175$YY_Tj#vjfrR}00*}YZ&xv0M4Azb8&=Hn|o z(Wn50Tpa9>mJb4f4fp18TPey~+?&S@GwxlRjKxFb-t576-wsSd_FZ;wo~nlXO4z2^BP<83xS35z+9F_4h`D0&eEEikvrXHIvu)4#<3?l} z&bF+ z+BgL~3JzqZA^1ZTAkqu~*^RU9GRPm2JSstm5vliaepkGM%_kTviNkKh95ozlT&v@E zWyZmFCzPkG7T7GAJ*lG%v)*}dY7>RilEd|;**H^1i>&F_}^H~jo=J=6Kk_8f3Z zzIvFWT=gA5cAryh;HToNB~H;QT(HGPR_ZptWP}CM_>P!P_$tmBb&ExiMMbWK3DiIrLPD?1 z&GKX^Jwz;w&nX6Yj92 z@{mRKfYUi4-{x6-5NeqpvVmI`RUb+*mqjHLt5xZTEULbfb+nRmaO)Sz=(u`DWkBe-Asj?ENZ)bJ{cs&83T z&zPQR?iV%2xJ3r|wm6H5DK_0N3$mydPgTp%;(l=eZWgY&EGi?jF-IYn1<_NMFo<@r zO$aiIW2O^jvIX)>D( z$)LVo#TY)hHk_`Y%d}$aSeQs<9pe`0wo!Yw!Kjlk>O~3mj24#2unjdJW^;btD*tPa zbtrEK)R4dvr~GuhZ46#UyD&l@zpneu2m+TO(v>gbfMgFIqiu6o`wgf#AQM_-Vub^` zso+mRZq~BT7+5_ITwpibAswi)o3RT9GmGtJWWtCLFS45*_eQI++0CLm?e>iALOWh9 zj}MPrfeL***;oq~gNBPkwR%{+4cGYEG>mnY*}cGUaV?uaZ<^#$+YYVO@XT7Ro-I!n zuuTrbiNzTyc+1RiOI}=>tW<%IapY!?udNqh`5(QwzO-_Dbeg$sbyRhCe=S69!F_H0 z)d4^cfx!?cX~1kP`^pC%+&+%BC{Wqts<1s~|G{Z7R0XM|@c8SKkv^oEX1c91D^CdE z#(%26lhm%io4~cy216p5a9;Q+ddyVnLA6#CO^iQyF)+D;LF6+1r@PMl_X;YAPE$Pi14cw`D3PY%1Ko zaYg`UVK%#)%HDV?>_fCGfNcd}qiQOnou@Jy?rE9IKRTC zaBGh%zWy>?SsRX9rt)Q*is`y%0AQ9My1QK&$5R2MqN%J#Q(3L1f-`$3v|k-=*i<6& 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 literal 0 HcmV?d00001 diff --git a/tests/rpc/integration/put_deploy_test.go b/tests/rpc/integration/put_deploy_test.go index 0c7fc09..4bd0f6c 100644 --- a/tests/rpc/integration/put_deploy_test.go +++ b/tests/rpc/integration/put_deploy_test.go @@ -26,7 +26,7 @@ func Test_PutDeploy(t *testing.T) { facetKeys, err := casper.NewED25519PrivateKeyFromPEMFile("../../data/keys/docker-nctl-secret.pem") require.NoError(t, err) require.NoError(t, err) - header := types.DefaultHeader() + header := types.DefaultDeployHeader() header.ChainName = "casper-net-1" header.Account = facetKeys.PublicKey() require.NoError(t, err) @@ -46,7 +46,7 @@ func Test_PutDeploy(t *testing.T) { } deploy, err := types.MakeDeploy(header, payment, session) - err = deploy.SignDeploy(facetKeys) + err = deploy.Sign(facetKeys) require.NoError(t, err) rpcClient := rpc.NewClient(rpc.NewHttpHandler("http://127.0.0.1:11101/rpc", http.DefaultClient)) diff --git a/tests/rpc/integration/put_transaction_test.go b/tests/rpc/integration/put_transaction_test.go new file mode 100644 index 0000000..ec38468 --- /dev/null +++ b/tests/rpc/integration/put_transaction_test.go @@ -0,0 +1,90 @@ +//go:build integration +// +build integration + +package integration + +import ( + "context" + "encoding/hex" + "log" + "math/big" + "net/http" + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/make-software/casper-go-sdk/casper" + "github.com/make-software/casper-go-sdk/rpc" + "github.com/make-software/casper-go-sdk/types" + "github.com/make-software/casper-go-sdk/types/clvalue" +) + +func Test_PutTransaction(t *testing.T) { + keys, err := casper.NewED25519PrivateKeyFromPEMFile("../../data/keys/docker-nctl-rc3-secret.pem") + require.NoError(t, err) + + pubKey := keys.PublicKey() + + header := types.TransactionV1Header{ + ChainName: "casper-net-1", + Timestamp: types.Timestamp(time.Now().UTC()), + TTL: 18000000000, + InitiatorAddr: types.InitiatorAddr{ + PublicKey: &pubKey, + }, + PricingMode: types.PricingMode{ + Fixed: &types.FixedMode{ + GasPriceTolerance: 3, + }, + }, + } + + moduleBytes, err := os.ReadFile("../../data/wasm/cep18-rc3.wasm") + require.NoError(t, err) + + args := &types.Args{} + args.AddArgument("name", *clvalue.NewCLString("Test")). + AddArgument("symbol", *clvalue.NewCLString("test")). + AddArgument("decimals", *clvalue.NewCLUint8(9)). + AddArgument("total_supply", *clvalue.NewCLUInt256(big.NewInt(1_000_000_000_000_000))). + AddArgument("events_mode", *clvalue.NewCLUint8(2)). + AddArgument("enable_mint_burn", *clvalue.NewCLUint8(1)) + + body := types.TransactionV1Body{ + Args: args, + Target: types.TransactionTarget{ + Session: &types.SessionTarget{ + ModuleBytes: hex.EncodeToString(moduleBytes), + Runtime: types.TransactionRuntimeVmCasperV1, + }, + }, + TransactionEntryPoint: types.TransactionEntryPoint{ + Call: &struct{}{}, + }, + TransactionScheduling: types.TransactionScheduling{ + Standard: &struct{}{}, + }, + TransactionCategory: 2, + } + + transaction, err := types.MakeTransactionV1(header, body) + err = transaction.Sign(keys) + require.NoError(t, err) + + rpcClient := rpc.NewClient(rpc.NewHttpHandler("http://127.0.0.1:11101/rpc", http.DefaultClient)) + res, err := rpcClient.PutTransaction(context.Background(), *transaction) + require.NoError(t, err) + assert.NotEmpty(t, res.TransactionHash.Transaction) + assert.NoError(t, transaction.Validate()) + + log.Println("Transaction submitted:", res.TransactionHash.Transaction) + + time.Sleep(time.Second * 10) + transactionRes, err := rpcClient.GetTransactionByTransactionHash(context.Background(), res.TransactionHash.Transaction.ToHex()) + require.NoError(t, err) + assert.NotEmpty(t, transactionRes.Transaction) + assert.NotEmpty(t, transactionRes.ExecutionInfo) +} diff --git a/tests/types/deploy_make_test.go b/tests/types/deploy_make_test.go index e75ea56..e35267f 100644 --- a/tests/types/deploy_make_test.go +++ b/tests/types/deploy_make_test.go @@ -78,7 +78,7 @@ func Test_MakeDeploy(t *testing.T) { require.NoError(t, err) privateKey, err := casper.NewED25519PrivateKeyFromPEMFile("../data/keys/secret_key.pem") require.NoError(t, err) - header := types.DefaultHeader() + header := types.DefaultDeployHeader() header.ChainName = "casper-net-1" header.Account = privateKey.PublicKey() dateTime, err := time.Parse("2006-01-02T15:04:05.999Z", "2023-05-08T21:33:00.268Z") @@ -100,7 +100,7 @@ func Test_MakeDeploy(t *testing.T) { deploy, err := types.MakeDeploy(header, payment, session) require.NoError(t, err) - err = deploy.SignDeploy(privateKey) + err = deploy.Sign(privateKey) require.NoError(t, err) actual, err := json.Marshal(deploy) require.NoError(t, err) diff --git a/types/addressable_entity.go b/types/addressable_entity.go index b6e62cf..2944971 100644 --- a/types/addressable_entity.go +++ b/types/addressable_entity.go @@ -42,11 +42,25 @@ type SystemEntityType string // TransactionRuntime SmartContract transaction types. type TransactionRuntime string +const ( + TransactionRuntimeTagVmCasperV1 = iota + TransactionRuntimeTagVmCasperV2 +) + const ( TransactionRuntimeVmCasperV1 TransactionRuntime = "VmCasperV1" TransactionRuntimeVmCasperV2 TransactionRuntime = "VmCasperV2" ) +func (t TransactionRuntime) RuntimeTag() byte { + if t == TransactionRuntimeVmCasperV1 { + return TransactionRuntimeTagVmCasperV1 + } else if t == TransactionRuntimeVmCasperV2 { + return TransactionRuntimeTagVmCasperV2 + } + return 0 +} + type EntityKind struct { System *SystemEntityType `json:"System,omitempty"` Account *key.AccountHash `json:"Account,omitempty"` diff --git a/types/args.go b/types/args.go index 958ceca..9e5795b 100644 --- a/types/args.go +++ b/types/args.go @@ -13,19 +13,19 @@ var ErrArgumentNotFound = errors.New("argument is not found") type Args []PairArgument -func (a Args) Bytes() ([]byte, error) { +func (args Args) Bytes() ([]byte, error) { var result []byte - result = append(result, clvalue.SizeToBytes(len(a))...) - for _, one := range a { - val, err := one.Value() + result = append(result, clvalue.SizeToBytes(len(args))...) + for _, arg := range args { + val, err := arg.Value() if err != nil { return nil, err } - name, err := one.Name() + argName, err := arg.Name() if err != nil { return nil, err } - result = append(result, clvalue.NewCLString(name).Bytes()...) + result = append(result, clvalue.NewCLString(argName).Bytes()...) valueBytes, err := clvalue.ToBytesWithType(val) if err != nil { return nil, err @@ -36,8 +36,8 @@ func (a Args) Bytes() ([]byte, error) { return result, nil } -func (a Args) Find(name string) (*Argument, error) { - for _, one := range a { +func (args Args) Find(name string) (*Argument, error) { + for _, one := range args { getName, err := one.Name() if err != nil { return nil, err @@ -49,12 +49,12 @@ func (a Args) Find(name string) (*Argument, error) { return nil, fmt.Errorf("%w, target: %s", ErrArgumentNotFound, name) } -func (a *Args) AddArgument(name string, value clvalue.CLValue) *Args { +func (args *Args) AddArgument(name string, value clvalue.CLValue) *Args { pair := PairArgument{} pair[0] = &Argument{name: &name} pair[1] = &Argument{value: &value} - *a = append(*a, pair) - return a + *args = append(*args, pair) + return args } type PairArgument [2]*Argument diff --git a/types/deploy.go b/types/deploy.go index 68ae854..4ce6307 100644 --- a/types/deploy.go +++ b/types/deploy.go @@ -1,6 +1,7 @@ package types import ( + "errors" "time" "golang.org/x/crypto/blake2b" @@ -11,6 +12,10 @@ import ( "github.com/make-software/casper-go-sdk/types/keypair" ) +var ( + ErrInvalidDeployHash = errors.New("invalid deploy hash") +) + // Deploy is an item containing a smart contract along with the requester's signature(s). type Deploy struct { // List of signers and signatures for this `deploy`. @@ -45,7 +50,7 @@ type DeployHeader struct { TTL Duration `json:"ttl"` } -func DefaultHeader() DeployHeader { +func DefaultDeployHeader() DeployHeader { return DeployHeader{ Dependencies: []key.Hash{}, GasPrice: 1, @@ -71,33 +76,33 @@ func (d DeployHeader) Bytes() []byte { return result } -func (d *Deploy) ValidateDeploy() (bool, error) { +func (d *Deploy) Validate() error { paymentBytes, err := d.Payment.Bytes() if err != nil { - return false, err + return err } sessionBytes, err := d.Session.Bytes() if err != nil { - return false, err + return err } if d.Header.BodyHash != blake2b.Sum256(append(paymentBytes, sessionBytes...)) { - return false, nil + return ErrInvalidBodyHash } if d.Hash != blake2b.Sum256(d.Header.Bytes()) { - return false, nil + return ErrInvalidDeployHash } for _, one := range d.Approvals { if one.Signer.VerifySignature(d.Hash.Bytes(), one.Signature) != nil { - return false, nil + return ErrInvalidApprovalSignature } } - return true, nil + return nil } -func (d *Deploy) SignDeploy(keys keypair.PrivateKey) error { +func (d *Deploy) Sign(keys keypair.PrivateKey) error { signature, err := keys.Sign(d.Hash.Bytes()) if err != nil { return err diff --git a/types/executable_deploy_item.go b/types/executable_deploy_item.go index 55eff04..ea119e3 100644 --- a/types/executable_deploy_item.go +++ b/types/executable_deploy_item.go @@ -99,7 +99,10 @@ type ModuleBytes struct { } func (m ModuleBytes) Bytes() ([]byte, error) { - bytes, _ := hex.DecodeString(m.ModuleBytes) + bytes, err := hex.DecodeString(m.ModuleBytes) + if err != nil { + return nil, err + } res := clvalue.NewCLUInt32(uint32(len(bytes))).Bytes() res = append(res, clvalue.NewCLByteArray(bytes).Bytes()...) argBytes, err := m.Args.Bytes() diff --git a/types/pricing_mode.go b/types/pricing_mode.go new file mode 100644 index 0000000..c5d8232 --- /dev/null +++ b/types/pricing_mode.go @@ -0,0 +1,62 @@ +package types + +import ( + "github.com/make-software/casper-go-sdk/types/clvalue" + "github.com/make-software/casper-go-sdk/types/key" +) + +const ( + PricingModeClassicTag = iota + PricingModeFixedTag + PricingModeReservedTag +) + +type PricingMode struct { + // The original payment model, where the creator of the transaction specifies how much they will pay, at what gas price. + Classic *ClassicMode `json:"Classic,omitempty"` + // The cost of the transaction is determined by the cost table, per the transaction kind. + Fixed *FixedMode `json:"Fixed,omitempty"` + // The payment for this transaction was previously reserved, as proven by the receipt hash. + Reserved *ReservedMode `json:"reserved,omitempty"` +} + +func (d PricingMode) Bytes() []byte { + result := make([]byte, 0, 2) + if d.Classic != nil { + result = append(result, PricingModeClassicTag) + result = append(result, clvalue.NewCLUInt64(d.Classic.PaymentAmount).Bytes()...) + result = append(result, d.Classic.GasPriceTolerance) + if d.Classic.StandardPayment { + result = append(result, 1) + } else { + result = append(result, 0) + } + } else if d.Fixed != nil { + result = append(result, PricingModeFixedTag) + result = append(result, d.Fixed.GasPriceTolerance) + } else if d.Reserved != nil { + result = append(result, PricingModeReservedTag) + result = append(result, d.Reserved.Receipt.Bytes()...) + } + + return result +} + +type ClassicMode struct { + // User-specified gas_price tolerance (minimum 1). This is interpreted to mean "do not include this transaction in a block if the current gas price is greater than this number" + GasPriceTolerance uint8 `json:"gas_price_tolerance"` + // User-specified payment amount. + PaymentAmount uint64 `json:"payment_amount"` + // Standard payment. + StandardPayment bool `json:"standard_payment"` +} + +type FixedMode struct { + // User-specified gas_price tolerance (minimum 1). This is interpreted to mean "do not include this transaction in a block if the current gas price is greater than this number" + GasPriceTolerance uint8 `json:"gas_price_tolerance"` +} + +type ReservedMode struct { + // Pre-paid receipt + Receipt key.Hash `json:"receipt"` +} diff --git a/types/transaction.go b/types/transaction.go index 9dfc460..59de51b 100644 --- a/types/transaction.go +++ b/types/transaction.go @@ -2,14 +2,26 @@ package types import ( "encoding/json" + "errors" "strconv" + "time" + "golang.org/x/crypto/blake2b" + + "github.com/make-software/casper-go-sdk/types/clvalue" "github.com/make-software/casper-go-sdk/types/key" + "github.com/make-software/casper-go-sdk/types/keypair" +) + +var ( + ErrInvalidBodyHash = errors.New("invalid body hash") + ErrInvalidTransactionHash = errors.New("invalid transaction hash") + ErrInvalidApprovalSignature = errors.New("invalid approval signature") ) type Transaction struct { // Hex-encoded TransactionV1 hash - TransactionHash *key.Hash `json:"hash"` + TransactionHash key.Hash `json:"hash"` // The header portion of a TransactionV1 TransactionHeader TransactionHeader `json:"header"` // Body of a `TransactionV1` @@ -108,7 +120,7 @@ func NewTransactionFromDeploy(deploy Deploy) Transaction { // Use StandardPayment as true only for payments without explicit `payment amount` var standardPayment = paymentAmount == 0 return Transaction{ - TransactionHash: &deploy.Hash, + TransactionHash: deploy.Hash, TransactionHeader: TransactionHeader{ BodyHash: deploy.Header.BodyHash, ChainName: deploy.Header.ChainName, @@ -145,7 +157,7 @@ type TransactionWrapper struct { type TransactionV1 struct { // Hex-encoded TransactionV1 hash - TransactionV1Hash *key.Hash `json:"hash"` + TransactionV1Hash key.Hash `json:"hash"` // The header portion of a TransactionV1 TransactionV1Header TransactionV1Header `json:"header"` // Body of a `TransactionV1` @@ -168,68 +180,17 @@ type TransactionV1Header struct { PricingMode PricingMode `json:"pricing_mode"` } -type TransactionEntryPoint struct { - Custom *struct { - Type string - } - Transfer *struct{} - AddBid *struct{} - WithdrawBid *struct{} - Delegate *struct{} - Undelegate *struct{} - Redelegate *struct{} - ActivateBid *struct{} +func (d TransactionV1Header) Bytes() []byte { + result := make([]byte, 0, 32) + result = append(result, clvalue.NewCLString(d.ChainName).Bytes()...) + result = append(result, clvalue.NewCLUInt64(uint64(time.Time(d.Timestamp).UnixMilli())).Bytes()...) + result = append(result, clvalue.NewCLUInt64(uint64(time.Duration(d.TTL).Milliseconds())).Bytes()...) + result = append(result, d.BodyHash.Bytes()...) + result = append(result, d.PricingMode.Bytes()...) + result = append(result, d.InitiatorAddr.Bytes()...) + return result } -func (t *TransactionEntryPoint) UnmarshalJSON(data []byte) error { - var custom struct { - Custom string `json:"Custom"` - } - if err := json.Unmarshal(data, &custom); err == nil { - *t = TransactionEntryPoint{ - Custom: &struct{ Type string }{Type: custom.Custom}, - } - return nil - } - - var key string - if err := json.Unmarshal(data, &key); err != nil { - return err - } - - var entryPoint TransactionEntryPoint - switch key { - case TransactionEntryPointTransfer: - entryPoint.Transfer = &struct{}{} - case TransactionEntryPointAddBid: - entryPoint.AddBid = &struct{}{} - case TransactionEntryPointWithdrawBid: - entryPoint.WithdrawBid = &struct{}{} - case TransactionEntryPointDelegate: - entryPoint.Delegate = &struct{}{} - case TransactionEntryPointUndelegate: - entryPoint.Undelegate = &struct{}{} - case TransactionEntryPointRedelegate: - entryPoint.Redelegate = &struct{}{} - case TransactionEntryPointActivateBid: - entryPoint.ActivateBid = &struct{}{} - } - - *t = entryPoint - return nil -} - -const ( - TransactionEntryPointCustom = "Custom" - TransactionEntryPointTransfer = "Transfer" - TransactionEntryPointAddBid = "AddBid" - TransactionEntryPointWithdrawBid = "WithdrawBid" - TransactionEntryPointDelegate = "Delegate" - TransactionEntryPointUndelegate = "Undelegate" - TransactionEntryPointRedelegate = "Redelegate" - TransactionEntryPointActivateBid = "ActivateBid" -) - type TransactionV1Body struct { Args *Args `json:"args,omitempty"` // Execution target of a Transaction. @@ -238,261 +199,93 @@ type TransactionV1Body struct { TransactionEntryPoint TransactionEntryPoint `json:"entry_point"` // Scheduling mode of a Transaction. TransactionScheduling TransactionScheduling `json:"scheduling"` + // Scheduling mode of a Transaction. + TransactionCategory uint8 `json:"transaction_category"` } -type TransactionScheduling struct { - // No special scheduling applied. - Standard *struct{} - // Execution should be scheduled for the specified era. - FutureEra *FutureEraScheduling - // Execution should be scheduled for the specified timestamp or later. - FutureTimestamp *FutureTimestampScheduling -} - -func (t *TransactionScheduling) UnmarshalJSON(data []byte) error { - var futureKey struct { - EraID *uint64 `json:"FutureEra"` - FutureTimestamp *string `json:"FutureTimestamp"` +func (t *TransactionV1Body) Bytes() ([]byte, error) { + result := make([]byte, 0, 32) + argsBytes, err := t.Args.Bytes() + if err != nil { + return nil, err } - if err := json.Unmarshal(data, &futureKey); err == nil { - if futureKey.FutureTimestamp != nil { - *t = TransactionScheduling{ - FutureTimestamp: &FutureTimestampScheduling{ - TimeStamp: *futureKey.FutureTimestamp, - }, - } - } - if futureKey.EraID != nil { - *t = TransactionScheduling{ - FutureEra: &FutureEraScheduling{ - EraID: *futureKey.EraID, - }, - } - } - return nil - } - - var key string - if err := json.Unmarshal(data, &key); err == nil && key == "Standard" { - *t = TransactionScheduling{ - Standard: &struct{}{}, - } - return nil + targetBytes, err := t.Target.Bytes() + if err != nil { + return nil, err } - return nil -} - -type FutureEraScheduling struct { - EraID uint64 -} -type FutureTimestampScheduling struct { - TimeStamp string `json:"FutureTimestamp"` + result = append(result, argsBytes...) + result = append(result, targetBytes...) + result = append(result, t.TransactionEntryPoint.Bytes()...) + result = append(result, t.TransactionCategory) + result = append(result, t.TransactionScheduling.Bytes()...) + return result, nil } -type TransactionTarget struct { - // The execution target is a native operation (e.g. a transfer). - Native *struct{} - // The execution target is a stored entity or package. - Stored *StoredTarget `json:"Stored"` - // The execution target is the included module bytes, i.e. compiled Wasm. - Session *SessionTarget `json:"Session"` +// TransactionHash A versioned wrapper for a transaction hash or deploy hash +type TransactionHash struct { + Deploy *key.Hash `json:"Deploy,omitempty"` + Transaction *key.Hash `json:"Version1,omitempty"` } -func (t *TransactionTarget) UnmarshalJSON(data []byte) error { - var target struct { - Stored *StoredTarget `json:"Stored"` - Session *SessionTarget `json:"Session"` +func (t *TransactionV1) Sign(keys keypair.PrivateKey) error { + signature, err := keys.Sign(t.TransactionV1Hash.Bytes()) + if err != nil { + return err } - if err := json.Unmarshal(data, &target); err == nil { - if target.Session != nil { - *t = TransactionTarget{ - Session: target.Session, - } - } - - if target.Stored != nil { - *t = TransactionTarget{ - Stored: target.Stored, - } - } - return nil + approval := Approval{ + Signer: keys.PublicKey(), + Signature: signature, } - var key string - if err := json.Unmarshal(data, &key); err == nil && key == "Native" { - *t = TransactionTarget{ - Native: &struct{}{}, - } - return nil + if t.Approvals == nil { + t.Approvals = make([]Approval, 0, 1) } + t.Approvals = append(t.Approvals, approval) return nil } -// NewTransactionTargetFromSession create new TransactionTarget from ExecutableDeployItem -func NewTransactionTargetFromSession(session ExecutableDeployItem) TransactionTarget { - if session.Transfer != nil { - return TransactionTarget{ - Native: &struct{}{}, - } - } - - if session.ModuleBytes != nil { - return TransactionTarget{ - Session: &SessionTarget{ - ModuleBytes: session.ModuleBytes.ModuleBytes, - Runtime: "VmCasperV1", - }, - } - } - - if session.StoredContractByHash != nil { - hash := session.StoredContractByHash.Hash.Hash.ToHex() - return TransactionTarget{ - Stored: &StoredTarget{ - ID: TransactionInvocationTarget{ - ByHash: &hash, - }, - Runtime: "VmCasperV1", - }, - } +func (t *TransactionV1) Validate() error { + bodyBytes, err := t.TransactionV1Body.Bytes() + if err != nil { + return err } - if session.StoredContractByName != nil { - return TransactionTarget{ - Stored: &StoredTarget{ - ID: TransactionInvocationTarget{ - ByName: &session.StoredContractByName.Name, - }, - Runtime: "VmCasperV1", - }, - } + if t.TransactionV1Header.BodyHash != blake2b.Sum256(bodyBytes) { + return ErrInvalidBodyHash } - if session.StoredVersionedContractByHash != nil { - var version *uint32 - if storedVersion := session.StoredVersionedContractByHash.Version; storedVersion != nil { - versionNum, err := storedVersion.Int64() - if err == nil { - temp := uint32(versionNum) - version = &temp - } - } - byHashTarget := ByPackageHashInvocationTarget{ - Addr: session.StoredVersionedContractByHash.Hash.Hash, - Version: version, - } - return TransactionTarget{ - Stored: &StoredTarget{ - ID: TransactionInvocationTarget{ - ByPackageHash: &byHashTarget, - }, - Runtime: "VmCasperV1", - }, - } + if t.TransactionV1Hash != blake2b.Sum256(t.TransactionV1Header.Bytes()) { + return ErrInvalidTransactionHash } - if session.StoredVersionedContractByName != nil { - var version *uint32 - if storedVersion := session.StoredVersionedContractByName.Version; storedVersion != nil { - versionNum, err := storedVersion.Int64() - if err == nil { - temp := uint32(versionNum) - version = &temp - } - } - byNameTarget := ByPackageNameInvocationTarget{ - Version: version, - } - - if session.StoredContractByName != nil { - byNameTarget.Name = session.StoredContractByName.Name - } - - return TransactionTarget{ - Stored: &StoredTarget{ - ID: TransactionInvocationTarget{ - ByPackageName: &byNameTarget, - }, - Runtime: "VmCasperV1", - }, + for _, one := range t.Approvals { + if one.Signer.VerifySignature(t.TransactionV1Hash.Bytes(), one.Signature) != nil { + return ErrInvalidApprovalSignature } } - return TransactionTarget{} -} - -type StoredTarget struct { - // Identifier of a `Stored` transaction target. - ID TransactionInvocationTarget `json:"id"` - Runtime string `json:"runtime"` -} - -type TransactionInvocationTarget struct { - // Hex-encoded entity address identifying the invocable entity. - ByHash *string `json:"ByHash"` - // The alias identifying the invocable entity. - ByName *string `json:"ByName"` - // The address and optional version identifying the package. - ByPackageHash *ByPackageHashInvocationTarget `json:"ByPackageHash"` - // The alias and optional version identifying the package. - ByPackageName *ByPackageNameInvocationTarget `json:"ByPackageName"` -} - -// ByPackageHashInvocationTarget The address and optional version identifying the package. -type ByPackageHashInvocationTarget struct { - Addr key.Hash `json:"addr"` - Version *uint32 `json:"version"` -} - -// ByPackageNameInvocationTarget The alias and optional version identifying the package. -type ByPackageNameInvocationTarget struct { - Name string `json:"name"` - Version *uint32 `json:"version"` -} - -type SessionTarget struct { - Kind string `json:"string"` - ModuleBytes string `json:"module_bytes"` - Runtime string `json:"runtime"` -} - -type PricingMode struct { - // The original payment model, where the creator of the transaction specifies how much they will pay, at what gas price. - Classic *ClassicMode `json:"Classic"` - // The cost of the transaction is determined by the cost table, per the transaction kind. - Fixed *FixedMode `json:"Fixed"` - - Reserved *ReservedMode `json:"reserved"` -} - -type ClassicMode struct { - // User-specified gas_price tolerance (minimum 1). This is interpreted to mean "do not include this transaction in a block if the current gas price is greater than this number" - GasPriceTolerance uint8 `json:"gas_price_tolerance"` - // User-specified payment amount. - PaymentAmount uint64 `json:"payment_amount"` - // Standard payment. - StandardPayment bool `json:"standard_payment"` + return nil } -type FixedMode struct { - // // User-specified gas_price tolerance (minimum 1). This is interpreted to mean "do not include this transaction in a block if the current gas price is greater than this number" - GasPriceTolerance uint8 `json:"gas_price_tolerance"` +func NewTransactionV1(hash key.Hash, header TransactionV1Header, body TransactionV1Body, approvals []Approval) *TransactionV1 { + return &TransactionV1{ + TransactionV1Hash: hash, + TransactionV1Header: header, + TransactionV1Body: body, + Approvals: approvals, + } } -type ReservedMode struct { - // Pre-paid receipt - Receipt key.Hash `json:"receipt"` - // Price paid in the past to reserve space in a future block. - PaidAmount uint64 `json:"paid_amount"` - // The gas price at the time of reservation. - StrikePrice uint `json:"strike_price"` -} +func MakeTransactionV1(transactionHeader TransactionV1Header, transactionBody TransactionV1Body) (*TransactionV1, error) { + bodyBytes, err := transactionBody.Bytes() + if err != nil { + return nil, err + } -// TransactionHash A versioned wrapper for a transaction hash or deploy hash -type TransactionHash struct { - Deploy *key.Hash `json:"Deploy,omitempty"` - Transaction *key.Hash `json:"Version1,omitempty"` + transactionHeader.BodyHash = blake2b.Sum256(bodyBytes) + transactionHash := blake2b.Sum256(transactionHeader.Bytes()) + return NewTransactionV1(transactionHash, transactionHeader, transactionBody, make([]Approval, 0)), nil } diff --git a/types/transaction_entrypoint.go b/types/transaction_entrypoint.go new file mode 100644 index 0000000..e5cf38c --- /dev/null +++ b/types/transaction_entrypoint.go @@ -0,0 +1,171 @@ +package types + +import ( + "encoding/json" + "errors" + + "github.com/make-software/casper-go-sdk/types/clvalue" +) + +const ( + TransactionEntryPointCustom = "Custom" + TransactionEntryPointTransfer = "Transfer" + TransactionEntryPointAddBid = "AddBid" + TransactionEntryPointWithdrawBid = "WithdrawBid" + TransactionEntryPointDelegate = "Delegate" + TransactionEntryPointUndelegate = "Undelegate" + TransactionEntryPointRedelegate = "Redelegate" + TransactionEntryPointActivateBid = "ActivateBid" + TransactionEntryPointChangeBidPublicKey = "ChangeBidPublicKey" + TransactionEntryPointCall = "Call" +) + +const ( + TransactionEntryPointCustomTag = iota + TransactionEntryPointTransferTag + TransactionEntryPointAddBidTag + TransactionEntryPointWithdrawBidTag + TransactionEntryPointDelegateTag + TransactionEntryPointUndelegateTag + TransactionEntryPointRedelegateTag + TransactionEntryPointActivateBidTag + TransactionEntryPointChangeBidPublicKeyTag + TransactionEntryPointCallTag +) + +type TransactionEntryPoint struct { + Custom *struct { + Type string + } + // The `transfer` native entry point, used to transfer `Motes` from a source purse to a target purse. + Transfer *struct{} + // The `add_bid` native entry point, used to create or top off a bid purse. + AddBid *struct{} + // The `withdraw_bid` native entry point, used to decrease a stake. + WithdrawBid *struct{} + // The `delegate` native entry point, used to add a new delegator or increase an existing delegator's stake. + Delegate *struct{} + // The `undelegate` native entry point, used to reduce a delegator's stake or remove the delegator if the remaining stake is 0. + Undelegate *struct{} + // The `redelegate` native entry point, used to reduce a delegator's stake or remove the delegator if + // the remaining stake is 0, and after the unbonding delay, automatically delegate to a new validator. + Redelegate *struct{} + // The `activate_bid` native entry point, used to used to reactivate an inactive bid. + ActivateBid *struct{} + // The `change_bid_public_key` native entry point, used to change a bid's public key. + ChangeBidPublicKey *struct{} + // Used to call entry point call() in session transactions + Call *struct{} +} + +func (t *TransactionEntryPoint) Bytes() []byte { + result := make([]byte, 0, 2) + result = append(result, t.Tag()) + + if t.Custom != nil { + result = append(result, clvalue.NewCLString(t.Custom.Type).Bytes()...) + } + return result +} + +func (t *TransactionEntryPoint) Tag() byte { + switch { + case t.Custom != nil: + return TransactionEntryPointCustomTag + case t.Transfer != nil: + return TransactionEntryPointTransferTag + case t.AddBid != nil: + return TransactionEntryPointAddBidTag + case t.WithdrawBid != nil: + return TransactionEntryPointWithdrawBidTag + case t.Delegate != nil: + return TransactionEntryPointDelegateTag + case t.Undelegate != nil: + return TransactionEntryPointUndelegateTag + case t.Redelegate != nil: + return TransactionEntryPointRedelegateTag + case t.ActivateBid != nil: + return TransactionEntryPointActivateBidTag + case t.ChangeBidPublicKey != nil: + return TransactionEntryPointChangeBidPublicKeyTag + case t.Call != nil: + return TransactionEntryPointCallTag + default: + return 0 + } +} + +func (t *TransactionEntryPoint) UnmarshalJSON(data []byte) error { + var custom struct { + Custom string `json:"Custom"` + } + if err := json.Unmarshal(data, &custom); err == nil { + *t = TransactionEntryPoint{ + Custom: &struct{ Type string }{Type: custom.Custom}, + } + return nil + } + + var key string + if err := json.Unmarshal(data, &key); err != nil { + return err + } + + var entryPoint TransactionEntryPoint + switch key { + case TransactionEntryPointTransfer: + entryPoint.Transfer = &struct{}{} + case TransactionEntryPointAddBid: + entryPoint.AddBid = &struct{}{} + case TransactionEntryPointWithdrawBid: + entryPoint.WithdrawBid = &struct{}{} + case TransactionEntryPointDelegate: + entryPoint.Delegate = &struct{}{} + case TransactionEntryPointUndelegate: + entryPoint.Undelegate = &struct{}{} + case TransactionEntryPointRedelegate: + entryPoint.Redelegate = &struct{}{} + case TransactionEntryPointActivateBid: + entryPoint.ActivateBid = &struct{}{} + case TransactionEntryPointChangeBidPublicKey: + entryPoint.ChangeBidPublicKey = &struct{}{} + case TransactionEntryPointCall: + entryPoint.Call = &struct{}{} + } + + *t = entryPoint + return nil +} + +func (t TransactionEntryPoint) MarshalJSON() ([]byte, error) { + if t.Custom != nil { + return json.Marshal(struct { + Custom string `json:"Custom"` + }{ + Custom: t.Custom.Type, + }) + } + + switch { + case t.Transfer != nil: + return json.Marshal(TransactionEntryPointTransfer) + case t.AddBid != nil: + return json.Marshal(TransactionEntryPointAddBid) + case t.WithdrawBid != nil: + return json.Marshal(TransactionEntryPointWithdrawBid) + case t.Delegate != nil: + return json.Marshal(TransactionEntryPointDelegate) + case t.Undelegate != nil: + return json.Marshal(TransactionEntryPointUndelegate) + case t.Redelegate != nil: + return json.Marshal(TransactionEntryPointRedelegate) + case t.ActivateBid != nil: + return json.Marshal(TransactionEntryPointActivateBid) + case t.ChangeBidPublicKey != nil: + return json.Marshal(TransactionEntryPointChangeBidPublicKey) + case t.Call != nil: + return json.Marshal(TransactionEntryPointCall) + default: + return nil, errors.New("unknown entry point") + } +} diff --git a/types/transaction_scheduling.go b/types/transaction_scheduling.go new file mode 100644 index 0000000..ce06451 --- /dev/null +++ b/types/transaction_scheduling.go @@ -0,0 +1,116 @@ +package types + +import ( + "encoding/json" + "errors" + "time" + + "github.com/make-software/casper-go-sdk/types/clvalue" +) + +const ( + TransactionSchedulingNativeTag = iota + TransactionSchedulingFutureEraTag + TransactionSchedulingFutureTimestampTag +) + +type TransactionScheduling struct { + // No special scheduling applied. + Standard *struct{} `json:"Standard,omitempty"` + // Execution should be scheduled for the specified era. + FutureEra *FutureEraScheduling `json:"FutureTimestamp,omitempty"` + // Execution should be scheduled for the specified timestamp or later. + FutureTimestamp *FutureTimestampScheduling `json:"FutureEra,omitempty"` +} + +func (t *TransactionScheduling) Tag() byte { + switch { + case t.Standard != nil: + return TransactionSchedulingNativeTag + case t.FutureEra != nil: + return TransactionSchedulingFutureEraTag + case t.FutureTimestamp != nil: + return TransactionSchedulingFutureTimestampTag + default: + return 0 + } +} + +func (t *TransactionScheduling) Bytes() []byte { + result := make([]byte, 0, 2) + result = append(result, t.Tag()) + + if t.FutureEra != nil { + result = append(result, clvalue.NewCLUInt64(t.FutureEra.EraID).Bytes()...) + } else if t.FutureTimestamp != nil { + result = append(result, clvalue.NewCLUInt64(uint64(time.Time(t.FutureTimestamp.TimeStamp).UnixMilli())).Bytes()...) + } + return result +} + +func (t *TransactionScheduling) UnmarshalJSON(data []byte) error { + var futureKey struct { + EraID *uint64 `json:"FutureEra"` + FutureTimestamp *Timestamp `json:"FutureTimestamp"` + } + if err := json.Unmarshal(data, &futureKey); err == nil { + if futureKey.FutureTimestamp != nil { + *t = TransactionScheduling{ + FutureTimestamp: &FutureTimestampScheduling{ + TimeStamp: *futureKey.FutureTimestamp, + }, + } + } + + if futureKey.EraID != nil { + *t = TransactionScheduling{ + FutureEra: &FutureEraScheduling{ + EraID: *futureKey.EraID, + }, + } + } + return nil + } + + var key string + if err := json.Unmarshal(data, &key); err == nil && key == "Standard" { + *t = TransactionScheduling{ + Standard: &struct{}{}, + } + return nil + } + + return nil +} + +func (t TransactionScheduling) MarshalJSON() ([]byte, error) { + if t.Standard != nil { + return json.Marshal("Standard") + } + + if t.FutureTimestamp != nil { + return json.Marshal(struct { + FutureTimestamp Timestamp `json:"FutureTimestamp"` + }{ + FutureTimestamp: t.FutureTimestamp.TimeStamp, + }) + } + + if t.FutureEra != nil { + return json.Marshal(struct { + FutureEra uint64 `json:"FutureEra"` + }{ + FutureEra: t.FutureEra.EraID, + }) + } + + return nil, errors.New("unknown scheduling type") +} + +type FutureEraScheduling struct { + EraID uint64 +} + +type FutureTimestampScheduling struct { + TimeStamp Timestamp `json:"FutureTimestamp"` +} diff --git a/types/transaction_target.go b/types/transaction_target.go new file mode 100644 index 0000000..89d142d --- /dev/null +++ b/types/transaction_target.go @@ -0,0 +1,256 @@ +package types + +import ( + "encoding/hex" + "encoding/json" + "errors" + + "github.com/make-software/casper-go-sdk/types/clvalue" + "github.com/make-software/casper-go-sdk/types/key" +) + +const ( + TransactionTargetTypeNative = iota + TransactionTargetTypeStored + TransactionTargetTypeSession +) + +const ( + InvocationTargetTagByHash = iota + InvocationTargetTagByName + InvocationTargetTagByPackageHash + InvocationTargetTagByPackageName +) + +type TransactionTarget struct { + // The execution target is a native operation (e.g. a transfer). + Native *struct{} + // The execution target is a stored entity or package. + Stored *StoredTarget `json:"Stored"` + // The execution target is the included module bytes, i.e. compiled Wasm. + Session *SessionTarget `json:"Session"` +} + +func (t *TransactionTarget) Bytes() ([]byte, error) { + result := make([]byte, 0, 8) + + if t.Native != nil { + result = append(result, TransactionTargetTypeNative) + } else if t.Stored != nil { + result = append(result, TransactionTargetTypeStored) + if byHash := t.Stored.ID.ByHash; byHash != nil { + result = append(result, InvocationTargetTagByHash) + result = append(result, byHash.Bytes()...) + } else if byName := t.Stored.ID.ByName; byName != nil { + result = append(result, InvocationTargetTagByName) + result = append(result, clvalue.NewCLString(*byName).Bytes()...) + } else if byPackageHash := t.Stored.ID.ByPackageHash; byPackageHash != nil { + result = append(result, InvocationTargetTagByPackageHash) + result = append(result, byPackageHash.Addr.Bytes()...) + if byPackageHash.Version != nil { + result = append(result, clvalue.NewCLUInt32(*byPackageHash.Version).Bytes()...) + } + } else if byPackageName := t.Stored.ID.ByPackageName; byPackageName != nil { + result = append(result, InvocationTargetTagByPackageName) + result = append(result, clvalue.NewCLString(byPackageName.Name).Bytes()...) + if byPackageHash.Version != nil { + result = append(result, clvalue.NewCLUInt32(*byPackageName.Version).Bytes()...) + } + } + result = append(result, t.Stored.Runtime.RuntimeTag()) + } else if t.Session != nil { + result = append(result, TransactionTargetTypeSession) + bytes, err := hex.DecodeString(t.Session.ModuleBytes) + if err != nil { + return nil, err + } + result = append(result, clvalue.NewCLUInt32(uint32(len(bytes))).Bytes()...) + result = append(result, clvalue.NewCLByteArray(bytes).Bytes()...) + + result = append(result, t.Session.Runtime.RuntimeTag()) + } + + return result, nil +} + +func (t *TransactionTarget) UnmarshalJSON(data []byte) error { + var target struct { + Stored *StoredTarget `json:"Stored"` + Session *SessionTarget `json:"Session"` + } + if err := json.Unmarshal(data, &target); err == nil { + if target.Session != nil { + *t = TransactionTarget{ + Session: target.Session, + } + } + + if target.Stored != nil { + *t = TransactionTarget{ + Stored: target.Stored, + } + } + return nil + } + + var key string + if err := json.Unmarshal(data, &key); err == nil && key == "Native" { + *t = TransactionTarget{ + Native: &struct{}{}, + } + return nil + } + + return nil +} + +func (t TransactionTarget) MarshalJSON() ([]byte, error) { + if t.Native != nil { + return json.Marshal("Native") + } + + if t.Stored != nil { + return json.Marshal(struct { + Stored *StoredTarget `json:"Stored"` + }{ + Stored: t.Stored, + }) + } + + if t.Session != nil { + return json.Marshal(struct { + Session *SessionTarget `json:"Session"` + }{ + Session: t.Session, + }) + } + + return nil, errors.New("unknown target type") +} + +// NewTransactionTargetFromSession create new TransactionTarget from ExecutableDeployItem +func NewTransactionTargetFromSession(session ExecutableDeployItem) TransactionTarget { + if session.Transfer != nil { + return TransactionTarget{ + Native: &struct{}{}, + } + } + + if session.ModuleBytes != nil { + return TransactionTarget{ + Session: &SessionTarget{ + ModuleBytes: session.ModuleBytes.ModuleBytes, + Runtime: "VmCasperV1", + }, + } + } + + if session.StoredContractByHash != nil { + hash := session.StoredContractByHash.Hash.Hash + return TransactionTarget{ + Stored: &StoredTarget{ + ID: TransactionInvocationTarget{ + ByHash: &hash, + }, + Runtime: "VmCasperV1", + }, + } + } + + if session.StoredContractByName != nil { + return TransactionTarget{ + Stored: &StoredTarget{ + ID: TransactionInvocationTarget{ + ByName: &session.StoredContractByName.Name, + }, + Runtime: "VmCasperV1", + }, + } + } + + if session.StoredVersionedContractByHash != nil { + var version *uint32 + if storedVersion := session.StoredVersionedContractByHash.Version; storedVersion != nil { + versionNum, err := storedVersion.Int64() + if err == nil { + temp := uint32(versionNum) + version = &temp + } + } + byHashTarget := ByPackageHashInvocationTarget{ + Addr: session.StoredVersionedContractByHash.Hash.Hash, + Version: version, + } + return TransactionTarget{ + Stored: &StoredTarget{ + ID: TransactionInvocationTarget{ + ByPackageHash: &byHashTarget, + }, + Runtime: "VmCasperV1", + }, + } + } + + if session.StoredVersionedContractByName != nil { + var version *uint32 + if storedVersion := session.StoredVersionedContractByName.Version; storedVersion != nil { + versionNum, err := storedVersion.Int64() + if err == nil { + temp := uint32(versionNum) + version = &temp + } + } + byNameTarget := ByPackageNameInvocationTarget{ + Version: version, + } + + if session.StoredContractByName != nil { + byNameTarget.Name = session.StoredContractByName.Name + } + + return TransactionTarget{ + Stored: &StoredTarget{ + ID: TransactionInvocationTarget{ + ByPackageName: &byNameTarget, + }, + Runtime: "VmCasperV1", + }, + } + } + + return TransactionTarget{} +} + +type StoredTarget struct { + // Identifier of a `Stored` transaction target. + ID TransactionInvocationTarget `json:"id"` + Runtime TransactionRuntime `json:"runtime"` +} + +type TransactionInvocationTarget struct { + // Hex-encoded entity address identifying the invocable entity. + ByHash *key.Hash `json:"ByHash"` + // The alias identifying the invocable entity. + ByName *string `json:"ByName"` + // The address and optional version identifying the package. + ByPackageHash *ByPackageHashInvocationTarget `json:"ByPackageHash"` + // The alias and optional version identifying the package. + ByPackageName *ByPackageNameInvocationTarget `json:"ByPackageName"` +} + +// ByPackageHashInvocationTarget The address and optional version identifying the package. +type ByPackageHashInvocationTarget struct { + Addr key.Hash `json:"addr"` + Version *uint32 `json:"version"` +} + +// ByPackageNameInvocationTarget The alias and optional version identifying the package. +type ByPackageNameInvocationTarget struct { + Name string `json:"name"` + Version *uint32 `json:"version"` +} + +type SessionTarget struct { + ModuleBytes string `json:"module_bytes"` + Runtime TransactionRuntime `json:"runtime"` +} diff --git a/types/transfer.go b/types/transfer.go index 44e11eb..62f30fb 100644 --- a/types/transfer.go +++ b/types/transfer.go @@ -137,3 +137,17 @@ type InitiatorAddr struct { // The account hash derived from the public key of the initiator AccountHash *key.AccountHash `json:"AccountHash,omitempty"` } + +func (d InitiatorAddr) Bytes() []byte { + var result []byte + + if d.AccountHash != nil { + result = append(result, 1) + result = append(result, d.AccountHash.Bytes()...) + } else if d.PublicKey != nil { + result = append(result, 0) + result = append(result, d.PublicKey.Bytes()...) + } + + return result +} From 41bb034697a47992c095c9a6af3f24a033a6875c Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Wed, 17 Jul 2024 10:12:52 +0100 Subject: [PATCH 2/6] CSDK/implement_account_put_transaction Updated comment --- rpc/client.go | 4 ++-- rpc/rpc_client.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rpc/client.go b/rpc/client.go index f23f566..5e02a64 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -159,8 +159,8 @@ type ClientInformational interface { GetChainspec(ctx context.Context) (InfoGetChainspecResult, error) } -// ClientTransactional contains the description of account_put_deploy, -// the only means by which users can send their compiled Wasm (as part of a Deploy) to a node on a Casper network. +// ClientTransactional contains the description of account_put_deploy, account_put_transaction +// the only means by which users can send their compiled Wasm (as part of a Deploy or Transaction) to a node on a Casper network. type ClientTransactional interface { PutDeploy(ctx context.Context, deploy types.Deploy) (PutDeployResult, error) PutTransaction(ctx context.Context, transaction types.TransactionV1) (PutTransactionResult, error) diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index e8b6604..c83e1b9 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -642,9 +642,9 @@ func (c *client) PutDeploy(ctx context.Context, deploy types.Deploy) (PutDeployR func (c *client) PutTransaction(ctx context.Context, transaction types.TransactionV1) (PutTransactionResult, error) { var result PutTransactionResult - resp, err := c.processRequest(ctx, MethodPutTransaction, map[string]interface{}{ - "transaction": map[string]interface{}{ - "Version1": transaction, + resp, err := c.processRequest(ctx, MethodPutTransaction, PutTransactionRequest{ + Transaction: types.TransactionWrapper{ + TransactionV1: &transaction, }, }, &result) if err != nil { From 6243805840a437a9a5009777bcb35ac0ce14d26d Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Wed, 17 Jul 2024 15:02:12 +0100 Subject: [PATCH 3/6] CSDK/implement_account_put_transaction Fixed after review --- types/initiator_addr.go | 28 ++++++++++++++++++++++++++++ types/transaction.go | 17 +++++++++++++---- types/transaction_entrypoint.go | 10 ++++------ types/transaction_target.go | 14 +++++++++----- types/transfer.go | 23 ----------------------- 5 files changed, 54 insertions(+), 38 deletions(-) create mode 100644 types/initiator_addr.go diff --git a/types/initiator_addr.go b/types/initiator_addr.go new file mode 100644 index 0000000..a33f18c --- /dev/null +++ b/types/initiator_addr.go @@ -0,0 +1,28 @@ +package types + +import ( + "github.com/make-software/casper-go-sdk/types/key" + "github.com/make-software/casper-go-sdk/types/keypair" +) + +// InitiatorAddr the address of the initiator of a TransactionV1. +type InitiatorAddr struct { + // The public key of the initiator + PublicKey *keypair.PublicKey `json:"PublicKey,omitempty"` + // The account hash derived from the public key of the initiator + AccountHash *key.AccountHash `json:"AccountHash,omitempty"` +} + +func (d InitiatorAddr) Bytes() []byte { + result := make([]byte, 0, 32) + + if d.AccountHash != nil { + result = append(result, 1) + result = append(result, d.AccountHash.Bytes()...) + } else if d.PublicKey != nil { + result = append(result, 0) + result = append(result, d.PublicKey.Bytes()...) + } + + return result +} diff --git a/types/transaction.go b/types/transaction.go index 59de51b..cff7ea7 100644 --- a/types/transaction.go +++ b/types/transaction.go @@ -97,12 +97,21 @@ func NewTransactionFromDeploy(deploy Deploy) Transaction { if deploy.Session.Transfer != nil { transactionEntryPoint.Transfer = &struct{}{} + } else if deploy.Session.ModuleBytes != nil { + transactionEntryPoint.Call = &struct{}{} } else { - transactionEntryPoint.Custom = &struct { - Type string - }{ - Type: "Call", + var entrypoint string + switch { + case deploy.Session.StoredContractByHash != nil: + entrypoint = deploy.Session.StoredContractByHash.EntryPoint + case deploy.Session.StoredContractByName != nil: + entrypoint = deploy.Session.StoredContractByName.EntryPoint + case deploy.Session.StoredVersionedContractByHash != nil: + entrypoint = deploy.Session.StoredVersionedContractByHash.EntryPoint + case deploy.Session.StoredVersionedContractByName != nil: + entrypoint = deploy.Session.StoredVersionedContractByName.EntryPoint } + transactionEntryPoint.Custom = &entrypoint } if args := deploy.Payment.Args(); args != nil { diff --git a/types/transaction_entrypoint.go b/types/transaction_entrypoint.go index e5cf38c..e7caf27 100644 --- a/types/transaction_entrypoint.go +++ b/types/transaction_entrypoint.go @@ -34,9 +34,7 @@ const ( ) type TransactionEntryPoint struct { - Custom *struct { - Type string - } + Custom *string // The `transfer` native entry point, used to transfer `Motes` from a source purse to a target purse. Transfer *struct{} // The `add_bid` native entry point, used to create or top off a bid purse. @@ -63,7 +61,7 @@ func (t *TransactionEntryPoint) Bytes() []byte { result = append(result, t.Tag()) if t.Custom != nil { - result = append(result, clvalue.NewCLString(t.Custom.Type).Bytes()...) + result = append(result, clvalue.NewCLString(*t.Custom).Bytes()...) } return result } @@ -101,7 +99,7 @@ func (t *TransactionEntryPoint) UnmarshalJSON(data []byte) error { } if err := json.Unmarshal(data, &custom); err == nil { *t = TransactionEntryPoint{ - Custom: &struct{ Type string }{Type: custom.Custom}, + Custom: &custom.Custom, } return nil } @@ -142,7 +140,7 @@ func (t TransactionEntryPoint) MarshalJSON() ([]byte, error) { return json.Marshal(struct { Custom string `json:"Custom"` }{ - Custom: t.Custom.Type, + Custom: *t.Custom, }) } diff --git a/types/transaction_target.go b/types/transaction_target.go index 89d142d..c133673 100644 --- a/types/transaction_target.go +++ b/types/transaction_target.go @@ -60,12 +60,16 @@ func (t *TransactionTarget) Bytes() ([]byte, error) { result = append(result, t.Stored.Runtime.RuntimeTag()) } else if t.Session != nil { result = append(result, TransactionTargetTypeSession) - bytes, err := hex.DecodeString(t.Session.ModuleBytes) - if err != nil { - return nil, err + if len(t.Session.ModuleBytes) == 0 { + result = append(result, clvalue.NewCLInt32(0).Bytes()...) + } else { + bytes, err := hex.DecodeString(t.Session.ModuleBytes) + if err != nil { + return nil, err + } + result = append(result, clvalue.NewCLUInt32(uint32(len(bytes))).Bytes()...) + result = append(result, clvalue.NewCLByteArray(bytes).Bytes()...) } - result = append(result, clvalue.NewCLUInt32(uint32(len(bytes))).Bytes()...) - result = append(result, clvalue.NewCLByteArray(bytes).Bytes()...) result = append(result, t.Session.Runtime.RuntimeTag()) } diff --git a/types/transfer.go b/types/transfer.go index 62f30fb..795a50a 100644 --- a/types/transfer.go +++ b/types/transfer.go @@ -6,7 +6,6 @@ import ( "github.com/make-software/casper-go-sdk/types/clvalue" "github.com/make-software/casper-go-sdk/types/key" - "github.com/make-software/casper-go-sdk/types/keypair" ) // Transfer a versioned wrapper for a transfer. @@ -129,25 +128,3 @@ type TransferV2 struct { // Account to which funds are transferred To *key.AccountHash `json:"to"` } - -// InitiatorAddr the address of the initiator of a TransactionV1. -type InitiatorAddr struct { - // The public key of the initiator - PublicKey *keypair.PublicKey `json:"PublicKey,omitempty"` - // The account hash derived from the public key of the initiator - AccountHash *key.AccountHash `json:"AccountHash,omitempty"` -} - -func (d InitiatorAddr) Bytes() []byte { - var result []byte - - if d.AccountHash != nil { - result = append(result, 1) - result = append(result, d.AccountHash.Bytes()...) - } else if d.PublicKey != nil { - result = append(result, 0) - result = append(result, d.PublicKey.Bytes()...) - } - - return result -} From cf99376bd3dda227027ec5709d8ac861f4a5f568 Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Wed, 17 Jul 2024 15:59:34 +0100 Subject: [PATCH 4/6] CSDK/implement_account_put_transaction Fixed after review --- rpc/client.go | 12 +-- rpc/rpc_client.go | 6 +- sse/event.go | 4 +- tests/rpc/integration/put_transaction_test.go | 8 +- tests/rpc/rpc_client_test.go | 2 +- tests/sse/events_parsing_test.go | 4 +- types/block.go | 52 ++++------ types/execution_result.go | 2 +- types/transaction.go | 99 +++++++++++-------- types/transaction_target.go | 10 +- 10 files changed, 103 insertions(+), 96 deletions(-) diff --git a/rpc/client.go b/rpc/client.go index 5e02a64..458ad76 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -55,13 +55,13 @@ type ClientInformational interface { GetDeploy(ctx context.Context, hash string) (InfoGetDeployResult, error) // GetDeployFinalizedApproval returns Deploy with the finalized approvals substituted. GetDeployFinalizedApproval(ctx context.Context, hash string) (InfoGetDeployResult, error) - // GetTransactionByTransactionHash returns a Transaction from the network + // GetTransactionByTransactionHash returns a TransactionV1 from the network GetTransactionByTransactionHash(ctx context.Context, transactionHash string) (InfoGetTransactionResult, error) - // GetTransactionByDeployHash returns a Deploy as Transaction from the network + // GetTransactionByDeployHash returns a Deploy as TransactionV1 from the network GetTransactionByDeployHash(ctx context.Context, deployHash string) (InfoGetTransactionResult, error) - // GetTransactionFinalizedApprovalByTransactionHash return the Transaction with the finalized approvals substituted. + // GetTransactionFinalizedApprovalByTransactionHash return the TransactionV1 with the finalized approvals substituted. GetTransactionFinalizedApprovalByTransactionHash(ctx context.Context, transactionHash string) (InfoGetTransactionResult, error) - // GetTransactionFinalizedApprovalByDeployHash return the Deploy as Transaction with the finalized approvals substituted. + // GetTransactionFinalizedApprovalByDeployHash return the Deploy as TransactionV1 with the finalized approvals substituted. GetTransactionFinalizedApprovalByDeployHash(ctx context.Context, deployHash string) (InfoGetTransactionResult, error) // GetDictionaryItem returns an item from a Dictionary. // The address of a stored value is the blake2b hash of the seed URef and the byte representation of the dictionary key. @@ -160,10 +160,10 @@ type ClientInformational interface { } // ClientTransactional contains the description of account_put_deploy, account_put_transaction -// the only means by which users can send their compiled Wasm (as part of a Deploy or Transaction) to a node on a Casper network. +// the only means by which users can send their compiled Wasm (as part of a Deploy or TransactionV1) to a node on a Casper network. type ClientTransactional interface { PutDeploy(ctx context.Context, deploy types.Deploy) (PutDeployResult, error) - PutTransaction(ctx context.Context, transaction types.TransactionV1) (PutTransactionResult, error) + PutTransactionV1(ctx context.Context, transaction types.TransactionV1) (PutTransactionResult, error) } // Client interface represent full RPC client that includes all possible queries. diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go index c83e1b9..d51d73b 100644 --- a/rpc/rpc_client.go +++ b/rpc/rpc_client.go @@ -64,7 +64,7 @@ func (c *client) GetTransactionByTransactionHash(ctx context.Context, transactio var result infoGetTransactionResultV1Compatible resp, err := c.processRequest(ctx, MethodGetTransaction, ParamTransactionHash{ TransactionHash: types.TransactionHash{ - Transaction: &hash, + TransactionV1: &hash, }, }, &result) if err != nil { @@ -102,7 +102,7 @@ func (c *client) GetTransactionFinalizedApprovalByTransactionHash(ctx context.Co var result infoGetTransactionResultV1Compatible resp, err := c.processRequest(ctx, MethodGetTransaction, ParamTransactionHash{ TransactionHash: types.TransactionHash{ - Transaction: &hash, + TransactionV1: &hash, }, FinalizedApprovals: &[]bool{true}[0], }, &result) @@ -639,7 +639,7 @@ func (c *client) PutDeploy(ctx context.Context, deploy types.Deploy) (PutDeployR return result, nil } -func (c *client) PutTransaction(ctx context.Context, transaction types.TransactionV1) (PutTransactionResult, error) { +func (c *client) PutTransactionV1(ctx context.Context, transaction types.TransactionV1) (PutTransactionResult, error) { var result PutTransactionResult resp, err := c.processRequest(ctx, MethodPutTransaction, PutTransactionRequest{ diff --git a/sse/event.go b/sse/event.go index 4827a03..040a7a2 100644 --- a/sse/event.go +++ b/sse/event.go @@ -224,7 +224,7 @@ func (t *TransactionProcessedEvent) UnmarshalJSON(data []byte) error { return err } - if transactionEvent.TransactionProcessedPayload.TransactionHash.Transaction != nil || + if transactionEvent.TransactionProcessedPayload.TransactionHash.TransactionV1 != nil || transactionEvent.TransactionProcessedPayload.TransactionHash.Deploy != nil { *t = transactionEvent return nil @@ -264,7 +264,7 @@ func (t *TransactionExpiredEvent) UnmarshalJSON(data []byte) error { return err } - if transactionEvent.TransactionExpiredPayload.TransactionHash.Transaction != nil || + if transactionEvent.TransactionExpiredPayload.TransactionHash.TransactionV1 != nil || transactionEvent.TransactionExpiredPayload.TransactionHash.Deploy != nil { *t = transactionEvent return nil diff --git a/tests/rpc/integration/put_transaction_test.go b/tests/rpc/integration/put_transaction_test.go index ec38468..5f21add 100644 --- a/tests/rpc/integration/put_transaction_test.go +++ b/tests/rpc/integration/put_transaction_test.go @@ -75,15 +75,15 @@ func Test_PutTransaction(t *testing.T) { require.NoError(t, err) rpcClient := rpc.NewClient(rpc.NewHttpHandler("http://127.0.0.1:11101/rpc", http.DefaultClient)) - res, err := rpcClient.PutTransaction(context.Background(), *transaction) + res, err := rpcClient.PutTransactionV1(context.Background(), *transaction) require.NoError(t, err) - assert.NotEmpty(t, res.TransactionHash.Transaction) + assert.NotEmpty(t, res.TransactionHash.TransactionV1) assert.NoError(t, transaction.Validate()) - log.Println("Transaction submitted:", res.TransactionHash.Transaction) + log.Println("TransactionV1 submitted:", res.TransactionHash.TransactionV1) time.Sleep(time.Second * 10) - transactionRes, err := rpcClient.GetTransactionByTransactionHash(context.Background(), res.TransactionHash.Transaction.ToHex()) + transactionRes, err := rpcClient.GetTransactionByTransactionHash(context.Background(), res.TransactionHash.TransactionV1.ToHex()) require.NoError(t, err) assert.NotEmpty(t, transactionRes.Transaction) assert.NotEmpty(t, transactionRes.ExecutionInfo) diff --git a/tests/rpc/rpc_client_test.go b/tests/rpc/rpc_client_test.go index 10021c3..9423ec4 100644 --- a/tests/rpc/rpc_client_test.go +++ b/tests/rpc/rpc_client_test.go @@ -132,7 +132,7 @@ func Test_DefaultClient_GetTransaction_Example(t *testing.T) { assert.NotEmpty(t, result.Transaction.TransactionHeader.PricingMode) assert.NotEmpty(t, result.Transaction.TransactionHeader.InitiatorAddr) assert.NotEmpty(t, result.Transaction.TransactionBody.Target) - assert.NotEmpty(t, result.Transaction.TransactionBody.TransactionScheduling) + assert.NotEmpty(t, result.Transaction.TransactionBody.Scheduling) assert.NotEmpty(t, result.ExecutionInfo.ExecutionResult.Initiator) assert.NotEmpty(t, result.ExecutionInfo.ExecutionResult.Effects) assert.NotEmpty(t, result.Transaction.Approvals) diff --git a/tests/sse/events_parsing_test.go b/tests/sse/events_parsing_test.go index 1b3503f..b4cb771 100644 --- a/tests/sse/events_parsing_test.go +++ b/tests/sse/events_parsing_test.go @@ -163,7 +163,7 @@ func Test_RawEvent_ParseAsTransactionExpiredEvent(t *testing.T) { require.NotEmpty(t, res.TransactionExpiredPayload.TransactionHash) if tc.isTransaction { - require.NotEmpty(t, res.TransactionExpiredPayload.TransactionHash.Transaction) + require.NotEmpty(t, res.TransactionExpiredPayload.TransactionHash.TransactionV1) } else { require.NotEmpty(t, res.TransactionExpiredPayload.TransactionHash.Deploy) } @@ -238,7 +238,7 @@ func Test_RawEvent_ParseAsTransactionProcessedEvent(t *testing.T) { require.NotEmpty(t, res.TransactionProcessedPayload.TransactionHash) if tc.isTransaction { - require.NotEmpty(t, res.TransactionProcessedPayload.TransactionHash.Transaction) + require.NotEmpty(t, res.TransactionProcessedPayload.TransactionHash.TransactionV1) require.NotEmpty(t, res.TransactionProcessedPayload.Messages) } else { require.NotEmpty(t, res.TransactionProcessedPayload.TransactionHash.Deploy) diff --git a/types/block.go b/types/block.go index 31b26d4..3549573 100644 --- a/types/block.go +++ b/types/block.go @@ -76,16 +76,16 @@ func NewBlockFromBlockV1(blockV1 BlockV1) Block { blockTransactions := make(BlockTransactions, 0) for i := range blockV1.Body.TransferHashes { blockTransactions = append(blockTransactions, BlockTransaction{ - Category: BlockTransactionCategoryMint, - Version: BlockTransactionDeploy, + Category: TransactionCategoryMint, + Version: TransactionDeploy, Hash: blockV1.Body.TransferHashes[i], }) } for i := range blockV1.Body.DeployHashes { blockTransactions = append(blockTransactions, BlockTransaction{ - Category: BlockTransactionCategoryLarge, - Version: BlockTransactionDeploy, + Category: TransactionCategoryLarge, + Version: TransactionDeploy, Hash: blockV1.Body.DeployHashes[i], }) } @@ -228,24 +228,6 @@ type BlockV2 struct { // We need to wait for a few blocks to pass (`signature_rewards_max_delay`) to store the finality signers because we need a bit of time to get the block finality. type SingleBlockRewardedSignatures []uint8 -type BlockTransactionCategory uint - -const ( - BlockTransactionCategoryMint BlockTransactionCategory = iota - BlockTransactionCategoryAuction - BlockTransactionCategoryInstallUpgrade - BlockTransactionCategoryLarge - BlockTransactionCategoryMedium - BlockTransactionCategorySmall -) - -type BlockTransactionVersion uint - -const ( - BlockTransactionVersionV1 BlockTransactionVersion = iota - BlockTransactionDeploy -) - type BlockTransactions []BlockTransaction func (t *BlockTransactions) UnmarshalJSON(data []byte) error { @@ -267,19 +249,19 @@ func (t *BlockTransactions) UnmarshalJSON(data []byte) error { } res := make(BlockTransactions, 0) - res = append(res, getBlockTransactionsFromTransactionHashes(source.Mint, BlockTransactionCategoryMint)...) - res = append(res, getBlockTransactionsFromTransactionHashes(source.Auction, BlockTransactionCategoryAuction)...) - res = append(res, getBlockTransactionsFromTransactionHashes(source.InstallUpgrade, BlockTransactionCategoryInstallUpgrade)...) - res = append(res, getBlockTransactionsFromTransactionHashes(source.Large, BlockTransactionCategoryLarge)...) - res = append(res, getBlockTransactionsFromTransactionHashes(source.Medium, BlockTransactionCategoryMedium)...) - res = append(res, getBlockTransactionsFromTransactionHashes(source.Small, BlockTransactionCategorySmall)...) + res = append(res, getBlockTransactionsFromTransactionHashes(source.Mint, TransactionCategoryMint)...) + res = append(res, getBlockTransactionsFromTransactionHashes(source.Auction, TransactionCategoryAuction)...) + res = append(res, getBlockTransactionsFromTransactionHashes(source.InstallUpgrade, TransactionCategoryInstallUpgrade)...) + res = append(res, getBlockTransactionsFromTransactionHashes(source.Large, TransactionCategoryLarge)...) + res = append(res, getBlockTransactionsFromTransactionHashes(source.Medium, TransactionCategoryMedium)...) + res = append(res, getBlockTransactionsFromTransactionHashes(source.Small, TransactionCategorySmall)...) *t = res return nil } type BlockTransaction struct { - Category BlockTransactionCategory - Version BlockTransactionVersion + Category TransactionCategory + Version TransactionVersion Hash key.Hash } @@ -314,7 +296,7 @@ type Proof struct { Signature HexBytes `json:"signature"` } -func getBlockTransactionsFromTransactionHashes(hashes []TransactionHash, category BlockTransactionCategory) BlockTransactions { +func getBlockTransactionsFromTransactionHashes(hashes []TransactionHash, category TransactionCategory) BlockTransactions { if len(hashes) == 0 { return nil } @@ -324,12 +306,12 @@ func getBlockTransactionsFromTransactionHashes(hashes []TransactionHash, categor blockTransaction := BlockTransaction{ Category: category, } - if hashes[i].Transaction != nil { - blockTransaction.Hash = *hashes[i].Transaction - blockTransaction.Version = BlockTransactionVersionV1 + if hashes[i].TransactionV1 != nil { + blockTransaction.Hash = *hashes[i].TransactionV1 + blockTransaction.Version = TransactionVersionV1 } else { blockTransaction.Hash = *hashes[i].Deploy - blockTransaction.Version = BlockTransactionDeploy + blockTransaction.Version = TransactionDeploy } res = append(res, blockTransaction) diff --git a/types/execution_result.go b/types/execution_result.go index b0166ca..22ea82a 100644 --- a/types/execution_result.go +++ b/types/execution_result.go @@ -118,7 +118,7 @@ func NewExecutionResultFromV1(v1 ExecutionResultV1) ExecutionResult { transfers = append(transfers, Transfer{ Amount: writeTransfer.Amount, TransactionHash: TransactionHash{ - Transaction: transform.Key.Hash, + TransactionV1: transform.Key.Hash, }, From: InitiatorAddr{ AccountHash: &writeTransfer.From, diff --git a/types/transaction.go b/types/transaction.go index cff7ea7..fdd5cc8 100644 --- a/types/transaction.go +++ b/types/transaction.go @@ -19,6 +19,24 @@ var ( ErrInvalidApprovalSignature = errors.New("invalid approval signature") ) +type TransactionCategory uint + +const ( + TransactionCategoryMint TransactionCategory = iota + TransactionCategoryAuction + TransactionCategoryInstallUpgrade + TransactionCategoryLarge + TransactionCategoryMedium + TransactionCategorySmall +) + +type TransactionVersion uint + +const ( + TransactionVersionV1 TransactionVersion = iota + TransactionDeploy +) + type Transaction struct { // Hex-encoded TransactionV1 hash TransactionHash key.Hash `json:"hash"` @@ -29,7 +47,7 @@ type Transaction struct { // List of signers and signatures for this `deploy` Approvals []Approval `json:"approvals"` - // source BlockV1, nil if constructed from BlockV2 + // source DeployV1, nil if constructed from TransactionV1 originDeployV1 *Deploy originTransactionV1 *TransactionV1 } @@ -39,21 +57,21 @@ type TransactionBody struct { // Execution target of a Transaction. Target TransactionTarget `json:"target"` // Entry point of a Transaction. - TransactionEntryPoint TransactionEntryPoint `json:"entry_point"` + EntryPoint TransactionEntryPoint `json:"entry_point"` // Scheduling mode of a Transaction. - TransactionScheduling TransactionScheduling `json:"scheduling"` + Scheduling TransactionScheduling `json:"scheduling"` + // Transaction category + Category uint8 `json:"transaction_category"` } type TransactionHeader struct { - // `Hash` of the body part of this `Deploy`. - BodyHash key.Hash `json:"body_hash"` - + // Transaction chain name ChainName string `json:"chain_name"` // `Timestamp` formatted as per RFC 3339 Timestamp Timestamp `json:"timestamp"` - // Duration of the `Deploy` in milliseconds (from timestamp). + // Duration of the `TransactionV1` in milliseconds (from timestamp). TTL Duration `json:"ttl"` - // The address of the initiator of a TransactionV1. + // The address of the initiator of a Transaction. InitiatorAddr InitiatorAddr `json:"initiator_addr"` // Pricing mode of a Transaction. PricingMode PricingMode `json:"pricing_mode"` @@ -69,20 +87,19 @@ func (t *Transaction) GetTransactionV1() *TransactionV1 { func NewTransactionFromTransactionV1(v1 TransactionV1) Transaction { return Transaction{ - TransactionHash: v1.TransactionV1Hash, + TransactionHash: v1.Hash, TransactionHeader: TransactionHeader{ - BodyHash: v1.TransactionV1Header.BodyHash, - ChainName: v1.TransactionV1Header.ChainName, - Timestamp: v1.TransactionV1Header.Timestamp, - TTL: v1.TransactionV1Header.TTL, - InitiatorAddr: v1.TransactionV1Header.InitiatorAddr, - PricingMode: v1.TransactionV1Header.PricingMode, + ChainName: v1.Header.ChainName, + Timestamp: v1.Header.Timestamp, + TTL: v1.Header.TTL, + InitiatorAddr: v1.Header.InitiatorAddr, + PricingMode: v1.Header.PricingMode, }, TransactionBody: TransactionBody{ - Args: v1.TransactionV1Body.Args, - Target: v1.TransactionV1Body.Target, - TransactionEntryPoint: v1.TransactionV1Body.TransactionEntryPoint, - TransactionScheduling: v1.TransactionV1Body.TransactionScheduling, + Args: v1.Body.Args, + Target: v1.Body.Target, + EntryPoint: v1.Body.TransactionEntryPoint, + Scheduling: v1.Body.TransactionScheduling, }, Approvals: v1.Approvals, originTransactionV1: &v1, @@ -93,9 +110,11 @@ func NewTransactionFromDeploy(deploy Deploy) Transaction { var ( paymentAmount uint64 transactionEntryPoint TransactionEntryPoint + transactionCategory = TransactionCategoryLarge ) if deploy.Session.Transfer != nil { + transactionCategory = TransactionCategoryMint transactionEntryPoint.Transfer = &struct{}{} } else if deploy.Session.ModuleBytes != nil { transactionEntryPoint.Call = &struct{}{} @@ -127,11 +146,10 @@ func NewTransactionFromDeploy(deploy Deploy) Transaction { } // Use StandardPayment as true only for payments without explicit `payment amount` - var standardPayment = paymentAmount == 0 + var standardPayment = paymentAmount == 0 && deploy.Payment.ModuleBytes == nil return Transaction{ TransactionHash: deploy.Hash, TransactionHeader: TransactionHeader{ - BodyHash: deploy.Header.BodyHash, ChainName: deploy.Header.ChainName, Timestamp: deploy.Header.Timestamp, TTL: deploy.Header.TTL, @@ -147,12 +165,13 @@ func NewTransactionFromDeploy(deploy Deploy) Transaction { }, }, TransactionBody: TransactionBody{ - Args: deploy.Session.Args(), - Target: NewTransactionTargetFromSession(deploy.Session), - TransactionEntryPoint: transactionEntryPoint, - TransactionScheduling: TransactionScheduling{ + Args: deploy.Session.Args(), + Target: NewTransactionTargetFromSession(deploy.Session), + EntryPoint: transactionEntryPoint, + Scheduling: TransactionScheduling{ Standard: &struct{}{}, }, + Category: uint8(transactionCategory), }, Approvals: deploy.Approvals, originDeployV1: &deploy, @@ -166,11 +185,11 @@ type TransactionWrapper struct { type TransactionV1 struct { // Hex-encoded TransactionV1 hash - TransactionV1Hash key.Hash `json:"hash"` + Hash key.Hash `json:"hash"` // The header portion of a TransactionV1 - TransactionV1Header TransactionV1Header `json:"header"` + Header TransactionV1Header `json:"header"` // Body of a `TransactionV1` - TransactionV1Body TransactionV1Body `json:"body"` + Body TransactionV1Body `json:"body"` // List of signers and signatures for this `deploy` Approvals []Approval `json:"approvals"` } @@ -208,7 +227,7 @@ type TransactionV1Body struct { TransactionEntryPoint TransactionEntryPoint `json:"entry_point"` // Scheduling mode of a Transaction. TransactionScheduling TransactionScheduling `json:"scheduling"` - // Scheduling mode of a Transaction. + // Transaction category TransactionCategory uint8 `json:"transaction_category"` } @@ -234,12 +253,12 @@ func (t *TransactionV1Body) Bytes() ([]byte, error) { // TransactionHash A versioned wrapper for a transaction hash or deploy hash type TransactionHash struct { - Deploy *key.Hash `json:"Deploy,omitempty"` - Transaction *key.Hash `json:"Version1,omitempty"` + Deploy *key.Hash `json:"Deploy,omitempty"` + TransactionV1 *key.Hash `json:"Version1,omitempty"` } func (t *TransactionV1) Sign(keys keypair.PrivateKey) error { - signature, err := keys.Sign(t.TransactionV1Hash.Bytes()) + signature, err := keys.Sign(t.Hash.Bytes()) if err != nil { return err } @@ -257,21 +276,21 @@ func (t *TransactionV1) Sign(keys keypair.PrivateKey) error { } func (t *TransactionV1) Validate() error { - bodyBytes, err := t.TransactionV1Body.Bytes() + bodyBytes, err := t.Body.Bytes() if err != nil { return err } - if t.TransactionV1Header.BodyHash != blake2b.Sum256(bodyBytes) { + if t.Header.BodyHash != blake2b.Sum256(bodyBytes) { return ErrInvalidBodyHash } - if t.TransactionV1Hash != blake2b.Sum256(t.TransactionV1Header.Bytes()) { + if t.Hash != blake2b.Sum256(t.Header.Bytes()) { return ErrInvalidTransactionHash } for _, one := range t.Approvals { - if one.Signer.VerifySignature(t.TransactionV1Hash.Bytes(), one.Signature) != nil { + if one.Signer.VerifySignature(t.Hash.Bytes(), one.Signature) != nil { return ErrInvalidApprovalSignature } } @@ -281,10 +300,10 @@ func (t *TransactionV1) Validate() error { func NewTransactionV1(hash key.Hash, header TransactionV1Header, body TransactionV1Body, approvals []Approval) *TransactionV1 { return &TransactionV1{ - TransactionV1Hash: hash, - TransactionV1Header: header, - TransactionV1Body: body, - Approvals: approvals, + Hash: hash, + Header: header, + Body: body, + Approvals: approvals, } } diff --git a/types/transaction_target.go b/types/transaction_target.go index c133673..c15c2b7 100644 --- a/types/transaction_target.go +++ b/types/transaction_target.go @@ -48,13 +48,19 @@ func (t *TransactionTarget) Bytes() ([]byte, error) { result = append(result, InvocationTargetTagByPackageHash) result = append(result, byPackageHash.Addr.Bytes()...) if byPackageHash.Version != nil { + result = append(result, 1) result = append(result, clvalue.NewCLUInt32(*byPackageHash.Version).Bytes()...) + } else { + result = append(result, 0) } } else if byPackageName := t.Stored.ID.ByPackageName; byPackageName != nil { result = append(result, InvocationTargetTagByPackageName) result = append(result, clvalue.NewCLString(byPackageName.Name).Bytes()...) if byPackageHash.Version != nil { + result = append(result, 1) result = append(result, clvalue.NewCLUInt32(*byPackageName.Version).Bytes()...) + } else { + result = append(result, 0) } } result = append(result, t.Stored.Runtime.RuntimeTag()) @@ -208,8 +214,8 @@ func NewTransactionTargetFromSession(session ExecutableDeployItem) TransactionTa Version: version, } - if session.StoredContractByName != nil { - byNameTarget.Name = session.StoredContractByName.Name + if session.StoredVersionedContractByName != nil { + byNameTarget.Name = session.StoredVersionedContractByName.Name } return TransactionTarget{ From a23f140fa0b93783cee21aa6671552e64ae40651 Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Wed, 17 Jul 2024 16:06:00 +0100 Subject: [PATCH 5/6] CSDK/implement_info_get_reward_rpc Remove auto changes --- rpc/client.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rpc/client.go b/rpc/client.go index 458ad76..74c987e 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -55,13 +55,13 @@ type ClientInformational interface { GetDeploy(ctx context.Context, hash string) (InfoGetDeployResult, error) // GetDeployFinalizedApproval returns Deploy with the finalized approvals substituted. GetDeployFinalizedApproval(ctx context.Context, hash string) (InfoGetDeployResult, error) - // GetTransactionByTransactionHash returns a TransactionV1 from the network + // GetTransactionByTransactionHash returns a Transaction from the network GetTransactionByTransactionHash(ctx context.Context, transactionHash string) (InfoGetTransactionResult, error) - // GetTransactionByDeployHash returns a Deploy as TransactionV1 from the network + // GetTransactionByDeployHash returns a Deploy as Transaction from the network GetTransactionByDeployHash(ctx context.Context, deployHash string) (InfoGetTransactionResult, error) - // GetTransactionFinalizedApprovalByTransactionHash return the TransactionV1 with the finalized approvals substituted. + // GetTransactionFinalizedApprovalByTransactionHash return the Transaction with the finalized approvals substituted. GetTransactionFinalizedApprovalByTransactionHash(ctx context.Context, transactionHash string) (InfoGetTransactionResult, error) - // GetTransactionFinalizedApprovalByDeployHash return the Deploy as TransactionV1 with the finalized approvals substituted. + // GetTransactionFinalizedApprovalByDeployHash return the Deploy as Transaction with the finalized approvals substituted. GetTransactionFinalizedApprovalByDeployHash(ctx context.Context, deployHash string) (InfoGetTransactionResult, error) // GetDictionaryItem returns an item from a Dictionary. // The address of a stored value is the blake2b hash of the seed URef and the byte representation of the dictionary key. From abd4b0d815b66e701a53d096aa0221e875ffda7f Mon Sep 17 00:00:00 2001 From: Artem Zhmaka Date: Wed, 17 Jul 2024 16:31:05 +0100 Subject: [PATCH 6/6] CSDK/implement_account_put_transaction Fixed naming --- tests/rpc/rpc_client_test.go | 16 ++++++++-------- tests/sse/events_parsing_test.go | 4 ++-- types/transaction.go | 26 +++++++++++++------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/tests/rpc/rpc_client_test.go b/tests/rpc/rpc_client_test.go index 9423ec4..92ec103 100644 --- a/tests/rpc/rpc_client_test.go +++ b/tests/rpc/rpc_client_test.go @@ -125,14 +125,14 @@ func Test_DefaultClient_GetTransaction_Example(t *testing.T) { result, err := client.GetTransactionByTransactionHash(context.Background(), "0009ea4441f4700325d9c38b0b6df415537596e1204abe4f6a94b6996aebf2f1") require.NoError(t, err) assert.NotEmpty(t, result.APIVersion) - assert.NotEmpty(t, result.Transaction.TransactionHash) - assert.NotEmpty(t, result.Transaction.TransactionHeader) - assert.NotEmpty(t, result.Transaction.TransactionHeader.TTL) - assert.NotEmpty(t, result.Transaction.TransactionHeader.ChainName) - assert.NotEmpty(t, result.Transaction.TransactionHeader.PricingMode) - assert.NotEmpty(t, result.Transaction.TransactionHeader.InitiatorAddr) - assert.NotEmpty(t, result.Transaction.TransactionBody.Target) - assert.NotEmpty(t, result.Transaction.TransactionBody.Scheduling) + assert.NotEmpty(t, result.Transaction.Hash) + assert.NotEmpty(t, result.Transaction.Header) + assert.NotEmpty(t, result.Transaction.Header.TTL) + assert.NotEmpty(t, result.Transaction.Header.ChainName) + assert.NotEmpty(t, result.Transaction.Header.PricingMode) + assert.NotEmpty(t, result.Transaction.Header.InitiatorAddr) + assert.NotEmpty(t, result.Transaction.Body.Target) + assert.NotEmpty(t, result.Transaction.Body.Scheduling) assert.NotEmpty(t, result.ExecutionInfo.ExecutionResult.Initiator) assert.NotEmpty(t, result.ExecutionInfo.ExecutionResult.Effects) assert.NotEmpty(t, result.Transaction.Approvals) diff --git a/tests/sse/events_parsing_test.go b/tests/sse/events_parsing_test.go index b4cb771..579a50a 100644 --- a/tests/sse/events_parsing_test.go +++ b/tests/sse/events_parsing_test.go @@ -204,8 +204,8 @@ func Test_RawEvent_ParseAsTransactionAcceptedEvent(t *testing.T) { } require.NotEmpty(t, res.TransactionAcceptedPayload.Transaction) - require.NotEmpty(t, res.TransactionAcceptedPayload.Transaction.TransactionHeader) - require.NotEmpty(t, res.TransactionAcceptedPayload.Transaction.TransactionBody) + require.NotEmpty(t, res.TransactionAcceptedPayload.Transaction.Header) + require.NotEmpty(t, res.TransactionAcceptedPayload.Transaction.Body) }) } } diff --git a/types/transaction.go b/types/transaction.go index fdd5cc8..be6da28 100644 --- a/types/transaction.go +++ b/types/transaction.go @@ -38,13 +38,13 @@ const ( ) type Transaction struct { - // Hex-encoded TransactionV1 hash - TransactionHash key.Hash `json:"hash"` - // The header portion of a TransactionV1 - TransactionHeader TransactionHeader `json:"header"` - // Body of a `TransactionV1` - TransactionBody TransactionBody `json:"body"` - // List of signers and signatures for this `deploy` + // Hex-encoded Transaction hash + Hash key.Hash `json:"hash"` + // The header portion of a Transaction + Header TransactionHeader `json:"header"` + // Body of a `Transaction` + Body TransactionBody `json:"body"` + // List of signers and signatures for this Transaction Approvals []Approval `json:"approvals"` // source DeployV1, nil if constructed from TransactionV1 @@ -87,15 +87,15 @@ func (t *Transaction) GetTransactionV1() *TransactionV1 { func NewTransactionFromTransactionV1(v1 TransactionV1) Transaction { return Transaction{ - TransactionHash: v1.Hash, - TransactionHeader: TransactionHeader{ + Hash: v1.Hash, + Header: TransactionHeader{ ChainName: v1.Header.ChainName, Timestamp: v1.Header.Timestamp, TTL: v1.Header.TTL, InitiatorAddr: v1.Header.InitiatorAddr, PricingMode: v1.Header.PricingMode, }, - TransactionBody: TransactionBody{ + Body: TransactionBody{ Args: v1.Body.Args, Target: v1.Body.Target, EntryPoint: v1.Body.TransactionEntryPoint, @@ -148,8 +148,8 @@ func NewTransactionFromDeploy(deploy Deploy) Transaction { // Use StandardPayment as true only for payments without explicit `payment amount` var standardPayment = paymentAmount == 0 && deploy.Payment.ModuleBytes == nil return Transaction{ - TransactionHash: deploy.Hash, - TransactionHeader: TransactionHeader{ + Hash: deploy.Hash, + Header: TransactionHeader{ ChainName: deploy.Header.ChainName, Timestamp: deploy.Header.Timestamp, TTL: deploy.Header.TTL, @@ -164,7 +164,7 @@ func NewTransactionFromDeploy(deploy Deploy) Transaction { }, }, }, - TransactionBody: TransactionBody{ + Body: TransactionBody{ Args: deploy.Session.Args(), Target: NewTransactionTargetFromSession(deploy.Session), EntryPoint: transactionEntryPoint,