From 483b6d5c3421a877586a76ef36dd3842e5ebacfe Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 7 Sep 2023 17:07:35 +0300 Subject: [PATCH 01/55] [refactor] #3875: Fix authentication/authorization docstring (#3876) Signed-off-by: 6r1d --- client/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/client.rs b/client/src/client.rs index 492fbea2d50..46f0b6acd5f 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -415,7 +415,7 @@ impl Client { /// Constructor for client from configuration and headers /// - /// *Authentication* header will be added, if `login` and `password` fields are presented + /// *Authorization* header will be added, if `login` and `password` fields are presented /// /// # Errors /// If configuration isn't valid (e.g public/private keys don't match) From 3ffa79994292b6bea118f2cd56522b44aacb7229 Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Wed, 6 Sep 2023 13:58:50 +0300 Subject: [PATCH 02/55] [feature] #3868: Add iroha_swarm disclaimer header Signed-off-by: Daniil Polyakov --- Cargo.lock | 1 - docker-compose.dev.local.yml | 3 +++ docker-compose.dev.single.yml | 3 +++ docker-compose.dev.yml | 3 +++ scripts/check.sh | 2 +- tools/swarm/src/cli.rs | 5 +++++ tools/swarm/src/compose.rs | 29 +++++++++++++++++++++-------- tools/swarm/src/main.rs | 5 ++++- 8 files changed, 40 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53d938da852..fa3ed716021 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3341,7 +3341,6 @@ dependencies = [ "derive_more", "displaydoc", "fixnum", - "hex", "iroha_ffi", "iroha_macro", "iroha_primitives_derive", diff --git a/docker-compose.dev.local.yml b/docker-compose.dev.local.yml index 8e0fe8d562e..622a526966d 100644 --- a/docker-compose.dev.local.yml +++ b/docker-compose.dev.local.yml @@ -1,3 +1,6 @@ +# This file is generated by iroha_swarm. +# Do not edit it manually. + version: '3.8' services: iroha0: diff --git a/docker-compose.dev.single.yml b/docker-compose.dev.single.yml index ed47d5d35bc..70e045ced3f 100644 --- a/docker-compose.dev.single.yml +++ b/docker-compose.dev.single.yml @@ -1,3 +1,6 @@ +# This file is generated by iroha_swarm. +# Do not edit it manually. + version: '3.8' services: iroha0: diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index e96423a2864..b02503e45bc 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,3 +1,6 @@ +# This file is generated by iroha_swarm. +# Do not edit it manually. + version: '3.8' services: iroha0: diff --git a/scripts/check.sh b/scripts/check.sh index 74dafbf2b88..3e2a833e998 100755 --- a/scripts/check.sh +++ b/scripts/check.sh @@ -39,7 +39,7 @@ case $1 in eval "$full_cmd" diff "$temp_file" "$target" || { - echo "Please re-generate \`$target\` with \`$full_cmd\`" + echo "Please re-generate \`$target\` with \`$cmd_base --outfile $target\`" exit 1 } } diff --git a/tools/swarm/src/cli.rs b/tools/swarm/src/cli.rs index ffe08c3fe79..eb7f45e9371 100644 --- a/tools/swarm/src/cli.rs +++ b/tools/swarm/src/cli.rs @@ -20,6 +20,11 @@ pub struct Cli { /// overwrite the file anyway, pass `--force` flag. #[arg(long, short)] pub outfile: PathBuf, + /// Disable banner in the file saying that the file is generated. + /// + /// It includes all passed arguments in order to help with reproducibility. + #[arg(long)] + pub no_banner: bool, /// Path to a directory with Iroha configuration. It will be mapped as volume for containers. /// /// The directory should contain `config.json` and `genesis.json`. diff --git a/tools/swarm/src/compose.rs b/tools/swarm/src/compose.rs index 264e393d21e..697658750ac 100644 --- a/tools/swarm/src/compose.rs +++ b/tools/swarm/src/compose.rs @@ -39,13 +39,26 @@ impl DockerCompose { } } - pub fn write_file(&self, path: &PathBuf) -> Result<(), color_eyre::Report> { + pub fn write_file( + &self, + path: &PathBuf, + banner_enabled: bool, + ) -> Result<(), color_eyre::Report> { + let mut file = File::create(path) + .wrap_err_with(|| eyre!("Failed to create file {}", path.display()))?; + + if banner_enabled { + file.write_all( + b"# This file is generated by iroha_swarm.\n\ + # Do not edit it manually.\n\n", + ) + .wrap_err_with(|| eyre!("Failed to write banner into {}", path.display()))?; + } + let yaml = serde_yaml::to_string(self).wrap_err("Failed to serialise YAML")?; - File::create(path) - .wrap_err_with(|| eyre!("Failed to create file {}", path.display()))? - .write_all(yaml.as_bytes()) - .wrap_err_with(|| eyre!("Failed to write YAML content into {}", path.display()))?; - Ok(()) + file.write_all(yaml.as_bytes()) + .wrap_err_with(|| eyre!("Failed to write YAML content into {}", path.display())) + .map_err(Into::into) } } @@ -331,12 +344,12 @@ impl DockerComposeBuilder<'_> { Ok(compose) } - pub(crate) fn build_and_write(&self) -> color_eyre::Result<()> { + pub(crate) fn build_and_write(&self, banner_enabled: bool) -> color_eyre::Result<()> { let target_file = self.target_file; let compose = self .build() .wrap_err("Failed to build a docker compose file")?; - compose.write_file(&target_file.path) + compose.write_file(&target_file.path, banner_enabled) } } diff --git a/tools/swarm/src/main.rs b/tools/swarm/src/main.rs index 2f3d832e7c3..bcd4a2b297e 100644 --- a/tools/swarm/src/main.rs +++ b/tools/swarm/src/main.rs @@ -17,6 +17,7 @@ fn main() -> Result<()> { peers, seed, force, + no_banner, source: image_source, outfile: target_file_raw, config_dir: config_dir_raw, @@ -41,6 +42,8 @@ fn main() -> Result<()> { } } + let banner_enabled = !no_banner; + compose::DockerComposeBuilder { target_file: &target_file, config_dir: &config_dir, @@ -48,7 +51,7 @@ fn main() -> Result<()> { peers, seed, } - .build_and_write()?; + .build_and_write(banner_enabled)?; ui::log_file_mode_complete(&target_file, &target_file_raw); From c6805437673ccad844e395d7ef0b5ae950edcf10 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Wed, 6 Sep 2023 09:12:39 +0300 Subject: [PATCH 03/55] [refactor] #3526: Allow only a fixed set of signature verification conditions Signed-off-by: Nikita Strygin --- .../integration/multisignature_transaction.rs | 17 +-- client_cli/src/main.rs | 5 +- configs/peer/validator.wasm | Bin 504672 -> 504170 bytes core/src/queue.rs | 101 ++---------------- data_model/src/account.rs | 93 +++++++++------- data_model/src/lib.rs | 5 +- docs/source/references/schema.json | 18 +++- primitives/src/const_vec.rs | 8 ++ primitives/src/lib.rs | 1 + 9 files changed, 98 insertions(+), 150 deletions(-) diff --git a/client/tests/integration/multisignature_transaction.rs b/client/tests/integration/multisignature_transaction.rs index cb2abe8ad8a..2aba6abf4d7 100644 --- a/client/tests/integration/multisignature_transaction.rs +++ b/client/tests/integration/multisignature_transaction.rs @@ -7,10 +7,8 @@ use iroha_client::client::{self, Client, QueryResult}; use iroha_config::client::Configuration as ClientConfiguration; use iroha_crypto::KeyPair; use iroha_data_model::{ - account::TRANSACTION_SIGNATORIES_VALUE, parameter::{default::MAX_TRANSACTIONS_IN_BLOCK, ParametersBuilder}, prelude::*, - val_vec, }; use test_network::*; @@ -35,15 +33,9 @@ fn multisignature_transactions_should_wait_for_all_signatures() -> Result<()> { let asset_definition_id = AssetDefinitionId::from_str("camomile#wonderland")?; let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); let set_signature_condition = MintBox::new( - SignatureCheckCondition::new(EvaluatesTo::new_unchecked(ContainsAll::new( - EvaluatesTo::new_unchecked(ContextValue::new(Name::from_str( - TRANSACTION_SIGNATORIES_VALUE, - )?)), - val_vec![ - alice_key_pair.public_key().clone(), - key_pair_2.public_key().clone(), - ], - ))), + SignatureCheckCondition::AllAccountSignaturesAnd( + vec![key_pair_2.public_key().clone()].into(), + ), IdBox::AccountId(alice_id.clone()), ); @@ -84,7 +76,8 @@ fn multisignature_transactions_should_wait_for_all_signatures() -> Result<()> { .collect::>>()?; assert_eq!( assets.len(), - 2 // Alice has roses and cabbage from Genesis + 2, // Alice has roses and cabbage from Genesis, but doesn't yet have camomile + "Multisignature transaction was committed before all required signatures were added" ); let (public_key2, private_key2) = key_pair_2.into(); client_configuration.public_key = public_key2; diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index b1ec7516d13..f4c732562ea 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -519,8 +519,9 @@ mod account { let deser_err_msg = format!("Failed to deserialize signature condition from file {}", &s); let content = fs::read_to_string(s).wrap_err(err_msg)?; - let condition: EvaluatesTo = json5::from_str(&content).wrap_err(deser_err_msg)?; - Ok(Self(SignatureCheckCondition::new(condition))) + let condition: SignatureCheckCondition = + json5::from_str(&content).wrap_err(deser_err_msg)?; + Ok(Self(condition)) } } diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index 78b3a6380724bbd556aef3e0907e805a5a4b52e6..f19d200f2e41af9b9895abf2d7945ac1b8173257 100644 GIT binary patch delta 165041 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≀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

ZbT)eI&k% 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 a*BQXVQ(95-J$pOKGudTxbKbvF-hTr24MlSR delta 165000 zcmeFad3+Q_^FO}bGrKdpn`1%}awof+011cO0R@CX33veFjiBPAK5D=NNcNINMn- zIIp%2Ila~iXC8MttPEF2>t>gmDOO8YrZv^2S&zE5*QdOyU3sD)^k)s!Hux4Q3l*or z97(PWCCJROvMPr+=rCV>d5yd-vaZ#euu7{;FXST?YnYy8HRfK`Fg34fh0rd z8~VzizDj>ne@lN`|4Lt@|ERBWzv=!}sd7KAeyW^MhN(xDkJ(XnjEz%%)+Q)InW$_~ z-d8?QwkTVb50$Txy4bZ>eL+90f2Y0X{!#lv`$>CBU!pH^@6e9w&#GT*$MvtYAN0N2 zXnmyqp=!Cuy2tC|bW7i=KJOOp;3jpRdye~Yy-eT1o^n6o9-&Xwr|2)~Q{0o?W89PV z=kz)HY<-6N759to@$M(}E$TDwQSOu4FM5@}T3@2Qt5)i3^^N)l?J;$~{*RwM>-BZ| zclz(j9&MZctiDD6U8{8es=wu4>3+k#!oA#mLO-gV(w^2o(l)9~+`$U>d+JI3BX&%G z-Tj=h)cqnmq%Cv*rXSM|YrFMb`aAkk{dN5t{agKO{d@g@{sp2OnzmS5q%G7IXs>GX zwRzfHZH_iOsLj%5YBRLy+AG@2+B9vdHbr|$TdaPp{;V%ie|G<@ZPh>2HtV11+x1WN zN%{``?=NaQ_0RQB^pEuq^$+y-^-cPF`UZWH_NsfB`?P*aU#y?de$b9<`?c?tGWQw% zcl{S_k6xkg)n8X%(-*rJx)-<)Y6rAg?rH9kLHFbC3GPYm`RR zeSyAEpRd2F&(-JYKk4slbJQ>Ox#~CCm)dS^r}mlliFQ&Mqra$6)Yoe>^qKlA`t+c_ zNqbrUMmggCK>JzSqW$3h(fyPAd-qZILeCP&1NdDpYfGuQLFXNu=-&zqk4o)ex4-pSqxuaH4Z+o*&tcl>rG}`u zJ)u8l)2z+)18ll=tbS)Ut)fNRLdIUH z*puFz;f;}5fH!S3JK@cPnKS84W_AOfFELHzrM^6%DhQ*VjRZXSd=mHHa__d`_Olvr zCy)?@`!4t9dJ^AyBqOVxy`q2K7rg!qZzig6Oe@9j2ybaXGs~GV!|EN#VKc0I1N{se zV41tr7kbsJA-(!Ja9N`LYD5z8stGdn%0JZBPAgYJ_#`%2#4@ckp!&GkE`)JAFE!Z^ zpGpbVeFZ}r*f|%WAjK^AmYO3#hc`2h5sS-^%FGskbT;T1up#$@7tAaSp|eZeqm|n9 z-`?QU6dQ~vmsPW0*whbdcwLD4a%YJ8iY*No0nuukb!=8oWtwz`rN*_Qh%;5#i#jP zsKc|(8v|^4^EUWB(!7Apw31ugfct?hy4K`r#mW}<5YAn#a^i>(hnaSf!x49>WfXR? z#DYY}=E)Y@Ke~)cG>nuBF9Vrd4z+K15Y$+5Q3i zzTDno<0^_TbaFg&?BK`mEgcrhMr3Fwlx(gChbwYA!rGW&`8yRB&+rBebGxI|SI_6d z%R!}}43|(I-hus`L@f+4l!6lA<~kDLV5jSV;Nwmm@mufWGW=Q>7q$U1mqeC?My-Ji zoj-&OJhV~TsE%G-jO-0Nx5n>Ho#}pT=k93m&pKbhs!9BMr!9X{;-{%~NPJ(jkvFCt ztWhSlj%=@rz2+`RVntQS24X=~NxGHLtzpIb9;29oCbkY=($RYE@{^HQ4Xlk<#5?gO zj$3C+9<};ic}263D4>fd<_SlXC?C7XF@jUw?CvM~W5q{TKEhl!HP*GgE(T_+*AaHq zdaU={`v{Z6Y)^=eMG?V3DGhgK>Y`FJDx@A2v&+C3@xm)A(}DCdURvPrZb)Tu!F&gh z4Gg#n9He-gIUE7a$8hN`lD<+?M3?7TF868H!UyxL@2MuhclfkdjI%(9H}#P~S*Np%jBs4C~0%1?dwhG06+X z#=C<6#pER=@dnCmd`+8vGDl)GM+ip(rKp5M4V4ogn=+nI#!*UmqGzw`YYfB9?j=Ap65O{v}>u~jhfR{i)X+{2&z~qje?q$d0i2BeCc(&*hwq@ z`dd>@ux|17sbY$mP5mz$mA58b|2PvBnKz^|v_y*=yCuDdx+cVcyl6dnV>z2_rS&bu zZyajJoqm+!huU?S9ZUTTmz{W}+2}Tfp@J@g?ufUz-0gF9b+l6kK*PI>d3#)xV%`Q9 zUd&tAAWiAXbaW2@ywC`h5KBE+z2?jp*3AnFp%Di z67_&ai4HT4hSxZfsCb9hbfAf~>J3`ZFQ3h_di1+GS?lfRR5$d-0*8-#e{wQ0_-kjn z=<=vDDJ?bL!MLvLiW={9X>Q%)#Y3EKDgEyXe!`?YqnMSEyH%09HzRk`B6n}tcc@4) zh(yo&l;PU6)Ywkf_NB&WbOpj4bVXActwUYL_y-b@;qy?2oy^xzLiVsTwhqC65h;N( z5GKpGIj!DXl*~+CB4ytwHL9!&Z*Em@msB-qeTg2)+pPcGoar@s$WrxEW4AcI)z#ML zWn6I*1JUxv9*N7?YnMbRTdnw8((jQRMlb%7d1ZFoer3Y|(LSPkKEqIIe9e3ey#mjR zq`(>9(7R>w-M5i~nIB=X&AiAgH1Op;OOEBVK}y)Tz`sBb+IehngUqi{3-g{vi%1 z)@m?KNh_f7h>A!-P+HZ1!Z23u-@*)o8a^jTEE-a|VJM=H6mIM@NmJ~ztHv{lW9)mC z%Dns>4H;XgQX>;Oel;Z29YRR0(|-#v%ktfx%l2BGZy&%uu%_PLl#R4D-`=4i4dUFS zX##$gSlgPLvtg@qC@f=(b-^7zjQzduXd%Utn|q)vWj1MyTh<-<9i*8-!$4YhbWKiO z{IG{C0B#nR8sB-mX1X6#b0~?ftQ}f`n`rI=T&7#c@5o?FE$^M(Jwy-lsm5|{^}q84 ze#j#_PiEJ%Lssv<=lKtLq+G{^238~dEQeJv?2t9)?`f3h;AB=zSN}^aj~#mMuI^0; zuQYh@i#`>ZeUJ!)*TFz1j)k2U13JJHFu-*tball8pkGLRtdX~p(g@7*(}(B@i~ zfyl5vg3PY#PRUBl&*Y@!MGP}DtW{7JGps$Oxqdt2I&^AIMbeB)T2XQ;B8}6$f!Ait zP=Sl2z#zK_gJ{sy%_^5M-Wok{GJDZ#Jm|`V`S3KsE`kZ>W5!R`@IgI{*+_x_`V{2k zL(SRN&OuqtrvQ&nDdcewe42@G1Rm}7Xsqh4yB8o$P2D#jEq@-)2nGWN6ez`cKu zpW*fEz-3Qt#Dbn`Bg=DN9Gf8y^i&H`pDy>^4qB$)w+Yjf!S`R^9yOunJ?^rN+hssZ zHIf3>qSTn=^l@KGJEa9KU^)$@s%=D{xj&1QTUie@0n+Xd6thXzqYsP*Qt#kQ{5Bj+ zh4mgRr=5cfaR1!k)^f_je93Z3U~L_ohU5c-3sPrF@ljyL@S&yV30VG482o`DE%5%D zA+td5$szZ-X6A7%=(6sAu!Fej6BaLg3tUZDy47r0dT=diX=#?qp_iMBI2k@6tx=@R z=IzkMp(oKjq~QgzJ56~wnX(Y-FbGs<49GCj$chA^5xo|)soqwxnc5(a`bT+EtUg1N zS+a<0>B{d&`qtEJN>~wBiB_mwNl1Xi0@VIa)WS|x%z}{c>Btagh`l{{hV{YFR*7e5 zl4#cs!|r32@sHHTZX~UhtnlM)A)n3tn6nr0`P}cJ>q_pAGZjCa##ZltWZw8Vx8YGF zI)58t%X%L0b}hr-1CRUT3B_7YsO+qCUBY2^Mo@-|@Xqo(O%-@CRB>~OFn7A@TU-9& z4n9`11fSA@Z9(EWN~%e0xFjMvN=YH#!ZCH1B|1@JOe2F0!wGei#-OaXO{D1pG=|0) zrj-G@kgw-(4V-69O)ZSXo)5sXlI^fkN*R>t6I5Yn8?dw~So$PAZj+C&ww|J=Xp_;? z9{G+euQsOcSCC?e)1SN2f_jKY2{Elvq?9w_eoPyiTkPg0<8~h}E#eM8s(9{}r}RDC zulW+tTr`^s6NAB{1P|rmN??W=UG)Tcgr_XgORkaU+>h%4N$IDT{2GLbvsMBypyjgelp&>EQjTWhs>l zLe`MxE7U(Q$lxtFB5S`yGHje(dvk=e!qUMsy9lBxY-2zS+9{48l8(uwsZnOo{2l4g z0?P$C3{1oDOvWg zJEcgVt>9BIo+0rKbvtYHqgioMo?FPy>9Hyv4K(t!QOoFK<`6bG~ zcJ;A(2IEqnC27fu49=zjTAh|zmg$0F!p(f^wz9NfmYIZPOcNwu(3w=*$)NSnusr4^ zgDQY6O6Iex^-A_Q2OB{Mrc%j$Y4q&gGs7SP$}&yOfAO}qD`{v!aHC* zM~~a(BOC&TMUPeTk+cUyM^+t^k?<72Af%W(+Ko!a8jv;v))3&tFklh^N*6`FkZcw@ zSh0h}xvUnCwqR&MtC7wSm)0n!vE; zd>D@$Nb{BY;%FKtU8!#S4x@?3zJrkqk6nLy-5xDmr08}!`Qp6xE&1=H?~VLMzIdPW z)#3IFIj=Ip%ECcDKbtFI72z=5Al6#>SZ7RCPCfQ_EG*pq_$6$-HS6&Lw#M4@_)PYp z_26)eeN>@6(S)&&tkzGyf*HW4PYwdm%BQldTc7e7GiU-r{z6*5QH+_^n5UY`*ZtTy zG3OOmu2npu6G1s7l*@;C6rdg-aS@v-u9^-zblZp(z&d8+$K)c1HEoqX{Z%4n10hoe z?RSP*{YSmPHdOpF3Uq9!$bV)SWA9lrp1qVEu?{|aJ=wEhcUv2gSH!C#gA*yb-V^2p>+Dn z(FUe|$Y)r{Rim6M9?M}m(T>s->S$Bb*DHAC{-#C&i--bx5w17a0HKY z%F3OX?>lHCQYBbnDQ3tLJAlYFZ@gpOHt~6sesW?LWgSbjjz5=d^?Cm9MY{+M^d>WQ zxu`zO)FcK~>PO;%R1L;DYtQq!$baVf%(Uj%jA0DKau_$yoKXgw&fZycV_on<5j$wz z_(D<3bs_(u0WMR1BErVA7UiK&pu9Ciu$*f$;|1%r7n&wdRZMt>i3&1`N$4h9$6vS_ zl6L8fdkt`vrg4Nu@i{?I+euBFQx&iGiHbWX1=Nc|RH13AQ8hRKdramGun>p}@vlbs zs;P6Y-pH6DSG{=`Q}a0pREeo$yj{n^SW1JJKJ+$%DEziW4WZz01X-h|6}VHtTG+K% z8o2f4Z08B)^eNV7(*i-McjelJH(p9O21~`5%Du0L=`hu^sc=WBfY{ZfBK)=*6UHP)78f|&l0Tg`sn)s>Is#11;Qfw!>^~=kbw;NB(7}7y0#R)$K zCB?_dHViNRP*NP)6hoU-;^VD{U&)4M8UM;X!5?ksZ!9Q@UIY|bUG^eQEQr(A_pwQ8 zxEsqxm1MwFuzPkiiIbTS7CT6p^`Gf&^Tu;YZnVsZ1X5ogZ*86an6id>g{eA|F-a<& z(S{ungCBDG#FPO}t&W9+z~2{zQ5(y{6*Xq4q2i30_8qtu<5{0&Ct|=hW}~giwQkIz z8yYs}(hUumA*Z(>ECBg)kkf^1MMD|Im=AIq(dPM zfzD(sVb-8I8CJsV6!*rD07G_|)nxXi=v#Z|q*%jeU)XXX(u*9@&>`c_T!-gEhohJj z3DB5t#lDA&tI|3$`)2mJb>*B4*Io}g^t0B$IgRySiJoF$pFHOhiM^TP?!c_1xjAfu z)qHMSq}@5ULCBkmISj;&mbPeXgZ0wfEVkTQG50dvcBvWfRe0wOV9DfXvKJgkte^p4 zqdYplaeNh4-ff=><7!gs->&^ zGbFrX`M*lBzIgpV?3guXK~uo)`RXG4?tP~bQt}pFj(he+2CESM)~unT8q2J$`!aK? zwxeDi^w4hcs!xlTMvfewF>w53EvjtGwpy8s?qY9?yf*A!Jp?}6+Pf~JUIqC{oV17q zuLxN;N5orgSf=7KPFtN9_k_}XX7TKlSuP*our;EaPwh4YC8)+MtIzf{&~w{sIqZNH zd~Hgq4FmwM4dswfXI3<0`>oq5{%N2nr#&vof|d(x-)oZfC5=dsCOB2=LEB((Fb#56 zJB+0Sxx<@luxtO0zoy8A*tM>1 zcFnITU1dA}((Kw$H@ilk#jY>@((Kw;H@kLL*Z-}YyZ)-&5{uh0fBgH{bzu*e3Wm$( zKhzj54@cQGOB`#@S~rU;X76Wj*^_!1yTA{~%BvzsqX5(Ql19 za2dp<$;pPWTTUHl>KYv$68%>1gH5r<`R{}MUHkS)j_o?Qh(zm9Gr+Do)B(SH-^sPk zoYuK<%<>=ZjfBC6Gi_5W2kBnOnD_S_cR8|~I%Ldh`Fk>Z$vS%YW;i~2em8@y71R7| znH~a|Ep7|2%yZaZ*6t&@5USsg^oBt7I{FhCUs#92CZZVQOT5ZhI!L(fwM?;xvF;G5 zy;ztf8w{{DZLnvK_kj(z`}oS*WXt;W`>K(?{_d>FSWtmk7Hx8&eonsIy2 zhjA;H{Yg6ptm?9FcW%b!Iq4!`H zyC!`?OcPi3VDRsX;1w)SjO@WC0zv2NSP>9hc^SJHmr<9ohDiM2I(8YJPF+UR64CN1 z)(D6?UCuJIw|tBVky}o>amFQ{+{`V=wGLnN3Q>MNOJzI6$jez%wni+yoOS3Hf}c%} zX{?HJ(@Cc~(|8>*%5JSm!bJi^cz9o!Mz|{9mko2WgUa85mmm!P*&4_Q{o>53$q! zO^!uxoILD;!>x33%J{yH(%-t7Wq2n^-`Dw;j*ffVE$Fa6{sCI?z#Yta{*?mSRsC_m z;T!Qqf0kpMf`T=_qn%~YEw~daA7MVx_-2+A|8pG$2XAA!f2vGbl@oPflpI?5zv9qu zb)Y?S%m0SZQ*~gJgdTnm9rL^eiG5k={~NoJ8J}(ex4(&S`y0{WKkP#B!;Rqf?{ydX zC%A2^pDqK%u^}uqei%lBXrJ)k$x6{Du+W=9doO7#X@#g7#0p)9CF{kJL9E0(%|m-! zZ^Y(N#oF?!Uktbx`^2^#BV80)0Inw{-pg*4u5G!AQzDx157rJn?WX%!0m=y8$GWG> zu~2TNOD*O%f|78VyY6ERFaRIFi)H4N0dr(|SVbR;t`I}{b-15h$fk>b+|T~b-W5CV zXSe8~46}vre^~uQS%!5O!hweow#^KBe@! z=stwq9*?r+)*mn#Dy4D=iu_W1GLUto@s{1mlH(sgPyVlz)^i>F-*o)H{69bb9~i>2 z2N-3D}MyPZGn%Ua5L-XPm}k+Fe(G3yo)h`$mj;gypyod;lGD1e&+< z^+(u4%)M$Wp1;MjX!9R7k1Z9e$FQ{YN^F*~H+W#j7HvR+=ETOMN|E>|s~?Pc8z+ww zhTcXqdF5gKvywe=a$l^CD+=wF2lmf`*5y{NvywG2{ZST3UmDHtj5#&BRO|wYsE5{- z=ZW3VG7q$CUXa!AioN9FI^hmz!L4N>E>h)U-pkE&_Ir7T*#@o@7g*4tOPP1=_;TJ- zyd7lz&>o~Mat{*r=*vTiVk_tAIO>;F#_E?eXOnmU`-@6oSE1Anj5cMtXkIlDo3vd+ z%s_ZwG@UV&CsDbXNAIDQBM~1eCzr9?8LGt|W2w{t*kIQ^w3{x%A(>`xr>mY8M?3q& zZ5Ybyt=@7nucvym$uxKMHlwtJcs;ho#4C@nMyY5I3Ga+)wWVTOIRc9<6+b-23NE3| z{H9S7F9(wlHFjEen>XiZ5s5O|93potON*}zw;Eb-sd)5p)-U+E2eUmzZdwl?%*5_q zY$%&AuQ(>Y zVI-0;A4qd@SCBsn;;K~HZ+*r8?jS)?rz~py}D0zZC zlQ+i0v2PTIIw<-BCfLE|xxyl>|CRzViUr+4*@ zm}Pv1U8X*Lma)SrCO-*7W~5m2Bqk7L;=q%v3y5m`6brDGqUTerQ$1{JMmas`=SpLr z$Kl;5#%^{E6~+kmV;sUO$0Mn5=TgAIIU74D54P`mc#(}zMKsCbv~ zznJZ?3~ed*?}j(LibZ?SM8+FT?B2t3#A6;;nk=@_7AoP7ixu8c%vT?~3@NAqf?AR5 z0cC*aXP7WYvF5=!sx5xy&Vd01@~4;|$|DUC0aVN#G69>@nWGr80)dkf`5tXZ#!hY= zJHeS3B`lPR`Mx|3rkJ1DX)=pa#MUeAlqzP|8i$_|`DeTuC}ChTv>u5lE+nGZ+*t%b zl2Jx7Di5iUY-6{v&l&0#AflMhr+uKbxpb%aY!vH+_D>tl@}y8A=nb~kDkhGd$sL&D z^3kkB>NKLdTrEXN4Gb?+N3#@4g+)oO84CIUd00D|H4Fuwvat}XJZ(M^NVyT`r}OMj z2m}nn5oXc&8Rmx<>dI%>6G2m2Eoc90nAS(tv$NVkB!lA`5Ih^K- zVRAUlIU&e$Q^PD#(m)?4m2=YhTRkP`n!e&WmhapC7q< zHFCGWz5{VGJdFe1=DcyNsK-ZC-hRwYLosjOBg^T8qm*2`^6Z-NB0=l{#726BE#MLq zh$QG}R_ZlcdmD=Kajc+2UvDZp2JO*Db?mx;_SP~r9QFp$bQ~0e$xbC$6m9Gf$HuYN znUWkTjK~2Swh=I*1sScylrxH-AK4%VjAz~0uVUtSmdkz z?NhabXgPsh&R!J%p1|7odLGs}1uT*m>;*?3kP46v6Dy@SKo-sZqRSfxR2W`-INZa$ zo4p9cz{qAO!zmMtD8?z#zh)61`@2u$FfTUNfhbSMgpmx0Y9NUNf(jS6;8_i+zPYV*34RpL15#?KK0jzyJy} zNcWog=Y9ns2*C!idLo=WGlc(nRz}?AaXv4NV^JI-K!%O;d0tbAeHEAMMGS@**ti_8 z>8zHJ?M0A*ScojI>8_TL=`}reLNL^-8D7&{4J6%b(r6j2R+`t0ua;2Xi{ra75HUoj zddFlQN38;m{$;^dU z+ONX(hsb2d0%K@`c*W#~7KKp7CP?v!O^`AXlMqv&l!=&E(5_}f!WOAN*1XI{)$rqV zM#FQ<5iNr?s^yj9H4AHbMYF+3uSFC`oaJ+f>`ANz+FqLLD zdzd|WfE^&GEB1k97@~@?S={v!jHma-$d_P(e;_`7iCus>gE|FPt9?=iXHD%eK2U1% z^zcPfq|tTb6!;ORi?S)~<~*{^R1?Oau?Cu|kUu~_Lyf*hVsDG@P{xlN6cx8W=kWfH=LTKb38^nD$ijTAp_q*m)Zx= zjhP%}!$4OtBlk%$#^F^^4u!gjiLpIh864O7JzXutQ^#HR_@@&*%^pLUh@T2#56Sc2 zsPHCnY#Qrz&1e~NFiQEksH%l19E6VMi{XkG`!Y+Bx~4W>;SlpVbJ~@+s~nA%Ww!xM z#KO6VC3LdJ(fKl7<+!nW?(}KhU zVq}ON{G9BVG=t62w_zF!(R*L?oXJ|FYYv-(4tTz(I{x=xvX_7yLf|&H+UENN8}_WC=SLE3y&Go zof3&=sz5@|V)|U^iP$ig`P?B=Fp2zrE)>)ZkvWg$OWO&tH0WTuIYyxn2=iED_Oy6- z9;UfZi$(L;B+nSEk2Ggxs+lUTpU*AOq{I8_brc8~O@tlUMezy$aBx7^H zg(F$LZvk5717R%0;?Xyv*uL~%$QqVPMZ9`-C^whw<5Y!WBUA>dY&!UG;SIJ^|i z*>>GbwS&%qYv@A~0u?9za`SO2G4$lHqtg=hM&Rt>g$&`9D=%Hdrn9bF(fJUK)2t^K zhUH)&&2-5^l4Mf44uin#m$<5?&uA2qa$}ch{2Er5)`-ckK?ZkGaL4-MgV)%2_J(Nr zgsY_JX^#XYHDKS7f{EOP-Xd+Z*jB+_;nOuyR>>}=YgHwNoR>8*U?~J-x>o9UC|#r- zjj-I)MdIr$;92V!RBA4POX5}W=2Di%R*T)sAvdc9t7LhVlV4{(#unJG*4VGsRN_?+ zCUz}nS5%H$##%A{787qRW%b#cHpH7UGdm+N5i1bAR$%#VnLyBk&bX{!!2+0zA6mf* zFo&;35!}^pu=FBzC>lfB`p_e|8hx>_r}z-V)JMSupkUCj7>C~ycf0{g->Mw*1|}b@ z$}YRgF1xevtz!Nz@6rYwgF+clWIQ>8Anin0pKy9}Xsqlq5T}H3#l(i@JaV#w$WEtYVdv6_!@P8jA=#Wp-dU1{lWvM=KgN_A!n!5(q>HrLhs zAQMTyD)q(Sw^*};!$3(QA&L4<%tuX2#wiqvK&-4{8El^Tq>6Ruzf?xLY7O zx5y?3KDe?0UrK$GeULu_n4{H7jxA$hY@rYU!I1&CQlP zT&3i#;8OCE5R5EV^6=Vtou%p7kUWU(v$k}NvDnDFCti5n7M1)$2#zI6pLBw#PTSh}1HzAY* zDEh8vMZIQu0~qLh%0L9mfScUW9nI?Kk>xEw{U}0p9Hbfmwz!8*XG@e9IpVx62?$F! z2;PMs1SSxDep0g)XyVG<>)9=gf4@O=eh&gMOWgV%EY|VjKkqSL#uP#sj-5i{j}?Gr z9BX5u`6n#rViWC0?4+qPs$0z$EaM#@)~$+Izd9lwQ_axYXeC6ILzWIq{DzY5g1bKy zOh#%+yf49PC#8lg1UuKINOe)FZGRbMk;nq}dz`Yzm`(ub)-?*l!FMrgBep5XK#3ka z&8H_xh!;vbN2X94;<|M#KfxCmw?x&>$olj$)R8EcIyhN)44J5;wz` zm@4}0Wfvx_bNdiDx)kB9C>p&8Zf4iADPr4Zc$7a9_1MC3x zVbrM*xgW8Sgm2DA>>sE?-Zt#goFUq8!$?~p%I&8)+psG1oY=h$7R@%1_A%=%-u@V- z*XQEc$E>|`xEhl22BfjilJSVf?)wP~lu+BrML)C`>K>9{Dc3YoR7;g|Elr4Oy#azP zR)4}Wf>J=WkTA%YMRqt}DcKMZR^&jGD@cr)No8f0h9X5sfnkuE$g_vudqU54^bT|b z60$mQ1SwOkNbH#q^}LY5Zr4`!Jai)m8SgcEUR?F6RO_0uuJP3X#DtA3xgeohn(e9# zvzEG$nFw~3Y-e|1?lf;ZdzMWT7k$Qh1zxtJk73$Q*6)%#osR5+ z*q*LzxEouP*=+IF9yXROwzb0t5$!;cJjBGktaWfs688t)#4;m<<<#El-P zZ>)Cu>ca^<$e)b{L>zj560Wcr{Pl1hj%y;Wr;wh8YZ;!Cam7--KOI-Nml5ib0{0Qt z47#X+9DfQ7#FTD6udgV(WC(pI!0XGvmq~aeG7qPuEcjSxl^#kZ5GNk}lC{LgtkMT! zBbZJT7gM1~JGdfx4yV!CO!K2dhC@7~XqaywqiBpx_~Hqc0XYRE#4}I;2n1Q0@x}KyU}L8LhiHe zA!=z2yC?=He8(~>%(*~oKqmSn1LPnZY0gx?$EW%OzCwRPUju)>9j(u%3QZN^vM0jj zAc=HCpaz@4r7)X;HOyuyoDmc@o6%5F6m?*b6I}b;LIlHS;ii@tf|0hag$Nr(RGh*B z7)YQlufTwWP=-XYLQdJD58!#|VTYSWiO2)mqL8B!Dq{T>DGy5qpcNzo2B8HMZ&(Xe zFAkP%v^0vh3=LqnEF?kp25NX}sP=*Uc6^X8e-@Q1$GpgEk{a@dQdDm84gk0vA8KdQ z!`UE^^d?GLtN_7+*y8pj0}IyCa3_^pdW>@OrAL(+6qw|+tZp@wM1By}wVOSGD2?{+ zumnPEP^bJ*Bxa)N?mz)HuM7vb3J^;qZJf^oZPF0hBmvsQ32l-OZGt%@ zL6hG|K|n=GVvtlZsZ9kT97DR9D%LTq^=O(@V86K=w?0Y-ZUr_oz)=GAC%S8dJ2|UC zY2j)hIy`}EaLmLZF`F{SFw&^Nq$dq8ut-@#T!0=oP(>)90=f(ZQlvg$M*|;(s^IBv zpi_Ykx5H`V2mMmEfeZr{;X)w+MgtnBu)6JS7&JP$wIvCNVv1~NcYgu3f9>Ts?Q*)% zA{1g7&_Lw^3w(xshtJtaN3;ut`U)sCr3=jPHL~x}hvRKH*had2S5Rt`8&ZTW^A-%P zzBt;aBEMYYYeIvg%Z_kb=xARoUmz+gvUMm8MHx#$&-15Xbq)))elMyABi2{nj@F+8 zk2jt&s5ove5}Ai!G@lgR53vP7iaM8Uf5`|G(d-35;gBL@!pEf43p=_aFiDY!cHvw` zB%ob5B~flIA!9n6V(+ntq$Hy-+FW5<+%}MS>M#qm#S42gMFbWpZaYL}6kj*EE2USM zMBNxKb{&RuYP^{69b1LVwMSS9E-xNo1-Mk%m#>dt7BOCA9c6dpf(-S=3rAT~MCpsC z@g|lM9xuCxoDGC4U~l4!5>Xde0lu=P zFG;mz&?zwJ7m(^x@yQ+%S3TgQH0m(0JuwQM5KsIFci@lW#E)zk+bRC_6Y8*2tp15z z?EM02!Po_J)!0?(`I+gg`ALRvEkUKiTpkh+0Y=Zb9(y zWvm2q$O?y-9F&n?h8#3L*A-dtO^^!|Z=pBAclz>{3MqoY4bhS2p5ntN7j>Gvz6b z&F#JMjOVcBl}#9L5dPMQxSsR7>dI7kkaJH2`ZtAt+UtoERcLLqoGxzgeC^M;iEMI& zul?Nn9QQ&TF;atvODh%b2|8(xbj&FRTFBWb9}hFZPXghV2Ua+$ngin8Ra|3^Dd0o+kRo^E*7K9F*le=5va; zn^3u*;`yKph&%X3vYaK_-0{}I9Wf?>j~C;v=4pX#w7ECJ_AT@jV!N3#D1c3+F0tob z9uUDq{!S*jbm{AD3ic-3@?%UTRXvZ3z3V{V&HZ@eB8(W=pg=^TCSf9EXnrh@MHA4j z)8cq)ylgev;z`XW4jO!A)<)oL=4e4X#B<=s9*W*6WtH4#tCP3|rd?N$KhTT1Bvil& zNM<2F1+n$fQXQOgcBi+aQqvbLp#%In$u#6yZO&SdI3qk}bysiYsd{{X0vWBmr9Qt6 zABL=~O5<+E`c`gC=ar0vcX%d$kM$K-W$`SwQ4GrB86f4!EItaCdfEKnw0{*;U_quP z6}FobREWXX@{Fvy$k?3C^Ej1uB$vN;VPBK^;f|!GN7dX1HmR^W!PP)K*-yYz#M=ZC z+VP#Z#XA^5QVO=K0vhxdQPPm7iuE}>rNJZ#0B$J(m}BVb@GcSG%2aA-Cq7JD%%=-{ z7P6oacT?rDY1J%~UvGsk${P|c)jRC`=@xZ07J_$ zv9f?;+nt|#LpACze)aSFoZDem^{Bizz{_M+j~4I+;NeRRcqa-pt5Oe!95Q1`<$(tL zCCU7ejremoy_Q|b@%>nFNgG}uQuWDpd}w{%Ks%Tp4F3BN~PM2H)T%gUK0JAK`Y;U0dJp=eub|Cxu`(WDu{|q z#9@Jg)|h3=3bE`0-V^9t&G~p-CN<~y##QC&=6ok3KfHv(&mI~^X&3sUmb`~}sTJ2J zv_gq*h-R($)i}ja){5Vut^#_|q7}~~fO;aeHE)BZ+{;@7a7N|-w1ym#G<(}hp+gLeh!ycAg>8+2EF|54E9!gSL?YK|4kx7i@&ZMvy*Tg_# z90rhL90D*SazZU1hLCbx69vg}7(j}#4IoUDCtrecrR3JkM3NiMBqg^d07g3=rEu^AA^x+r)5^ITw#QIzSB;+>0 zgzgv?r*!2LAUMUB@VDvU)<%o~w9h$1IXs8 z2|z@K0c2|hYeGst|kDrT^K-oc^z+3Q}4)^;ntJ6 zYqVY%K(?L@Ag;O|dgtlOp?99R9(srFq~4LRQtu4AJfwH*Bs9t2LdR8XcOSxroAd?2 z%7?o1D_QL5kx`>FiZ6Qb(*L%gl+^#bE$9>XUBRD0r#f{7e@mJWFger3<^3@INVyhw zjeGO7SiPEFqbZ?R(?yw+r(&PTi9Y<2%H_TJV^XbGLzIIZ0+EhNPB_djxDlhT(`w)q zyZXQ?oL32)@B9I}`sYAbzb3i?*Zx=HLb~z)qQr@<*Yl;YDn{JEJJf5=@FhSpJVFy_ zV^QVDH}K^w9+s;V5Lnj660!OXo?5x6FaNg`gA4lcXZY((_%`x97v|kGm-(_E?;NXc zQfoGT$Nrqw{_h#d+lp`d^DBM!`~n|f#f}1UB+HqOA7PTPR7cYs;la1FjOOeFhAcYj ziOG8#(_MMd)BH(HXvFGKd>JldpW|J`mI2%?ZuuLphlIg@m^C4FFHB>-7aM~lCV``wmAdGk2F1y2`@4?ndOR}J8~;^cT9 ztda5lQhqOzz9{8gaq$i06}XI=7=CIdPELg5VeufIjr3bz>VD%9JP8-51RyUmkjqzkrt?+|S$N0%WUjd0;SaB))q9N<-d1NEYFw zm-rKS95{rx!sVqQyqU{x3$b+w{{cy?4AZd|kMMkP`a%8_5*Gi1W9Ouup8F7QC-zJ` zSNfah0&PE?(^5WAbQHcBn36{Eq=*F%^R0EgED$?q@{zSbv=g4$(zcDC%O44&eQ7RF z5x2}aS9(>gc&-fchw$=&S2>*&MfEGIJv9&u7Q(bW^(yZpCJd8opYj-Q37D;qK_m|? zfbyFmqDjl`r&KZZah?~3N*vCoSA%LS@Rd(kT!bW*?i+}Sukpb#30~2-LN*8>(!`@r zaUDTQE?$CevF<58&nbJ2xZrinCBKv=Ubv?(W?qhdA8OQBNAM=GV@yho{);gtMRe)U zTZy8PoZN}%$ix2IhySn-lUV+5yKe{NmEHZnJ@@~oo=eRc?V)vb+8Y-Af6{3W{fYh> z@X)%gZN!Q4*Lj8$LuyUb%89h7>6NO4y8l zlU8W^Rs5RD6D#<|;iozDiEZf-bz(oYIMR=2RqAi@2K2tNc@^KlVl_y;vo%P)2yOL5 z$r?@@b)Q-z37o%%Z@OAq1mS%Ew%gvOdE!}4`+)86Oi;;fk0}&9_LEd>k&*n6PIGBP zR93vrAC@*tvv>HR3he& zOfGd83%TvH!@8Ur;8<)9sEGeDZ40#iLeYLJ9|Q_#Y=zM?Lp1%6{|z6S#|DB>J>hG% z9mKXKZ(+Jh$d+r)t~FJ$^g|5YuT~!Tkatq4PM|xzvdgC!z1XYb(e2V<|MGU;1n%GW zw}+%h6A7y^2d)1Zey&-@yV4>))>n+hCG7VaHbG8=Fe zMxCkR(AE5QF?mF>ZZo)Y*e>2jiUxHH(P$4(PX`DhYe>IJH9wcQ z0kJl&iS3DCNjQf9uCDY|xjQfh;#8!x5r=TkEXS4maP>zpyRj2%({jwBE`CQ~WFUsGwOIdcHmQwKTtLmlvcp%E3 zHV4nMl=XHgT@UfJbGE{Unx*{bP`H#f=T(jOsDQ!e#EtJORj+~TJ01wPaJTQU5xEK< z?}^A!VyXE7o(sbt4a97Bz3BWC?;n<^O?F*wKf>$BwDo53-C^0*laEAOVb_sAi(TkP zct3IKXtmbZ9FbOh)2Dh}+8>LS_RnLO^n}EIt4-v?$MNOzs6c)w@{UO&mmCkXH(UG& zm_Nq?k#ihG*88DaV@8R@S7E9X+4F}e!$@Rlt=h*NA>c4`6XIj z@d-XO+>kqMM6G|VhA7G?eA%KpqI-XhGHSuEQAE2$pWpb97-FJ0cGtx5?QcB3P}!~iBm=*+i&}oV79qp80;<>h$J5bzxBZ>h|C8nIv&-YZ z^Hgk>G@^Yb+GdElU%kj@&dAz9t^e8DeIrX7e?W;(p zSI6E&RcQE=1JfY&kFc}vZ0a9!DzQU$lzPPRu8#jTrxHk9!D&~i9Ml8MI4b(MmBu38 zrPR+uTPhg#!y`UoQ&-R4)pb_(<97DR=g5xW($%wn=u!%5l>URAy}72O*DM`Dq^oED zyLMLgpX}^!pCda$L08ZIo2KN~DE$}8-bCD>pIvvveXgE;w0>6hU+vQO>q=Tp;t}7u zdiGrRS;U{D>|JZ-L>%YpIbU<1Rq$!M-~`Xv1^-?%`=y?!z&`GQNKqu>*bXs5G>=mv zWA+(aq@MLw6WKCsxwfsqVK~=Z%?e!ajf$*0?vL<`)?Rdol=x}_8^w;u!_~206|Y2W z%<}j@!p?>ZGeL&vPZE>@qk3O>QW0;bf%{ps6X!4{1lq z+GqH}xyk%G^+oLRxzrdd@=}$5CYO7#28->~#s<2<-dJN}<-Am&V(Udhnv#Xs1C7&^ zrnuaYro34o0EOI`I>-Yx0on*Fcj+3xx@^3sTw?Io&UAc|-VnE?E1eM+a$35QocpVb zb}Gbo{e8vSSBEYA?Nmju>%`$>rtMfXYT8i4hDiYo_K;EmW{BwDTq2mMWED-OI=GAp zviL15KzrMaQz%ky-qn3>Ol2tPIngOYxdY#gB_)9V@A1$ zc2-Er4-%=W0m?7VRMLyeJRv68=xioUl<`#0QPGC4$f;TF6(xqFmQ|Tbhte{SABRJ1 zTIFf75(5=?Q-V8G8of0pf*Uv-?zf#KevY#abY2G@ADP!Ut15VP4%&)l+ci6nMwpYO zT*QRfm!&ieMq09#HaJCCX-X?kpy4V{OAy;>hFU;p=#23mY9Cp=FWwjM`3JbM@eZv3h|v0 z%^lKC+ttkR^r+zxo4Tn%Y$=m_`)go+CP&F@xR5Y=LYS*qKsGVD0$rnZ7bkO-jIN)C zS?0#6TL^_b({~Qufzh86Xo7K4cH?Ld6U}m!3$sT5w%SqJ+~Mee89g?S4Fsxvj{8hD z)Eq5_RiZSK1Q1uR&r{mrwD+@M zJT9~IlnY`AqUPxLrk&Fk-AHplmTDAAeT3S;E*qy0NUv3E6|_=~Rv`s--|E-`z&_be z(JFL}wo0@Mz;hB-L(B|$bJ0Jtm%NsC-B%7#wZQChlyc z3{OQ0@xntL*Awoz;`c^MTa2j9i-4|7OfFIi#QlXzZY|LA{kyfl2R6UREK*Wxpu}4{+)&e4D@uY z$RwlMaf8SM9XAL&88$S9ne&lo)J%C6@vxRQQy!9_I)VCpDH1fn2EF70<@)FzPaPY( zY2Ui>ftY`R(h2dZ4ql+NOMl;k!y!sBHb9_L8rUr_!2on&b7dx{zxo{v2#CeTR#oks*4%{JUS}FM{pLhZuB5nW-7LQHXr=qyEG9~FV z4-FcKyo|l=+@~Ac#W$^$Ic$U|Zv(^oD^bx#X$&)PR~zLfwoY8wR+*dbh3nj8@US8h zje&bwGy%Pb#nHBkK(x`-Thw$hrC1rmCw?Zzno6$d)lT``OZ9^|%bh80+A9OuFJfwY zr4NvQ-(I;BPd8qO#2I4kg-Ris0!LdBxEb~In(fhQIFdxIrd*_42$)V6K|!Ao|F}q@ zjS#ahQm(+|$BUE>{8zVV*+ID*k1uqv@x)0ysS*Q@c-VM8>j1f*Ard<(#d5EnlbVcT zZA#|-<`#WBq6F+#>8PahlWsAuqh!M;9hHKNU)=$m1Hc}3bZKZbFpdPmK&IqQN_S-H z*GZwRC7*Xv+ELz=iy@RJM2Cyf^6SN*iaPa}GYaR@$rgXYc*2M%xRt)yqH z1a?AcP=NVDo^H$s9GdNGF|`Y7vs`TKqIAQYBgs@+Wvrq6T#d`#O7TBmHYpMt;^OBTZh-l(M@&Ja`-DrvUt0j zlB7qN4gR&}hxgfJE-1lVYlYZTqBO5ZOGKfWEWT)0YL1^K{N0tlwp4h+Qh^zUEfq0~ zAW|yUi zCd=GoL+z^-N|w0=t6|hHzNs5*$tMJsE0kVPYAZx>FXeG``4zn||9)KT>!l1L|2{YD z&Mx}(R&q1;*Nt)dr?O!2&)#Rr}cI!r$S)I>jqo)osI2>I>8XU z(7YNN>8HA(_S;au)Ct8W9kq-6wQjHz+ib9tb%SjWVLM$n*v?~wEmwSgtkv@L5=70M-b` zx0yGbtcY`tH?kZ27y^5;R;_mAG%CngB9K*!+R`y}!~nSdPPWg&f{Px?JlgZ-(O{$8KE7ikphJ6jT96?$BuRupQde+)Yv3 zr_;L=U<$&5VWY(hIK_alHi&jwj&Kn8G7v&x;=>m>v8{EBM=%8nz;J?-v}oWKGLK2b^r1UV9POIXddRdl?pQrZ3)yy7* z365gUcy2?%Wr!e1!6|$O1(KnI*4v3O24IT$9x%XZI&j7vCm2CDD2>MfO7I&LyeRow zrjkT~(Zh*Viroywtl7S)dM?tDj$5)StT_7WxqXZ!a zDC!0TNr$QG*W(;G)h~-WCz2qrNTyfA(w#7$jYT&Rpny)x`8De1k?-ZbNLeRf=*U@=)6Bj zrw)YhJf;2wRFBIr5dgxRjZV%M@+%>~xb!e(d%Exx?|1tW{q%{XAVejhHwsL!XCz8b zS-2ug@L;as!;d3?s9-7z##aDPaDCdUmU0|WBalkc<|Huy zD+l@AByzq~WJ&R*mJSTmy8?B0`_fD4y9(IHh|pjJkJ<*{JVhf@JNfjUV4Az<5XclY z&>beZ@Qi`DHNqkns0UFk38YcjGQ1=ZO6iVgr!OrlAft?dJ#?}XZz7?>;-)td-+Vig&m>M4autUlBj>X zk{g^NW$6^RgY%r=kXvX#I1mEvVvYe>s>3q6B3h38#wye!76-YxSS|GbPMTm$Po;w1{@Qw%)6iI*}Q3C`;iGUInG$LX+A_hf`iiiLAw{}%eX9%MI>%HW| zRCU#^{aAbLwbov*eIdV1Vm`BMbQH2ZC2i=Gz5LL zMTpg)9%p59cuYHW5S=GH3jU@SMBPt-w22S#;bwCnY=-QIik$_En%U{lSY(r>u2*6n z>akdVBkj@b(!}|}!z8Yv7os@6G7gd`;{SbR9ClGWfK))Inw9zN1y7i8_oC5wM zs@$2jFV6ZukbJ?QD{vA2A0`*XX(bu5XIrAW(xf$b@my5zsdWL7E>=&uj-%)8VZHOf zZgg#$LXCnHF60B~gilHTS;wE4A~bgh{8(s#K0&WZI|%9YWjd`)+aXlb$;Ms)uXc?W)w>(wH)uzonOu`=!JAwIG>QxaP_K9~$4&7XDn@Z&pweypt&av5nP`}y zo>AC9RjcvVpjb<}vz5v88(LFJDW&S&Oay5Gp?QNW6fGWcg?cwb1O2E_SgjOLbwQcL zft57%rK;4RM=2H7^vL85Wk}I2n3hiSX$cW8_=Y4*qtmf!m9=SwpfM_A^|NNuhTW!9 ztu8LeGHI96=#&lS3R?8gVre9a1hX+S`2T~?TXt*gyiUp;ffCv+ug@uoiTq7;?0);7fOsffiTSww`|lDfTknSowb zgc3@y2z?RoYz+yl|Jpih*ICtu`&whEjR25TbVNyNJ=ZTueRP#u5@8l&*RpFFP3)b&BWJY8=6C3h56mV_e zn*fh`q79*OT%NDtUJG#`WKpswH^vJXTA+_7zr@a>HhJyPLi-@J*As&!JZN{{TpaC+ znPbc1XovA~RWM#+&9SY$friQ7I_vmoa7Pw3UbSKN1Y=YlwPwMsXiHEol9Q1NBlof6 zqwx)P)hnbBX`>){-gvp0z=EfALu#mGy)pzyuTm0eWjr^8N|Y=3!8XF|7DE2_G+~c> zVNq*)o7FL);?)=%B#N)|CsBg09E$%7e{?8k zjhy*@3`MKmUGK-@^I7-U`=e)qbKU(Ph>n`#H5rHVEmf=uxNcp#vHSB&tV>Uf zMm7En9%tGET_J3c1TfM^NZBipmS$o&v|Qo zYEILbH^;JBgxcrZCq{dXrz>RFEBVsO-n?KjReaWsIw{iWCi73iyXmv;ohL=#>AFW0 z1RBGqdw<9tzwJZO?!BM2HGTr8juAC5+8f=~UhpXkf->sqc; zw%fY44eF_T;lt6?;K@}}Pl=8S8o%kn{%|f%XWJgua<2K}#YFJffh?jvz8Hdq6(4a} zOK~_+qWYj=T{eqtTIq3kYA|6*z=oA4p+wG9K3l zSh}?2aeYv@zH1KHEBHp=-ko2c`Y+Z9ziX%Y=LhE3_vP2m=2s@fzWX89?YBAQMQzse zHfMg!f4h*YFzm(so&2J2r{!4l&y=0|FO+rv{V|VJf1@)(q8B$XG4G7q=i|{V!RCD* zk9N`3ecX@Zj{N%bk9*jSZ@d&tB5J}z=^TBq&?=QMD&W!%|p*L_&%B)gpl0Exl;5FUw zvE=edCr!|OpNvxcq_PW{I-!VB^2ea=kMJ(>owW1O!pW@W*PMkq{xbK$v!a0>iUi<$ zkO7(GN_Wj!xSd?(c3uj@xyminOAd4q>d~)G5OM}fwQAG1i_b9H9ixa7&mT;#4NIo6KT4X zE&0|Xvy=Q$l0Uk6Eo?Yh2~7#I)IVFQXL0^)ZOK1eu7~aU!zF=#c#9tP6c0oH@M%4q ztcMl%!DZ3q!If^*dC?9tZ#I2moDIIdIXVIU=16IYCE*V##m}4011v{?A82I8G6dc0v-l<=DmjW(_S8t^3PMqyG$oZ@X7~A(H>X zm0!SL;9mF87m%*+b$wrqj_SQPqHVJBFQP$CFj$N(=vsIB7b$n0`|1~AR@b_pei7<+ zuj{!y>YsF7gxpVgy z`x7Vkf%IHOpeH|G1fO~^37rINY zi~7T-?sK{kd=10So(-WJ>_+PRT}{m<>OL$MUo~;wi!cPm>W( zyX(ANXM9KAERa@F-;j!2)q4<)s7|{vde^8Qk!TiOLTB2Q{3uEua$9bUb|5|R_^(8VPrl0222^TGmaHpD>t@0t zW`@UBec~(85Abk|lz6_JZCneE?UJqhCKt}HdG1?Wzr~plAe0OdRX|454m^U3ie#!F1R(?lPO+x z->s|;K>ycO(M~MDnX7T>)YLDyjd48fPQ4AUtlzrJZj1WIT#5D!wbk747$bruJet1a zUq5qOG;uF`otCb{`)Z%kUK$Q1B`XI0C@N^cKzIzkHc__MBCU*2D`Vf=qgU>61;{VG zNw9xu{|A3@{ZD>--F;{Mi5*;GFOWq;Ui{&!8^8I*FW!0oMGd`hH{2dg;3Sm0Z;!sf zgj=>Iis{QmYj6-d$E{uyE#wm38P(Gl^{g$UXCG+R>khaR zdHWo9!ktXYIqr%(VV>u>wRbWV=eVtR!UE56v%e9YH20;@1I1E;@@fp2lC3_U)zg7F z?Rg@u{n~is8__EhNCpI;Niwco8WptTewc?oTL1wMPVT(5%U5ALns#G&&KtIqgl z^hnV6oUsl_lQb~og(Y(|?Dd3iM=K!M6W0O8=iI*Qq6xj%NtvCQ!h(dZ-sn^=%kG8x-|cR@7xr_v`|G`}g!HlX z(GrfgI`+QkNG@NyFS;Q8jYbFEWI;Z!TlpcSlCE_PlE1rme+Re9Z@a&IC%Tl&Mc<9) zj$3C1d3%rD7@LA|s%xt&+DgM+0Wla-Y8I4XL$WgJhgcR$#GUH*<$$q%CTAh^>_co4#Qr+d|d z5Q011q6hI3_^MdPlCDL{QeDa}3y^HCe=vH@abJrj*}mT1p&DHL&4fpl5S1H;$%&fj zY)j}_8*jd1vupJLLS>-fk=Oz_ID{^IxlRSz+HLwBni^6Xts@?a264dquZN=A%-b-Y zsOPFOxh3yWa%*H%)7t4uZgSszC^}}goDMKo(ixd7TIYwpm8 zqbZ&Kqllj;JsiDj@~t_^$I5X?w`qp0WpsP1-0vTb_S^MV+g_?+c=amT?>M#y`>rom zrDp{Iuw|}t$Nn%HH>Ty80fOge{t!6dOytKF<0!Rx-^&i_$# z1zAn^d<3HTLgbEpgwi*z`t&2w_<)RgS8Rkb+~C%3gb&`}9@FJ^_t%ZlwA%HE6;d;f z1ACMY$$m5W-ipa@4!MH3+~F4gIC_?(0B`vTzt*^OxePGfoT7yKXF_7POHjJ?``Z=x z-wh+dlRt?LY%t?_@ixsq_bPAqCe38}2D890av&H9IU+fn@}{)-n*=C+rD!z2RVBJ@ z*1@DTk;Y`E4G8I*EAINAMq@H25A0x(s5ORcod8RcuSaVSZMFr16rClK!{5`6?%m&i z8qG4qLD?(BK{+i(wH|xQavcS;mBWVFLllUEnFLHZ`q600B5xHDZ3KDXtp4t@sXLx1gM*T9H7(N@g`xitLdzeU!0u_Yv67r=x;+N6XczqPa?touJ zyESUzbR3#+7vp^-Ap@Hej!6(^?E`K8v@e8_af$0}v4WFzTdK1~LJWM(Ny+DZiV z$+m3wlV*)Y6Wy6VPY3I;_fIlzqfIveVUtTgB}_`jrJdw#Fuhj%8tzEZv$Zrjri3M^ zLUf~*R8(8+7EEfJT)ly#MpY~QTjQ4fG8*@a>AJT#L9TX)8p+wc_5j-sMU$f|uM1Ep zaq_6@VI2H$V3I_1geT|wh2oy!o&p)6foFM~LeT!O{& z=RlWvd#mv*u1k1j=sx#%fps#no+5xN_DNZJ#~xU&CbY?UnZ^Gz{`lV zu{2r9a)uj1$x$TlqSe#DFBk0M96}}2yw^`%7rS zwkwF%n@|)p%;4-`a3EN(cpJ}#5{GRfgv&6Z$LbNk@8P!u@4s+u!*C11s<%@WkLJkR zDKECSaMaf%$?!PUda%$))?ZE&J%D>24e;3x!dzcP%9|PRTyKKc*<2DcXQ+5!rc3n! zPdiPtdZVfb=0(S)@JLNN=L~vFW6LpyjIOT9V|>MD*-m~8jD_x7=dF{zi?n#a{9qsr zcJzjF+8K-v7WA2GL74}$gMs-aa!A|MyWPGQ_w9|tj1lr2tN`6+0HG|9hUDTPB)6o%w81zfB*lLz5b_z54{WYPT8H9w3O}LcdeuLTiwZDy~b>1H4 zZW-BILw%R0>LRheJnX19;^Twn~ z?!^7#-myAHDUKHS5r=?`!G|FJ>#EGtOtaC7%sC z-3iCGb-M??*EY9tjo`!v;F`EN35?t3qtOBrvQEn*j6owGX(KnH6pHVWkCfqkM5!ts zha;cC_(ncb-gf_`W!E23iE^@!c!U?sh)4W3&AgpjoxGa_c49^3MZM&&(PDs5#R8GT zp;;6|Ljjs8!?*pzx10}D6fj3_4@TJzbBIENirewSx8sIy`|P%n1K9Vlclh<#;afYV z%^ILeU(hCJ+ebDz+di_%@jbIi+4ikXO2fal!`b|;O@hBQ;QL#p$InM*K)0vO?ikR0 zK~#T5K@;8lQ)I3Yvm$oNqqlB@U>F=m7K6NP^XM6SU}w+lSeeWkO>P2bXO#~3C(o8d z3X_$r)QNg`vwP?njGbR)iCHypo8)V8WxU?~ibwozK7TUs&woAQ`R2gab&J-99Wuz( z79+A2t`RmTbM0O7h?>C$yiwO(79~ICn*8ML`nC6>WDj4QMfG7{{HJ;GM^(%g8sF^U z3qKZA`t!;uo%}>aF%j$S02Ne5=_Mvm90W?qde^Zf+BaMmyKjCw=)GXh=gO74<6>>z z;}&g+UODh|kg5(ZCH^+3Oe;Z}yoDuDVue!jWsPu#dtgh{7tcV_bDOsy%?OwxhFWME zCK$+tbCCT{b!R*hKFFw63b`SF- z&*eDPz41@cALiYyiO`97*sH5ul_u%C*Wl&t*Bma!loU2?P0mVp`k$i(;k~ij?JsSU z++%-^j+r2&O77v$wifYw+!0%&-iBU?E!j2BQg0tuT|aBuz=!F7F-6xjXKj1$)bm!N zRyh`%pQpIt0%GG0DC{)>3I|A|y2{ErNt&CUIEqSvXh7l-d8a& zzd4rSyZkL5KVWZxcNWQW&??;E2LC6T@s6Jbl`%ZA8MZAAtEXa*pef$Ps+9bIM}s9; zya}rI;a@0$D=rsuvytRFX>K@!U+&pI zwT*Mn#BrA!isGIiFTQzX@yXjOUUpF&@7>=osRap4J`LwQhig0k5t*{nDB2; zm~x*#VjVkI9Y||#YJ@T9*L%%*o&GN6rPL)$8r-mViB8ToXyqrUk(C)e6;am}|kK=+u(d78#Ozo%GvJBvJXAVTON`p1Q$aW;Y5UQ=@3<>w?BJ2_B z3wyPC)X3O6`H-cK!zN<~KSJ+jumR(evP1APzZ|octE=?uLhJI}a2Z!S57>5l0K?A< zn+Kk=l_<6l+7lc;FH+(U)N5>BYhojkPWkf=y4dXh1p1GF%t$7p!eamfH0E8I=18e& z{a;2v953cr_pSG6lJsO5ZlcmxmhcGlpZZZObH8hgCpFkxu#|k!CHNAk$kL$B`IrpS zd%@9UJNs8A2U}&RU?|DV*%YFjDV(5p`o@E6ON0JI_fpokD0`^&H$}hS`Wxl@J5wh62*)oj{dL zU5BPlAo8F)L5L+xR-BEHa?YaUESg|<=w}ZN3pLIvY16F6@?F)N^wsgURG2~H3O+}w zVfL@3b5zs>RJlY_6;&J=j@GaDYrI20rkjRUc0!5CuMgLxgJvTgx zF0s2h)p`bO^HJE!c`wB!>H#Ami~e57Jm|V42fF{oxXAM2@2&8j++*Chc0)SJ24-j4814Iw7xrdyr z;=S0yY9VQ*P1_p1R5!wGrQB_86>K3elua*6{2rMgJF-o-sqQ(j zyMxF9D-YqxJzBTm(TYp>w$92caiiXhd8JevgQjN`v}lroVv444yQZno5MWE-{+h&x z|L1ZDIM)7+CE_%PP!#$&&C8_NSu0ZuD+zaW^4j}2&9z0G<~qwN?_&)C+q!sCm5q|M zl>E25d^CZ!W8Gb&<8lAloA!ua)+P~%iP}?29nqdP5}hazvjg*w1!DF*xMRn}2XMJ+Ok8WQFC#JzM|?SJVMtk2 z%byT=)47oPx(R~pQJ~K$(4Jl^tY)Rp8(pi=KRW{2nv~IyNvbEr=j4Ew^~7$en@xf! zPU0W%mv~3_>ai@JPBQn!vyK>zeT42)64w!0B*gJ)3vom_CK0I(tzri>JwuV@BOD0` z?g8S!Mlooz8hS8wScKzf_t@BY=Z246+*b$0L)3iiVmr)WH0-yVzzqgY81G@!#KriC z?xBblqu9slP5EP?i<;iV9$V<*goU)%Md)Hr+J~$N)=gkoL{W75*u{zZ_3CKzOPFEhR~0H>YqJH2RCe`C?K^$r&OLG{QY zDJ$8EMy5C)AE^kqC({m}^B3^?2!<%_!45+Go!}5P6B*@eMk)Gw8ZBGYAu0ao3IBsG zA}e`2ZOsZhKuXl-X@@(ZFP=J=5U(0cOHXLlhY2Edl`v~g+%`;5U@gJ~-EK4DsSTzz z`E4_{?%h8r%Y1Q0&r5T}RFJ9`pRh`<>9f zx#1So1D%k7F`3(QpnT)GJ|{(a#$q1>+EVEjW2gQLck`OKudysO+#0guq%?h{Tsi=f;*d3eCpn}9A*|>^l zs&jc+bTAz+z4@L*n<-L8jB{yD{93>Qy_KcG2C;D@bT-+87U*oY2mcT{9ItH95ruC+ zI1NZX5J7-iR`wcaYASl1E#;X+e41-MTf#GuUiwr#GiWigt>UW?XH#a=LNm$%R7-xR zm&^m_Wn(w+ntJA7SW_81G@^&fH(2F1^-&P7nrP?P zyp{=8i_&A&JM~Vm1@iSS%Jk}89u#6T4B|)WB-K_Q$8Muu9F=Zs4%`^WvaYwwsAuLH zroH~QZi{m!YlMF~jw>-UW2s!#^ola@WE#IsnO;k|vje_sQ}Fia)n^dIj&zDH?LHW+ z%?H(mirCxW(#dgegRWy4B=*+Fu-N(pA-aqC*BSI;03;xQ7{;2 zIQy!?&fGySEu76dB~jn-I((hF=*a-x#QH?=V_pe)BueSTYy%D#5tBw>YMXXQ33pPC zXy(MYCYS|;Qfz9-#@mlHGtt%hu+4`vYNx-EVkzi)%Wx~V@|Ew%4H;@Nzh!5TYyVuagbZq})oCqA$QuYRD<^+6>Oe~r$~n^0k*|GoRI65_vg8`E_s|_aC2kV|qZ5$F zl0pZ=lnu#Rk&5va$rPq&GB|$~9rqZ0HpcU3aW%TYniTIAOvi|ckSKs?Y$DiwsgibK zC4GyW?5ovvb%4BB(jxCkM>Sa8yq|?st%zd42T*~C!`rX!#p|cc1&W8ZlevFSp$@yFPB5X8w2-HEyL@!^5DekG7)x2tv zV=;8=ALM%b)xj1*+YIH~h7|Q1pUtQt8vqzUuuni{p~m15)O z66(&K24$on`Agn9c03qak8Qg(fEveIWvNVj>>m_)Y)jU-uWH(M-ymAN!M$x-+&f^R zgo*yv3iXE!c_3VCfnI|M`jCRIbd3ALw77oU7-UBz&oOwOpvYOss;LP(x-1C{l8iP% zCfUG9{LaFh>%gj1jK-vzd}p!TyC@4yZU18!>!zjg^!X%s8O3OpD8UOkKt_Qe9gAy9 z&w$+5uWbb|tn$A$?b~iI+{dT@dHjkrzV+=bWZfGwfybpHGkb|B;M79`>LGoTu`5 zv5d~-B!5F44A!x>jCxA#r*+A4f;|P0o#$;iv3x*WlhQ?GAw*QYS(vR11G+*7H|4*v zRhhaL5eil>6=110$_wO3`OTN^`!m>{ZVtSv^a&HywNOp;9H7=Zv}}M@>Pjn+R%|7+ z@x*5b$(2Us&4Z%^w19jACeA~vbw(8LC6-DPgw%y@2N zd?8$oCs77$6kVtiVC2FT$uy3wM~8F^A=qKDEuJ47>qRRr3=}NoI-YCJhQ*2M-8kVP zK#fO$8mk3~h^T_v%hr`Nf-rO_iJrZo9(X8dw~c|~4dOxwv~J3d@&7W8`9B7r zUXMfxE_*GAH>?iI**5d330GJJGl;-zsE2#$3)EusCjV@Ym@sR53$re_GHdXFvJxKB z|7qdYP~f%VDP(?;lUv#WMRubG;{6)pb&}n4R%psvo~g7kVKAN501m**nRo^`3-)wi zH}fqKCczk+f6Idn2nl;oL^2FkTitC%n0i#7Wh-)yjTVW!5Br@~15KrEdDeza#+xm( zRTySN!y80XARC_;X3*xJBpilyw=nH!HNw`x3{rw0{2Mj5-LK%@6sE-Tv(b^7bQ2Cu zbs;m{y0wN4Y_5(yG>p6k`FN5(rgX`U~JArzn(%mWk z0GH04<2P}6=g#q~xvbcklGnJcJI6D3*n-7uhQbL;pzTxTy6IBIh|9FCz!&}`Pq|m` z5+91PY}qdHI2~IF)+u#1c>dL0;+^`uszgK_eF3@?|LWOY;+<(`$}D&(Cl=0%-#_NR zX-%tolM&s@YC~qUVN)=Wqv#Ut;8ZPkvv|=WhoBlx9uf-uj zYDcCXIqC%cLW9mP$RIP%?;RnSCv(N(!s0?-zJ$G|$k?pXzS`_6Ip11K&R0GVMKa40 zG?=3ehUFPndX2hmba?^_1{Xa0yK#+E(b)pt8foRovMZmi?*_u`V>! zhI%P68HJ^qSsZl zSvo5Dyqoh@jPPBM*~v&C@X>&3gS5-?=}`vu6m6SP4@a>@HHdSe8dSYXr?JwRtBo;=$<6*9N2H)hQq9F|rzI!44=thCt$y|0S zA0Pen`S`kljQ2M0P(D872_Rb`A0ICkGLTUytC^D^!)9B^v!~-4rj#_Mt!@XXI^BYa zC99S4@sZ`Ji!Lgf3#Kh%;^!X5Pd+~K{E;CBHVk6Jc!b-m!V=GzGM|T%S*HwJQ7`)T zD!>RwW|Y=iCtaw=N15!~;dR=*htXaYl>`fiRBURSkY(vVq|>(SdSfIIcTq%-$Md*u zI_(M|=|cB`PP@$Jo@t^}ye`!z@&hX=kkp`R&=sY+7@^Q6S)?`reLzg5>g`@4=CgJ~ z&`1(-yJ?+cx^zN@a)jyOw&}@DDs^eOB`Zr#R1rNY&a;gP%{&tEk-F4) zjo`y@16#L%#y2jRxXt26C`jN#i-vq$IwqIC$0JP9e@#-MAqOp(^2KNuN?waVbe;0( zN#+X@P%QaG8SsZ9)w@8?l=o%8lTS(HpM(MrgnLR|j#*q=WxgaK8K!#Kh@pbA5s&sZ zVt!%L%>D@fQ9#!BxXN<&DKM^s>w?AFTxI9-vokB#$XQey%>>dse=UpNp??0`fy0Ri zo|Z+AN%vXw#6j!UV1QqQ6nj329)gXn;GDS=6`qY6_9wQr92uz&W|z9>2j^gb2dJXH zl8I10H6ta+eVH{{QsgB@E9~1I{H5(%#9`BoDv+DNllYY63QN<3SStxTsRdZowfBr6_B zho*_p1{G479xH=LZ;8!BJi6vnGboI@R9BBbT&brJ>ZJjylSxlPeJ4Ua+YMw)Kxslf zYb$C+ zKJk}nE9az%HuT;3=#}>mE_DC{#r)T@BT)aeBLGO+5m=%+VNBo?)k)UF6F!(9+(M_* zZghQtJAChWd;_c$a)PRIU_ct5(@aWtPGG6UkRZIJ14O8IK;D2Fn@mk_w!uzpDUG6pPKGjK*@9>rSp(^TWwvw}k9VykP$9P;AO=xao@H)89t;EFX?Prv?N@RlD?ytwxR79JY$D8l z#1n#%fI^W~PR=*}r8;qHeTwAuJdqsWKN1#ZypL_0xX z88Qn*OK4D4*0?cHToY&21(6GL{%9jmZu)u9pGlpB8KC;;O;bPN=i`7RKLjWm;f`+9SL(PgchR2Miq*<;uTrM41 z9jcR}I;6p(I?>Qp2%>Lo7E@$E4!NmW3Mdr};2$&ux@|wy;pI8xhs$;Mk1QrBE-$8l zg1mkptlBn2{)s|MkamY>HYBZC@tqu6$8Ip?LzO@Td(3B_cJH20K1u|;N+3e`VPC2)+!x7`GV{enx#ocIf;|$fx1GIl%tvrRxuWRL##^?))aU4~D4m`Dj_5r!# zKf(*k?yh=y_uh-FMd{BJ9an3&-j=7A_w2b?jng><&?q_Ay=HoO$MB-EJ7IeH2l%4x zKcl?QOuEZ1fo?M8vr2baQuDyF8Y)x*QAc>B910cCa+CCh5a3ExobJv5ZY)oKU1;>{PX_yF#K8rj?si0%EPIPX1%LLhDhf{2#MlW{qqBbZW?ngXm1HBtgtc> z;e1i_5^=!b5)1q2L2%`WEn-6yQ&V-LUmcGNkFL1y!8|8!R_&GvkP(>WGEyAf zt%3X73vvHg#KrALyWJ98^xE>?y&ot6A`pcZg%Y^V^QB_l-iAD)MQHLaQ}1;F79lDz zA^)wtVj-167Y&Rifyq9TDWVYPujChXwf}l!#Kh02i%UYkKfomMAMe5AI!YM zedhJ?z!aNsvYf&v1A4~`FqKTFy6be`dp)YEjabEl@V|yKZU4jsl&Y4%bgTg#5t&ZoF1X~kz?jm!k`5I@kfn?(=ikF1@pgb74PNxScNi5Ehm+q^0sP&!!@2HNlrIx zgvoO*eGDc&p-mYUgug#S*x2rc!%gjwT-Bt;H_5F924rm!daJ zq3Wu8ll>r&sm)1gV0LLK`ILp)phO23(1kh9pypwAc9avpEKep66qBh1S|G&~Xo0!C zq-cKH@OTkso508->us@l_zct2L`PEH3LQ1aYWtII>ds(kNm~m#p4C>MqYNlHIwBSo z?OuTzy=b;k$gIkt3%*Hg&c8rH3Z?l~24EIZdk99Lw-9?TWyYaK+(LqaQN81yd zC#zq@h;dkjv{{3cXyqL4UU?+8gCpGAj*Q1P{Q7>}`no#qo~ae7bi{Q=zEm!LzQ9%G z(16DQHpWK6Y(O*aJU9aw{&B@65?R}bkcg{A;8~vTZN4_U~+VrK$$FNOb3a^s_ zQJ0ahubHW#`9aH&x9z;T?2Tv|#)qryG{U{Y8yM?e;nL3i(=*QiZ44f;!rC61dIrEi zG(aXlABe8!bk=r9+Grdg0`sgn9m5kZ?NRA3GNHkQnP1`>lxt}&aa`sMCy0p{J+H{}8yk)?HV1QsT z7_I2?GsuAFNX4g6!J=!|`mQzN?mEvn4nSaQfuL#7fFODuJ|wKS`0zSDBxi_4z195i z=!wPZ5eLVUy~2&LpMZyL0tUnTb47D zlPNL)z8iafpv3a6|HydroulKvv8*nbv}Q4uQJrN-im;0)-9@?5O zxL8Tj(>8bbo8n2+FKknlN=(#&bYbC^+*ctHMP+BZ&%P<1!*=G`x5N|Q(*~C@T2F$K z1X^VED&8#4R$|cq4gidGA_URa+~E02464KrEXa7lc5ywUX;H^t%e;VGB*@ZSrh=VI7oD z7y>wPPG#g5uFuC9Ns1BP#YSRQ$>FR5LqPKJp=rh2^YB6y@N`%V!?ZdWht*+eHR9}E zh`fe&0YfX5B;jHq=2=4`&pEhf`^AIQi4&_}0SubYaE-vgR=9}9*(3bs#Id3xIqp0U zVy&f<>INpZIJ=H%ZZAq?L;NZnXX9)+zbf8s*6r|?_@E=Z=7tBPoHsRB^DMb;UoI$| z_vV6s?J_DqnA?thO7Ea*+t&&!)LbIx9JzOM-`fJQv)$Ua6gV;UFtL7RVID>Y`r3jH zYjOTCbReGpyEa$C3#PG{zeq4y!Ms<}c6ZFN@x<2(aOSfzgKl-bC$K6lr#@hgt0GEj z)Mk%1oAqnvI3UU$`BvyLS_ehpB7e^f`?&yTN#Foj;j21Rtrz`vUY7)F)S&rND$8G` z={;iK=&*zL`p*aEp$jJ*GhmX7&sFW(^1N`VOdweA(`s?nOWEv2U9NIm{0ckY(1Wha zz5cj(+CqVqWm+^GXG)wq75+R>g#MOxOi4jalbk) zp2^T{v%q%4Zx-0QRf{GRu(h4B9ZtVD@uEwWfj;HzLPnwUe5?vJyMgl;&XKi*`;~x$ zsJe1yn^R4I?MgtIv@$T$J`$1fJut#k&NnP<$l4`+^t-ihW0sz5A=jImH%Zu<9(P+Hg4l2%?$OVeHTb|wP-}w&& zif+iiiJ|_(rtB*{m`MlPpCH8s$(PHpXWK_g^qGr3Gwab_0D+nrYIDDMI})^nWW3FD zWTlGPhzs+BwO(XET$mTF4=985&ZOEP^6n$I)Aca>DLKG@$)tIpGu*1pf2?^Zgi)_~pf^y&P$b?1BhyLj`A)7lBO{P*M(dycWTvE;)R6XT zyz~|5mFX37RFK?YBE`~3G!;JvEhzsEiFv746QJx#Zlu_((sg-iQ3@s3##M6PkSE%F z$A|p1vIN5HetVKnv^`m8Pu!e$#g+f1(K6HF8f$nx1|dEHzv_s2Y8_|Pj8JT?K##^T zr=8eO+xw`G!Vi@O$?csRdY6T7OvDDjj92v~YnC;OKhX6P8LXG{GarBWzsN z*X3oVB+Y<&z3krl9+VlHdu@D|NR`2&)!OBeG#Vke$v$~_!4Zs6c6YxAe>yRf zVoNR);)$F~M_U8sKp^U0BEsnz4-pO*&M@WCKGlJ0G3 zp?f<=SqQxH?Pe-OL)8dZ7=cm(08Yux@0SG9ziGFl=H)@1>))C?c)H{l7u$BccI6uc zeDTTbYU1~Rs>}6nL*!T7uKo>;aQcrGa7%Lq+_S&b}P%s+7q!`Ay=*8wHz?zW9Q0mF0xTcc9axgl<1hh!(UfNcUFR*i^@ESX*Hh>x*4A_BZ z$PBf?XhB+26RAFwtW`?cCd>aD9P|Q(wp9@v#G`h&!2W%lzi7$S$yufM=IhQL6c69m zQ!WKz6w6GMe9NmcMvHcPH$lHn_!t+N6T3-YIea{@uXJ=z6qf?D3*IY0iY`i_CEb99mC@!f(IEF zd$YWvMHR}e(w!7VCqh~SvcwfIK!3xLpvzEvAuKYwDDpWmwVrus)~u%5-jRzqGSP zGH`4ed(`$x=hWt>yVqVtT469HtnXGc%CRP_mx*S7F-(D`#J~c2cNabG%1Dwtw&)=W z6+=NLBA-B}GM~Vq<^%#RO`z}F9u42kwJ+06oAQ~_a z9qCFFzb+Wllp5y^q5ll)Q#rbK3K%h!HMD2#)r?8&&o4?8e>M%GH~1PE@NE*-v`j)~ ziKewGiy<ptJ^7Wg=S8_;HrB zP$yqNU`f`^9PDSE>$8rvTc=)S9oiSH*e87@9hsjlVAAKMlQ~kob@lLhR~7Gx0x0+7 zKsm6Ra9s1FAH~*3v;1NZw6;{>+jd&a8_Y-4pt`Oq(%Fk!3`MR^?m+gi+YmiSAr zKRm*1{Ta%z{>IS@2<^YP_V&r~Tae~kTVjygCXr%6c?8Aqp;hPUheyQb>T1*Kf_Q5c zdnN!~X!c9}1T~o;)z3beE5|KD++hZxh`mS?IwYQ77S`tKDk5i4jUb047LYP}wG5rOH12Qk&B+jxq;1pVJ znBiN6{zIfiu3xIzZRmpyE@E&xtlX*tUwPL^DIf5Gznp z%ExpEq(*r*OOTGz9Z=Ak#s%TZ#GlM2dCqkve&s~EN$}+Q>;WPr4Vxu~MbTimxn@z^ zl7@?JBnm073ugwwe_3eaGGZT^9SlrG;obK`rb@H@m+;>SpG#u~y>tY!psC$S=Rjb_q2PrVQ(1<2-q3>F|kufxTHrtedO%wfUYaMnbp4{nsjhl9{ zK1pSSq}@8LudrzqoJLLwaJHqh7Y?G5m`A?PWrNyY=3J7$NB(I}6wt{l2$g5!6$R+` zGSKgt?sZ+wi)I}RMKCs@%Z%(E37MT)r3G~Pq;6C`Abh7Ui0CuCq*|rMSJWDNrd@EC zef-Fq_HpVtTtjCQec^8&#rRQBs3UZwFe>$8bobfZ!tmRCNehco4wTw7n}x8plSTyr zK0v>b=4a>%A>LV6q6?X=lyFh+hc0M`TL;i-Y3e8s99tONDR-~=bmqSbJ)f$FhL&C{REsBC? z;3OQ}>gGqzkm#)#n#OOtldBus*}h;DA8jkqG}Z+wzD<*RoK3FQj3=xG@m526`mYXR zW23o8RrQ57$aABk>uvb~(nWK4SlMW0-U4PepR;sjJi9WDt)p(cG2OK}Z^gc>*r)k@ z8$6&fI-NygG+R#|d=+-no+L_vlUyHb)(U>`kC;wcfiAP~M9hWo5=OPEC4&?qea@fK zeJbpqkdTpobN(UHDUo?fT@R+#*)%aAhJ-50GI2)fpebZ8wSg}U>YPj}t&tq8B6YP^ z_YPJ)GfKd3qO>3r&B3ZJ2dn9Fu$oB}*Ti%t5pG;FIatk^$Rrwnl~3ZB_~ zKAl?0B_R*1o^-m(NWs&S)?NCMxVLL|I+NFOsdD>$B%aWip4QWeQU}-5>0&26?8T%S z!9gLYp%CU~NkALaBbV6G`;?BNvi;{phjYP$-7=flhbp=}m|HrUI;0lgL;8&#smm?m zv?tq_6SaI3&`ENx=xu{IVsqT;AtP-%&wnyw5$gH8FH-ENAkoRhqUa9e)L#BAO0zxv z9ZD3l==8{QmyVP!r6Y{OfN5DmYjTCG`51uI(8P#GBg(BWLl*ysT>^h!^N7h8v#H^S zx-daVyHx0lq=-5dcFg58WT#MZy1&lVP*Mx30aFQr0p9f?`*nq2-5YYnASI;Kx+F%6 z2Q@-%xtfTegA_iC`bmzM9ZC&iCLJ1Q+?Fc{jkug)^R9Jxeg8@x6=#Vk)Q-Aw=)sl8 z+n(?!15P}vwpdu;cARLjv6?mdYn*sPIzy-l>M7Ho@fUq0odcWlo=Hnd5)noEQWRzG zf!!o!)cwhL{002$1U0!DYU*GE1hXK!=KT9+EX1!9nLSJ=S)ebIZHApml$jf@Z&Zsw z-*p1bQt3g7*hF7W4}75S(yI72kUmGYezHJnsoKv;I@tjB-APBAvA%?CoI>68sl;>= z5k(X;ON@JL;$wj#r`Am7vW{T7DFit;6uU{npTlUP6G!VEQnG5LQ+*Q04syXz6AQFW zT+BEbWi4vV=WuM3NZzKT>7Tc>eE1Z3P>r#`-59`3A)EwxOtFiQwsmxUM+eyT#G-fhMHeo3Gyp08ZtPJQL-XH*ZQPRd~$gq zAXiLjA682eNfNJYr5U*oH5Q}@E|aT*3E-(E}?yn8VR( lSdHhgo#fOh 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 LDWswMMBaY@Ka-&@ diff --git a/core/src/queue.rs b/core/src/queue.rs index 681a899bb3c..64fb5e97a78 100644 --- a/core/src/queue.rs +++ b/core/src/queue.rs @@ -14,12 +14,7 @@ use dashmap::{mapref::entry::Entry, DashMap}; use eyre::{Report, Result}; use iroha_config::queue::Configuration; use iroha_crypto::HashOf; -use iroha_data_model::{ - account::{Account, AccountId}, - evaluate::ExpressionEvaluator as _, - expression::{EvaluatesTo, Where}, - transaction::prelude::*, -}; +use iroha_data_model::{account::AccountId, transaction::prelude::*}; use iroha_logger::{debug, info, trace, warn}; use iroha_primitives::must_use::MustUse; use rand::seq::IteratorRandom; @@ -32,16 +27,17 @@ impl AcceptedTransaction { fn check_signature_condition(&self, wsv: &WorldStateView) -> Result> { let authority = &self.payload().authority; - let signatories = self + let transaction_signatories = self .signatures() .iter() .map(|signature| signature.public_key()) - .cloned(); + .cloned() + .collect(); wsv.map_account(authority, |account| { - wsv.evaluate(&check_signature_condition(account, signatories)) - .map(MustUse::new) - .map_err(Into::into) + Ok(account + .signature_check_condition + .check(&account.signatories, &transaction_signatories)) })? } @@ -51,29 +47,6 @@ impl AcceptedTransaction { } } -fn check_signature_condition( - account: &Account, - signatories: impl IntoIterator, -) -> EvaluatesTo { - let where_expr = Where::new(EvaluatesTo::new_evaluates_to_value( - *account.signature_check_condition.0.expression.clone(), - )) - .with_value( - iroha_data_model::account::ACCOUNT_SIGNATORIES_VALUE - .parse() - .expect("ACCOUNT_SIGNATORIES_VALUE should be valid."), - account.signatories.iter().cloned().collect::>(), - ) - .with_value( - iroha_data_model::account::TRANSACTION_SIGNATORIES_VALUE - .parse() - .expect("TRANSACTION_SIGNATORIES_VALUE should be valid."), - signatories.into_iter().collect::>(), - ); - - EvaluatesTo::new_unchecked(where_expr) -} - /// Lockfree queue for transactions /// /// Multiple producers, single consumer @@ -414,11 +387,7 @@ mod tests { use std::{str::FromStr, sync::Arc, thread, time::Duration}; use iroha_config::{base::proxy::Builder, queue::ConfigurationProxy}; - use iroha_data_model::{ - account::{ACCOUNT_SIGNATORIES_VALUE, TRANSACTION_SIGNATORIES_VALUE}, - prelude::*, - transaction::TransactionLimits, - }; + use iroha_data_model::{prelude::*, transaction::TransactionLimits}; use iroha_primitives::must_use::MustUse; use rand::Rng as _; @@ -509,46 +478,6 @@ mod tests { )); } - #[test] - fn push_tx_signature_condition_failure() { - let max_txs_in_queue = 10; - let key_pair = KeyPair::generate().unwrap(); - - let wsv = { - let domain_id = DomainId::from_str("wonderland").expect("Valid"); - let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); - let mut domain = Domain::new(domain_id.clone()).build(&account_id); - let mut account = Account::new(account_id.clone(), [key_pair.public_key().clone()]) - .build(&account_id); - // Cause `check_siganture_condition` failure by trying to convert `u32` to `bool` - account.signature_check_condition = - SignatureCheckCondition(EvaluatesTo::new_unchecked(0u32)); - assert!(domain.add_account(account).is_none()); - - let kura = Kura::blank_kura_for_testing(); - Arc::new(WorldStateView::new( - World::with([domain], PeersIds::new()), - kura.clone(), - )) - }; - - let queue = Queue::from_configuration(&Configuration { - transaction_time_to_live_ms: 100_000, - max_transactions_in_queue: max_txs_in_queue, - ..ConfigurationProxy::default() - .build() - .expect("Default queue config should always build") - }); - - assert!(matches!( - queue.push(accepted_tx("alice@wonderland", key_pair), &wsv), - Err(Failure { - err: Error::SignatureCondition { .. }, - .. - }) - )); - } - #[test] fn push_multisignature_tx() { let max_txs_in_block = 2; @@ -563,19 +492,7 @@ mod tests { key_pairs.iter().map(KeyPair::public_key).cloned(), ) .build(&account_id); - account.signature_check_condition = SignatureCheckCondition( - ContainsAll::new( - EvaluatesTo::new_unchecked(ContextValue::new( - Name::from_str(TRANSACTION_SIGNATORIES_VALUE) - .expect("TRANSACTION_SIGNATORIES_VALUE should be valid."), - )), - EvaluatesTo::new_unchecked(ContextValue::new( - Name::from_str(ACCOUNT_SIGNATORIES_VALUE) - .expect("ACCOUNT_SIGNATORIES_VALUE should be valid."), - )), - ) - .into(), - ); + account.signature_check_condition = SignatureCheckCondition::all_account_signatures(); assert!(domain.add_account(account).is_none()); Arc::new(WorldStateView::new( World::with([domain], PeersIds::new()), diff --git a/data_model/src/account.rs b/data_model/src/account.rs index e652b8f63c7..1e9d358372c 100644 --- a/data_model/src/account.rs +++ b/data_model/src/account.rs @@ -15,6 +15,7 @@ use std::collections::{btree_map, btree_set}; use derive_more::{Constructor, DebugCustom, Display}; use getset::Getters; use iroha_data_model_derive::{model, IdEqOrdHash}; +use iroha_primitives::{const_vec::ConstVec, must_use::MustUse}; use iroha_schema::IntoSchema; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; @@ -27,7 +28,6 @@ use crate::{ AssetsMap, }, domain::prelude::*, - expression::{ContainsAny, ContextValue, EvaluatesTo}, metadata::Metadata, role::{prelude::RoleId, RoleIds}, HasMetadata, Identifiable, Name, ParseError, PublicKey, Registered, @@ -44,18 +44,6 @@ pub type AccountsMap = btree_map::BTreeMap; // of space, over `Vec`. type Signatories = btree_set::BTreeSet; -/// The context value name for transaction signatories. -#[cfg(feature = "transparent_api")] -pub const TRANSACTION_SIGNATORIES_VALUE: &str = "transaction_signatories"; -#[cfg(not(feature = "transparent_api"))] -const TRANSACTION_SIGNATORIES_VALUE: &str = "transaction_signatories"; - -/// The context value name for account signatories. -#[cfg(feature = "transparent_api")] -pub const ACCOUNT_SIGNATORIES_VALUE: &str = "account_signatories"; -#[cfg(not(feature = "transparent_api"))] -const ACCOUNT_SIGNATORIES_VALUE: &str = "account_signatories"; - #[model] pub mod model { use super::*; @@ -154,18 +142,20 @@ pub mod model { Eq, PartialOrd, Ord, - Constructor, Decode, Encode, Deserialize, Serialize, IntoSchema, )] - #[serde(transparent)] - #[repr(transparent)] - // SAFETY: `SignatureCheckCondition` has no trap representation in `EvalueatesTo` - #[ffi_type(unsafe {robust})] - pub struct SignatureCheckCondition(pub EvaluatesTo); + #[ffi_type(opaque)] + #[allow(clippy::enum_variant_names)] + pub enum SignatureCheckCondition { + #[display(fmt = "AnyAccountSignatureOr({_0:?})")] + AnyAccountSignatureOr(ConstVec), + #[display(fmt = "AllAccountSignaturesAnd({_0:?})")] + AllAccountSignaturesAnd(ConstVec), + } } impl Account { @@ -278,27 +268,6 @@ impl NewAccount { } } -/// Default signature condition check for accounts. -/// Returns true if any of the signatories have signed the transaction. -impl Default for SignatureCheckCondition { - #[inline] - fn default() -> Self { - Self( - ContainsAny::new( - EvaluatesTo::new_unchecked(ContextValue::new( - Name::from_str(TRANSACTION_SIGNATORIES_VALUE) - .expect("TRANSACTION_SIGNATORIES_VALUE should be valid."), - )), - EvaluatesTo::new_unchecked(ContextValue::new( - Name::from_str(ACCOUNT_SIGNATORIES_VALUE) - .expect("ACCOUNT_SIGNATORIES_VALUE should be valid."), - )), - ) - .into(), - ) - } -} - impl HasMetadata for NewAccount { fn metadata(&self) -> &Metadata { &self.metadata @@ -345,6 +314,50 @@ impl FromStr for AccountId { } } +impl Default for SignatureCheckCondition { + fn default() -> Self { + Self::AnyAccountSignatureOr(ConstVec::new_empty()) + } +} + +impl SignatureCheckCondition { + /// Shorthand to create a [`SignatureCheckCondition::AnyAccountSignatureOr`] variant without additional allowed signatures. + #[inline] + pub fn any_account_signature() -> Self { + Self::AnyAccountSignatureOr(ConstVec::new_empty()) + } + + /// Shorthand to create a [`SignatureCheckCondition::AllAccountSignaturesAnd`] variant without additional required signatures. + #[inline] + pub fn all_account_signatures() -> Self { + Self::AllAccountSignaturesAnd(ConstVec::new_empty()) + } + + /// Checks whether the transaction contains all the signatures required by the `SignatureCheckCondition`. + pub fn check( + &self, + account_signatories: &btree_set::BTreeSet, + transaction_signatories: &btree_set::BTreeSet, + ) -> MustUse { + let result = match &self { + SignatureCheckCondition::AnyAccountSignatureOr(additional_allowed_signatures) => { + account_signatories + .iter() + .chain(additional_allowed_signatures.as_ref()) + .any(|allowed| transaction_signatories.contains(allowed)) + } + SignatureCheckCondition::AllAccountSignaturesAnd(additional_required_signatures) => { + account_signatories + .iter() + .chain(additional_required_signatures.as_ref()) + .all(|required_signature| transaction_signatories.contains(required_signature)) + } + }; + + MustUse::new(result) + } +} + /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { pub use super::{Account, AccountId, SignatureCheckCondition}; diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 6e3f2bdaee0..b8fcf553afb 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -34,7 +34,6 @@ use block::VersionedCommittedBlock; #[cfg(not(target_arch = "aarch64"))] use derive_more::Into; use derive_more::{AsRef, DebugCustom, Deref, Display, From, FromStr}; -use evaluate::Evaluate; use events::TriggeringFilterBox; use getset::Getters; use iroha_crypto::{HashOf, PublicKey}; @@ -1126,10 +1125,10 @@ impl Value { | LengthLimits(_) | Numeric(_) | Validator(_) - | LogLevel(_) => 1_usize, + | LogLevel(_) + | SignatureCheckCondition(_) => 1_usize, Vec(v) => v.iter().map(Self::len).sum::() + 1_usize, LimitedMetadata(data) => data.nested_len() + 1_usize, - SignatureCheckCondition(s) => Evaluate::len(&s.0), } } } diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index 8352748b3fb..ebc01c96330 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -3940,7 +3940,20 @@ } ] }, - "SignatureCheckCondition": "EvaluatesTo", + "SignatureCheckCondition": { + "Enum": [ + { + "tag": "AnyAccountSignatureOr", + "discriminant": 0, + "type": "Vec" + }, + { + "tag": "AllAccountSignaturesAnd", + "discriminant": 1, + "type": "Vec" + } + ] + }, "SignatureOf": "Signature", "SignatureOf": "Signature", "SignatureOf": "Signature", @@ -4771,6 +4784,9 @@ "Vec": { "Vec": "PeerId" }, + "Vec": { + "Vec": "PublicKey" + }, "Vec": { "Vec": "TransactionValue" }, diff --git a/primitives/src/const_vec.rs b/primitives/src/const_vec.rs index 859129fe3b3..27578187b53 100644 --- a/primitives/src/const_vec.rs +++ b/primitives/src/const_vec.rs @@ -21,11 +21,19 @@ impl ConstVec { /// Create a new `ConstVec` from something convertible into a `Box<[T]>`. /// /// Using `Vec` here would take ownership of the data without needing to copy it (if length is the same as capacity). + #[inline] pub fn new(content: impl Into>) -> Self { Self(content.into()) } + /// Creates an empty `ConstVec`. This operation does not allocate any memory. + #[inline] + pub fn new_empty() -> Self { + Self(Vec::new().into()) + } + /// Converts the `ConstVec` into a `Vec`, reusing the heap allocation. + #[inline] pub fn into_vec(self) -> Vec { self.0.into_vec() } diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index a97ab4fd19c..e52774ece8f 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -12,6 +12,7 @@ extern crate alloc; pub mod addr; +#[cfg(not(feature = "ffi_import"))] pub mod const_vec; #[cfg(not(feature = "ffi_import"))] pub mod conststr; From 4c7ef1f7c53ac603b429bf238c01d73237fd6495 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Fri, 8 Sep 2023 09:58:22 +0300 Subject: [PATCH 04/55] [refactor] #3526: Add signature check condition unit tests Signed-off-by: Nikita Strygin --- data_model/src/account.rs | 97 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/data_model/src/account.rs b/data_model/src/account.rs index 1e9d358372c..aeb5269a829 100644 --- a/data_model/src/account.rs +++ b/data_model/src/account.rs @@ -362,3 +362,100 @@ impl SignatureCheckCondition { pub mod prelude { pub use super::{Account, AccountId, SignatureCheckCondition}; } + +#[cfg(test)] +mod tests { + use iroha_crypto::{KeyPair, PublicKey}; + + use super::SignatureCheckCondition; + + fn make_key() -> PublicKey { + KeyPair::generate().unwrap().public_key().clone() + } + + fn check_signature_check_condition( + condition: &SignatureCheckCondition, + account_signatories: &[&PublicKey], + tx_signatories: &[&PublicKey], + result: bool, + ) { + let account_signatories = account_signatories.iter().copied().cloned().collect(); + let tx_signatories = tx_signatories.iter().copied().cloned().collect(); + + assert_eq!( + condition.check(&account_signatories, &tx_signatories,).0, + result + ); + } + + #[test] + fn signature_check_condition_default() { + let key1 = make_key(); + let key2 = make_key(); + let key3 = make_key(); + let condition = SignatureCheckCondition::default(); + + check_signature_check_condition(&condition, &[], &[], false); + check_signature_check_condition(&condition, &[&key1], &[], false); + check_signature_check_condition(&condition, &[], &[&key1], false); + check_signature_check_condition(&condition, &[&key1], &[&key1], true); + check_signature_check_condition(&condition, &[&key1], &[&key2], false); + check_signature_check_condition(&condition, &[&key1, &key2, &key3], &[&key1], true); + check_signature_check_condition(&condition, &[&key1, &key2, &key3], &[&key2], true); + check_signature_check_condition(&condition, &[&key1, &key2, &key3], &[&key3], true); + } + + #[test] + fn signature_check_condition_all() { + let key1 = make_key(); + let key2 = make_key(); + let key3 = make_key(); + let condition = SignatureCheckCondition::all_account_signatures(); + + // technically, `\forall x \in \emptyset, check(x)` is true for any `check`, so this evaluate to true + // maybe not the logic we want? + check_signature_check_condition(&condition, &[], &[], true); + check_signature_check_condition(&condition, &[], &[&key1], true); + + check_signature_check_condition(&condition, &[&key1], &[], false); + check_signature_check_condition(&condition, &[&key1], &[&key1], true); + check_signature_check_condition(&condition, &[&key1], &[&key2], false); + check_signature_check_condition(&condition, &[&key1, &key2, &key3], &[&key1], false); + check_signature_check_condition(&condition, &[&key1, &key2, &key3], &[&key2], false); + check_signature_check_condition(&condition, &[&key1, &key2, &key3], &[&key3], false); + check_signature_check_condition(&condition, &[&key1, &key2], &[&key1, &key2, &key3], true); + check_signature_check_condition(&condition, &[&key1, &key2], &[&key1, &key2], true); + check_signature_check_condition(&condition, &[&key1, &key2], &[&key2, &key3], false); + } + + #[test] + fn signature_check_condition_any_or() { + let key1 = make_key(); + let key2 = make_key(); + let key3 = make_key(); + let condition = SignatureCheckCondition::AnyAccountSignatureOr(vec![key3.clone()].into()); + + check_signature_check_condition(&condition, &[], &[], false); + check_signature_check_condition(&condition, &[], &[&key3], true); + check_signature_check_condition(&condition, &[], &[&key2], false); + check_signature_check_condition(&condition, &[], &[&key1, &key2], false); + check_signature_check_condition(&condition, &[&key2], &[&key2], true); + check_signature_check_condition(&condition, &[&key2, &key3], &[&key2], true); + check_signature_check_condition(&condition, &[&key1, &key2], &[&key2], true); + } + + #[test] + fn signature_check_condition_all_and() { + let key1 = make_key(); + let key2 = make_key(); + let key3 = make_key(); + let condition = SignatureCheckCondition::AllAccountSignaturesAnd(vec![key3.clone()].into()); + + check_signature_check_condition(&condition, &[], &[], false); + check_signature_check_condition(&condition, &[], &[&key3], true); + check_signature_check_condition(&condition, &[&key1], &[&key3], false); + check_signature_check_condition(&condition, &[&key1], &[&key1, &key3], true); + check_signature_check_condition(&condition, &[&key2], &[&key1, &key3], false); + check_signature_check_condition(&condition, &[&key2], &[&key1, &key2, &key3], true); + } +} From 8c4c94ff2eb874e7c45475b8c383a9adff83812a Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Tue, 5 Sep 2023 15:12:10 +0300 Subject: [PATCH 05/55] [feature] #1915: Implement `Fast` kura init mode Signed-off-by: Shanin Roman --- core/benches/kura.rs | 6 +- core/src/kura.rs | 329 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 268 insertions(+), 67 deletions(-) diff --git a/core/benches/kura.rs b/core/benches/kura.rs index 3f5ecfbc0e4..02cbdb6b82c 100644 --- a/core/benches/kura.rs +++ b/core/benches/kura.rs @@ -14,7 +14,6 @@ use iroha_crypto::KeyPair; use iroha_data_model::{ block::VersionedCommittedBlock, prelude::*, transaction::TransactionLimits, }; -use iroha_version::scale::EncodeVersioned; use tokio::{fs, runtime::Runtime}; async fn measure_block_size_for_n_validators(n_validators: u32) { @@ -62,10 +61,7 @@ async fn measure_block_size_for_n_validators(n_validators: u32) { let mut block_store = BlockStore::new(dir.path(), LockStatus::Unlocked); block_store.create_files_if_they_do_not_exist().unwrap(); - let serialized_block: Vec = block.encode_versioned(); - block_store - .append_block_to_chain(&serialized_block) - .unwrap(); + block_store.append_block_to_chain(&block).unwrap(); let metadata = fs::metadata(dir.path().join("blocks.data")).await.unwrap(); let file_size = Byte::from_bytes(u128::from(metadata.len())).get_appropriate_unit(false); diff --git a/core/src/kura.rs b/core/src/kura.rs index 0a648f36095..a02f772d822 100644 --- a/core/src/kura.rs +++ b/core/src/kura.rs @@ -6,13 +6,13 @@ use std::{ fmt::Debug, fs, - io::{Read, Seek, SeekFrom, Write}, + io::{BufWriter, Read, Seek, SeekFrom, Write}, path::{Path, PathBuf}, sync::Arc, }; use iroha_config::kura::Mode; -use iroha_crypto::HashOf; +use iroha_crypto::{Hash, HashOf}; use iroha_data_model::block::VersionedCommittedBlock; use iroha_logger::prelude::*; use iroha_version::scale::{DecodeVersioned, EncodeVersioned}; @@ -22,8 +22,11 @@ use crate::handler::ThreadHandler; const INDEX_FILE_NAME: &str = "blocks.index"; const DATA_FILE_NAME: &str = "blocks.data"; +const HASHES_FILE_NAME: &str = "blocks.hashes"; const LOCK_FILE_NAME: &str = "kura.lock"; +const SIZE_OF_BLOCK_HASH: u64 = std::mem::size_of::>() as u64; + /// The interface of Kura subsystem #[derive(Debug)] pub struct Kura { @@ -113,16 +116,55 @@ impl Kura { /// - data in file storage is invalid or corrupted #[iroha_logger::log(skip_all, name = "kura_init")] pub fn init(self: &Arc) -> Result { - let block_store = self.block_store.lock(); + let mut block_store = self.block_store.lock(); let block_index_count: usize = block_store .read_index_count()? .try_into() .expect("We don't have 4 billion blocks."); + + let block_hashes = match self.mode { + Mode::Fast => Kura::init_fast_mode(&block_store, block_index_count).or_else(|error| { + warn!(%error, "Hashes file is broken. Falling back to strict init mode."); + Kura::init_strict_mode(&mut block_store, block_index_count) + }), + Mode::Strict => Kura::init_strict_mode(&mut block_store, block_index_count), + }?; + + let block_count = block_hashes.len(); + info!(mode=?self.mode, block_count, "Kura init complete"); + + // The none value is set in order to indicate that the blocks exist on disk but + // are not yet loaded. + *self.block_data.lock() = block_hashes.into_iter().map(|hash| (hash, None)).collect(); + Ok(BlockCount(block_count)) + } + + fn init_fast_mode( + block_store: &BlockStore, + block_index_count: usize, + ) -> Result>, Error> { + let block_hashes_count = block_store + .read_hashes_count()? + .try_into() + .expect("We don't have 4 billion blocks."); + if block_hashes_count == block_index_count { + block_store.read_block_hashes(0, block_hashes_count) + } else { + Err(Error::HashesFileHeightMismatch) + } + } + + fn init_strict_mode( + block_store: &mut BlockStore, + block_index_count: usize, + ) -> Result>, Error> { + let mut block_hashes = Vec::with_capacity(block_index_count); + let mut block_indices = vec![BlockIndex::default(); block_index_count]; block_store.read_block_indices(0, &mut block_indices)?; - let mut block_hashes: Vec> = Vec::new(); + let mut previous_block_hash = None; for block in block_indices { // This is re-allocated every iteration. This could cause a problem. let mut block_data_buffer = vec![0_u8; block.length.try_into()?]; @@ -130,7 +172,13 @@ impl Kura { match block_store.read_block_data(block.start, &mut block_data_buffer) { Ok(_) => match VersionedCommittedBlock::decode_all_versioned(&block_data_buffer) { Ok(decoded_block) => { - block_hashes.push(decoded_block.hash()); + if previous_block_hash != decoded_block.as_v1().header.previous_block_hash { + error!("Block has wrong previous block hash. Not reading any blocks beyond this height."); + break; + } + let decoded_block_hash = decoded_block.hash(); + block_hashes.push(decoded_block_hash); + previous_block_hash = Some(decoded_block_hash); } Err(error) => { error!(?error, "Encountered malformed block. Not reading any blocks beyond this height."); @@ -143,13 +191,10 @@ impl Kura { } } } - let block_count = block_hashes.len(); - info!(block_count, "Kura init complete"); - // The none value is set in order to indicate that the blocks exist on disk but - // are not yet loaded. - *self.block_data.lock() = block_hashes.into_iter().map(|hash| (hash, None)).collect(); - Ok(BlockCount(block_count)) + block_store.overwrite_block_hashes(&block_hashes)?; + + Ok(block_hashes) } #[allow(clippy::expect_used, clippy::cognitive_complexity, clippy::panic)] @@ -227,9 +272,7 @@ impl Kura { } for block in blocks_to_be_written { - let serialized_block: Vec = block.encode_versioned(); - - if let Err(error) = block_store_guard.append_block_to_chain(&serialized_block) { + if let Err(error) = block_store_guard.append_block_to_chain(&block) { error!(?error, "Failed to store block"); panic!("Kura has encountered a fatal IO error."); } @@ -422,15 +465,12 @@ impl BlockStore { let mut index_file = std::fs::OpenOptions::new() .read(true) .open(path.clone()) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; let start_location = start_block_height * (2 * std::mem::size_of::() as u64); let block_count = dest_buffer.len(); if start_location + (2 * std::mem::size_of::() as u64) * block_count as u64 - > index_file - .metadata() - .map_err(|e| Error::IO(e, path.clone()))? - .len() + > index_file.metadata().add_err_context(path.clone())?.len() { return Err(Error::OutOfBoundsBlockRead { start_block_height, @@ -439,7 +479,7 @@ impl BlockStore { } index_file .seek(SeekFrom::Start(start_location)) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; let mut buffer = [0; core::mem::size_of::()]; // (start, length), (start,length) ... for current_buffer in dest_buffer.iter_mut() { @@ -447,13 +487,13 @@ impl BlockStore { start: { index_file .read_exact(&mut buffer) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; u64::from_le_bytes(buffer) }, length: { index_file .read_exact(&mut buffer) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; u64::from_le_bytes(buffer) }, }; @@ -492,12 +532,70 @@ impl BlockStore { let index_file = std::fs::OpenOptions::new() .read(true) .open(path.clone()) - .map_err(|e| Error::IO(e, path.clone()))?; - Ok(index_file.metadata().map_err(|e| Error::IO(e, path))?.len() + .add_err_context(path.clone())?; + Ok(index_file.metadata().add_err_context(path)?.len() / (2 * std::mem::size_of::() as u64)) // Each entry is 16 bytes. } + /// Read a series of block hashes from the block hashes file + /// + /// # Errors + /// IO Error. + pub fn read_block_hashes( + &self, + start_block_height: u64, + block_count: usize, + ) -> Result>> { + let path = self.path_to_blockchain.join(HASHES_FILE_NAME); + let mut hashes_file = std::fs::OpenOptions::new() + .read(true) + .open(path.clone()) + .add_err_context(path.clone())?; + let start_location = start_block_height * SIZE_OF_BLOCK_HASH; + + if start_location + (SIZE_OF_BLOCK_HASH) * block_count as u64 + > hashes_file.metadata().add_err_context(path.clone())?.len() + { + return Err(Error::OutOfBoundsBlockRead { + start_block_height, + block_count, + }); + } + hashes_file + .seek(SeekFrom::Start(start_location)) + .add_err_context(path.clone())?; + + let mut buffer = [0; Hash::LENGTH]; + (0..block_count) + .map(|_| { + hashes_file + .read_exact(&mut buffer) + .add_err_context(path.clone()) + .map(|_| HashOf::from_untyped_unchecked(Hash::prehashed(buffer))) + }) + .collect() + } + + /// Get the number of hashes in the hashes file, which is + /// calculated as the size of the hashes file in bytes divided by + /// `size_of(HashOf)`. + /// + /// # Errors + /// IO Error. + /// + /// The most common reason this function fails is + /// that you did not call `create_files_if_they_do_not_exist`. + #[allow(clippy::integer_division)] + pub fn read_hashes_count(&self) -> Result { + let path = self.path_to_blockchain.join(HASHES_FILE_NAME); + let hashes_file = std::fs::OpenOptions::new() + .read(true) + .open(path.clone()) + .add_err_context(path.clone())?; + Ok(hashes_file.metadata().add_err_context(path)?.len() / SIZE_OF_BLOCK_HASH) + } + /// Read block data starting from the /// `start_location_in_data_file` in data file in order to fill /// `dest_buffer`. @@ -513,13 +611,11 @@ impl BlockStore { let mut data_file = std::fs::OpenOptions::new() .read(true) .open(path.clone()) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; data_file .seek(SeekFrom::Start(start_location_in_data_file)) - .map_err(|e| Error::IO(e, path.clone()))?; - data_file - .read_exact(dest_buffer) - .map_err(|e| Error::IO(e, path))?; + .add_err_context(path.clone())?; + data_file.read_exact(dest_buffer).add_err_context(path)?; Ok(()) } @@ -535,29 +631,26 @@ impl BlockStore { .write(true) .create(true) .open(path.clone()) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; let start_location = block_height * (2 * std::mem::size_of::() as u64); if start_location + (2 * std::mem::size_of::() as u64) - > index_file - .metadata() - .map_err(|e| Error::IO(e, path.clone()))? - .len() + > index_file.metadata().add_err_context(path.clone())?.len() { index_file .set_len(start_location + (2 * std::mem::size_of::() as u64)) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; } index_file .seek(SeekFrom::Start(start_location)) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; // block0 | block1 // start, length| start, length ... et cetera. index_file .write_all(&start.to_le_bytes()) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; index_file .write_all(&length.to_le_bytes()) - .map_err(|e| Error::IO(e, path))?; + .add_err_context(path)?; Ok(()) } @@ -577,11 +670,9 @@ impl BlockStore { let index_file = std::fs::OpenOptions::new() .write(true) .open(path.clone()) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; let new_byte_size = new_count * (2 * std::mem::size_of::() as u64); - index_file - .set_len(new_byte_size) - .map_err(|e| Error::IO(e, path))?; + index_file.set_len(new_byte_size).add_err_context(path)?; Ok(()) } @@ -600,23 +691,74 @@ impl BlockStore { let mut data_file = std::fs::OpenOptions::new() .write(true) .open(path.clone()) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; if start_location_in_data_file + block_data.len() as u64 - > data_file - .metadata() - .map_err(|e| Error::IO(e, path.clone()))? - .len() + > data_file.metadata().add_err_context(path.clone())?.len() { data_file .set_len(start_location_in_data_file + block_data.len() as u64) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; } data_file .seek(SeekFrom::Start(start_location_in_data_file)) - .map_err(|e| Error::IO(e, path.clone()))?; - data_file - .write_all(block_data) - .map_err(|e| Error::IO(e, path.clone()))?; + .add_err_context(path.clone())?; + data_file.write_all(block_data).add_err_context(path)?; + Ok(()) + } + + /// Write the hash of a single block at the specified `block_height`. + /// If `block_height` is beyond the end of the index file, attempt to + /// extend the index file. + /// + /// # Errors + /// IO Error. + pub fn write_block_hash( + &mut self, + block_height: u64, + hash: HashOf, + ) -> Result<()> { + let path = self.path_to_blockchain.join(HASHES_FILE_NAME); + let mut hashes_file = std::fs::OpenOptions::new() + .write(true) + .create(true) + .open(path.clone()) + .add_err_context(path.clone())?; + let start_location = block_height * SIZE_OF_BLOCK_HASH; + if start_location + SIZE_OF_BLOCK_HASH + > hashes_file.metadata().add_err_context(path.clone())?.len() + { + hashes_file + .set_len(start_location + SIZE_OF_BLOCK_HASH) + .add_err_context(path.clone())?; + } + hashes_file + .seek(SeekFrom::Start(start_location)) + .add_err_context(path.clone())?; + hashes_file.write_all(hash.as_ref()).add_err_context(path)?; + Ok(()) + } + + /// Write the hashes to the hashes file overwriting any previous hashes. + /// + /// # Errors + /// IO Error. + pub fn overwrite_block_hashes( + &mut self, + hashes: &[HashOf], + ) -> Result<()> { + let path = self.path_to_blockchain.join(HASHES_FILE_NAME); + let hashes_file = std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(path.clone()) + .add_err_context(path.clone())?; + let mut hashes_file = BufWriter::new(hashes_file); + for hash in hashes { + hashes_file + .write_all(hash.as_ref()) + .add_err_context(path.clone())?; + } Ok(()) } @@ -634,13 +776,19 @@ impl BlockStore { .write(true) .create(true) .open(path.clone()) - .map_err(|e| Error::IO(e, path))?; + .add_err_context(path)?; let path = self.path_to_blockchain.join(DATA_FILE_NAME); std::fs::OpenOptions::new() .write(true) .create(true) .open(path.clone()) - .map_err(|e| Error::IO(e, path))?; + .add_err_context(path)?; + let path = self.path_to_blockchain.join(HASHES_FILE_NAME); + std::fs::OpenOptions::new() + .write(true) + .create(true) + .open(path.clone()) + .add_err_context(path)?; Ok(()) } @@ -651,7 +799,8 @@ impl BlockStore { /// # Errors /// Fails if any of the required platform-specific functions /// fail. - pub fn append_block_to_chain(&mut self, block_data: &[u8]) -> Result<()> { + pub fn append_block_to_chain(&mut self, block: &VersionedCommittedBlock) -> Result<()> { + let bytes = block.encode_versioned(); let new_block_height = self.read_index_count()?; let start_location_in_data_file = if new_block_height == 0 { 0 @@ -660,12 +809,13 @@ impl BlockStore { ultimate_block.start + ultimate_block.length }; - self.write_block_data(start_location_in_data_file, block_data)?; + self.write_block_data(start_location_in_data_file, &bytes)?; self.write_block_index( new_block_height, start_location_in_data_file, - block_data.len() as u64, + bytes.len() as u64, )?; + self.write_block_hash(new_block_height, block.hash())?; Ok(()) } @@ -694,6 +844,22 @@ pub enum Error { Locked(PathBuf), /// Conversion of wide integer into narrow integer failed. This error cannot be caught at compile time at present IntConversion(#[from] std::num::TryFromIntError), + /// Blocks count differs hashes file and index file + HashesFileHeightMismatch, +} + +trait AddErrContextExt { + type Context; + + fn add_err_context(self, context: Self::Context) -> Result; +} + +impl AddErrContextExt for Result { + type Context = PathBuf; + + fn add_err_context(self, path: Self::Context) -> Result { + self.map_err(|e| Error::IO(e, path)) + } } #[allow(clippy::unwrap_used)] @@ -703,6 +869,7 @@ mod tests { use tempfile::TempDir; use super::*; + use crate::block::PendingBlock; fn indices(value: [(u64, u64); N]) -> [BlockIndex; N] { let mut ret = [BlockIndex { @@ -802,27 +969,65 @@ mod tests { let mut block_store = BlockStore::new(dir.path(), LockStatus::Unlocked); block_store.create_files_if_they_do_not_exist().unwrap(); + let dummy_block = PendingBlock::new_dummy().commit_unchecked().into(); + let append_count = 35; for _ in 0..append_count { - block_store - .append_block_to_chain(b"A hypothetical block") - .unwrap(); + block_store.append_block_to_chain(&dummy_block).unwrap(); } assert_eq!(append_count, block_store.read_index_count().unwrap()); } + #[test] + fn append_block_to_chain_increases_hashes_count() { + let dir = tempfile::tempdir().unwrap(); + let mut block_store = BlockStore::new(dir.path(), LockStatus::Unlocked); + block_store.create_files_if_they_do_not_exist().unwrap(); + + let dummy_block = PendingBlock::new_dummy().commit_unchecked().into(); + + let append_count = 35; + for _ in 0..append_count { + block_store.append_block_to_chain(&dummy_block).unwrap(); + } + + assert_eq!(append_count, block_store.read_hashes_count().unwrap()); + } + + #[test] + fn append_block_to_chain_write_correct_hashes() { + let dir = tempfile::tempdir().unwrap(); + let mut block_store = BlockStore::new(dir.path(), LockStatus::Unlocked); + block_store.create_files_if_they_do_not_exist().unwrap(); + + let dummy_block = PendingBlock::new_dummy().commit_unchecked().into(); + + let append_count = 35; + for _ in 0..append_count { + block_store.append_block_to_chain(&dummy_block).unwrap(); + } + + let block_hashes = block_store.read_block_hashes(0, append_count).unwrap(); + + for hash in block_hashes { + assert_eq!(hash, dummy_block.hash()) + } + } + #[test] fn append_block_to_chain_places_blocks_correctly_in_data_file() { let dir = tempfile::tempdir().unwrap(); let mut block_store = BlockStore::new(dir.path(), LockStatus::Unlocked); block_store.create_files_if_they_do_not_exist().unwrap(); - let block_data = b"some block data"; + let dummy_block: VersionedCommittedBlock = + PendingBlock::new_dummy().commit_unchecked().into(); + let block_data = dummy_block.encode_versioned(); let append_count = 35; for _ in 0..append_count { - block_store.append_block_to_chain(block_data).unwrap(); + block_store.append_block_to_chain(&dummy_block).unwrap(); } for i in 0..append_count { From a062515710e3bd7a3cf66fd8b6ba131ada787b19 Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Wed, 6 Sep 2023 12:34:10 +0300 Subject: [PATCH 06/55] [fix]: Don't fail if dir exists in test_env.py Signed-off-by: Shanin Roman --- scripts/test_env.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/scripts/test_env.py b/scripts/test_env.py index 93bee9cb17a..b29236f4ad9 100755 --- a/scripts/test_env.py +++ b/scripts/test_env.py @@ -26,7 +26,7 @@ class Network: def __init__(self, args: argparse.Namespace): logging.info("Setting up test environment...") peers_dir = args.out_dir.joinpath("peers") - os.mkdir(peers_dir) + os.makedirs(peers_dir, exist_ok=True) try: shutil.copy2(f"{args.root_dir}/configs/peer/config.json", peers_dir) shutil.copy2(f"{args.root_dir}/configs/peer/genesis.json", peers_dir) @@ -57,7 +57,7 @@ def wait_for_genesis(self, n_tries: int): try: with urllib.request.urlopen(f"http://{self.peers[0].host_ip}:{self.peers[0].telemetry_port}/status/blocks") as response: block_count = int(response.read()) - if block_count == 1: + if block_count > 1: logging.info(f"Genesis block created. Block count: {block_count}") return else: @@ -93,8 +93,10 @@ def __init__(self, args: argparse.Namespace, nth: int): logging.info(f"Peer {self.name} generating key pair...") - kagami = subprocess.run([f"{self.out_dir}/kagami","crypto", "-j"], - capture_output=True) + command = [f"{self.out_dir}/kagami", "crypto", "-j"] + if args.peer_name_as_seed: + command.extend(["-s", self.name]) + kagami = subprocess.run(command, capture_output=True) if kagami.returncode: logging.error("Kagami failed to generate a key pair.") sys.exit(3) @@ -109,8 +111,8 @@ def __init__(self, args: argparse.Namespace, nth: int): def run(self, is_genesis: bool = False): logging.info(f"Running peer {self.name}...") peer_dir = self.out_dir.joinpath(f"peers/{self.name}") - os.mkdir(peer_dir) - os.mkdir(peer_dir.joinpath("storage")) + os.makedirs(peer_dir, exist_ok=True) + os.makedirs(peer_dir.joinpath("storage"), exist_ok=True) os.environ["KURA_BLOCK_STORE_PATH"] = str(peer_dir.joinpath("storage")) os.environ["SNAPSHOT_DIR_PATH"] = str(peer_dir.joinpath("storage")) @@ -177,11 +179,7 @@ def main(args): def setup(args): logging.info(f"Starting iroha network with {args.n_peers} peers...") - try: - os.mkdir(args.out_dir) - except FileExistsError: - logging.error(f"Test directory `{args.out_dir}` already exists") - sys.exit(5) + os.makedirs(args.out_dir, exist_ok=True) copy_or_prompt_build_bin("iroha_client_cli", args.root_dir, args.out_dir) with open(os.path.join(args.out_dir, "metadata.json"), "w") as f: f.write('{"comment":{"String": "Hello Meta!"}}') @@ -227,6 +225,9 @@ def cleanup(args): help="Directory containing Iroha project root. \ Defaults to `.`, i.e. the directory script is being run from. \ This is used to locate the `iroha` binary and config files") + parser.add_argument("--peer-name-as-seed", action="store_true", + help="Use peer name as seed for key generation. \ + This option could be useful to preserve the same peer keys between script invocations") parser.add_argument("--verbose", "-v", action="store_true", help="Enable verbose output") From 4b3f66b04d03ed296d3bde96218f1316cabed859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Tue, 19 Sep 2023 07:58:50 +0200 Subject: [PATCH 07/55] [feature] #3355: Standardize block API (#3884) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Shanin Roman [fix] #3890: Fix validate topology on block sync Signed-off-by: Marin Veršić --- Cargo.lock | 369 +++--- cli/src/event.rs | 8 +- cli/src/lib.rs | 4 +- cli/src/stream.rs | 24 +- cli/src/torii/routing.rs | 16 +- client/benches/tps/utils.rs | 8 +- client/src/client.rs | 28 +- client/tests/integration/asset.rs | 10 +- client/tests/integration/burn_public_keys.rs | 54 +- client/tests/integration/events/data.rs | 6 +- client/tests/integration/non_mintable.rs | 6 +- client/tests/integration/queries/account.rs | 5 +- client/tests/integration/queries/asset.rs | 9 +- client/tests/integration/queries/role.rs | 8 +- client/tests/integration/restart_peer.rs | 2 +- client/tests/integration/roles.rs | 12 +- .../src/lib.rs | 4 +- client/tests/integration/transfer_asset.rs | 2 +- .../integration/triggers/data_trigger.rs | 14 +- .../integration/triggers/event_trigger.rs | 2 +- .../integration/triggers/time_trigger.rs | 9 +- client/tests/integration/unregister_peer.rs | 18 +- client/tests/integration/unstable_network.rs | 2 +- client/tests/integration/upgrade.rs | 6 +- client_cli/src/main.rs | 4 +- config/src/client.rs | 2 +- configs/peer/validator.wasm | Bin 504170 -> 492656 bytes core/Cargo.toml | 2 - core/benches/apply_blocks/apply_blocks.rs | 97 +- core/benches/kura.rs | 28 +- .../validate_blocks/validate_blocks.rs | 26 +- core/benches/validation.rs | 23 +- core/src/block.rs | 1012 ++++++++--------- core/src/block_sync.rs | 49 +- core/src/kura.rs | 175 +-- core/src/lib.rs | 10 +- core/src/smartcontracts/isi/block.rs | 12 +- core/src/smartcontracts/isi/query.rs | 65 +- core/src/smartcontracts/isi/tx.rs | 22 +- core/src/smartcontracts/wasm.rs | 8 +- core/src/snapshot.rs | 6 +- core/src/sumeragi/main_loop.rs | 685 ++++++----- core/src/sumeragi/message.rs | 98 +- core/src/sumeragi/mod.rs | 73 +- core/src/sumeragi/network_topology.rs | 162 +-- core/src/sumeragi/view_change.rs | 100 +- core/src/tx.rs | 10 +- core/src/wsv.rs | 107 +- core/test_network/src/lib.rs | 23 +- crypto/src/hash.rs | 6 +- crypto/src/lib.rs | 24 +- crypto/src/signature.rs | 171 +-- data_model/src/asset.rs | 2 + data_model/src/block.rs | 618 +++++----- data_model/src/events/data/events.rs | 70 +- data_model/src/events/execute_trigger.rs | 4 +- data_model/src/events/mod.rs | 70 +- data_model/src/events/notification.rs | 23 +- data_model/src/events/pipeline.rs | 18 +- data_model/src/events/time.rs | 2 + data_model/src/lib.rs | 28 +- data_model/src/predicate.rs | 6 +- data_model/src/query/mod.rs | 29 +- data_model/src/transaction.rs | 40 +- docs/source/references/schema.json | 148 +-- genesis/src/lib.rs | 2 +- macro/utils/Cargo.toml | 2 - primitives/src/addr.rs | 69 +- schema/gen/src/lib.rs | 45 +- tools/kagami/src/genesis.rs | 2 +- tools/kura_inspector/src/main.rs | 4 +- tools/parity_scale_decoder/src/main.rs | 16 +- 72 files changed, 2220 insertions(+), 2604 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa3ed716021..fc139524157 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -239,18 +239,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] name = "async-trait" -version = "0.1.71" +version = "0.1.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" +checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -497,7 +497,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", - "regex-automata 0.3.3", + "regex-automata 0.3.4", "serde", ] @@ -657,9 +657,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.15" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f644d0dac522c8b05ddc39aaaccc5b136d5dc4ff216610c5641e3be5becf56c" +checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" dependencies = [ "clap_builder", "clap_derive 4.3.12", @@ -668,9 +668,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.15" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af410122b9778e024f9e0fb35682cc09cc3f85cad5e8d3ba8f47a9702df6e73d" +checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" dependencies = [ "anstream", "anstyle", @@ -701,7 +701,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -1206,9 +1206,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5032837c1384de3708043de9d4e97bb91290faca6c16529a28aa340592a78166" +checksum = "f68e12e817cb19eaab81aaec582b4052d07debd3c3c6b083b9d361db47c7dc9d" dependencies = [ "cc", "cxxbridge-flags", @@ -1218,9 +1218,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51368b3d0dbf356e10fcbfd455a038503a105ee556f7ee79b6bb8c53a7247456" +checksum = "e789217e4ab7cf8cc9ce82253180a9fe331f35f5d339f0ccfe0270b39433f397" dependencies = [ "cc", "codespan-reporting", @@ -1228,24 +1228,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] name = "cxxbridge-flags" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d9062157072e4aafc8e56ceaf8325ce850c5ae37578c852a0d4de2cecdded13" +checksum = "78a19f4c80fd9ab6c882286fa865e92e07688f4387370a209508014ead8751d0" [[package]] name = "cxxbridge-macro" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf01e8a540f5a4e0f284595834f81cf88572f244b768f051724537afa99a2545" +checksum = "b8fcfa71f66c8563c4fa9dd2bb68368d50267856f831ac5d85367e0805f9606c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -1269,7 +1269,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -1280,7 +1280,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -1314,6 +1314,12 @@ dependencies = [ "const-oid", ] +[[package]] +name = "deranged" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01" + [[package]] name = "derive_more" version = "0.99.17" @@ -1392,7 +1398,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -1456,9 +1462,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elliptic-curve" @@ -1521,9 +1527,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", @@ -1588,15 +1594,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.0.0" @@ -1757,7 +1754,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -1912,8 +1909,8 @@ dependencies = [ "gix-date", "gix-diff", "gix-discover", - "gix-features", - "gix-fs", + "gix-features 0.31.1", + "gix-fs 0.3.0", "gix-glob", "gix-hash", "gix-hashtable", @@ -1979,27 +1976,27 @@ dependencies = [ [[package]] name = "gix-bitmap" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311e2fa997be6560c564b070c5da2d56d038b645a94e1e5796d5d85a350da33c" +checksum = "0aa8bbde7551a9e3e783a2871f53bbb0f50aac7a77db5680c8709f69e8ce724f" dependencies = [ "thiserror", ] [[package]] name = "gix-chunk" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39db5ed0fc0a2e9b1b8265993f7efdbc30379dec268f3b91b7af0c2de4672fdd" +checksum = "5b42ea64420f7994000130328f3c7a2038f639120518870436d31b8bde704493" dependencies = [ "thiserror", ] [[package]] name = "gix-command" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb49ab557a37b0abb2415bca2b10e541277dff0565deb5bd5e99fd95f93f51eb" +checksum = "2783ad148fb16bf9cfd46423706ba552a62a4d4a18fda5dd07648eb0228862dd" dependencies = [ "bstr", ] @@ -2012,7 +2009,7 @@ checksum = "ed42baa50075d41c1a0931074ce1a97c5797c7c6fe7591d9f1f2dcd448532c26" dependencies = [ "bstr", "gix-chunk", - "gix-features", + "gix-features 0.31.1", "gix-hash", "memmap2", "thiserror", @@ -2026,7 +2023,7 @@ checksum = "817688c7005a716d9363e267913526adea402dabd947f4ba63842d10cc5132af" dependencies = [ "bstr", "gix-config-value", - "gix-features", + "gix-features 0.31.1", "gix-glob", "gix-path", "gix-ref", @@ -2042,9 +2039,9 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83960be5e99266bcf55dae5a24731bbd39f643bfb68f27e939d6b06836b5b87d" +checksum = "6e874f41437441c02991dcea76990b9058fadfc54b02ab4dd06ab2218af43897" dependencies = [ "bitflags 2.3.3", "bstr", @@ -2071,14 +2068,14 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9a04a1d2387c955ec91059d56b673000dd24f3c07cad08ed253e36381782bf" +checksum = "56b0312dba1ad003d9b8c502bed52fbcf106f8de3a9a26bfa7b45642a6f94b72" dependencies = [ "bstr", "itoa", "thiserror", - "time 0.3.23", + "time 0.3.24", ] [[package]] @@ -2126,13 +2123,33 @@ dependencies = [ "walkdir", ] +[[package]] +name = "gix-features" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882695cccf38da4c3cc7ee687bdb412cf25e37932d7f8f2c306112ea712449f1" +dependencies = [ + "gix-hash", + "gix-trace", + "libc", +] + [[package]] name = "gix-fs" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb15956bc0256594c62a2399fcf6958a02a11724217eddfdc2b49b21b6292496" dependencies = [ - "gix-features", + "gix-features 0.31.1", +] + +[[package]] +name = "gix-fs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d5b6e9d34a2c61ea4a02bbca94c409ab6dbbca1348cbb67298cd7fed8758761" +dependencies = [ + "gix-features 0.32.1", ] [[package]] @@ -2143,15 +2160,15 @@ checksum = "c18bdff83143d61e7d60da6183b87542a870d026b2a2d0b30170b8e9c0cd321a" dependencies = [ "bitflags 2.3.3", "bstr", - "gix-features", + "gix-features 0.31.1", "gix-path", ] [[package]] name = "gix-hash" -version = "0.11.3" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0dd58cdbe7ffa4032fc111864c80d5f8cecd9a2c9736c97ae7e5be834188272" +checksum = "4b422ff2ad9a0628baaad6da468cf05385bf3f5ab495ad5a33cce99b9f41092f" dependencies = [ "hex", "thiserror", @@ -2159,9 +2176,9 @@ dependencies = [ [[package]] name = "gix-hashtable" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e133bc56d938eaec1c675af7c681a51de9662b0ada779f45607b967a10da77a" +checksum = "385f4ce6ecf3692d313ca3aa9bd3b3d8490de53368d6d94bedff3af8b6d9c58d" dependencies = [ "gix-hash", "hashbrown 0.14.0", @@ -2191,7 +2208,7 @@ dependencies = [ "btoi", "filetime", "gix-bitmap", - "gix-features", + "gix-features 0.31.1", "gix-hash", "gix-lock", "gix-object", @@ -2204,9 +2221,9 @@ dependencies = [ [[package]] name = "gix-lock" -version = "7.0.1" +version = "7.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714bcb13627995ac33716e9c5e4d25612b19947845395f64d2a9cbe6007728e4" +checksum = "7e82ec23c8a281f91044bf3ed126063b91b59f9c9340bf0ae746f385cc85a6fa" dependencies = [ "gix-tempfile", "gix-utils", @@ -2251,7 +2268,7 @@ dependencies = [ "btoi", "gix-actor", "gix-date", - "gix-features", + "gix-features 0.31.1", "gix-hash", "gix-validate", "hex", @@ -2269,7 +2286,7 @@ checksum = "f6418cff00ecc2713b58c8e04bff30dda808fbba1a080e7248b299d069894a01" dependencies = [ "arc-swap", "gix-date", - "gix-features", + "gix-features 0.31.1", "gix-hash", "gix-object", "gix-pack", @@ -2289,7 +2306,7 @@ dependencies = [ "clru", "gix-chunk", "gix-diff", - "gix-features", + "gix-features 0.31.1", "gix-hash", "gix-hashtable", "gix-object", @@ -2304,9 +2321,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfca182d2575ded2ed38280f1ebf75cd5d3790b77e0872de07854cf085821fbe" +checksum = "18609c8cbec8508ea97c64938c33cd305b75dfc04a78d0c3b78b8b3fd618a77c" dependencies = [ "bstr", "gix-trace", @@ -2317,22 +2334,22 @@ dependencies = [ [[package]] name = "gix-prompt" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dfd363fd89a40c1e7bff9c9c1b136cd2002480f724b0c627c1bc771cd5480ec" +checksum = "2f755e8eb83ee9a06642a8fbd3009b033db2b5bd774f3aaf3de0b07f9b6ebdc5" dependencies = [ "gix-command", "gix-config-value", "parking_lot", - "rustix 0.37.23", + "rustix 0.38.4", "thiserror", ] [[package]] name = "gix-quote" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3874de636c2526de26a3405b8024b23ef1a327bebf4845d770d00d48700b6a40" +checksum = "dfd80d3d0c733508df9449b1d3795da36083807e31d851d7d61d29af13bd4b0a" dependencies = [ "bstr", "btoi", @@ -2347,8 +2364,8 @@ checksum = "39453f4e5f23cddc2e6e4cca2ba20adfdbec29379e3ca829714dfe98ae068ccd" dependencies = [ "gix-actor", "gix-date", - "gix-features", - "gix-fs", + "gix-features 0.31.1", + "gix-fs 0.3.0", "gix-hash", "gix-lock", "gix-object", @@ -2406,9 +2423,9 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede298863db2a0574a14070991710551e76d1f47c9783b62d4fcbca17f56371c" +checksum = "9615cbd6b456898aeb942cd75e5810c382fbfc48dbbff2fa23ebd2d33dcbe9c7" dependencies = [ "bitflags 2.3.3", "gix-path", @@ -2418,11 +2435,11 @@ dependencies = [ [[package]] name = "gix-tempfile" -version = "7.0.0" +version = "7.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fac8310c17406ea619af72f42ee46dac795110f68f41b4f4fa231b69889c6a2" +checksum = "fa28d567848cec8fdd77d36ad4f5f78ecfaba7d78f647d4f63c8ae1a2cec7243" dependencies = [ - "gix-fs", + "gix-fs 0.4.1", "libc", "once_cell", "parking_lot", @@ -2433,9 +2450,9 @@ dependencies = [ [[package]] name = "gix-trace" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "103eac621617be3ebe0605c9065ca51a223279a23218aaf67d10daa6e452f663" +checksum = "96b6d623a1152c3facb79067d6e2ecdae48130030cf27d6eb21109f13bd7b836" [[package]] name = "gix-traverse" @@ -2460,7 +2477,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "beaede6dbc83f408b19adfd95bb52f1dbf01fb8862c3faf6c6243e2e67fcdfa1" dependencies = [ "bstr", - "gix-features", + "gix-features 0.31.1", "gix-path", "home", "thiserror", @@ -2469,18 +2486,18 @@ dependencies = [ [[package]] name = "gix-utils" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7058c94f4164fcf5b8457d35f6d8f6e1007f9f7f938c9c7684a7e01d23c6ddde" +checksum = "b85d89dc728613e26e0ed952a19583744e7f5240fcd4aa30d6c824ffd8b52f0f" dependencies = [ - "fastrand 2.0.0", + "fastrand", ] [[package]] name = "gix-validate" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d092b594c8af00a3a31fe526d363ee8a51a6f29d8496cdb991ed2f01ec0ec13" +checksum = "ba9b3737b2cef3dcd014633485f0034b0f1a931ee54aeb7d8f87f177f3c89040" dependencies = [ "bstr", "thiserror", @@ -2495,8 +2512,8 @@ dependencies = [ "bstr", "filetime", "gix-attributes", - "gix-features", - "gix-fs", + "gix-features 0.31.1", + "gix-fs 0.3.0", "gix-glob", "gix-hash", "gix-ignore", @@ -2864,15 +2881,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "int_traits" version = "0.1.1" @@ -3092,7 +3100,6 @@ dependencies = [ "parity-scale-codec", "parking_lot", "rand 0.8.5", - "sealed", "serde", "serde_json", "tempfile", @@ -3186,7 +3193,7 @@ dependencies = [ "manyhow", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", "trybuild", ] @@ -3227,7 +3234,7 @@ dependencies = [ "proc-macro2", "quote", "rustc-hash", - "syn 2.0.26", + "syn 2.0.28", "trybuild", ] @@ -3363,7 +3370,7 @@ dependencies = [ "manyhow", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -3387,7 +3394,7 @@ dependencies = [ "manyhow", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", "trybuild", ] @@ -3410,7 +3417,7 @@ version = "2.0.0-pre-rc.19" name = "iroha_swarm" version = "2.0.0-pre-rc.19" dependencies = [ - "clap 4.3.15", + "clap 4.3.19", "color-eyre", "derive_more", "expect-test", @@ -3490,7 +3497,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.26", + "syn 2.0.28", "trybuild", ] @@ -3509,7 +3516,7 @@ dependencies = [ name = "iroha_wasm_builder_cli" version = "2.0.0-pre-rc.19" dependencies = [ - "clap 4.3.15", + "clap 4.3.19", "color-eyre", "iroha_wasm_builder", "owo-colors", @@ -3623,7 +3630,7 @@ dependencies = [ name = "kagami" version = "2.0.0-pre-rc.19" dependencies = [ - "clap 4.3.15", + "clap 4.3.19", "color-eyre", "derive_more", "iroha_config", @@ -3659,7 +3666,7 @@ dependencies = [ name = "kura_inspector" version = "2.0.0-pre-rc.19" dependencies = [ - "clap 4.3.15", + "clap 4.3.19", "iroha_core", "iroha_data_model", "iroha_version", @@ -3755,7 +3762,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -3780,9 +3787,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +checksum = "67827e6ea8ee8a7c4a72227ef4fc08957040acffdb5f122733b24fa12daff41b" [[package]] name = "memchr" @@ -3942,9 +3949,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg 1.1.0", "libm", @@ -4037,7 +4044,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -4119,7 +4126,7 @@ dependencies = [ name = "parity_scale_decoder" version = "2.0.0-pre-rc.19" dependencies = [ - "clap 4.3.15", + "clap 4.3.19", "colored", "eyre", "iroha_crypto", @@ -4183,7 +4190,7 @@ dependencies = [ "regex", "regex-syntax 0.7.4", "structmeta", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -4252,7 +4259,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -4293,7 +4300,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -4533,9 +4540,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -4789,7 +4796,7 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.3", + "regex-automata 0.3.4", "regex-syntax 0.7.4", ] @@ -4804,9 +4811,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" dependencies = [ "aho-corasick", "memchr", @@ -4933,18 +4940,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" -[[package]] -name = "sealed" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.26", -] - [[package]] name = "secp256k1" version = "0.19.0" @@ -4967,9 +4962,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -4980,9 +4975,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -4996,9 +4991,9 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.171" +version = "1.0.179" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" +checksum = "0a5bf42b8d227d4abf38a1ddb08602e229108a517cd4e5bb28f9c7eaafdce5c0" dependencies = [ "serde_derive", ] @@ -5024,20 +5019,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.171" +version = "1.0.179" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" +checksum = "741e124f5485c7e60c03b043f79f320bff3527f4bbf12cf3831750dc46a0ec2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] name = "serde_json" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -5075,14 +5070,14 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] name = "serde_yaml" -version = "0.9.24" +version = "0.9.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5f51e3fdb5b9cdd1577e1cb7a733474191b1aca6a72c2e50913241632c1180" +checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" dependencies = [ "indexmap 2.0.0", "itoa", @@ -5237,9 +5232,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "signal-hook" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b824b6e687aff278cdbf3b36f07aa52d4bd4099699324d5da86a2ebce3aa00b3" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", @@ -5387,7 +5382,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -5398,7 +5393,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -5471,9 +5466,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.26" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -5506,21 +5501,20 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.9" +version = "0.12.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8e77cb757a61f51b947ec4a7e3646efd825b73561db1c232a8ccb639e611a0" +checksum = "1d2faeef5759ab89935255b1a4cd98e0baf99d1085e37d36599c625dac49ae8e" [[package]] name = "tempfile" -version = "3.6.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" dependencies = [ - "autocfg 1.1.0", "cfg-if", - "fastrand 1.9.0", + "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.23", + "rustix 0.38.4", "windows-sys 0.48.0", ] @@ -5573,22 +5567,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -5631,10 +5625,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b" dependencies = [ + "deranged", "itoa", "libc", "num_threads", @@ -5651,9 +5646,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" dependencies = [ "time-core", ] @@ -5721,7 +5716,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -5904,7 +5899,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -5918,7 +5913,7 @@ dependencies = [ "log", "serde", "serde_json", - "time 0.3.23", + "time 0.3.24", "tracing", "tracing-core", "tracing-log", @@ -6002,9 +5997,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "trybuild" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04366e99ff743345622cd00af2af01d711dc2d1ef59250d7347698d21b546729" +checksum = "a84e0202ea606ba5ebee8507ab2bfbe89b98551ed9b8f0be198109275cff284b" dependencies = [ "basic-toml", "glob", @@ -6269,7 +6264,7 @@ dependencies = [ "anyhow", "gix", "rustversion", - "time 0.3.23", + "time 0.3.24", ] [[package]] @@ -6376,7 +6371,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -6398,7 +6393,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6411,9 +6406,9 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-encoder" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06a3d1b4a575ffb873679402b2aedb3117555eb65c27b1b86c8a91e574bc2a2a" +checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" dependencies = [ "leb128", ] @@ -6723,9 +6718,9 @@ dependencies = [ [[package]] name = "wast" -version = "62.0.0" +version = "62.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f7ee878019d69436895f019b65f62c33da63595d8e857cbdc87c13ecb29a32" +checksum = "b8ae06f09dbe377b889fbd620ff8fa21e1d49d1d9d364983c0cdbf9870cb9f1f" dependencies = [ "leb128", "memchr", @@ -6735,9 +6730,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "295572bf24aa5b685a971a83ad3e8b6e684aaad8a9be24bc7bf59bed84cc1c08" +checksum = "842e15861d203fb4a96d314b0751cdeaf0f6f8b35e8d81d2953af2af5e44e637" dependencies = [ "wast", ] @@ -6942,9 +6937,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" +checksum = "8bd122eb777186e60c3fdf765a58ac76e41c582f1f535fbf3314434c6b58f3f7" dependencies = [ "memchr", ] @@ -7002,7 +6997,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] diff --git a/cli/src/event.rs b/cli/src/event.rs index 601ab41bb6f..817310f1aab 100644 --- a/cli/src/event.rs +++ b/cli/src/event.rs @@ -14,7 +14,7 @@ use warp::ws::WebSocket; use crate::stream::{self, Sink, Stream}; /// Type of Stream error -pub type StreamError = stream::Error<>::Err>; +pub type StreamError = stream::Error<>::Err>; /// Type of error for `Consumer` #[derive(thiserror::Error, Debug)] @@ -57,9 +57,7 @@ impl Consumer { /// Can fail due to timeout or without message at websocket or during decoding request #[iroha_futures::telemetry_future] pub async fn new(mut stream: WebSocket) -> Result { - let subscription_request: VersionedEventSubscriptionRequest = stream.recv().await?; - let EventSubscriptionRequest(filter) = subscription_request.into_v1(); - + let EventSubscriptionRequest(filter) = stream.recv().await?; Ok(Consumer { stream, filter }) } @@ -74,7 +72,7 @@ impl Consumer { } self.stream - .send(VersionedEventMessage::from(EventMessage(event))) + .send(EventMessage(event)) .await .map_err(Into::into) } diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 802f9fbc38c..44efca1113f 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -160,9 +160,9 @@ impl NetworkRelay { match msg { SumeragiPacket(data) => { - self.sumeragi.incoming_message(data.into_v1()); + self.sumeragi.incoming_message(*data); } - BlockSync(data) => self.block_sync.message(data.into_v1()).await, + BlockSync(data) => self.block_sync.message(*data).await, TransactionGossiper(data) => self.gossiper.gossip(*data).await, Health => {} } diff --git a/cli/src/stream.rs b/cli/src/stream.rs index 340923c9426..b776907260c 100644 --- a/cli/src/stream.rs +++ b/cli/src/stream.rs @@ -6,6 +6,7 @@ use core::{result::Result, time::Duration}; use futures::{SinkExt, StreamExt}; use iroha_version::prelude::*; +use parity_scale_codec::DecodeAll; #[cfg(test)] const TIMEOUT: Duration = Duration::from_millis(10_000); @@ -34,7 +35,7 @@ where /// Unexpected non-binary message received NonBinaryMessage, /// Error during versioned message decoding - IrohaVersion(#[from] iroha_version::error::Error), + Decode(#[from] parity_scale_codec::Error), } /// Represents message used by the stream @@ -56,7 +57,7 @@ pub trait StreamMessage { #[async_trait::async_trait] pub trait Sink: SinkExt + Unpin where - S: EncodeVersioned + Send + Sync + 'static, + S: Encode + Send + Sync + 'static, { /// Error type returned by the sink type Err: std::error::Error + Send + Sync + 'static; @@ -68,10 +69,7 @@ where async fn send(&mut self, message: S) -> Result<(), Error> { tokio::time::timeout( TIMEOUT, - >::send( - self, - Self::Message::binary(message.encode_versioned()), - ), + >::send(self, Self::Message::binary(message.encode())), ) .await .map_err(|_err| Error::SendTimeout)? @@ -81,7 +79,7 @@ where /// Trait for reading custom messages from stream #[async_trait::async_trait] -pub trait Stream: +pub trait Stream: StreamExt> + Unpin { /// Error type returned by the stream @@ -106,9 +104,7 @@ pub trait Stream: return Err(Error::NonBinaryMessage); } - Ok(R::decode_all_versioned( - subscription_request_message.as_bytes(), - )?) + Ok(R::decode_all(&mut subscription_request_message.as_bytes())?) } } @@ -133,14 +129,14 @@ impl StreamMessage for warp::ws::Message { #[async_trait::async_trait] impl Sink for warp::ws::WebSocket where - M: EncodeVersioned + Send + Sync + 'static, + M: Encode + Send + Sync + 'static, { type Err = warp::Error; type Message = warp::ws::Message; } #[async_trait::async_trait] -impl Stream for warp::ws::WebSocket { +impl Stream for warp::ws::WebSocket { type Err = warp::Error; type Message = warp::ws::Message; } @@ -152,14 +148,14 @@ mod ws_client { use super::*; #[async_trait::async_trait] - impl Stream for WsClient { + impl Stream for WsClient { type Err = warp::test::WsError; type Message = warp::ws::Message; } #[async_trait::async_trait] impl Sink for WsClient where - M: EncodeVersioned + Send + Sync + 'static, + M: Encode + Send + Sync + 'static, { type Err = warp::test::WsError; type Message = warp::ws::Message; diff --git a/cli/src/torii/routing.rs b/cli/src/torii/routing.rs index 468a95b877e..8397a3e505f 100644 --- a/cli/src/torii/routing.rs +++ b/cli/src/torii/routing.rs @@ -25,11 +25,8 @@ use iroha_core::{ }; use iroha_data_model::{ block::{ - stream::{ - BlockMessage, BlockSubscriptionRequest, VersionedBlockMessage, - VersionedBlockSubscriptionRequest, - }, - VersionedCommittedBlock, + stream::{BlockMessage, BlockSubscriptionRequest}, + VersionedSignedBlock, }, http::{BatchedResponse, VersionedBatchedResponse}, prelude::*, @@ -278,8 +275,7 @@ async fn handle_post_configuration( #[iroha_futures::telemetry_future] async fn handle_blocks_stream(kura: Arc, mut stream: WebSocket) -> eyre::Result<()> { - let subscription_request: VersionedBlockSubscriptionRequest = stream.recv().await?; - let BlockSubscriptionRequest(mut from_height) = subscription_request.into_v1(); + let BlockSubscriptionRequest(mut from_height) = stream.recv().await?; let mut interval = tokio::time::interval(std::time::Duration::from_millis(10)); loop { @@ -307,10 +303,8 @@ async fn handle_blocks_stream(kura: Arc, mut stream: WebSocket) -> eyre::R _ = interval.tick() => { if let Some(block) = kura.get_block_by_height(from_height.get()) { stream - // TODO: to avoid clone `VersionedBlockMessage` could be split into sending and receiving parts - .send(VersionedBlockMessage::from( - BlockMessage(VersionedCommittedBlock::clone(&block)), - )) + // TODO: to avoid clone `BlockMessage` could be split into sending and receiving parts + .send(BlockMessage(VersionedSignedBlock::clone(&block))) .await?; from_height = from_height.checked_add(1).expect("Maximum block height is achieved."); } diff --git a/client/benches/tps/utils.rs b/client/benches/tps/utils.rs index a16fb8c6ecf..66f8bb01599 100644 --- a/client/benches/tps/utils.rs +++ b/client/benches/tps/utils.rs @@ -132,14 +132,15 @@ impl Config { let block = blocks .next() .expect("The block is not yet in WSV. Need more sleep?"); - let block = block.as_v1(); ( block + .payload() .transactions .iter() .filter(|tx| tx.error.is_none()) .count(), block + .payload() .transactions .iter() .filter(|tx| tx.error.is_some()) @@ -173,7 +174,7 @@ impl MeasurerUnit { let keypair = iroha_crypto::KeyPair::generate().expect("Failed to generate KeyPair."); let account_id = account_id(self.name); - let alice_id = ::Id::from_str("alice@wonderland")?; + let alice_id = AccountId::from_str("alice@wonderland")?; let asset_id = asset_id(self.name); let register_me = RegisterBox::new(Account::new( @@ -238,8 +239,7 @@ impl MeasurerUnit { let submitter = self.client.clone(); let interval_us_per_tx = self.config.interval_us_per_tx; let instructions = self.instructions(); - let alice_id = ::Id::from_str("alice@wonderland") - .expect("Failed to parse account id"); + let alice_id = AccountId::from_str("alice@wonderland").expect("Failed to parse account id"); let mut nonce = NonZeroU32::new(1).expect("Valid"); diff --git a/client/src/client.rs b/client/src/client.rs index 46f0b6acd5f..e4fceccb515 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -21,7 +21,7 @@ use http_default::{AsyncWebSocketStream, WebSocketStream}; use iroha_config::{client::Configuration, torii::uri, GetConfiguration, PostConfiguration}; use iroha_crypto::{HashOf, KeyPair}; use iroha_data_model::{ - block::VersionedCommittedBlock, + block::VersionedSignedBlock, http::VersionedBatchedResponse, isi::Instruction, predicate::PredicateBox, @@ -654,7 +654,7 @@ impl Client { PipelineStatus::Rejected(ref reason) => { return Err(reason.clone().into()); } - PipelineStatus::Committed => return Ok(hash.transmute()), + PipelineStatus::Committed => return Ok(hash), } } } @@ -1036,7 +1036,7 @@ impl Client { pub fn listen_for_blocks( &self, height: NonZeroU64, - ) -> Result>> { + ) -> Result>> { blocks_api::BlockIterator::new(self.blocks_handler(height)?) } @@ -1448,10 +1448,7 @@ pub mod events_api { url, } = self; - let msg = - VersionedEventSubscriptionRequest::from(EventSubscriptionRequest::new(filter)) - .encode_versioned(); - + let msg = EventSubscriptionRequest::new(filter).encode(); InitData::new(R::new(HttpMethod::GET, url).headers(headers), msg, Events) } } @@ -1464,8 +1461,7 @@ pub mod events_api { type Event = iroha_data_model::prelude::Event; fn message(&self, message: Vec) -> Result { - let event_socket_message = - VersionedEventMessage::decode_all_versioned(&message)?.into_v1(); + let event_socket_message = EventMessage::decode_all(&mut message.as_slice())?; Ok(event_socket_message.into()) } } @@ -1532,10 +1528,7 @@ mod blocks_api { url, } = self; - let msg = - VersionedBlockSubscriptionRequest::from(BlockSubscriptionRequest::new(height)) - .encode_versioned(); - + let msg = BlockSubscriptionRequest::new(height).encode(); InitData::new(R::new(HttpMethod::GET, url).headers(headers), msg, Events) } } @@ -1545,11 +1538,10 @@ mod blocks_api { pub struct Events; impl FlowEvents for Events { - type Event = iroha_data_model::block::VersionedCommittedBlock; + type Event = iroha_data_model::block::VersionedSignedBlock; fn message(&self, message: Vec) -> Result { - let block_msg = VersionedBlockMessage::decode_all_versioned(&message)?.into_v1(); - Ok(block_msg.into()) + Ok(BlockMessage::decode_all(&mut message.as_slice()).map(Into::into)?) } } } @@ -1610,7 +1602,7 @@ pub mod asset { } /// Construct a query to get an asset by its id - pub fn by_id(asset_id: impl Into::Id>>) -> FindAssetById { + pub fn by_id(asset_id: impl Into>) -> FindAssetById { FindAssetById::new(asset_id) } } @@ -1632,7 +1624,7 @@ pub mod block { /// Construct a query to find block header by hash pub fn header_by_hash( - hash: impl Into>>, + hash: impl Into>>, ) -> FindBlockHeaderByHash { FindBlockHeaderByHash::new(hash) } diff --git a/client/tests/integration/asset.rs b/client/tests/integration/asset.rs index bd9cde52c1e..56f363dfbb6 100644 --- a/client/tests/integration/asset.rs +++ b/client/tests/integration/asset.rs @@ -14,7 +14,7 @@ use super::Configuration; #[test] fn client_register_asset_should_add_asset_once_but_not_twice() -> Result<()> { - let (_rt, _peer, mut test_client) = ::new().with_port(10_620).start_with_runtime(); + let (_rt, _peer, test_client) = ::new().with_port(10_620).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); // Given @@ -48,7 +48,7 @@ fn client_register_asset_should_add_asset_once_but_not_twice() -> Result<()> { #[test] fn unregister_asset_should_remove_asset_from_account() -> Result<()> { - let (_rt, _peer, mut test_client) = ::new().with_port(10_555).start_with_runtime(); + let (_rt, _peer, test_client) = ::new().with_port(10_555).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); // Given @@ -87,7 +87,7 @@ fn unregister_asset_should_remove_asset_from_account() -> Result<()> { #[test] fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount() -> Result<()> { - let (_rt, _peer, mut test_client) = ::new().with_port(10_000).start_with_runtime(); + let (_rt, _peer, test_client) = ::new().with_port(10_000).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); // Given @@ -120,7 +120,7 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount() -> #[test] fn client_add_big_asset_quantity_to_existing_asset_should_increase_asset_amount() -> Result<()> { - let (_rt, _peer, mut test_client) = ::new().with_port(10_510).start_with_runtime(); + let (_rt, _peer, test_client) = ::new().with_port(10_510).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); // Given @@ -153,7 +153,7 @@ fn client_add_big_asset_quantity_to_existing_asset_should_increase_asset_amount( #[test] fn client_add_asset_with_decimal_should_increase_asset_amount() -> Result<()> { - let (_rt, _peer, mut test_client) = ::new().with_port(10_515).start_with_runtime(); + let (_rt, _peer, test_client) = ::new().with_port(10_515).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); // Given diff --git a/client/tests/integration/burn_public_keys.rs b/client/tests/integration/burn_public_keys.rs index aece78e66ce..2e93c816daf 100644 --- a/client/tests/integration/burn_public_keys.rs +++ b/client/tests/integration/burn_public_keys.rs @@ -1,15 +1,18 @@ #![allow(clippy::pedantic, clippy::restriction)] use iroha_client::client::{account, transaction, Client}; -use iroha_crypto::{KeyPair, PublicKey}; -use iroha_data_model::{isi::Instruction, prelude::*}; +use iroha_crypto::{HashOf, KeyPair, PublicKey}; +use iroha_data_model::{isi::Instruction, prelude::*, transaction::TransactionPayload}; use test_network::*; -fn submit_and_get( - client: &mut Client, +fn submit( + client: &Client, instructions: impl IntoIterator, submitter: Option<(AccountId, KeyPair)>, -) -> TransactionValue { +) -> ( + HashOf, + eyre::Result>, +) { let tx = if let Some((account_id, keypair)) = submitter { TransactionBuilder::new(account_id) .with_instructions(instructions) @@ -22,16 +25,17 @@ fn submit_and_get( client.sign_transaction(tx).unwrap() }; - let hash = tx.hash(); - let _ = client.submit_transaction_blocking(&tx); + (tx.hash(), client.submit_transaction_blocking(&tx)) +} +fn get(client: &Client, hash: HashOf) -> TransactionValue { client .request(transaction::by_hash(hash)) .unwrap() .transaction } -fn account_keys_count(client: &mut Client, account_id: AccountId) -> usize { +fn account_keys_count(client: &Client, account_id: AccountId) -> usize { let account = client.request(account::by_id(account_id)).unwrap(); let signatories = account.signatories(); signatories.len() @@ -41,9 +45,9 @@ fn account_keys_count(client: &mut Client, account_id: AccountId) -> usize { fn public_keys_cannot_be_burned_to_nothing() { const KEYS_COUNT: usize = 3; let charlie_id: AccountId = "charlie@wonderland".parse().expect("Valid"); - let charlie_keys_count = |client: &mut Client| account_keys_count(client, charlie_id.clone()); + let charlie_keys_count = |client: &Client| account_keys_count(client, charlie_id.clone()); - let (_rt, _peer, mut client) = ::new().with_port(10_045).start_with_runtime(); + let (_rt, _peer, client) = ::new().with_port(10_045).start_with_runtime(); wait_for_genesis_committed(&vec![client.clone()], 0); let charlie_initial_keypair = KeyPair::generate().unwrap(); @@ -52,8 +56,10 @@ fn public_keys_cannot_be_burned_to_nothing() { [charlie_initial_keypair.public_key().clone()], )); - let _unused = submit_and_get(&mut client, [register_charlie], None); - let mut keys_count = charlie_keys_count(&mut client); + let (tx_hash, res) = submit(&client, [register_charlie], None); + res.unwrap(); + get(&client, tx_hash); + let mut keys_count = charlie_keys_count(&client); assert_eq!(keys_count, 1); let mint_keys = (0..KEYS_COUNT - 1).map(|_| { @@ -61,12 +67,14 @@ fn public_keys_cannot_be_burned_to_nothing() { MintBox::new(public_key, charlie_id.clone()) }); - let _unused = submit_and_get( - &mut client, + let (tx_hash, res) = submit( + &client, mint_keys, Some((charlie_id.clone(), charlie_initial_keypair.clone())), ); - keys_count = charlie_keys_count(&mut client); + res.unwrap(); + get(&client, tx_hash); + keys_count = charlie_keys_count(&client); assert_eq!(keys_count, KEYS_COUNT); let charlie = client.request(account::by_id(charlie_id.clone())).unwrap(); @@ -78,23 +86,27 @@ fn public_keys_cannot_be_burned_to_nothing() { .cloned() .map(burn); - let mut committed_txn = submit_and_get( - &mut client, + let (tx_hash, res) = submit( + &client, burn_keys_leaving_one, Some((charlie_id.clone(), charlie_initial_keypair.clone())), ); - keys_count = charlie_keys_count(&mut client); + res.unwrap(); + let committed_txn = get(&client, tx_hash); + keys_count = charlie_keys_count(&client); assert_eq!(keys_count, 1); assert!(committed_txn.error.is_none()); let burn_the_last_key = burn(charlie_initial_keypair.public_key().clone()); - committed_txn = submit_and_get( - &mut client, + let (tx_hash, res) = submit( + &client, std::iter::once(burn_the_last_key), Some((charlie_id.clone(), charlie_initial_keypair)), ); - keys_count = charlie_keys_count(&mut client); + assert!(res.is_err()); + let committed_txn = get(&client, tx_hash); + keys_count = charlie_keys_count(&client); assert_eq!(keys_count, 1); assert!(committed_txn.error.is_some()); } diff --git a/client/tests/integration/events/data.rs b/client/tests/integration/events/data.rs index 51c2f245f9c..a9430daff13 100644 --- a/client/tests/integration/events/data.rs +++ b/client/tests/integration/events/data.rs @@ -162,8 +162,8 @@ fn produce_multiple_events() -> Result<()> { init_receiver.recv()?; // Registering role - let alice_id = ::Id::from_str("alice@wonderland")?; - let role_id = ::Id::from_str("TEST_ROLE")?; + let alice_id = AccountId::from_str("alice@wonderland")?; + let role_id = RoleId::from_str("TEST_ROLE")?; let token_1 = PermissionToken::new( "CanRemoveKeyValueInUserAccount".parse()?, &json!({ "account_id": alice_id }), @@ -179,7 +179,7 @@ fn produce_multiple_events() -> Result<()> { client.submit_all_blocking(instructions)?; // Grants role to Bob - let bob_id = ::Id::from_str("bob@wonderland")?; + let bob_id = AccountId::from_str("bob@wonderland")?; let grant_role = GrantBox::new(role_id.clone(), bob_id.clone()); client.submit_blocking(grant_role)?; diff --git a/client/tests/integration/non_mintable.rs b/client/tests/integration/non_mintable.rs index 404ad8d3192..636d05fd8e6 100644 --- a/client/tests/integration/non_mintable.rs +++ b/client/tests/integration/non_mintable.rs @@ -9,7 +9,7 @@ use test_network::*; #[test] fn non_mintable_asset_can_be_minted_once_but_not_twice() -> Result<()> { - let (_rt, _peer, mut test_client) = ::new().with_port(10_625).start_with_runtime(); + let (_rt, _peer, test_client) = ::new().with_port(10_625).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); // Given @@ -59,7 +59,7 @@ fn non_mintable_asset_can_be_minted_once_but_not_twice() -> Result<()> { #[test] fn non_mintable_asset_cannot_be_minted_if_registered_with_non_zero_value() -> Result<()> { - let (_rt, _peer, mut test_client) = ::new().with_port(10_610).start_with_runtime(); + let (_rt, _peer, test_client) = ::new().with_port(10_610).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); // Given @@ -93,7 +93,7 @@ fn non_mintable_asset_cannot_be_minted_if_registered_with_non_zero_value() -> Re #[test] fn non_mintable_asset_can_be_minted_if_registered_with_zero_value() -> Result<()> { - let (_rt, _peer, mut test_client) = ::new().with_port(10_630).start_with_runtime(); + let (_rt, _peer, test_client) = ::new().with_port(10_630).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); // Given diff --git a/client/tests/integration/queries/account.rs b/client/tests/integration/queries/account.rs index f9a07b84560..7791c7da327 100644 --- a/client/tests/integration/queries/account.rs +++ b/client/tests/integration/queries/account.rs @@ -13,8 +13,7 @@ fn find_accounts_with_asset() -> Result<()> { wait_for_genesis_committed(&[test_client.clone()], 0); // Registering new asset definition - let definition_id = - ::Id::from_str("test_coin#wonderland").expect("Valid"); + let definition_id = AssetDefinitionId::from_str("test_coin#wonderland").expect("Valid"); let asset_definition = AssetDefinition::quantity(definition_id.clone()); test_client.submit_blocking(RegisterBox::new(asset_definition.clone()))?; @@ -48,7 +47,7 @@ fn find_accounts_with_asset() -> Result<()> { let mint_asset = accounts .iter() .cloned() - .map(|account_id| ::Id::new(definition_id.clone(), account_id)) + .map(|account_id| AssetId::new(definition_id.clone(), account_id)) .map(|asset_id| MintBox::new(1_u32, asset_id)) .collect::>(); test_client.submit_all_blocking(mint_asset)?; diff --git a/client/tests/integration/queries/asset.rs b/client/tests/integration/queries/asset.rs index 79b94d3dc38..27e8912ef9c 100644 --- a/client/tests/integration/queries/asset.rs +++ b/client/tests/integration/queries/asset.rs @@ -78,7 +78,7 @@ fn find_asset_total_quantity() -> Result<()> { ), ] { // Registering new asset definition - let definition_id: ::Id = + let definition_id: AssetDefinitionId = definition.parse().expect("Failed to parse `definition_id`"); let asset_definition = AssetDefinition::new(definition_id.clone(), asset_value_type); test_client.submit_blocking(RegisterBox::new(asset_definition.clone()))?; @@ -86,7 +86,7 @@ fn find_asset_total_quantity() -> Result<()> { let asset_ids = accounts .iter() .cloned() - .map(|account_id| ::Id::new(definition_id.clone(), account_id)) + .map(|account_id| AssetId::new(definition_id.clone(), account_id)) .collect::>(); // Assert that initial total quantity before any burns and mints is zero @@ -151,15 +151,14 @@ fn find_asset_total_quantity() -> Result<()> { } // Test for `Store` asset value type - let definition_id: ::Id = - "store#wonderland".parse().expect("Valid"); + let definition_id: AssetDefinitionId = "store#wonderland".parse().expect("Valid"); let asset_definition = AssetDefinition::store(definition_id.clone()); test_client.submit_blocking(RegisterBox::new(asset_definition))?; let asset_ids = accounts .iter() .cloned() - .map(|account_id| ::Id::new(definition_id.clone(), account_id)) + .map(|account_id| AssetId::new(definition_id.clone(), account_id)) .collect::>(); // Assert that initial total quantity before any registrations and unregistrations is zero diff --git a/client/tests/integration/queries/role.rs b/client/tests/integration/queries/role.rs index 36f42004123..f2d88d573ec 100644 --- a/client/tests/integration/queries/role.rs +++ b/client/tests/integration/queries/role.rs @@ -8,7 +8,7 @@ use iroha_data_model::{prelude::*, query::error::QueryExecutionFail}; use serde_json::json; use test_network::*; -fn create_role_ids() -> [::Id; 5] { +fn create_role_ids() -> [RoleId; 5] { [ "a".parse().expect("Valid"), "b".parse().expect("Valid"), @@ -83,7 +83,7 @@ fn find_role_by_id() -> Result<()> { let (_rt, _peer, test_client) = ::new().with_port(10_535).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); - let role_id: ::Id = "root".parse().expect("Valid"); + let role_id: RoleId = "root".parse().expect("Valid"); let new_role = Role::new(role_id.clone()); // Registering role @@ -103,7 +103,7 @@ fn find_unregistered_role_by_id() { let (_rt, _peer, test_client) = ::new().with_port(10_540).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); - let role_id: ::Id = "root".parse().expect("Valid"); + let role_id: RoleId = "root".parse().expect("Valid"); let found_role = test_client.request(client::role::by_id(role_id)); @@ -123,7 +123,7 @@ fn find_roles_by_account_id() -> Result<()> { wait_for_genesis_committed(&[test_client.clone()], 0); let role_ids = create_role_ids(); - let alice_id: ::Id = "alice@wonderland".parse().expect("Valid"); + let alice_id: AccountId = "alice@wonderland".parse().expect("Valid"); // Registering roles let register_roles = role_ids diff --git a/client/tests/integration/restart_peer.rs b/client/tests/integration/restart_peer.rs index dbc4f2cd082..6044faeebab 100644 --- a/client/tests/integration/restart_peer.rs +++ b/client/tests/integration/restart_peer.rs @@ -24,7 +24,7 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); let quantity: u32 = 200; - let mut iroha_client = client::Client::test(&peer.api_address, &peer.telemetry_address); + let iroha_client = client::Client::test(&peer.api_address, &peer.telemetry_address); { let rt = Runtime::test(); diff --git a/client/tests/integration/roles.rs b/client/tests/integration/roles.rs index 7a030a76053..60ae9fb97f5 100644 --- a/client/tests/integration/roles.rs +++ b/client/tests/integration/roles.rs @@ -48,8 +48,8 @@ fn register_and_grant_role_for_metadata_access() -> Result<()> { let (_rt, _peer, test_client) = ::new().with_port(10_700).start_with_runtime(); wait_for_genesis_committed(&vec![test_client.clone()], 0); - let alice_id = ::Id::from_str("alice@wonderland")?; - let mouse_id = ::Id::from_str("mouse@wonderland")?; + let alice_id = AccountId::from_str("alice@wonderland")?; + let mouse_id = AccountId::from_str("mouse@wonderland")?; // Registering Mouse let mouse_key_pair = iroha_crypto::KeyPair::generate()?; @@ -60,7 +60,7 @@ fn register_and_grant_role_for_metadata_access() -> Result<()> { test_client.submit_blocking(register_mouse)?; // Registering role - let role_id = ::Id::from_str("ACCESS_TO_MOUSE_METADATA")?; + let role_id = RoleId::from_str("ACCESS_TO_MOUSE_METADATA")?; let role = Role::new(role_id.clone()) .add_permission(PermissionToken::new( "CanSetKeyValueInUserAccount".parse()?, @@ -102,9 +102,9 @@ fn unregistered_role_removed_from_account() -> Result<()> { let (_rt, _peer, test_client) = ::new().with_port(10_705).start_with_runtime(); wait_for_genesis_committed(&vec![test_client.clone()], 0); - let role_id: ::Id = "root".parse().expect("Valid"); - let alice_id: ::Id = "alice@wonderland".parse().expect("Valid"); - let mouse_id: ::Id = "mouse@wonderland".parse().expect("Valid"); + let role_id: RoleId = "root".parse().expect("Valid"); + let alice_id: AccountId = "alice@wonderland".parse().expect("Valid"); + let mouse_id: AccountId = "mouse@wonderland".parse().expect("Valid"); // Registering Mouse let register_mouse = RegisterBox::new(Account::new(mouse_id.clone(), [])); diff --git a/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs b/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs index 5a01c663f5f..75de8cd08f4 100644 --- a/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs +++ b/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs @@ -35,7 +35,7 @@ fn main(_owner: AccountId, _event: Event) { let nft_definition = AssetDefinition::store(nft_id.clone()) .mintable_once() .with_metadata(metadata); - let account_nft_id = ::Id::new(nft_id, account.id().clone()); + let account_nft_id = AssetId::new(nft_id, account.id().clone()); let account_nft = Asset::new(account_nft_id, Metadata::new()); RegisterBox::new(nft_definition).execute().dbg_unwrap(); @@ -45,7 +45,7 @@ fn main(_owner: AccountId, _event: Event) { iroha_trigger::info!("Smart contract executed successfully"); } -fn generate_new_nft_id(account_id: &::Id) -> AssetDefinitionId { +fn generate_new_nft_id(account_id: &AccountId) -> AssetDefinitionId { let assets = FindAssetsByAccountId::new(account_id.clone()) .execute() .dbg_unwrap(); diff --git a/client/tests/integration/transfer_asset.rs b/client/tests/integration/transfer_asset.rs index 674a1fa405e..e473b61b088 100644 --- a/client/tests/integration/transfer_asset.rs +++ b/client/tests/integration/transfer_asset.rs @@ -51,7 +51,7 @@ fn simulate_transfer< ) where Value: From, { - let (_rt, _peer, mut iroha_client) = ::new() + let (_rt, _peer, iroha_client) = ::new() .with_port(port_number) .start_with_runtime(); wait_for_genesis_committed(&[iroha_client.clone()], 0); diff --git a/client/tests/integration/triggers/data_trigger.rs b/client/tests/integration/triggers/data_trigger.rs index 64975b25faf..91280f32bea 100644 --- a/client/tests/integration/triggers/data_trigger.rs +++ b/client/tests/integration/triggers/data_trigger.rs @@ -7,14 +7,14 @@ use test_network::*; #[test] fn must_execute_both_triggers() -> Result<()> { - let (_rt, _peer, mut test_client) = ::new().with_port(10_650).start_with_runtime(); + let (_rt, _peer, test_client) = ::new().with_port(10_650).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); let account_id: AccountId = "alice@wonderland".parse()?; let asset_definition_id = "rose#wonderland".parse()?; let asset_id = AssetId::new(asset_definition_id, account_id.clone()); - let prev_value = get_asset_value(&mut test_client, asset_id.clone())?; + let prev_value = get_asset_value(&test_client, asset_id.clone())?; let instruction = MintBox::new(1_u32, asset_id.clone()); let register_trigger = RegisterBox::new(Trigger::new( @@ -49,7 +49,7 @@ fn must_execute_both_triggers() -> Result<()> { )))?; test_client.submit_blocking(RegisterBox::new(Domain::new("neverland".parse()?)))?; - let new_value = get_asset_value(&mut test_client, asset_id)?; + let new_value = get_asset_value(&test_client, asset_id)?; assert_eq!(new_value, prev_value + 2); Ok(()) @@ -57,7 +57,7 @@ fn must_execute_both_triggers() -> Result<()> { #[test] fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Result<()> { - let (_rt, _peer, mut test_client) = ::new().with_port(10_655).start_with_runtime(); + let (_rt, _peer, test_client) = ::new().with_port(10_655).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); let create_neverland_domain = RegisterBox::new(Domain::new("neverland".parse()?)); @@ -80,7 +80,7 @@ fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Resu create_sakura_asset, ])?; - let prev_value = get_asset_value(&mut test_client, asset_id.clone())?; + let prev_value = get_asset_value(&test_client, asset_id.clone())?; let register_trigger = RegisterBox::new(Trigger::new( "mint_sakura$neverland".parse()?, @@ -105,13 +105,13 @@ fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Resu [], )))?; - let new_value = get_asset_value(&mut test_client, asset_id)?; + let new_value = get_asset_value(&test_client, asset_id)?; assert_eq!(new_value, prev_value + 1); Ok(()) } -fn get_asset_value(client: &mut client::Client, asset_id: AssetId) -> Result { +fn get_asset_value(client: &client::Client, asset_id: AssetId) -> Result { let asset = client.request(client::asset::by_id(asset_id))?; Ok(*TryAsRef::::try_as_ref(asset.value())?) } diff --git a/client/tests/integration/triggers/event_trigger.rs b/client/tests/integration/triggers/event_trigger.rs index cdb3f1492b6..f76f1868f6a 100644 --- a/client/tests/integration/triggers/event_trigger.rs +++ b/client/tests/integration/triggers/event_trigger.rs @@ -13,7 +13,7 @@ fn test_mint_asset_when_new_asset_definition_created() -> Result<()> { wait_for_genesis_committed(&vec![test_client.clone()], 0); let asset_definition_id = "rose#wonderland".parse()?; - let account_id = ::Id::from_str("alice@wonderland")?; + let account_id = AccountId::from_str("alice@wonderland")?; let asset_id = AssetId::new(asset_definition_id, account_id.clone()); let prev_value = get_asset_value(&mut test_client, asset_id.clone())?; diff --git a/client/tests/integration/triggers/time_trigger.rs b/client/tests/integration/triggers/time_trigger.rs index c1dcfb2129c..f238414e644 100644 --- a/client/tests/integration/triggers/time_trigger.rs +++ b/client/tests/integration/triggers/time_trigger.rs @@ -92,9 +92,8 @@ fn change_asset_metadata_after_1_sec() -> Result<()> { // Start listening BEFORE submitting any transaction not to miss any block committed event let event_listener = get_block_committed_event_listener(&test_client)?; - let asset_definition_id = - ::Id::from_str("rose#wonderland").expect("Valid"); - let account_id = ::Id::from_str("alice@wonderland").expect("Valid"); + let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland").expect("Valid"); + let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let key = Name::from_str("petal")?; let schedule = TimeSchedule::starting_at(start_time + Duration::from_millis(PERIOD_MS)); @@ -182,9 +181,7 @@ fn mint_nft_for_every_user_every_1_sec() -> Result<()> { let (_rt, _peer, mut test_client) = ::new().with_port(10_780).start_with_runtime(); wait_for_genesis_committed(&vec![test_client.clone()], 0); - let alice_id = "alice@wonderland" - .parse::<::Id>() - .expect("Valid"); + let alice_id = "alice@wonderland".parse::().expect("Valid"); let accounts: Vec = vec![ alice_id.clone(), diff --git a/client/tests/integration/unregister_peer.rs b/client/tests/integration/unregister_peer.rs index 817e90ded4e..c30f05fb30d 100644 --- a/client/tests/integration/unregister_peer.rs +++ b/client/tests/integration/unregister_peer.rs @@ -17,21 +17,21 @@ use super::Configuration; #[test] fn unstable_network_stable_after_add_and_after_remove_peer() -> Result<()> { // Given a network - let (rt, network, mut genesis_client, pipeline_time, account_id, asset_definition_id) = init()?; + let (rt, network, genesis_client, pipeline_time, account_id, asset_definition_id) = init()?; wait_for_genesis_committed(&network.clients(), 0); // When assets are minted mint( &asset_definition_id, &account_id, - &mut genesis_client, + &genesis_client, pipeline_time, 100, )?; // and a new peer is registered - let (peer, mut peer_client) = rt.block_on(network.add_peer()); + let (peer, peer_client) = rt.block_on(network.add_peer()); // Then the new peer should already have the mint result. - check_assets(&mut peer_client, &account_id, &asset_definition_id, 100); + check_assets(&peer_client, &account_id, &asset_definition_id, 100); // Also, when a peer is unregistered let remove_peer = UnregisterBox::new(IdBox::PeerId(peer.id.clone())); genesis_client.submit(remove_peer)?; @@ -40,20 +40,20 @@ fn unstable_network_stable_after_add_and_after_remove_peer() -> Result<()> { mint( &asset_definition_id, &account_id, - &mut genesis_client, + &genesis_client, pipeline_time, 200, )?; // Assets are increased on the main network. - check_assets(&mut genesis_client, &account_id, &asset_definition_id, 300); + check_assets(&genesis_client, &account_id, &asset_definition_id, 300); // But not on the unregistered peer's network. - check_assets(&mut peer_client, &account_id, &asset_definition_id, 100); + check_assets(&peer_client, &account_id, &asset_definition_id, 100); Ok(()) } #[allow(clippy::expect_used)] fn check_assets( - iroha_client: &mut client::Client, + iroha_client: &client::Client, account_id: &AccountId, asset_definition_id: &AssetDefinitionId, quantity: u32, @@ -78,7 +78,7 @@ fn check_assets( fn mint( asset_definition_id: &AssetDefinitionId, account_id: &AccountId, - client: &mut client::Client, + client: &client::Client, pipeline_time: std::time::Duration, quantity: u32, ) -> Result { diff --git a/client/tests/integration/unstable_network.rs b/client/tests/integration/unstable_network.rs index 8b2f911938c..52fec1aa735 100644 --- a/client/tests/integration/unstable_network.rs +++ b/client/tests/integration/unstable_network.rs @@ -52,7 +52,7 @@ fn unstable_network( } let rt = Runtime::test(); // Given - let (network, mut iroha_client) = rt.block_on(async { + let (network, iroha_client) = rt.block_on(async { let mut configuration = Configuration::test(); configuration.sumeragi.max_transactions_in_block = MAX_TRANSACTIONS_IN_BLOCK; configuration.logger.max_log_level = Level::INFO.into(); diff --git a/client/tests/integration/upgrade.rs b/client/tests/integration/upgrade.rs index 368b34bcfcb..83e0db2afe1 100644 --- a/client/tests/integration/upgrade.rs +++ b/client/tests/integration/upgrade.rs @@ -20,15 +20,15 @@ fn validator_upgrade_should_work() -> Result<()> { let register_admin_domain = RegisterBox::new(admin_domain); client.submit_blocking(register_admin_domain)?; - let admin_id: ::Id = "admin@admin".parse()?; + let admin_id: AccountId = "admin@admin".parse()?; let admin_keypair = KeyPair::generate()?; let admin_account = Account::new(admin_id.clone(), [admin_keypair.public_key().clone()]); let register_admin_account = RegisterBox::new(admin_account); client.submit_blocking(register_admin_account)?; // Check that admin isn't allowed to transfer alice's rose by default - let alice_rose: ::Id = "rose##alice@wonderland".parse()?; - let admin_rose: ::Id = "admin@admin".parse()?; + let alice_rose: AssetId = "rose##alice@wonderland".parse()?; + let admin_rose: AccountId = "admin@admin".parse()?; let transfer_alice_rose = TransferBox::new(alice_rose, NumericValue::U32(1), admin_rose); let transfer_rose_tx = TransactionBuilder::new(admin_id.clone()) .with_instructions([transfer_alice_rose.clone()]) diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index f4c732562ea..bf859002bcb 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -577,7 +577,7 @@ mod account { pub struct Grant { /// Account id #[structopt(short, long)] - pub id: ::Id, + pub id: AccountId, /// The JSON/JSON5 file with a permission token #[structopt(short, long)] pub permission: Permission, @@ -622,7 +622,7 @@ mod account { pub struct ListPermissions { /// Account id #[structopt(short, long)] - id: ::Id, + id: AccountId, } impl RunArgs for ListPermissions { diff --git a/config/src/client.rs b/config/src/client.rs index cf740a974de..fea87d4f3a6 100644 --- a/config/src/client.rs +++ b/config/src/client.rs @@ -224,7 +224,7 @@ mod tests { } #[allow(clippy::expect_used)] - fn placeholder_account() -> ::Id { + fn placeholder_account() -> AccountId { AccountId::from_str("alice@wonderland").expect("Invalid account Id ") } diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index f19d200f2e41af9b9895abf2d7945ac1b8173257..06c460d42c9896e7857615c8a83303e7d3970663 100644 GIT binary patch literal 492656 zcmeFa3%DIsdH+ARy=V6AWO5;dT*&MlgcBtgTAEO_KQqxJP(={6KWhCwKwF-c6I2Ma z|Mq#5#EKdLH7W`!YE+b{fKh3U6*VfYQBh+>MMaG*YN}{srJ5@0|MPv<%-(ZuNkE~I z?i1KEvu0i2_1@pL)_CV#@+{x;JpU)b3FihIH~Jg(>z(WKf4I?}bx{JZJpPY(JcJ#$mH7rY5JUZy%ObD1u?jCZknr>c}+uWB1FocHHm-Mw3I z3GXgCf5Wpbxa1OwoO9`O)}R0Eb1wO_zdZk0=aqG5D*xB#U3kHttAa~6ocHWY&a(z4 zRyICkr6&_J&L3Cf#ea4FhQFPdCH(V0?GLU~4$g9VUiiY+3tCYW9NG3GFNpk_A4Fl` z`$0VjJd%{+`5sA13_5;2u1ASKE8vm8AgD#|&L<;}Q4mGZJa=EdAlWjzAKh1;-Mb>e zi>wlw_GnP;TkgR9dFoCSc{P{2NS%10a@DE-LTV6!HM~aT)hm5)w-Fcp&-ln9LevkL zJ>Rd_>wZ0=B4r4CFQQBOtNSBxA=S!-KYS_21|KR>2s{R41O4B#9P z^_Ksq`=hiMMRiIAeljs@JzxTuEMbKv)+3{CBERM9)<2ee6{aj`6I5Q?z0gQ`?ZMru zGeWiqME5)Xtg>G~L`bOrYBj(W3*q7z#MbzH|2W^DYhx=4XqXfJ=2V_Ft5HZ5wPN(H zmNJK6Yxf0uIY8dOUz>$VMGm#XNvpXROZcO8zsB^| zsM?1Jm8uz`L~Oh=P7FoDDE5Qn(=-()jhoFN_9zxFn;FiW8G<9Rf06&b@O@z|^u3w& zqr#1TzG>4=ueH(3zy9Wr*>#Vu@xS_w`m@e|)^j%eZQ#v2$D~&&QJ%A*luh0(!6PQU zn@a9@FANWmu_AZ8&EewdYjo1&%5Y|p<^MyqIp@3!FMQ6Qd0%MGt|tEZ`7Zg6X7ikL zkb>u(bN;jcJoH=Vob#9GpLfwYe|p{}=Z8V#yD-GuZ@o8sCTxG&rpeJT8>=q1tSXjk;9=+n{1qEAFGt?dav z9)7L)^7yv+mGR5s+oN6aXQEHVpNYR1e=_=y_!sdn;};~CCwtuwI^WwNF5vc{&y70IvS*Cek_Uema`aaH3*jUUH5qF*NWC41w&$xX@4$*bZU zqwACRBs-E1#Xk?fn4I&~=HDl`BwtN_8h$?hX!7&;L&^8!ZH@0G+Z#7EZfv}(@y^D- zCtr{MJ^pF@&+*6ouP4_x-W%PMyf1oN@`rP1e;561r(e<0owzd!zm`0wLe;`hbx zjo%Y*kKY~N9N!e*7{4oiXZ((MTYN+O_V{h__3>Ndx5RIbx5jUZ-x$9kzAk=!{JQwH z@wM?a@oVB&$1jbqj<1bA5`8y$ZS>v7&Gio_{}lgY^3TaXCATF{-4eef`9$)`WLNU> z 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

{ /// Logically `&&` the results of applying the predicates. - And(NonTrivial>), + And(NonTrivial), /// Logically `||` the results of applying the predicats. - Or(NonTrivial>), + Or(NonTrivial), /// Negate the result of applying the predicate. - Not(Box>), + Not(Box), /// The raw predicate that must be applied. #[serde_partially_tagged(untagged)] Raw(P), From d1380a5d7393fc1e67abe5a48cd063004a2beafb Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Mon, 18 Sep 2023 16:10:18 +0300 Subject: [PATCH 18/55] [refactor] #2437: Improve naming, simplify repeated .filter_maps & get rid of unnecessary .except in derive(Filter) This addresses the last of the concerns raised in #2437 Signed-off-by: Nikita Strygin --- data_model/derive/src/filter.rs | 157 ++++++++++++++++---------------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/data_model/derive/src/filter.rs b/data_model/derive/src/filter.rs index 3fccf4e73ac..42a79a93270 100644 --- a/data_model/derive/src/filter.rs +++ b/data_model/derive/src/filter.rs @@ -24,7 +24,8 @@ enum EventVariant { /// Delegates all the filterting to the corresponding event's filter. Delegating { variant_name: Ident, - delegated_event_ty_name: Ident, + /// A name of the event this variant delegates to, without the the `Event` suffix + delegated_event_name_base: String, }, /// An actual event. Has either an Id or an identifiable object as a payload /// The presense of the Id field is not required by this macro per se, but will be enfored by `OriginFilter` requiring a `HasOrigin` impl. @@ -48,10 +49,14 @@ impl FromVariant for EventVariant { return Err(darling::Error::custom("Only identifiers supported as event types").with_span(first_field_ty)); }; - if first_field_ty_name.to_string().ends_with("Event") { + // What clippy suggests is much less readable in this case + #[allow(clippy::option_if_let_else)] + if let Some(delegated_event_name_base) = + first_field_ty_name.to_string().strip_suffix("Event") + { Ok(EventVariant::Delegating { variant_name: variant.ident.clone(), - delegated_event_ty_name: first_field_ty_name.clone(), + delegated_event_name_base: delegated_event_name_base.to_string(), }) } else { Ok(EventVariant::Direct(variant.ident.clone())) @@ -67,90 +72,86 @@ impl EventEnum { } } + fn filter_map_variants Option>(&self, fun: F) -> Vec { + self.variants().iter().filter_map(fun).collect() + } + /// Used to produce fields like `ByAccount(crate::prelude::FilterOpt)` in `DomainEventFilter`. - fn generate_filter_variants_for_delegating_events(&self) -> Vec { - self.variants() - .iter() - .filter_map(|variant| match variant { - EventVariant::Direct(_) => None, - EventVariant::Delegating { - variant_name, - delegated_event_ty_name, - } => { - // E.g. `Account` field in the event => `ByAccount` in the event filter - let filter_variant_ident = format_ident!("By{}", variant_name); - // E.g. `AccountEvent` inner field from `Account` variant in event => - // `AccountFilter` inside the event filter - let inner_filter_ident = - format_ident!( - "{}Filter", - delegated_event_ty_name.to_string().strip_suffix("Event").expect( - "BUG: Variant name should have suffix `Event` (checked in FromVariant)" - ), - ); - let import_path = quote! {crate::prelude}; - Some(quote! { - #filter_variant_ident(#import_path::FilterOpt<#inner_filter_ident>) }) - } - }) - .collect() + fn generate_filter_variants_for_delegating_events(&self) -> Vec { + self.filter_map_variants(|variant| { + if let EventVariant::Delegating { + variant_name, + delegated_event_name_base, + } = variant + { + // E.g. `Account` field in the event => `ByAccount` in the event filter + let filter_variant_ident = format_ident!("By{}", variant_name); + // E.g. `AccountEvent` inner field from `Account` variant in event => + // `AccountFilter` inside the event filter + let inner_filter_ident = format_ident!("{}Filter", delegated_event_name_base); + let import_path = quote! {crate::prelude}; + Some(quote! { + #filter_variant_ident(#import_path::FilterOpt<#inner_filter_ident>) + }) + } else { + None + } + }) } /// Used to produce fields like `ByCreated` in `DomainEventFilter`. fn generate_filter_variants_for_direct_events(&self) -> Vec { - self.variants() - .iter() - .filter_map(|variant| match variant { - EventVariant::Direct(event_variant_ident) => { - // Event fields such as `MetadataRemoved` get mapped to `ByMetadataRemoved` - let filter_variant_ident = format_ident!("By{}", event_variant_ident); - Some(filter_variant_ident) - } - EventVariant::Delegating { .. } => None, - }) - .collect() + self.filter_map_variants(|variant| { + if let EventVariant::Direct(event_variant_ident) = variant { + // Event fields such as `MetadataRemoved` get mapped to `ByMetadataRemoved` + let filter_variant_ident = format_ident!("By{}", event_variant_ident); + Some(filter_variant_ident) + } else { + None + } + }) } /// Match arms for `Filter` impls of event filters of the form /// `(Self::ByAccount(filter_opt), crate::prelude::DomainEvent::Account(event)) => {filter_opt.matches(event)}`. - fn generate_filter_impls_for_delegaring_events(&self) -> Vec { - self.variants() - .iter() - .filter_map(|variant| match variant { - EventVariant::Direct(_) => None, - EventVariant::Delegating { - variant_name, - .. - } => { - let event_ident = &self.ident; - let filter_variant_ident = format_ident!("By{}", variant_name); - let import_path = quote! {crate::prelude}; - Some(quote! { - (Self::#filter_variant_ident(filter_opt), #import_path::#event_ident::#variant_name(event)) => { - filter_opt.matches(event) - }}) - - }}).collect() + fn generate_filter_arms_for_delegating_events(&self) -> Vec { + self.filter_map_variants(|variant| { + if let EventVariant::Delegating { variant_name, .. } = variant { + let event_ident = &self.ident; + let filter_variant_ident = format_ident!("By{}", variant_name); + let import_path = quote! {crate::prelude}; + Some(quote! { + ( + Self::#filter_variant_ident(filter_opt), + #import_path::#event_ident::#variant_name(event) + ) => { + filter_opt.matches(event) + } + }) + } else { + None + } + }) } /// Match arms for `Filter` impls of event filters of the form /// `(Self::ByCreated, crate::prelude::DomainEvent::Created(_))`. - fn generate_filter_impls_for_direct_events(&self) -> Vec { - self.variants() - .iter() - .filter_map(|variant| match variant { - EventVariant::Direct(event_variant_ident) => { - let event_ident = &self.ident; - let filter_variant_ident = format_ident!("By{}", event_variant_ident); - let import_path = quote! {crate::prelude}; - Some( - quote! { - (Self::#filter_variant_ident, #import_path::#event_ident::#event_variant_ident(_)) - }) - }, - EventVariant::Delegating { .. } => None, - }) - .collect() + fn generate_filter_patterns_for_direct_events(&self) -> Vec { + self.filter_map_variants(|variant| { + if let EventVariant::Direct(event_variant_ident) = variant { + let event_ident = &self.ident; + let filter_variant_ident = format_ident!("By{}", event_variant_ident); + let import_path = quote! {crate::prelude}; + Some(quote! { + ( + Self::#filter_variant_ident, + #import_path::#event_ident::#event_variant_ident(_) + ) + }) + } else { + None + } + }) } } @@ -167,8 +168,8 @@ fn impl_event_filter(event: &EventEnum) -> proc_macro2::TokenStream { let id_variants = event.generate_filter_variants_for_direct_events(); let event_variants = event.generate_filter_variants_for_delegating_events(); - let id_impls = event.generate_filter_impls_for_direct_events(); - let event_impls = event.generate_filter_impls_for_delegaring_events(); + let id_patterns = event.generate_filter_patterns_for_direct_events(); + let event_arms = event.generate_filter_arms_for_delegating_events(); let event_filter_ident = format_ident!("{}Filter", event_ident); let import_path = quote! { crate::prelude }; @@ -193,8 +194,8 @@ fn impl_event_filter(event: &EventEnum) -> proc_macro2::TokenStream { fn matches(&self, event: &#imp_event) -> bool { match (self, event) { - #(#id_impls)|* => true, - #(#event_impls),* + #(#id_patterns)|* => true, + #(#event_arms),* _ => false, } } From 53491a4f8d261f26d18b31feaf7bcecd37eb6de5 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Mon, 18 Sep 2023 17:11:21 +0300 Subject: [PATCH 19/55] [refactor] #3882: Add tests for derive(HasOrigin) macro, reduce repetition in derive(IdEqOrdHash), fix error reporting on stable Signed-off-by: Nikita Strygin --- data_model/derive/src/id.rs | 25 +----- data_model/derive/tests/has_origin.rs | 53 +++++++++++ .../ui_fail/has_origin_multiple_attributes.rs | 9 ++ .../has_origin_multiple_attributes.stderr | 6 ++ macro/utils/src/lib.rs | 87 +++++++++++++++---- 5 files changed, 141 insertions(+), 39 deletions(-) create mode 100644 data_model/derive/tests/has_origin.rs create mode 100644 data_model/derive/tests/ui_fail/has_origin_multiple_attributes.rs create mode 100644 data_model/derive/tests/ui_fail/has_origin_multiple_attributes.stderr diff --git a/data_model/derive/src/id.rs b/data_model/derive/src/id.rs index 18af318dcf7..39983e1ad8e 100644 --- a/data_model/derive/src/id.rs +++ b/data_model/derive/src/id.rs @@ -1,7 +1,7 @@ #![allow(clippy::str_to_string, clippy::mixed_read_write_in_expression)] use darling::{FromAttributes, FromDeriveInput, FromField}; -use iroha_macro_utils::Emitter; +use iroha_macro_utils::{find_single_attr_opt, Emitter}; use manyhow::emit; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; @@ -20,27 +20,8 @@ enum IdAttr { impl FromAttributes for IdAttr { fn from_attributes(attrs: &[syn2::Attribute]) -> darling::Result { let mut accumulator = darling::error::Accumulator::default(); - let attrs = attrs - .iter() - .filter(|v| v.path().is_ident("id")) - .collect::>(); - let attr = match attrs.as_slice() { - [] => { - return accumulator.finish_with(IdAttr::Missing); - } - [attr] => attr, - [attr, ref tail @ ..] => { - accumulator.push( - darling::Error::custom("Only one `#[id]` attribute is allowed!").with_span( - &tail - .iter() - .map(syn2::spanned::Spanned::span) - .reduce(|a, b| a.join(b).unwrap()) - .unwrap(), - ), - ); - attr - } + let Some(attr) = find_single_attr_opt(&mut accumulator, "id", attrs) else { + return accumulator.finish_with(IdAttr::Missing); }; let result = match &attr.meta { diff --git a/data_model/derive/tests/has_origin.rs b/data_model/derive/tests/has_origin.rs new file mode 100644 index 00000000000..8522c4268fd --- /dev/null +++ b/data_model/derive/tests/has_origin.rs @@ -0,0 +1,53 @@ +use iroha_data_model::prelude::{HasOrigin, Identifiable}; +use iroha_data_model_derive::{HasOrigin, IdEqOrdHash}; + +#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +struct ObjectId(pub i32); + +// fake impl for `#[derive(IdEqOrdHash)]` +impl From for iroha_data_model::IdBox { + fn from(_: ObjectId) -> Self { + unimplemented!("fake impl") + } +} + +#[derive(Debug, IdEqOrdHash)] +struct Object { + id: ObjectId, +} + +impl Object { + fn id(&self) -> &ObjectId { + &self.id + } +} + +#[allow(clippy::enum_variant_names)] // it's a test, duh +#[derive(Debug, HasOrigin)] +#[has_origin(origin = Object)] +enum ObjectEvent { + EventWithId(ObjectId), + #[has_origin(event => &event.0)] + EventWithExtractor((ObjectId, i32)), + #[has_origin(obj => obj.id())] + EventWithAnotherExtractor(Object), +} + +#[test] +fn has_origin() { + let events = vec![ + ObjectEvent::EventWithId(ObjectId(1)), + ObjectEvent::EventWithExtractor((ObjectId(2), 2)), + ObjectEvent::EventWithAnotherExtractor(Object { id: ObjectId(3) }), + ]; + let expected_ids = vec![ObjectId(1), ObjectId(2), ObjectId(3)]; + + for (event, expected_id) in events.into_iter().zip(expected_ids) { + assert_eq!( + event.origin_id(), + &expected_id, + "mismatched origin id for event {:?}", + event + ); + } +} diff --git a/data_model/derive/tests/ui_fail/has_origin_multiple_attributes.rs b/data_model/derive/tests/ui_fail/has_origin_multiple_attributes.rs new file mode 100644 index 00000000000..ad09416af20 --- /dev/null +++ b/data_model/derive/tests/ui_fail/has_origin_multiple_attributes.rs @@ -0,0 +1,9 @@ +use iroha_data_model_derive::HasOrigin; + +#[derive(HasOrigin)] +#[has_origin(origin = Object)] +#[has_origin(origin = Object)] +#[has_origin(origin = Object)] +enum MultipleAttributes {} + +fn main() {} diff --git a/data_model/derive/tests/ui_fail/has_origin_multiple_attributes.stderr b/data_model/derive/tests/ui_fail/has_origin_multiple_attributes.stderr new file mode 100644 index 00000000000..35511493350 --- /dev/null +++ b/data_model/derive/tests/ui_fail/has_origin_multiple_attributes.stderr @@ -0,0 +1,6 @@ +error: Only one #[has_origin] attribute is allowed! + --> tests/ui_fail/has_origin_multiple_attributes.rs:5:1 + | +5 | / #[has_origin(origin = Object)] +6 | | #[has_origin(origin = Object)] + | |______________________________^ diff --git a/macro/utils/src/lib.rs b/macro/utils/src/lib.rs index 9f19785d07c..09eba6f07e8 100644 --- a/macro/utils/src/lib.rs +++ b/macro/utils/src/lib.rs @@ -70,42 +70,89 @@ macro_rules! attr_struct { }; } -/// Parses a single attribute of the form `#[attr_name(...)]` for darling using a `syn::parse::Parse` implementation. +/// Extension trait for [`darling::Error`]. /// -/// If no attribute with specified name is found, returns `Ok(None)`. -pub fn parse_single_list_attr_opt( - attr_name: &str, - attrs: &[syn2::Attribute], -) -> darling::Result> { - let mut accumulator = darling::error::Accumulator::default(); +/// Currently exists to add `with_spans` method. +pub trait DarlingErrorExt: Sized { + /// Attaches a combination of multiple spans to the error. + /// + /// Note that it only attaches the first span on stable rustc, as the `Span::join` method is not yet stabilized (https://github.com/rust-lang/rust/issues/54725#issuecomment-649078500). + fn with_spans(self, spans: impl IntoIterator>) -> Self; +} - // first, ensure there is only one attribute with the requested name - // take the first one if there are multiple +impl DarlingErrorExt for darling::Error { + fn with_spans(self, spans: impl IntoIterator>) -> Self { + // Unfortunately, the story for combining multiple spans in rustc proc macro is not yet complete. + // (see https://github.com/rust-lang/rust/issues/54725#issuecomment-649078500, https://github.com/rust-lang/rust/issues/54725#issuecomment-1547795742) + // syn does some hacks to get error reporting that is a bit better: https://docs.rs/syn/2.0.37/src/syn/error.rs.html#282 + // we can't to that because darling's error type does not let us do that. + + // on nightly, we are fine, as `.join` method works. On stable, we fall back to returning the first span. + + let mut iter = spans.into_iter(); + let Some(first) = iter.next() else { + return self; + }; + let first: proc_macro2::Span = first.into(); + let r = iter + .try_fold(first, |a, b| a.join(b.into())) + .unwrap_or(first); + + self.with_span(&r) + } +} + +/// Finds an optional single attribute with specified name. +/// +/// Returns `None` if no attributes with specified name are found. +/// +/// Emits an error into accumulator if multiple attributes with specified name are found. +#[must_use] +pub fn find_single_attr_opt<'a>( + accumulator: &mut darling::error::Accumulator, + attr_name: &str, + attrs: &'a [syn2::Attribute], +) -> Option<&'a syn2::Attribute> { let matching_attrs = attrs .iter() .filter(|a| a.path().is_ident(attr_name)) .collect::>(); let attr = match *matching_attrs.as_slice() { [] => { - return accumulator.finish_with(None); + return None; } [attr] => attr, [attr, ref tail @ ..] => { // allow parsing to proceed further to collect more errors accumulator.push( darling::Error::custom(format!("Only one #[{}] attribute is allowed!", attr_name)) - .with_span( - &tail - .iter() - .map(syn2::spanned::Spanned::span) - .reduce(|a, b| a.join(b).unwrap()) - .unwrap(), - ), + .with_spans(tail.iter().map(syn2::spanned::Spanned::span)), ); attr } }; + Some(attr) +} + +/// Parses a single attribute of the form `#[attr_name(...)]` for darling using a `syn::parse::Parse` implementation. +/// +/// If no attribute with specified name is found, returns `Ok(None)`. +/// +/// # Errors +/// +/// - If multiple attributes with specified name are found +/// - If attribute is not a list +pub fn parse_single_list_attr_opt( + attr_name: &str, + attrs: &[syn2::Attribute], +) -> darling::Result> { + let mut accumulator = darling::error::Accumulator::default(); + + let Some(attr) = find_single_attr_opt(&mut accumulator, attr_name, attrs) else { + return accumulator.finish_with(None); + }; + let mut kind = None; match &attr.meta { @@ -123,6 +170,12 @@ pub fn parse_single_list_attr_opt( /// Parses a single attribute of the form `#[attr_name(...)]` for darling using a `syn::parse::Parse` implementation. /// /// If no attribute with specified name is found, returns an error. +/// +/// # Errors +/// +/// - If multiple attributes with specified name are found +/// - If attribute is not a list +/// - If attribute is not found pub fn parse_single_list_attr( attr_name: &str, attrs: &[syn2::Attribute], From ea20c6b439f5dfedbf0b2451b2fc56ad0c5ed4c6 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Mon, 18 Sep 2023 17:17:20 +0300 Subject: [PATCH 20/55] [refactor] #3882: Clean up Emitter APIs documentation to make clippy happy Signed-off-by: Nikita Strygin --- macro/utils/src/emitter.rs | 27 ++++++++++++++++++++++++--- macro/utils/src/lib.rs | 3 ++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/macro/utils/src/emitter.rs b/macro/utils/src/emitter.rs index f5edda28b1b..9509b43930d 100644 --- a/macro/utils/src/emitter.rs +++ b/macro/utils/src/emitter.rs @@ -16,6 +16,7 @@ pub struct Emitter { } impl Emitter { + /// Creates a new emitter. It must be consumed by calling any of the `finish_*` functions before dropping or it will panic. pub fn new() -> Self { Self { inner: manyhow::Emitter::new(), @@ -54,18 +55,32 @@ impl Emitter { } /// Consume the emitter, returning a [`manyhow::Error`] if any errors were emitted. + /// + /// # Errors + /// + /// This function returns an error if the emitter has some errors accumulated. pub fn finish(mut self) -> manyhow::Result<()> { self.bomb.defuse(); self.inner.into_result() } /// Same as [`Emitter::finish`], but returns the given value if no errors were emitted. + /// + /// # Errors + /// + /// This function returns an error if the emitter has some errors accumulated. #[allow(unused)] pub fn finish_with(self, result: T) -> manyhow::Result { self.finish().map(|_| result) } /// Handles the given [`manyhow::Result`] and consumes the emitter. + /// + /// # Errors + /// + /// This function returns an error if: + /// - The given result is `Err` + /// - The emitter has some errors accumulated #[allow(unused)] pub fn finish_and( mut self, @@ -81,7 +96,7 @@ impl Emitter { } /// Consume the emitter, convert all errors into a token stream and append it to the given token stream. - pub fn into_tokens(self, tokens: &mut TokenStream) { + pub fn finish_to_token_stream(self, tokens: &mut TokenStream) { match self.finish() { Ok(()) => {} Err(e) => e.to_tokens(tokens), @@ -91,7 +106,7 @@ impl Emitter { /// Consume the emitter, convert all errors into a token stream. pub fn finish_token_stream(self) -> TokenStream { let mut tokens_stream = TokenStream::new(); - self.into_tokens(&mut tokens_stream); + self.finish_to_token_stream(&mut tokens_stream); tokens_stream } @@ -99,11 +114,17 @@ impl Emitter { /// /// This function is useful when you want to handle errors in a macro, but want to emit some tokens even in case of an error. pub fn finish_token_stream_with(self, mut tokens_stream: TokenStream) -> TokenStream { - self.into_tokens(&mut tokens_stream); + self.finish_to_token_stream(&mut tokens_stream); tokens_stream } } +impl Default for Emitter { + fn default() -> Self { + Self::new() + } +} + impl Extend for Emitter { fn extend>(&mut self, iter: T) { self.inner.extend(iter) diff --git a/macro/utils/src/lib.rs b/macro/utils/src/lib.rs index 09eba6f07e8..1e069d1bfd8 100644 --- a/macro/utils/src/lib.rs +++ b/macro/utils/src/lib.rs @@ -76,7 +76,8 @@ macro_rules! attr_struct { pub trait DarlingErrorExt: Sized { /// Attaches a combination of multiple spans to the error. /// - /// Note that it only attaches the first span on stable rustc, as the `Span::join` method is not yet stabilized (https://github.com/rust-lang/rust/issues/54725#issuecomment-649078500). + /// Note that it only attaches the first span on stable rustc, as the `Span::join` method is not yet stabilized (). + #[must_use] fn with_spans(self, spans: impl IntoIterator>) -> Self; } From d06bc33e4dca9b8bde41650710ba5498818e8223 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Mon, 25 Sep 2023 14:38:02 +0300 Subject: [PATCH 21/55] [refactor] #3882: Add basic generics support to `derive(HasOrigin)` Signed-off-by: Nikita Strygin --- Cargo.lock | 4 +- data_model/derive/src/has_origin.rs | 29 ++++++---- data_model/derive/src/lib.rs | 12 +++-- .../derive/tests/has_origin_generics.rs | 53 +++++++++++++++++++ 4 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 data_model/derive/tests/has_origin_generics.rs diff --git a/Cargo.lock b/Cargo.lock index 0f31f1171e9..9407cd43944 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3183,7 +3183,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.26", + "syn 2.0.28", "trybuild", ] @@ -3321,7 +3321,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] diff --git a/data_model/derive/src/has_origin.rs b/data_model/derive/src/has_origin.rs index 18df35f8d10..31033128b42 100644 --- a/data_model/derive/src/has_origin.rs +++ b/data_model/derive/src/has_origin.rs @@ -5,8 +5,9 @@ )] use darling::{FromDeriveInput, FromVariant}; -use iroha_macro_utils::{attr_struct2, parse_single_list_attr, parse_single_list_attr_opt}; -use manyhow::Result; +use iroha_macro_utils::{ + attr_struct2, parse_single_list_attr, parse_single_list_attr_opt, Emitter, +}; use proc_macro2::TokenStream; use quote::quote; use syn2::{parse_quote, Ident, Token, Type}; @@ -19,6 +20,8 @@ const HAS_ORIGIN_ATTR: &str = "has_origin"; pub struct HasOriginEnum { ident: Ident, + #[allow(unused)] + generics: syn2::Generics, variants: Vec, origin: Type, } @@ -26,6 +29,7 @@ pub struct HasOriginEnum { impl FromDeriveInput for HasOriginEnum { fn from_derive_input(input: &syn2::DeriveInput) -> darling::Result { let ident = input.ident.clone(); + let generics = input.generics.clone(); let Some(variants) = darling::ast::Data::::try_from(&input.data)?.take_enum() else { return Err(darling::Error::custom("Expected enum")); @@ -35,6 +39,7 @@ impl FromDeriveInput for HasOriginEnum { Ok(Self { ident, + generics, variants, origin, }) @@ -71,12 +76,14 @@ attr_struct2! { } } -pub fn impl_has_origin(input: &syn2::DeriveInput) -> Result { - let enum_ = HasOriginEnum::from_derive_input(input)?; +pub fn impl_has_origin(emitter: &mut Emitter, input: &syn2::DeriveInput) -> TokenStream { + let Some(enum_) = emitter.handle(HasOriginEnum::from_derive_input(input)) else { + return quote!(); + }; - // TODO: verify enum is non-empty (or make it work with empty enums) - // TODO: verify all the enum variants are newtype variants - // TODO: verify there are no generics on the enum + if enum_.variants.is_empty() { + return quote!(); + } let enum_ident = &enum_.ident; let enum_origin = &enum_.origin; @@ -96,8 +103,10 @@ pub fn impl_has_origin(input: &syn2::DeriveInput) -> Result { }) .collect::>(); - Ok(quote! { - impl HasOrigin for #enum_ident { + let (impl_generics, ty_generics, where_clause) = enum_.generics.split_for_impl(); + + quote! { + impl #impl_generics HasOrigin for #enum_ident #ty_generics #where_clause { type Origin = #enum_origin; fn origin_id(&self) -> &::Id { @@ -109,5 +118,5 @@ pub fn impl_has_origin(input: &syn2::DeriveInput) -> Result { } } } - }) + } } diff --git a/data_model/derive/src/lib.rs b/data_model/derive/src/lib.rs index e61eff96d8c..6351fa41329 100644 --- a/data_model/derive/src/lib.rs +++ b/data_model/derive/src/lib.rs @@ -598,8 +598,14 @@ pub fn partially_tagged_deserialize_derive(input: TokenStream) -> Result Result { - let input = syn2::parse2(input)?; +pub fn has_origin_derive(input: TokenStream) -> TokenStream { + let mut emitter = Emitter::new(); - has_origin::impl_has_origin(&input) + let Some(input) = emitter.handle(syn2::parse2(input)) else { + return emitter.finish_token_stream() + }; + + let result = has_origin::impl_has_origin(&mut emitter, &input); + + emitter.finish_token_stream_with(result) } diff --git a/data_model/derive/tests/has_origin_generics.rs b/data_model/derive/tests/has_origin_generics.rs new file mode 100644 index 00000000000..b344aba802e --- /dev/null +++ b/data_model/derive/tests/has_origin_generics.rs @@ -0,0 +1,53 @@ +use iroha_data_model::prelude::{HasOrigin, Identifiable}; +use iroha_data_model_derive::{HasOrigin, IdEqOrdHash}; + +#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +struct ObjectId(pub i32); + +// fake impl for `#[derive(IdEqOrdHash)]` +impl From for iroha_data_model::IdBox { + fn from(_: ObjectId) -> Self { + unimplemented!("fake impl") + } +} + +#[derive(Debug, IdEqOrdHash)] +struct Object { + id: ObjectId, +} + +impl Object { + fn id(&self) -> &ObjectId { + &self.id + } +} + +#[allow(clippy::enum_variant_names)] // it's a test, duh +#[derive(Debug, HasOrigin)] +#[has_origin(origin = Object)] +enum ObjectEvent> { + EventWithId(ObjectId), + #[has_origin(event => &event.0)] + EventWithExtractor((ObjectId, i32)), + #[has_origin(obj => obj.id())] + EventWithAnotherExtractor(T), +} + +#[test] +fn has_origin() { + let events = vec![ + ObjectEvent::EventWithId(ObjectId(1)), + ObjectEvent::EventWithExtractor((ObjectId(2), 2)), + ObjectEvent::EventWithAnotherExtractor(Object { id: ObjectId(3) }), + ]; + let expected_ids = vec![ObjectId(1), ObjectId(2), ObjectId(3)]; + + for (event, expected_id) in events.into_iter().zip(expected_ids) { + assert_eq!( + event.origin_id(), + &expected_id, + "mismatched origin id for event {:?}", + event + ); + } +} From 9d6c35eedffa7e0dab4ba3515433c34b68fc20a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Tue, 26 Sep 2023 09:34:17 +0200 Subject: [PATCH 22/55] [refactor]: Replace Registered with Identifiable in ISI bounds (#3925) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- data_model/src/isi.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data_model/src/isi.rs b/data_model/src/isi.rs index ea03aafe13a..39ee4422ff6 100644 --- a/data_model/src/isi.rs +++ b/data_model/src/isi.rs @@ -178,7 +178,7 @@ mod transparent { /// Generic instruction for an unregistration of an object from the identifiable destination. #[derive(Debug, Clone)] - pub struct Unregister { + pub struct Unregister { /// [`Identifiable::Id`] of the object which should be unregistered. pub object_id: O::Id, } @@ -214,7 +214,7 @@ mod transparent { /// Generic instruction for granting permission to an entity. #[derive(Debug, Clone)] - pub struct Grant> { + pub struct Grant> { /// Object to grant. pub object: O, /// Entity to which to grant this token. @@ -223,7 +223,7 @@ mod transparent { /// Generic instruction for revoking permission from an entity. #[derive(Debug, Clone)] - pub struct Revoke> { + pub struct Revoke> { /// Object to revoke. pub object: O, /// Entity which is being revoked this token from. @@ -285,7 +285,7 @@ mod transparent { } } - impl From> for UnregisterBox { + impl From> for UnregisterBox { fn from(source: Unregister) -> Self { Self::new(source.object_id.into()) } @@ -313,13 +313,13 @@ mod transparent { } } - impl> From> for GrantBox { + impl> From> for GrantBox { fn from(source: Grant) -> Self { Self::new(source.object, source.destination_id.into()) } } - impl> From> for RevokeBox { + impl> From> for RevokeBox { fn from(source: Revoke) -> Self { Self::new(source.object, source.destination_id.into()) } From 0fa1ca463e28baabac2115d0c8467e9150012c5f Mon Sep 17 00:00:00 2001 From: 0x009922 Date: Tue, 26 Sep 2023 15:03:17 +0700 Subject: [PATCH 23/55] [feature]: parse filter as JSON5 in `iroha_client_cli` (#3923) [feat]: parse filter as JSON5 in `iroha_client_cli` Signed-off-by: Dmitry Balashov --- client_cli/README.md | 2 +- client_cli/src/main.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/client_cli/README.md b/client_cli/README.md index 52e8a7e37d2..a2242468444 100644 --- a/client_cli/README.md +++ b/client_cli/README.md @@ -141,7 +141,7 @@ Generally it looks like this: ./iroha_client_cli ENTITY list filter PREDICATE ``` -Where ENTITY is asset, account or domain and PREDICATE is condition used for filtering serialized using JSON (check `ValuePredicate` and `GenericPredicateBox` in [schema](https://github.com/hyperledger/iroha/blob/iroha2-dev/docs/source/references/schema.json) for reference). +Where ENTITY is asset, account or domain and PREDICATE is condition used for filtering serialized using JSON5 (check `iroha_data_model::predicate::value::ValuePredicate` type). Examples: diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index bf859002bcb..729648b2898 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -283,14 +283,13 @@ mod filter { /// Filter for queries #[derive(Clone, Debug, clap::Parser)] pub struct Filter { - /// Predicate for filtering given as JSON string + /// Predicate for filtering given as JSON5 string #[clap(value_parser = parse_filter)] pub predicate: PredicateBox, } fn parse_filter(s: &str) -> Result { - serde_json::from_str(s) - .map_err(|err| format!("Failed to deserialize filter from JSON: {err}")) + json5::from_str(s).map_err(|err| format!("Failed to deserialize filter from JSON5: {err}")) } } From 2963457f54f627c9ccd7797dc456f97074668e11 Mon Sep 17 00:00:00 2001 From: Ekaterina Mekhnetsova Date: Tue, 26 Sep 2023 12:47:37 +0200 Subject: [PATCH 24/55] [documentation]: Remove the develop-iroha-module guide (#3907) Signed-off-by: Ekaterina Mekhnetsova --- docs/README.md | 1 - docs/source/guides/develop-iroha-module.md | 140 --------------------- 2 files changed, 141 deletions(-) delete mode 100644 docs/source/guides/develop-iroha-module.md diff --git a/docs/README.md b/docs/README.md index 2744d219045..8074f170ec7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,5 +19,4 @@ Documentation for Iroha 2 tools: The following is useful for development: - [Hot reload Iroha in a Docker container](./source/guides/hot-reload.md) -- [Develop a new Iroha module](./source/guides/develop-iroha-module.md) - [Benchmark your code](../client/benches/tps/README.md) diff --git a/docs/source/guides/develop-iroha-module.md b/docs/source/guides/develop-iroha-module.md deleted file mode 100644 index b8810cfa5ba..00000000000 --- a/docs/source/guides/develop-iroha-module.md +++ /dev/null @@ -1,140 +0,0 @@ -# How to Develop a New Iroha Module - -When you need to add some functionality to Iroha, use this guide to develop a new Iroha Module. - -## Prerequisites - -* [Rust](https://www.rust-lang.org/tools/install) -* Text Editor or IDE - -## Steps - -### 1. Create new Rust module inside Iroha crate - -Inside `core/src/lib.rs` add a declaration of your new module. -For example, for `bridge` module we add the following declaration, - -```rust -#[cfg(feature = "bridge")] -pub mod bridge; -``` - -so for you module `x` you would add `pub mod x;`. -You should also place your new module under the [Cargo feature](https://doc.rust-lang.org/cargo/reference/features.html) so other developers would be able to turn it on and off when needed. - -Now, create a separate file for your module. -For `bridge` module it will be `core/src/bridge.rs`. -Likewise, for your module `x` you will need to create a new file `core/src/x.rs`. - -### 2. Add documentation - -Each module must provide description of its own functionality via Rust Docs. - -For that, at the beginning of the module file you should place docs block for the enclosing item. - -```rust -//! Here you can see a good description of the module `x` and its functionality. -``` - -All public entites of your module should be documented as well. But first, let's create them. - -### 3. Write your logic - -The development of a new Iroha Module has a goal of bringing new functionality to Iroha. -So based on the goal and requirements, you have you will introduce new entities and place them inside newly created module. - -Let's specify particular categories of such entities and look how they can be implemented according to Iroha best practices. - -#### 4. Add custom Iroha Special Instruction - -If you need to have some module-related Iroha Special Instructions you should add `isi` submodule to the file of your newly created module, like that: - -```rust -... -pub mod isi { -} -``` - -Inside this submodule you may declare new Iroha Special Instructions. -To provide safety guarantees, Iroha Modules can create new Iroha Special Instructions composed of the Out of the Box Instructions. - -Let's look at the [example](https://github.com/hyperledger/iroha/blob/2005335348585b03b3ee7887272af4c76170c10a/iroha/src/bridge.rs) from the `bridge` Iroha Module: - -```rust -... -pub fn register_bridge(&self, bridge_definition: BridgeDefinition) -> Instruction { - let seed = crate::crypto::hash(bridge_definition.encode()); - let public_key = crate::crypto::generate_key_pair_from_seed(seed) - .expect("Failed to generate key pair.") - .0; - let domain = Domain::new(bridge_definition.id.name.clone()); - let account = Account::new("bridge", &domain.name, public_key); - Instruction::If( - Box::new(Instruction::ExecuteQuery(IrohaQuery::GetAccount( - GetAccount { - account_id: bridge_definition.owner_account_id.clone(), - }, - ))), - Box::new(Instruction::Sequence(vec![ - Add { - object: domain.clone(), - destination_id: self.id.clone(), - } - .into(), - Register { - object: account.clone(), - destination_id: domain.name, - } - .into(), - Mint { - object: ( - "owner_id".to_string(), - bridge_definition.owner_account_id.to_string(), - ), - destination_id: AssetId { - definition_id: owner_asset_definition_id(), - account_id: account.id.clone(), - }, - } - .into(), - Mint { - object: ( - "bridge_definition".to_string(), - format!("{:?}", bridge_definition.encode()), - ), - destination_id: AssetId { - definition_id: bridge_asset_definition_id(), - account_id: account.id, - }, - } - .into(), - ])), - None, - ) -} -... -``` - -And see what it does to register a new Bridge: - -1. Check that Bridge's Owner's Account exists and terminate execution if not. -1. Add new Domain. -1. Register new Account. -1. Mint one Asset. -1. Mint another Asset. - -We will not discuss Bridge-related terminology here – the thing we want to look at is how we can compose these steps into one new Iroha Special Instruction. - -As you can see, we have `Instruction::If(...)` here. It's [the utility Iroha Special Instruction](references/glossary#utility-iroha-special-instruction). -It takes three arguments: `condition`, `instruction_to_do_if_true`, `instruction_to_do_if_false_or_nothing`. -By this instruction we've made the first step of our algorithm: run a check and terminate execution if there is no Owner's Account. -Inside `condition` we placed `Instruction::ExecuteQuery(...)` which fails if [Iroha Query](references/glossary#iroha-query) fails. - -If the first step succeeds, we should move forward and execute sequence of the following steps. -For this purpose we also have a utility Iroha Special Instruction `Sequence` with a [vector](https://doc.rust-lang.org/alloc/vec/struct.Vec.html) of Iroha Special Instructions executed one by one. - -Inside this sequence we use [domains-related Iroha Special Instructions](references/glossary#domains-related-iroha-special-instruction) `Add`, `Register`, and `Mint` twice. - -## Additional resources - -* //TODO: add link to the pair programming session on `Bridge` module. From dc05218607447e1cb9658e621a9243572fdd3837 Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Tue, 26 Sep 2023 16:23:47 +0300 Subject: [PATCH 25/55] [fix] #3899: Fix topology mismatch bug (#3903) Signed-off-by: Daniil Polyakov --- Cargo.lock | 1 + cli/Cargo.toml | 1 + cli/src/samples.rs | 5 +- client/benches/torii.rs | 11 +- client/examples/million_accounts_genesis.rs | 6 +- client/tests/integration/restart_peer.rs | 3 +- config/src/sumeragi.rs | 65 +--- configs/peer/validator.wasm | Bin 493320 -> 493285 bytes core/benches/blocks/common.rs | 7 +- core/benches/kura.rs | 3 +- core/benches/validation.rs | 7 +- core/src/block.rs | 241 ++++++++++--- core/src/lib.rs | 3 +- core/src/smartcontracts/isi/query.rs | 5 +- core/src/smartcontracts/isi/world.rs | 8 +- core/src/sumeragi/main_loop.rs | 28 +- core/src/sumeragi/mod.rs | 36 +- core/src/sumeragi/network_topology.rs | 330 ++++-------------- core/src/wsv.rs | 10 +- core/test_network/src/lib.rs | 28 +- crypto/src/signature.rs | 4 +- data_model/src/block.rs | 7 +- docs/source/references/schema.json | 3 +- primitives/src/lib.rs | 1 + primitives/src/unique_vec.rs | 363 ++++++++++++++++++++ scripts/test_env.py | 8 +- 26 files changed, 746 insertions(+), 438 deletions(-) create mode 100644 primitives/src/unique_vec.rs diff --git a/Cargo.lock b/Cargo.lock index 9407cd43944..b76f8bde171 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2928,6 +2928,7 @@ dependencies = [ "iroha_logger", "iroha_macro", "iroha_p2p", + "iroha_primitives", "iroha_schema_gen", "iroha_telemetry", "iroha_version", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index ba0bd4ac4d1..a1b3f06cca9 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -47,6 +47,7 @@ iroha_macro = { workspace = true } iroha_logger = { workspace = true } iroha_futures = { workspace = true } iroha_data_model = { workspace = true, features = ["http"] } +iroha_primitives = { workspace = true } iroha_telemetry = { workspace = true, optional = true } iroha_version = { workspace = true, features = ["http"] } iroha_config = { workspace = true } diff --git a/cli/src/samples.rs b/cli/src/samples.rs index 2a064bd9e64..d023905d9db 100644 --- a/cli/src/samples.rs +++ b/cli/src/samples.rs @@ -9,6 +9,7 @@ use iroha_config::{ }; use iroha_crypto::{KeyPair, PublicKey}; use iroha_data_model::{peer::PeerId, prelude::*}; +use iroha_primitives::unique_vec::UniqueVec; /// Get sample trusted peers. The public key must be the same as `configuration.public_key` /// @@ -52,7 +53,7 @@ pub fn get_trusted_peers(public_key: Option<&PublicKey>) -> HashSet { /// /// # Panics /// - when [`KeyPair`] generation fails (rare case). -pub fn get_config_proxy(peers: HashSet, key_pair: Option) -> ConfigurationProxy { +pub fn get_config_proxy(peers: UniqueVec, key_pair: Option) -> ConfigurationProxy { let (public_key, private_key) = key_pair .unwrap_or_else(|| KeyPair::generate().expect("Key pair generation failed")) .into(); @@ -94,7 +95,7 @@ pub fn get_config_proxy(peers: HashSet, key_pair: Option) -> Co /// /// # Panics /// - when [`KeyPair`] generation fails (rare case). -pub fn get_config(trusted_peers: HashSet, key_pair: Option) -> Configuration { +pub fn get_config(trusted_peers: UniqueVec, key_pair: Option) -> Configuration { get_config_proxy(trusted_peers, key_pair) .build() .expect("Iroha config should build as all required fields were provided") diff --git a/client/benches/torii.rs b/client/benches/torii.rs index 13045603e80..7327672d96c 100644 --- a/client/benches/torii.rs +++ b/client/benches/torii.rs @@ -9,6 +9,7 @@ use iroha_config::base::runtime_upgrades::Reload; use iroha_crypto::KeyPair; use iroha_data_model::prelude::*; use iroha_genesis::{GenesisNetwork, RawGenesisBlockBuilder}; +use iroha_primitives::unique_vec; use iroha_version::Encode; use test_network::{get_key_pair, Peer as TestPeer, PeerBuilder, TestRuntime}; use tokio::runtime::Runtime; @@ -17,10 +18,7 @@ const MINIMUM_SUCCESS_REQUEST_RATIO: f32 = 0.9; fn query_requests(criterion: &mut Criterion) { let mut peer = ::new().expect("Failed to create peer"); - let configuration = get_config( - std::iter::once(peer.id.clone()).collect(), - Some(get_key_pair()), - ); + let configuration = get_config(unique_vec![peer.id.clone()], Some(get_key_pair())); let rt = Runtime::test(); let genesis = GenesisNetwork::from_configuration( @@ -117,10 +115,7 @@ fn instruction_submits(criterion: &mut Criterion) { println!("instruction submits"); let rt = Runtime::test(); let mut peer = ::new().expect("Failed to create peer"); - let configuration = get_config( - std::iter::once(peer.id.clone()).collect(), - Some(get_key_pair()), - ); + let configuration = get_config(unique_vec![peer.id.clone()], Some(get_key_pair())); let genesis = GenesisNetwork::from_configuration( RawGenesisBlockBuilder::new() .domain("wonderland".parse().expect("Valid")) diff --git a/client/examples/million_accounts_genesis.rs b/client/examples/million_accounts_genesis.rs index f2452b2a786..a04e8a4d108 100644 --- a/client/examples/million_accounts_genesis.rs +++ b/client/examples/million_accounts_genesis.rs @@ -5,6 +5,7 @@ use std::{thread, time::Duration}; use iroha::samples::{construct_validator, get_config}; use iroha_data_model::prelude::*; use iroha_genesis::{GenesisNetwork, RawGenesisBlock, RawGenesisBlockBuilder}; +use iroha_primitives::unique_vec; use test_network::{ get_key_pair, wait_for_genesis_committed, Peer as TestPeer, PeerBuilder, TestRuntime, }; @@ -37,10 +38,7 @@ fn generate_genesis(num_domains: u32) -> RawGenesisBlock { fn main_genesis() { let mut peer = ::new().expect("Failed to create peer"); - let configuration = get_config( - std::iter::once(peer.id.clone()).collect(), - Some(get_key_pair()), - ); + let configuration = get_config(unique_vec![peer.id.clone()], Some(get_key_pair())); let rt = Runtime::test(); let genesis = GenesisNetwork::from_configuration( generate_genesis(1_000_000_u32), diff --git a/client/tests/integration/restart_peer.rs b/client/tests/integration/restart_peer.rs index 6044faeebab..1a9f810853f 100644 --- a/client/tests/integration/restart_peer.rs +++ b/client/tests/integration/restart_peer.rs @@ -5,6 +5,7 @@ use std::{str::FromStr, sync::Arc}; use eyre::Result; use iroha_client::client::{self, QueryResult}; use iroha_data_model::prelude::*; +use iroha_primitives::unique_vec; use tempfile::TempDir; use test_network::*; use tokio::runtime::Runtime; @@ -17,7 +18,7 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { let mut configuration = Configuration::test(); let mut peer = ::new().with_port(10_000).build()?; - configuration.sumeragi.trusted_peers.peers = std::iter::once(peer.id.clone()).collect(); + configuration.sumeragi.trusted_peers.peers = unique_vec![peer.id.clone()]; let account_id = AccountId::from_str("alice@wonderland").unwrap(); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").unwrap(); diff --git a/config/src/sumeragi.rs b/config/src/sumeragi.rs index dc8099a876e..1ebcfa30972 100644 --- a/config/src/sumeragi.rs +++ b/config/src/sumeragi.rs @@ -1,11 +1,12 @@ //! `Sumeragi` configuration. Contains both block commit and Gossip-related configuration. #![allow(clippy::std_instead_of_core, clippy::arithmetic_side_effects)] -use std::{collections::HashSet, fmt::Debug, fs::File, io::BufReader, path::Path}; +use std::{fmt::Debug, fs::File, io::BufReader, path::Path}; use eyre::{Result, WrapErr}; use iroha_config_base::derive::{view, Documented, Proxy}; use iroha_crypto::prelude::*; use iroha_data_model::prelude::*; +use iroha_primitives::{unique_vec, unique_vec::UniqueVec}; use serde::{Deserialize, Serialize}; use self::default::*; @@ -92,14 +93,14 @@ impl ConfigurationProxy { /// The [`peer_id`] field of [`Self`] /// has not been initialized prior to calling this method. pub fn insert_self_as_trusted_peers(&mut self) { - let mut peers = HashSet::new(); #[allow(clippy::expect_used)] let peer_id = self .peer_id .clone() .expect("Insertion of `self` as `trusted_peers` implies that `peer_id` field should be initialized"); - peers.insert(peer_id); - self.trusted_peers = Some(TrustedPeers { peers }); + self.trusted_peers = Some(TrustedPeers { + peers: unique_vec![peer_id], + }); } } @@ -122,52 +123,8 @@ impl Configuration { pub struct TrustedPeers { /// Optional list of predefined trusted peers. Must contain unique /// entries. Custom deserializer raises error if duplicates found. - #[serde(deserialize_with = "deserialize_unique_trusted_peers")] - pub peers: HashSet, -} - -/// Custom deserializer that ensures that `trusted_peers` only -/// contains unique `PeerId`'s. -/// -/// # Errors -/// - Peer Ids not unique, -/// - Not a sequence (array) -fn deserialize_unique_trusted_peers<'de, D>(deserializer: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - /// Helper, for constructing a unique visitor that errors whenever - /// a duplicate entry is found. - struct UniqueVisitor(core::marker::PhantomData HashSet>); - - impl<'de> serde::de::Visitor<'de> for UniqueVisitor { - type Value = HashSet; - - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { - formatter.write_str("a set of unique `Peer::Id`s.") - } - - fn visit_seq(self, mut seq: S) -> Result, S::Error> - where - S: serde::de::SeqAccess<'de>, - { - let mut result = HashSet::new(); - while let Some(value) = seq.next_element()? { - if result.contains(&value) { - return Err(serde::de::Error::custom(format!( - "The peer id: {}'s public key appears twice.", - &value - ))); - } - result.insert(value); - } - - Ok(result) - } - } - - let visitor = UniqueVisitor(core::marker::PhantomData); - deserializer.deserialize_seq(visitor) + #[serde(deserialize_with = "UniqueVec::display_deserialize_failing_on_duplicates")] + pub peers: UniqueVec, } impl TrustedPeers { @@ -181,11 +138,9 @@ impl TrustedPeers { let file = File::open(&path) .wrap_err_with(|| format!("Failed to open trusted peers file {:?}", &path))?; let reader = BufReader::new(file); - let trusted_peers: HashSet = - serde_json::from_reader(reader).wrap_err("Failed to deserialize json from reader")?; - Ok(TrustedPeers { - peers: trusted_peers, - }) + serde_json::from_reader(reader) + .wrap_err("Failed to deserialize json from reader") + .map_err(Into::into) } } diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index 13671a3555766bc342a16d93d6f5fd1e2d192d4c..addfc5d3d8daa8ae4bce07a361f6b376f7262240 100644 GIT binary patch delta 139577 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%0D-(Ik!3G~WdQNx)#ofhmxZ0=|(#!q7;g?hf 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 B0tx^C delta 138389 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 pb|bwvC)M^w5V#~xPD0p&FyrK&&)#nI`ClWPZ$ WorldStateView { let kura = iroha_core::kura::Kura::blank_kura_for_testing(); - let mut wsv = WorldStateView::new(World::with([], BTreeSet::new()), kura); + let mut wsv = WorldStateView::new(World::with([], UniqueVec::new()), kura); wsv.config.transaction_limits = TransactionLimits::new(u64::MAX, u64::MAX); wsv.config.wasm_runtime_config.fuel_limit = u64::MAX; wsv.config.wasm_runtime_config.max_memory = u32::MAX; diff --git a/core/benches/kura.rs b/core/benches/kura.rs index cb082b94ba4..558e83c0cd5 100644 --- a/core/benches/kura.rs +++ b/core/benches/kura.rs @@ -13,6 +13,7 @@ use iroha_core::{ }; use iroha_crypto::KeyPair; use iroha_data_model::{prelude::*, transaction::TransactionLimits}; +use iroha_primitives::unique_vec::UniqueVec; use tokio::{fs, runtime::Runtime}; async fn measure_block_size_for_n_validators(n_validators: u32) { @@ -42,7 +43,7 @@ async fn measure_block_size_for_n_validators(n_validators: u32) { let _thread_handle = iroha_core::kura::Kura::start(kura.clone()); let mut wsv = WorldStateView::new(World::new(), kura); - let topology = Topology::new(Vec::new()); + let topology = Topology::new(UniqueVec::new()); let mut block = BlockBuilder::new(vec![tx], topology, Vec::new()) .chain_first(&mut wsv) .sign(KeyPair::generate().unwrap()) diff --git a/core/benches/validation.rs b/core/benches/validation.rs index ea30e4e14db..36886ac87d4 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -1,6 +1,6 @@ #![allow(missing_docs, clippy::restriction)] -use std::{collections::BTreeSet, str::FromStr as _}; +use std::str::FromStr as _; use criterion::{criterion_group, criterion_main, Criterion}; use iroha_core::{ @@ -12,6 +12,7 @@ use iroha_core::{ wsv::World, }; use iroha_data_model::{prelude::*, transaction::TransactionLimits}; +use iroha_primitives::unique_vec::UniqueVec; const START_DOMAIN: &str = "start"; const START_ACCOUNT: &str = "starter"; @@ -66,7 +67,7 @@ fn build_test_and_transient_wsv(keys: KeyPair) -> WorldStateView { let mut domain = Domain::new(domain_id).build(&account_id); let account = Account::new(account_id.clone(), [public_key]).build(&account_id); assert!(domain.add_account(account).is_none()); - World::with([domain], BTreeSet::new()) + World::with([domain], UniqueVec::new()) }, kura, ); @@ -146,7 +147,7 @@ fn sign_blocks(criterion: &mut Criterion) { let key_pair = KeyPair::generate().expect("Failed to generate KeyPair."); let kura = iroha_core::kura::Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(World::new(), kura); - let topology = Topology::new(Vec::new()); + let topology = Topology::new(UniqueVec::new()); let mut success_count = 0; let mut failures_count = 0; diff --git a/core/src/block.rs b/core/src/block.rs index 55f48805171..609179c710b 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -22,14 +22,11 @@ use iroha_data_model::{ transaction::{error::TransactionRejectionReason, prelude::*}, }; use iroha_genesis::GenesisTransaction; +use iroha_primitives::unique_vec::UniqueVec; use thiserror::Error; pub use self::{chained::Chained, commit::CommittedBlock, valid::ValidBlock}; -use crate::{ - prelude::*, - sumeragi::network_topology::{SignatureVerificationError, Topology}, - tx::AcceptTransactionFail, -}; +use crate::{prelude::*, sumeragi::network_topology::Topology, tx::AcceptTransactionFail}; /// Error during transaction validation #[derive(Debug, displaydoc::Display, Error)] @@ -68,9 +65,9 @@ pub enum BlockValidationError { /// Mismatch between the actual and expected topology. Expected: {expected:?}, actual: {actual:?} TopologyMismatch { /// Expected value - expected: Vec, + expected: UniqueVec, /// Actual value - actual: Vec, + actual: UniqueVec, }, /// Error during block signatures check SignatureVerification(#[from] SignatureVerificationError), @@ -78,6 +75,26 @@ pub enum BlockValidationError { ViewChangeIndexTooLarge, } +/// Error during signature verification +#[derive(thiserror::Error, displaydoc::Display, Debug, Clone, Copy, PartialEq, Eq)] +pub enum SignatureVerificationError { + /// The block doesn't have enough valid signatures to be committed ({votes_count} out of {min_votes_for_commit}) + NotEnoughSignatures { + /// Current number of signatures + votes_count: usize, + /// Minimal required number of signatures + min_votes_for_commit: usize, + }, + /// The block doesn't contain an expected signature. Expected signature can be leader or the current peer + SignatureMissing, + /// Found signature that does not correspond to block payload + UnknownSignature, + /// The block doesn't have proxy tail signature + ProxyTailMissing, + /// The block doesn't have leader signature + LeaderMissing, +} + /// Builder for blocks #[derive(Debug, Clone)] pub struct BlockBuilder(B); @@ -434,39 +451,9 @@ mod valid { self, topology: &Topology, ) -> Result { - // TODO: Should the peer that serves genesis have a fixed role of ProxyTail in topology? - if !self.payload().header.is_genesis() - && topology.is_consensus_required().is_some() - && topology - .filter_signatures_by_roles(&[Role::ProxyTail], self.signatures()) - .is_empty() - { - return Err((self, SignatureVerificationError::ProxyTailMissing.into())); - } - - #[allow(clippy::collapsible_else_if)] - if self.payload().header.is_genesis() { - // At genesis round we blindly take on the network topology from the genesis block. - } else { - let roles = [ - Role::ValidatingPeer, - Role::Leader, - Role::ProxyTail, - Role::ObservingPeer, - ]; - - let votes_count = topology - .filter_signatures_by_roles(&roles, self.signatures()) - .len(); - if votes_count.lt(&topology.min_votes_for_commit()) { - return Err(( - self, - SignatureVerificationError::NotEnoughSignatures { - votes_count, - min_votes_for_commit: topology.min_votes_for_commit(), - } - .into(), - )); + if !self.payload().header.is_genesis() { + if let Err(err) = self.verify_signatures(topology) { + return Err((self, err.into())); } } @@ -500,11 +487,11 @@ mod valid { header: BlockHeader { timestamp_ms: 0, consensus_estimation_ms: DEFAULT_CONSENSUS_ESTIMATION_MS, - height: 1, + height: 2, view_change_index: 0, previous_block_hash: None, transactions_hash: None, - commit_topology: Vec::new(), + commit_topology: UniqueVec::new(), }, transactions: Vec::new(), event_recommendations: Vec::new(), @@ -512,6 +499,50 @@ mod valid { .sign(KeyPair::generate().unwrap()) .unwrap() } + + /// Check if block's signatures meet requirements for given topology. + /// + /// In order for block to be considered valid there should be at least $2f + 1$ signatures (including proxy tail and leader signature) where f is maximum number of faulty nodes. + /// For further information please refer to the [whitepaper](docs/source/iroha_2_whitepaper.md) section 2.8 consensus. + /// + /// # Errors + /// - Not enough signatures + /// - Missing proxy tail signature + fn verify_signatures(&self, topology: &Topology) -> Result<(), SignatureVerificationError> { + // TODO: Should the peer that serves genesis have a fixed role of ProxyTail in topology? + if !self.payload().header.is_genesis() + && topology.is_consensus_required().is_some() + && topology + .filter_signatures_by_roles(&[Role::ProxyTail], self.signatures()) + .is_empty() + { + return Err(SignatureVerificationError::ProxyTailMissing); + } + + #[allow(clippy::collapsible_else_if)] + if self.payload().header.is_genesis() { + // At genesis round we blindly take on the network topology from the genesis block. + } else { + let roles = [ + Role::ValidatingPeer, + Role::Leader, + Role::ProxyTail, + Role::ObservingPeer, + ]; + + let votes_count = topology + .filter_signatures_by_roles(&roles, self.signatures()) + .len(); + if votes_count < topology.min_votes_for_commit() { + return Err(SignatureVerificationError::NotEnoughSignatures { + votes_count, + min_votes_for_commit: topology.min_votes_for_commit(), + }); + } + } + + Ok(()) + } } impl From for VersionedSignedBlock { @@ -519,6 +550,118 @@ mod valid { source.0 } } + + #[cfg(test)] + mod tests { + use super::*; + use crate::sumeragi::network_topology::test_peers; + + #[test] + fn signature_verification_ok() { + let key_pairs = core::iter::repeat_with(|| { + KeyPair::generate().expect("Failed to generate key pair") + }) + .take(7) + .collect::>(); + let mut key_pairs_iter = key_pairs.iter(); + let peers = test_peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; + let topology = Topology::new(peers); + + let mut block = ValidBlock::new_dummy(); + let payload = block.payload().clone(); + key_pairs + .iter() + .map(|key_pair| { + SignatureOf::new(key_pair.clone(), &payload).expect("Failed to sign") + }) + .try_for_each(|signature| block.add_signature(signature)) + .expect("Failed to add signatures"); + + assert_eq!(block.verify_signatures(&topology), Ok(())); + } + + #[test] + fn signature_verification_consensus_not_required_ok() { + let key_pairs = core::iter::repeat_with(|| { + KeyPair::generate().expect("Failed to generate key pair") + }) + .take(1) + .collect::>(); + let mut key_pairs_iter = key_pairs.iter(); + let peers = test_peers![0,: key_pairs_iter]; + let topology = Topology::new(peers); + + let mut block = ValidBlock::new_dummy(); + let payload = block.payload().clone(); + key_pairs + .iter() + .enumerate() + .map(|(_, key_pair)| { + SignatureOf::new(key_pair.clone(), &payload).expect("Failed to sign") + }) + .try_for_each(|signature| block.add_signature(signature)) + .expect("Failed to add signatures"); + + assert_eq!(block.verify_signatures(&topology), Ok(())); + } + + /// Check requirement of having at least $2f + 1$ signatures in $3f + 1$ network + #[test] + fn signature_verification_not_enough_signatures() { + let key_pairs = core::iter::repeat_with(|| { + KeyPair::generate().expect("Failed to generate key pair") + }) + .take(7) + .collect::>(); + let mut key_pairs_iter = key_pairs.iter(); + let peers = test_peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; + let topology = Topology::new(peers); + + let mut block = ValidBlock::new_dummy(); + let payload = block.payload().clone(); + let proxy_tail_signature = + SignatureOf::new(key_pairs[4].clone(), &payload).expect("Failed to sign"); + block + .add_signature(proxy_tail_signature) + .expect("Failed to add signature"); + + assert_eq!( + block.verify_signatures(&topology), + Err(SignatureVerificationError::NotEnoughSignatures { + votes_count: 1, + min_votes_for_commit: topology.min_votes_for_commit(), + }) + ) + } + + /// Check requirement of having leader signature + #[test] + fn signature_verification_miss_proxy_tail_signature() { + let key_pairs = core::iter::repeat_with(|| { + KeyPair::generate().expect("Failed to generate key pair") + }) + .take(7) + .collect::>(); + let mut key_pairs_iter = key_pairs.iter(); + let peers = test_peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; + let topology = Topology::new(peers); + + let mut block = ValidBlock::new_dummy(); + let payload = block.payload().clone(); + key_pairs + .iter() + .enumerate() + .filter(|(i, _)| *i != 4) // Skip proxy tail + .map(|(_, key_pair)| SignatureOf::new(key_pair.clone(), &payload).expect("Failed to sign")) + .try_for_each(|signature| block.add_signature(signature)) + .expect("Failed to add signatures"); + + assert_eq!( + block.verify_signatures(&topology), + Err(SignatureVerificationError::ProxyTailMissing) + ) + } + } } mod commit { @@ -596,7 +739,7 @@ mod tests { #[test] pub fn committed_and_valid_block_hashes_are_equal() { let valid_block = ValidBlock::new_dummy(); - let topology = Topology::new(Vec::new()); + let topology = Topology::new(UniqueVec::new()); let committed_block = valid_block.clone().commit(&topology).unwrap(); assert_eq!( @@ -615,7 +758,7 @@ mod tests { let domain_id = DomainId::from_str("wonderland").expect("Valid"); let mut domain = Domain::new(domain_id).build(&alice_id); assert!(domain.add_account(account).is_none()); - let world = World::with([domain], Vec::new()); + let world = World::with([domain], UniqueVec::new()); let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(world, kura); @@ -634,7 +777,7 @@ mod tests { // Creating a block of two identical transactions and validating it let transactions = vec![tx.clone(), tx]; - let topology = Topology::new(Vec::new()); + let topology = Topology::new(UniqueVec::new()); let valid_block = BlockBuilder::new(transactions, topology, Vec::new()) .chain_first(&mut wsv) .sign(alice_keys) @@ -657,7 +800,7 @@ mod tests { let domain_id = DomainId::from_str("wonderland").expect("Valid"); let mut domain = Domain::new(domain_id).build(&alice_id); assert!(domain.add_account(account).is_none()); - let world = World::with([domain], Vec::new()); + let world = World::with([domain], UniqueVec::new()); let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(world, kura); @@ -701,7 +844,7 @@ mod tests { // Creating a block of two identical transactions and validating it let transactions = vec![tx0, tx, tx2]; - let topology = Topology::new(Vec::new()); + let topology = Topology::new(UniqueVec::new()); let valid_block = BlockBuilder::new(transactions, topology, Vec::new()) .chain_first(&mut wsv) .sign(alice_keys) @@ -727,7 +870,7 @@ mod tests { domain.add_account(account).is_none(), "`alice@wonderland` already exist in the blockchain" ); - let world = World::with([domain], Vec::new()); + let world = World::with([domain], UniqueVec::new()); let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(world, kura); let transaction_limits = &wsv.transaction_validator().transaction_limits; @@ -754,7 +897,7 @@ mod tests { // Creating a block of where first transaction must fail and second one fully executed let transactions = vec![tx_fail, tx_accept]; - let topology = Topology::new(Vec::new()); + let topology = Topology::new(UniqueVec::new()); let valid_block = BlockBuilder::new(transactions, topology, Vec::new()) .chain_first(&mut wsv) .sign(alice_keys) diff --git a/core/src/lib.rs b/core/src/lib.rs index 2ccbacd4f06..40da6b6b051 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -18,6 +18,7 @@ use std::collections::{HashMap, HashSet}; use gossiper::TransactionGossip; use iroha_data_model::{permission::Permissions, prelude::*}; +use iroha_primitives::unique_vec::UniqueVec; use parity_scale_codec::{Decode, Encode}; use tokio::sync::broadcast; @@ -33,7 +34,7 @@ pub const TX_RETRIEVAL_INTERVAL: Duration = Duration::from_millis(100); pub type IrohaNetwork = iroha_p2p::NetworkHandle; /// Ids of peers. -pub type PeersIds = HashSet; +pub type PeersIds = UniqueVec; /// Parameters set. pub type Parameters = HashSet; diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index bb33e436c7b..f33d9cff7b0 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -180,6 +180,7 @@ mod tests { use iroha_crypto::{Hash, HashOf, KeyPair}; use iroha_data_model::{query::error::FindError, transaction::TransactionLimits}; + use iroha_primitives::unique_vec::UniqueVec; use once_cell::sync::Lazy; use super::*; @@ -290,7 +291,7 @@ mod tests { let mut transactions = vec![valid_tx; valid_tx_per_block]; transactions.append(&mut vec![invalid_tx; invalid_tx_per_block]); - let topology = Topology::new(vec![]); + let topology = Topology::new(UniqueVec::new()); let first_block = BlockBuilder::new(transactions.clone(), topology.clone(), Vec::new()) .chain_first(&mut wsv) .sign(ALICE_KEYS.clone())? @@ -426,7 +427,7 @@ mod tests { let tx_limits = &wsv.transaction_validator().transaction_limits; let va_tx = AcceptedTransaction::accept(tx, tx_limits)?; - let topology = Topology::new(vec![]); + let topology = Topology::new(UniqueVec::new()); let vcb = BlockBuilder::new(vec![va_tx.clone()], topology.clone(), Vec::new()) .chain_first(&mut wsv) .sign(ALICE_KEYS.clone())? diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index 681599efc33..87c0a95e805 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -33,7 +33,7 @@ pub mod isi { let peer_id = self.object.id; let world = wsv.world_mut(); - if !world.trusted_peers_ids.insert(peer_id.clone()) { + if !world.trusted_peers_ids.push(peer_id.clone()) { return Err(RepetitionError { instruction_type: InstructionType::Register, id: IdBox::PeerId(peer_id), @@ -52,9 +52,11 @@ pub mod isi { fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let peer_id = self.object_id; let world = wsv.world_mut(); - if !world.trusted_peers_ids.remove(&peer_id) { + let Some(index) = world.trusted_peers_ids.iter().position(|id| id == &peer_id) else { return Err(FindError::Peer(peer_id).into()); - } + }; + + world.trusted_peers_ids.remove(index); wsv.emit_events(Some(PeerEvent::Removed(peer_id))); diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index 133e3018c46..9691564db65 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -6,6 +6,7 @@ use iroha_data_model::{ transaction::error::TransactionRejectionReason, }; use iroha_p2p::UpdateTopology; +use iroha_primitives::unique_vec::UniqueVec; use tracing::{span, Level}; use super::{view_change::ProofBuilder, *}; @@ -288,13 +289,10 @@ impl Sumeragi { self.update_state::(block, new_wsv); } - fn update_topology(&mut self, block_signees: &[PublicKey], peers: Vec) { + fn update_topology(&mut self, block_signees: &[PublicKey], peers: UniqueVec) { let mut topology = Topology::new(peers); - topology.update_topology( - block_signees, - self.wsv.peers_ids().iter().cloned().collect(), - ); + topology.update_topology(block_signees, self.wsv.peers_ids().clone()); self.current_topology = topology; self.connect_peers(&self.current_topology); @@ -1102,7 +1100,7 @@ fn handle_block_sync( let last_committed_block = new_wsv .latest_block_ref() .expect("Not in genesis round so must have at least genesis block"); - let new_peers = new_wsv.peers_ids().iter().cloned().collect(); + let new_peers = new_wsv.peers_ids().clone(); let view_change_index = block.payload().header().view_change_index; Topology::recreate_topology(&last_committed_block, view_change_index, new_peers) }; @@ -1122,7 +1120,7 @@ fn handle_block_sync( let last_committed_block = new_wsv .latest_block_ref() .expect("Not in genesis round so must have at least genesis block"); - let new_peers = new_wsv.peers_ids().iter().cloned().collect(); + let new_peers = new_wsv.peers_ids().clone(); let view_change_index = block.payload().header().view_change_index; Topology::recreate_topology(&last_committed_block, view_change_index, new_peers) }; @@ -1162,6 +1160,8 @@ fn handle_block_sync( #[cfg(test)] mod tests { + use iroha_primitives::unique_vec; + use super::*; use crate::smartcontracts::Registrable; @@ -1239,7 +1239,7 @@ mod tests { #[allow(clippy::redundant_clone)] fn block_sync_invalid_block() { let leader_key_pair = KeyPair::generate().unwrap(); - let topology = Topology::new(vec![PeerId::new( + let topology = Topology::new(unique_vec![PeerId::new( &"127.0.0.1:8080".parse().unwrap(), leader_key_pair.public_key(), )]); @@ -1256,7 +1256,7 @@ mod tests { #[test] fn block_sync_invalid_soft_fork_block() { let leader_key_pair = KeyPair::generate().unwrap(); - let topology = Topology::new(vec![PeerId::new( + let topology = Topology::new(unique_vec![PeerId::new( &"127.0.0.1:8080".parse().unwrap(), leader_key_pair.public_key(), )]); @@ -1282,7 +1282,7 @@ mod tests { #[test] #[allow(clippy::redundant_clone)] fn block_sync_not_proper_height() { - let topology = Topology::new(Vec::new()); + let topology = Topology::new(UniqueVec::new()); let leader_key_pair = KeyPair::generate().unwrap(); let (finalized_wsv, _, mut block) = create_data_for_test(&topology, leader_key_pair); let wsv = finalized_wsv.clone(); @@ -1307,7 +1307,7 @@ mod tests { #[allow(clippy::redundant_clone)] fn block_sync_commit_block() { let leader_key_pair = KeyPair::generate().unwrap(); - let topology = Topology::new(vec![PeerId::new( + let topology = Topology::new(unique_vec![PeerId::new( &"127.0.0.1:8080".parse().unwrap(), leader_key_pair.public_key(), )]); @@ -1320,7 +1320,7 @@ mod tests { #[test] fn block_sync_replace_top_block() { let leader_key_pair = KeyPair::generate().unwrap(); - let topology = Topology::new(vec![PeerId::new( + let topology = Topology::new(unique_vec![PeerId::new( &"127.0.0.1:8080".parse().unwrap(), leader_key_pair.public_key(), )]); @@ -1344,7 +1344,7 @@ mod tests { #[test] fn block_sync_small_view_change_index() { let leader_key_pair = KeyPair::generate().unwrap(); - let topology = Topology::new(vec![PeerId::new( + let topology = Topology::new(unique_vec![PeerId::new( &"127.0.0.1:8080".parse().unwrap(), leader_key_pair.public_key(), )]); @@ -1380,7 +1380,7 @@ mod tests { #[test] #[allow(clippy::redundant_clone)] fn block_sync_genesis_block_do_not_replace() { - let topology = Topology::new(Vec::new()); + let topology = Topology::new(UniqueVec::new()); let leader_key_pair = KeyPair::generate().unwrap(); let (finalized_wsv, _, mut block) = create_data_for_test(&topology, leader_key_pair); let wsv = finalized_wsv.clone(); diff --git a/core/src/sumeragi/mod.rs b/core/src/sumeragi/mod.rs index b45d2f08c0f..59a0e1ae729 100644 --- a/core/src/sumeragi/mod.rs +++ b/core/src/sumeragi/mod.rs @@ -212,11 +212,19 @@ impl SumeragiHandle { view_change_proofs: msg.view_change_proofs, }) { self.metrics.dropped_messages.inc(); - error!(?error, "This peer is faulty. Incoming control messages have to be dropped due to low processing speed."); + error!( + ?error, + "This peer is faulty. \ + Incoming control messages have to be dropped due to low processing speed." + ); } } else if let Err(error) = self.message_sender.try_send(msg) { self.metrics.dropped_messages.inc(); - error!(?error, "This peer is faulty. Incoming messages have to be dropped due to low processing speed."); + error!( + ?error, + "This peer is faulty. \ + Incoming messages have to be dropped due to low processing speed." + ); } } @@ -224,6 +232,7 @@ impl SumeragiHandle { /// /// # Panics /// May panic if something is of during initialization which is bug. + #[allow(clippy::too_many_lines)] pub fn start( SumeragiStartArgs { configuration, @@ -241,8 +250,10 @@ impl SumeragiHandle { let skip_block_count = wsv.block_hashes.len(); let mut blocks_iter = (skip_block_count + 1..=block_count).map(|block_height| { - kura.get_block_by_height(block_height as u64) - .expect("Sumeragi should be able to load the block that was reported as presented. If not, the block storage was probably disconnected.") + kura.get_block_by_height(block_height as u64).expect( + "Sumeragi should be able to load the block that was reported as presented. \ + If not, the block storage was probably disconnected.", + ) }); let current_topology = match wsv.height() { @@ -251,7 +262,10 @@ impl SumeragiHandle { Topology::new(configuration.trusted_peers.peers.clone()) } height => { - let block_ref = kura.get_block_by_height(height).expect("Sumeragi could not load block that was reported as present. Please check that the block storage was not disconnected."); + let block_ref = kura.get_block_by_height(height).expect( + "Sumeragi could not load block that was reported as present. \ + Please check that the block storage was not disconnected.", + ); let mut topology = Topology::new(block_ref.payload().header.commit_topology.clone()); topology.rotate_set_a(); @@ -266,8 +280,10 @@ impl SumeragiHandle { .expect("Kura blocks should be valid") .commit(¤t_topology) .expect("Kura blocks should be valid"); - wsv.apply_without_execution(&block) - .expect("Block application in init should not fail. Blocks loaded from kura assumed to be valid"); + wsv.apply_without_execution(&block).expect( + "Block application in init should not fail. \ + Blocks loaded from kura assumed to be valid", + ); } // finalized_wsv is one block behind @@ -279,8 +295,10 @@ impl SumeragiHandle { .expect("Kura blocks should be valid") .commit(¤t_topology) .expect("Kura blocks should be valid"); - wsv.apply_without_execution(&latest_block) - .expect("Block application in init should not fail. Blocks loaded from kura assumed to be valid"); + wsv.apply_without_execution(&latest_block).expect( + "Block application in init should not fail. \ + Blocks loaded from kura assumed to be valid", + ); } info!("Sumeragi has finished loading blocks and setting up the WSV"); diff --git a/core/src/sumeragi/network_topology.rs b/core/src/sumeragi/network_topology.rs index 3612e0dd48f..0ca6e1d3f9a 100644 --- a/core/src/sumeragi/network_topology.rs +++ b/core/src/sumeragi/network_topology.rs @@ -9,12 +9,10 @@ use std::collections::HashSet; use derive_more::Display; -use iroha_crypto::{PublicKey, SignatureOf, SignaturesOf}; -use iroha_data_model::{ - block::{BlockPayload, VersionedSignedBlock}, - prelude::PeerId, -}; +use iroha_crypto::{PublicKey, SignatureOf}; +use iroha_data_model::{block::VersionedSignedBlock, prelude::PeerId}; use iroha_logger::trace; +use iroha_primitives::unique_vec::UniqueVec; /// The ordering of the peers which defines their roles in the current round of consensus. /// @@ -30,7 +28,7 @@ use iroha_logger::trace; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Topology { /// Current order of peers. The roles of peers are defined based on this order. - pub(crate) ordered_peers: Vec, + pub(crate) ordered_peers: UniqueVec, } /// Topology with at least one peer @@ -47,9 +45,9 @@ pub struct ConsensusTopology<'topology> { impl Topology { /// Create a new topology. - pub fn new(peers: impl IntoIterator) -> Self { + pub fn new(peers: UniqueVec) -> Self { Topology { - ordered_peers: peers.into_iter().collect(), + ordered_peers: peers, } } @@ -141,9 +139,8 @@ impl Topology { } /// Add or remove peers from the topology. - pub fn update_peer_list(&mut self, mut new_peers: HashSet) { - self.ordered_peers.retain(|peer| new_peers.remove(peer)); - self.ordered_peers.extend(new_peers); + pub fn update_peer_list(&mut self, new_peers: UniqueVec) { + self.ordered_peers = new_peers } /// Rotate peers after each failed attempt to create a block. @@ -158,19 +155,12 @@ impl Topology { .len() .try_into() .expect("`usize` should fit into `u64`"); - if let Some(mut rem) = n.checked_rem(len) { - // In case where `n` is larger than `usize` could fit - let usize_max = usize::MAX - .try_into() - .expect("`usize` should fit into `u64`"); - while rem > usize_max { - rem -= usize_max; - self.ordered_peers.rotate_left(usize::MAX); - } - let rem = rem - .try_into() - .expect("`rem` is smaller or equal then `usize::MAX`"); - self.ordered_peers.rotate_left(rem); + if let Some(rem) = n.checked_rem(len) { + let rem = rem.try_into().expect( + "`rem` is smaller than `usize::MAX`, because remainder is always smaller than divisor", + ); + + self.modify_peers_directly(|peers| peers.rotate_left(rem)); } } @@ -178,18 +168,19 @@ impl Topology { pub fn rotate_set_a(&mut self) { let rotate_at = self.min_votes_for_commit(); if rotate_at > 0 { - self.ordered_peers[..rotate_at].rotate_left(1); + self.modify_peers_directly(|peers| peers[..rotate_at].rotate_left(1)); } } /// Pull peers up in the topology to the top of the a set while preserving local order. pub fn lift_up_peers(&mut self, to_lift_up: &[PublicKey]) { - self.ordered_peers - .sort_by_cached_key(|peer| !to_lift_up.contains(&peer.public_key)); + self.modify_peers_directly(|peers| { + peers.sort_by_cached_key(|peer| !to_lift_up.contains(&peer.public_key)); + }); } /// Perform sequence of actions after block committed. - pub fn update_topology(&mut self, block_signees: &[PublicKey], new_peers: HashSet) { + pub fn update_topology(&mut self, block_signees: &[PublicKey], new_peers: UniqueVec) { self.lift_up_peers(block_signees); self.rotate_set_a(); self.update_peer_list(new_peers); @@ -199,7 +190,7 @@ impl Topology { pub fn recreate_topology( block: &VersionedSignedBlock, view_change_index: u64, - new_peers: HashSet, + new_peers: UniqueVec, ) -> Self { let mut topology = Topology::new(block.payload().header().commit_topology.clone()); let block_signees = block @@ -217,57 +208,14 @@ impl Topology { topology } - /// Check if block's signatures meet requirements for given topology. - /// - /// In order for block to be considered valid there should be at least $2f + 1$ signatures (including proxy tail and leader signature) where f is maximum number of faulty nodes. - /// For further information please refer to the [whitepaper](docs/source/iroha_2_whitepaper.md) section 2.8 consensus. - /// - /// # Errors - /// - Not enough signatures - /// - Missing proxy tail signature - /// - Missing leader signature - pub fn verify_signatures( - &self, - signatures: &SignaturesOf, - ) -> Result<(), SignatureVerificationError> { - if self.is_consensus_required().is_none() { - return Ok(()); - } + /// Modify [`ordered_peers`](Self::ordered_peers) directly as [`Vec`]. + fn modify_peers_directly(&mut self, f: impl FnOnce(&mut Vec)) { + let unique_peers = std::mem::take(&mut self.ordered_peers); - let votes_count = self - .filter_signatures_by_roles( - &[ - Role::ValidatingPeer, - Role::Leader, - Role::ProxyTail, - Role::ObservingPeer, - ], - signatures.iter(), - ) - .len(); - let min_votes_for_commit = self.min_votes_for_commit(); - if votes_count < min_votes_for_commit { - return Err(SignatureVerificationError::NotEnoughSignatures { - votes_count, - min_votes_for_commit, - }); - } + let mut peers_vec = Vec::from(unique_peers); + f(&mut peers_vec); - if self - .filter_signatures_by_roles(&[Role::Leader], signatures.iter()) - .is_empty() - { - return Err(SignatureVerificationError::LeaderMissing); - } - - if self - .filter_signatures_by_roles(&[Role::ProxyTail], signatures.iter()) - .is_empty() - { - return Err(SignatureVerificationError::ProxyTailMissing); - } - - Ok(()) + self.ordered_peers = UniqueVec::from_iter(peers_vec); } } @@ -320,47 +268,31 @@ pub enum Role { Undefined, } -/// Error during signature verification -#[derive(thiserror::Error, displaydoc::Display, Debug, Clone, Copy, PartialEq, Eq)] -pub enum SignatureVerificationError { - /// The block doesn't have enough valid signatures to be committed ({votes_count} out of {min_votes_for_commit}) - NotEnoughSignatures { - /// Current number of signatures - votes_count: usize, - /// Minimal required number of signatures - min_votes_for_commit: usize, - }, - /// The block doesn't contain an expected signature. Expected signature can be leader or the current peer - SignatureMissing, - /// Found signature that does not correspond to block payload - UnknownSignature, - /// The block doesn't have proxy tail signature - ProxyTailMissing, - /// The block doesn't have leader signature - LeaderMissing, +#[cfg(test)] +macro_rules! test_peers { + ($($id:literal),+$(,)?) => {{ + let mut iter = ::core::iter::repeat_with(|| KeyPair::generate().expect("Failed to generate key pair")); + test_peers![$($id),*: iter] + }}; + ($($id:literal),+$(,)?: $key_pair_iter:expr) => { + ::iroha_primitives::unique_vec![ + $(PeerId::new(&(([0, 0, 0, 0], $id).into()), $key_pair_iter.next().expect("Not enough key pairs").public_key())),+ + ] + }; } +#[cfg(test)] +pub(crate) use test_peers; + #[cfg(test)] mod tests { use iroha_crypto::KeyPair; + use iroha_primitives::unique_vec; use super::*; - use crate::block::ValidBlock; - - macro_rules! peers { - ($($id:literal),+$(,)?) => {{ - let mut iter = core::iter::repeat_with(|| KeyPair::generate().expect("Failed to generate key pair")); - peers![$($id),*: iter] - }}; - ($($id:literal),+$(,)?: $key_pair_iter:expr) => { - vec![ - $(PeerId::new(&(([0, 0, 0, 0], $id).into()), $key_pair_iter.next().expect("Not enough key pairs").public_key())),+ - ] - }; - } fn topology() -> Topology { - let peers = peers![0, 1, 2, 3, 4, 5, 6]; + let peers = test_peers![0, 1, 2, 3, 4, 5, 6]; Topology::new(peers) } @@ -405,12 +337,12 @@ mod tests { let mut topology = topology(); // New peers will be 0, 2, 5, 7 let new_peers = { - let mut peers = HashSet::from([ + let mut peers = unique_vec![ topology.ordered_peers[0].clone(), - topology.ordered_peers[5].clone(), topology.ordered_peers[2].clone(), - ]); - peers.extend(peers![7]); + topology.ordered_peers[5].clone(), + ]; + peers.extend(test_peers![7]); peers }; topology.update_peer_list(new_peers); @@ -424,7 +356,7 @@ mod tests { .take(7) .collect::>(); let mut key_pairs_iter = key_pairs.iter(); - let peers = peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; + let peers = test_peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; let topology = Topology::new(peers.clone()); let dummy = "value to sign"; @@ -466,7 +398,7 @@ mod tests { core::iter::repeat_with(|| KeyPair::generate().expect("Failed to generate key pair")) .take(7) .collect::>(); - let peers = Vec::new(); + let peers = UniqueVec::new(); let topology = Topology::new(peers); let dummy = "value to sign"; @@ -499,7 +431,7 @@ mod tests { .take(7) .collect::>(); let mut key_pairs_iter = key_pairs.iter(); - let peers = peers![0: key_pairs_iter]; + let peers = test_peers![0: key_pairs_iter]; let topology = Topology::new(peers.clone()); let dummy = "value to sign"; @@ -533,7 +465,7 @@ mod tests { .take(7) .collect::>(); let mut key_pairs_iter = key_pairs.iter(); - let peers = peers![0, 1: key_pairs_iter]; + let peers = test_peers![0, 1: key_pairs_iter]; let topology = Topology::new(peers.clone()); let dummy = "value to sign"; @@ -568,7 +500,7 @@ mod tests { .take(7) .collect::>(); let mut key_pairs_iter = key_pairs.iter(); - let peers = peers![0, 1, 2: key_pairs_iter]; + let peers = test_peers![0, 1, 2: key_pairs_iter]; let topology = Topology::new(peers.clone()); let dummy = "value to sign"; @@ -602,8 +534,8 @@ mod tests { #[test] fn roles() { - let peers = peers![0, 1, 2, 3, 4, 5, 6]; - let not_in_topology_peers = peers![7, 8, 9]; + let peers = test_peers![0, 1, 2, 3, 4, 5, 6]; + let not_in_topology_peers = test_peers![7, 8, 9]; let topology = Topology::new(peers.clone()); let expected_roles = [ Role::Leader, @@ -632,7 +564,7 @@ mod tests { #[test] fn proxy_tail() { - let peers = peers![0, 1, 2, 3, 4, 5, 6]; + let peers = test_peers![0, 1, 2, 3, 4, 5, 6]; let topology = Topology::new(peers.clone()); assert_eq!( @@ -646,7 +578,7 @@ mod tests { #[test] fn proxy_tail_empty() { - let peers = Vec::new(); + let peers = UniqueVec::new(); let topology = Topology::new(peers); assert_eq!( @@ -660,7 +592,7 @@ mod tests { #[test] fn proxy_tail_1() { - let peers = peers![0]; + let peers = test_peers![0]; let topology = Topology::new(peers); assert_eq!( @@ -674,7 +606,7 @@ mod tests { #[test] fn proxy_tail_2() { - let peers = peers![0, 1]; + let peers = test_peers![0, 1]; let topology = Topology::new(peers.clone()); assert_eq!( @@ -688,7 +620,7 @@ mod tests { #[test] fn proxy_tail_3() { - let peers = peers![0, 1, 2]; + let peers = test_peers![0, 1, 2]; let topology = Topology::new(peers.clone()); assert_eq!( @@ -702,7 +634,7 @@ mod tests { #[test] fn leader() { - let peers = peers![0, 1, 2, 3, 4, 5, 6]; + let peers = test_peers![0, 1, 2, 3, 4, 5, 6]; let topology = Topology::new(peers.clone()); assert_eq!( @@ -716,7 +648,7 @@ mod tests { #[test] fn leader_empty() { - let peers = Vec::new(); + let peers = UniqueVec::new(); let topology = Topology::new(peers); assert_eq!( @@ -730,7 +662,7 @@ mod tests { #[test] fn leader_1() { - let peers = peers![0]; + let peers = test_peers![0]; let topology = Topology::new(peers.clone()); assert_eq!( @@ -744,7 +676,7 @@ mod tests { #[test] fn leader_2() { - let peers = peers![0, 1]; + let peers = test_peers![0, 1]; let topology = Topology::new(peers.clone()); assert_eq!( @@ -758,7 +690,7 @@ mod tests { #[test] fn leader_3() { - let peers = peers![0, 1, 3]; + let peers = test_peers![0, 1, 3]; let topology = Topology::new(peers.clone()); assert_eq!( @@ -772,7 +704,7 @@ mod tests { #[test] fn validating_peers() { - let peers = peers![0, 1, 2, 3, 4, 5, 6]; + let peers = test_peers![0, 1, 2, 3, 4, 5, 6]; let topology = Topology::new(peers.clone()); assert_eq!( @@ -786,7 +718,7 @@ mod tests { #[test] fn validating_peers_empty() { - let peers = Vec::new(); + let peers = UniqueVec::new(); let topology = Topology::new(peers); assert_eq!( @@ -800,7 +732,7 @@ mod tests { #[test] fn validating_peers_1() { - let peers = peers![0]; + let peers = test_peers![0]; let topology = Topology::new(peers); assert_eq!( @@ -814,7 +746,7 @@ mod tests { #[test] fn validating_peers_2() { - let peers = peers![0, 1]; + let peers = test_peers![0, 1]; let topology = Topology::new(peers); let empty_peer_slice: &[PeerId] = &[]; @@ -829,7 +761,7 @@ mod tests { #[test] fn validating_peers_3() { - let peers = peers![0, 1, 2]; + let peers = test_peers![0, 1, 2]; let topology = Topology::new(peers.clone()); assert_eq!( @@ -843,7 +775,7 @@ mod tests { #[test] fn observing_peers() { - let peers = peers![0, 1, 2, 3, 4, 5, 6]; + let peers = test_peers![0, 1, 2, 3, 4, 5, 6]; let topology = Topology::new(peers.clone()); assert_eq!( @@ -857,7 +789,7 @@ mod tests { #[test] fn observing_peers_empty() { - let peers = Vec::new(); + let peers = UniqueVec::new(); let topology = Topology::new(peers); assert_eq!( @@ -871,7 +803,7 @@ mod tests { #[test] fn observing_peers_1() { - let peers = peers![0]; + let peers = test_peers![0]; let topology = Topology::new(peers); assert_eq!( @@ -885,7 +817,7 @@ mod tests { #[test] fn observing_peers_2() { - let peers = peers![0, 1]; + let peers = test_peers![0, 1]; let topology = Topology::new(peers); let empty_peer_slice: &[PeerId] = &[]; @@ -900,7 +832,7 @@ mod tests { #[test] fn observing_peers_3() { - let peers = peers![0, 1, 2]; + let peers = test_peers![0, 1, 2]; let topology = Topology::new(peers); let empty_peer_slice: &[PeerId] = &[]; @@ -912,120 +844,4 @@ mod tests { Some(empty_peer_slice) ); } - - #[test] - fn signature_verification_ok() { - let key_pairs = - core::iter::repeat_with(|| KeyPair::generate().expect("Failed to generate key pair")) - .take(7) - .collect::>(); - let mut key_pairs_iter = key_pairs.iter(); - let peers = peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; - let topology = Topology::new(peers); - - let dummy = ValidBlock::new_dummy(); - let signatures = key_pairs - .iter() - .map(|key_pair| { - SignatureOf::new(key_pair.clone(), dummy.payload()).expect("Failed to sign") - }) - .collect(); - - assert_eq!(topology.verify_signatures(&signatures), Ok(())); - } - - #[test] - fn signature_verification_consensus_not_required_ok() { - let key_pairs = - core::iter::repeat_with(|| KeyPair::generate().expect("Failed to generate key pair")) - .take(1) - .collect::>(); - let mut key_pairs_iter = key_pairs.iter(); - let peers = peers![0,: key_pairs_iter]; - let topology = Topology::new(peers); - - let dummy = ValidBlock::new_dummy(); - let signatures = key_pairs - .iter() - .enumerate() - .map(|(_, key_pair)| { - SignatureOf::new(key_pair.clone(), dummy.payload()).expect("Failed to sign") - }) - .collect(); - - let result = topology.verify_signatures(&signatures); - assert_eq!(result, Ok(())) - } - - /// Check requirement of having at least $2f + 1$ signatures in $3f + 1$ network - #[test] - fn signature_verification_not_enough_signatures() { - let key_pairs = - core::iter::repeat_with(|| KeyPair::generate().expect("Failed to generate key pair")) - .take(7) - .collect::>(); - let mut key_pairs_iter = key_pairs.iter(); - let peers = peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; - let topology = Topology::new(peers); - - let dummy = ValidBlock::new_dummy(); - let signatures = SignatureOf::new(key_pairs[0].clone(), dummy.payload()) - .expect("Failed to sign") - .into(); - - let result = topology.verify_signatures(&signatures); - assert_eq!( - result, - Err(SignatureVerificationError::NotEnoughSignatures { - votes_count: 1, - min_votes_for_commit: topology.min_votes_for_commit(), - }) - ) - } - - /// Check requirement of having leader signature - #[test] - fn signature_verification_miss_leader_signature() { - let key_pairs = - core::iter::repeat_with(|| KeyPair::generate().expect("Failed to generate key pair")) - .take(7) - .collect::>(); - let mut key_pairs_iter = key_pairs.iter(); - let peers = peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; - let topology = Topology::new(peers); - - let dummy = ValidBlock::new_dummy(); - let signatures = key_pairs - .iter() - .enumerate() - .filter(|(i, _)| *i != 0) // Skip leader - .map(|(_, key_pair)| SignatureOf::new(key_pair.clone(), dummy.payload()).expect("Failed to sign")) - .collect(); - - let result = topology.verify_signatures(&signatures); - assert_eq!(result, Err(SignatureVerificationError::LeaderMissing)) - } - - /// Check requirement of having leader signature - #[test] - fn signature_verification_miss_proxy_tail_signature() { - let key_pairs = - core::iter::repeat_with(|| KeyPair::generate().expect("Failed to generate key pair")) - .take(7) - .collect::>(); - let mut key_pairs_iter = key_pairs.iter(); - let peers = peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; - let topology = Topology::new(peers); - - let dummy = ValidBlock::new_dummy(); - let signatures = key_pairs - .iter() - .enumerate() - .filter(|(i, _)| *i != 4) // Skip proxy tail - .map(|(_, key_pair)| SignatureOf::new(key_pair.clone(), dummy.payload()).expect("Failed to sign")) - .collect(); - - let result = topology.verify_signatures(&signatures); - assert_eq!(result, Err(SignatureVerificationError::ProxyTailMissing)) - } } diff --git a/core/src/wsv.rs b/core/src/wsv.rs index e1e9d1adc48..f6ed8a07444 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -248,16 +248,14 @@ impl World { } /// Creates a [`World`] with these [`Domain`]s and trusted [`PeerId`]s. - pub fn with(domains: D, trusted_peers_ids: P) -> Self + pub fn with(domains: D, trusted_peers_ids: PeersIds) -> Self where D: IntoIterator, - P: IntoIterator, { let domains = domains .into_iter() .map(|domain| (domain.id().clone(), domain)) .collect(); - let trusted_peers_ids = trusted_peers_ids.into_iter().collect(); World { domains, trusted_peers_ids, @@ -1251,6 +1249,8 @@ impl WorldStateView { mod tests { #![allow(clippy::restriction)] + use iroha_primitives::unique_vec::UniqueVec; + use super::*; use crate::{block::ValidBlock, sumeragi::network_topology::Topology}; @@ -1258,7 +1258,7 @@ mod tests { fn get_block_hashes_after_hash() { const BLOCK_CNT: usize = 10; - let topology = Topology::new(Vec::new()); + let topology = Topology::new(UniqueVec::new()); let block = ValidBlock::new_dummy().commit(&topology).unwrap(); let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(World::default(), kura); @@ -1285,7 +1285,7 @@ mod tests { fn get_blocks_from_height() { const BLOCK_CNT: usize = 10; - let topology = Topology::new(Vec::new()); + let topology = Topology::new(UniqueVec::new()); let block = ValidBlock::new_dummy().commit(&topology).unwrap(); let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(World::default(), kura.clone()); diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 217961f466a..2589745665e 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -4,12 +4,7 @@ use core::{fmt::Debug, str::FromStr as _, time::Duration}; #[cfg(debug_assertions)] use std::sync::atomic::AtomicBool; -use std::{ - collections::{HashMap, HashSet}, - path::Path, - sync::Arc, - thread, -}; +use std::{collections::BTreeMap, path::Path, sync::Arc, thread}; use eyre::Result; use futures::{prelude::*, stream::FuturesUnordered}; @@ -28,7 +23,11 @@ use iroha_data_model::{ }; use iroha_genesis::{GenesisNetwork, RawGenesisBlock}; use iroha_logger::{Configuration as LoggerConfiguration, InstrumentFutures}; -use iroha_primitives::addr::{socket_addr, SocketAddr}; +use iroha_primitives::{ + addr::{socket_addr, SocketAddr}, + unique_vec, + unique_vec::UniqueVec, +}; use rand::seq::IteratorRandom; use serde_json::json; use tempfile::TempDir; @@ -47,7 +46,9 @@ pub struct Network { /// Genesis peer which sends genesis block to everyone pub genesis: Peer, /// Peers excluding the `genesis` peer. Use [`Network::peers`] function to get all instead. - pub peers: HashMap, + /// + /// [`BTreeMap`] is used in order to have deterministic order of peers. + pub peers: BTreeMap, } /// Get a standardised key-pair from the hard-coded literals. @@ -205,7 +206,8 @@ impl Network { Client::test(&self.genesis.api_address, &self.genesis.telemetry_address); let mut config = Configuration::test(); - config.sumeragi.trusted_peers.peers = self.peers().map(|peer| &peer.id).cloned().collect(); + config.sumeragi.trusted_peers.peers = + UniqueVec::from_iter(self.peers().map(|peer| &peer.id).cloned()); let peer = PeerBuilder::new() .with_configuration(config) @@ -264,7 +266,7 @@ impl Network { let mut configuration = default_configuration.unwrap_or_else(Configuration::test); configuration.sumeragi.trusted_peers.peers = - peers.iter().map(|peer| peer.id.clone()).collect(); + UniqueVec::from_iter(peers.iter().map(|peer| peer.id.clone())); let mut genesis_peer = peers.remove(0); let genesis_builder = builders.remove(0).with_configuration(configuration.clone()); @@ -296,7 +298,7 @@ impl Network { peers: peers .into_iter() .map(|peer| (peer.id.clone(), peer)) - .collect::>(), + .collect::>(), }) } @@ -609,7 +611,7 @@ impl PeerBuilder { pub async fn start_with_peer(self, peer: &mut Peer) { let configuration = self.configuration.unwrap_or_else(|| { let mut config = Configuration::test(); - config.sumeragi.trusted_peers.peers = std::iter::once(peer.id.clone()).collect(); + config.sumeragi.trusted_peers.peers = unique_vec![peer.id.clone()]; config }); let genesis = match self.genesis { @@ -779,7 +781,7 @@ impl TestRuntime for Runtime { impl TestConfiguration for Configuration { fn test() -> Self { let mut sample_proxy = - iroha::samples::get_config_proxy(HashSet::new(), Some(get_key_pair())); + iroha::samples::get_config_proxy(UniqueVec::new(), Some(get_key_pair())); let env_proxy = ConfigurationProxy::from_std_env().expect("Test env variables should parse properly"); let (public_key, private_key) = KeyPair::generate().unwrap().into(); diff --git a/crypto/src/signature.rs b/crypto/src/signature.rs index a3bfaa00a59..4a5c65d7efb 100644 --- a/crypto/src/signature.rs +++ b/crypto/src/signature.rs @@ -25,7 +25,9 @@ use ursa::{ }, }; -use crate::{ffi, Error, PublicKey}; +#[cfg(any(feature = "std", feature = "import_ffi"))] +use crate::Error; +use crate::{ffi, PublicKey}; #[cfg(feature = "std")] use crate::{HashOf, KeyPair}; diff --git a/data_model/src/block.rs b/data_model/src/block.rs index d2d502292db..170a8efbd42 100644 --- a/data_model/src/block.rs +++ b/data_model/src/block.rs @@ -10,9 +10,12 @@ use core::{fmt::Display, time::Duration}; use derive_more::Display; use getset::Getters; -use iroha_crypto::{HashOf, KeyPair, MerkleTree, SignaturesOf}; +#[cfg(all(feature = "std", feature = "transparent_api"))] +use iroha_crypto::KeyPair; +use iroha_crypto::{HashOf, MerkleTree, SignaturesOf}; use iroha_data_model_derive::model; use iroha_macro::FromVariant; +use iroha_primitives::unique_vec::UniqueVec; use iroha_schema::IntoSchema; use iroha_version::{declare_versioned, version_with_scale}; use parity_scale_codec::{Decode, Encode}; @@ -60,7 +63,7 @@ pub mod model { pub transactions_hash: Option>>, /// Topology of the network at the time of block commit. #[getset(skip)] // FIXME: Because ffi related issues - pub commit_topology: Vec, + pub commit_topology: UniqueVec, /// Value of view change index. Used to resolve soft forks. pub view_change_index: u64, /// Estimation of consensus duration (in milliseconds). diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index f078ffe49be..d8763aeb9c6 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -674,7 +674,7 @@ }, { "name": "commit_topology", - "type": "Vec" + "type": "UniqueVec" }, { "name": "view_change_index", @@ -4513,6 +4513,7 @@ } ] }, + "UniqueVec": "Vec", "UnregisterBox": { "Struct": [ { diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index e52774ece8f..faf1990c37b 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -20,6 +20,7 @@ pub mod fixed; pub mod must_use; pub mod riffle_iter; pub mod small; +pub mod unique_vec; use fixed::prelude::*; diff --git a/primitives/src/unique_vec.rs b/primitives/src/unique_vec.rs new file mode 100644 index 00000000000..0e3a4bc3484 --- /dev/null +++ b/primitives/src/unique_vec.rs @@ -0,0 +1,363 @@ +//! Module with [`UniqueVec`] type and related functional. + +#[cfg(not(feature = "std"))] +use alloc::{borrow::ToOwned as _, format, string::String, vec::Vec}; +use core::{ + borrow::Borrow, + fmt::{Debug, Display}, +}; + +use derive_more::{AsRef, Deref}; +use iroha_schema::IntoSchema; +use parity_scale_codec::{Decode, Encode}; +use serde::{Deserialize, Serialize}; + +/// Creates a [`UniqueVec`](unique_vec::UniqueVec) from a list of values. +/// +/// Works like [`vec!`] macro, but does not accept syntax for repeated values +/// and might return [`Result`]. +#[macro_export] +macro_rules! unique_vec { + () => { + $crate::unique_vec::UniqueVec::new() + }; + ($($x:expr),+ $(,)?) => {{ + let mut v = $crate::unique_vec::UniqueVec::new(); + $(v.push($x);)+ + v + }}; +} + +/// Wrapper type for [`Vec`] which ensures that all elements are unique. +#[derive( + Debug, + Deref, + AsRef, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Deserialize, + Serialize, + Encode, + Decode, + IntoSchema, +)] +pub struct UniqueVec(Vec); + +impl UniqueVec { + /// Create new [`UniqueVec`]. + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// Removes the element at the given `index` and returns it. + /// + /// # Panics + /// + /// Panics if the `index` is out of bounds. + pub fn remove(&mut self, index: usize) -> T { + self.0.remove(index) + } + + /// Clears the [`UniqueVec`], removing all values. + pub fn clear(&mut self) { + self.0.clear() + } +} + +impl UniqueVec { + /// Push `value` to [`UniqueVec`] if it is not already present. + /// + /// Returns `true` if value was pushed and `false` if not. + pub fn push(&mut self, value: T) -> bool { + if self.contains(&value) { + false + } else { + self.0.push(value); + true + } + } +} + +impl Default for UniqueVec { + fn default() -> Self { + Self(Vec::new()) + } +} + +impl FromIterator for UniqueVec { + fn from_iter>(iter: I) -> Self { + let mut unique_vec = Self::new(); + unique_vec.extend(iter); + unique_vec + } +} + +impl Extend for UniqueVec { + fn extend>(&mut self, iter: I) { + for value in iter { + self.push(value); + } + } +} + +impl From> for Vec { + fn from(value: UniqueVec) -> Self { + value.0 + } +} + +impl Borrow<[T]> for UniqueVec { + fn borrow(&self) -> &[T] { + self.0.borrow() + } +} + +impl IntoIterator for UniqueVec { + type Item = T; + type IntoIter = as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'ve, T: PartialEq> IntoIterator for &'ve UniqueVec { + type Item = &'ve T; + type IntoIter = <&'ve Vec as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl<'de, T: PartialEq + Deserialize<'de>> UniqueVec { + /// Deserialize [`UniqueVec`], failing on first duplicate. + /// + /// Default implementation of [`Deserialize`] for [`UniqueVec`] ignores duplicates. + /// + /// # Errors + /// + /// - If deserialization of `T` fails. + /// - If there are duplicates in the sequence. + /// + /// # Example + /// + /// ``` + /// use serde::{Deserialize, de::Error as _}; + /// use iroha_primitives::unique_vec::UniqueVec; + /// + /// #[derive(Debug, PartialEq, Deserialize)] + /// pub struct Config { + /// #[serde(deserialize_with = "UniqueVec::deserialize_failing_on_duplicates")] + /// numbers: UniqueVec, + /// } + /// + /// let err = serde_json::from_str::(r#"{"numbers": [1, 2, 3, 2, 4, 5]}"#).unwrap_err(); + /// assert_eq!( + /// err.to_string(), + /// "Duplicated value at line 1 column 25", + /// ); + /// ``` + pub fn deserialize_failing_on_duplicates(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Self::fail_on_duplicate_deserialize_impl(deserializer, |_value| { + "Duplicated value".to_owned() + }) + } +} + +impl<'de, T: Debug + PartialEq + Deserialize<'de>> UniqueVec { + /// Deserialize [`UniqueVec`], failing on first duplicate and printing it's [`Debug`] + /// representation. + /// + /// Default implementation of [`Deserialize`] for [`UniqueVec`] ignores duplicates. + /// + /// # Errors + /// + /// - If deserialization of `T` fails. + /// - If there are duplicates in the sequence. + /// + /// # Example + /// + /// ``` + /// use serde::{Deserialize, de::Error as _}; + /// use iroha_primitives::unique_vec::UniqueVec; + /// + /// #[derive(Debug, PartialEq, Deserialize)] + /// pub struct Config { + /// #[serde(deserialize_with = "UniqueVec::debug_deserialize_failing_on_duplicates")] + /// arrays: UniqueVec>, + /// } + /// + /// let err = serde_json::from_str::(r#"{"arrays": [[1, 2, 3], [9, 8], [1, 2, 3]]}"#).unwrap_err(); + /// assert_eq!( + /// err.to_string(), + /// "Duplicated value `[1, 2, 3]` at line 1 column 41", + /// ); + /// ``` + pub fn debug_deserialize_failing_on_duplicates(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Self::fail_on_duplicate_deserialize_impl(deserializer, |value| { + format!("Duplicated value `{value:?}`") + }) + } +} + +impl<'de, T: Display + PartialEq + Deserialize<'de>> UniqueVec { + /// Deserialize [`UniqueVec`], failing on first duplicate and printing it's [`Display`] + /// representation. + /// + /// Default implementation of [`Deserialize`] for [`UniqueVec`] ignores duplicates. + /// + /// # Errors + /// + /// - If deserialization of `T` fails. + /// - If there are duplicates in the sequence. + /// + /// # Example + /// + /// ``` + /// use serde::{Deserialize, de::Error as _}; + /// use iroha_primitives::unique_vec::UniqueVec; + /// + /// #[derive(Debug, PartialEq, Deserialize)] + /// pub struct Config { + /// #[serde(deserialize_with = "UniqueVec::display_deserialize_failing_on_duplicates")] + /// numbers: UniqueVec, + /// } + /// + /// let err = serde_json::from_str::(r#"{"numbers": [1, 2, 3, 2, 4, 5]}"#).unwrap_err(); + /// assert_eq!( + /// err.to_string(), + /// "Duplicated value `2` at line 1 column 25", + /// ); + /// ``` + pub fn display_deserialize_failing_on_duplicates(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Self::fail_on_duplicate_deserialize_impl(deserializer, |value| { + format!("Duplicated value `{value}`") + }) + } +} + +impl<'de, T: PartialEq + Deserialize<'de>> UniqueVec { + /// Deserialize [`UniqueVec`] calling `f` on duplicated value to get error message. + fn fail_on_duplicate_deserialize_impl(deserializer: D, f: F) -> Result + where + D: serde::Deserializer<'de>, + F: FnOnce(&T) -> String, + { + /// Helper, for constructing a unique visitor that errors whenever + /// a duplicate entry is found. + struct UniqueVisitor String> { + _marker: core::marker::PhantomData, + f: F, + } + + impl<'de, T, F> serde::de::Visitor<'de> for UniqueVisitor + where + T: Deserialize<'de> + PartialEq, + F: FnOnce(&T) -> String, + { + type Value = Vec; + + fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + formatter.write_str("a set of unique items.") + } + + fn visit_seq(self, mut seq: S) -> Result, S::Error> + where + S: serde::de::SeqAccess<'de>, + { + let mut result = Vec::with_capacity(seq.size_hint().unwrap_or(0)); + + while let Some(value) = seq.next_element()? { + if result.contains(&value) { + return Err(serde::de::Error::custom((self.f)(&value))); + } + result.push(value); + } + + Ok(result) + } + } + + let inner = deserializer.deserialize_seq(UniqueVisitor:: { + _marker: core::marker::PhantomData, + f, + })?; + Ok(UniqueVec(inner)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_creates_empty_vec() { + let unique_vec = UniqueVec::::default(); + assert!(unique_vec.is_empty()); + } + + #[test] + fn new_creates_empty_vec() { + let unique_vec = UniqueVec::::new(); + assert!(unique_vec.is_empty()); + } + + #[test] + fn push_returns_true_if_value_is_unique() { + let mut unique_vec = unique_vec![1, 3, 4]; + assert!(unique_vec.push(2)); + } + + #[test] + fn push_returns_false_if_value_is_not_unique() { + let mut unique_vec = unique_vec![1, 2, 3]; + assert!(!unique_vec.push(1)); + } + + #[test] + fn remove_returns_value_at_index() { + let mut unique_vec = unique_vec![1, 2, 3]; + assert_eq!(unique_vec.remove(1), 2); + } + + #[test] + #[should_panic] + fn remove_out_of_bounds_panics() { + let mut unique_vec = unique_vec![1, 2, 3]; + unique_vec.remove(3); + } + + #[test] + fn clear_removes_all_values() { + let mut unique_vec = unique_vec![1, 2, 3]; + unique_vec.clear(); + assert!(unique_vec.is_empty()); + } + + #[test] + fn from_iter_creates_unique_vec() { + let unique_vec = UniqueVec::from_iter([1, 1, 2, 3, 2]); + assert_eq!(unique_vec, unique_vec![1, 2, 3]); + } + + #[test] + fn extend_adds_unique_values() { + let mut unique_vec = unique_vec![1, 2, 3]; + unique_vec.extend([1, 2, 3, 4, 5]); + assert_eq!(unique_vec, unique_vec![1, 2, 3, 4, 5]); + } +} diff --git a/scripts/test_env.py b/scripts/test_env.py index b29236f4ad9..2e848d153ce 100755 --- a/scripts/test_env.py +++ b/scripts/test_env.py @@ -50,14 +50,14 @@ def __init__(self, args: argparse.Namespace): peer_entry = {"address": f"{peer.host_ip}:{peer.p2p_port}", "public_key": peer.public_key} self.trusted_peers.append(json.dumps(peer_entry)) os.environ["SUMERAGI_TRUSTED_PEERS"] = f"[{','.join(self.trusted_peers)}]" - + def wait_for_genesis(self, n_tries: int): for i in range(n_tries): logging.info(f"Waiting for genesis block to be created... Attempt {i+1}/{n_tries}") try: with urllib.request.urlopen(f"http://{self.peers[0].host_ip}:{self.peers[0].telemetry_port}/status/blocks") as response: block_count = int(response.read()) - if block_count > 1: + if block_count >= 1: logging.info(f"Genesis block created. Block count: {block_count}") return else: @@ -107,7 +107,7 @@ def __init__(self, args: argparse.Namespace, nth: int): self.private_key = json.dumps(json_keypair['private_key']) logging.info(f"Peer {self.name} initialized") - + def run(self, is_genesis: bool = False): logging.info(f"Running peer {self.name}...") peer_dir = self.out_dir.joinpath(f"peers/{self.name}") @@ -162,7 +162,7 @@ def copy_or_prompt_build_bin(bin_name: str, root_dir: pathlib.Path, target_dir: def main(args): # Bold ASCII escape sequence logging.basicConfig(level=logging.INFO if args.verbose else logging.WARNING, - style="{", + style="{", format="{asctime} {levelname} \033[1m{funcName}:{lineno}\033[0m: {message}",) # ISO 8601 timestamps without timezone logging.Formatter.formatTime = (lambda self, record, datefmt=None: From 6ebe32bab8576dd3f5d211997685d857e750b1ce Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Fri, 22 Sep 2023 14:58:49 +0300 Subject: [PATCH 26/55] [refactor] #3911: Migrate iroha_futures_derive to syn 2.0 Also, a drive-by fix to silence the "unused" lints in some other feature combinations Signed-off-by: Nikita Strygin --- Cargo.lock | 5 +++-- crypto/src/lib.rs | 5 ++++- futures/derive/Cargo.toml | 6 ++++-- futures/derive/src/lib.rs | 39 +++++++++++++++++++++++++-------------- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b76f8bde171..c03b35cc834 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3261,10 +3261,11 @@ dependencies = [ name = "iroha_futures_derive" version = "2.0.0-pre-rc.19" dependencies = [ - "proc-macro-error", + "iroha_macro_utils", + "manyhow", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index e866bb85d15..d9a059aef24 100755 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -1,7 +1,6 @@ //! This module contains structures and implementations related to the cryptographic parts of the Iroha. #![cfg_attr(not(feature = "std"), no_std)] // in no_std some code gets cfg-ed out, so we silence the warnings -#![cfg_attr(not(feature = "std"), allow(unused, unused_tuple_struct_fields))] #![allow(clippy::arithmetic_side_effects)] #[cfg(not(feature = "std"))] @@ -120,6 +119,10 @@ impl FromStr for Algorithm { /// Options for key generation #[cfg(not(feature = "ffi_import"))] +#[cfg_attr( + any(not(feature = "std"), feature = "ffi_import"), + allow(unused_tuple_struct_fields) +)] #[derive(Debug, Clone)] enum KeyGenOption { /// Use seed diff --git a/futures/derive/Cargo.toml b/futures/derive/Cargo.toml index 772801c9f21..cd0afdb1cb0 100644 --- a/futures/derive/Cargo.toml +++ b/futures/derive/Cargo.toml @@ -19,7 +19,9 @@ telemetry = [] proc-macro = true [dependencies] -syn = { workspace = true, features = ["default", "full"] } +iroha_macro_utils = { workspace = true } + +syn2 = { workspace = true, features = ["default", "full"] } quote = { workspace = true } proc-macro2 = { workspace = true } -proc-macro-error = { workspace = true } +manyhow = { workspace = true } diff --git a/futures/derive/src/lib.rs b/futures/derive/src/lib.rs index e4c14935b35..43ebc497e11 100644 --- a/futures/derive/src/lib.rs +++ b/futures/derive/src/lib.rs @@ -6,20 +6,21 @@ clippy::std_instead_of_core )] -use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; -use proc_macro_error::{abort, proc_macro_error}; +use iroha_macro_utils::Emitter; +use manyhow::{emit, manyhow}; +use proc_macro2::TokenStream; use quote::quote; -use syn::{parse_macro_input, Generics, ItemFn, ReturnType, Signature}; +use syn2::{Generics, ItemFn, ReturnType, Signature}; fn impl_telemetry_future( + emitter: &mut Emitter, ItemFn { attrs, vis, sig, block, }: ItemFn, -) -> TokenStream2 { +) -> TokenStream { let Signature { asyncness, ident, @@ -34,8 +35,9 @@ fn impl_telemetry_future( } = sig; if asyncness.is_none() { - abort!( - asyncness, + emit!( + emitter, + ident, "Only async functions can be instrumented for `telemetry_future`" ); } @@ -57,14 +59,23 @@ fn impl_telemetry_future( } /// Macro for wrapping future for getting telemetry info about poll times and numbers -#[proc_macro_error] +#[manyhow] #[proc_macro_attribute] -pub fn telemetry_future(_args: TokenStream, input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as ItemFn); - if cfg!(feature = "telemetry") { - impl_telemetry_future(input) +pub fn telemetry_future(args: TokenStream, input: TokenStream) -> TokenStream { + let mut emitter = Emitter::new(); + + if !args.is_empty() { + emit!(emitter, args, "Unexpected arguments") + } + + let Some(input) = emitter.handle(syn2::parse2(input)) else { + return emitter.finish_token_stream(); + }; + let result = if cfg!(feature = "telemetry") { + impl_telemetry_future(&mut emitter, input) } else { quote! { #input } - } - .into() + }; + + emitter.finish_token_stream_with(result) } From a9958c0a194017a36aaf4060e7043bac781d4693 Mon Sep 17 00:00:00 2001 From: BAStos525 <66615487+BAStos525@users.noreply.github.com> Date: Tue, 26 Sep 2023 23:24:48 +0300 Subject: [PATCH 27/55] [ci] #3825: Clean default runner free space (#3902) Signed-off-by: BAStos525 --- .github/workflows/iroha2-dev-pr-ui.yml | 4 ++++ .github/workflows/iroha2-release-pr.yml | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/.github/workflows/iroha2-dev-pr-ui.yml b/.github/workflows/iroha2-dev-pr-ui.yml index ef2881c9e84..7d70feafb86 100644 --- a/.github/workflows/iroha2-dev-pr-ui.yml +++ b/.github/workflows/iroha2-dev-pr-ui.yml @@ -26,6 +26,10 @@ jobs: matrix: feature_flag: [all-features, no-default-features] steps: + - name: Maximize build space + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf "$AGENT_TOOLSDIRECTORY" - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 - name: Run tests, with ${{ matrix.feature_flag }} diff --git a/.github/workflows/iroha2-release-pr.yml b/.github/workflows/iroha2-release-pr.yml index 7959d47a6a6..76782aa166e 100644 --- a/.github/workflows/iroha2-release-pr.yml +++ b/.github/workflows/iroha2-release-pr.yml @@ -17,6 +17,10 @@ jobs: container: image: hyperledger/iroha2-ci:nightly-2023-06-25 steps: + - name: Maximize build space + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf "$AGENT_TOOLSDIRECTORY" - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 - name: Build iroha @@ -50,6 +54,10 @@ jobs: container: image: hyperledger/iroha2-ci:nightly-2023-06-25 steps: + - name: Maximize build space + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf "$AGENT_TOOLSDIRECTORY" - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 - name: Run benchmarks @@ -62,6 +70,10 @@ jobs: container: image: hyperledger/iroha2-ci:nightly-2023-06-25 steps: + - name: Maximize build space + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf "$AGENT_TOOLSDIRECTORY" - uses: actions/checkout@v3 - name: Set up JDK 11 uses: actions/setup-java@v3.11.0 @@ -112,6 +124,10 @@ jobs: container: image: hyperledger/iroha2-ci:nightly-2023-06-25 steps: + - name: Maximize build space + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf "$AGENT_TOOLSDIRECTORY" - uses: actions/checkout@v3 - name: Run long tests run: mold --run cargo test --workspace --no-fail-fast -- --ignored --test-threads=1 long From 539c3f984e3a3f417106028fe70bc5d2b20d3484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Wed, 27 Sep 2023 19:14:49 +0200 Subject: [PATCH 28/55] [refactor] #3895: move `commit_topology` into block payload (#3916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- core/benches/kura.rs | 2 +- core/benches/validation.rs | 2 +- core/src/block.rs | 51 ++++++++------------------- core/src/smartcontracts/isi/query.rs | 4 +-- core/src/sumeragi/main_loop.rs | 10 +++--- core/src/sumeragi/mod.rs | 3 +- core/src/sumeragi/network_topology.rs | 2 +- data_model/src/block.rs | 6 ++-- docs/source/references/schema.json | 8 ++--- 9 files changed, 32 insertions(+), 56 deletions(-) diff --git a/core/benches/kura.rs b/core/benches/kura.rs index 558e83c0cd5..c3874bd8a59 100644 --- a/core/benches/kura.rs +++ b/core/benches/kura.rs @@ -45,7 +45,7 @@ async fn measure_block_size_for_n_validators(n_validators: u32) { let mut wsv = WorldStateView::new(World::new(), kura); let topology = Topology::new(UniqueVec::new()); let mut block = BlockBuilder::new(vec![tx], topology, Vec::new()) - .chain_first(&mut wsv) + .chain(0, &mut wsv) .sign(KeyPair::generate().unwrap()) .unwrap(); diff --git a/core/benches/validation.rs b/core/benches/validation.rs index 36886ac87d4..02085aef02e 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -152,7 +152,7 @@ fn sign_blocks(criterion: &mut Criterion) { let mut success_count = 0; let mut failures_count = 0; - let block = BlockBuilder::new(vec![transaction], topology, Vec::new()).chain_first(&mut wsv); + let block = BlockBuilder::new(vec![transaction], topology, Vec::new()).chain(0, &mut wsv); let _ = criterion.bench_function("sign_block", |b| { b.iter(|| match block.clone().sign(key_pair.clone()) { diff --git a/core/src/block.rs b/core/src/block.rs index 609179c710b..fc7837934f2 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -110,13 +110,11 @@ mod pending { /// the previous round, which might then be processed by the trigger system. #[derive(Debug, Clone)] pub struct Pending { - /// Unix timestamp - timestamp_ms: u64, + /// The topology at the time of block commit. + commit_topology: Topology, /// Collection of transactions which have been accepted. /// Transaction will be validated when block is chained. transactions: Vec, - /// The topology at the time of block commit. - commit_topology: Topology, /// Event recommendations for use in triggers and off-chain work event_recommendations: Vec, } @@ -136,10 +134,6 @@ mod pending { assert!(!transactions.is_empty(), "Empty block created"); Self(Pending { - timestamp_ms: iroha_data_model::current_time() - .as_millis() - .try_into() - .expect("Time should fit into u64"), transactions, commit_topology, event_recommendations, @@ -147,15 +141,16 @@ mod pending { } fn make_header( - timestamp_ms: u64, previous_height: u64, previous_block_hash: Option>, view_change_index: u64, transactions: &[TransactionValue], - commit_topology: Topology, ) -> BlockHeader { BlockHeader { - timestamp_ms, + timestamp_ms: iroha_data_model::current_time() + .as_millis() + .try_into() + .expect("Time should fit into u64"), consensus_estimation_ms: DEFAULT_CONSENSUS_ESTIMATION_MS, height: previous_height + 1, view_change_index, @@ -165,7 +160,6 @@ mod pending { .map(TransactionValue::hash) .collect::>() .hash(), - commit_topology: commit_topology.ordered_peers, } } @@ -196,6 +190,8 @@ mod pending { } /// Chain the block with existing blockchain. + /// + /// Upon executing this method current timestamp is stored in the block header. pub fn chain( self, view_change_index: u64, @@ -205,32 +201,13 @@ mod pending { BlockBuilder(Chained(BlockPayload { header: Self::make_header( - self.0.timestamp_ms, wsv.height(), wsv.latest_block_hash(), view_change_index, &transactions, - self.0.commit_topology, - ), - transactions, - event_recommendations: self.0.event_recommendations, - })) - } - - /// Create a new blockchain with current block as the first block. - pub fn chain_first(self, wsv: &mut WorldStateView) -> BlockBuilder { - let transactions = Self::categorize_transactions(self.0.transactions, wsv); - - BlockBuilder(Chained(BlockPayload { - header: Self::make_header( - self.0.timestamp_ms, - 0, - None, - 0, - &transactions, - self.0.commit_topology, ), transactions, + commit_topology: self.0.commit_topology.ordered_peers, event_recommendations: self.0.event_recommendations, })) } @@ -297,7 +274,7 @@ mod valid { topology: &Topology, wsv: &mut WorldStateView, ) -> Result { - let actual_commit_topology = &block.payload().header.commit_topology; + let actual_commit_topology = &block.payload().commit_topology; let expected_commit_topology = &topology.ordered_peers; if actual_commit_topology != expected_commit_topology { @@ -491,9 +468,9 @@ mod valid { view_change_index: 0, previous_block_hash: None, transactions_hash: None, - commit_topology: UniqueVec::new(), }, transactions: Vec::new(), + commit_topology: UniqueVec::new(), event_recommendations: Vec::new(), })) .sign(KeyPair::generate().unwrap()) @@ -779,7 +756,7 @@ mod tests { let transactions = vec![tx.clone(), tx]; let topology = Topology::new(UniqueVec::new()); let valid_block = BlockBuilder::new(transactions, topology, Vec::new()) - .chain_first(&mut wsv) + .chain(0, &mut wsv) .sign(alice_keys) .expect("Valid"); @@ -846,7 +823,7 @@ mod tests { let transactions = vec![tx0, tx, tx2]; let topology = Topology::new(UniqueVec::new()); let valid_block = BlockBuilder::new(transactions, topology, Vec::new()) - .chain_first(&mut wsv) + .chain(0, &mut wsv) .sign(alice_keys) .expect("Valid"); @@ -899,7 +876,7 @@ mod tests { let transactions = vec![tx_fail, tx_accept]; let topology = Topology::new(UniqueVec::new()); let valid_block = BlockBuilder::new(transactions, topology, Vec::new()) - .chain_first(&mut wsv) + .chain(0, &mut wsv) .sign(alice_keys) .expect("Valid"); diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index f33d9cff7b0..8c4f3ed88f0 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -293,7 +293,7 @@ mod tests { let topology = Topology::new(UniqueVec::new()); let first_block = BlockBuilder::new(transactions.clone(), topology.clone(), Vec::new()) - .chain_first(&mut wsv) + .chain(0, &mut wsv) .sign(ALICE_KEYS.clone())? .commit(&topology) .expect("Block is valid"); @@ -429,7 +429,7 @@ mod tests { let topology = Topology::new(UniqueVec::new()); let vcb = BlockBuilder::new(vec![va_tx.clone()], topology.clone(), Vec::new()) - .chain_first(&mut wsv) + .chain(0, &mut wsv) .sign(ALICE_KEYS.clone())? .commit(&topology) .expect("Block is valid"); diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index 9691564db65..333d487cddf 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -249,7 +249,7 @@ impl Sumeragi { let mut new_wsv = self.wsv.clone(); let genesis = BlockBuilder::new(transactions, self.current_topology.clone(), vec![]) - .chain_first(&mut new_wsv) + .chain(0, &mut new_wsv) .sign(self.key_pair.clone()) .expect("Genesis signing failed"); @@ -324,7 +324,7 @@ impl Sumeragi { // Parameters are updated before updating public copy of sumeragi self.update_params(); - let block_topology = block.payload().header.commit_topology.clone(); + let block_topology = block.payload().commit_topology.clone(); let block_signees = block .signatures() .into_iter() @@ -1195,7 +1195,7 @@ mod tests { // Creating a block of two identical transactions and validating it let block = BlockBuilder::new(vec![tx.clone(), tx], topology.clone(), Vec::new()) - .chain_first(&mut wsv) + .chain(0, &mut wsv) .sign(leader_key_pair.clone()) .expect("Block is valid"); @@ -1247,7 +1247,7 @@ mod tests { let wsv = finalized_wsv.clone(); // Malform block to make it invalid - block.payload_mut().header.commit_topology.clear(); + block.payload_mut().commit_topology.clear(); let result = handle_block_sync(block, &wsv, &finalized_wsv); assert!(matches!(result, Err((_, BlockSyncError::BlockNotValid(_))))) @@ -1270,7 +1270,7 @@ mod tests { kura.store_block(committed_block); // Malform block to make it invalid - block.payload_mut().header.commit_topology.clear(); + block.payload_mut().commit_topology.clear(); let result = handle_block_sync(block, &wsv, &finalized_wsv); assert!(matches!( diff --git a/core/src/sumeragi/mod.rs b/core/src/sumeragi/mod.rs index 59a0e1ae729..3123025f805 100644 --- a/core/src/sumeragi/mod.rs +++ b/core/src/sumeragi/mod.rs @@ -266,8 +266,7 @@ impl SumeragiHandle { "Sumeragi could not load block that was reported as present. \ Please check that the block storage was not disconnected.", ); - let mut topology = - Topology::new(block_ref.payload().header.commit_topology.clone()); + let mut topology = Topology::new(block_ref.payload().commit_topology.clone()); topology.rotate_set_a(); topology } diff --git a/core/src/sumeragi/network_topology.rs b/core/src/sumeragi/network_topology.rs index 0ca6e1d3f9a..753694d34e1 100644 --- a/core/src/sumeragi/network_topology.rs +++ b/core/src/sumeragi/network_topology.rs @@ -192,7 +192,7 @@ impl Topology { view_change_index: u64, new_peers: UniqueVec, ) -> Self { - let mut topology = Topology::new(block.payload().header().commit_topology.clone()); + let mut topology = Topology::new(block.payload().commit_topology.clone()); let block_signees = block .signatures() .into_iter() diff --git a/data_model/src/block.rs b/data_model/src/block.rs index 170a8efbd42..fe471df2901 100644 --- a/data_model/src/block.rs +++ b/data_model/src/block.rs @@ -61,9 +61,6 @@ pub mod model { pub previous_block_hash: Option>, /// Hash of merkle tree root of transactions' hashes. pub transactions_hash: Option>>, - /// Topology of the network at the time of block commit. - #[getset(skip)] // FIXME: Because ffi related issues - pub commit_topology: UniqueVec, /// Value of view change index. Used to resolve soft forks. pub view_change_index: u64, /// Estimation of consensus duration (in milliseconds). @@ -92,6 +89,9 @@ pub mod model { pub struct BlockPayload { /// Block header pub header: BlockHeader, + /// Topology of the network at the time of block commit. + #[getset(skip)] // FIXME: Because ffi related issues + pub commit_topology: UniqueVec, /// array of transactions, which successfully passed validation and consensus step. #[getset(skip)] // FIXME: Because ffi related issues pub transactions: Vec, diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index d8763aeb9c6..ef55739736e 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -672,10 +672,6 @@ "name": "transactions_hash", "type": "Option>>" }, - { - "name": "commit_topology", - "type": "UniqueVec" - }, { "name": "view_change_index", "type": "u64" @@ -693,6 +689,10 @@ "name": "header", "type": "BlockHeader" }, + { + "name": "commit_topology", + "type": "UniqueVec" + }, { "name": "transactions", "type": "Vec" From 88b289d1f3abdcac375b64a1057627c30a80879a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Thu, 28 Sep 2023 05:08:20 +0200 Subject: [PATCH 29/55] [refactor] #3886: Remove 'Versioned' prefix from versioned containers (#3913) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- cli/src/torii/routing.rs | 20 +-- client/src/client.rs | 55 ++++--- client/tests/integration/burn_public_keys.rs | 4 +- client/tests/integration/permissions.rs | 2 +- .../validator_with_admin/src/lib.rs | 4 +- .../validator_with_custom_token/src/lib.rs | 4 +- .../validator_with_migration_fail/src/lib.rs | 4 +- .../integration/triggers/by_call_trigger.rs | 2 +- core/benches/validation.rs | 2 +- core/src/block.rs | 30 ++-- core/src/block_sync.rs | 20 +-- core/src/gossiper.rs | 4 +- core/src/kura.rs | 52 +++---- core/src/queue.rs | 2 +- core/src/smartcontracts/isi/block.rs | 6 +- core/src/smartcontracts/isi/query.rs | 7 +- core/src/smartcontracts/isi/tx.rs | 10 +- core/src/smartcontracts/wasm.rs | 4 +- core/src/snapshot.rs | 6 +- core/src/sumeragi/main_loop.rs | 6 +- core/src/sumeragi/message.rs | 14 +- core/src/sumeragi/network_topology.rs | 4 +- core/src/sumeragi/view_change.rs | 17 +- core/src/tx.rs | 17 +- core/src/validator.rs | 6 +- core/src/wsv.rs | 37 ++--- data_model/src/block.rs | 46 +++--- data_model/src/events/pipeline.rs | 2 +- data_model/src/lib.rs | 50 +++--- data_model/src/predicate.rs | 2 +- data_model/src/query/mod.rs | 62 ++++---- data_model/src/transaction.rs | 58 +++---- data_model/src/visit.rs | 4 +- data_model/src/wasm.rs | 2 +- default_validator/src/lib.rs | 4 +- docs/source/references/api_spec.md | 4 +- docs/source/references/schema.json | 146 +++++++++--------- genesis/src/lib.rs | 6 +- schema/gen/src/lib.rs | 58 +++---- tools/kura_inspector/src/main.rs | 4 +- tools/parity_scale_decoder/src/main.rs | 8 +- wasm/validator/derive/src/lib.rs | 2 +- wasm/validator/src/default.rs | 4 +- 43 files changed, 386 insertions(+), 415 deletions(-) diff --git a/cli/src/torii/routing.rs b/cli/src/torii/routing.rs index 8397a3e505f..c1ee5061f11 100644 --- a/cli/src/torii/routing.rs +++ b/cli/src/torii/routing.rs @@ -26,9 +26,9 @@ use iroha_core::{ use iroha_data_model::{ block::{ stream::{BlockMessage, BlockSubscriptionRequest}, - VersionedSignedBlock, + SignedBlock, }, - http::{BatchedResponse, VersionedBatchedResponse}, + http::{BatchedResponse, BatchedResponseV1}, prelude::*, query::{ForwardCursor, Pagination, Sorting}, }; @@ -59,7 +59,7 @@ fn paginate() -> impl warp::Filter, sumeragi: SumeragiHandle, - transaction: VersionedSignedTransaction, + transaction: SignedTransaction, ) -> Result { let wsv = sumeragi.wsv_clone(); let transaction_limits = wsv.config.transaction_limits; @@ -85,12 +85,12 @@ async fn handle_queries( query_store: Arc, fetch_size: NonZeroUsize, - request: VersionedSignedQuery, + request: SignedQuery, sorting: Sorting, pagination: Pagination, cursor: ForwardCursor, -) -> Result>> { +) -> Result>> { let valid_request = sumeragi.apply_wsv(|wsv| ValidQueryRequest::validate(request, wsv))?; let request_id = (&valid_request, &sorting, &pagination); @@ -114,7 +114,7 @@ async fn handle_queries( match res { LazyValue::Value(batch) => { let cursor = ForwardCursor::default(); - let result = BatchedResponse { batch, cursor }; + let result = BatchedResponseV1 { batch, cursor }; Ok(Scale(result.into())) } LazyValue::Iter(iter) => { @@ -141,14 +141,14 @@ fn construct_query_response( query_id: String, curr_cursor: Option, mut live_query: Batched>, -) -> Result>> { +) -> Result>> { let (batch, next_cursor) = live_query.next_batch(curr_cursor)?; if !live_query.is_depleted() { query_store.insert(query_id.clone(), request_id, live_query); } - let query_response = BatchedResponse { + let query_response = BatchedResponseV1 { batch: Value::Vec(batch), cursor: ForwardCursor { query_id: Some(query_id), @@ -220,7 +220,7 @@ async fn handle_pending_transactions( queue: Arc, sumeragi: SumeragiHandle, pagination: Pagination, -) -> Result>> { +) -> Result>> { let query_response = sumeragi.apply_wsv(|wsv| { queue .all_transactions(wsv) @@ -304,7 +304,7 @@ async fn handle_blocks_stream(kura: Arc, mut stream: WebSocket) -> eyre::R if let Some(block) = kura.get_block_by_height(from_height.get()) { stream // TODO: to avoid clone `BlockMessage` could be split into sending and receiving parts - .send(BlockMessage(VersionedSignedBlock::clone(&block))) + .send(BlockMessage(SignedBlock::clone(&block))) .await?; from_height = from_height.checked_add(1).expect("Maximum block height is achieved."); } diff --git a/client/src/client.rs b/client/src/client.rs index e4fceccb515..852fc67117c 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -21,8 +21,8 @@ use http_default::{AsyncWebSocketStream, WebSocketStream}; use iroha_config::{client::Configuration, torii::uri, GetConfiguration, PostConfiguration}; use iroha_crypto::{HashOf, KeyPair}; use iroha_data_model::{ - block::VersionedSignedBlock, - http::VersionedBatchedResponse, + block::SignedBlock, + http::BatchedResponse, isi::Instruction, predicate::PredicateBox, prelude::*, @@ -76,23 +76,23 @@ pub trait Sign { fn sign( self, key_pair: iroha_crypto::KeyPair, - ) -> Result; + ) -> Result; } impl Sign for TransactionBuilder { fn sign( self, key_pair: iroha_crypto::KeyPair, - ) -> Result { + ) -> Result { self.sign(key_pair) } } -impl Sign for VersionedSignedTransaction { +impl Sign for SignedTransaction { fn sign( self, key_pair: iroha_crypto::KeyPair, - ) -> Result { + ) -> Result { self.sign(key_pair) } } @@ -105,10 +105,10 @@ where // Separate-compilation friendly response handling fn _handle_query_response_base( resp: &Response>, - ) -> QueryResult> { + ) -> QueryResult> { match resp.status() { StatusCode::OK => { - let res = VersionedBatchedResponse::decode_all_versioned(resp.body()); + let res = BatchedResponse::decode_all_versioned(resp.body()); res.wrap_err( "Failed to decode response from Iroha. \ You are likely using a version of the client library \ @@ -143,8 +143,8 @@ where } } - let response = _handle_query_response_base(resp) - .map(|VersionedBatchedResponse::V1(response)| response)?; + let response = + _handle_query_response_base(resp).map(|BatchedResponse::V1(response)| response)?; let (batch, cursor) = response.into(); @@ -457,7 +457,7 @@ impl Client { &self, instructions: impl Into, metadata: UnlimitedMetadata, - ) -> Result { + ) -> Result { let tx_builder = TransactionBuilder::new(self.account_id.clone()); let mut tx_builder = match instructions.into() { @@ -483,10 +483,7 @@ impl Client { /// /// # Errors /// Fails if signature generation fails - pub fn sign_transaction( - &self, - transaction: Tx, - ) -> Result { + pub fn sign_transaction(&self, transaction: Tx) -> Result { transaction .sign(self.key_pair.clone()) .wrap_err("Failed to sign transaction") @@ -496,7 +493,7 @@ impl Client { /// /// # Errors /// Fails if signature generation fails - pub fn sign_query(&self, query: QueryBuilder) -> Result { + pub fn sign_query(&self, query: QueryBuilder) -> Result { query .sign(self.key_pair.clone()) .wrap_err("Failed to sign query") @@ -559,7 +556,7 @@ impl Client { /// Fails if sending transaction to peer fails or if it response with error pub fn submit_transaction( &self, - transaction: &VersionedSignedTransaction, + transaction: &SignedTransaction, ) -> Result> { iroha_logger::trace!(tx=?transaction, "Submitting"); let (req, hash) = self.prepare_transaction_request::(transaction); @@ -578,7 +575,7 @@ impl Client { /// Fails if sending a transaction to a peer fails or there is an error in the response pub fn submit_transaction_blocking( &self, - transaction: &VersionedSignedTransaction, + transaction: &SignedTransaction, ) -> Result> { let (init_sender, init_receiver) = tokio::sync::oneshot::channel(); let hash = transaction.payload().hash(); @@ -672,7 +669,7 @@ impl Client { /// For general usage example see [`Client::prepare_query_request`]. fn prepare_transaction_request( &self, - transaction: &VersionedSignedTransaction, + transaction: &SignedTransaction, ) -> (B, HashOf) { let transaction_bytes: Vec = transaction.encode_versioned(); @@ -1036,7 +1033,7 @@ impl Client { pub fn listen_for_blocks( &self, height: NonZeroU64, - ) -> Result>> { + ) -> Result>> { blocks_api::BlockIterator::new(self.blocks_handler(height)?) } @@ -1081,11 +1078,11 @@ impl Client { /// - if subscribing to websocket fails pub fn get_original_transaction_with_pagination( &self, - transaction: &VersionedSignedTransaction, + transaction: &SignedTransaction, retry_count: u32, retry_in: Duration, pagination: Pagination, - ) -> Result> { + ) -> Result> { let pagination: Vec<_> = pagination.into(); for _ in 0..retry_count { let response = DefaultRequestBuilder::new( @@ -1100,7 +1097,7 @@ impl Client { .send()?; if response.status() == StatusCode::OK { - let pending_transactions: Vec = + let pending_transactions: Vec = DecodeAll::decode_all(&mut response.body().as_slice())?; let transaction = pending_transactions @@ -1133,10 +1130,10 @@ impl Client { /// - if sending request fails pub fn get_original_transaction( &self, - transaction: &VersionedSignedTransaction, + transaction: &SignedTransaction, retry_count: u32, retry_in: Duration, - ) -> Result> { + ) -> Result> { self.get_original_transaction_with_pagination( transaction, retry_count, @@ -1538,7 +1535,7 @@ mod blocks_api { pub struct Events; impl FlowEvents for Events { - type Event = iroha_data_model::block::VersionedSignedBlock; + type Event = iroha_data_model::block::SignedBlock; fn message(&self, message: Vec) -> Result { Ok(BlockMessage::decode_all(&mut message.as_slice()).map(Into::into)?) @@ -1624,7 +1621,7 @@ pub mod block { /// Construct a query to find block header by hash pub fn header_by_hash( - hash: impl Into>>, + hash: impl Into>>, ) -> FindBlockHeaderByHash { FindBlockHeaderByHash::new(hash) } @@ -1664,7 +1661,7 @@ pub mod transaction { /// Construct a query to retrieve transaction by hash pub fn by_hash( - hash: impl Into>>, + hash: impl Into>>, ) -> FindTransactionByHash { FindTransactionByHash::new(hash) } @@ -1785,7 +1782,7 @@ mod tests { let mut tx2 = build_transaction(); assert_ne!(tx1.payload().hash(), tx2.payload().hash()); - let VersionedSignedTransaction::V1(tx2_ref) = &mut tx2; + let SignedTransaction::V1(tx2_ref) = &mut tx2; tx2_ref.payload.creation_time_ms = tx1 .payload() .creation_time() diff --git a/client/tests/integration/burn_public_keys.rs b/client/tests/integration/burn_public_keys.rs index 2e93c816daf..014656cabac 100644 --- a/client/tests/integration/burn_public_keys.rs +++ b/client/tests/integration/burn_public_keys.rs @@ -10,7 +10,7 @@ fn submit( instructions: impl IntoIterator, submitter: Option<(AccountId, KeyPair)>, ) -> ( - HashOf, + HashOf, eyre::Result>, ) { let tx = if let Some((account_id, keypair)) = submitter { @@ -28,7 +28,7 @@ fn submit( (tx.hash(), client.submit_transaction_blocking(&tx)) } -fn get(client: &Client, hash: HashOf) -> TransactionValue { +fn get(client: &Client, hash: HashOf) -> TransactionValue { client .request(transaction::by_hash(hash)) .unwrap() diff --git a/client/tests/integration/permissions.rs b/client/tests/integration/permissions.rs index 033ab3e1030..ff4ee340b54 100644 --- a/client/tests/integration/permissions.rs +++ b/client/tests/integration/permissions.rs @@ -23,7 +23,7 @@ fn genesis_transactions_are_validated() { AccountId::from_str("alice@wonderland").unwrap(), ); - let VersionedSignedTransaction::V1(tx_ref) = &mut genesis.transactions.last_mut().unwrap().0; + let SignedTransaction::V1(tx_ref) = &mut genesis.transactions.last_mut().unwrap().0; match &mut tx_ref.payload.instructions { Executable::Instructions(instructions) => { instructions.push(grant_invalid_token.into()); diff --git a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs index cbc6d280537..b9040c81b4a 100644 --- a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs @@ -50,7 +50,7 @@ impl Visit for Validator { defaults! { visit_unsupported(T), - visit_transaction(&VersionedSignedTransaction), + visit_transaction(&SignedTransaction), visit_expression(&EvaluatesTo), visit_sequence(&SequenceBox), visit_if(&Conditional), @@ -139,7 +139,7 @@ pub fn migrate(_block_height: u64) -> MigrationResult { #[entrypoint] pub fn validate_transaction( authority: AccountId, - transaction: VersionedSignedTransaction, + transaction: SignedTransaction, block_height: u64, ) -> Result { let mut validator = Validator::new(block_height); diff --git a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs index 660a5d076db..2b6451d48c0 100644 --- a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs @@ -203,7 +203,7 @@ impl Visit for Validator { defaults! { visit_unsupported(T), - visit_transaction(&VersionedSignedTransaction), + visit_transaction(&SignedTransaction), visit_instruction(&InstructionBox), visit_expression(&EvaluatesTo), visit_sequence(&SequenceBox), @@ -303,7 +303,7 @@ pub fn migrate(_block_height: u64) -> MigrationResult { #[entrypoint] pub fn validate_transaction( authority: AccountId, - transaction: VersionedSignedTransaction, + transaction: SignedTransaction, block_height: u64, ) -> Result { let mut validator = Validator::new(block_height); diff --git a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs index 859dc13b801..0b4b3b36c93 100644 --- a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs @@ -54,7 +54,7 @@ impl Visit for Validator { defaults! { visit_unsupported(T), - visit_transaction(&VersionedSignedTransaction), + visit_transaction(&SignedTransaction), visit_instruction(&InstructionBox), visit_expression(&EvaluatesTo), visit_sequence(&SequenceBox), @@ -157,7 +157,7 @@ pub fn migrate(_block_height: u64) -> MigrationResult { #[entrypoint] pub fn validate_transaction( authority: AccountId, - transaction: VersionedSignedTransaction, + transaction: SignedTransaction, block_height: u64, ) -> Result { let mut validator = Validator::new(block_height); diff --git a/client/tests/integration/triggers/by_call_trigger.rs b/client/tests/integration/triggers/by_call_trigger.rs index 0608c82764b..926982ac12a 100644 --- a/client/tests/integration/triggers/by_call_trigger.rs +++ b/client/tests/integration/triggers/by_call_trigger.rs @@ -357,7 +357,7 @@ fn trigger_in_genesis_using_base64() -> Result<()> { // Registering trigger in genesis let mut genesis = GenesisNetwork::test(true).expect("Expected genesis"); - let VersionedSignedTransaction::V1(tx_ref) = &mut genesis.transactions[0].0; + let SignedTransaction::V1(tx_ref) = &mut genesis.transactions[0].0; match &mut tx_ref.payload.instructions { Executable::Instructions(instructions) => { instructions.push(RegisterBox::new(trigger).into()); diff --git a/core/benches/validation.rs b/core/benches/validation.rs index 02085aef02e..3d9211968ec 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -22,7 +22,7 @@ const TRANSACTION_LIMITS: TransactionLimits = TransactionLimits { max_wasm_size_bytes: 0, }; -fn build_test_transaction(keys: KeyPair) -> VersionedSignedTransaction { +fn build_test_transaction(keys: KeyPair) -> SignedTransaction { let domain_name = "domain"; let domain_id = DomainId::from_str(domain_name).expect("does not panic"); let create_domain = RegisterBox::new(Domain::new(domain_id)); diff --git a/core/src/block.rs b/core/src/block.rs index fc7837934f2..ff4c1b2fced 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -2,7 +2,7 @@ //! 1. If a new block is constructed by the node: //! `BlockBuilder` -> `BlockBuilder` -> `ValidBlock` -> `CommittedBlock` //! 2. If a block is received, i.e. deserialized: -//! `VersionedSignedBlock` -> `ValidBlock` -> `CommittedBlock` +//! `SignedBlock` -> `ValidBlock` -> `CommittedBlock` //! [`Block`]s are organised into a linear sequence over time (also known as the block chain). #![allow( clippy::module_name_repetitions, @@ -47,9 +47,9 @@ pub enum BlockValidationError { /// Mismatch between the actual and expected hashes of the latest block. Expected: {expected:?}, actual: {actual:?} LatestBlockHashMismatch { /// Expected value - expected: Option>, + expected: Option>, /// Actual value - actual: Option>, + actual: Option>, }, /// Mismatch between the actual and expected height of the latest block. Expected: {expected}, actual: {actual} LatestBlockHeightMismatch { @@ -142,7 +142,7 @@ mod pending { fn make_header( previous_height: u64, - previous_block_hash: Option>, + previous_block_hash: Option>, view_change_index: u64, transactions: &[TransactionValue], ) -> BlockHeader { @@ -231,7 +231,7 @@ mod chained { let signature = SignatureOf::new(key_pair, &self.0 .0)?; Ok(ValidBlock( - SignedBlock { + SignedBlockV1 { payload: self.0 .0, signatures: SignaturesOf::from(signature), } @@ -248,7 +248,7 @@ mod valid { /// Block that was validated and accepted #[derive(Debug, Clone)] #[repr(transparent)] - pub struct ValidBlock(pub(super) VersionedSignedBlock); + pub struct ValidBlock(pub(super) SignedBlock); impl ValidBlock { pub(crate) fn payload(&self) -> &BlockPayload { @@ -270,10 +270,10 @@ mod valid { /// - Error during validation of individual transactions /// - Topology field is incorrect pub fn validate( - block: VersionedSignedBlock, + block: SignedBlock, topology: &Topology, wsv: &mut WorldStateView, - ) -> Result { + ) -> Result { let actual_commit_topology = &block.payload().commit_topology; let expected_commit_topology = &topology.ordered_peers; @@ -336,9 +336,9 @@ mod valid { return Err((block, error.into())); } - let VersionedSignedBlock::V1(block) = block; + let SignedBlock::V1(block) = block; Ok(ValidBlock( - SignedBlock { + SignedBlockV1 { payload: block.payload, signatures: block.signatures, } @@ -347,7 +347,7 @@ mod valid { } fn validate_transactions( - block: &VersionedSignedBlock, + block: &SignedBlock, wsv: &mut WorldStateView, ) -> Result<(), TransactionValidationError> { let is_genesis = block.payload().header.is_genesis(); @@ -522,7 +522,7 @@ mod valid { } } - impl From for VersionedSignedBlock { + impl From for SignedBlock { fn from(source: ValidBlock) -> Self { source.0 } @@ -648,11 +648,11 @@ mod commit { /// Every [`Self`] will have a different height. #[derive(Debug, Clone)] // TODO: Make it pub(super) at most - pub struct CommittedBlock(pub(crate) VersionedSignedBlock); + pub struct CommittedBlock(pub(crate) SignedBlock); impl CommittedBlock { /// Calculate block hash - pub fn hash(&self) -> HashOf { + pub fn hash(&self) -> HashOf { self.0.hash() } /// Get block payload @@ -695,7 +695,7 @@ mod commit { } } - impl From for VersionedSignedBlock { + impl From for SignedBlock { fn from(source: CommittedBlock) -> Self { source.0 } diff --git a/core/src/block_sync.rs b/core/src/block_sync.rs index 89b1dd2518e..a56e83be7e6 100644 --- a/core/src/block_sync.rs +++ b/core/src/block_sync.rs @@ -8,7 +8,7 @@ use std::{fmt::Debug, sync::Arc, time::Duration}; use iroha_config::block_sync::Configuration; use iroha_crypto::HashOf; -use iroha_data_model::{block::VersionedSignedBlock, prelude::*}; +use iroha_data_model::{block::SignedBlock, prelude::*}; use iroha_logger::prelude::*; use iroha_macro::*; use iroha_p2p::Post; @@ -43,8 +43,8 @@ pub struct BlockSynchronizer { gossip_period: Duration, block_batch_size: u32, network: IrohaNetwork, - latest_hash: Option>, - previous_hash: Option>, + latest_hash: Option>, + previous_hash: Option>, } impl BlockSynchronizer { @@ -139,9 +139,9 @@ pub mod message { #[derive(Debug, Clone, Decode, Encode)] pub struct GetBlocksAfter { /// Hash of latest available block - pub latest_hash: Option>, + pub latest_hash: Option>, /// Hash of second to latest block - pub previous_hash: Option>, + pub previous_hash: Option>, /// Peer id pub peer_id: PeerId, } @@ -149,8 +149,8 @@ pub mod message { impl GetBlocksAfter { /// Construct [`GetBlocksAfter`]. pub const fn new( - latest_hash: Option>, - previous_hash: Option>, + latest_hash: Option>, + previous_hash: Option>, peer_id: PeerId, ) -> Self { Self { @@ -165,14 +165,14 @@ pub mod message { #[derive(Debug, Clone, Decode, Encode)] pub struct ShareBlocks { /// Blocks - pub blocks: Vec, + pub blocks: Vec, /// Peer id pub peer_id: PeerId, } impl ShareBlocks { /// Construct [`ShareBlocks`]. - pub const fn new(blocks: Vec, peer_id: PeerId) -> Self { + pub const fn new(blocks: Vec, peer_id: PeerId) -> Self { Self { blocks, peer_id } } } @@ -222,7 +222,7 @@ pub mod message { .take(1 + block_sync.block_batch_size as usize) .map_while(|height| block_sync.kura.get_block_by_height(height)) .skip_while(|block| Some(block.hash()) == *latest_hash) - .map(|block| VersionedSignedBlock::clone(&block)) + .map(|block| SignedBlock::clone(&block)) .collect::>(); if blocks.is_empty() { diff --git a/core/src/gossiper.rs b/core/src/gossiper.rs index 34c22ca1b59..1ee8312e8b3 100644 --- a/core/src/gossiper.rs +++ b/core/src/gossiper.rs @@ -3,7 +3,7 @@ use std::{sync::Arc, time::Duration}; use iroha_config::sumeragi::Configuration; -use iroha_data_model::transaction::VersionedSignedTransaction; +use iroha_data_model::transaction::SignedTransaction; use iroha_p2p::Broadcast; use parity_scale_codec::{Decode, Encode}; use tokio::sync::mpsc; @@ -140,7 +140,7 @@ impl TransactionGossiper { #[derive(Decode, Encode, Debug, Clone)] pub struct TransactionGossip { /// Batch of transactions. - pub txs: Vec, + pub txs: Vec, } impl TransactionGossip { diff --git a/core/src/kura.rs b/core/src/kura.rs index 28f5515ada8..309ad9cad16 100644 --- a/core/src/kura.rs +++ b/core/src/kura.rs @@ -1,6 +1,6 @@ //! Translates to warehouse. File-system and persistence-related //! logic. [`Kura`] is the main entity which should be used to store -//! new [`Block`](`crate::block::VersionedSignedBlock`)s on the +//! new [`Block`](`crate::block::SignedBlock`)s on the //! blockchain. #![allow(clippy::std_instead_of_alloc, clippy::arithmetic_side_effects)] use std::{ @@ -13,7 +13,7 @@ use std::{ use iroha_config::kura::Mode; use iroha_crypto::{Hash, HashOf}; -use iroha_data_model::block::VersionedSignedBlock; +use iroha_data_model::block::SignedBlock; use iroha_logger::prelude::*; use iroha_version::scale::{DecodeVersioned, EncodeVersioned}; use parity_scale_codec::DecodeAll; @@ -38,12 +38,7 @@ pub struct Kura { block_store: Mutex, /// The array of block hashes and a slot for an arc of the block. This is normally recovered from the index file. #[allow(clippy::type_complexity)] - block_data: Mutex< - Vec<( - HashOf, - Option>, - )>, - >, + block_data: Mutex, Option>)>>, /// Path to file for plain text blocks. block_plain_text_path: Option, } @@ -144,7 +139,7 @@ impl Kura { fn init_fast_mode( block_store: &BlockStore, block_index_count: usize, - ) -> Result>, Error> { + ) -> Result>, Error> { let block_hashes_count = block_store .read_hashes_count()? .try_into() @@ -159,7 +154,7 @@ impl Kura { fn init_strict_mode( block_store: &mut BlockStore, block_index_count: usize, - ) -> Result>, Error> { + ) -> Result>, Error> { let mut block_hashes = Vec::with_capacity(block_index_count); let mut block_indices = vec![BlockIndex::default(); block_index_count]; @@ -171,7 +166,7 @@ impl Kura { let mut block_data_buffer = vec![0_u8; block.length.try_into()?]; match block_store.read_block_data(block.start, &mut block_data_buffer) { - Ok(_) => match VersionedSignedBlock::decode_all_versioned(&block_data_buffer) { + Ok(_) => match SignedBlock::decode_all_versioned(&block_data_buffer) { Ok(decoded_block) => { if previous_block_hash != decoded_block.payload().header.previous_block_hash { @@ -284,7 +279,7 @@ impl Kura { /// Get the hash of the block at the provided height. #[allow(clippy::expect_used)] - pub fn get_block_hash(&self, block_height: u64) -> Option> { + pub fn get_block_hash(&self, block_height: u64) -> Option> { let hash_data_guard = self.block_data.lock(); if block_height == 0 || block_height > hash_data_guard.len() as u64 { return None; @@ -296,7 +291,7 @@ impl Kura { } /// Search through blocks for the height of the block with the given hash. - pub fn get_block_height_by_hash(&self, hash: &HashOf) -> Option { + pub fn get_block_height_by_hash(&self, hash: &HashOf) -> Option { self.block_data .lock() .iter() @@ -308,7 +303,7 @@ impl Kura { #[allow(clippy::expect_used)] // The below lint suggests changing the code into something that does not compile due // to the borrow checker. - pub fn get_block_by_height(&self, block_height: u64) -> Option> { + pub fn get_block_by_height(&self, block_height: u64) -> Option> { let mut data_array_guard = self.block_data.lock(); if block_height == 0 || block_height > data_array_guard.len() as u64 { return None; @@ -331,8 +326,7 @@ impl Kura { block_store .read_block_data(start, &mut block_buf) .expect("Failed to read block data."); - let block = - VersionedSignedBlock::decode_all_versioned(&block_buf).expect("Failed to decode block"); + let block = SignedBlock::decode_all_versioned(&block_buf).expect("Failed to decode block"); let block_arc = Arc::new(block); data_array_guard[block_number].1 = Some(Arc::clone(&block_arc)); @@ -344,10 +338,7 @@ impl Kura { /// Internally this function searches linearly for the block's height and /// then calls `get_block_by_height`. If you know the height of the block, /// call `get_block_by_height` directly. - pub fn get_block_by_hash( - &self, - block_hash: &HashOf, - ) -> Option> { + pub fn get_block_by_hash(&self, block_hash: &HashOf) -> Option> { let index = self .block_data .lock() @@ -359,13 +350,13 @@ impl Kura { /// Put a block in kura's in memory block store. pub fn store_block(&self, block: CommittedBlock) { - let block = Arc::new(VersionedSignedBlock::from(block)); + let block = Arc::new(SignedBlock::from(block)); self.block_data.lock().push((block.hash(), Some(block))); } /// Replace the block in `Kura`'s in memory block store. pub fn replace_top_block(&self, block: CommittedBlock) { - let block = Arc::new(VersionedSignedBlock::from(block)); + let block = Arc::new(SignedBlock::from(block)); let mut data = self.block_data.lock(); data.pop(); data.push((block.hash(), Some(block))); @@ -546,7 +537,7 @@ impl BlockStore { &self, start_block_height: u64, block_count: usize, - ) -> Result>> { + ) -> Result>> { let path = self.path_to_blockchain.join(HASHES_FILE_NAME); let mut hashes_file = std::fs::OpenOptions::new() .read(true) @@ -580,7 +571,7 @@ impl BlockStore { /// Get the number of hashes in the hashes file, which is /// calculated as the size of the hashes file in bytes divided by - /// `size_of(HashOf)`. + /// `size_of(HashOf)`. /// /// # Errors /// IO Error. @@ -714,11 +705,7 @@ impl BlockStore { /// /// # Errors /// IO Error. - pub fn write_block_hash( - &mut self, - block_height: u64, - hash: HashOf, - ) -> Result<()> { + pub fn write_block_hash(&mut self, block_height: u64, hash: HashOf) -> Result<()> { let path = self.path_to_blockchain.join(HASHES_FILE_NAME); let mut hashes_file = std::fs::OpenOptions::new() .write(true) @@ -746,10 +733,7 @@ impl BlockStore { /// /// # Errors /// IO Error. - pub fn overwrite_block_hashes( - &mut self, - hashes: &[HashOf], - ) -> Result<()> { + pub fn overwrite_block_hashes(&mut self, hashes: &[HashOf]) -> Result<()> { let path = self.path_to_blockchain.join(HASHES_FILE_NAME); let hashes_file = std::fs::OpenOptions::new() .write(true) @@ -803,7 +787,7 @@ impl BlockStore { /// # Errors /// Fails if any of the required platform-specific functions /// fail. - pub fn append_block_to_chain(&mut self, block: &VersionedSignedBlock) -> Result<()> { + pub fn append_block_to_chain(&mut self, block: &SignedBlock) -> Result<()> { let bytes = block.encode_versioned(); let new_block_height = self.read_index_count()?; let start_location_in_data_file = if new_block_height == 0 { diff --git a/core/src/queue.rs b/core/src/queue.rs index 64fb5e97a78..114262946e8 100644 --- a/core/src/queue.rs +++ b/core/src/queue.rs @@ -863,7 +863,7 @@ mod tests { let mut tx = accepted_tx("alice@wonderland", alice_key); assert!(queue.push(tx.clone(), &wsv).is_ok()); // tamper timestamp - let VersionedSignedTransaction::V1(tx_ref) = &mut tx.0; + let SignedTransaction::V1(tx_ref) = &mut tx.0; tx_ref.payload.creation_time_ms += 2 * future_threshold_ms; assert!(matches!( queue.push(tx, &wsv), diff --git a/core/src/smartcontracts/isi/block.rs b/core/src/smartcontracts/isi/block.rs index e72a8161d5e..4f241372ef1 100644 --- a/core/src/smartcontracts/isi/block.rs +++ b/core/src/smartcontracts/isi/block.rs @@ -1,7 +1,7 @@ //! This module contains trait implementations related to block queries use eyre::{Result, WrapErr}; use iroha_data_model::{ - block::{BlockHeader, VersionedSignedBlock}, + block::{BlockHeader, SignedBlock}, evaluate::ExpressionEvaluator, query::{ block::FindBlockHeaderByHash, @@ -17,11 +17,11 @@ impl ValidQuery for FindAllBlocks { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result + 'wsv>, QueryExecutionFail> { + ) -> Result + 'wsv>, QueryExecutionFail> { Ok(Box::new( wsv.all_blocks() .rev() - .map(|block| VersionedSignedBlock::clone(&block)), + .map(|block| SignedBlock::clone(&block)), )) } } diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 8c4f3ed88f0..cd15a888f90 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -58,7 +58,7 @@ impl_lazy! { /// Query Request statefully validated on the Iroha node side. #[derive(Debug, Decode, Encode)] #[repr(transparent)] -pub struct ValidQueryRequest(VersionedSignedQuery); +pub struct ValidQueryRequest(SignedQuery); impl ValidQueryRequest { /// Validate query. @@ -67,10 +67,7 @@ impl ValidQueryRequest { /// - Account doesn't exist /// - Account doesn't have the correct public key /// - Account has incorrect permissions - pub fn validate( - query: VersionedSignedQuery, - wsv: &WorldStateView, - ) -> Result { + pub fn validate(query: SignedQuery, wsv: &WorldStateView) -> Result { let account_has_public_key = wsv .map_account(query.authority(), |account| { account.signatories.contains(query.signature().public_key()) diff --git a/core/src/smartcontracts/isi/tx.rs b/core/src/smartcontracts/isi/tx.rs index 9729ed44153..b33fa69f7f5 100644 --- a/core/src/smartcontracts/isi/tx.rs +++ b/core/src/smartcontracts/isi/tx.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use eyre::{Result, WrapErr}; use iroha_crypto::HashOf; use iroha_data_model::{ - block::VersionedSignedBlock, + block::SignedBlock, evaluate::ExpressionEvaluator, prelude::*, query::{ @@ -18,11 +18,11 @@ use iroha_telemetry::metrics; use super::*; -pub(crate) struct BlockTransactionIter(Arc, usize); -pub(crate) struct BlockTransactionRef(Arc, usize); +pub(crate) struct BlockTransactionIter(Arc, usize); +pub(crate) struct BlockTransactionRef(Arc, usize); impl BlockTransactionIter { - fn new(block: Arc) -> Self { + fn new(block: Arc) -> Self { Self(block, 0) } } @@ -43,7 +43,7 @@ impl Iterator for BlockTransactionIter { } impl BlockTransactionRef { - fn block_hash(&self) -> HashOf { + fn block_hash(&self) -> HashOf { self.0.hash() } diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 32d6e1770e7..289b8f4517c 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -470,7 +470,7 @@ pub mod state { } /// State for executing `validate_transaction()` entrypoint of validator - pub type ValidateTransaction<'wrld> = ValidateMut<'wrld, VersionedSignedTransaction>; + pub type ValidateTransaction<'wrld> = ValidateMut<'wrld, SignedTransaction>; /// State for executing `validate_instruction()` entrypoint of validator pub type ValidateInstruction<'wrld> = ValidateMut<'wrld, InstructionBox>; @@ -1006,7 +1006,7 @@ impl<'wrld> Runtime> { wsv: &'wrld mut WorldStateView, authority: &AccountId, module: &wasmtime::Module, - transaction: VersionedSignedTransaction, + transaction: SignedTransaction, ) -> Result { let span = wasm_log_span!("Running `validate_transaction()`"); diff --git a/core/src/snapshot.rs b/core/src/snapshot.rs index bef4d0140da..bc8b9f8b376 100644 --- a/core/src/snapshot.rs +++ b/core/src/snapshot.rs @@ -15,7 +15,7 @@ use std::{ use iroha_config::snapshot::Configuration; use iroha_crypto::HashOf; -use iroha_data_model::block::VersionedSignedBlock; +use iroha_data_model::block::SignedBlock; use iroha_logger::prelude::*; use serde::{de::DeserializeSeed, Serialize}; use tokio::sync::mpsc; @@ -219,8 +219,8 @@ pub enum Error { /// Height at which block hashes differs between snapshot and [`Kura`] height: usize, /// Hash of the block stored in snapshot - snapshot_block_hash: HashOf, + snapshot_block_hash: HashOf, /// Hash of the block stored in kura - kura_block_hash: HashOf, + kura_block_hash: HashOf, }, } diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index 333d487cddf..5ec973be3c8 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -1087,10 +1087,10 @@ enum BlockSyncError { } fn handle_block_sync( - block: VersionedSignedBlock, + block: SignedBlock, wsv: &WorldStateView, finalized_wsv: &WorldStateView, -) -> Result { +) -> Result { let block_height = block.payload().header.height; let wsv_height = wsv.height(); if wsv_height + 1 == block_height { @@ -1168,7 +1168,7 @@ mod tests { fn create_data_for_test( topology: &Topology, leader_key_pair: KeyPair, - ) -> (WorldStateView, Arc, VersionedSignedBlock) { + ) -> (WorldStateView, Arc, SignedBlock) { // Predefined world state let alice_id: AccountId = "alice@wonderland".parse().expect("Valid"); let alice_keys = KeyPair::generate().expect("Valid"); diff --git a/core/src/sumeragi/message.rs b/core/src/sumeragi/message.rs index 65f309be4a1..e54e07c752b 100644 --- a/core/src/sumeragi/message.rs +++ b/core/src/sumeragi/message.rs @@ -7,7 +7,7 @@ )] use iroha_crypto::{HashOf, SignaturesOf}; -use iroha_data_model::block::{BlockPayload, VersionedSignedBlock}; +use iroha_data_model::block::{BlockPayload, SignedBlock}; use iroha_macro::*; use parity_scale_codec::{Decode, Encode}; @@ -69,7 +69,7 @@ impl From for MessagePacket { #[non_exhaustive] pub struct BlockCreated { /// The corresponding block. - pub block: VersionedSignedBlock, + pub block: SignedBlock, } impl From for BlockCreated { @@ -93,7 +93,7 @@ pub struct BlockSigned { impl From for BlockSigned { fn from(block: ValidBlock) -> Self { let block_hash = block.payload().hash(); - let VersionedSignedBlock::V1(block) = block.into(); + let SignedBlock::V1(block) = block.into(); Self { hash: block_hash, @@ -115,7 +115,7 @@ pub struct BlockCommitted { impl From for BlockCommitted { fn from(block: CommittedBlock) -> Self { let block_hash = block.payload().hash(); - let VersionedSignedBlock::V1(block) = block.into(); + let SignedBlock::V1(block) = block.into(); Self { hash: block_hash, @@ -129,11 +129,11 @@ impl From for BlockCommitted { #[non_exhaustive] pub struct BlockSyncUpdate { /// The corresponding block. - pub block: VersionedSignedBlock, + pub block: SignedBlock, } -impl From for BlockSyncUpdate { - fn from(block: VersionedSignedBlock) -> Self { +impl From for BlockSyncUpdate { + fn from(block: SignedBlock) -> Self { Self { block } } } diff --git a/core/src/sumeragi/network_topology.rs b/core/src/sumeragi/network_topology.rs index 753694d34e1..495c72c6a47 100644 --- a/core/src/sumeragi/network_topology.rs +++ b/core/src/sumeragi/network_topology.rs @@ -10,7 +10,7 @@ use std::collections::HashSet; use derive_more::Display; use iroha_crypto::{PublicKey, SignatureOf}; -use iroha_data_model::{block::VersionedSignedBlock, prelude::PeerId}; +use iroha_data_model::{block::SignedBlock, prelude::PeerId}; use iroha_logger::trace; use iroha_primitives::unique_vec::UniqueVec; @@ -188,7 +188,7 @@ impl Topology { /// Recreate topology for given block and view change index pub fn recreate_topology( - block: &VersionedSignedBlock, + block: &SignedBlock, view_change_index: u64, new_peers: UniqueVec, ) -> Self { diff --git a/core/src/sumeragi/view_change.rs b/core/src/sumeragi/view_change.rs index d9560ffe8e2..f4de4d07f18 100644 --- a/core/src/sumeragi/view_change.rs +++ b/core/src/sumeragi/view_change.rs @@ -11,7 +11,7 @@ use std::collections::HashSet; use derive_more::{Deref, DerefMut}; use eyre::Result; use iroha_crypto::{HashOf, KeyPair, PublicKey, SignatureOf, SignaturesOf}; -use iroha_data_model::{block::VersionedSignedBlock, prelude::PeerId}; +use iroha_data_model::{block::SignedBlock, prelude::PeerId}; use parity_scale_codec::{Decode, Encode}; use thiserror::Error; @@ -28,7 +28,7 @@ pub enum Error { #[derive(Debug, Clone, Decode, Encode)] struct ProofPayload { /// Hash of the latest committed block. - latest_block_hash: Option>, + latest_block_hash: Option>, /// Within a round, what is the index of the view change this proof is trying to prove. view_change_index: u64, } @@ -47,10 +47,7 @@ pub struct ProofBuilder(SignedProof); impl ProofBuilder { /// Constructor from index. - pub fn new( - latest_block_hash: Option>, - view_change_index: u64, - ) -> Self { + pub fn new(latest_block_hash: Option>, view_change_index: u64) -> Self { let proof = SignedProof { payload: ProofPayload { latest_block_hash, @@ -115,7 +112,7 @@ impl ProofChain { &self, peers: &[PeerId], max_faults: usize, - latest_block_hash: Option>, + latest_block_hash: Option>, ) -> usize { self.iter() .enumerate() @@ -128,7 +125,7 @@ impl ProofChain { } /// Remove invalid proofs from the chain. - pub fn prune(&mut self, latest_block_hash: Option>) { + pub fn prune(&mut self, latest_block_hash: Option>) { let valid_count = self .iter() .enumerate() @@ -150,7 +147,7 @@ impl ProofChain { &mut self, peers: &[PeerId], max_faults: usize, - latest_block_hash: Option>, + latest_block_hash: Option>, new_proof: SignedProof, ) -> Result<(), Error> { if new_proof.payload.latest_block_hash != latest_block_hash { @@ -181,7 +178,7 @@ impl ProofChain { mut other: Self, peers: &[PeerId], max_faults: usize, - latest_block_hash: Option>, + latest_block_hash: Option>, ) -> Result<(), Error> { // Prune to exclude invalid proofs other.prune(latest_block_hash); diff --git a/core/src/tx.rs b/core/src/tx.rs index 5475849e548..3fe133c9ec4 100644 --- a/core/src/tx.rs +++ b/core/src/tx.rs @@ -31,9 +31,9 @@ use crate::{prelude::*, smartcontracts::wasm}; /// `AcceptedTransaction` — a transaction accepted by iroha peer. #[derive(Debug, Clone, PartialEq, Eq)] // TODO: Inner field should be private to maintain invariants -pub struct AcceptedTransaction(pub(crate) VersionedSignedTransaction); +pub struct AcceptedTransaction(pub(crate) SignedTransaction); -/// Error type for transaction from [`VersionedSignedTransaction`] to [`AcceptedTransaction`] +/// Error type for transaction from [`SignedTransaction`] to [`AcceptedTransaction`] #[derive(Debug, FromVariant, thiserror::Error, displaydoc::Display)] pub enum AcceptTransactionFail { /// Failure during limits check @@ -79,13 +79,13 @@ impl AcceptedTransaction { Self(tx.0) } - /// Accept transaction. Transition from [`VersionedSignedTransaction`] to [`AcceptedTransaction`]. + /// Accept transaction. Transition from [`SignedTransaction`] to [`AcceptedTransaction`]. /// /// # Errors /// /// - if it does not adhere to limits pub fn accept( - transaction: VersionedSignedTransaction, + transaction: SignedTransaction, limits: &TransactionLimits, ) -> Result { if *iroha_genesis::GENESIS_ACCOUNT_ID == transaction.payload().authority { @@ -138,7 +138,7 @@ impl AcceptedTransaction { } /// Transaction hash - pub fn hash(&self) -> HashOf { + pub fn hash(&self) -> HashOf { self.0.hash() } @@ -156,7 +156,7 @@ impl AcceptedTransaction { } } -impl From for VersionedSignedTransaction { +impl From for SignedTransaction { fn from(source: AcceptedTransaction) -> Self { source.0 } @@ -194,8 +194,7 @@ impl TransactionValidator { &self, tx: AcceptedTransaction, wsv: &mut WorldStateView, - ) -> Result - { + ) -> Result { if let Err(rejection_reason) = self.validate_internal(tx.clone(), wsv) { return Err((tx.0, rejection_reason)); } @@ -273,7 +272,7 @@ impl TransactionValidator { tx: AcceptedTransaction, wsv: &mut WorldStateView, ) -> Result<(), TransactionRejectionReason> { - let tx: VersionedSignedTransaction = tx.into(); + let tx: SignedTransaction = tx.into(); let authority = tx.payload().authority.clone(); wsv.validator() diff --git a/core/src/validator.rs b/core/src/validator.rs index 0784bc594ff..c44d3611db9 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -5,7 +5,7 @@ use iroha_data_model::{ account::AccountId, isi::InstructionBox, query::QueryBox, - transaction::{Executable, VersionedSignedTransaction}, + transaction::{Executable, SignedTransaction}, validator as data_model_validator, ValidationFail, }; use iroha_logger::trace; @@ -126,7 +126,7 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Validator> { } impl Validator { - /// Validate [`VersionedSignedTransaction`]. + /// Validate [`SignedTransaction`]. /// /// # Errors /// @@ -137,7 +137,7 @@ impl Validator { &self, wsv: &mut WorldStateView, authority: &AccountId, - transaction: VersionedSignedTransaction, + transaction: SignedTransaction, ) -> Result<(), ValidationFail> { trace!("Running transaction validation"); diff --git a/core/src/wsv.rs b/core/src/wsv.rs index f6ed8a07444..3bfe40f127b 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -24,7 +24,7 @@ use iroha_config::{ use iroha_crypto::HashOf; use iroha_data_model::{ account::AccountId, - block::VersionedSignedBlock, + block::SignedBlock, events::notification::{TriggerCompletedEvent, TriggerCompletedOutcome}, isi::error::{InstructionExecutionError as Error, MathError}, parameter::Parameter, @@ -272,9 +272,9 @@ pub struct WorldStateView { /// Configuration of World State View. pub config: Configuration, /// Blockchain. - pub block_hashes: Vec>, + pub block_hashes: Vec>, /// Hashes of transactions mapped onto block height where they stored - pub transactions: HashMap, u64>, + pub transactions: HashMap, u64>, /// Buffer containing events generated during `WorldStateView::apply`. Renewed on every block commit. #[serde(skip)] pub events_buffer: Vec, @@ -636,7 +636,7 @@ impl WorldStateView { .transactions .iter() .map(|tx| &tx.value) - .map(VersionedSignedTransaction::hash) + .map(SignedTransaction::hash) .for_each(|tx_hash| { self.transactions.insert(tx_hash, block_height); }); @@ -690,7 +690,7 @@ impl WorldStateView { /// Get a reference to the latest block. Returns none if genesis is not committed. #[inline] - pub fn latest_block_ref(&self) -> Option> { + pub fn latest_block_ref(&self) -> Option> { self.kura .get_block_by_height(self.block_hashes.len() as u64) } @@ -788,7 +788,7 @@ impl WorldStateView { } /// Load all blocks in the block chain from disc - pub fn all_blocks(&self) -> impl DoubleEndedIterator> + '_ { + pub fn all_blocks(&self) -> impl DoubleEndedIterator> + '_ { let block_count = self.block_hashes.len() as u64; (1..=block_count).map(|height| { self.kura @@ -800,8 +800,8 @@ impl WorldStateView { /// Return a vector of blockchain blocks after the block with the given `hash` pub fn block_hashes_after_hash( &self, - hash: Option>, - ) -> Vec> { + hash: Option>, + ) -> Vec> { hash.map_or_else( || self.block_hashes.clone(), |block_hash| { @@ -827,7 +827,7 @@ impl WorldStateView { } /// Return an iterator over blockchain block hashes starting with the block of the given `height` - pub fn block_hashes_from_height(&self, height: usize) -> Vec> { + pub fn block_hashes_from_height(&self, height: usize) -> Vec> { self.block_hashes .iter() .skip(height.saturating_sub(1)) @@ -928,9 +928,9 @@ impl WorldStateView { } } - /// Check if this [`VersionedSignedTransaction`] is already committed or rejected. + /// Check if this [`SignedTransaction`] is already committed or rejected. #[inline] - pub fn has_transaction(&self, hash: HashOf) -> bool { + pub fn has_transaction(&self, hash: HashOf) -> bool { self.transactions.contains_key(&hash) } @@ -941,7 +941,7 @@ impl WorldStateView { } /// Return the hash of the latest block - pub fn latest_block_hash(&self) -> Option> { + pub fn latest_block_hash(&self) -> Option> { self.block_hashes.iter().nth_back(0).copied() } @@ -953,7 +953,7 @@ impl WorldStateView { } /// Return the hash of the block one before the latest block - pub fn previous_block_hash(&self) -> Option> { + pub fn previous_block_hash(&self) -> Option> { self.block_hashes.iter().nth_back(1).copied() } @@ -1160,11 +1160,8 @@ impl WorldStateView { Ok(()) } - /// Find a [`VersionedSignedBlock`] by hash. - pub fn block_with_tx( - &self, - hash: &HashOf, - ) -> Option> { + /// Find a [`SignedBlock`] by hash. + pub fn block_with_tx(&self, hash: &HashOf) -> Option> { let height = *self.transactions.get(hash)?; self.kura.get_block_by_height(height) } @@ -1267,7 +1264,7 @@ mod tests { for i in 1..=BLOCK_CNT { let mut block = block.clone(); - let VersionedSignedBlock::V1(v1_block) = &mut block.0; + let SignedBlock::V1(v1_block) = &mut block.0; v1_block.payload.header.height = i as u64; v1_block.payload.header.previous_block_hash = block_hashes.last().copied(); @@ -1293,7 +1290,7 @@ mod tests { for i in 1..=BLOCK_CNT { let mut block = block.clone(); - let VersionedSignedBlock::V1(v1_block) = &mut block.0; + let SignedBlock::V1(v1_block) = &mut block.0; v1_block.payload.header.height = i as u64; wsv.apply(&block).unwrap(); diff --git a/data_model/src/block.rs b/data_model/src/block.rs index fe471df2901..8fb6a040b54 100644 --- a/data_model/src/block.rs +++ b/data_model/src/block.rs @@ -58,9 +58,9 @@ pub mod model { #[getset(skip)] pub timestamp_ms: u64, /// Hash of the previous block in the chain. - pub previous_block_hash: Option>, + pub previous_block_hash: Option>, /// Hash of merkle tree root of transactions' hashes. - pub transactions_hash: Option>>, + pub transactions_hash: Option>>, /// Value of view change index. Used to resolve soft forks. pub view_change_index: u64, /// Estimation of consensus duration (in milliseconds). @@ -101,7 +101,7 @@ pub mod model { } /// Signed block - #[version_with_scale(version = 1, versioned_alias = "VersionedSignedBlock")] + #[version_with_scale(version = 1, versioned_alias = "SignedBlock")] #[derive( Debug, Display, @@ -119,7 +119,7 @@ pub mod model { #[cfg_attr(feature = "std", display(fmt = "{}", "self.hash()"))] #[getset(get = "pub")] #[ffi_type] - pub struct SignedBlock { + pub struct SignedBlockV1 { /// Signatures of peers which approved this block. #[getset(skip)] pub signatures: SignaturesOf, @@ -129,9 +129,9 @@ pub mod model { } #[cfg(any(feature = "ffi_export", feature = "ffi_import"))] -declare_versioned!(VersionedSignedBlock 1..2, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, FromVariant, iroha_ffi::FfiType, IntoSchema); +declare_versioned!(SignedBlock 1..2, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, FromVariant, iroha_ffi::FfiType, IntoSchema); #[cfg(all(not(feature = "ffi_export"), not(feature = "ffi_import")))] -declare_versioned!(VersionedSignedBlock 1..2, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, FromVariant, IntoSchema); +declare_versioned!(SignedBlock 1..2, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, FromVariant, IntoSchema); impl BlockPayload { /// Calculate block payload [`Hash`](`iroha_crypto::HashOf`). @@ -159,18 +159,18 @@ impl BlockHeader { } } -impl SignedBlock { +impl SignedBlockV1 { #[cfg(feature = "std")] - fn hash(&self) -> iroha_crypto::HashOf { + fn hash(&self) -> iroha_crypto::HashOf { iroha_crypto::HashOf::from_untyped_unchecked(iroha_crypto::HashOf::new(self).into()) } } -impl VersionedSignedBlock { +impl SignedBlock { /// Block payload // FIXME: Leaking concrete type BlockPayload from Versioned container. Payload should be versioned pub fn payload(&self) -> &BlockPayload { - let VersionedSignedBlock::V1(block) = self; + let SignedBlock::V1(block) = self; block.payload() } @@ -178,13 +178,13 @@ impl VersionedSignedBlock { #[cfg(debug_assertions)] #[cfg(feature = "transparent_api")] pub fn payload_mut(&mut self) -> &mut BlockPayload { - let VersionedSignedBlock::V1(block) = self; + let SignedBlock::V1(block) = self; &mut block.payload } /// Signatures of peers which approved this block. pub fn signatures(&self) -> &SignaturesOf { - let VersionedSignedBlock::V1(block) = self; + let SignedBlock::V1(block) = self; &block.signatures } @@ -203,7 +203,7 @@ impl VersionedSignedBlock { #[cfg(feature = "transparent_api")] pub fn sign(mut self, key_pair: KeyPair) -> Result { iroha_crypto::SignatureOf::new(key_pair, self.payload()).map(|signature| { - let VersionedSignedBlock::V1(block) = &mut self; + let SignedBlock::V1(block) = &mut self; block.signatures.insert(signature); self }) @@ -222,7 +222,7 @@ impl VersionedSignedBlock { ) -> Result<(), iroha_crypto::error::Error> { signature.verify(self.payload())?; - let VersionedSignedBlock::V1(block) = self; + let SignedBlock::V1(block) = self; block.signatures.insert(signature); Ok(()) @@ -240,7 +240,7 @@ impl VersionedSignedBlock { #[cfg(feature = "std")] use std::collections::BTreeSet; - let VersionedSignedBlock::V1(block) = self; + let SignedBlock::V1(block) = self; block.signatures = BTreeSet::new().into(); for signature in signatures { @@ -265,7 +265,7 @@ mod candidate { } impl SignedBlockCandidate { - fn validate(self) -> Result { + fn validate(self) -> Result { #[cfg(feature = "std")] self.validate_signatures()?; #[cfg(feature = "std")] @@ -275,7 +275,7 @@ mod candidate { return Err("Block is empty"); } - Ok(SignedBlock { + Ok(SignedBlockV1 { payload: self.payload, signatures: self.signatures, }) @@ -309,14 +309,14 @@ mod candidate { } } - impl Decode for SignedBlock { + impl Decode for SignedBlockV1 { fn decode(input: &mut I) -> Result { SignedBlockCandidate::decode(input)? .validate() .map_err(Into::into) } } - impl<'de> Deserialize<'de> for SignedBlock { + impl<'de> Deserialize<'de> for SignedBlockV1 { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -330,9 +330,9 @@ mod candidate { } } -impl Display for VersionedSignedBlock { +impl Display for SignedBlock { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let VersionedSignedBlock::V1(block) = self; + let SignedBlock::V1(block) = self; block.fmt(f) } } @@ -362,10 +362,10 @@ pub mod stream { /// Message sent by the stream producer containing block. #[derive(Debug, Clone, Decode, Encode, IntoSchema)] #[repr(transparent)] - pub struct BlockMessage(pub VersionedSignedBlock); + pub struct BlockMessage(pub SignedBlock); } - impl From for VersionedSignedBlock { + impl From for SignedBlock { fn from(source: BlockMessage) -> Self { source.0 } diff --git a/data_model/src/events/pipeline.rs b/data_model/src/events/pipeline.rs index e42f9a8d3ee..4fbe2cfc8b6 100644 --- a/data_model/src/events/pipeline.rs +++ b/data_model/src/events/pipeline.rs @@ -40,7 +40,7 @@ pub mod model { /// If `Some::`, filter by the [`StatusKind`]. If `None`, accept all the [`StatusKind`]. pub(super) status_kind: Option, /// If `Some::`, filter by the [`struct@Hash`]. If `None`, accept all the [`struct@Hash`]. - // TODO: Can we make hash typed like HashOf? + // TODO: Can we make hash typed like HashOf? pub(super) hash: Option, } diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 45c9791b156..00562ad9ae4 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -32,7 +32,7 @@ use core::{ str::FromStr, }; -use block::VersionedSignedBlock; +use block::SignedBlock; #[cfg(not(target_arch = "aarch64"))] use derive_more::Into; use derive_more::{AsRef, DebugCustom, Deref, Display, From, FromStr}; @@ -50,7 +50,7 @@ use iroha_primitives::{ use iroha_schema::IntoSchema; pub use numeric::model::NumericValue; use parity_scale_codec::{Decode, Encode}; -use prelude::{Executable, TransactionQueryOutput, VersionedSignedTransaction}; +use prelude::{Executable, SignedTransaction, TransactionQueryOutput}; use serde::{Deserialize, Serialize}; use serde_with::{DeserializeFromStr, SerializeDisplay}; use strum::FromRepr; @@ -781,7 +781,7 @@ pub mod model { PermissionToken(permission::PermissionToken), PermissionTokenSchema(permission::PermissionTokenSchema), Hash(HashValue), - Block(VersionedSignedBlockWrapper), + Block(SignedBlockWrapper), BlockHeader(block::BlockHeader), Ipv4Addr(iroha_primitives::addr::Ipv4Addr), Ipv6Addr(iroha_primitives::addr::Ipv6Addr), @@ -811,12 +811,12 @@ pub mod model { #[ffi_type] pub enum HashValue { /// Transaction hash - Transaction(HashOf), + Transaction(HashOf), /// Block hash - Block(HashOf), + Block(HashOf), } - /// Cross-platform wrapper for [`VersionedSignedBlock`]. + /// Cross-platform wrapper for [`SignedBlock`]. #[cfg(not(target_arch = "aarch64"))] #[derive( Debug, @@ -835,12 +835,12 @@ pub mod model { Serialize, IntoSchema, )] - // SAFETY: VersionedSignedBlockWrapper has no trap representations in VersionedSignedBlock + // SAFETY: SignedBlockWrapper has no trap representations in SignedBlock #[schema(transparent)] #[ffi_type(unsafe {robust})] #[serde(transparent)] #[repr(transparent)] - pub struct VersionedSignedBlockWrapper(VersionedSignedBlock); + pub struct SignedBlockWrapper(SignedBlock); /// Cross-platform wrapper for `BlockValue`. #[cfg(target_arch = "aarch64")] @@ -864,11 +864,11 @@ pub mod model { #[as_ref(forward)] #[deref(forward)] #[from(forward)] - // SAFETY: VersionedSignedBlockWrapper has no trap representations in Box + // SAFETY: SignedBlockWrapper has no trap representations in Box #[ffi_type(unsafe {robust})] #[serde(transparent)] #[repr(transparent)] - pub struct VersionedSignedBlockWrapper(pub(super) Box); + pub struct SignedBlockWrapper(pub(super) Box); /// Limits of length of the identifiers (e.g. in [`domain::Domain`], [`account::Account`], [`asset::AssetDefinition`]) in number of chars #[derive( @@ -1056,8 +1056,8 @@ macro_rules! val_vec { } #[cfg(target_arch = "aarch64")] -impl From for VersionedSignedBlock { - fn from(block_value: VersionedSignedBlockWrapper) -> Self { +impl From for SignedBlock { + fn from(block_value: SignedBlockWrapper) -> Self { *block_value.0 } } @@ -1135,8 +1135,8 @@ impl Value { } } -impl From for Value { - fn from(block_value: VersionedSignedBlock) -> Self { +impl From for Value { + fn from(block_value: SignedBlock) -> Self { Value::Block(block_value.into()) } } @@ -1328,8 +1328,8 @@ from_and_try_from_value_identifiable!( ); from_and_try_from_and_try_as_value_hash! { - Transaction(HashOf), - Block(HashOf), + Transaction(HashOf), + Block(HashOf), } from_and_try_from_and_try_as_value_numeric! { @@ -1429,7 +1429,7 @@ where } } -impl TryFrom for VersionedSignedBlock { +impl TryFrom for SignedBlock { type Error = ErrorTryFromEnum; fn try_from(value: Value) -> Result { @@ -1855,7 +1855,7 @@ pub mod http { pub use self::model::*; use crate::prelude::QueryOutput; - declare_versioned_with_scale!(VersionedBatchedResponse 1..2, Debug, Clone, iroha_macro::FromVariant, IntoSchema); + declare_versioned_with_scale!(BatchedResponse 1..2, Debug, Clone, iroha_macro::FromVariant, IntoSchema); #[model] pub mod model { @@ -1868,10 +1868,10 @@ pub mod http { /// Batched response of a query sent to torii #[derive(Debug, Clone, Getters, Decode, Encode, Deserialize, Serialize, IntoSchema)] - #[version_with_scale(version = 1, versioned_alias = "VersionedBatchedResponse")] + #[version_with_scale(version = 1, versioned_alias = "BatchedResponse")] #[getset(get = "pub")] #[must_use] - pub struct BatchedResponse { + pub struct BatchedResponseV1 { /// Current batch pub batch: T, /// Index of the next element in the result set. Client will use this value @@ -1880,16 +1880,16 @@ pub mod http { } } - impl From> for QueryOutput { + impl From> for QueryOutput { #[inline] - fn from(source: BatchedResponse) -> Self { + fn from(source: BatchedResponseV1) -> Self { source.batch } } - impl From> for (T, crate::query::cursor::ForwardCursor) { - fn from(source: BatchedResponse) -> Self { - let BatchedResponse { batch, cursor } = source; + impl From> for (T, crate::query::cursor::ForwardCursor) { + fn from(source: BatchedResponseV1) -> Self { + let BatchedResponseV1 { batch, cursor } = source; (batch, cursor) } diff --git a/data_model/src/predicate.rs b/data_model/src/predicate.rs index da9cc267b59..3cd95902fb4 100644 --- a/data_model/src/predicate.rs +++ b/data_model/src/predicate.rs @@ -992,7 +992,7 @@ pub mod value { Display(string::StringPredicate), /// Apply predicate to the numerical value. Numerical(numerical::SemiRange), - /// Timestamp (currently for [`VersionedSignedBlock`] only). + /// Timestamp (currently for [`SignedBlock`] only). TimeStamp(numerical::SemiInterval), /// IpAddress enumerable by `u32` Ipv4Addr(ip_addr::Ipv4Predicate), diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index 9c1d657b022..b33f153d210 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -28,9 +28,9 @@ use self::{ }; use crate::{ account::Account, - block::VersionedSignedBlock, + block::SignedBlock, seal, - transaction::{TransactionPayload, TransactionValue, VersionedSignedTransaction}, + transaction::{SignedTransaction, TransactionPayload, TransactionValue}, Identifiable, Value, }; @@ -71,7 +71,7 @@ pub mod model { use iroha_crypto::HashOf; use super::*; - use crate::{block::VersionedSignedBlock, permission::PermissionTokenId}; + use crate::{block::SignedBlock, permission::PermissionTokenId}; /// Sized container for all possible Queries. #[allow(clippy::enum_variant_names)] @@ -146,7 +146,7 @@ pub mod model { /// Transaction pub transaction: TransactionValue, /// The hash of the block to which `tx` belongs to - pub block_hash: HashOf, + pub block_hash: HashOf, } /// Type returned from [`Metadata`] queries @@ -1116,7 +1116,7 @@ pub mod transaction { use super::{Query, TransactionQueryOutput}; use crate::{ account::AccountId, expression::EvaluatesTo, prelude::Account, - transaction::VersionedSignedTransaction, + transaction::SignedTransaction, }; queries! { @@ -1143,11 +1143,11 @@ pub mod transaction { #[derive(Display)] #[display(fmt = "Find transaction with `{hash}` hash")] #[repr(transparent)] - // SAFETY: `FindTransactionByHash` has no trap representation in `EvaluatesTo>` + // SAFETY: `FindTransactionByHash` has no trap representation in `EvaluatesTo>` #[ffi_type(unsafe {robust})] pub struct FindTransactionByHash { /// Transaction hash. - pub hash: EvaluatesTo>, + pub hash: EvaluatesTo>, } } @@ -1174,7 +1174,7 @@ pub mod transaction { impl FindTransactionByHash { /// Construct [`FindTransactionByHash`]. - pub fn new(hash: impl Into>>) -> Self { + pub fn new(hash: impl Into>>) -> Self { Self { hash: hash.into() } } } @@ -1198,7 +1198,7 @@ pub mod block { use super::Query; use crate::{ - block::{BlockHeader, VersionedSignedBlock}, + block::{BlockHeader, SignedBlock}, prelude::EvaluatesTo, }; @@ -1221,16 +1221,16 @@ pub mod block { #[derive(Display)] #[display(fmt = "Find block header with `{hash}` hash")] #[repr(transparent)] - // SAFETY: `FindBlockHeaderByHash` has no trap representation in `EvaluatesTo>` + // SAFETY: `FindBlockHeaderByHash` has no trap representation in `EvaluatesTo>` #[ffi_type(unsafe {robust})] pub struct FindBlockHeaderByHash { /// Block hash. - pub hash: EvaluatesTo>, + pub hash: EvaluatesTo>, } } impl Query for FindAllBlocks { - type Output = Vec; + type Output = Vec; } impl Query for FindAllBlockHeaders { @@ -1243,7 +1243,7 @@ pub mod block { impl FindBlockHeaderByHash { /// Construct [`FindBlockHeaderByHash`]. - pub fn new(hash: impl Into>>) -> Self { + pub fn new(hash: impl Into>>) -> Self { Self { hash: hash.into() } } } @@ -1269,7 +1269,7 @@ pub mod http { /// Type representing Result of executing a query pub type QueryOutput = Value; - declare_versioned_with_scale!(VersionedSignedQuery 1..2, Debug, Clone, iroha_macro::FromVariant, IntoSchema); + declare_versioned_with_scale!(SignedQuery 1..2, Debug, Clone, iroha_macro::FromVariant, IntoSchema); #[model] pub mod model { @@ -1301,8 +1301,8 @@ pub mod http { /// I/O ready structure to send queries. #[derive(Debug, Clone, Encode, Serialize, IntoSchema)] - #[version_with_scale(version = 1, versioned_alias = "VersionedSignedQuery")] - pub struct SignedQuery { + #[version_with_scale(version = 1, versioned_alias = "SignedQuery")] + pub struct SignedQueryV1 { /// Signature of the client who sends this query. pub signature: SignatureOf, /// Payload @@ -1322,20 +1322,20 @@ pub mod http { } impl SignedQueryCandidate { - fn validate(self) -> Result { + fn validate(self) -> Result { #[cfg(feature = "std")] if self.signature.verify(&self.payload).is_err() { return Err("Query signature not valid"); } - Ok(SignedQuery { + Ok(SignedQueryV1 { payload: self.payload, signature: self.signature, }) } } - impl Decode for SignedQuery { + impl Decode for SignedQueryV1 { fn decode(input: &mut I) -> Result { SignedQueryCandidate::decode(input)? .validate() @@ -1343,7 +1343,7 @@ pub mod http { } } - impl<'de> Deserialize<'de> for SignedQuery { + impl<'de> Deserialize<'de> for SignedQueryV1 { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -1358,25 +1358,25 @@ pub mod http { } #[cfg(feature = "transparent_api")] - impl VersionedSignedQuery { + impl SignedQuery { /// Return query signature pub fn signature(&self) -> &SignatureOf { - let VersionedSignedQuery::V1(query) = self; + let SignedQuery::V1(query) = self; &query.signature } /// Return query payload pub fn query(&self) -> &QueryBox { - let VersionedSignedQuery::V1(query) = self; + let SignedQuery::V1(query) = self; &query.payload.query } /// Return query authority pub fn authority(&self) -> &AccountId { - let VersionedSignedQuery::V1(query) = self; + let SignedQuery::V1(query) = self; &query.payload.authority } /// Return query filter pub fn filter(&self) -> &PredicateBox { - let VersionedSignedQuery::V1(query) = self; + let SignedQuery::V1(query) = self; &query.payload.filter } } @@ -1408,9 +1408,9 @@ pub mod http { pub fn sign( self, key_pair: iroha_crypto::KeyPair, - ) -> Result { + ) -> Result { SignatureOf::new(key_pair, &self.payload) - .map(|signature| SignedQuery { + .map(|signature| SignedQueryV1 { payload: self.payload, signature, }) @@ -1421,7 +1421,7 @@ pub mod http { pub mod prelude { //! The prelude re-exports most commonly used traits, structs and macros from this crate. - pub use super::{QueryBuilder, SignedQuery, VersionedSignedQuery}; + pub use super::{QueryBuilder, SignedQuery, SignedQueryV1}; } } @@ -1437,7 +1437,7 @@ pub mod error { pub use self::model::*; use super::*; - use crate::{block::VersionedSignedBlock, permission, prelude::*, validator}; + use crate::{block::SignedBlock, permission, prelude::*, validator}; #[model] pub mod model { @@ -1516,9 +1516,9 @@ pub mod error { /// Failed to find metadata key: `{0}` MetadataKey(Name), /// Block with hash `{0}` not found - Block(HashOf), + Block(HashOf), /// Transaction with hash `{0}` not found - Transaction(HashOf), + Transaction(HashOf), /// Peer with id `{0}` not found Peer(PeerId), /// Trigger with id `{0}` not found diff --git a/data_model/src/transaction.rs b/data_model/src/transaction.rs index 021042cd154..7aadcf1b047 100644 --- a/data_model/src/transaction.rs +++ b/data_model/src/transaction.rs @@ -154,7 +154,7 @@ pub mod model { /// After a transaction is signed and before it can be processed any further, /// the transaction must be accepted by the `Iroha` peer. /// The peer verifies the signatures and checks the limits. - #[version(version = 1, versioned_alias = "VersionedSignedTransaction")] + #[version(version = 1, versioned_alias = "SignedTransaction")] #[derive( Debug, Display, Clone, PartialEq, Eq, PartialOrd, Ord, Encode, Serialize, IntoSchema, )] @@ -162,7 +162,7 @@ pub mod model { #[cfg_attr(feature = "std", display(fmt = "{}", "self.hash()"))] #[ffi_type] // TODO: All fields in this struct should be private - pub struct SignedTransaction { + pub struct SignedTransactionV1 { /// [`iroha_crypto::SignatureOf`]<[`TransactionPayload`]>. pub signatures: SignaturesOf, /// [`Transaction`] payload. @@ -174,7 +174,7 @@ pub mod model { #[ffi_type] pub struct TransactionValue { /// Committed transaction - pub value: VersionedSignedTransaction, + pub value: SignedTransaction, /// Reason of rejection pub error: Option, } @@ -253,21 +253,21 @@ impl TransactionPayload { } #[cfg(any(feature = "ffi_export", feature = "ffi_import"))] -declare_versioned!(VersionedSignedTransaction 1..2, Debug, Display, Clone, PartialEq, Eq, PartialOrd, Ord, FromVariant, iroha_ffi::FfiType, IntoSchema); +declare_versioned!(SignedTransaction 1..2, Debug, Display, Clone, PartialEq, Eq, PartialOrd, Ord, FromVariant, iroha_ffi::FfiType, IntoSchema); #[cfg(all(not(feature = "ffi_export"), not(feature = "ffi_import")))] -declare_versioned!(VersionedSignedTransaction 1..2, Debug, Display, Clone, PartialEq, Eq, PartialOrd, Ord, FromVariant, IntoSchema); +declare_versioned!(SignedTransaction 1..2, Debug, Display, Clone, PartialEq, Eq, PartialOrd, Ord, FromVariant, IntoSchema); -impl VersionedSignedTransaction { +impl SignedTransaction { /// Return transaction payload // FIXME: Leaking concrete type TransactionPayload from Versioned container. Payload should be versioned pub fn payload(&self) -> &TransactionPayload { - let VersionedSignedTransaction::V1(tx) = self; + let SignedTransaction::V1(tx) = self; &tx.payload } /// Return transaction signatures pub fn signatures(&self) -> &SignaturesOf { - let VersionedSignedTransaction::V1(tx) = self; + let SignedTransaction::V1(tx) = self; &tx.signatures } @@ -286,12 +286,12 @@ impl VersionedSignedTransaction { pub fn sign( self, key_pair: iroha_crypto::KeyPair, - ) -> Result { - let VersionedSignedTransaction::V1(mut tx) = self; + ) -> Result { + let SignedTransaction::V1(mut tx) = self; let signature = iroha_crypto::SignatureOf::new(key_pair, &tx.payload)?; tx.signatures.insert(signature); - Ok(SignedTransaction { + Ok(SignedTransactionV1 { payload: tx.payload, signatures: tx.signatures, } @@ -306,8 +306,8 @@ impl VersionedSignedTransaction { return false; } - let VersionedSignedTransaction::V1(tx1) = self; - let VersionedSignedTransaction::V1(tx2) = other; + let SignedTransaction::V1(tx1) = self; + let SignedTransaction::V1(tx2) = other; tx1.signatures.extend(tx2.signatures); true @@ -315,16 +315,16 @@ impl VersionedSignedTransaction { } #[cfg(feature = "transparent_api")] -impl From for (AccountId, Executable) { - fn from(source: VersionedSignedTransaction) -> Self { - let VersionedSignedTransaction::V1(tx) = source; +impl From for (AccountId, Executable) { + fn from(source: SignedTransaction) -> Self { + let SignedTransaction::V1(tx) = source; (tx.payload.authority, tx.payload.instructions) } } -impl SignedTransaction { +impl SignedTransactionV1 { #[cfg(feature = "std")] - fn hash(&self) -> iroha_crypto::HashOf { + fn hash(&self) -> iroha_crypto::HashOf { iroha_crypto::HashOf::from_untyped_unchecked(iroha_crypto::HashOf::new(self).into()) } } @@ -332,7 +332,7 @@ impl SignedTransaction { impl TransactionValue { /// Calculate transaction [`Hash`](`iroha_crypto::HashOf`). #[cfg(feature = "std")] - pub fn hash(&self) -> iroha_crypto::HashOf { + pub fn hash(&self) -> iroha_crypto::HashOf { self.value.hash() } @@ -378,24 +378,24 @@ mod candidate { impl SignedTransactionCandidate { #[cfg(feature = "std")] - fn validate(self) -> Result { + fn validate(self) -> Result { self.validate_signatures()?; self.validate_instructions() } #[cfg(not(feature = "std"))] - fn validate(self) -> Result { + fn validate(self) -> Result { self.validate_instructions() } - fn validate_instructions(self) -> Result { + fn validate_instructions(self) -> Result { if let Executable::Instructions(instructions) = &self.payload.instructions { if instructions.is_empty() { return Err("Transaction is empty"); } } - Ok(SignedTransaction { + Ok(SignedTransactionV1 { payload: self.payload, signatures: self.signatures, }) @@ -409,14 +409,14 @@ mod candidate { } } - impl Decode for SignedTransaction { + impl Decode for SignedTransactionV1 { fn decode(input: &mut I) -> Result { SignedTransactionCandidate::decode(input)? .validate() .map_err(Into::into) } } - impl<'de> Deserialize<'de> for SignedTransaction { + impl<'de> Deserialize<'de> for SignedTransactionV1 { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -743,10 +743,10 @@ mod http { pub fn sign( self, key_pair: iroha_crypto::KeyPair, - ) -> Result { + ) -> Result { let signatures = SignaturesOf::new(key_pair, &self.payload)?; - Ok(SignedTransaction { + Ok(SignedTransactionV1 { payload: self.payload, signatures, } @@ -760,8 +760,8 @@ pub mod prelude { #[cfg(feature = "http")] pub use super::http::TransactionBuilder; pub use super::{ - error::prelude::*, Executable, TransactionPayload, TransactionValue, - VersionedSignedTransaction, WasmSmartContract, + error::prelude::*, Executable, SignedTransaction, TransactionPayload, TransactionValue, + WasmSmartContract, }; } diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index 1f33124d6fa..35efa301c3e 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -38,7 +38,7 @@ pub trait Visit: ExpressionEvaluator { visit_unsupported(T), // Visit SignedTransaction - visit_transaction(&VersionedSignedTransaction), + visit_transaction(&SignedTransaction), visit_instruction(&InstructionBox), visit_expression(&EvaluatesTo), visit_wasm(&WasmSmartContract), @@ -177,7 +177,7 @@ fn visit_unsupported( pub fn visit_transaction( visitor: &mut V, authority: &AccountId, - transaction: &VersionedSignedTransaction, + transaction: &SignedTransaction, ) { match transaction.payload().instructions() { Executable::Wasm(wasm) => visitor.visit_wasm(authority, wasm), diff --git a/data_model/src/wasm.rs b/data_model/src/wasm.rs index 4d22a3cc218..e4282aae7bc 100644 --- a/data_model/src/wasm.rs +++ b/data_model/src/wasm.rs @@ -99,7 +99,7 @@ pub mod payloads { } /// Payload for [`validate_transaction()`](super::export::fn_names::VALIDATOR_VALIDATE_TRANSACTION) entrypoint - pub type ValidateTransaction = Validate; + pub type ValidateTransaction = Validate; /// Payload for [`validate_instruction()`](super::export::fn_names::VALIDATOR_VALIDATE_INSTRUCTION) entrypoint pub type ValidateInstruction = Validate; diff --git a/default_validator/src/lib.rs b/default_validator/src/lib.rs index 7a670099a5a..0bafebce69d 100644 --- a/default_validator/src/lib.rs +++ b/default_validator/src/lib.rs @@ -59,7 +59,7 @@ impl Visit for Validator { defaults! { visit_unsupported(T), - visit_transaction(&VersionedSignedTransaction), + visit_transaction(&SignedTransaction), visit_instruction(&InstructionBox), visit_expression(&EvaluatesTo), visit_sequence(&SequenceBox), @@ -169,7 +169,7 @@ pub fn migrate(block_height: u64) -> MigrationResult { #[entrypoint] pub fn validate_transaction( authority: AccountId, - transaction: VersionedSignedTransaction, + transaction: SignedTransaction, block_height: u64, ) -> Result { let mut validator = Validator::new(block_height); diff --git a/docs/source/references/api_spec.md b/docs/source/references/api_spec.md index 75d1a6f8130..8c4ccafb248 100644 --- a/docs/source/references/api_spec.md +++ b/docs/source/references/api_spec.md @@ -12,7 +12,7 @@ **Method**: `POST` -**Expects**: Body: `VersionedSignedTransaction` +**Expects**: Body: `SignedTransaction` **Responses**: @@ -34,7 +34,7 @@ **Expects**: -- Body: `VersionedSignedQuery` +- Body: `SignedQuery` - Query parameters: - `start`: Optional parameter in queries where results can be indexed. Use to return results from specified point. Results are ordered where can be by id which uses diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index ef55739736e..248ff170c81 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -619,6 +619,24 @@ ] }, "BatchedResponse": { + "Enum": [ + { + "tag": "V1", + "discriminant": 1, + "type": "BatchedResponseV1" + } + ] + }, + "BatchedResponse>": { + "Enum": [ + { + "tag": "V1", + "discriminant": 1, + "type": "BatchedResponseV1>" + } + ] + }, + "BatchedResponseV1": { "Struct": [ { "name": "batch", @@ -630,11 +648,11 @@ } ] }, - "BatchedResponse>": { + "BatchedResponseV1>": { "Struct": [ { "name": "batch", - "type": "Vec" + "type": "Vec" }, { "name": "cursor", @@ -666,11 +684,11 @@ }, { "name": "previous_block_hash", - "type": "Option>" + "type": "Option>" }, { "name": "transactions_hash", - "type": "Option>>" + "type": "Option>>" }, { "name": "view_change_index", @@ -682,7 +700,7 @@ } ] }, - "BlockMessage": "VersionedSignedBlock", + "BlockMessage": "SignedBlock", "BlockPayload": { "Struct": [ { @@ -1099,7 +1117,7 @@ } ] }, - "EvaluatesTo>": { + "EvaluatesTo>": { "Struct": [ { "name": "expression", @@ -1107,7 +1125,7 @@ } ] }, - "EvaluatesTo>": { + "EvaluatesTo>": { "Struct": [ { "name": "expression", @@ -1912,7 +1930,7 @@ "Struct": [ { "name": "hash", - "type": "EvaluatesTo>" + "type": "EvaluatesTo>" } ] }, @@ -1966,12 +1984,12 @@ { "tag": "Block", "discriminant": 5, - "type": "HashOf" + "type": "HashOf" }, { "tag": "Transaction", "discriminant": 6, - "type": "HashOf" + "type": "HashOf" }, { "tag": "Peer", @@ -2042,7 +2060,7 @@ "Struct": [ { "name": "hash", - "type": "EvaluatesTo>" + "type": "EvaluatesTo>" } ] }, @@ -2150,21 +2168,21 @@ ] }, "Hash": "Array", - "HashOf>": "Hash", - "HashOf": "Hash", - "HashOf": "Hash", + "HashOf>": "Hash", + "HashOf": "Hash", + "HashOf": "Hash", "HashOf": "Hash", "HashValue": { "Enum": [ { "tag": "Transaction", "discriminant": 0, - "type": "HashOf" + "type": "HashOf" }, { "tag": "Block", "discriminant": 1, - "type": "HashOf" + "type": "HashOf" } ] }, @@ -2726,8 +2744,8 @@ } ] }, - "MerkleTree": { - "Vec": "HashOf" + "MerkleTree": { + "Vec": "HashOf" }, "Metadata": { "Struct": [ @@ -3082,11 +3100,11 @@ "Option": { "Option": "Hash" }, - "Option>>": { - "Option": "HashOf>" + "Option>>": { + "Option": "HashOf>" }, - "Option>": { - "Option": "HashOf" + "Option>": { + "Option": "HashOf" }, "Option": { "Option": "InstructionBox" @@ -3966,6 +3984,15 @@ ] }, "SignedBlock": { + "Enum": [ + { + "tag": "V1", + "discriminant": 1, + "type": "SignedBlockV1" + } + ] + }, + "SignedBlockV1": { "Struct": [ { "name": "signatures", @@ -3978,6 +4005,15 @@ ] }, "SignedQuery": { + "Enum": [ + { + "tag": "V1", + "discriminant": 1, + "type": "SignedQueryV1" + } + ] + }, + "SignedQueryV1": { "Struct": [ { "name": "signature", @@ -3990,6 +4026,15 @@ ] }, "SignedTransaction": { + "Enum": [ + { + "tag": "V1", + "discriminant": 1, + "type": "SignedTransactionV1" + } + ] + }, + "SignedTransactionV1": { "Struct": [ { "name": "signatures", @@ -4238,7 +4283,7 @@ }, { "name": "block_hash", - "type": "HashOf" + "type": "HashOf" } ] }, @@ -4279,7 +4324,7 @@ "Struct": [ { "name": "value", - "type": "VersionedSignedTransaction" + "type": "SignedTransaction" }, { "name": "error", @@ -4681,7 +4726,7 @@ { "tag": "Block", "discriminant": 16, - "type": "VersionedSignedBlock" + "type": "SignedBlock" }, { "tag": "BlockHeader", @@ -4788,6 +4833,9 @@ "Vec": { "Vec": "PublicKey" }, + "Vec": { + "Vec": "SignedTransaction" + }, "Vec": { "Vec": "TransactionValue" }, @@ -4797,57 +4845,9 @@ "Vec>": { "Vec": "Vec" }, - "Vec": { - "Vec": "VersionedSignedTransaction" - }, "Vec": { "Vec": "u8" }, - "VersionedBatchedResponse": { - "Enum": [ - { - "tag": "V1", - "discriminant": 1, - "type": "BatchedResponse" - } - ] - }, - "VersionedBatchedResponse>": { - "Enum": [ - { - "tag": "V1", - "discriminant": 1, - "type": "BatchedResponse>" - } - ] - }, - "VersionedSignedBlock": { - "Enum": [ - { - "tag": "V1", - "discriminant": 1, - "type": "SignedBlock" - } - ] - }, - "VersionedSignedQuery": { - "Enum": [ - { - "tag": "V1", - "discriminant": 1, - "type": "SignedQuery" - } - ] - }, - "VersionedSignedTransaction": { - "Enum": [ - { - "tag": "V1", - "discriminant": 1, - "type": "SignedTransaction" - } - ] - }, "WasmExecutionFail": { "Struct": [ { diff --git a/genesis/src/lib.rs b/genesis/src/lib.rs index 398c81d2b42..1cb890de02d 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -37,7 +37,7 @@ pub static GENESIS_ACCOUNT_ID: Lazy = /// Genesis transaction #[derive(Debug, Clone)] -pub struct GenesisTransaction(pub VersionedSignedTransaction); +pub struct GenesisTransaction(pub SignedTransaction); /// [`GenesisNetwork`] contains initial transactions and genesis setup related parameters. #[derive(Debug, Clone)] @@ -202,14 +202,14 @@ pub struct GenesisTransactionBuilder { } impl GenesisTransactionBuilder { - /// Convert [`GenesisTransactionBuilder`] into [`VersionedSignedTransaction`] with signature. + /// Convert [`GenesisTransactionBuilder`] into [`SignedTransaction`] with signature. /// /// # Errors /// Fails if signing or accepting fails. pub fn sign( self, genesis_key_pair: KeyPair, - ) -> core::result::Result { + ) -> core::result::Result { TransactionBuilder::new(GENESIS_ACCOUNT_ID.clone()) .with_instructions(self.isi) .sign(genesis_key_pair) diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index c7087903abd..66bcf492255 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -6,7 +6,7 @@ use iroha_crypto::MerkleTree; use iroha_data_model::{ block::stream::{BlockMessage, BlockSubscriptionRequest}, - http::VersionedBatchedResponse, + http::BatchedResponse, query::error::QueryExecutionFail, }; use iroha_genesis::RawGenesisBlock; @@ -21,7 +21,7 @@ macro_rules! types { $( $callback!($t); )+ #[cfg(target_arch = "aarch64")] - $callback!(Box); + $callback!(Box); }} } } @@ -48,12 +48,12 @@ pub fn build_schemas() -> MetaMap { BlockSubscriptionRequest, EventMessage, EventSubscriptionRequest, - VersionedBatchedResponse, - VersionedBatchedResponse>, - VersionedSignedQuery, + BatchedResponse, + BatchedResponse>, + SignedQuery, // Never referenced, but present in type signature. Like `PhantomData` - MerkleTree, + MerkleTree, RegistrableBox, UpgradableBox, @@ -100,7 +100,9 @@ types!( BTreeSet, BTreeSet, BatchedResponse, - BatchedResponse>, + BatchedResponse>, + BatchedResponseV1, + BatchedResponseV1>, BlockHeader, BlockMessage, BlockRejectionReason, @@ -111,7 +113,6 @@ types!( Box, Box, BurnBox, - SignedBlock, Conditional, ConfigurationEvent, ConstString, @@ -192,7 +193,6 @@ types!( FindAllDomains, FindAllParameters, FindAllPeers, - FindPermissionTokenSchema, FindAllRoleIds, FindAllRoles, FindAllTransactions, @@ -210,6 +210,7 @@ types!( FindDomainById, FindDomainKeyValueByIdAndKey, FindError, + FindPermissionTokenSchema, FindPermissionTokensByAccountId, FindRoleByRoleId, FindRolesByAccountId, @@ -225,9 +226,9 @@ types!( GrantBox, Greater, Hash, - HashOf>, - HashOf, - HashOf, + HashOf>, + HashOf, + HashOf, IdBox, IdentifiableBox, If, @@ -243,7 +244,7 @@ types!( IsAssetDefinitionOwner, LengthLimits, Less, - MerkleTree, + MerkleTree, Metadata, MetadataChanged, MetadataChanged, @@ -268,8 +269,8 @@ types!( Option, Option, Option, - Option>>, - Option>, + Option>>, + Option>, Option, Option, Option, @@ -333,8 +334,13 @@ types!( SignatureOf, SignatureWrapperOf, SignaturesOf, + SignedBlock, + SignedBlockV1, + SignedBlockWrapper, SignedQuery, + SignedQueryV1, SignedTransaction, + SignedTransactionV1, String, StringPredicate, Subtract, @@ -350,13 +356,13 @@ types!( TransactionValue, TransferBox, Trigger, + TriggerCompletedEventFilter, + TriggerCompletedOutcomeType, TriggerEvent, TriggerEventFilter, TriggerFilter, TriggerId, TriggerNumberOfExecutionsChanged, - TriggerCompletedEventFilter, - TriggerCompletedOutcomeType, TriggeringFilterBox, UnregisterBox, UpgradableBox, @@ -370,15 +376,9 @@ types!( Vec, Vec, Vec, + Vec, Vec, - Vec, Vec, - VersionedBatchedResponse, - VersionedBatchedResponse>, - VersionedSignedBlock, - VersionedSignedBlockWrapper, - VersionedSignedQuery, - VersionedSignedTransaction, WasmExecutionFail, WasmSmartContract, Where, @@ -411,10 +411,10 @@ mod tests { block::{ error::BlockRejectionReason, stream::{BlockMessage, BlockSubscriptionRequest}, - BlockHeader, SignedBlock, VersionedSignedBlock, + BlockHeader, SignedBlock, SignedBlockV1, }, domain::NewDomain, - http::{BatchedResponse, VersionedBatchedResponse}, + http::{BatchedResponse, BatchedResponseV1}, ipfs::IpfsPath, predicate::{ ip_addr::{Ipv4Predicate, Ipv6Predicate}, @@ -428,9 +428,9 @@ mod tests { error::{FindError, QueryExecutionFail}, ForwardCursor, }, - transaction::{error::TransactionLimitError, SignedTransaction, TransactionLimits}, + transaction::{error::TransactionLimitError, SignedTransactionV1, TransactionLimits}, validator::Validator, - VersionedSignedBlockWrapper, + SignedBlockWrapper, }; use iroha_genesis::RawGenesisBlock; use iroha_primitives::{ @@ -567,6 +567,6 @@ mod tests { fn no_schema_type_overlap() { let mut schemas = super::build_schemas(); >::update_schema_map(&mut schemas); - >::update_schema_map(&mut schemas); + >::update_schema_map(&mut schemas); } } diff --git a/tools/kura_inspector/src/main.rs b/tools/kura_inspector/src/main.rs index 8f0fda6a01a..9d705b401b4 100644 --- a/tools/kura_inspector/src/main.rs +++ b/tools/kura_inspector/src/main.rs @@ -8,7 +8,7 @@ use std::path::{Path, PathBuf}; use clap::{Parser, Subcommand}; use iroha_core::kura::{BlockIndex, BlockStore, LockStatus}; -use iroha_data_model::block::VersionedSignedBlock; +use iroha_data_model::block::SignedBlock; use iroha_version::scale::DecodeVersioned; /// Kura inspector @@ -136,7 +136,7 @@ fn print_blockchain(block_store_path: &Path, from_height: u64, block_count: u64) block_store .read_block_data(idx.start, &mut block_buf) .expect(&format!("Failed to read block № {} data.", meta_index + 1)); - let block = VersionedSignedBlock::decode_all_versioned(&block_buf) + let block = SignedBlock::decode_all_versioned(&block_buf) .expect(&format!("Failed to decode block № {}", meta_index + 1)); println!("Block#{} :", meta_index + 1); println!("{block:#?}"); diff --git a/tools/parity_scale_decoder/src/main.rs b/tools/parity_scale_decoder/src/main.rs index 7f432285715..b7271a64946 100644 --- a/tools/parity_scale_decoder/src/main.rs +++ b/tools/parity_scale_decoder/src/main.rs @@ -25,10 +25,10 @@ use iroha_data_model::{ block::{ error::BlockRejectionReason, stream::{BlockMessage, BlockSubscriptionRequest}, - BlockHeader, SignedBlock, VersionedSignedBlock, + BlockHeader, SignedBlock, SignedBlockV1, }, domain::NewDomain, - http::{BatchedResponse, VersionedBatchedResponse}, + http::{BatchedResponse, BatchedResponseV1}, ipfs::IpfsPath, predicate::{ ip_addr::{Ipv4Predicate, Ipv6Predicate}, @@ -42,9 +42,9 @@ use iroha_data_model::{ error::{FindError, QueryExecutionFail}, ForwardCursor, }, - transaction::{error::TransactionLimitError, SignedTransaction, TransactionLimits}, + transaction::{error::TransactionLimitError, SignedTransactionV1, TransactionLimits}, validator::Validator, - VersionedSignedBlockWrapper, + SignedBlockWrapper, }; use iroha_primitives::{ addr::{Ipv4Addr, Ipv6Addr}, diff --git a/wasm/validator/derive/src/lib.rs b/wasm/validator/derive/src/lib.rs index 1d8c98f81df..8a789a78ee3 100644 --- a/wasm/validator/derive/src/lib.rs +++ b/wasm/validator/derive/src/lib.rs @@ -28,7 +28,7 @@ mod validate; /// #[entrypoint] /// pub fn validate_transaction( /// authority: AccountId, -/// transaction: VersionedSignedTransaction, +/// transaction: SignedTransaction, /// block_height: u64, /// ) -> Result { /// todo!() diff --git a/wasm/validator/src/default.rs b/wasm/validator/src/default.rs index 364fc1b72c9..aadac443213 100644 --- a/wasm/validator/src/default.rs +++ b/wasm/validator/src/default.rs @@ -93,7 +93,7 @@ pub fn default_permission_token_schema() -> PermissionTokenSchema { schema } -/// Default validation for [`VersionedSignedTransaction`]. +/// Default validation for [`SignedTransaction`]. /// /// # Warning /// @@ -102,7 +102,7 @@ pub fn default_permission_token_schema() -> PermissionTokenSchema { pub fn visit_transaction( validator: &mut V, authority: &AccountId, - transaction: &VersionedSignedTransaction, + transaction: &SignedTransaction, ) { match transaction.payload().instructions() { Executable::Wasm(wasm) => validator.visit_wasm(authority, wasm), From 9aa90bf410cd5ed2c50540d2839dd8182528ac0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Mon, 2 Oct 2023 14:17:24 +0200 Subject: [PATCH 30/55] [refactor]: Rename ISI from *Box to *Expr (#3930) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- CONTRIBUTING.md | 2 +- cli/src/torii/mod.rs | 2 +- client/benches/torii.rs | 16 +- client/benches/tps/utils.rs | 24 +- client/examples/million_accounts_genesis.rs | 4 +- client/examples/tutorial.rs | 34 +- client/src/client.rs | 2 +- client/tests/integration/add_account.rs | 4 +- client/tests/integration/add_domain.rs | 4 +- client/tests/integration/asset.rs | 65 ++-- client/tests/integration/asset_propagation.rs | 8 +- client/tests/integration/burn_public_keys.rs | 6 +- client/tests/integration/connected_peers.rs | 4 +- client/tests/integration/events/data.rs | 22 +- .../tests/integration/events/notification.rs | 16 +- client/tests/integration/events/pipeline.rs | 6 +- .../integration/multiple_blocks_created.rs | 8 +- .../integration/multisignature_account.rs | 8 +- .../integration/multisignature_transaction.rs | 8 +- client/tests/integration/non_mintable.rs | 20 +- client/tests/integration/pagination.rs | 4 +- client/tests/integration/permissions.rs | 40 +-- client/tests/integration/queries/account.rs | 6 +- client/tests/integration/queries/asset.rs | 24 +- client/tests/integration/queries/role.rs | 10 +- client/tests/integration/restart_peer.rs | 4 +- client/tests/integration/roles.rs | 22 +- client/tests/integration/set_parameter.rs | 6 +- .../src/lib.rs | 4 +- .../mint_rose_trigger/src/lib.rs | 2 +- .../validator_with_admin/src/lib.rs | 30 +- .../validator_with_custom_token/src/lib.rs | 34 +- .../validator_with_migration_fail/src/lib.rs | 32 +- client/tests/integration/sorting.rs | 18 +- client/tests/integration/transfer_asset.rs | 10 +- .../integration/triggers/by_call_trigger.rs | 64 ++-- .../integration/triggers/data_trigger.rs | 26 +- .../integration/triggers/event_trigger.rs | 6 +- .../integration/triggers/time_trigger.rs | 20 +- client/tests/integration/tx_history.rs | 8 +- client/tests/integration/tx_rollback.rs | 6 +- client/tests/integration/unregister_peer.rs | 12 +- client/tests/integration/unstable_network.rs | 4 +- client/tests/integration/upgrade.rs | 9 +- client_cli/src/main.rs | 22 +- core/benches/blocks/common.rs | 46 +-- core/benches/blocks/validate_blocks.rs | 4 +- core/benches/kura.rs | 2 +- core/benches/validation.rs | 8 +- core/src/block.rs | 20 +- core/src/queue.rs | 6 +- core/src/smartcontracts/isi/account.rs | 29 +- core/src/smartcontracts/isi/asset.rs | 23 +- core/src/smartcontracts/isi/mod.rs | 130 ++++---- core/src/smartcontracts/isi/query.rs | 8 +- core/src/smartcontracts/isi/triggers/mod.rs | 6 +- core/src/smartcontracts/isi/triggers/set.rs | 2 +- core/src/smartcontracts/isi/world.rs | 2 +- core/src/smartcontracts/wasm.rs | 30 +- core/src/sumeragi/main_loop.rs | 6 +- core/src/tx.rs | 22 +- core/src/validator.rs | 6 +- core/src/wsv.rs | 4 +- core/test_network/src/lib.rs | 8 +- data_model/src/isi.rs | 291 +++++++++--------- data_model/src/lib.rs | 50 +-- data_model/src/query/mod.rs | 4 +- data_model/src/transaction.rs | 12 +- data_model/src/trigger.rs | 6 +- data_model/src/validator.rs | 2 +- data_model/src/visit.rs | 204 ++++++------ data_model/src/wasm.rs | 2 +- data_model/tests/data_model.rs | 12 +- default_validator/src/lib.rs | 30 +- docs/source/references/schema.json | 276 ++++++++--------- genesis/src/lib.rs | 30 +- schema/gen/src/lib.rs | 40 +-- tools/kagami/src/genesis.rs | 12 +- tools/parity_scale_decoder/src/main.rs | 2 +- wasm/src/lib.rs | 14 +- wasm/validator/derive/src/lib.rs | 2 +- wasm/validator/src/default.rs | 52 ++-- 82 files changed, 1040 insertions(+), 1049 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 907b4bf321e..2fc9c77a9be 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -304,7 +304,7 @@ Code guidelines: - Avoid `Box` if possible (we prefer strong typing). - If your function is a getter/setter, mark it `#[inline]`. - If your function is a constructor (i.e., it's creating a new value from the input parameters and calls `default()`), mark it `#[inline]`. -- Avoid tying your code to concrete data structures; `rustc` is smart enough to turn a `Vec` into `impl IntoIterator` and vice versa when it needs to. +- Avoid tying your code to concrete data structures; `rustc` is smart enough to turn a `Vec` into `impl IntoIterator` and vice versa when it needs to. Naming guidelines: - Use only full words in *public* structure, variable, method, trait, constant, and module names. However, abbreviations are allowed if: diff --git a/cli/src/torii/mod.rs b/cli/src/torii/mod.rs index be3dce65184..5a2dc45bb9d 100644 --- a/cli/src/torii/mod.rs +++ b/cli/src/torii/mod.rs @@ -123,7 +123,7 @@ fn query_status_code(validation_error: &iroha_data_model::ValidationFail) -> Sta QueryFailed(query_error) | InstructionFailed(InstructionExecutionError::Query(query_error)) => match query_error { Evaluate(_) | Conversion(_) => StatusCode::BAD_REQUEST, - Signature(_) | Unauthorized => StatusCode::UNAUTHORIZED, + Signature(_) => StatusCode::UNAUTHORIZED, Find(_) => StatusCode::NOT_FOUND, }, TooComplex => StatusCode::UNPROCESSABLE_ENTITY, diff --git a/client/benches/torii.rs b/client/benches/torii.rs index 7327672d96c..c4674134bc7 100644 --- a/client/benches/torii.rs +++ b/client/benches/torii.rs @@ -49,16 +49,16 @@ fn query_requests(criterion: &mut Criterion) { .expect("Should not fail"); let mut group = criterion.benchmark_group("query-requests"); let domain_id: DomainId = "domain".parse().expect("Valid"); - let create_domain = RegisterBox::new(Domain::new(domain_id.clone())); + let create_domain = RegisterExpr::new(Domain::new(domain_id.clone())); let account_id = AccountId::new("account".parse().expect("Valid"), domain_id.clone()); let (public_key, _) = KeyPair::generate() .expect("Failed to generate KeyPair") .into(); - let create_account = RegisterBox::new(Account::new(account_id.clone(), [public_key])); + let create_account = RegisterExpr::new(Account::new(account_id.clone(), [public_key])); let asset_definition_id = AssetDefinitionId::new("xor".parse().expect("Valid"), domain_id); - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); let quantity: u32 = 200; - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new(asset_definition_id, account_id.clone())), ); @@ -69,7 +69,7 @@ fn query_requests(criterion: &mut Criterion) { let iroha_client = Client::new(&client_config).expect("Invalid client configuration"); thread::sleep(std::time::Duration::from_millis(5000)); - let instructions: [InstructionBox; 4] = [ + let instructions: [InstructionExpr; 4] = [ create_domain.into(), create_account.into(), create_asset.into(), @@ -137,12 +137,12 @@ fn instruction_submits(criterion: &mut Criterion) { rt.block_on(builder.start_with_peer(&mut peer)); let mut group = criterion.benchmark_group("instruction-requests"); let domain_id: DomainId = "domain".parse().expect("Valid"); - let create_domain = RegisterBox::new(Domain::new(domain_id.clone())); + let create_domain = RegisterExpr::new(Domain::new(domain_id.clone())); let account_id = AccountId::new("account".parse().expect("Valid"), domain_id.clone()); let (public_key, _) = KeyPair::generate() .expect("Failed to generate Key-pair.") .into(); - let create_account = RegisterBox::new(Account::new(account_id.clone(), [public_key])); + let create_account = RegisterExpr::new(Account::new(account_id.clone(), [public_key])); let asset_definition_id = AssetDefinitionId::new("xor".parse().expect("Valid"), domain_id); let mut client_config = iroha_client::samples::get_client_config(&get_key_pair()); client_config.torii_api_url = format!("http://{}", peer.api_address).parse().unwrap(); @@ -157,7 +157,7 @@ fn instruction_submits(criterion: &mut Criterion) { let _dropable = group.bench_function("instructions", |b| { b.iter(|| { let quantity: u32 = 200; - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), diff --git a/client/benches/tps/utils.rs b/client/benches/tps/utils.rs index 66f8bb01599..b14a9509015 100644 --- a/client/benches/tps/utils.rs +++ b/client/benches/tps/utils.rs @@ -177,7 +177,7 @@ impl MeasurerUnit { let alice_id = AccountId::from_str("alice@wonderland")?; let asset_id = asset_id(self.name); - let register_me = RegisterBox::new(Account::new( + let register_me = RegisterExpr::new(Account::new( account_id.clone(), [keypair.public_key().clone()], )); @@ -187,12 +187,12 @@ impl MeasurerUnit { "CanBurnUserAsset".parse().unwrap(), &json!({ "asset_id": asset_id }), ); - let allow_alice_to_burn_my_asset = GrantBox::new(can_burn_my_asset, alice_id.clone()); + let allow_alice_to_burn_my_asset = GrantExpr::new(can_burn_my_asset, alice_id.clone()); let can_transfer_my_asset = PermissionToken::new( "CanTransferUserAsset".parse().unwrap(), &json!({ "asset_id": asset_id }), ); - let allow_alice_to_transfer_my_asset = GrantBox::new(can_transfer_my_asset, alice_id); + let allow_alice_to_transfer_my_asset = GrantExpr::new(can_transfer_my_asset, alice_id); let grant_tx = TransactionBuilder::new(account_id) .with_instructions([ allow_alice_to_burn_my_asset, @@ -201,7 +201,7 @@ impl MeasurerUnit { .sign(keypair)?; self.client.submit_transaction_blocking(&grant_tx)?; - let mint_a_rose = MintBox::new(1_u32, asset_id); + let mint_a_rose = MintExpr::new(1_u32, asset_id); self.client.submit_blocking(mint_a_rose)?; Ok(self) @@ -274,26 +274,26 @@ impl MeasurerUnit { } #[allow(clippy::expect_used)] - fn instructions(&self) -> impl Iterator { + fn instructions(&self) -> impl Iterator { [self.mint_or_burn(), self.relay_a_rose()] .into_iter() .cycle() } - fn mint_or_burn(&self) -> InstructionBox { + fn mint_or_burn(&self) -> InstructionExpr { let is_running_out = Less::new( EvaluatesTo::new_unchecked(Expression::Query( FindAssetQuantityById::new(asset_id(self.name)).into(), )), 100_u32, ); - let supply_roses = MintBox::new(100_u32.to_value(), asset_id(self.name)); - let burn_a_rose = BurnBox::new(1_u32.to_value(), asset_id(self.name)); + let supply_roses = MintExpr::new(100_u32.to_value(), asset_id(self.name)); + let burn_a_rose = BurnExpr::new(1_u32.to_value(), asset_id(self.name)); - Conditional::with_otherwise(is_running_out, supply_roses, burn_a_rose).into() + ConditionalExpr::with_otherwise(is_running_out, supply_roses, burn_a_rose).into() } - fn relay_a_rose(&self) -> InstructionBox { + fn relay_a_rose(&self) -> InstructionExpr { // Save at least one rose // because if asset value hits 0 it's automatically deleted from account // and query `FindAssetQuantityById` return error @@ -303,13 +303,13 @@ impl MeasurerUnit { )), 1_u32, ); - let transfer_rose = TransferBox::new( + let transfer_rose = TransferExpr::new( asset_id(self.name), 1_u32.to_value(), account_id(self.next_name), ); - Conditional::new(enough_to_transfer, transfer_rose).into() + ConditionalExpr::new(enough_to_transfer, transfer_rose).into() } } diff --git a/client/examples/million_accounts_genesis.rs b/client/examples/million_accounts_genesis.rs index a04e8a4d108..1ee815fd1de 100644 --- a/client/examples/million_accounts_genesis.rs +++ b/client/examples/million_accounts_genesis.rs @@ -67,8 +67,8 @@ fn create_million_accounts_directly() { format!("bob-{i}").parse().expect("Valid"), domain_id.clone(), ); - let create_domain = RegisterBox::new(Domain::new(domain_id)); - let create_account = RegisterBox::new(Account::new(normal_account_id.clone(), [])); + let create_domain = RegisterExpr::new(Domain::new(domain_id)); + let create_account = RegisterExpr::new(Account::new(normal_account_id.clone(), [])); if test_client .submit_all([create_domain, create_account]) .is_err() diff --git a/client/examples/tutorial.rs b/client/examples/tutorial.rs index b18c9c424ce..5d8ec417b6f 100644 --- a/client/examples/tutorial.rs +++ b/client/examples/tutorial.rs @@ -52,7 +52,7 @@ fn domain_registration_test(config: &Configuration) -> Result<(), Error> { use iroha_client::client::Client; use iroha_data_model::{ metadata::UnlimitedMetadata, - prelude::{Domain, DomainId, InstructionBox, RegisterBox}, + prelude::{Domain, DomainId, InstructionExpr, RegisterExpr}, }; // #endregion domain_register_example_crates @@ -63,7 +63,7 @@ fn domain_registration_test(config: &Configuration) -> Result<(), Error> { // #region domain_register_example_create_isi // Create an ISI - let create_looking_glass = RegisterBox::new(Domain::new(looking_glass)); + let create_looking_glass = RegisterExpr::new(Domain::new(looking_glass)); // #endregion domain_register_example_create_isi // #region rust_client_create @@ -74,7 +74,7 @@ fn domain_registration_test(config: &Configuration) -> Result<(), Error> { // #region domain_register_example_prepare_tx // Prepare a transaction let metadata = UnlimitedMetadata::default(); - let instructions: Vec = vec![create_looking_glass.into()]; + let instructions: Vec = vec![create_looking_glass.into()]; let tx = iroha_client .build_transaction(instructions, metadata) .wrap_err("Error building a domain registration transaction")?; @@ -117,7 +117,7 @@ fn account_registration_test(config: &Configuration) -> Result<(), Error> { use iroha_crypto::KeyPair; use iroha_data_model::{ metadata::UnlimitedMetadata, - prelude::{Account, AccountId, InstructionBox, RegisterBox}, + prelude::{Account, AccountId, InstructionExpr, RegisterExpr}, }; // #endregion register_account_crates @@ -139,14 +139,14 @@ fn account_registration_test(config: &Configuration) -> Result<(), Error> { // #region register_account_generate // Generate a new account - let create_account = RegisterBox::new(Account::new(account_id, [public_key])); + let create_account = RegisterExpr::new(Account::new(account_id, [public_key])); // #endregion register_account_generate // #region register_account_prepare_tx // Prepare a transaction using the - // Account's RegisterBox + // Account's RegisterExpr let metadata = UnlimitedMetadata::new(); - let instructions: Vec = vec![create_account.into()]; + let instructions: Vec = vec![create_account.into()]; let tx = iroha_client.build_transaction(instructions, metadata)?; // #endregion register_account_prepare_tx @@ -165,7 +165,7 @@ fn asset_registration_test(config: &Configuration) -> Result<(), Error> { use iroha_client::client::Client; use iroha_data_model::prelude::{ - AccountId, AssetDefinition, AssetDefinitionId, AssetId, IdBox, MintBox, RegisterBox, + AccountId, AssetDefinition, AssetDefinitionId, AssetId, IdBox, MintExpr, RegisterExpr, }; // #endregion register_asset_crates @@ -181,7 +181,7 @@ fn asset_registration_test(config: &Configuration) -> Result<(), Error> { // #region register_asset_init_submit // Initialise the registration time let register_time = - RegisterBox::new(AssetDefinition::fixed(asset_def_id.clone()).mintable_once()); + RegisterExpr::new(AssetDefinition::fixed(asset_def_id.clone()).mintable_once()); // Submit a registration time iroha_client.submit(register_time)?; @@ -193,8 +193,8 @@ fn asset_registration_test(config: &Configuration) -> Result<(), Error> { .expect("Valid, because the string contains no whitespace, has a single '@' character and is not empty after"); // #region register_asset_mint_submit - // Create a MintBox using a previous asset and account - let mint = MintBox::new( + // Create a MintExpr using a previous asset and account + let mint = MintExpr::new( 12.34_f64.try_to_value()?, IdBox::AssetId(AssetId::new(asset_def_id, account_id)), ); @@ -213,7 +213,7 @@ fn asset_minting_test(config: &Configuration) -> Result<(), Error> { use iroha_client::client::Client; use iroha_data_model::{ - prelude::{AccountId, AssetDefinitionId, AssetId, MintBox, ToValue}, + prelude::{AccountId, AssetDefinitionId, AssetId, MintExpr, ToValue}, IdBox, }; // #endregion mint_asset_crates @@ -231,7 +231,7 @@ fn asset_minting_test(config: &Configuration) -> Result<(), Error> { // Mint the Asset instance // #region mint_asset_mint - let mint_roses = MintBox::new( + let mint_roses = MintExpr::new( 42_u32.to_value(), IdBox::AssetId(AssetId::new(roses, alice)), ); @@ -249,7 +249,7 @@ fn asset_minting_test(config: &Configuration) -> Result<(), Error> { // or `roses.to_string() + "#" + alice.to_string()`. // The `##` is a short-hand for the rose `which belongs to the same domain as the account // to which it belongs to. - let mint_roses_alt = MintBox::new( + let mint_roses_alt = MintExpr::new( 10_u32.to_value(), IdBox::AssetId("rose##alice@wonderland".parse()?), ); @@ -271,7 +271,7 @@ fn asset_burning_test(config: &Configuration) -> Result<(), Error> { use iroha_client::client::Client; use iroha_data_model::{ - prelude::{AccountId, AssetDefinitionId, AssetId, BurnBox, ToValue}, + prelude::{AccountId, AssetDefinitionId, AssetId, BurnExpr, ToValue}, IdBox, }; // #endregion burn_asset_crates @@ -289,7 +289,7 @@ fn asset_burning_test(config: &Configuration) -> Result<(), Error> { // #region burn_asset_burn // Burn the Asset instance - let burn_roses = BurnBox::new( + let burn_roses = BurnExpr::new( 10_u32.to_value(), IdBox::AssetId(AssetId::new(roses, alice)), ); @@ -307,7 +307,7 @@ fn asset_burning_test(config: &Configuration) -> Result<(), Error> { // or `roses.to_string() + "#" + alice.to_string()`. // The `##` is a short-hand for the rose `which belongs to the same domain as the account // to which it belongs to. - let burn_roses_alt = BurnBox::new( + let burn_roses_alt = BurnExpr::new( 10_u32.to_value(), IdBox::AssetId("rose##alice@wonderland".parse()?), ); diff --git a/client/src/client.rs b/client/src/client.rs index 852fc67117c..ee61666141c 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -1775,7 +1775,7 @@ mod tests { let build_transaction = || { client - .build_transaction(Vec::::new(), UnlimitedMetadata::new()) + .build_transaction(Vec::::new(), UnlimitedMetadata::new()) .unwrap() }; let tx1 = build_transaction(); diff --git a/client/tests/integration/add_account.rs b/client/tests/integration/add_account.rs index d40fa4d6304..5b14d2895be 100644 --- a/client/tests/integration/add_account.rs +++ b/client/tests/integration/add_account.rs @@ -16,14 +16,14 @@ fn client_add_account_with_name_length_more_than_limit_should_not_commit_transac let pipeline_time = super::Configuration::pipeline_time(); let normal_account_id: AccountId = "bob@wonderland".parse().expect("Valid"); - let create_account = RegisterBox::new(Account::new(normal_account_id.clone(), [])); + let create_account = RegisterExpr::new(Account::new(normal_account_id.clone(), [])); test_client.submit(create_account)?; let too_long_account_name = "0".repeat(2_usize.pow(14)); let incorrect_account_id: AccountId = (too_long_account_name + "@wonderland") .parse() .expect("Valid"); - let create_account = RegisterBox::new(Account::new(incorrect_account_id.clone(), [])); + let create_account = RegisterExpr::new(Account::new(incorrect_account_id.clone(), [])); test_client.submit(create_account)?; thread::sleep(pipeline_time * 2); diff --git a/client/tests/integration/add_domain.rs b/client/tests/integration/add_domain.rs index b17acf319db..98633857e57 100644 --- a/client/tests/integration/add_domain.rs +++ b/client/tests/integration/add_domain.rs @@ -19,11 +19,11 @@ fn client_add_domain_with_name_length_more_than_limit_should_not_commit_transact // Given let normal_domain_id: DomainId = "sora".parse()?; - let create_domain = RegisterBox::new(Domain::new(normal_domain_id.clone())); + let create_domain = RegisterExpr::new(Domain::new(normal_domain_id.clone())); test_client.submit(create_domain)?; let too_long_domain_name: DomainId = "0".repeat(2_usize.pow(14)).parse()?; - let create_domain = RegisterBox::new(Domain::new(too_long_domain_name.clone())); + let create_domain = RegisterExpr::new(Domain::new(too_long_domain_name.clone())); test_client.submit(create_domain)?; thread::sleep(pipeline_time * 2); diff --git a/client/tests/integration/asset.rs b/client/tests/integration/asset.rs index 56f363dfbb6..81ebfb7c17f 100644 --- a/client/tests/integration/asset.rs +++ b/client/tests/integration/asset.rs @@ -21,8 +21,8 @@ fn client_register_asset_should_add_asset_once_but_not_twice() -> Result<()> { let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("test_asset#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); - let register_asset = RegisterBox::new(Asset::new( + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); + let register_asset = RegisterExpr::new(Asset::new( AssetId::new(asset_definition_id.clone(), account_id.clone()), AssetValue::Quantity(0), )); @@ -56,9 +56,9 @@ fn unregister_asset_should_remove_asset_from_account() -> Result<()> { let asset_definition_id = AssetDefinitionId::from_str("test_asset#wonderland").expect("Valid"); let asset_id = AssetId::new(asset_definition_id.clone(), account_id.clone()); - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); - let register_asset = RegisterBox::new(Asset::new(asset_id.clone(), AssetValue::Quantity(0))); - let unregister_asset = UnregisterBox::new(asset_id); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); + let register_asset = RegisterExpr::new(Asset::new(asset_id.clone(), AssetValue::Quantity(0))); + let unregister_asset = UnregisterExpr::new(asset_id); test_client.submit_all([create_asset, register_asset])?; @@ -93,18 +93,18 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount() -> // Given let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); let metadata = iroha_data_model::metadata::UnlimitedMetadata::default(); //When let quantity: u32 = 200; - let mint = MintBox::new( + let mint = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), account_id.clone(), )), ); - let instructions: [InstructionBox; 2] = [create_asset.into(), mint.into()]; + let instructions: [InstructionExpr; 2] = [create_asset.into(), mint.into()]; let tx = test_client.build_transaction(instructions, metadata)?; test_client.submit_transaction(&tx)?; test_client.poll_request(client::asset::by_account_id(account_id), |result| { @@ -126,18 +126,19 @@ fn client_add_big_asset_quantity_to_existing_asset_should_increase_asset_amount( // Given let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::big_quantity(asset_definition_id.clone())); + let create_asset = + RegisterExpr::new(AssetDefinition::big_quantity(asset_definition_id.clone())); let metadata = iroha_data_model::metadata::UnlimitedMetadata::default(); //When let quantity: u128 = 2_u128.pow(65); - let mint = MintBox::new( + let mint = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), account_id.clone(), )), ); - let instructions: [InstructionBox; 2] = [create_asset.into(), mint.into()]; + let instructions: [InstructionExpr; 2] = [create_asset.into(), mint.into()]; let tx = test_client.build_transaction(instructions, metadata)?; test_client.submit_transaction(&tx)?; test_client.poll_request(client::asset::by_account_id(account_id), |result| { @@ -160,19 +161,19 @@ fn client_add_asset_with_decimal_should_increase_asset_amount() -> Result<()> { let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let identifiable_box = AssetDefinition::fixed(asset_definition_id.clone()); - let create_asset = RegisterBox::new(identifiable_box); + let create_asset = RegisterExpr::new(identifiable_box); let metadata = iroha_data_model::metadata::UnlimitedMetadata::default(); //When let quantity: Fixed = Fixed::try_from(123.456_f64).unwrap(); - let mint = MintBox::new( + let mint = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), account_id.clone(), )), ); - let instructions: [InstructionBox; 2] = [create_asset.into(), mint.into()]; + let instructions: [InstructionExpr; 2] = [create_asset.into(), mint.into()]; let tx = test_client.build_transaction(instructions, metadata)?; test_client.submit_transaction(&tx)?; test_client.poll_request(client::asset::by_account_id(account_id.clone()), |result| { @@ -186,7 +187,7 @@ fn client_add_asset_with_decimal_should_increase_asset_amount() -> Result<()> { // Add some fractional part let quantity2: Fixed = Fixed::try_from(0.55_f64).unwrap(); - let mint = MintBox::new( + let mint = MintExpr::new( quantity2.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), @@ -216,7 +217,7 @@ fn client_add_asset_with_name_length_more_than_limit_should_not_commit_transacti // Given let normal_asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::quantity( + let create_asset = RegisterExpr::new(AssetDefinition::quantity( normal_asset_definition_id.clone(), )); test_client.submit(create_asset)?; @@ -225,7 +226,7 @@ fn client_add_asset_with_name_length_more_than_limit_should_not_commit_transacti let too_long_asset_name = "0".repeat(2_usize.pow(14)); let incorrect_asset_definition_id = AssetDefinitionId::from_str(&(too_long_asset_name + "#wonderland")).expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::quantity( + let create_asset = RegisterExpr::new(AssetDefinition::quantity( incorrect_asset_definition_id.clone(), )); @@ -272,11 +273,11 @@ fn find_rate_and_make_exchange_isi_should_succeed() { let buyer_keypair = KeyPair::generate().expect("Failed to generate seller KeyPair."); let register_account = |account_id: AccountId, signature: PublicKey| { - RegisterBox::new(Account::new(account_id, [signature])) + RegisterExpr::new(Account::new(account_id, [signature])) }; let grant_alice_asset_transfer_permission = |asset_id: AssetId, owner_keypair: KeyPair| { - let allow_alice_to_transfer_asset = GrantBox::new( + let allow_alice_to_transfer_asset = GrantExpr::new( PermissionToken::new( "CanTransferUserAsset".parse().unwrap(), &json!({ "asset_id": asset_id }), @@ -303,7 +304,7 @@ fn find_rate_and_make_exchange_isi_should_succeed() { "exchange", account_id_new("dex", "exchange"), ); - let instructions: [InstructionBox; 12] = [ + let instructions: [InstructionExpr; 12] = [ register::domain("exchange").into(), register::domain("company").into(), register::domain("crypto").into(), @@ -313,17 +314,17 @@ fn find_rate_and_make_exchange_isi_should_succeed() { register::asset_definition("btc", "crypto").into(), register::asset_definition("eth", "crypto").into(), register::asset_definition("btc2eth_rate", "exchange").into(), - MintBox::new( + MintExpr::new( 200_u32.to_value(), IdBox::AssetId(asset_id_new("eth", "crypto", buyer_account_id.clone())), ) .into(), - MintBox::new( + MintExpr::new( 20_u32.to_value(), IdBox::AssetId(asset_id_new("btc", "crypto", seller_account_id.clone())), ) .into(), - MintBox::new(20_u32.to_value(), IdBox::AssetId(asset_id.clone())).into(), + MintExpr::new(20_u32.to_value(), IdBox::AssetId(asset_id.clone())).into(), ]; test_client .submit_all_blocking(instructions) @@ -333,15 +334,15 @@ fn find_rate_and_make_exchange_isi_should_succeed() { grant_alice_asset_transfer_permission(buyer_eth, buyer_keypair); test_client - .submit_all_blocking([Pair::new( - TransferBox::new( + .submit_all_blocking([PairExpr::new( + TransferExpr::new( IdBox::AssetId(asset_id_new("btc", "crypto", seller_account_id.clone())), EvaluatesTo::new_evaluates_to_value(Expression::Query( FindAssetQuantityById::new(asset_id.clone()).into(), )), IdBox::AccountId(buyer_account_id.clone()), ), - TransferBox::new( + TransferExpr::new( IdBox::AssetId(asset_id_new("eth", "crypto", buyer_account_id)), EvaluatesTo::new_evaluates_to_value(Expression::Query( FindAssetQuantityById::new(asset_id).into(), @@ -412,12 +413,12 @@ fn asset_id_new(definition_name: &str, definition_domain: &str, account_id: Acco mod register { use super::*; - pub fn domain(name: &str) -> RegisterBox { - RegisterBox::new(Domain::new(DomainId::from_str(name).expect("Valid"))) + pub fn domain(name: &str) -> RegisterExpr { + RegisterExpr::new(Domain::new(DomainId::from_str(name).expect("Valid"))) } - pub fn account(account_name: &str, domain_name: &str) -> RegisterBox { - RegisterBox::new(Account::new( + pub fn account(account_name: &str, domain_name: &str) -> RegisterExpr { + RegisterExpr::new(Account::new( AccountId::new( account_name.parse().expect("Valid"), domain_name.parse().expect("Valid"), @@ -426,8 +427,8 @@ mod register { )) } - pub fn asset_definition(asset_name: &str, domain_name: &str) -> RegisterBox { - RegisterBox::new(AssetDefinition::quantity(AssetDefinitionId::new( + pub fn asset_definition(asset_name: &str, domain_name: &str) -> RegisterExpr { + RegisterExpr::new(AssetDefinition::quantity(AssetDefinitionId::new( asset_name.parse().expect("Valid"), domain_name.parse().expect("Valid"), ))) diff --git a/client/tests/integration/asset_propagation.rs b/client/tests/integration/asset_propagation.rs index ddd34ee81b3..22d86427629 100644 --- a/client/tests/integration/asset_propagation.rs +++ b/client/tests/integration/asset_propagation.rs @@ -27,17 +27,17 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount_on_a .into_set_parameters(), )?; - let create_domain = RegisterBox::new(Domain::new(DomainId::from_str("domain")?)); + let create_domain = RegisterExpr::new(Domain::new(DomainId::from_str("domain")?)); let account_id = AccountId::from_str("account@domain")?; let (public_key, _) = KeyPair::generate()?.into(); - let create_account = RegisterBox::new(Account::new(account_id.clone(), [public_key])); + let create_account = RegisterExpr::new(Account::new(account_id.clone(), [public_key])); let asset_definition_id = AssetDefinitionId::from_str("xor#domain")?; - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); client.submit_all([create_domain, create_account, create_asset])?; thread::sleep(pipeline_time * 3); //When let quantity: u32 = 200; - client.submit(MintBox::new( + client.submit(MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), diff --git a/client/tests/integration/burn_public_keys.rs b/client/tests/integration/burn_public_keys.rs index 014656cabac..970133a088a 100644 --- a/client/tests/integration/burn_public_keys.rs +++ b/client/tests/integration/burn_public_keys.rs @@ -51,7 +51,7 @@ fn public_keys_cannot_be_burned_to_nothing() { wait_for_genesis_committed(&vec![client.clone()], 0); let charlie_initial_keypair = KeyPair::generate().unwrap(); - let register_charlie = RegisterBox::new(Account::new( + let register_charlie = RegisterExpr::new(Account::new( charlie_id.clone(), [charlie_initial_keypair.public_key().clone()], )); @@ -64,7 +64,7 @@ fn public_keys_cannot_be_burned_to_nothing() { let mint_keys = (0..KEYS_COUNT - 1).map(|_| { let (public_key, _) = KeyPair::generate().unwrap().into(); - MintBox::new(public_key, charlie_id.clone()) + MintExpr::new(public_key, charlie_id.clone()) }); let (tx_hash, res) = submit( @@ -79,7 +79,7 @@ fn public_keys_cannot_be_burned_to_nothing() { let charlie = client.request(account::by_id(charlie_id.clone())).unwrap(); let mut keys = charlie.signatories(); - let burn = |key: PublicKey| InstructionBox::from(BurnBox::new(key, charlie_id.clone())); + let burn = |key: PublicKey| InstructionExpr::from(BurnExpr::new(key, charlie_id.clone())); let burn_keys_leaving_one = keys .by_ref() .filter(|pub_key| pub_key != &charlie_initial_keypair.public_key()) diff --git a/client/tests/integration/connected_peers.rs b/client/tests/integration/connected_peers.rs index 7977967113d..03ba2e995d3 100644 --- a/client/tests/integration/connected_peers.rs +++ b/client/tests/integration/connected_peers.rs @@ -53,7 +53,7 @@ fn connected_peers_with_f(faults: u64, start_port: Option) -> Result<()> { // then `status.peers` decrements let peer = network.peers.values().last().unwrap(); let peer_client = Client::test(&peer.api_address, &peer.telemetry_address); - let unregister_peer = UnregisterBox::new(IdBox::PeerId(peer.id.clone())); + let unregister_peer = UnregisterExpr::new(IdBox::PeerId(peer.id.clone())); client.submit_blocking(unregister_peer)?; thread::sleep(pipeline_time * 2); // Wait for some time to allow peers to connect status = client.get_status()?; @@ -64,7 +64,7 @@ fn connected_peers_with_f(faults: u64, start_port: Option) -> Result<()> { // Re-register the peer: committed with f = `faults` - 1 then // `status.peers` increments - let register_peer = RegisterBox::new(DataModelPeer::new(peer.id.clone())); + let register_peer = RegisterExpr::new(DataModelPeer::new(peer.id.clone())); client.submit_blocking(register_peer)?; thread::sleep(pipeline_time * 4); // Wait for some time to allow peers to connect status = client.get_status()?; diff --git a/client/tests/integration/events/data.rs b/client/tests/integration/events/data.rs index a9430daff13..03a0ecf96aa 100644 --- a/client/tests/integration/events/data.rs +++ b/client/tests/integration/events/data.rs @@ -9,14 +9,14 @@ use test_network::*; use crate::wasm::utils::wasm_template; -fn produce_instructions() -> Vec { +fn produce_instructions() -> Vec { let domains = (0..4) .map(|domain_index: usize| Domain::new(domain_index.to_string().parse().expect("Valid"))); - let registers: [InstructionBox; 4] = domains + let registers: [InstructionExpr; 4] = domains .into_iter() - .map(RegisterBox::new) - .map(InstructionBox::from) + .map(RegisterExpr::new) + .map(InstructionExpr::from) .collect::>() .try_into() .unwrap(); @@ -30,12 +30,12 @@ fn produce_instructions() -> Vec { // domain "2" // domain "3" registers[0].clone(), - Pair::new::( + PairExpr::new( registers[1].clone(), - Conditional::with_otherwise( + ConditionalExpr::with_otherwise( false, - FailBox::new("unreachable"), - SequenceBox::new([registers[2].clone(), registers[3].clone()]), + Fail::new("unreachable"), + SequenceExpr::new([registers[2].clone(), registers[3].clone()]), ), ) .into(), @@ -175,16 +175,16 @@ fn produce_multiple_events() -> Result<()> { let role = iroha_data_model::role::Role::new(role_id.clone()) .add_permission(token_1.clone()) .add_permission(token_2.clone()); - let instructions = [RegisterBox::new(role.clone())]; + let instructions = [RegisterExpr::new(role.clone())]; client.submit_all_blocking(instructions)?; // Grants role to Bob let bob_id = AccountId::from_str("bob@wonderland")?; - let grant_role = GrantBox::new(role_id.clone(), bob_id.clone()); + let grant_role = GrantExpr::new(role_id.clone(), bob_id.clone()); client.submit_blocking(grant_role)?; // Unregister role - let unregister_role = UnregisterBox::new(role_id.clone()); + let unregister_role = UnregisterExpr::new(role_id.clone()); client.submit_blocking(unregister_role)?; // Inspect produced events diff --git a/client/tests/integration/events/notification.rs b/client/tests/integration/events/notification.rs index 12858a02581..29d3ef58180 100644 --- a/client/tests/integration/events/notification.rs +++ b/client/tests/integration/events/notification.rs @@ -16,11 +16,11 @@ fn trigger_completion_success_should_produce_event() -> Result<()> { let asset_id = AssetId::new(asset_definition_id, account_id); let trigger_id = TriggerId::from_str("mint_rose")?; - let instruction = MintBox::new(1_u32, asset_id.clone()); - let register_trigger = RegisterBox::new(Trigger::new( + let instruction = MintExpr::new(1_u32, asset_id.clone()); + let register_trigger = RegisterExpr::new(Trigger::new( trigger_id.clone(), Action::new( - vec![InstructionBox::from(instruction)], + vec![InstructionExpr::from(instruction)], Repeats::Indefinitely, asset_id.account_id.clone(), TriggeringFilterBox::ExecuteTrigger(ExecuteTriggerEventFilter::new( @@ -31,7 +31,7 @@ fn trigger_completion_success_should_produce_event() -> Result<()> { )); test_client.submit_blocking(register_trigger)?; - let call_trigger = ExecuteTriggerBox::new(trigger_id.clone()); + let call_trigger = ExecuteTriggerExpr::new(trigger_id.clone()); let thread_client = test_client.clone(); let (sender, receiver) = mpsc::channel(); @@ -65,11 +65,11 @@ fn trigger_completion_failure_should_produce_event() -> Result<()> { let account_id: AccountId = "alice@wonderland".parse()?; let trigger_id = TriggerId::from_str("fail_box")?; - let instruction = FailBox::new("Fail box"); - let register_trigger = RegisterBox::new(Trigger::new( + let instruction = Fail::new("Fail box"); + let register_trigger = RegisterExpr::new(Trigger::new( trigger_id.clone(), Action::new( - vec![InstructionBox::from(instruction)], + vec![InstructionExpr::from(instruction)], Repeats::Indefinitely, account_id.clone(), TriggeringFilterBox::ExecuteTrigger(ExecuteTriggerEventFilter::new( @@ -80,7 +80,7 @@ fn trigger_completion_failure_should_produce_event() -> Result<()> { )); test_client.submit_blocking(register_trigger)?; - let call_trigger = ExecuteTriggerBox::new(trigger_id.clone()); + let call_trigger = ExecuteTriggerExpr::new(trigger_id.clone()); let thread_client = test_client.clone(); let (sender, receiver) = mpsc::channel(); diff --git a/client/tests/integration/events/pipeline.rs b/client/tests/integration/events/pipeline.rs index b359077c41f..d0759371ea4 100644 --- a/client/tests/integration/events/pipeline.rs +++ b/client/tests/integration/events/pipeline.rs @@ -26,7 +26,7 @@ fn transaction_with_no_instructions_should_be_committed() -> Result<()> { // #[ignore = "Experiment"] #[test] fn transaction_with_fail_instruction_should_be_rejected() -> Result<()> { - let fail = FailBox::new("Should be rejected"); + let fail = Fail::new("Should be rejected"); test_with_instruction_and_status_and_port( Some(fail.into()), PipelineStatusKind::Rejected, @@ -36,7 +36,7 @@ fn transaction_with_fail_instruction_should_be_rejected() -> Result<()> { #[allow(dead_code, clippy::needless_range_loop, clippy::needless_pass_by_value)] fn test_with_instruction_and_status_and_port( - instruction: Option, + instruction: Option, should_be: PipelineStatusKind, port: u16, ) -> Result<()> { @@ -112,7 +112,7 @@ fn committed_block_must_be_available_in_kura() { .expect("Failed to subscribe for events"); client - .submit(FailBox::new("Dummy instruction")) + .submit(Fail::new("Dummy instruction")) .expect("Failed to submit transaction"); let event = event_iter.next().expect("Block must be committed"); diff --git a/client/tests/integration/multiple_blocks_created.rs b/client/tests/integration/multiple_blocks_created.rs index 0cbb55fdffc..79abff38095 100644 --- a/client/tests/integration/multiple_blocks_created.rs +++ b/client/tests/integration/multiple_blocks_created.rs @@ -29,12 +29,12 @@ fn long_multiple_blocks_created() -> Result<()> { .into_set_parameters(), )?; - let create_domain = RegisterBox::new(Domain::new("domain".parse()?)); + let create_domain = RegisterExpr::new(Domain::new("domain".parse()?)); let account_id: AccountId = "account@domain".parse()?; let (public_key, _) = KeyPair::generate()?.into(); - let create_account = RegisterBox::new(Account::new(account_id.clone(), [public_key])); + let create_account = RegisterExpr::new(Account::new(account_id.clone(), [public_key])); let asset_definition_id: AssetDefinitionId = "xor#domain".parse()?; - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); client.submit_all([create_domain, create_account, create_asset])?; @@ -44,7 +44,7 @@ fn long_multiple_blocks_created() -> Result<()> { //When for _ in 0..N_BLOCKS { let quantity: u32 = 1; - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), diff --git a/client/tests/integration/multisignature_account.rs b/client/tests/integration/multisignature_account.rs index dd5f1454328..3e3e4bcaf41 100644 --- a/client/tests/integration/multisignature_account.rs +++ b/client/tests/integration/multisignature_account.rs @@ -19,19 +19,19 @@ fn transaction_signed_by_new_signatory_of_account_should_pass() -> Result<()> { // Given let account_id: AccountId = "alice@wonderland".parse().expect("Valid"); let asset_definition_id: AssetDefinitionId = "xor#wonderland".parse().expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); let key_pair = KeyPair::generate()?; - let add_signatory = MintBox::new( + let add_signatory = MintExpr::new( key_pair.public_key().clone(), IdBox::AccountId(account_id.clone()), ); - let instructions: [InstructionBox; 2] = [create_asset.into(), add_signatory.into()]; + let instructions: [InstructionExpr; 2] = [create_asset.into(), add_signatory.into()]; client.submit_all(instructions)?; thread::sleep(pipeline_time * 2); //When let quantity: u32 = 200; - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), diff --git a/client/tests/integration/multisignature_transaction.rs b/client/tests/integration/multisignature_transaction.rs index 2aba6abf4d7..ca061ccf50f 100644 --- a/client/tests/integration/multisignature_transaction.rs +++ b/client/tests/integration/multisignature_transaction.rs @@ -31,8 +31,8 @@ fn multisignature_transactions_should_wait_for_all_signatures() -> Result<()> { let alice_key_pair = get_key_pair(); let key_pair_2 = KeyPair::generate()?; let asset_definition_id = AssetDefinitionId::from_str("camomile#wonderland")?; - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); - let set_signature_condition = MintBox::new( + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); + let set_signature_condition = MintExpr::new( SignatureCheckCondition::AllAccountSignaturesAnd( vec![key_pair_2.public_key().clone()].into(), ), @@ -44,13 +44,13 @@ fn multisignature_transactions_should_wait_for_all_signatures() -> Result<()> { &network.genesis.telemetry_address, ); let client = Client::new(&client_configuration)?; - let instructions: [InstructionBox; 2] = [create_asset.into(), set_signature_condition.into()]; + let instructions: [InstructionExpr; 2] = [create_asset.into(), set_signature_condition.into()]; client.submit_all_blocking(instructions)?; //When let quantity: u32 = 200; let asset_id = AssetId::new(asset_definition_id, alice_id.clone()); - let mint_asset = MintBox::new(quantity.to_value(), IdBox::AssetId(asset_id.clone())); + let mint_asset = MintExpr::new(quantity.to_value(), IdBox::AssetId(asset_id.clone())); let (public_key1, private_key1) = alice_key_pair.into(); client_configuration.account_id = alice_id.clone(); diff --git a/client/tests/integration/non_mintable.rs b/client/tests/integration/non_mintable.rs index 636d05fd8e6..adec2a9dbc0 100644 --- a/client/tests/integration/non_mintable.rs +++ b/client/tests/integration/non_mintable.rs @@ -16,11 +16,11 @@ fn non_mintable_asset_can_be_minted_once_but_not_twice() -> Result<()> { let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let create_asset = - RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).mintable_once()); + RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone()).mintable_once()); let metadata = UnlimitedMetadata::default(); - let mint = MintBox::new( + let mint = MintExpr::new( 200_u32.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), @@ -28,7 +28,7 @@ fn non_mintable_asset_can_be_minted_once_but_not_twice() -> Result<()> { )), ); - let instructions: [InstructionBox; 2] = [create_asset.into(), mint.clone().into()]; + let instructions: [InstructionExpr; 2] = [create_asset.into(), mint.clone().into()]; let tx = test_client.build_transaction(instructions, metadata)?; // We can register and mint the non-mintable token @@ -66,10 +66,10 @@ fn non_mintable_asset_cannot_be_minted_if_registered_with_non_zero_value() -> Re let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let create_asset = - RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).mintable_once()); + RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone()).mintable_once()); let asset_id = AssetId::new(asset_definition_id.clone(), account_id.clone()); - let register_asset = RegisterBox::new(Asset::new(asset_id.clone(), 1_u32)); + let register_asset = RegisterExpr::new(Asset::new(asset_id.clone(), 1_u32)); // We can register the non-mintable token test_client.submit_all([create_asset, register_asset.clone()])?; @@ -85,7 +85,7 @@ fn non_mintable_asset_cannot_be_minted_if_registered_with_non_zero_value() -> Re assert!(test_client.submit_blocking(register_asset).is_err()); // And can't be minted - let mint = MintBox::new(1_u32.to_value(), IdBox::AssetId(asset_id)); + let mint = MintExpr::new(1_u32.to_value(), IdBox::AssetId(asset_id)); assert!(test_client.submit_blocking(mint).is_err()); Ok(()) @@ -100,14 +100,14 @@ fn non_mintable_asset_can_be_minted_if_registered_with_zero_value() -> Result<() let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let create_asset = - RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone()).mintable_once()); + RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone()).mintable_once()); let asset_id = AssetId::new(asset_definition_id.clone(), account_id.clone()); - let register_asset = RegisterBox::new(Asset::new(asset_id.clone(), 0_u32)); - let mint = MintBox::new(1_u32.to_value(), IdBox::AssetId(asset_id)); + let register_asset = RegisterExpr::new(Asset::new(asset_id.clone(), 0_u32)); + let mint = MintExpr::new(1_u32.to_value(), IdBox::AssetId(asset_id)); // We can register the non-mintable token wih zero value and then mint it - let instructions: [InstructionBox; 3] = + let instructions: [InstructionExpr; 3] = [create_asset.into(), register_asset.into(), mint.into()]; test_client.submit_all(instructions)?; test_client.poll_request(client::asset::by_account_id(account_id), |result| { diff --git a/client/tests/integration/pagination.rs b/client/tests/integration/pagination.rs index e50251eb980..1ec4992a035 100644 --- a/client/tests/integration/pagination.rs +++ b/client/tests/integration/pagination.rs @@ -12,11 +12,11 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount() -> let (_rt, _peer, client) = ::new().with_port(10_690).start_with_runtime(); wait_for_genesis_committed(&vec![client.clone()], 0); - let register: Vec = ('a'..='z') // This is a subtle mistake, I'm glad we can lint it now. + let register: Vec = ('a'..='z') // This is a subtle mistake, I'm glad we can lint it now. .map(|c| c.to_string()) .map(|name| (name + "#wonderland").parse().expect("Valid")) .map(|asset_definition_id| { - RegisterBox::new(AssetDefinition::quantity(asset_definition_id)).into() + RegisterExpr::new(AssetDefinition::quantity(asset_definition_id)).into() }) .collect(); client.submit_all_blocking(register)?; diff --git a/client/tests/integration/permissions.rs b/client/tests/integration/permissions.rs index ff4ee340b54..d19a4b709c1 100644 --- a/client/tests/integration/permissions.rs +++ b/client/tests/integration/permissions.rs @@ -18,7 +18,7 @@ fn genesis_transactions_are_validated() { let mut genesis = GenesisNetwork::test(true).expect("Expected genesis"); - let grant_invalid_token = GrantBox::new( + let grant_invalid_token = GrantExpr::new( PermissionToken::new("InvalidToken".parse().unwrap(), &json!(null)), AccountId::from_str("alice@wonderland").unwrap(), ); @@ -78,7 +78,7 @@ fn permissions_disallow_asset_transfer() { let bob_id: AccountId = "bob@wonderland".parse().expect("Valid"); let mouse_id: AccountId = "mouse@wonderland".parse().expect("Valid"); let asset_definition_id: AssetDefinitionId = "xor#wonderland".parse().expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); let mouse_keypair = iroha_crypto::KeyPair::generate().expect("Failed to generate KeyPair."); let alice_start_assets = get_assets(&iroha_client, &alice_id); @@ -87,7 +87,7 @@ fn permissions_disallow_asset_transfer() { .expect("Failed to prepare state."); let quantity: u32 = 200; - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new(asset_definition_id.clone(), bob_id.clone())), ); @@ -96,7 +96,7 @@ fn permissions_disallow_asset_transfer() { .expect("Failed to create asset."); //When - let transfer_asset = TransferBox::new( + let transfer_asset = TransferExpr::new( IdBox::AssetId(AssetId::new(asset_definition_id, bob_id)), quantity.to_value(), IdBox::AccountId(alice_id.clone()), @@ -131,7 +131,7 @@ fn permissions_disallow_asset_burn() { let bob_id: AccountId = "bob@wonderland".parse().expect("Valid"); let mouse_id: AccountId = "mouse@wonderland".parse().expect("Valid"); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); let mouse_keypair = iroha_crypto::KeyPair::generate().expect("Failed to generate KeyPair."); let alice_start_assets = get_assets(&iroha_client, &alice_id); @@ -141,14 +141,14 @@ fn permissions_disallow_asset_burn() { .expect("Failed to prepare state."); let quantity: u32 = 200; - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new(asset_definition_id.clone(), bob_id)), ); iroha_client .submit_blocking(mint_asset) .expect("Failed to create asset."); - let burn_asset = BurnBox::new( + let burn_asset = BurnExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new(asset_definition_id, mouse_id.clone())), ); @@ -184,7 +184,7 @@ fn account_can_query_only_its_own_domain() -> Result<()> { // Given let domain_id: DomainId = "wonderland".parse()?; let new_domain_id: DomainId = "wonderland2".parse()?; - let register_domain = RegisterBox::new(Domain::new(new_domain_id.clone())); + let register_domain = RegisterExpr::new(Domain::new(new_domain_id.clone())); client.submit_blocking(register_domain)?; @@ -213,20 +213,20 @@ fn permissions_differ_not_only_by_names() { let new_shoes_definition = AssetDefinition::store(shoes_definition_id.clone()); client .submit_all_blocking([ - RegisterBox::new(new_hat_definition), - RegisterBox::new(new_shoes_definition), + RegisterExpr::new(new_hat_definition), + RegisterExpr::new(new_shoes_definition), ]) .expect("Failed to register new asset definitions"); // Registering mouse let new_mouse_account = Account::new(mouse_id.clone(), [mouse_keypair.public_key().clone()]); client - .submit_blocking(RegisterBox::new(new_mouse_account)) + .submit_blocking(RegisterExpr::new(new_mouse_account)) .expect("Failed to register mouse"); // Granting permission to Alice to modify metadata in Mouse's hats let mouse_hat_id = AssetId::new(hat_definition_id, mouse_id.clone()); - let allow_alice_to_set_key_value_in_hats = GrantBox::new( + let allow_alice_to_set_key_value_in_hats = GrantExpr::new( PermissionToken::new( "CanSetKeyValueInUserAsset".parse().unwrap(), &json!({ "asset_id": mouse_hat_id }), @@ -244,7 +244,7 @@ fn permissions_differ_not_only_by_names() { // Checking that Alice can modify Mouse's hats ... client - .submit_blocking(SetKeyValueBox::new( + .submit_blocking(SetKeyValueExpr::new( mouse_hat_id, Name::from_str("color").expect("Valid"), "red".to_owned(), @@ -253,7 +253,7 @@ fn permissions_differ_not_only_by_names() { // ... but not shoes let mouse_shoes_id = AssetId::new(shoes_definition_id, mouse_id.clone()); - let set_shoes_color = SetKeyValueBox::new( + let set_shoes_color = SetKeyValueExpr::new( mouse_shoes_id.clone(), Name::from_str("color").expect("Valid"), "yellow".to_owned(), @@ -263,7 +263,7 @@ fn permissions_differ_not_only_by_names() { .expect_err("Expected Alice to fail to modify Mouse's shoes"); // Granting permission to Alice to modify metadata in Mouse's shoes - let allow_alice_to_set_key_value_in_shoes = GrantBox::new( + let allow_alice_to_set_key_value_in_shoes = GrantExpr::new( PermissionToken::new( "CanSetKeyValueInUserAsset".parse().unwrap(), &json!({ "asset_id": mouse_shoes_id }), @@ -296,12 +296,12 @@ fn stored_vs_granted_token_payload() -> Result<()> { // Registering mouse and asset definition let asset_definition_id: AssetDefinitionId = "xor#wonderland".parse().expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::store(asset_definition_id.clone())); + let create_asset = RegisterExpr::new(AssetDefinition::store(asset_definition_id.clone())); let mouse_id: AccountId = "mouse@wonderland".parse().expect("Valid"); let mouse_keypair = iroha_crypto::KeyPair::generate().expect("Failed to generate KeyPair."); let new_mouse_account = Account::new(mouse_id.clone(), [mouse_keypair.public_key().clone()]); - let instructions: [InstructionBox; 2] = [ - RegisterBox::new(new_mouse_account).into(), + let instructions: [InstructionExpr; 2] = [ + RegisterExpr::new(new_mouse_account).into(), create_asset.into(), ]; iroha_client @@ -310,7 +310,7 @@ fn stored_vs_granted_token_payload() -> Result<()> { // Allow alice to mint mouse asset and mint initial value let mouse_asset = AssetId::new(asset_definition_id, mouse_id.clone()); - let allow_alice_to_set_key_value_in_mouse_asset = GrantBox::new( + let allow_alice_to_set_key_value_in_mouse_asset = GrantExpr::new( PermissionToken::from_str_unchecked( "CanSetKeyValueInUserAsset".parse().unwrap(), // NOTE: Introduced additional whitespaces in the serialized form @@ -329,7 +329,7 @@ fn stored_vs_granted_token_payload() -> Result<()> { // Check that alice can indeed mint mouse asset let set_key_value = - SetKeyValueBox::new(mouse_asset, Name::from_str("color")?, "red".to_owned()); + SetKeyValueExpr::new(mouse_asset, Name::from_str("color")?, "red".to_owned()); iroha_client .submit_blocking(set_key_value) .expect("Failed to mint asset for mouse."); diff --git a/client/tests/integration/queries/account.rs b/client/tests/integration/queries/account.rs index 7791c7da327..de3fdb023a6 100644 --- a/client/tests/integration/queries/account.rs +++ b/client/tests/integration/queries/account.rs @@ -15,7 +15,7 @@ fn find_accounts_with_asset() -> Result<()> { // Registering new asset definition let definition_id = AssetDefinitionId::from_str("test_coin#wonderland").expect("Valid"); let asset_definition = AssetDefinition::quantity(definition_id.clone()); - test_client.submit_blocking(RegisterBox::new(asset_definition.clone()))?; + test_client.submit_blocking(RegisterExpr::new(asset_definition.clone()))?; // Checking results before all let received_asset_definition = @@ -40,7 +40,7 @@ fn find_accounts_with_asset() -> Result<()> { .iter() .skip(1) // Alice has already been registered in genesis .cloned() - .map(|account_id| RegisterBox::new(Account::new(account_id, []))) + .map(|account_id| RegisterExpr::new(Account::new(account_id, []))) .collect::>(); test_client.submit_all_blocking(register_accounts)?; @@ -48,7 +48,7 @@ fn find_accounts_with_asset() -> Result<()> { .iter() .cloned() .map(|account_id| AssetId::new(definition_id.clone(), account_id)) - .map(|asset_id| MintBox::new(1_u32, asset_id)) + .map(|asset_id| MintExpr::new(1_u32, asset_id)) .collect::>(); test_client.submit_all_blocking(mint_asset)?; diff --git a/client/tests/integration/queries/asset.rs b/client/tests/integration/queries/asset.rs index 27e8912ef9c..d9875ecdc4b 100644 --- a/client/tests/integration/queries/asset.rs +++ b/client/tests/integration/queries/asset.rs @@ -18,7 +18,7 @@ fn find_asset_total_quantity() -> Result<()> { // Register new domain let domain_id: DomainId = "looking_glass".parse()?; let domain = Domain::new(domain_id); - test_client.submit_blocking(RegisterBox::new(domain))?; + test_client.submit_blocking(RegisterExpr::new(domain))?; let accounts: [AccountId; 5] = [ "alice@wonderland".parse()?, @@ -39,7 +39,7 @@ fn find_asset_total_quantity() -> Result<()> { .skip(1) // Alice has already been registered in genesis .cloned() .zip(keys.iter().map(KeyPair::public_key).cloned()) - .map(|(account_id, public_key)| RegisterBox::new(Account::new(account_id, [public_key]))) + .map(|(account_id, public_key)| RegisterExpr::new(Account::new(account_id, [public_key]))) .collect::>(); test_client.submit_all_blocking(register_accounts)?; @@ -81,7 +81,7 @@ fn find_asset_total_quantity() -> Result<()> { let definition_id: AssetDefinitionId = definition.parse().expect("Failed to parse `definition_id`"); let asset_definition = AssetDefinition::new(definition_id.clone(), asset_value_type); - test_client.submit_blocking(RegisterBox::new(asset_definition.clone()))?; + test_client.submit_blocking(RegisterExpr::new(asset_definition.clone()))?; let asset_ids = accounts .iter() @@ -99,20 +99,20 @@ fn find_asset_total_quantity() -> Result<()> { .iter() .cloned() .map(|asset_id| Asset::new(asset_id, initial_value.clone())) - .map(RegisterBox::new) + .map(RegisterExpr::new) .collect::>(); test_client.submit_all_blocking(register_asset)?; let mint_asset = asset_ids .iter() .cloned() - .map(|asset_id| MintBox::new(to_mint.clone(), asset_id)); + .map(|asset_id| MintExpr::new(to_mint.clone(), asset_id)); test_client.submit_all_blocking(mint_asset)?; let burn_asset = asset_ids .iter() .cloned() - .map(|asset_id| BurnBox::new(to_burn.clone(), asset_id)) + .map(|asset_id| BurnExpr::new(to_burn.clone(), asset_id)) .collect::>(); test_client.submit_all_blocking(burn_asset)?; @@ -125,7 +125,7 @@ fn find_asset_total_quantity() -> Result<()> { let unregister_asset = asset_ids .iter() .cloned() - .map(UnregisterBox::new) + .map(UnregisterExpr::new) .collect::>(); test_client.submit_all_blocking(unregister_asset)?; @@ -136,7 +136,7 @@ fn find_asset_total_quantity() -> Result<()> { assert!(total_asset_quantity.is_zero_value()); // Unregister asset definition - test_client.submit_blocking(UnregisterBox::new(definition_id.clone()))?; + test_client.submit_blocking(UnregisterExpr::new(definition_id.clone()))?; // Assert that total asset quantity cleared with unregistering of asset definition let result = test_client.request(FindTotalAssetQuantityByAssetDefinitionId::new( @@ -153,7 +153,7 @@ fn find_asset_total_quantity() -> Result<()> { // Test for `Store` asset value type let definition_id: AssetDefinitionId = "store#wonderland".parse().expect("Valid"); let asset_definition = AssetDefinition::store(definition_id.clone()); - test_client.submit_blocking(RegisterBox::new(asset_definition))?; + test_client.submit_blocking(RegisterExpr::new(asset_definition))?; let asset_ids = accounts .iter() @@ -171,7 +171,7 @@ fn find_asset_total_quantity() -> Result<()> { .iter() .cloned() .map(|asset_id| Asset::new(asset_id, Metadata::default())) - .map(RegisterBox::new) + .map(RegisterExpr::new) .collect::>(); test_client.submit_all_blocking(register_asset)?; @@ -184,7 +184,7 @@ fn find_asset_total_quantity() -> Result<()> { let unregister_asset = asset_ids .iter() .cloned() - .map(UnregisterBox::new) + .map(UnregisterExpr::new) .collect::>(); test_client.submit_all_blocking(unregister_asset)?; @@ -195,7 +195,7 @@ fn find_asset_total_quantity() -> Result<()> { assert!(total_asset_quantity.is_zero_value()); // Unregister asset definition - test_client.submit_blocking(UnregisterBox::new(definition_id.clone()))?; + test_client.submit_blocking(UnregisterExpr::new(definition_id.clone()))?; // Assert that total asset quantity cleared with unregistering of asset definition let result = test_client.request(FindTotalAssetQuantityByAssetDefinitionId::new( diff --git a/client/tests/integration/queries/role.rs b/client/tests/integration/queries/role.rs index f2d88d573ec..0bb221e484a 100644 --- a/client/tests/integration/queries/role.rs +++ b/client/tests/integration/queries/role.rs @@ -29,7 +29,7 @@ fn find_roles() -> Result<()> { let register_roles = role_ids .iter() .cloned() - .map(|role_id| RegisterBox::new(Role::new(role_id))) + .map(|role_id| RegisterExpr::new(Role::new(role_id))) .collect::>(); test_client.submit_all_blocking(register_roles)?; @@ -61,7 +61,7 @@ fn find_role_ids() -> Result<()> { let register_roles = role_ids .iter() .cloned() - .map(|role_id| RegisterBox::new(Role::new(role_id))) + .map(|role_id| RegisterExpr::new(Role::new(role_id))) .collect::>(); test_client.submit_all_blocking(register_roles)?; @@ -87,7 +87,7 @@ fn find_role_by_id() -> Result<()> { let new_role = Role::new(role_id.clone()); // Registering role - let register_role = RegisterBox::new(new_role.clone()); + let register_role = RegisterExpr::new(new_role.clone()); test_client.submit_blocking(register_role)?; let found_role = test_client.request(client::role::by_id(role_id))?; @@ -130,7 +130,7 @@ fn find_roles_by_account_id() -> Result<()> { .iter() .cloned() .map(|role_id| { - RegisterBox::new(Role::new(role_id).add_permission(PermissionToken::new( + RegisterExpr::new(Role::new(role_id).add_permission(PermissionToken::new( "CanSetKeyValueInUserAccount".parse().unwrap(), &json!({ "account_id": alice_id }), ))) @@ -142,7 +142,7 @@ fn find_roles_by_account_id() -> Result<()> { let grant_roles = role_ids .iter() .cloned() - .map(|role_id| GrantBox::new(role_id, alice_id.clone())) + .map(|role_id| GrantExpr::new(role_id, alice_id.clone())) .collect::>(); test_client.submit_all_blocking(grant_roles)?; diff --git a/client/tests/integration/restart_peer.rs b/client/tests/integration/restart_peer.rs index 1a9f810853f..6a6c3a95be1 100644 --- a/client/tests/integration/restart_peer.rs +++ b/client/tests/integration/restart_peer.rs @@ -22,7 +22,7 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { let account_id = AccountId::from_str("alice@wonderland").unwrap(); let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").unwrap(); - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); let quantity: u32 = 200; let iroha_client = client::Client::test(&peer.api_address, &peer.telemetry_address); @@ -38,7 +38,7 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { wait_for_genesis_committed(&vec![iroha_client.clone()], 0); iroha_client.submit_blocking(create_asset)?; - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), diff --git a/client/tests/integration/roles.rs b/client/tests/integration/roles.rs index 60ae9fb97f5..5466aa001c7 100644 --- a/client/tests/integration/roles.rs +++ b/client/tests/integration/roles.rs @@ -14,7 +14,7 @@ fn register_empty_role() -> Result<()> { wait_for_genesis_committed(&vec![test_client.clone()], 0); let role_id = "root".parse().expect("Valid"); - let register_role = RegisterBox::new(Role::new(role_id)); + let register_role = RegisterExpr::new(Role::new(role_id)); test_client.submit(register_role)?; Ok(()) @@ -29,7 +29,7 @@ fn register_role_with_empty_token_params() -> Result<()> { let token = PermissionToken::new("token".parse()?, &json!(null)); let role = Role::new(role_id).add_permission(token); - test_client.submit(RegisterBox::new(role))?; + test_client.submit(RegisterExpr::new(role))?; Ok(()) } @@ -53,7 +53,7 @@ fn register_and_grant_role_for_metadata_access() -> Result<()> { // Registering Mouse let mouse_key_pair = iroha_crypto::KeyPair::generate()?; - let register_mouse = RegisterBox::new(Account::new( + let register_mouse = RegisterExpr::new(Account::new( mouse_id.clone(), [mouse_key_pair.public_key().clone()], )); @@ -70,18 +70,18 @@ fn register_and_grant_role_for_metadata_access() -> Result<()> { "CanRemoveKeyValueInUserAccount".parse()?, &json!({ "account_id": mouse_id }), )); - let register_role = RegisterBox::new(role); + let register_role = RegisterExpr::new(role); test_client.submit_blocking(register_role)?; // Mouse grants role to Alice - let grant_role = GrantBox::new(role_id.clone(), alice_id.clone()); + let grant_role = GrantExpr::new(role_id.clone(), alice_id.clone()); let grant_role_tx = TransactionBuilder::new(mouse_id.clone()) .with_instructions([grant_role]) .sign(mouse_key_pair)?; test_client.submit_transaction_blocking(&grant_role_tx)?; // Alice modifies Mouse's metadata - let set_key_value = SetKeyValueBox::new( + let set_key_value = SetKeyValueExpr::new( mouse_id, Name::from_str("key").expect("Valid"), Value::String("value".to_owned()), @@ -107,11 +107,11 @@ fn unregistered_role_removed_from_account() -> Result<()> { let mouse_id: AccountId = "mouse@wonderland".parse().expect("Valid"); // Registering Mouse - let register_mouse = RegisterBox::new(Account::new(mouse_id.clone(), [])); + let register_mouse = RegisterExpr::new(Account::new(mouse_id.clone(), [])); test_client.submit_blocking(register_mouse)?; // Register root role - let register_role = RegisterBox::new(Role::new(role_id.clone()).add_permission( + let register_role = RegisterExpr::new(Role::new(role_id.clone()).add_permission( PermissionToken::new( "CanSetKeyValueInUserAccount".parse()?, &json!({ "account_id": alice_id }), @@ -120,7 +120,7 @@ fn unregistered_role_removed_from_account() -> Result<()> { test_client.submit_blocking(register_role)?; // Grant root role to Mouse - let grant_role = GrantBox::new(role_id.clone(), mouse_id.clone()); + let grant_role = GrantExpr::new(role_id.clone(), mouse_id.clone()); test_client.submit_blocking(grant_role)?; // Check that Mouse has root role @@ -130,7 +130,7 @@ fn unregistered_role_removed_from_account() -> Result<()> { assert!(found_mouse_roles.contains(&role_id)); // Unregister root role - let unregister_role = UnregisterBox::new(role_id.clone()); + let unregister_role = UnregisterExpr::new(role_id.clone()); test_client.submit_blocking(unregister_role)?; // Check that Mouse doesn't have the root role @@ -155,7 +155,7 @@ fn role_with_invalid_permissions_is_not_accepted() -> Result<()> { )); let err = test_client - .submit_blocking(RegisterBox::new(role)) + .submit_blocking(RegisterExpr::new(role)) .expect_err("Submitting role with invalid permission token should fail"); let rejection_reason = err diff --git a/client/tests/integration/set_parameter.rs b/client/tests/integration/set_parameter.rs index a9533f5f541..a395d16493f 100644 --- a/client/tests/integration/set_parameter.rs +++ b/client/tests/integration/set_parameter.rs @@ -14,7 +14,7 @@ fn can_change_parameter_value() -> Result<()> { let parameter = Parameter::from_str("?BlockTime=4000")?; let parameter_id = ParameterId::from_str("BlockTime")?; - let param_box = SetParameterBox::new(parameter); + let param_box = SetParameterExpr::new(parameter); let old_params = test_client .request(client::parameter::all())? @@ -46,13 +46,13 @@ fn parameter_propagated() -> Result<()> { wait_for_genesis_committed(&vec![test_client.clone()], 0); let too_long_domain_name: DomainId = "0".repeat(2_usize.pow(8)).parse()?; - let create_domain = RegisterBox::new(Domain::new(too_long_domain_name)); + let create_domain = RegisterExpr::new(Domain::new(too_long_domain_name)); let _ = test_client .submit_blocking(create_domain.clone()) .expect_err("Should fail before ident length limits update"); let parameter = Parameter::from_str("?WSVIdentLengthLimits=1,256_LL")?; - let param_box = SetParameterBox::new(parameter); + let param_box = SetParameterExpr::new(parameter); test_client.submit_blocking(param_box)?; test_client diff --git a/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs b/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs index 75de8cd08f4..325e732dda0 100644 --- a/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs +++ b/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs @@ -38,8 +38,8 @@ fn main(_owner: AccountId, _event: Event) { let account_nft_id = AssetId::new(nft_id, account.id().clone()); let account_nft = Asset::new(account_nft_id, Metadata::new()); - RegisterBox::new(nft_definition).execute().dbg_unwrap(); - RegisterBox::new(account_nft).execute().dbg_unwrap(); + RegisterExpr::new(nft_definition).execute().dbg_unwrap(); + RegisterExpr::new(account_nft).execute().dbg_unwrap(); } iroha_trigger::info!("Smart contract executed successfully"); diff --git a/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs b/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs index c49a6136f71..a617b3ffd63 100644 --- a/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs +++ b/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs @@ -16,7 +16,7 @@ fn main(owner: AccountId, _event: Event) { .dbg_expect("Failed to parse `rose#wonderland` asset definition id"); let rose_id = AssetId::new(rose_definition_id, owner); - MintBox::new(1_u32, rose_id) + MintExpr::new(1_u32, rose_id) .execute() .dbg_expect("Failed to mint rose"); } diff --git a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs index b9040c81b4a..80ba91b749d 100644 --- a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs @@ -39,7 +39,7 @@ macro_rules! defaults { } impl Visit for Validator { - fn visit_instruction(&mut self, authority: &AccountId, isi: &InstructionBox) { + fn visit_instruction(&mut self, authority: &AccountId, isi: &InstructionExpr) { if parse!("admin@admin" as AccountId) == *authority { pass!(self); } @@ -52,9 +52,9 @@ impl Visit for Validator { visit_transaction(&SignedTransaction), visit_expression(&EvaluatesTo), - visit_sequence(&SequenceBox), - visit_if(&Conditional), - visit_pair(&Pair), + visit_sequence(&SequenceExpr), + visit_if(&ConditionalExpr), + visit_pair(&PairExpr), // Peer validation visit_unregister_peer(Unregister), @@ -66,17 +66,17 @@ impl Visit for Validator { // Account validation visit_unregister_account(Unregister), - visit_mint_account_public_key(Mint), - visit_burn_account_public_key(Burn), - visit_mint_account_signature_check_condition(Mint), + visit_mint_account_public_key(Mint), + visit_burn_account_public_key(Burn), + visit_mint_account_signature_check_condition(Mint), visit_set_account_key_value(SetKeyValue), visit_remove_account_key_value(RemoveKeyValue), // Asset validation visit_register_asset(Register), visit_unregister_asset(Unregister), - visit_mint_asset(Mint), - visit_burn_asset(Burn), + visit_mint_asset(Mint), + visit_burn_asset(Burn), visit_transfer_asset(Transfer), visit_set_asset_key_value(SetKeyValue), visit_remove_asset_key_value(RemoveKeyValue), @@ -88,18 +88,18 @@ impl Visit for Validator { visit_remove_asset_definition_key_value(RemoveKeyValue), // Permission validation - visit_grant_account_permission(Grant), - visit_revoke_account_permission(Revoke), + visit_grant_account_permission(Grant), + visit_revoke_account_permission(Revoke), // Role validation visit_register_role(Register), visit_unregister_role(Unregister), - visit_grant_account_role(Grant), - visit_revoke_account_role(Revoke), + visit_grant_account_role(Grant), + visit_revoke_account_role(Revoke), // Trigger validation visit_unregister_trigger(Unregister>), - visit_mint_trigger_repetitions(Mint, u32>), + visit_mint_trigger_repetitions(Mint>), visit_execute_trigger(ExecuteTrigger), // Parameter validation @@ -150,7 +150,7 @@ pub fn validate_transaction( #[entrypoint] pub fn validate_instruction( authority: AccountId, - instruction: InstructionBox, + instruction: InstructionExpr, block_height: u64, ) -> Result { let mut validator = Validator::new(block_height); diff --git a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs index 2b6451d48c0..30f205b7bd5 100644 --- a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs @@ -118,7 +118,7 @@ impl Validator { accounts .iter() .try_for_each(|(account, domain_id)| { - RevokeBox::new( + RevokeExpr::new( PermissionToken::new( can_unregister_domain_definition_id.clone(), &json!({ "domain_id": domain_id }), @@ -137,7 +137,7 @@ impl Validator { ) })?; - GrantBox::new( + GrantExpr::new( PermissionToken::new( can_control_domain_lives_definition_id.clone(), &json!(null), @@ -204,11 +204,11 @@ impl Visit for Validator { visit_unsupported(T), visit_transaction(&SignedTransaction), - visit_instruction(&InstructionBox), + visit_instruction(&InstructionExpr), visit_expression(&EvaluatesTo), - visit_sequence(&SequenceBox), - visit_if(&Conditional), - visit_pair(&Pair), + visit_sequence(&SequenceExpr), + visit_if(&ConditionalExpr), + visit_pair(&PairExpr), // Peer validation visit_unregister_peer(Unregister), @@ -219,17 +219,17 @@ impl Visit for Validator { // Account validation visit_unregister_account(Unregister), - visit_mint_account_public_key(Mint), - visit_burn_account_public_key(Burn), - visit_mint_account_signature_check_condition(Mint), + visit_mint_account_public_key(Mint), + visit_burn_account_public_key(Burn), + visit_mint_account_signature_check_condition(Mint), visit_set_account_key_value(SetKeyValue), visit_remove_account_key_value(RemoveKeyValue), // Asset validation visit_register_asset(Register), visit_unregister_asset(Unregister), - visit_mint_asset(Mint), - visit_burn_asset(Burn), + visit_mint_asset(Mint), + visit_burn_asset(Burn), visit_transfer_asset(Transfer), visit_set_asset_key_value(SetKeyValue), visit_remove_asset_key_value(RemoveKeyValue), @@ -241,18 +241,18 @@ impl Visit for Validator { visit_remove_asset_definition_key_value(RemoveKeyValue), // Permission validation - visit_grant_account_permission(Grant), - visit_revoke_account_permission(Revoke), + visit_grant_account_permission(Grant), + visit_revoke_account_permission(Revoke), // Role validation visit_register_role(Register), visit_unregister_role(Unregister), - visit_grant_account_role(Grant), - visit_revoke_account_role(Revoke), + visit_grant_account_role(Grant), + visit_revoke_account_role(Revoke), // Trigger validation visit_unregister_trigger(Unregister>), - visit_mint_trigger_repetitions(Mint, u32>), + visit_mint_trigger_repetitions(Mint>), visit_execute_trigger(ExecuteTrigger), // Parameter validation @@ -314,7 +314,7 @@ pub fn validate_transaction( #[entrypoint] pub fn validate_instruction( authority: AccountId, - instruction: InstructionBox, + instruction: InstructionExpr, block_height: u64, ) -> Result { let mut validator = Validator::new(block_height); diff --git a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs index 0b4b3b36c93..86e532012b6 100644 --- a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs @@ -55,11 +55,11 @@ impl Visit for Validator { visit_unsupported(T), visit_transaction(&SignedTransaction), - visit_instruction(&InstructionBox), + visit_instruction(&InstructionExpr), visit_expression(&EvaluatesTo), - visit_sequence(&SequenceBox), - visit_if(&Conditional), - visit_pair(&Pair), + visit_sequence(&SequenceExpr), + visit_if(&ConditionalExpr), + visit_pair(&PairExpr), // Peer validation visit_unregister_peer(Unregister), @@ -71,17 +71,17 @@ impl Visit for Validator { // Account validation visit_unregister_account(Unregister), - visit_mint_account_public_key(Mint), - visit_burn_account_public_key(Burn), - visit_mint_account_signature_check_condition(Mint), + visit_mint_account_public_key(Mint), + visit_burn_account_public_key(Burn), + visit_mint_account_signature_check_condition(Mint), visit_set_account_key_value(SetKeyValue), visit_remove_account_key_value(RemoveKeyValue), // Asset validation visit_register_asset(Register), visit_unregister_asset(Unregister), - visit_mint_asset(Mint), - visit_burn_asset(Burn), + visit_mint_asset(Mint), + visit_burn_asset(Burn), visit_transfer_asset(Transfer), visit_set_asset_key_value(SetKeyValue), visit_remove_asset_key_value(RemoveKeyValue), @@ -93,18 +93,18 @@ impl Visit for Validator { visit_remove_asset_definition_key_value(RemoveKeyValue), // Permission validation - visit_grant_account_permission(Grant), - visit_revoke_account_permission(Revoke), + visit_grant_account_permission(Grant), + visit_revoke_account_permission(Revoke), // Role validation visit_register_role(Register), visit_unregister_role(Unregister), - visit_grant_account_role(Grant), - visit_revoke_account_role(Revoke), + visit_grant_account_role(Grant), + visit_revoke_account_role(Revoke), // Trigger validation visit_unregister_trigger(Unregister>), - visit_mint_trigger_repetitions(Mint, u32>), + visit_mint_trigger_repetitions(Mint>), visit_execute_trigger(ExecuteTrigger), // Parameter validation @@ -142,7 +142,7 @@ pub fn migrate(_block_height: u64) -> MigrationResult { // Registering a new domain (using ISI) let domain_id = parse!("failed_migration_test_domain" as DomainId); - RegisterBox::new(Domain::new(domain_id)) + RegisterExpr::new(Domain::new(domain_id)) .execute() .map_err(|error| { format!( @@ -168,7 +168,7 @@ pub fn validate_transaction( #[entrypoint] pub fn validate_instruction( authority: AccountId, - instruction: InstructionBox, + instruction: InstructionExpr, block_height: u64, ) -> Result { let mut validator = Validator::new(block_height); diff --git a/client/tests/integration/sorting.rs b/client/tests/integration/sorting.rs index bed460847a9..ff4ae41093e 100644 --- a/client/tests/integration/sorting.rs +++ b/client/tests/integration/sorting.rs @@ -46,8 +46,8 @@ fn correct_pagination_assets_after_creating_new_one() { assets.push(asset.clone()); - let create_asset_definition = RegisterBox::new(asset_definition); - let create_asset = RegisterBox::new(asset); + let create_asset_definition = RegisterExpr::new(asset_definition); + let create_asset = RegisterExpr::new(asset); instructions.push(create_asset_definition); instructions.push(create_asset); @@ -95,8 +95,8 @@ fn correct_pagination_assets_after_creating_new_one() { AssetValue::Store(new_asset_metadata), ); - let create_asset_definition = RegisterBox::new(new_asset_definition); - let create_asset = RegisterBox::new(new_asset.clone()); + let create_asset_definition = RegisterExpr::new(new_asset_definition); + let create_asset = RegisterExpr::new(new_asset.clone()); test_client .submit_all_blocking([create_asset_definition, create_asset]) @@ -154,7 +154,7 @@ fn correct_sorting_of_entities() { assets_metadata.push(asset_metadata); asset_definitions.push(asset_definition_id); - let create_asset_definition = RegisterBox::new(asset_definition); + let create_asset_definition = RegisterExpr::new(asset_definition); instructions.push(create_asset_definition); } @@ -205,7 +205,7 @@ fn correct_sorting_of_entities() { accounts.push(account_id); accounts_metadata.push(account_metadata); - let create_account = RegisterBox::new(account); + let create_account = RegisterExpr::new(account); instructions.push(create_account); } @@ -252,7 +252,7 @@ fn correct_sorting_of_entities() { domains.push(domain_id); domains_metadata.push(domain_metadata); - let create_account = RegisterBox::new(domain); + let create_account = RegisterExpr::new(domain); instructions.push(create_account); } @@ -299,7 +299,7 @@ fn correct_sorting_of_entities() { domains.push(domain_id); domains_metadata.push(domain_metadata); - let create_account = RegisterBox::new(domain); + let create_account = RegisterExpr::new(domain); instructions.push(create_account); } test_client @@ -363,7 +363,7 @@ fn sort_only_elements_which_have_sorting_key() -> Result<()> { account }; - let create_account = RegisterBox::new(account); + let create_account = RegisterExpr::new(account); instructions.push(create_account); } diff --git a/client/tests/integration/transfer_asset.rs b/client/tests/integration/transfer_asset.rs index e473b61b088..1b3be0e6449 100644 --- a/client/tests/integration/transfer_asset.rs +++ b/client/tests/integration/transfer_asset.rs @@ -61,15 +61,15 @@ fn simulate_transfer< let (bob_public_key, _) = KeyPair::generate() .expect("Failed to generate KeyPair") .into(); - let create_mouse = RegisterBox::new(Account::new(mouse_id.clone(), [bob_public_key])); + let create_mouse = RegisterExpr::new(Account::new(mouse_id.clone(), [bob_public_key])); let asset_definition_id: AssetDefinitionId = "camomile#wonderland".parse().expect("Valid"); - let create_asset = RegisterBox::new(value_type(asset_definition_id.clone())); - let mint_asset = MintBox::new( + let create_asset = RegisterExpr::new(value_type(asset_definition_id.clone())); + let mint_asset = MintExpr::new( starting_amount.to_value(), IdBox::AssetId(AssetId::new(asset_definition_id.clone(), alice_id.clone())), ); - let instructions: [InstructionBox; 3] = [ + let instructions: [InstructionExpr; 3] = [ // create_alice.into(), We don't need to register Alice, because she is created in genesis create_mouse.into(), create_asset.into(), @@ -80,7 +80,7 @@ fn simulate_transfer< .expect("Failed to prepare state."); //When - let transfer_asset = TransferBox::new( + let transfer_asset = TransferExpr::new( IdBox::AssetId(AssetId::new(asset_definition_id.clone(), alice_id)), amount_to_transfer.clone().to_value(), IdBox::AccountId(mouse_id.clone()), diff --git a/client/tests/integration/triggers/by_call_trigger.rs b/client/tests/integration/triggers/by_call_trigger.rs index 926982ac12a..5d0d134f157 100644 --- a/client/tests/integration/triggers/by_call_trigger.rs +++ b/client/tests/integration/triggers/by_call_trigger.rs @@ -25,12 +25,12 @@ fn call_execute_trigger() -> Result<()> { let asset_id = AssetId::new(asset_definition_id, account_id); let prev_value = get_asset_value(&mut test_client, asset_id.clone())?; - let instruction = MintBox::new(1_u32, asset_id.clone()); + let instruction = MintExpr::new(1_u32, asset_id.clone()); let register_trigger = build_register_trigger_isi(asset_id.clone(), vec![instruction.into()]); test_client.submit_blocking(register_trigger)?; let trigger_id = TriggerId::from_str(TRIGGER_NAME)?; - let call_trigger = ExecuteTriggerBox::new(trigger_id); + let call_trigger = ExecuteTriggerExpr::new(trigger_id); test_client.submit_blocking(call_trigger)?; let new_value = get_asset_value(&mut test_client, asset_id)?; @@ -48,12 +48,12 @@ fn execute_trigger_should_produce_event() -> Result<()> { let account_id: AccountId = "alice@wonderland".parse()?; let asset_id = AssetId::new(asset_definition_id, account_id.clone()); - let instruction = MintBox::new(1_u32, asset_id.clone()); + let instruction = MintExpr::new(1_u32, asset_id.clone()); let register_trigger = build_register_trigger_isi(asset_id, vec![instruction.into()]); test_client.submit_blocking(register_trigger)?; let trigger_id = TriggerId::from_str(TRIGGER_NAME)?; - let call_trigger = ExecuteTriggerBox::new(trigger_id.clone()); + let call_trigger = ExecuteTriggerExpr::new(trigger_id.clone()); let thread_client = test_client.clone(); let (sender, receiver) = mpsc::channel(); @@ -83,11 +83,11 @@ fn infinite_recursion_should_produce_one_call_per_block() -> Result<()> { let account_id = "alice@wonderland".parse()?; let asset_id = AssetId::new(asset_definition_id, account_id); let trigger_id = TriggerId::from_str(TRIGGER_NAME)?; - let call_trigger = ExecuteTriggerBox::new(trigger_id); + let call_trigger = ExecuteTriggerExpr::new(trigger_id); let prev_value = get_asset_value(&mut test_client, asset_id.clone())?; let instructions = vec![ - MintBox::new(1_u32, asset_id.clone()).into(), + MintExpr::new(1_u32, asset_id.clone()).into(), call_trigger.clone().into(), ]; let register_trigger = build_register_trigger_isi(asset_id.clone(), instructions); @@ -113,8 +113,8 @@ fn trigger_failure_should_not_cancel_other_triggers_execution() -> Result<()> { // Registering trigger that should fail on execution let bad_trigger_id = TriggerId::from_str("bad_trigger")?; // Invalid instruction - let bad_trigger_instructions = vec![MintBox::new(1_u32, account_id.clone())]; - let register_bad_trigger = RegisterBox::new(Trigger::new( + let bad_trigger_instructions = vec![MintExpr::new(1_u32, account_id.clone())]; + let register_bad_trigger = RegisterExpr::new(Trigger::new( bad_trigger_id.clone(), Action::new( bad_trigger_instructions, @@ -130,8 +130,8 @@ fn trigger_failure_should_not_cancel_other_triggers_execution() -> Result<()> { // Registering normal trigger let trigger_id = TriggerId::from_str(TRIGGER_NAME)?; - let trigger_instructions = vec![MintBox::new(1_u32, asset_id.clone())]; - let register_trigger = RegisterBox::new(Trigger::new( + let trigger_instructions = vec![MintExpr::new(1_u32, asset_id.clone())]; + let register_trigger = RegisterExpr::new(Trigger::new( trigger_id, Action::new( trigger_instructions, @@ -147,7 +147,7 @@ fn trigger_failure_should_not_cancel_other_triggers_execution() -> Result<()> { let prev_asset_value = get_asset_value(&mut test_client, asset_id.clone())?; // Executing bad trigger - test_client.submit_blocking(ExecuteTriggerBox::new(bad_trigger_id))?; + test_client.submit_blocking(ExecuteTriggerExpr::new(bad_trigger_id))?; // Checking results let new_asset_value = get_asset_value(&mut test_client, asset_id)?; @@ -165,8 +165,8 @@ fn trigger_should_not_be_executed_with_zero_repeats_count() -> Result<()> { let asset_id = AssetId::new(asset_definition_id, account_id.clone()); let trigger_id = TriggerId::from_str("self_modifying_trigger")?; - let trigger_instructions = vec![MintBox::new(1_u32, asset_id.clone())]; - let register_trigger = RegisterBox::new(Trigger::new( + let trigger_instructions = vec![MintExpr::new(1_u32, asset_id.clone())]; + let register_trigger = RegisterExpr::new(Trigger::new( trigger_id.clone(), Action::new( trigger_instructions, @@ -184,7 +184,7 @@ fn trigger_should_not_be_executed_with_zero_repeats_count() -> Result<()> { let prev_asset_value = get_asset_value(&mut test_client, asset_id.clone())?; // Executing trigger first time - let execute_trigger = ExecuteTriggerBox::new(trigger_id.clone()); + let execute_trigger = ExecuteTriggerExpr::new(trigger_id.clone()); test_client.submit_blocking(execute_trigger.clone())?; // Executing trigger second time @@ -224,10 +224,10 @@ fn trigger_should_be_able_to_modify_its_own_repeats_count() -> Result<()> { let trigger_id = TriggerId::from_str("self_modifying_trigger")?; let trigger_instructions = vec![ - MintBox::new(1_u32, trigger_id.clone()), - MintBox::new(1_u32, asset_id.clone()), + MintExpr::new(1_u32, trigger_id.clone()), + MintExpr::new(1_u32, asset_id.clone()), ]; - let register_trigger = RegisterBox::new(Trigger::new( + let register_trigger = RegisterExpr::new(Trigger::new( trigger_id.clone(), Action::new( trigger_instructions, @@ -245,7 +245,7 @@ fn trigger_should_be_able_to_modify_its_own_repeats_count() -> Result<()> { let prev_asset_value = get_asset_value(&mut test_client, asset_id.clone())?; // Executing trigger first time - let execute_trigger = ExecuteTriggerBox::new(trigger_id); + let execute_trigger = ExecuteTriggerExpr::new(trigger_id); test_client.submit_blocking(execute_trigger.clone())?; // Executing trigger second time @@ -270,7 +270,7 @@ fn unregister_trigger() -> Result<()> { let trigger = Trigger::new( trigger_id.clone(), Action::new( - Vec::::new(), + Vec::::new(), Repeats::Indefinitely, account_id.clone(), TriggeringFilterBox::ExecuteTrigger(ExecuteTriggerEventFilter::new( @@ -279,7 +279,7 @@ fn unregister_trigger() -> Result<()> { )), ), ); - let register_trigger = RegisterBox::new(trigger.clone()); + let register_trigger = RegisterExpr::new(trigger.clone()); test_client.submit_blocking(register_trigger)?; // Finding trigger @@ -303,7 +303,7 @@ fn unregister_trigger() -> Result<()> { assert_eq!(found_trigger, trigger); // Unregistering trigger - let unregister_trigger = UnregisterBox::new(trigger_id); + let unregister_trigger = UnregisterExpr::new(trigger_id); test_client.submit_blocking(unregister_trigger)?; // Checking result @@ -360,7 +360,7 @@ fn trigger_in_genesis_using_base64() -> Result<()> { let SignedTransaction::V1(tx_ref) = &mut genesis.transactions[0].0; match &mut tx_ref.payload.instructions { Executable::Instructions(instructions) => { - instructions.push(RegisterBox::new(trigger).into()); + instructions.push(RegisterExpr::new(trigger).into()); } Executable::Wasm(_) => panic!("Expected instructions"), } @@ -376,7 +376,7 @@ fn trigger_in_genesis_using_base64() -> Result<()> { let prev_value = get_asset_value(&mut test_client, asset_id.clone())?; // Executing trigger - let call_trigger = ExecuteTriggerBox::new(trigger_id); + let call_trigger = ExecuteTriggerExpr::new(trigger_id); test_client.submit_blocking(call_trigger)?; // Checking result @@ -397,10 +397,10 @@ fn trigger_should_be_able_to_modify_other_trigger() -> Result<()> { let trigger_id_unregister = TriggerId::from_str("unregister_other_trigger")?; let trigger_id_should_be_unregistered = TriggerId::from_str("should_be_unregistered_trigger")?; - let trigger_unregister_instructions = vec![UnregisterBox::new( + let trigger_unregister_instructions = vec![UnregisterExpr::new( trigger_id_should_be_unregistered.clone(), )]; - let register_trigger = RegisterBox::new(Trigger::new( + let register_trigger = RegisterExpr::new(Trigger::new( trigger_id_unregister.clone(), Action::new( trigger_unregister_instructions, @@ -414,8 +414,8 @@ fn trigger_should_be_able_to_modify_other_trigger() -> Result<()> { )); test_client.submit_blocking(register_trigger)?; - let trigger_should_be_unregistered_instructions = vec![MintBox::new(1_u32, asset_id.clone())]; - let register_trigger = RegisterBox::new(Trigger::new( + let trigger_should_be_unregistered_instructions = vec![MintExpr::new(1_u32, asset_id.clone())]; + let register_trigger = RegisterExpr::new(Trigger::new( trigger_id_should_be_unregistered.clone(), Action::new( trigger_should_be_unregistered_instructions, @@ -433,9 +433,9 @@ fn trigger_should_be_able_to_modify_other_trigger() -> Result<()> { let prev_asset_value = get_asset_value(&mut test_client, asset_id.clone())?; // Executing triggers - let execute_trigger_unregister = ExecuteTriggerBox::new(trigger_id_unregister); + let execute_trigger_unregister = ExecuteTriggerExpr::new(trigger_id_unregister); let execute_trigger_should_be_unregistered = - ExecuteTriggerBox::new(trigger_id_should_be_unregistered); + ExecuteTriggerExpr::new(trigger_id_should_be_unregistered); test_client.submit_all_blocking([ execute_trigger_unregister, execute_trigger_should_be_unregistered, @@ -456,11 +456,11 @@ fn get_asset_value(client: &mut Client, asset_id: AssetId) -> Result { fn build_register_trigger_isi( asset_id: AssetId, - trigger_instructions: Vec, -) -> RegisterBox { + trigger_instructions: Vec, +) -> RegisterExpr { let trigger_id: TriggerId = TRIGGER_NAME.parse().expect("Valid"); - RegisterBox::new(Trigger::new( + RegisterExpr::new(Trigger::new( trigger_id.clone(), Action::new( trigger_instructions, diff --git a/client/tests/integration/triggers/data_trigger.rs b/client/tests/integration/triggers/data_trigger.rs index 91280f32bea..3225bc94509 100644 --- a/client/tests/integration/triggers/data_trigger.rs +++ b/client/tests/integration/triggers/data_trigger.rs @@ -16,8 +16,8 @@ fn must_execute_both_triggers() -> Result<()> { let prev_value = get_asset_value(&test_client, asset_id.clone())?; - let instruction = MintBox::new(1_u32, asset_id.clone()); - let register_trigger = RegisterBox::new(Trigger::new( + let instruction = MintExpr::new(1_u32, asset_id.clone()); + let register_trigger = RegisterExpr::new(Trigger::new( "mint_rose_1".parse()?, Action::new( [instruction.clone()], @@ -30,7 +30,7 @@ fn must_execute_both_triggers() -> Result<()> { )); test_client.submit_blocking(register_trigger)?; - let register_trigger = RegisterBox::new(Trigger::new( + let register_trigger = RegisterExpr::new(Trigger::new( "mint_rose_2".parse()?, Action::new( [instruction], @@ -43,11 +43,11 @@ fn must_execute_both_triggers() -> Result<()> { )); test_client.submit_blocking(register_trigger)?; - test_client.submit_blocking(RegisterBox::new(Account::new( + test_client.submit_blocking(RegisterExpr::new(Account::new( "bunny@wonderland".parse()?, [], )))?; - test_client.submit_blocking(RegisterBox::new(Domain::new("neverland".parse()?)))?; + test_client.submit_blocking(RegisterExpr::new(Domain::new("neverland".parse()?)))?; let new_value = get_asset_value(&test_client, asset_id)?; assert_eq!(new_value, prev_value + 2); @@ -60,18 +60,18 @@ fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Resu let (_rt, _peer, test_client) = ::new().with_port(10_655).start_with_runtime(); wait_for_genesis_committed(&[test_client.clone()], 0); - let create_neverland_domain = RegisterBox::new(Domain::new("neverland".parse()?)); + let create_neverland_domain = RegisterExpr::new(Domain::new("neverland".parse()?)); let account_id: AccountId = "sapporo@neverland".parse()?; - let create_sapporo_account = RegisterBox::new(Account::new(account_id.clone(), [])); + let create_sapporo_account = RegisterExpr::new(Account::new(account_id.clone(), [])); let asset_definition_id: AssetDefinitionId = "sakura#neverland".parse()?; let create_sakura_asset_definition = - RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); let asset_id = AssetId::new(asset_definition_id, account_id.clone()); let create_sakura_asset = - RegisterBox::new(Asset::new(asset_id.clone(), AssetValue::Quantity(0))); + RegisterExpr::new(Asset::new(asset_id.clone(), AssetValue::Quantity(0))); test_client.submit_all_blocking([ create_neverland_domain, @@ -82,10 +82,10 @@ fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Resu let prev_value = get_asset_value(&test_client, asset_id.clone())?; - let register_trigger = RegisterBox::new(Trigger::new( + let register_trigger = RegisterExpr::new(Trigger::new( "mint_sakura$neverland".parse()?, Action::new( - [MintBox::new(1_u32, asset_id.clone())], + [MintExpr::new(1_u32, asset_id.clone())], Repeats::Indefinitely, account_id, TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAccount(BySome( @@ -95,12 +95,12 @@ fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Resu )); test_client.submit_blocking(register_trigger)?; - test_client.submit_blocking(RegisterBox::new(Account::new( + test_client.submit_blocking(RegisterExpr::new(Account::new( "asahi@wonderland".parse()?, [], )))?; - test_client.submit_blocking(RegisterBox::new(Account::new( + test_client.submit_blocking(RegisterExpr::new(Account::new( "asahi@neverland".parse()?, [], )))?; diff --git a/client/tests/integration/triggers/event_trigger.rs b/client/tests/integration/triggers/event_trigger.rs index f76f1868f6a..215897a8fa0 100644 --- a/client/tests/integration/triggers/event_trigger.rs +++ b/client/tests/integration/triggers/event_trigger.rs @@ -17,8 +17,8 @@ fn test_mint_asset_when_new_asset_definition_created() -> Result<()> { let asset_id = AssetId::new(asset_definition_id, account_id.clone()); let prev_value = get_asset_value(&mut test_client, asset_id.clone())?; - let instruction = MintBox::new(1_u32, asset_id.clone()); - let register_trigger = RegisterBox::new(Trigger::new( + let instruction = MintExpr::new(1_u32, asset_id.clone()); + let register_trigger = RegisterExpr::new(Trigger::new( "mint_rose".parse()?, Action::new( vec![instruction], @@ -35,7 +35,7 @@ fn test_mint_asset_when_new_asset_definition_created() -> Result<()> { test_client.submit(register_trigger)?; let tea_definition_id = "tea#wonderland".parse()?; - let register_tea_definition = RegisterBox::new(AssetDefinition::quantity(tea_definition_id)); + let register_tea_definition = RegisterExpr::new(AssetDefinition::quantity(tea_definition_id)); test_client.submit_blocking(register_tea_definition)?; let new_value = get_asset_value(&mut test_client, asset_id)?; diff --git a/client/tests/integration/triggers/time_trigger.rs b/client/tests/integration/triggers/time_trigger.rs index f238414e644..c8ca3e97a37 100644 --- a/client/tests/integration/triggers/time_trigger.rs +++ b/client/tests/integration/triggers/time_trigger.rs @@ -44,8 +44,8 @@ fn time_trigger_execution_count_error_should_be_less_than_15_percent() -> Result let schedule = TimeSchedule::starting_at(start_time).with_period(Duration::from_millis(PERIOD_MS)); - let instruction = MintBox::new(1_u32, asset_id.clone()); - let register_trigger = RegisterBox::new(Trigger::new( + let instruction = MintExpr::new(1_u32, asset_id.clone()); + let register_trigger = RegisterExpr::new(Trigger::new( "mint_rose".parse()?, Action::new( vec![instruction], @@ -98,8 +98,8 @@ fn change_asset_metadata_after_1_sec() -> Result<()> { let schedule = TimeSchedule::starting_at(start_time + Duration::from_millis(PERIOD_MS)); let instruction = - SetKeyValueBox::new(asset_definition_id.clone(), key.clone(), 3_u32.to_value()); - let register_trigger = RegisterBox::new(Trigger::new( + SetKeyValueExpr::new(asset_definition_id.clone(), key.clone(), 3_u32.to_value()); + let register_trigger = RegisterExpr::new(Trigger::new( "change_rose_metadata".parse().expect("Valid"), Action::new( vec![instruction], @@ -144,8 +144,8 @@ fn pre_commit_trigger_should_be_executed() -> Result<()> { // Start listening BEFORE submitting any transaction not to miss any block committed event let event_listener = get_block_committed_event_listener(&test_client)?; - let instruction = MintBox::new(1_u32, asset_id.clone()); - let register_trigger = RegisterBox::new(Trigger::new( + let instruction = MintExpr::new(1_u32, asset_id.clone()); + let register_trigger = RegisterExpr::new(Trigger::new( "mint_rose".parse()?, Action::new( vec![instruction], @@ -162,7 +162,7 @@ fn pre_commit_trigger_should_be_executed() -> Result<()> { prev_value = new_value; // ISI just to create a new block - let sample_isi = SetKeyValueBox::new( + let sample_isi = SetKeyValueExpr::new( account_id.clone(), "key".parse::()?, String::from("value"), @@ -196,7 +196,7 @@ fn mint_nft_for_every_user_every_1_sec() -> Result<()> { .iter() .skip(1) // Alice has already been registered in genesis .cloned() - .map(|account_id| RegisterBox::new(Account::new(account_id, []))) + .map(|account_id| RegisterExpr::new(Account::new(account_id, []))) .collect::>(); test_client.submit_all_blocking(register_accounts)?; @@ -219,7 +219,7 @@ fn mint_nft_for_every_user_every_1_sec() -> Result<()> { let start_time = current_time(); let schedule = TimeSchedule::starting_at(start_time).with_period(Duration::from_millis(TRIGGER_PERIOD_MS)); - let register_trigger = RegisterBox::new(Trigger::new( + let register_trigger = RegisterExpr::new(Trigger::new( "mint_nft_for_all".parse()?, Action::new( WasmSmartContract::from_compiled(wasm), @@ -294,7 +294,7 @@ fn submit_sample_isi_on_every_block_commit( for _ in block_committed_event_listener.take(times) { std::thread::sleep(timeout); // ISI just to create a new block - let sample_isi = SetKeyValueBox::new( + let sample_isi = SetKeyValueExpr::new( account_id.clone(), "key".parse::()?, String::from("value"), diff --git a/client/tests/integration/tx_history.rs b/client/tests/integration/tx_history.rs index af47084ca8f..a01662c56b7 100644 --- a/client/tests/integration/tx_history.rs +++ b/client/tests/integration/tx_history.rs @@ -24,14 +24,14 @@ fn client_has_rejected_and_acepted_txs_should_return_tx_history() -> Result<()> // Given let account_id = AccountId::from_str("alice@wonderland")?; let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland")?; - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); client.submit_blocking(create_asset)?; //When let quantity: u32 = 200; let asset_id = AssetId::new(asset_definition_id, account_id.clone()); - let mint_existed_asset = MintBox::new(quantity.to_value(), IdBox::AssetId(asset_id)); - let mint_not_existed_asset = MintBox::new( + let mint_existed_asset = MintExpr::new(quantity.to_value(), IdBox::AssetId(asset_id)); + let mint_not_existed_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( AssetDefinitionId::from_str("foo#wonderland")?, @@ -47,7 +47,7 @@ fn client_has_rejected_and_acepted_txs_should_return_tx_history() -> Result<()> } else { &mint_not_existed_asset }; - let instructions: Vec = vec![mint_asset.clone().into()]; + let instructions: Vec = vec![mint_asset.clone().into()]; let transaction = client.build_transaction(instructions, UnlimitedMetadata::new())?; client.submit_transaction(&transaction)?; } diff --git a/client/tests/integration/tx_rollback.rs b/client/tests/integration/tx_rollback.rs index e65037e9d7d..f24d240fd24 100644 --- a/client/tests/integration/tx_rollback.rs +++ b/client/tests/integration/tx_rollback.rs @@ -16,16 +16,16 @@ fn client_sends_transaction_with_invalid_instruction_should_not_see_any_changes( let account_id = AccountId::from_str("alice@wonderland")?; let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland")?; let wrong_asset_definition_id = AssetDefinitionId::from_str("ksor#wonderland")?; - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id)); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id)); let quantity: u32 = 200; - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( wrong_asset_definition_id.clone(), account_id.clone(), )), ); - let instructions: [InstructionBox; 2] = [create_asset.into(), mint_asset.into()]; + let instructions: [InstructionExpr; 2] = [create_asset.into(), mint_asset.into()]; let _ = client.submit_all_blocking(instructions); //Then diff --git a/client/tests/integration/unregister_peer.rs b/client/tests/integration/unregister_peer.rs index c30f05fb30d..f0216d23d5a 100644 --- a/client/tests/integration/unregister_peer.rs +++ b/client/tests/integration/unregister_peer.rs @@ -33,7 +33,7 @@ fn unstable_network_stable_after_add_and_after_remove_peer() -> Result<()> { // Then the new peer should already have the mint result. check_assets(&peer_client, &account_id, &asset_definition_id, 100); // Also, when a peer is unregistered - let remove_peer = UnregisterBox::new(IdBox::PeerId(peer.id.clone())); + let remove_peer = UnregisterExpr::new(IdBox::PeerId(peer.id.clone())); genesis_client.submit(remove_peer)?; thread::sleep(pipeline_time * 2); // We can mint without error. @@ -82,7 +82,7 @@ fn mint( pipeline_time: std::time::Duration, quantity: u32, ) -> Result { - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), @@ -110,13 +110,13 @@ fn init() -> Result<( let parameters = ParametersBuilder::new() .add_parameter(MAX_TRANSACTIONS_IN_BLOCK, 1u32)? .into_set_parameters(); - let create_domain = RegisterBox::new(Domain::new("domain".parse()?)); + let create_domain = RegisterExpr::new(Domain::new("domain".parse()?)); let account_id: AccountId = "account@domain".parse()?; let (public_key, _) = KeyPair::generate()?.into(); - let create_account = RegisterBox::new(Account::new(account_id.clone(), [public_key])); + let create_account = RegisterExpr::new(Account::new(account_id.clone(), [public_key])); let asset_definition_id: AssetDefinitionId = "xor#domain".parse()?; - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); - let instructions: [InstructionBox; 4] = [ + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); + let instructions: [InstructionExpr; 4] = [ parameters.into(), create_domain.into(), create_account.into(), diff --git a/client/tests/integration/unstable_network.rs b/client/tests/integration/unstable_network.rs index 52fec1aa735..327c3905496 100644 --- a/client/tests/integration/unstable_network.rs +++ b/client/tests/integration/unstable_network.rs @@ -80,7 +80,7 @@ fn unstable_network( let account_id: AccountId = "alice@wonderland".parse().expect("Valid"); let asset_definition_id: AssetDefinitionId = "camomile#wonderland".parse().expect("Valid"); - let register_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + let register_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); iroha_client .submit_blocking(register_asset) .expect("Failed to register asset"); @@ -102,7 +102,7 @@ fn unstable_network( } let quantity = 1; - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new( asset_definition_id.clone(), diff --git a/client/tests/integration/upgrade.rs b/client/tests/integration/upgrade.rs index 83e0db2afe1..f14c960a778 100644 --- a/client/tests/integration/upgrade.rs +++ b/client/tests/integration/upgrade.rs @@ -17,19 +17,19 @@ fn validator_upgrade_should_work() -> Result<()> { // Register `admin` domain and account let admin_domain = Domain::new("admin".parse()?); - let register_admin_domain = RegisterBox::new(admin_domain); + let register_admin_domain = RegisterExpr::new(admin_domain); client.submit_blocking(register_admin_domain)?; let admin_id: AccountId = "admin@admin".parse()?; let admin_keypair = KeyPair::generate()?; let admin_account = Account::new(admin_id.clone(), [admin_keypair.public_key().clone()]); - let register_admin_account = RegisterBox::new(admin_account); + let register_admin_account = RegisterExpr::new(admin_account); client.submit_blocking(register_admin_account)?; // Check that admin isn't allowed to transfer alice's rose by default let alice_rose: AssetId = "rose##alice@wonderland".parse()?; let admin_rose: AccountId = "admin@admin".parse()?; - let transfer_alice_rose = TransferBox::new(alice_rose, NumericValue::U32(1), admin_rose); + let transfer_alice_rose = TransferExpr::new(alice_rose, NumericValue::U32(1), admin_rose); let transfer_rose_tx = TransactionBuilder::new(admin_id.clone()) .with_instructions([transfer_alice_rose.clone()]) .sign(admin_keypair.clone())?; @@ -151,7 +151,8 @@ fn upgrade_validator(client: &Client, validator: impl AsRef) -> Result<()> info!("WASM size is {} bytes", wasm.len()); - let upgrade_validator = UpgradeBox::new(Validator::new(WasmSmartContract::from_compiled(wasm))); + let upgrade_validator = + UpgradeExpr::new(Validator::new(WasmSmartContract::from_compiled(wasm))); client.submit_blocking(upgrade_validator)?; Ok(()) diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index 729648b2898..beeb3df8bea 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -401,7 +401,7 @@ mod domain { id, metadata: Metadata(metadata), } = self; - let create_domain = RegisterBox::new(Domain::new(id)); + let create_domain = RegisterExpr::new(Domain::new(id)); submit([create_domain], metadata, context).wrap_err("Failed to create domain") } } @@ -490,7 +490,7 @@ mod account { key, metadata: Metadata(metadata), } = self; - let create_account = RegisterBox::new(Account::new(id, [key])); + let create_account = RegisterExpr::new(Account::new(id, [key])); submit([create_account], metadata, context).wrap_err("Failed to register account") } } @@ -541,7 +541,7 @@ mod account { condition: Signature(condition), metadata: Metadata(metadata), } = self; - let mint_box = MintBox::new(account, EvaluatesTo::new_unchecked(condition)); + let mint_box = MintExpr::new(account, EvaluatesTo::new_unchecked(condition)); submit([mint_box], metadata, context).wrap_err("Failed to set signature condition") } } @@ -610,7 +610,7 @@ mod account { permission, metadata: Metadata(metadata), } = self; - let grant = GrantBox::new(permission.0, id); + let grant = GrantExpr::new(permission.0, id); submit([grant], metadata, context) .wrap_err("Failed to grant the permission to the account") } @@ -703,7 +703,7 @@ mod asset { if unmintable { asset_definition = asset_definition.mintable_once(); } - let create_asset_definition = RegisterBox::new(asset_definition); + let create_asset_definition = RegisterExpr::new(asset_definition); submit([create_asset_definition], metadata, context) .wrap_err("Failed to register asset") } @@ -734,7 +734,7 @@ mod asset { quantity, metadata: Metadata(metadata), } = self; - let mint_asset = MintBox::new( + let mint_asset = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new(asset, account)), ); @@ -768,7 +768,7 @@ mod asset { quantity, metadata: Metadata(metadata), } = self; - let burn_asset = BurnBox::new( + let burn_asset = BurnExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new(asset, account)), ); @@ -806,7 +806,7 @@ mod asset { quantity, metadata: Metadata(metadata), } = self; - let transfer_asset = TransferBox::new( + let transfer_asset = TransferExpr::new( IdBox::AssetId(AssetId::new(asset_id, from)), quantity.to_value(), IdBox::AccountId(to), @@ -908,7 +908,7 @@ mod peer { key, metadata: Metadata(metadata), } = self; - let register_peer = RegisterBox::new(Peer::new(PeerId::new(&address, &key))); + let register_peer = RegisterExpr::new(Peer::new(PeerId::new(&address, &key))); submit([register_peer], metadata, context).wrap_err("Failed to register peer") } } @@ -934,7 +934,7 @@ mod peer { key, metadata: Metadata(metadata), } = self; - let unregister_peer = UnregisterBox::new(IdBox::PeerId(PeerId::new(&address, &key))); + let unregister_peer = UnregisterExpr::new(IdBox::PeerId(PeerId::new(&address, &key))); submit([unregister_peer], metadata, context).wrap_err("Failed to unregister peer") } } @@ -991,7 +991,7 @@ mod json { reader.read_to_end(&mut raw_content)?; let string_content = String::from_utf8(raw_content)?; - let instructions: Vec = json5::from_str(&string_content)?; + let instructions: Vec = json5::from_str(&string_content)?; submit(instructions, UnlimitedMetadata::new(), context) .wrap_err("Failed to submit parsed instructions") } diff --git a/core/benches/blocks/common.rs b/core/benches/blocks/common.rs index 9593d1cf817..8bdbef1a5e7 100644 --- a/core/benches/blocks/common.rs +++ b/core/benches/blocks/common.rs @@ -14,7 +14,7 @@ use iroha_data_model::{ account::Account, asset::{AssetDefinition, AssetDefinitionId}, domain::Domain, - isi::InstructionBox, + isi::InstructionExpr, prelude::*, transaction::TransactionLimits, }; @@ -24,7 +24,7 @@ use serde_json::json; /// Create block pub fn create_block( wsv: &mut WorldStateView, - instructions: Vec, + instructions: Vec, account_id: AccountId, key_pair: KeyPair, ) -> CommittedBlock { @@ -59,13 +59,13 @@ pub fn populate_wsv( accounts_per_domain: usize, assets_per_domain: usize, owner_id: &AccountId, -) -> Result> { - let mut instructions: Vec = Vec::new(); +) -> Result> { + let mut instructions: Vec = Vec::new(); for i in 0..domains { let domain_id = DomainId::from_str(&i.to_string())?; let domain = Domain::new(domain_id.clone()); - instructions.push(RegisterBox::new(domain).into()); - let can_unregister_domain = GrantBox::new( + instructions.push(RegisterExpr::new(domain).into()); + let can_unregister_domain = GrantExpr::new( PermissionToken::new( "CanUnregisterDomain".parse().unwrap(), &json!({ "domain_id": domain_id.clone() }), @@ -76,8 +76,8 @@ pub fn populate_wsv( for j in 0..accounts_per_domain { let account_id = AccountId::new(Name::from_str(&j.to_string())?, domain_id.clone()); let account = Account::new(account_id.clone(), []); - instructions.push(RegisterBox::new(account).into()); - let can_unregister_account = GrantBox::new( + instructions.push(RegisterExpr::new(account).into()); + let can_unregister_account = GrantExpr::new( PermissionToken::new( "CanUnregisterAccount".parse().unwrap(), &json!({ "account_id": account_id.clone() }), @@ -93,8 +93,8 @@ pub fn populate_wsv( asset_definition_id.clone(), iroha_data_model::asset::AssetValueType::Quantity, ); - instructions.push(RegisterBox::new(asset_definition).into()); - let can_unregister_asset_definition = GrantBox::new( + instructions.push(RegisterExpr::new(asset_definition).into()); + let can_unregister_asset_definition = GrantExpr::new( PermissionToken::new( "CanUnregisterAssetDefinition".parse().unwrap(), &json!({ "asset_definition_id": asset_definition_id }), @@ -112,25 +112,25 @@ pub fn delete_every_nth( accounts_per_domain: usize, assets_per_domain: usize, nth: usize, -) -> Result> { - let mut instructions: Vec = Vec::new(); +) -> Result> { + let mut instructions: Vec = Vec::new(); for i in 0..domains { let domain_id = DomainId::from_str(&i.to_string())?; if i % nth == 0 { - instructions.push(UnregisterBox::new(domain_id.clone()).into()); + instructions.push(UnregisterExpr::new(domain_id.clone()).into()); } else { for j in 0..accounts_per_domain { if j % nth == 0 { let account_id = AccountId::new(Name::from_str(&j.to_string())?, domain_id.clone()); - instructions.push(UnregisterBox::new(account_id.clone()).into()); + instructions.push(UnregisterExpr::new(account_id.clone()).into()); } } for k in 0..assets_per_domain { if k % nth == 0 { let asset_definition_id = AssetDefinitionId::new(Name::from_str(&k.to_string())?, domain_id.clone()); - instructions.push(UnregisterBox::new(asset_definition_id).into()); + instructions.push(UnregisterExpr::new(asset_definition_id).into()); } } } @@ -143,19 +143,19 @@ pub fn restore_every_nth( accounts_per_domain: usize, assets_per_domain: usize, nth: usize, -) -> Result> { - let mut instructions: Vec = Vec::new(); +) -> Result> { + let mut instructions: Vec = Vec::new(); for i in 0..domains { let domain_id = DomainId::from_str(&i.to_string())?; if i % nth == 0 { let domain = Domain::new(domain_id.clone()); - instructions.push(RegisterBox::new(domain).into()); + instructions.push(RegisterExpr::new(domain).into()); } for j in 0..accounts_per_domain { if j % nth == 0 || i % nth == 0 { let account_id = AccountId::new(Name::from_str(&j.to_string())?, domain_id.clone()); let account = Account::new(account_id.clone(), []); - instructions.push(RegisterBox::new(account).into()); + instructions.push(RegisterExpr::new(account).into()); } } for k in 0..assets_per_domain { @@ -166,7 +166,7 @@ pub fn restore_every_nth( asset_definition_id, iroha_data_model::asset::AssetValueType::Quantity, ); - instructions.push(RegisterBox::new(asset_definition).into()); + instructions.push(RegisterExpr::new(asset_definition).into()); } } } @@ -182,11 +182,11 @@ pub fn build_wsv(account_id: &AccountId, key_pair: &KeyPair) -> WorldStateView { { let domain = Domain::new(account_id.domain_id.clone()); - RegisterBox::new(domain) + RegisterExpr::new(domain) .execute(account_id, &mut wsv) .expect("Failed to register domain"); let account = Account::new(account_id.clone(), [key_pair.public_key().clone()]); - RegisterBox::new(account) + RegisterExpr::new(account) .execute(account_id, &mut wsv) .expect("Failed to register account"); } @@ -197,7 +197,7 @@ pub fn build_wsv(account_id: &AccountId, key_pair: &KeyPair) -> WorldStateView { let wasm = std::fs::read(&path_to_validator) .unwrap_or_else(|_| panic!("Failed to read file: {}", path_to_validator.display())); let validator = Validator::new(WasmSmartContract::from_compiled(wasm)); - UpgradeBox::new(validator) + UpgradeExpr::new(validator) .execute(account_id, &mut wsv) .expect("Failed to load validator"); } diff --git a/core/benches/blocks/validate_blocks.rs b/core/benches/blocks/validate_blocks.rs index f5c1dcbc4d2..129d14298a1 100644 --- a/core/benches/blocks/validate_blocks.rs +++ b/core/benches/blocks/validate_blocks.rs @@ -2,7 +2,7 @@ use eyre::Result; use iroha_core::prelude::*; -use iroha_data_model::{isi::InstructionBox, prelude::*}; +use iroha_data_model::{isi::InstructionExpr, prelude::*}; #[path = "./common.rs"] mod common; @@ -12,7 +12,7 @@ use common::*; #[derive(Clone)] pub struct WsvValidateBlocks { wsv: WorldStateView, - instructions: Vec>, + instructions: Vec>, key_pair: KeyPair, account_id: AccountId, } diff --git a/core/benches/kura.rs b/core/benches/kura.rs index c3874bd8a59..eff64c3ba29 100644 --- a/core/benches/kura.rs +++ b/core/benches/kura.rs @@ -21,7 +21,7 @@ async fn measure_block_size_for_n_validators(n_validators: u32) { let bob_id = AccountId::from_str("bob@test").expect("tested"); let xor_id = AssetDefinitionId::from_str("xor#test").expect("tested"); let alice_xor_id = AssetId::new(xor_id, alice_id); - let transfer = TransferBox::new( + let transfer = TransferExpr::new( IdBox::AssetId(alice_xor_id), 10_u32.to_value(), IdBox::AccountId(bob_id), diff --git a/core/benches/validation.rs b/core/benches/validation.rs index 3d9211968ec..4e2af6e771e 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -25,12 +25,12 @@ const TRANSACTION_LIMITS: TransactionLimits = TransactionLimits { fn build_test_transaction(keys: KeyPair) -> SignedTransaction { let domain_name = "domain"; let domain_id = DomainId::from_str(domain_name).expect("does not panic"); - let create_domain = RegisterBox::new(Domain::new(domain_id)); + let create_domain = RegisterExpr::new(Domain::new(domain_id)); let account_name = "account"; let (public_key, _) = KeyPair::generate() .expect("Failed to generate KeyPair.") .into(); - let create_account = RegisterBox::new(Account::new( + let create_account = RegisterExpr::new(Account::new( AccountId::new( account_name.parse().expect("Valid"), domain_name.parse().expect("Valid"), @@ -41,7 +41,7 @@ fn build_test_transaction(keys: KeyPair) -> SignedTransaction { "xor".parse().expect("Valid"), domain_name.parse().expect("Valid"), ); - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id)); + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id)); let instructions = [create_domain, create_account, create_asset]; TransactionBuilder::new(AccountId::new( @@ -79,7 +79,7 @@ fn build_test_and_transient_wsv(keys: KeyPair) -> WorldStateView { .unwrap_or_else(|_| panic!("Failed to read file: {}", path_to_validator.display())); let validator = Validator::new(WasmSmartContract::from_compiled(wasm)); let authority = "genesis@genesis".parse().expect("Valid"); - UpgradeBox::new(validator) + UpgradeExpr::new(validator) .execute(&authority, &mut wsv) .expect("Failed to load validator"); } diff --git a/core/src/block.rs b/core/src/block.rs index ff4c1b2fced..b880f428c55 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -742,7 +742,7 @@ mod tests { // Creating an instruction let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let create_asset_definition = - RegisterBox::new(AssetDefinition::quantity(asset_definition_id)); + RegisterExpr::new(AssetDefinition::quantity(asset_definition_id)); // Making two transactions that have the same instruction let transaction_limits = &wsv.transaction_validator().transaction_limits; @@ -784,7 +784,7 @@ mod tests { // Creating an instruction let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); let create_asset_definition = - RegisterBox::new(AssetDefinition::quantity(asset_definition_id.clone())); + RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); // Making two transactions that have the same instruction let transaction_limits = &wsv.transaction_validator().transaction_limits; @@ -797,12 +797,12 @@ mod tests { let quantity: u32 = 200; let fail_quantity: u32 = 20; - let fail_mint = MintBox::new( + let fail_mint = MintExpr::new( fail_quantity.to_value(), IdBox::AssetId(AssetId::new(asset_definition_id.clone(), alice_id.clone())), ); - let succeed_mint = MintBox::new( + let succeed_mint = MintExpr::new( quantity.to_value(), IdBox::AssetId(AssetId::new(asset_definition_id, alice_id.clone())), ); @@ -853,14 +853,14 @@ mod tests { let transaction_limits = &wsv.transaction_validator().transaction_limits; let domain_id = DomainId::from_str("domain").expect("Valid"); - let create_domain = RegisterBox::new(Domain::new(domain_id)); + let create_domain = RegisterExpr::new(Domain::new(domain_id)); let asset_definition_id = AssetDefinitionId::from_str("coin#domain").expect("Valid"); - let create_asset = RegisterBox::new(AssetDefinition::quantity(asset_definition_id)); - let instructions_fail: [InstructionBox; 2] = [ + let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id)); + let instructions_fail: [InstructionExpr; 2] = [ create_domain.clone().into(), - FailBox::new("Always fail").into(), + Fail::new("Always fail").into(), ]; - let instructions_accept: [InstructionBox; 2] = [create_domain.into(), create_asset.into()]; + let instructions_accept: [InstructionExpr; 2] = [create_domain.into(), create_asset.into()]; let tx_fail = TransactionBuilder::new(alice_id.clone()) .with_instructions(instructions_fail) .sign(alice_keys.clone()) @@ -883,7 +883,7 @@ mod tests { // The first transaction should be rejected assert!( valid_block.payload().transactions[0].error.is_some(), - "The first transaction should be rejected, as it contains `FailBox`." + "The first transaction should be rejected, as it contains `Fail`." ); // The second transaction should be accepted diff --git a/core/src/queue.rs b/core/src/queue.rs index 114262946e8..3d14dc0c628 100644 --- a/core/src/queue.rs +++ b/core/src/queue.rs @@ -398,7 +398,7 @@ mod tests { let message = std::iter::repeat_with(rand::random::) .take(16) .collect(); - let instructions = [FailBox { message }]; + let instructions = [Fail { message }]; let tx = TransactionBuilder::new(AccountId::from_str(account_id).expect("Valid")) .with_instructions(instructions) .sign(key) @@ -507,7 +507,7 @@ mod tests { .build() .expect("Default queue config should always build") }); - let instructions: [InstructionBox; 0] = []; + let instructions: [InstructionExpr; 0] = []; let tx = TransactionBuilder::new("alice@wonderland".parse().expect("Valid")) .with_instructions(instructions); let tx_limits = TransactionLimits { @@ -743,7 +743,7 @@ mod tests { .build() .expect("Default queue config should always build") }); - let instructions = [FailBox { + let instructions = [Fail { message: "expired".to_owned(), }]; let mut tx = diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index c7771229c72..18c63fe99d2 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -131,7 +131,7 @@ pub mod isi { } } - impl Execute for Mint { + impl Execute for Mint { #[metrics(+"mint_account_public_key")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let account_id = self.destination_id; @@ -158,7 +158,7 @@ pub mod isi { } } - impl Execute for Burn { + impl Execute for Burn { #[metrics(+"burn_account_public_key")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let account_id = self.destination_id; @@ -185,7 +185,7 @@ pub mod isi { } } - impl Execute for Mint { + impl Execute for Mint { #[metrics(+"mint_account_signature_check_condition")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let account_id = self.destination_id; @@ -199,6 +199,21 @@ pub mod isi { } } + impl Execute for Transfer { + fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { + wsv.asset_definition_mut(&self.object.id)?.owned_by = self.destination_id.clone(); + + wsv.emit_events(Some(AssetDefinitionEvent::OwnerChanged( + AssetDefinitionOwnerChanged { + asset_definition_id: self.object.id, + new_owner: self.destination_id, + }, + ))); + + Ok(()) + } + } + impl Execute for SetKeyValue { #[metrics(+"set_account_key_value")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { @@ -251,7 +266,7 @@ pub mod isi { } } - impl Execute for Grant { + impl Execute for Grant { #[metrics(+"grant_account_permission")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let account_id = self.destination_id; @@ -290,7 +305,7 @@ pub mod isi { } } - impl Execute for Revoke { + impl Execute for Revoke { #[metrics(+"revoke_account_permission")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let account_id = self.destination_id; @@ -314,7 +329,7 @@ pub mod isi { } } - impl Execute for Grant { + impl Execute for Grant { #[metrics(+"grant_account_role")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let account_id = self.destination_id; @@ -364,7 +379,7 @@ pub mod isi { } } - impl Execute for Revoke { + impl Execute for Revoke { #[metrics(+"revoke_account_role")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let account_id = self.destination_id; diff --git a/core/src/smartcontracts/isi/asset.rs b/core/src/smartcontracts/isi/asset.rs index fd1485dfd31..d3709c6ab59 100644 --- a/core/src/smartcontracts/isi/asset.rs +++ b/core/src/smartcontracts/isi/asset.rs @@ -104,26 +104,11 @@ pub mod isi { } } - impl Execute for Transfer { - fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { - wsv.asset_definition_mut(&self.object.id)?.owned_by = self.destination_id.clone(); - - wsv.emit_events(Some(AssetDefinitionEvent::OwnerChanged( - AssetDefinitionOwnerChanged { - asset_definition_id: self.object.id, - new_owner: self.destination_id, - }, - ))); - - Ok(()) - } - } - macro_rules! impl_mint { ($ty:ty, $metrics:literal) => { impl InnerMint for $ty {} - impl Execute for Mint { + impl Execute for Mint<$ty, Asset> { #[metrics(+$metrics)] fn execute( self, @@ -140,7 +125,7 @@ pub mod isi { ($ty:ty, $metrics:literal) => { impl InnerBurn for $ty {} - impl Execute for Burn { + impl Execute for Burn<$ty, Asset> { #[metrics(+$metrics)] fn execute( self, @@ -185,7 +170,7 @@ pub mod isi { /// Trait for blanket mint implementation. trait InnerMint { fn execute( - mint: Mint, + mint: Mint, _authority: &AccountId, wsv: &mut WorldStateView, ) -> Result<(), Error> @@ -243,7 +228,7 @@ pub mod isi { /// Trait for blanket burn implementation. trait InnerBurn { fn execute( - burn: Burn, + burn: Burn, _authority: &AccountId, wsv: &mut WorldStateView, ) -> Result<(), Error> diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index a5ce89639ac..ba59338c9fa 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -1,5 +1,5 @@ //! This module contains enumeration of all possible Iroha Special -//! Instructions [`InstructionBox`], generic instruction types and related +//! Instructions [`InstructionExpr`], generic instruction types and related //! implementations. #![allow( clippy::arithmetic_side_effects, @@ -36,7 +36,7 @@ pub trait Registrable { fn build(self, authority: &AccountId) -> Self::Target; } -impl Execute for InstructionBox { +impl Execute for InstructionExpr { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { iroha_logger::debug!(isi=%self, "Executing"); @@ -44,7 +44,7 @@ impl Execute for InstructionBox { ($($isi:ident),+ $(,)?) => { match self { $( - InstructionBox::$isi(isi) => isi.execute(authority, wsv), )+ + InstructionExpr::$isi(isi) => isi.execute(authority, wsv), )+ } }; } @@ -72,7 +72,7 @@ impl Execute for InstructionBox { } } -impl Execute for RegisterBox { +impl Execute for RegisterExpr { #[iroha_logger::log(name = "register", skip_all, fields(id))] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let object_id = wsv.evaluate(&self.object)?; @@ -96,7 +96,7 @@ impl Execute for RegisterBox { } } -impl Execute for UnregisterBox { +impl Execute for UnregisterExpr { #[iroha_logger::log(name = "unregister", skip_all, fields(id))] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let object_id = wsv.evaluate(&self.object_id)?; @@ -125,7 +125,7 @@ impl Execute for UnregisterBox { } } -impl Execute for MintBox { +impl Execute for MintExpr { #[iroha_logger::log(name = "Mint", skip_all, fields(destination))] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let destination_id = wsv.evaluate(&self.destination_id)?; @@ -134,42 +134,42 @@ impl Execute for MintBox { iroha_logger::trace!(?object, %authority); match (destination_id, object) { (IdBox::AssetId(destination_id), Value::Numeric(NumericValue::U32(object))) => { - Mint:: { + Mint:: { object, destination_id, } .execute(authority, wsv) } (IdBox::AssetId(destination_id), Value::Numeric(NumericValue::U128(object))) => { - Mint:: { + Mint:: { object, destination_id, } .execute(authority, wsv) } (IdBox::AssetId(destination_id), Value::Numeric(NumericValue::Fixed(object))) => { - Mint:: { + Mint:: { object, destination_id, } .execute(authority, wsv) } (IdBox::AccountId(destination_id), Value::PublicKey(object)) => { - Mint:: { + Mint:: { object, destination_id, } .execute(authority, wsv) } (IdBox::AccountId(destination_id), Value::SignatureCheckCondition(object)) => { - Mint:: { + Mint:: { object, destination_id, } .execute(authority, wsv) } (IdBox::TriggerId(destination_id), Value::Numeric(NumericValue::U32(object))) => { - Mint::, u32> { + Mint::> { object, destination_id, } @@ -180,7 +180,7 @@ impl Execute for MintBox { } } -impl Execute for BurnBox { +impl Execute for BurnExpr { #[iroha_logger::log(name = "burn", skip_all, fields(destination))] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let destination_id = wsv.evaluate(&self.destination_id)?; @@ -189,7 +189,7 @@ impl Execute for BurnBox { iroha_logger::trace!(?object, %authority); match (destination_id, object) { (IdBox::AssetId(destination_id), Value::Numeric(NumericValue::U32(object))) => { - Burn:: { + Burn:: { object, destination_id, } @@ -219,7 +219,7 @@ impl Execute for BurnBox { } } -impl Execute for TransferBox { +impl Execute for TransferExpr { #[iroha_logger::log(name = "transfer", skip_all, fields(from, to))] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let (IdBox::AssetId(source_id), IdBox::AccountId(destination_id)) = ( @@ -229,12 +229,12 @@ impl Execute for TransferBox { return Err(Error::Evaluate(InstructionType::Transfer.into())); }; - let value = wsv.evaluate(&self.object)?; + let object = wsv.evaluate(&self.object)?; Span::current().record("from", source_id.to_string()); Span::current().record("to", destination_id.to_string()); - iroha_logger::trace!(%value, %authority); + iroha_logger::trace!(%object, %authority); - match value { + match object { Value::Numeric(NumericValue::U32(object)) => Transfer { source_id, object, @@ -258,7 +258,7 @@ impl Execute for TransferBox { } } -impl Execute for SetKeyValueBox { +impl Execute for SetKeyValueExpr { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let key = wsv.evaluate(&self.key)?; let value = wsv.evaluate(&self.value)?; @@ -293,7 +293,7 @@ impl Execute for SetKeyValueBox { } } -impl Execute for RemoveKeyValueBox { +impl Execute for RemoveKeyValueExpr { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let key = wsv.evaluate(&self.key)?; iroha_logger::trace!(?key, %authority); @@ -312,7 +312,7 @@ impl Execute for RemoveKeyValueBox { } } -impl Execute for Conditional { +impl Execute for ConditionalExpr { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { iroha_logger::trace!(?self); if wsv.evaluate(&self.condition)? { @@ -324,7 +324,7 @@ impl Execute for Conditional { } } -impl Execute for Pair { +impl Execute for PairExpr { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { iroha_logger::trace!(?self); @@ -334,7 +334,7 @@ impl Execute for Pair { } } -impl Execute for SequenceBox { +impl Execute for SequenceExpr { #[iroha_logger::log(skip_all, name = "Sequence", fields(count))] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { Span::current().record("count", self.instructions.len()); @@ -346,7 +346,7 @@ impl Execute for SequenceBox { } } -impl Execute for FailBox { +impl Execute for Fail { fn execute(self, _authority: &AccountId, _wsv: &mut WorldStateView) -> Result<(), Error> { iroha_logger::trace!(?self); @@ -354,75 +354,67 @@ impl Execute for FailBox { } } -impl Execute for GrantBox { +impl Execute for GrantExpr { #[iroha_logger::log(name = "grant", skip_all, fields(object))] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let destination_id = wsv.evaluate(&self.destination_id)?; let object = wsv.evaluate(&self.object)?; Span::current().record("object", &object.to_string()); iroha_logger::trace!(%destination_id, %authority); - match (destination_id, object) { - (IdBox::AccountId(destination_id), Value::PermissionToken(object)) => { - Grant:: { - object, - destination_id, - } - .execute(authority, wsv) + match object { + Value::PermissionToken(object) => Grant:: { + object, + destination_id, } - (IdBox::AccountId(destination_id), Value::Id(IdBox::RoleId(object))) => { - Grant:: { - object, - destination_id, - } - .execute(authority, wsv) + .execute(authority, wsv), + Value::Id(IdBox::RoleId(object)) => Grant:: { + object, + destination_id, } + .execute(authority, wsv), _ => Err(Error::Evaluate(InstructionType::Grant.into())), } } } -impl Execute for RevokeBox { +impl Execute for RevokeExpr { #[iroha_logger::log(name = "revoke", skip_all, fields(object))] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let destination_id = wsv.evaluate(&self.destination_id)?; let object = wsv.evaluate(&self.object)?; Span::current().record("object", &object.to_string()); iroha_logger::trace!(?destination_id, ?object, %authority); - match (destination_id, object) { - (IdBox::AccountId(destination_id), Value::PermissionToken(object)) => { - Revoke:: { - object, - destination_id, - } - .execute(authority, wsv) + match object { + Value::PermissionToken(object) => Revoke:: { + object, + destination_id, } - (IdBox::AccountId(destination_id), Value::Id(IdBox::RoleId(object))) => { - Revoke:: { - object, - destination_id, - } - .execute(authority, wsv) + .execute(authority, wsv), + Value::Id(IdBox::RoleId(object)) => Revoke:: { + object, + destination_id, } + .execute(authority, wsv), _ => Err(Error::Evaluate(InstructionType::Revoke.into())), } } } -impl Execute for SetParameterBox { +impl Execute for SetParameterExpr { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let parameter = wsv.evaluate(&self.parameter)?; SetParameter { parameter }.execute(authority, wsv) } } -impl Execute for NewParameterBox { +impl Execute for NewParameterExpr { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let parameter = wsv.evaluate(&self.parameter)?; NewParameter { parameter }.execute(authority, wsv) } } -impl Execute for UpgradeBox { +impl Execute for UpgradeExpr { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let object = wsv.evaluate(&self.object)?; match object { @@ -433,7 +425,7 @@ impl Execute for UpgradeBox { } } -impl Execute for LogBox { +impl Execute for LogExpr { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let level = wsv.evaluate(&self.level)?; let msg = wsv.evaluate(&self.msg)?; @@ -466,11 +458,11 @@ mod tests { let account_id = AccountId::from_str("alice@wonderland")?; let (public_key, _) = KeyPair::generate()?.into(); let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; - RegisterBox::new(Domain::new(DomainId::from_str("wonderland")?)) + RegisterExpr::new(Domain::new(DomainId::from_str("wonderland")?)) .execute(&genesis_account_id, &mut wsv)?; - RegisterBox::new(Account::new(account_id, [public_key])) + RegisterExpr::new(Account::new(account_id, [public_key])) .execute(&genesis_account_id, &mut wsv)?; - RegisterBox::new(AssetDefinition::store(asset_definition_id)) + RegisterExpr::new(AssetDefinition::store(asset_definition_id)) .execute(&genesis_account_id, &mut wsv)?; Ok(wsv) } @@ -482,7 +474,7 @@ mod tests { let account_id = AccountId::from_str("alice@wonderland")?; let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; let asset_id = AssetId::new(asset_definition_id, account_id.clone()); - SetKeyValueBox::new( + SetKeyValueExpr::new( IdBox::from(asset_id.clone()), Name::from_str("Bytes")?, vec![1_u32, 2_u32, 3_u32], @@ -509,7 +501,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let mut wsv = wsv_with_test_domains(&kura)?; let account_id = AccountId::from_str("alice@wonderland")?; - SetKeyValueBox::new( + SetKeyValueExpr::new( IdBox::from(account_id.clone()), Name::from_str("Bytes")?, vec![1_u32, 2_u32, 3_u32], @@ -538,7 +530,7 @@ mod tests { let mut wsv = wsv_with_test_domains(&kura)?; let definition_id = AssetDefinitionId::from_str("rose#wonderland")?; let account_id = AccountId::from_str("alice@wonderland")?; - SetKeyValueBox::new( + SetKeyValueExpr::new( IdBox::from(definition_id.clone()), Name::from_str("Bytes")?, vec![1_u32, 2_u32, 3_u32], @@ -566,7 +558,7 @@ mod tests { let mut wsv = wsv_with_test_domains(&kura)?; let domain_id = DomainId::from_str("wonderland")?; let account_id = AccountId::from_str("alice@wonderland")?; - SetKeyValueBox::new( + SetKeyValueExpr::new( IdBox::from(domain_id.clone()), Name::from_str("Bytes")?, vec![1_u32, 2_u32, 3_u32], @@ -596,7 +588,7 @@ mod tests { let trigger_id = TriggerId::from_str("test_trigger_id")?; assert!(matches!( - ExecuteTriggerBox::new(trigger_id) + ExecuteTriggerExpr::new(trigger_id) .execute(&account_id, &mut wsv) .expect_err("Error expected"), Error::Find(_) @@ -618,14 +610,14 @@ mod tests { .expect("Failed to generate KeyPair") .into(); let register_account = - RegisterBox::new(Account::new(fake_account_id.clone(), [public_key])); + RegisterExpr::new(Account::new(fake_account_id.clone(), [public_key])); register_account.execute(&account_id, &mut wsv)?; // register the trigger - let register_trigger = RegisterBox::new(Trigger::new( + let register_trigger = RegisterExpr::new(Trigger::new( trigger_id.clone(), Action::new( - Vec::::new(), + Vec::::new(), Repeats::Indefinitely, account_id.clone(), TriggeringFilterBox::ExecuteTrigger(ExecuteTriggerEventFilter::new( @@ -638,11 +630,11 @@ mod tests { register_trigger.execute(&account_id, &mut wsv)?; // execute with the valid account - ExecuteTriggerBox::new(trigger_id.clone()).execute(&account_id, &mut wsv)?; + ExecuteTriggerExpr::new(trigger_id.clone()).execute(&account_id, &mut wsv)?; // execute with the fake account assert!(matches!( - ExecuteTriggerBox::new(trigger_id) + ExecuteTriggerExpr::new(trigger_id) .execute(&fake_account_id, &mut wsv) .expect_err("Error expected"), Error::InvariantViolation(_) diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index cd15a888f90..988474ef6d7 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -271,14 +271,14 @@ mod tests { wsv.config.transaction_limits = limits; let valid_tx = { - let instructions: [InstructionBox; 0] = []; + let instructions: [InstructionExpr; 0] = []; let tx = TransactionBuilder::new(ALICE_ID.clone()) .with_instructions(instructions) .sign(ALICE_KEYS.clone())?; AcceptedTransaction::accept(tx, &limits)? }; let invalid_tx = { - let isi = FailBox::new("fail"); + let isi = Fail::new("fail"); let tx = TransactionBuilder::new(ALICE_ID.clone()) .with_instructions([isi.clone(), isi]) .sign(ALICE_KEYS.clone())?; @@ -416,7 +416,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(world_with_test_domains(), kura.clone()); - let instructions: [InstructionBox; 0] = []; + let instructions: [InstructionExpr; 0] = []; let tx = TransactionBuilder::new(ALICE_ID.clone()) .with_instructions(instructions) .sign(ALICE_KEYS.clone())?; @@ -435,7 +435,7 @@ mod tests { kura.store_block(vcb); let unapplied_tx = TransactionBuilder::new(ALICE_ID.clone()) - .with_instructions([UnregisterBox::new( + .with_instructions([UnregisterExpr::new( "account@domain".parse::().unwrap(), )]) .sign(ALICE_KEYS.clone())?; diff --git a/core/src/smartcontracts/isi/triggers/mod.rs b/core/src/smartcontracts/isi/triggers/mod.rs index 6a9a1a6ad8c..2b35c7e1b0d 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -101,7 +101,7 @@ pub mod isi { } } - impl Execute for Mint, u32> { + impl Execute for Mint> { #[metrics(+"mint_trigger_repetitions")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let id = self.destination_id; @@ -133,7 +133,7 @@ pub mod isi { } } - impl Execute for Burn, u32> { + impl Execute for Burn> { #[metrics(+"burn_trigger_repetitions")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let trigger = self.destination_id; @@ -155,7 +155,7 @@ pub mod isi { } } - impl Execute for ExecuteTriggerBox { + impl Execute for ExecuteTriggerExpr { #[metrics(+"execute_trigger")] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let id = wsv.evaluate(&self.trigger_id)?; diff --git a/core/src/smartcontracts/isi/triggers/set.rs b/core/src/smartcontracts/isi/triggers/set.rs index 1897ae48081..a87217bc188 100644 --- a/core/src/smartcontracts/isi/triggers/set.rs +++ b/core/src/smartcontracts/isi/triggers/set.rs @@ -718,7 +718,7 @@ pub enum LoadedExecutable { /// Loaded WASM Wasm(LoadedWasm), /// Vector of ISI - Instructions(Vec), + Instructions(Vec), } impl core::fmt::Debug for LoadedExecutable { diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index 87c0a95e805..97bbdf43b69 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -160,7 +160,7 @@ pub mod isi { } for account_id in accounts_with_role { - let revoke: Revoke = Revoke { + let revoke = Revoke { object: role_id.clone(), destination_id: account_id, }; diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 289b8f4517c..62028abdf0e 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -13,7 +13,7 @@ use iroha_config::{ }; use iroha_data_model::{ account::AccountId, - isi::InstructionBox, + isi::InstructionExpr, permission::PermissionTokenSchema, prelude::*, validator::{self, MigrationResult}, @@ -49,7 +49,7 @@ mod import_traits { /// Execute `instruction` on host #[codec::wrap_trait_fn] fn execute_instruction( - instruction: InstructionBox, + instruction: InstructionExpr, state: &mut S, ) -> Result<(), ValidationFail>; } @@ -473,7 +473,7 @@ pub mod state { pub type ValidateTransaction<'wrld> = ValidateMut<'wrld, SignedTransaction>; /// State for executing `validate_instruction()` entrypoint of validator - pub type ValidateInstruction<'wrld> = ValidateMut<'wrld, InstructionBox>; + pub type ValidateInstruction<'wrld> = ValidateMut<'wrld, InstructionExpr>; /// State for executing `validate_query()` entrypoint of validator /// @@ -755,7 +755,7 @@ impl Runtime { } fn default_execute_instruction( - instruction: InstructionBox, + instruction: InstructionExpr, state: &mut S, ) -> Result<(), ValidationFail> { debug!(%instruction, "Executing"); @@ -860,7 +860,7 @@ impl<'wrld> import_traits::ExecuteOperations> #[codec::wrap] fn execute_instruction( - instruction: InstructionBox, + instruction: InstructionExpr, state: &mut state::SmartContract<'wrld>, ) -> Result<(), ValidationFail> { if let Some(limits_validator) = state.limits_validator.as_mut() { @@ -926,7 +926,7 @@ impl<'wrld> import_traits::ExecuteOperations> #[codec::wrap] fn execute_instruction( - instruction: InstructionBox, + instruction: InstructionExpr, state: &mut state::Trigger<'wrld>, ) -> Result<(), ValidationFail> { Self::default_execute_instruction(instruction, state) @@ -959,7 +959,7 @@ where #[codec::wrap] fn execute_instruction( - instruction: InstructionBox, + instruction: InstructionExpr, state: &mut S, ) -> Result<(), ValidationFail> { debug!(%instruction, "Executing as validator"); @@ -1082,7 +1082,7 @@ impl<'wrld> Runtime> { wsv: &'wrld mut WorldStateView, authority: &AccountId, module: &wasmtime::Module, - instruction: InstructionBox, + instruction: InstructionExpr, ) -> Result { let span = wasm_log_span!("Running `validate_instruction()`"); @@ -1197,7 +1197,7 @@ impl<'wrld> import_traits::ExecuteOperations, ) -> Result<(), ValidationFail> { panic!("Validator `validate_query()` entrypoint should not execute instructions") @@ -1657,8 +1657,8 @@ mod tests { let isi_hex = { let new_authority = AccountId::from_str("mad_hatter@wonderland").expect("Valid"); - let register_isi = RegisterBox::new(Account::new(new_authority, [])); - encode_hex(InstructionBox::from(register_isi)) + let register_isi = RegisterExpr::new(Account::new(new_authority, [])); + encode_hex(InstructionExpr::from(register_isi)) }; let wat = format!( @@ -1736,8 +1736,8 @@ mod tests { let isi_hex = { let new_authority = AccountId::from_str("mad_hatter@wonderland").expect("Valid"); - let register_isi = RegisterBox::new(Account::new(new_authority, [])); - encode_hex(InstructionBox::from(register_isi)) + let register_isi = RegisterExpr::new(Account::new(new_authority, [])); + encode_hex(InstructionExpr::from(register_isi)) }; let wat = format!( @@ -1784,8 +1784,8 @@ mod tests { let isi_hex = { let new_authority = AccountId::from_str("mad_hatter@wonderland").expect("Valid"); - let register_isi = RegisterBox::new(Account::new(new_authority, [])); - encode_hex(InstructionBox::from(register_isi)) + let register_isi = RegisterExpr::new(Account::new(new_authority, [])); + encode_hex(InstructionExpr::from(register_isi)) }; let wat = format!( diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index 5ec973be3c8..2866fdb7927 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -1183,7 +1183,7 @@ mod tests { // Create "genesis" block // Creating an instruction - let fail_box: InstructionBox = FailBox::new("Dummy isi").into(); + let fail_box: InstructionExpr = Fail::new("Dummy isi").into(); // Making two transactions that have the same instruction let tx = TransactionBuilder::new(alice_id.clone()) @@ -1204,10 +1204,10 @@ mod tests { kura.store_block(genesis); // Making two transactions that have the same instruction - let create_asset_definition1 = RegisterBox::new(AssetDefinition::quantity( + let create_asset_definition1 = RegisterExpr::new(AssetDefinition::quantity( "xor1#wonderland".parse().expect("Valid"), )); - let create_asset_definition2 = RegisterBox::new(AssetDefinition::quantity( + let create_asset_definition2 = RegisterExpr::new(AssetDefinition::quantity( "xor2#wonderland".parse().expect("Valid"), )); diff --git a/core/src/tx.rs b/core/src/tx.rs index 3fe133c9ec4..2ea863f19cf 100644 --- a/core/src/tx.rs +++ b/core/src/tx.rs @@ -44,8 +44,8 @@ pub enum AcceptTransactionFail { UnexpectedGenesisAccountSignature, } -fn instruction_size(isi: &InstructionBox) -> usize { - use InstructionBox::*; +fn instruction_size(isi: &InstructionExpr) -> usize { + use InstructionExpr::*; match isi { Register(isi) => isi.object.len() + 1, @@ -299,12 +299,12 @@ mod tests { fn if_instruction( c: impl Into, - then: InstructionBox, - otherwise: Option, - ) -> InstructionBox { + then: InstructionExpr, + otherwise: Option, + ) -> InstructionExpr { let condition: Expression = c.into(); let condition = EvaluatesTo::new_unchecked(condition); - Conditional { + ConditionalExpr { condition, then, otherwise, @@ -312,8 +312,8 @@ mod tests { .into() } - fn fail() -> InstructionBox { - FailBox { + fn fail() -> InstructionExpr { + Fail { message: String::default(), } .into() @@ -321,7 +321,7 @@ mod tests { #[test] fn len_empty_sequence() { - assert_eq!(instruction_size(&SequenceBox::new(vec![]).into()), 1); + assert_eq!(instruction_size(&SequenceExpr::new(vec![]).into()), 1); } #[test] @@ -334,7 +334,7 @@ mod tests { None, )]; - assert_eq!(instruction_size(&SequenceBox::new(instructions).into()), 4); + assert_eq!(instruction_size(&SequenceExpr::new(instructions).into()), 4); } #[test] @@ -351,6 +351,6 @@ mod tests { fail(), ]; - assert_eq!(instruction_size(&SequenceBox::new(instructions).into()), 7); + assert_eq!(instruction_size(&SequenceExpr::new(instructions).into()), 7); } } diff --git a/core/src/validator.rs b/core/src/validator.rs index c44d3611db9..e6eef59580c 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -3,7 +3,7 @@ use derive_more::DebugCustom; use iroha_data_model::{ account::AccountId, - isi::InstructionBox, + isi::InstructionExpr, query::QueryBox, transaction::{Executable, SignedTransaction}, validator as data_model_validator, ValidationFail, @@ -169,7 +169,7 @@ impl Validator { } } - /// Validate [`InstructionBox`]. + /// Validate [`InstructionExpr`]. /// /// # Errors /// @@ -180,7 +180,7 @@ impl Validator { &self, wsv: &mut WorldStateView, authority: &AccountId, - instruction: InstructionBox, + instruction: InstructionExpr, ) -> Result<(), ValidationFail> { trace!("Running instruction validation"); diff --git a/core/src/wsv.rs b/core/src/wsv.rs index 3bfe40f127b..33e271dc1f6 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -582,7 +582,7 @@ impl WorldStateView { fn process_instructions( &mut self, - instructions: impl IntoIterator, + instructions: impl IntoIterator, authority: &AccountId, ) -> Result<()> { instructions.into_iter().try_for_each(|instruction| { @@ -970,7 +970,7 @@ impl WorldStateView { let account = domain .accounts .get(id) - .ok_or(QueryExecutionFail::Unauthorized)?; + .ok_or(FindError::Account(id.clone()))?; Ok(f(account)) } diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 2589745665e..73cd37cf123 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -120,7 +120,7 @@ impl TestGenesis for GenesisNetwork { upgrade_validator_permission, ] { first_transaction - .append_instruction(GrantBox::new(permission, alice_id.clone()).into()); + .append_instruction(GrantExpr::new(permission, alice_id.clone()).into()); } if submit_genesis { @@ -217,7 +217,7 @@ impl Network { time::sleep(Configuration::pipeline_time() + Configuration::block_sync_gossip_time()).await; - let add_peer = RegisterBox::new(DataModelPeer::new(peer.id.clone())); + let add_peer = RegisterExpr::new(DataModelPeer::new(peer.id.clone())); genesis_client .submit(add_peer) .expect("Failed to add new peer."); @@ -728,7 +728,7 @@ pub trait TestClient: Sized { /// If predicate is not satisfied, after maximum retries. fn submit_all_till( &self, - instructions: Vec, + instructions: Vec, request: R, f: impl Fn(::Target) -> bool, ) -> eyre::Result<()> @@ -869,7 +869,7 @@ impl TestClient for Client { fn submit_all_till( &self, - instructions: Vec, + instructions: Vec, request: R, f: impl Fn(::Target) -> bool, ) -> eyre::Result<()> diff --git a/data_model/src/isi.rs b/data_model/src/isi.rs index 39ee4422ff6..3424fa5bf41 100644 --- a/data_model/src/isi.rs +++ b/data_model/src/isi.rs @@ -19,7 +19,7 @@ use super::{expression::EvaluatesTo, prelude::*, IdBox, RegistrableBox, Value}; use crate::{seal, Level, Registered}; /// Marker trait designating instruction -pub trait Instruction: Into + seal::Sealed {} +pub trait Instruction: Into + seal::Sealed {} macro_rules! isi { ($($meta:meta)* $item:item) => { @@ -79,67 +79,67 @@ pub mod model { )] #[ffi_type(opaque)] #[allow(missing_docs)] - pub enum InstructionBox { + pub enum InstructionExpr { #[debug(fmt = "{_0:?}")] - Register(RegisterBox), + Register(RegisterExpr), #[debug(fmt = "{_0:?}")] - Unregister(UnregisterBox), + Unregister(UnregisterExpr), #[debug(fmt = "{_0:?}")] - Mint(MintBox), + Mint(MintExpr), #[debug(fmt = "{_0:?}")] - Burn(BurnBox), + Burn(BurnExpr), #[debug(fmt = "{_0:?}")] - Transfer(TransferBox), + Transfer(TransferExpr), #[debug(fmt = "{_0:?}")] - If(Box), + If(Box), #[debug(fmt = "{_0:?}")] - Pair(Box), + Pair(Box), #[debug(fmt = "{_0:?}")] - Sequence(SequenceBox), + Sequence(SequenceExpr), #[debug(fmt = "{_0:?}")] - SetKeyValue(SetKeyValueBox), + SetKeyValue(SetKeyValueExpr), #[debug(fmt = "{_0:?}")] - RemoveKeyValue(RemoveKeyValueBox), + RemoveKeyValue(RemoveKeyValueExpr), #[debug(fmt = "{_0:?}")] - Grant(GrantBox), + Grant(GrantExpr), #[debug(fmt = "{_0:?}")] - Revoke(RevokeBox), + Revoke(RevokeExpr), #[debug(fmt = "{_0:?}")] - ExecuteTrigger(ExecuteTriggerBox), + ExecuteTrigger(ExecuteTriggerExpr), #[debug(fmt = "{_0:?}")] - SetParameter(SetParameterBox), + SetParameter(SetParameterExpr), #[debug(fmt = "{_0:?}")] - NewParameter(NewParameterBox), - Upgrade(UpgradeBox), + NewParameter(NewParameterExpr), + Upgrade(UpgradeExpr), /// `Log` variant. - Log(LogBox), + Log(LogExpr), #[debug(fmt = "{_0:?}")] - Fail(FailBox), - } - - impl Instruction for InstructionBox {} - - impl Instruction for SetKeyValueBox {} - impl Instruction for RemoveKeyValueBox {} - impl Instruction for RegisterBox {} - impl Instruction for UnregisterBox {} - impl Instruction for MintBox {} - impl Instruction for BurnBox {} - impl Instruction for TransferBox {} - impl Instruction for GrantBox {} - impl Instruction for RevokeBox {} - impl Instruction for SetParameterBox {} - impl Instruction for NewParameterBox {} - impl Instruction for UpgradeBox {} - impl Instruction for ExecuteTriggerBox {} - impl Instruction for FailBox {} - impl Instruction for LogBox {} + Fail(Fail), + } + + impl Instruction for InstructionExpr {} + + impl Instruction for SetKeyValueExpr {} + impl Instruction for RemoveKeyValueExpr {} + impl Instruction for RegisterExpr {} + impl Instruction for UnregisterExpr {} + impl Instruction for MintExpr {} + impl Instruction for BurnExpr {} + impl Instruction for TransferExpr {} + impl Instruction for GrantExpr {} + impl Instruction for RevokeExpr {} + impl Instruction for SetParameterExpr {} + impl Instruction for NewParameterExpr {} + impl Instruction for UpgradeExpr {} + impl Instruction for ExecuteTriggerExpr {} + impl Instruction for LogExpr {} + impl Instruction for Fail {} // Composite instructions - impl Instruction for SequenceBox {} - impl Instruction for Conditional {} - impl Instruction for Pair {} + impl Instruction for ConditionalExpr {} + impl Instruction for SequenceExpr {} + impl Instruction for PairExpr {} } mod transparent { @@ -185,7 +185,7 @@ mod transparent { /// Generic instruction for a mint of an object to the identifiable destination. #[derive(Debug, Clone)] - pub struct Mint> { + pub struct Mint, D: Identifiable> { /// Object which should be minted. pub object: O, /// Destination object [`Identifiable::Id`]. @@ -194,7 +194,7 @@ mod transparent { /// Generic instruction for a burn of an object to the identifiable destination. #[derive(Debug, Clone)] - pub struct Burn> { + pub struct Burn, D: Identifiable> { /// Object which should be burned. pub object: O, /// Destination object [`Identifiable::Id`]. @@ -214,20 +214,20 @@ mod transparent { /// Generic instruction for granting permission to an entity. #[derive(Debug, Clone)] - pub struct Grant> { + pub struct Grant> { /// Object to grant. pub object: O, /// Entity to which to grant this token. - pub destination_id: D::Id, + pub destination_id: AccountId, } /// Generic instruction for revoking permission from an entity. #[derive(Debug, Clone)] - pub struct Revoke> { + pub struct Revoke> { /// Object to revoke. pub object: O, /// Entity which is being revoked this token from. - pub destination_id: D::Id, + pub destination_id: AccountId, } /// Generic instruction for setting a chain-wide config parameter. @@ -267,43 +267,43 @@ mod transparent { pub level: Level, } - impl From> for SetKeyValueBox { + impl From> for SetKeyValueExpr { fn from(source: SetKeyValue) -> Self { Self::new(source.object_id.into(), source.key, source.value) } } - impl From> for RemoveKeyValueBox { + impl From> for RemoveKeyValueExpr { fn from(source: RemoveKeyValue) -> Self { Self::new(source.object_id.into(), source.key) } } - impl From> for RegisterBox { + impl From> for RegisterExpr { fn from(source: Register) -> Self { Self::new(source.object.into()) } } - impl From> for UnregisterBox { + impl From> for UnregisterExpr { fn from(source: Unregister) -> Self { Self::new(source.object_id.into()) } } - impl> From> for MintBox { - fn from(source: Mint) -> Self { + impl, D: Identifiable> From> for MintExpr { + fn from(source: Mint) -> Self { Self::new(source.object, source.destination_id.into()) } } - impl> From> for BurnBox { - fn from(source: Burn) -> Self { + impl, D: Identifiable> From> for BurnExpr { + fn from(source: Burn) -> Self { Self::new(source.object, source.destination_id.into()) } } - impl, D: Identifiable> From> for TransferBox { + impl, D: Identifiable> From> for TransferExpr { fn from(source: Transfer) -> Self { Self::new( source.source_id.into(), @@ -313,43 +313,43 @@ mod transparent { } } - impl> From> for GrantBox { - fn from(source: Grant) -> Self { - Self::new(source.object, source.destination_id.into()) + impl> From> for GrantExpr { + fn from(source: Grant) -> Self { + Self::new(source.object, source.destination_id) } } - impl> From> for RevokeBox { - fn from(source: Revoke) -> Self { - Self::new(source.object, source.destination_id.into()) + impl> From> for RevokeExpr { + fn from(source: Revoke) -> Self { + Self::new(source.object, source.destination_id) } } - impl From for SetParameterBox { + impl From for SetParameterExpr { fn from(source: SetParameter) -> Self { Self::new(source.parameter) } } - impl From for NewParameterBox { + impl From for NewParameterExpr { fn from(source: NewParameter) -> Self { Self::new(source.parameter) } } - impl From> for UpgradeBox { + impl From> for UpgradeExpr { fn from(source: Upgrade) -> Self { Self::new(source.object) } } - impl From for ExecuteTriggerBox { + impl From for ExecuteTriggerExpr { fn from(source: ExecuteTrigger) -> Self { Self::new(source.trigger_id) } } - impl From for LogBox { + impl From for LogExpr { fn from(source: Log) -> Self { Self::new(source.level, source.msg) } @@ -362,9 +362,9 @@ isi! { #[display(fmt = "SET `{parameter}`")] #[serde(transparent)] #[repr(transparent)] - // SAFETY: `SetParameterBox` has no trap representation in `EvaluatesTo` + // SAFETY: `SetParameterExpr` has no trap representation in `EvaluatesTo` #[ffi_type(unsafe {robust})] - pub struct SetParameterBox { + pub struct SetParameterExpr { /// The configuration parameter being changed. #[serde(flatten)] pub parameter: EvaluatesTo, @@ -377,9 +377,9 @@ isi! { #[display(fmt = "SET `{parameter}`")] #[serde(transparent)] #[repr(transparent)] - // SAFETY: `NewParameterBox` has no trap representation in `EvaluatesTo` + // SAFETY: `NewParameterExpr` has no trap representation in `EvaluatesTo` #[ffi_type(unsafe {robust})] - pub struct NewParameterBox { + pub struct NewParameterExpr { /// The configuration parameter being created. #[serde(flatten)] pub parameter: EvaluatesTo, @@ -391,7 +391,7 @@ isi! { #[derive(Display)] #[display(fmt = "SET `{key}` = `{value}` IN `{object_id}`")] #[ffi_type] - pub struct SetKeyValueBox { + pub struct SetKeyValueExpr { /// Where to set this key value. #[serde(flatten)] pub object_id: EvaluatesTo, @@ -407,7 +407,7 @@ isi! { #[derive(Display)] #[display(fmt = "REMOVE `{key}` from `{object_id}`")] #[ffi_type] - pub struct RemoveKeyValueBox { + pub struct RemoveKeyValueExpr { /// From where to remove this key value. #[serde(flatten)] pub object_id: EvaluatesTo, @@ -422,9 +422,9 @@ isi! { #[display(fmt = "REGISTER `{object}`")] #[serde(transparent)] #[repr(transparent)] - // SAFETY: `RegisterBox` has no trap representation in `EvaluatesTo` + // SAFETY: `RegisterExpr` has no trap representation in `EvaluatesTo` #[ffi_type(unsafe {robust})] - pub struct RegisterBox { + pub struct RegisterExpr { /// The object that should be registered, should be uniquely identifiable by its id. pub object: EvaluatesTo, } @@ -436,9 +436,9 @@ isi! { #[display(fmt = "UNREGISTER `{object_id}`")] #[serde(transparent)] #[repr(transparent)] - // SAFETY: `UnregisterBox` has no trap representation in `EvaluatesTo` + // SAFETY: `UnregisterExpr` has no trap representation in `EvaluatesTo` #[ffi_type(unsafe {robust})] - pub struct UnregisterBox { + pub struct UnregisterExpr { /// The id of the object that should be unregistered. pub object_id: EvaluatesTo, } @@ -449,7 +449,7 @@ isi! { #[derive(Display)] #[display(fmt = "MINT `{object}` TO `{destination_id}`")] #[ffi_type] - pub struct MintBox { + pub struct MintExpr { /// Object to mint. pub object: EvaluatesTo, /// Entity to mint to. @@ -462,7 +462,7 @@ isi! { #[derive(Display)] #[display(fmt = "BURN `{object}` FROM `{destination_id}`")] #[ffi_type] - pub struct BurnBox { + pub struct BurnExpr { /// Object to burn. pub object: EvaluatesTo, /// Entity to burn from. @@ -475,7 +475,7 @@ isi! { #[derive(Display)] #[display(fmt = "TRANSFER `{object}` FROM `{source_id}` TO `{destination_id}`")] #[ffi_type] - pub struct TransferBox { + pub struct TransferExpr { /// Entity to transfer from. pub source_id: EvaluatesTo, /// Object to transfer. @@ -490,11 +490,11 @@ isi! { #[derive(Display)] #[display(fmt = "(`{left_instruction}`, `{right_instruction}`)")] #[ffi_type] - pub struct Pair { + pub struct PairExpr { /// Left instruction - pub left_instruction: InstructionBox, + pub left_instruction: InstructionExpr, /// Right instruction - pub right_instruction: InstructionBox, + pub right_instruction: InstructionExpr, } } @@ -502,15 +502,15 @@ isi! { /// Composite instruction for a sequence of instructions. #[serde(transparent)] #[repr(transparent)] - // SAFETY: `SequenceBox` has no trap representation in `Vec` + // SAFETY: `SequenceExpr` has no trap representation in `Vec` #[ffi_type(unsafe {robust})] - pub struct SequenceBox { + pub struct SequenceExpr { /// Sequence of Iroha Special Instructions to execute. - pub instructions: Vec, + pub instructions: Vec, } } -impl core::fmt::Display for SequenceBox { +impl core::fmt::Display for SequenceExpr { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "SEQUENCE [")?; let mut first = true; @@ -529,17 +529,17 @@ impl core::fmt::Display for SequenceBox { isi! { /// Composite instruction for a conditional execution of other instructions. #[ffi_type] - pub struct Conditional { + pub struct ConditionalExpr { /// Condition to be checked. pub condition: EvaluatesTo, /// Instruction to be executed if condition pass. - pub then: InstructionBox, + pub then: InstructionExpr, /// Optional instruction to be executed if condition fail. - pub otherwise: Option, + pub otherwise: Option, } } -impl core::fmt::Display for Conditional { +impl core::fmt::Display for ConditionalExpr { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "IF `{}` THEN `{}`", self.condition, self.then)?; if let Some(otherwise) = &self.otherwise { @@ -558,7 +558,7 @@ isi! { #[repr(transparent)] // SAFETY: `Fail` has no trap representation in `String` #[ffi_type(unsafe {robust})] - pub struct FailBox { + pub struct Fail { /// Message to submit. pub message: String, } @@ -569,11 +569,11 @@ isi! { #[derive(Display)] #[display(fmt = "GRANT `{object}` TO `{destination_id}`")] #[ffi_type] - pub struct GrantBox { + pub struct GrantExpr { /// Object to grant. pub object: EvaluatesTo, - /// Entity to which to grant this token. - pub destination_id: EvaluatesTo, + /// Account to which to grant this object. + pub destination_id: EvaluatesTo, } } @@ -582,11 +582,11 @@ isi! { #[derive(Display)] #[display(fmt = "REVOKE `{object}` FROM `{destination_id}`")] #[ffi_type] - pub struct RevokeBox { - /// Object to grant. + pub struct RevokeExpr { + /// Object to revoke. pub object: EvaluatesTo, - /// Entity to which to grant this token. - pub destination_id: EvaluatesTo, + /// Account to which to revoke this object from. + pub destination_id: EvaluatesTo, } } @@ -596,9 +596,9 @@ isi! { #[display(fmt = "EXECUTE `{trigger_id}`")] #[serde(transparent)] #[repr(transparent)] - // SAFETY: `ExecuteTriggerBox` has no trap representation in `TriggerId` + // SAFETY: `ExecuteTriggerExpr` has no trap representation in `TriggerId` #[ffi_type(unsafe {robust})] - pub struct ExecuteTriggerBox { + pub struct ExecuteTriggerExpr { /// Id of a trigger to execute pub trigger_id: EvaluatesTo, } @@ -610,9 +610,9 @@ isi! { #[display(fmt = "UPGRADE `{object}`")] #[serde(transparent)] #[repr(transparent)] - // SAFETY: `UpgradeBox` has no trap representation in `EvaluatesTo` + // SAFETY: `UpgradeExpr` has no trap representation in `EvaluatesTo` #[ffi_type(unsafe {robust})] - pub struct UpgradeBox { + pub struct UpgradeExpr { /// The object to upgrade. pub object: EvaluatesTo, } @@ -623,7 +623,7 @@ isi! { #[derive(Display)] #[display(fmt = "LOG({level}): {msg}")] #[ffi_type] - pub struct LogBox { + pub struct LogExpr { /// Message log level #[serde(flatten)] pub level: EvaluatesTo, @@ -632,8 +632,8 @@ isi! { } } -impl ExecuteTriggerBox { - /// Construct [`ExecuteTriggerBox`] +impl ExecuteTriggerExpr { + /// Construct [`ExecuteTriggerExpr`] pub fn new(trigger_id: I) -> Self where I: Into>, @@ -644,9 +644,9 @@ impl ExecuteTriggerBox { } } -impl RevokeBox { +impl RevokeExpr { /// Generic constructor. - pub fn new>, I: Into>>( + pub fn new>, I: Into>>( object: P, destination_id: I, ) -> Self { @@ -657,9 +657,9 @@ impl RevokeBox { } } -impl GrantBox { +impl GrantExpr { /// Constructor. - pub fn new>, I: Into>>( + pub fn new>, I: Into>>( object: P, destination_id: I, ) -> Self { @@ -670,8 +670,8 @@ impl GrantBox { } } -impl SetKeyValueBox { - /// Construct [`SetKeyValueBox`]. +impl SetKeyValueExpr { + /// Construct [`SetKeyValueExpr`]. pub fn new< I: Into>, K: Into>, @@ -689,8 +689,8 @@ impl SetKeyValueBox { } } -impl RemoveKeyValueBox { - /// Construct [`RemoveKeyValueBox`]. +impl RemoveKeyValueExpr { + /// Construct [`RemoveKeyValueExpr`]. pub fn new>, K: Into>>( object_id: I, key: K, @@ -702,7 +702,7 @@ impl RemoveKeyValueBox { } } -impl RegisterBox { +impl RegisterExpr { /// Construct [`Register`]. pub fn new>>(object: O) -> Self { Self { @@ -711,7 +711,7 @@ impl RegisterBox { } } -impl UnregisterBox { +impl UnregisterExpr { /// Construct [`Unregister`]. pub fn new>>(object_id: O) -> Self { Self { @@ -720,7 +720,7 @@ impl UnregisterBox { } } -impl MintBox { +impl MintExpr { /// Construct [`Mint`]. pub fn new>, D: Into>>( object: O, @@ -733,7 +733,7 @@ impl MintBox { } } -impl BurnBox { +impl BurnExpr { /// Construct [`Burn`]. pub fn new>, D: Into>>( object: O, @@ -746,7 +746,7 @@ impl BurnBox { } } -impl TransferBox { +impl TransferExpr { /// Construct [`Transfer`]. pub fn new< S: Into>, @@ -765,31 +765,34 @@ impl TransferBox { } } -impl Pair { +impl PairExpr { /// Construct [`Pair`]. - pub fn new, RI: Into>( + pub fn new, RI: Into>( left_instruction: LI, right_instruction: RI, ) -> Self { - Pair { + PairExpr { left_instruction: left_instruction.into(), right_instruction: right_instruction.into(), } } } -impl SequenceBox { - /// Construct [`SequenceBox`]. - pub fn new(instructions: impl IntoIterator) -> Self { +impl SequenceExpr { + /// Construct [`SequenceExpr`]. + pub fn new(instructions: impl IntoIterator) -> Self { Self { instructions: instructions.into_iter().collect(), } } } -impl Conditional { +impl ConditionalExpr { /// Construct [`If`]. - pub fn new>, T: Into>(condition: C, then: T) -> Self { + pub fn new>, T: Into>( + condition: C, + then: T, + ) -> Self { Self { condition: condition.into(), then: then.into(), @@ -799,8 +802,8 @@ impl Conditional { /// [`If`] constructor with `Otherwise` instruction. pub fn with_otherwise< C: Into>, - T: Into, - O: Into, + T: Into, + O: Into, >( condition: C, then: T, @@ -814,7 +817,7 @@ impl Conditional { } } -impl FailBox { +impl Fail { /// Construct [`Fail`]. pub fn new(message: &str) -> Self { Self { @@ -823,8 +826,8 @@ impl FailBox { } } -impl SetParameterBox { - /// Construct [`SetParameterBox`]. +impl SetParameterExpr { + /// Construct [`SetParameterExpr`]. pub fn new>>(parameter: P) -> Self { Self { parameter: parameter.into(), @@ -832,8 +835,8 @@ impl SetParameterBox { } } -impl NewParameterBox { - /// Construct [`NewParameterBox`]. +impl NewParameterExpr { + /// Construct [`NewParameterExpr`]. pub fn new>>(parameter: P) -> Self { Self { parameter: parameter.into(), @@ -841,8 +844,8 @@ impl NewParameterBox { } } -impl UpgradeBox { - /// Construct [`UpgradeBox`]. +impl UpgradeExpr { + /// Construct [`UpgradeExpr`]. pub fn new>>(object: O) -> Self { Self { object: object.into(), @@ -850,8 +853,8 @@ impl UpgradeBox { } } -impl LogBox { - /// Construct [`LogBox`] +impl LogExpr { + /// Construct [`LogExpr`] pub fn new>, M: Into>>( level: L, msg: M, @@ -1212,10 +1215,10 @@ pub mod error { /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { pub use super::{ - Burn, BurnBox, Conditional, ExecuteTrigger, ExecuteTriggerBox, FailBox, Grant, GrantBox, - InstructionBox, Log, LogBox, Mint, MintBox, NewParameter, NewParameterBox, Pair, Register, - RegisterBox, RemoveKeyValue, RemoveKeyValueBox, Revoke, RevokeBox, SequenceBox, - SetKeyValue, SetKeyValueBox, SetParameter, SetParameterBox, Transfer, TransferBox, - Unregister, UnregisterBox, Upgrade, UpgradeBox, + Burn, BurnExpr, ConditionalExpr, ExecuteTrigger, ExecuteTriggerExpr, Fail, Grant, + GrantExpr, InstructionExpr, Log, LogExpr, Mint, MintExpr, NewParameter, NewParameterExpr, + PairExpr, Register, RegisterExpr, RemoveKeyValue, RemoveKeyValueExpr, Revoke, RevokeExpr, + SequenceExpr, SetKeyValue, SetKeyValueExpr, SetParameter, SetParameterExpr, Transfer, + TransferExpr, Unregister, UnregisterExpr, Upgrade, UpgradeExpr, }; } diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 00562ad9ae4..90bac808f97 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -95,28 +95,28 @@ mod seal { impl_sealed! { // Boxed instructions - InstructionBox, - SetKeyValueBox, - RemoveKeyValueBox, - RegisterBox, - UnregisterBox, - MintBox, - BurnBox, - TransferBox, - GrantBox, - RevokeBox, - SetParameterBox, - NewParameterBox, - UpgradeBox, - ExecuteTriggerBox, - LogBox, + InstructionExpr, + SetKeyValueExpr, + RemoveKeyValueExpr, + RegisterExpr, + UnregisterExpr, + MintExpr, + BurnExpr, + TransferExpr, + GrantExpr, + RevokeExpr, + SetParameterExpr, + NewParameterExpr, + UpgradeExpr, + ExecuteTriggerExpr, + LogExpr, // Composite instructions - SequenceBox, - Conditional, - Pair, + SequenceExpr, + ConditionalExpr, + PairExpr, - FailBox, + Fail, // Boxed queries QueryBox, @@ -458,24 +458,24 @@ pub mod parameter { } /// Create sequence isi for setting parameters - pub fn into_set_parameters(self) -> isi::SequenceBox { - isi::SequenceBox { + pub fn into_set_parameters(self) -> isi::SequenceExpr { + isi::SequenceExpr { instructions: self .parameters .into_iter() - .map(isi::SetParameterBox::new) + .map(isi::SetParameterExpr::new) .map(Into::into) .collect(), } } /// Create sequence isi for creating parameters - pub fn into_create_parameters(self) -> isi::SequenceBox { - isi::SequenceBox { + pub fn into_create_parameters(self) -> isi::SequenceExpr { + isi::SequenceExpr { instructions: self .parameters .into_iter() - .map(isi::NewParameterBox::new) + .map(isi::NewParameterExpr::new) .map(Into::into) .collect(), } diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index b33f153d210..fb0d78ad468 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -998,7 +998,7 @@ pub mod trigger { domain::prelude::*, events::TriggeringFilterBox, expression::EvaluatesTo, - prelude::InstructionBox, + prelude::InstructionExpr, trigger::{OptimizedExecutable, Trigger, TriggerId}, Executable, Identifiable, Name, Value, }; @@ -1482,8 +1482,6 @@ pub mod error { #[skip_try_from] String, ), - /// Unauthorized query: account not provided - Unauthorized, } /// Type assertion error diff --git a/data_model/src/transaction.rs b/data_model/src/transaction.rs index 7aadcf1b047..5a6684f4c65 100644 --- a/data_model/src/transaction.rs +++ b/data_model/src/transaction.rs @@ -23,7 +23,7 @@ use serde::{Deserialize, Serialize}; pub use self::model::*; use crate::{ account::AccountId, - isi::{Instruction, InstructionBox}, + isi::{Instruction, InstructionExpr}, metadata::UnlimitedMetadata, name::Name, Value, @@ -52,7 +52,7 @@ pub mod model { pub enum Executable { /// Ordered set of instructions. #[debug(fmt = "{_0:?}")] - Instructions(Vec), + Instructions(Vec), /// WebAssembly smartcontract Wasm(WasmSmartContract), } @@ -520,7 +520,7 @@ pub mod error { pub struct InstructionExecutionFail { /// Instruction for which execution failed #[getset(get = "pub")] - pub instruction: InstructionBox, + pub instruction: InstructionExpr, /// Error which happened during execution pub reason: String, } @@ -598,7 +598,7 @@ pub mod error { impl Display for InstructionExecutionFail { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - use InstructionBox::*; + use InstructionExpr::*; let kind = match self.instruction { Burn(_) => "burn", Fail(_) => "fail", @@ -678,7 +678,7 @@ mod http { creation_time_ms, nonce: None, time_to_live_ms: None, - instructions: Vec::::new().into(), + instructions: Vec::::new().into(), metadata: UnlimitedMetadata::new(), }, } @@ -694,7 +694,7 @@ mod http { self.payload.instructions = instructions .into_iter() .map(Into::into) - .collect::>() + .collect::>() .into(); self } diff --git a/data_model/src/trigger.rs b/data_model/src/trigger.rs index fd13104501f..48d6e5a7ed9 100644 --- a/data_model/src/trigger.rs +++ b/data_model/src/trigger.rs @@ -15,7 +15,7 @@ use serde_with::{DeserializeFromStr, SerializeDisplay}; pub use self::model::*; use crate::{ - domain::DomainId, events::prelude::*, metadata::Metadata, prelude::InstructionBox, + domain::DomainId, events::prelude::*, metadata::Metadata, prelude::InstructionExpr, transaction::Executable, Identifiable, Name, ParseError, Registered, }; @@ -91,8 +91,8 @@ pub mod model { pub enum OptimizedExecutable { /// WASM serialized with `wasmtime`. WasmInternalRepr(WasmInternalRepr), - /// Vector of [`instructions`](InstructionBox). - Instructions(Vec), + /// Vector of [`instructions`](InstructionExpr). + Instructions(Vec), } } diff --git a/data_model/src/validator.rs b/data_model/src/validator.rs index fc086f170ca..9167efa2033 100644 --- a/data_model/src/validator.rs +++ b/data_model/src/validator.rs @@ -20,7 +20,7 @@ pub mod model { /// validator that checks if an operation satisfies some conditions. /// /// Can be used with things like [`Transaction`]s, - /// [`InstructionBox`]s, etc. + /// [`InstructionExpr`]s, etc. #[derive( Debug, Clone, diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index 35efa301c3e..7ef7be8a2b0 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -39,26 +39,26 @@ pub trait Visit: ExpressionEvaluator { // Visit SignedTransaction visit_transaction(&SignedTransaction), - visit_instruction(&InstructionBox), + visit_instruction(&InstructionExpr), visit_expression(&EvaluatesTo), visit_wasm(&WasmSmartContract), visit_query(&QueryBox), - // Visit InstructionBox - visit_burn(&BurnBox), - visit_fail(&FailBox), - visit_grant(&GrantBox), - visit_if(&Conditional), - visit_mint(&MintBox), - visit_pair(&Pair), - visit_register(&RegisterBox), - visit_remove_key_value(&RemoveKeyValueBox), - visit_revoke(&RevokeBox), - visit_sequence(&SequenceBox), - visit_set_key_value(&SetKeyValueBox), - visit_transfer(&TransferBox), - visit_unregister(&UnregisterBox), - visit_upgrade(&UpgradeBox), + // Visit InstructionExpr + visit_burn(&BurnExpr), + visit_fail(&Fail), + visit_grant(&GrantExpr), + visit_if(&ConditionalExpr), + visit_mint(&MintExpr), + visit_pair(&PairExpr), + visit_register(&RegisterExpr), + visit_remove_key_value(&RemoveKeyValueExpr), + visit_revoke(&RevokeExpr), + visit_sequence(&SequenceExpr), + visit_set_key_value(&SetKeyValueExpr), + visit_transfer(&TransferExpr), + visit_unregister(&UnregisterExpr), + visit_upgrade(&UpgradeExpr), visit_execute_trigger(ExecuteTrigger), visit_new_parameter(NewParameter), @@ -108,7 +108,7 @@ pub trait Visit: ExpressionEvaluator { visit_find_triggers_by_domain_id(&FindTriggersByDomainId), visit_is_asset_definition_owner(&IsAssetDefinitionOwner), - // Visit RegisterBox + // Visit RegisterExpr visit_register_peer(Register), visit_register_domain(Register), visit_register_account(Register), @@ -117,7 +117,7 @@ pub trait Visit: ExpressionEvaluator { visit_register_role(Register), visit_register_trigger(Register>), - // Visit UnregisterBox + // Visit UnregisterExpr visit_unregister_peer(Unregister), visit_unregister_domain(Unregister), visit_unregister_account(Unregister), @@ -127,41 +127,41 @@ pub trait Visit: ExpressionEvaluator { visit_unregister_role(Unregister), visit_unregister_trigger(Unregister>), - // Visit MintBox - visit_mint_asset(Mint), - visit_mint_account_public_key(Mint), - visit_mint_account_signature_check_condition(Mint), - visit_mint_trigger_repetitions(Mint, u32>), + // Visit MintExpr + visit_mint_asset(Mint), + visit_mint_account_public_key(Mint), + visit_mint_account_signature_check_condition(Mint), + visit_mint_trigger_repetitions(Mint>), - // Visit BurnBox - visit_burn_account_public_key(Burn), - visit_burn_asset(Burn), + // Visit BurnExpr + visit_burn_account_public_key(Burn), + visit_burn_asset(Burn), - // Visit TransferBox + // Visit TransferExpr visit_transfer_asset_definition(Transfer), visit_transfer_asset(Transfer), - // Visit SetKeyValueBox + // Visit SetKeyValueExpr visit_set_domain_key_value(SetKeyValue), visit_set_account_key_value(SetKeyValue), visit_set_asset_definition_key_value(SetKeyValue), visit_set_asset_key_value(SetKeyValue), - // Visit RemoveKeyValueBox + // Visit RemoveKeyValueExpr visit_remove_domain_key_value(RemoveKeyValue), visit_remove_account_key_value(RemoveKeyValue), visit_remove_asset_definition_key_value(RemoveKeyValue), visit_remove_asset_key_value(RemoveKeyValue), - // Visit GrantBox - visit_grant_account_permission(Grant), - visit_grant_account_role(Grant), + // Visit GrantExpr + visit_grant_account_permission(Grant), + visit_grant_account_role(Grant), - // Visit RevokeBox - visit_revoke_account_permission(Revoke), - visit_revoke_account_role(Revoke), + // Visit RevokeExpr + visit_revoke_account_permission(Revoke), + visit_revoke_account_role(Revoke), - // Visit UpgradeBox + // Visit UpgradeExpr visit_upgrade_validator(Upgrade), } } @@ -251,7 +251,7 @@ pub fn visit_wasm( ) { } -/// Default validation for [`InstructionBox`]. +/// Default validation for [`InstructionExpr`]. /// /// # Warning /// @@ -259,29 +259,29 @@ pub fn visit_wasm( pub fn visit_instruction( visitor: &mut V, authority: &AccountId, - isi: &InstructionBox, + isi: &InstructionExpr, ) { macro_rules! isi_visitors { ( $($visitor:ident($isi:ident)),+ $(,)? ) => { match isi { - InstructionBox::NewParameter(isi) => { + InstructionExpr::NewParameter(isi) => { let parameter = evaluate_expr!(visitor, authority, ::parameter()); visitor.visit_new_parameter(authority, NewParameter{parameter}); } - InstructionBox::SetParameter(isi) => { + InstructionExpr::SetParameter(isi) => { let parameter = evaluate_expr!(visitor, authority, ::parameter()); visitor.visit_set_parameter(authority, SetParameter{parameter}); } - InstructionBox::ExecuteTrigger(isi) => { + InstructionExpr::ExecuteTrigger(isi) => { let trigger_id = evaluate_expr!(visitor, authority, ::trigger_id()); visitor.visit_execute_trigger(authority, ExecuteTrigger{trigger_id}); } - InstructionBox::Log(isi) => { - let msg = evaluate_expr!(visitor, authority, ::msg()); - let level = evaluate_expr!(visitor, authority, ::level()); + InstructionExpr::Log(isi) => { + let msg = evaluate_expr!(visitor, authority, ::msg()); + let level = evaluate_expr!(visitor, authority, ::level()); visitor.visit_log(authority, Log { msg, level }); } $( - InstructionBox::$isi(isi) => { + InstructionExpr::$isi(isi) => { visitor.$visitor(authority, isi); } )+ } @@ -364,7 +364,7 @@ pub fn visit_expression( pub fn visit_register( visitor: &mut V, authority: &AccountId, - isi: &RegisterBox, + isi: &RegisterExpr, ) { macro_rules! match_all { ( $( $visitor:ident($object:ident) ),+ $(,)? ) => { @@ -390,7 +390,7 @@ pub fn visit_register( pub fn visit_unregister( visitor: &mut V, authority: &AccountId, - isi: &UnregisterBox, + isi: &UnregisterExpr, ) { macro_rules! match_all { ( $( $visitor:ident($id:ident) ),+ $(,)? ) => { @@ -413,7 +413,7 @@ pub fn visit_unregister( } } -pub fn visit_mint(visitor: &mut V, authority: &AccountId, isi: &MintBox) { +pub fn visit_mint(visitor: &mut V, authority: &AccountId, isi: &MintExpr) { let destination_id = evaluate_expr!(visitor, authority, ::destination_id()); let object = evaluate_expr!(visitor, authority, ::object()); @@ -453,7 +453,7 @@ pub fn visit_mint(visitor: &mut V, authority: &AccountId, isi } } -pub fn visit_burn(visitor: &mut V, authority: &AccountId, isi: &BurnBox) { +pub fn visit_burn(visitor: &mut V, authority: &AccountId, isi: &BurnExpr) { let destination_id = evaluate_expr!(visitor, authority, ::destination_id()); let object = evaluate_expr!(visitor, authority, ::object()); @@ -480,7 +480,7 @@ pub fn visit_burn(visitor: &mut V, authority: &AccountId, isi pub fn visit_transfer( visitor: &mut V, authority: &AccountId, - isi: &TransferBox, + isi: &TransferExpr, ) { let object = evaluate_expr!(visitor, authority, ::object()); @@ -507,7 +507,7 @@ pub fn visit_transfer( pub fn visit_set_key_value( visitor: &mut V, authority: &AccountId, - isi: &SetKeyValueBox, + isi: &SetKeyValueExpr, ) { let object_id = evaluate_expr!(visitor, authority, ::object_id()); let key = evaluate_expr!(visitor, authority, ::key()); @@ -553,7 +553,7 @@ pub fn visit_set_key_value( pub fn visit_remove_key_value( visitor: &mut V, authority: &AccountId, - isi: &RemoveKeyValueBox, + isi: &RemoveKeyValueExpr, ) { let object_id = evaluate_expr!(visitor, authority, ::object_id()); let key = evaluate_expr!(visitor, authority, ::key()); @@ -574,57 +574,53 @@ pub fn visit_remove_key_value( } } -pub fn visit_grant(visitor: &mut V, authority: &AccountId, isi: &GrantBox) { +pub fn visit_grant(visitor: &mut V, authority: &AccountId, isi: &GrantExpr) { let destination_id = evaluate_expr!(visitor, authority, ::destination_id()); let object = evaluate_expr!(visitor, authority, ::object()); - match (object, destination_id) { - (Value::PermissionToken(object), IdBox::AccountId(destination_id)) => visitor - .visit_grant_account_permission( - authority, - Grant { - object, - destination_id, - }, - ), - (Value::Id(IdBox::RoleId(object)), IdBox::AccountId(destination_id)) => visitor - .visit_grant_account_role( - authority, - Grant { - object, - destination_id, - }, - ), + match object { + Value::PermissionToken(object) => visitor.visit_grant_account_permission( + authority, + Grant { + object, + destination_id, + }, + ), + Value::Id(IdBox::RoleId(object)) => visitor.visit_grant_account_role( + authority, + Grant { + object, + destination_id, + }, + ), _ => visitor.visit_unsupported(authority, isi), } } -pub fn visit_revoke(visitor: &mut V, authority: &AccountId, isi: &RevokeBox) { +pub fn visit_revoke(visitor: &mut V, authority: &AccountId, isi: &RevokeExpr) { let destination_id = evaluate_expr!(visitor, authority, ::destination_id()); let object = evaluate_expr!(visitor, authority, ::object()); - match (object, destination_id) { - (Value::PermissionToken(object), IdBox::AccountId(destination_id)) => visitor - .visit_revoke_account_permission( - authority, - Revoke { - object, - destination_id, - }, - ), - (Value::Id(IdBox::RoleId(object)), IdBox::AccountId(destination_id)) => visitor - .visit_revoke_account_role( - authority, - Revoke { - object, - destination_id, - }, - ), + match object { + Value::PermissionToken(object) => visitor.visit_revoke_account_permission( + authority, + Revoke { + object, + destination_id, + }, + ), + Value::Id(IdBox::RoleId(object)) => visitor.visit_revoke_account_role( + authority, + Revoke { + object, + destination_id, + }, + ), _ => visitor.visit_unsupported(authority, isi), } } -pub fn visit_upgrade(visitor: &mut V, authority: &AccountId, isi: &UpgradeBox) { +pub fn visit_upgrade(visitor: &mut V, authority: &AccountId, isi: &UpgradeExpr) { let object = evaluate_expr!(visitor, authority, ::object()); match object { @@ -634,8 +630,8 @@ pub fn visit_upgrade(visitor: &mut V, authority: &AccountId, } } -pub fn visit_if(visitor: &mut V, authority: &AccountId, isi: &Conditional) { - let condition = evaluate_expr!(visitor, authority, ::condition()); +pub fn visit_if(visitor: &mut V, authority: &AccountId, isi: &ConditionalExpr) { + let condition = evaluate_expr!(visitor, authority, ::condition()); // TODO: Should visit both by default or not? It will affect Validator behavior // because only one branch needs to be executed. IMO both should be validated @@ -646,7 +642,7 @@ pub fn visit_if(visitor: &mut V, authority: &AccountId, isi: } } -pub fn visit_pair(visitor: &mut V, authority: &AccountId, isi: &Pair) { +pub fn visit_pair(visitor: &mut V, authority: &AccountId, isi: &PairExpr) { visitor.visit_instruction(authority, isi.left_instruction()); visitor.visit_instruction(authority, isi.right_instruction()); } @@ -654,7 +650,7 @@ pub fn visit_pair(visitor: &mut V, authority: &AccountId, isi pub fn visit_sequence( visitor: &mut V, authority: &AccountId, - isi: &SequenceBox, + isi: &SequenceExpr, ) { for instruction in isi.instructions() { visitor.visit_instruction(authority, instruction); @@ -673,15 +669,15 @@ leaf_visitors! { // Instruction visitors visit_register_account(Register), visit_unregister_account(Unregister), - visit_mint_account_public_key(Mint), - visit_burn_account_public_key(Burn), - visit_mint_account_signature_check_condition(Mint), + visit_mint_account_public_key(Mint), + visit_burn_account_public_key(Burn), + visit_mint_account_signature_check_condition(Mint), visit_set_account_key_value(SetKeyValue), visit_remove_account_key_value(RemoveKeyValue), visit_register_asset(Register), visit_unregister_asset(Unregister), - visit_mint_asset(Mint), - visit_burn_asset(Burn), + visit_mint_asset(Mint), + visit_burn_asset(Burn), visit_transfer_asset(Transfer), visit_set_asset_key_value(SetKeyValue), visit_remove_asset_key_value(RemoveKeyValue), @@ -696,20 +692,20 @@ leaf_visitors! { visit_remove_domain_key_value(RemoveKeyValue), visit_register_peer(Register), visit_unregister_peer(Unregister), - visit_grant_account_permission(Grant), - visit_revoke_account_permission(Revoke), + visit_grant_account_permission(Grant), + visit_revoke_account_permission(Revoke), visit_register_role(Register), visit_unregister_role(Unregister), - visit_grant_account_role(Grant), - visit_revoke_account_role(Revoke), + visit_grant_account_role(Grant), + visit_revoke_account_role(Revoke), visit_register_trigger(Register>), visit_unregister_trigger(Unregister>), - visit_mint_trigger_repetitions(Mint, u32>), + visit_mint_trigger_repetitions(Mint>), visit_upgrade_validator(Upgrade), visit_new_parameter(NewParameter), visit_set_parameter(SetParameter), visit_execute_trigger(ExecuteTrigger), - visit_fail(&FailBox), + visit_fail(&Fail), visit_log(Log), // Query visitors diff --git a/data_model/src/wasm.rs b/data_model/src/wasm.rs index e4282aae7bc..9510a6d0f7d 100644 --- a/data_model/src/wasm.rs +++ b/data_model/src/wasm.rs @@ -102,7 +102,7 @@ pub mod payloads { pub type ValidateTransaction = Validate; /// Payload for [`validate_instruction()`](super::export::fn_names::VALIDATOR_VALIDATE_INSTRUCTION) entrypoint - pub type ValidateInstruction = Validate; + pub type ValidateInstruction = Validate; /// Payload for [`validate_query()`](super::export::fn_names::VALIDATOR_VALIDATE_QUERY) entrypoint pub type ValidateQuery = Validate; diff --git a/data_model/tests/data_model.rs b/data_model/tests/data_model.rs index 6c4c3bb6ef6..6d420ea13b4 100644 --- a/data_model/tests/data_model.rs +++ b/data_model/tests/data_model.rs @@ -6,7 +6,7 @@ use iroha_data_model::{prelude::*, ParseError}; #[test] fn transfer_isi_should_be_valid() { - let _instruction = TransferBox::new( + let _instruction = TransferExpr::new( IdBox::AssetId("btc##seller@crypto".parse().expect("Valid")), 12_u32, IdBox::AccountId("buyer@crypto".parse().expect("Valid")), @@ -18,9 +18,9 @@ fn find_quantity_and_check_it_greater_than_value_isi_should_be_valid() { let asset_id: AssetId = "rose##alice@wonderland".parse().expect("Valid"); let find_asset = QueryBox::from(FindAssetQuantityById::new(asset_id)); - let _instruction = Conditional::new( + let _instruction = ConditionalExpr::new( Not::new(Greater::new(EvaluatesTo::new_unchecked(find_asset), 10_u32)), - FailBox::new("rate is less or equal to value"), + Fail::new("rate is less or equal to value"), ); } @@ -39,8 +39,8 @@ impl FindRateAndCheckItGreaterThanValue { } } - pub fn into_isi(self) -> Conditional { - Conditional::new( + pub fn into_isi(self) -> ConditionalExpr { + ConditionalExpr::new( Not::new(Greater::new( EvaluatesTo::new_unchecked(QueryBox::from(FindAssetQuantityById::new( AssetId::new( @@ -52,7 +52,7 @@ impl FindRateAndCheckItGreaterThanValue { ))), self.value, )), - FailBox::new("rate is less or equal to value"), + Fail::new("rate is less or equal to value"), ) } } diff --git a/default_validator/src/lib.rs b/default_validator/src/lib.rs index 0bafebce69d..e602b8ccd89 100644 --- a/default_validator/src/lib.rs +++ b/default_validator/src/lib.rs @@ -60,11 +60,11 @@ impl Visit for Validator { visit_unsupported(T), visit_transaction(&SignedTransaction), - visit_instruction(&InstructionBox), + visit_instruction(&InstructionExpr), visit_expression(&EvaluatesTo), - visit_sequence(&SequenceBox), - visit_if(&Conditional), - visit_pair(&Pair), + visit_sequence(&SequenceExpr), + visit_if(&ConditionalExpr), + visit_pair(&PairExpr), // Peer validation visit_unregister_peer(Unregister), @@ -76,17 +76,17 @@ impl Visit for Validator { // Account validation visit_unregister_account(Unregister), - visit_mint_account_public_key(Mint), - visit_burn_account_public_key(Burn), - visit_mint_account_signature_check_condition(Mint), + visit_mint_account_public_key(Mint), + visit_burn_account_public_key(Burn), + visit_mint_account_signature_check_condition(Mint), visit_set_account_key_value(SetKeyValue), visit_remove_account_key_value(RemoveKeyValue), // Asset validation visit_register_asset(Register), visit_unregister_asset(Unregister), - visit_mint_asset(Mint), - visit_burn_asset(Burn), + visit_mint_asset(Mint), + visit_burn_asset(Burn), visit_transfer_asset(Transfer), visit_set_asset_key_value(SetKeyValue), visit_remove_asset_key_value(RemoveKeyValue), @@ -98,18 +98,18 @@ impl Visit for Validator { visit_remove_asset_definition_key_value(RemoveKeyValue), // Permission validation - visit_grant_account_permission(Grant), - visit_revoke_account_permission(Revoke), + visit_grant_account_permission(Grant), + visit_revoke_account_permission(Revoke), // Role validation visit_register_role(Register), visit_unregister_role(Unregister), - visit_grant_account_role(Grant), - visit_revoke_account_role(Revoke), + visit_grant_account_role(Grant), + visit_revoke_account_role(Revoke), // Trigger validation visit_unregister_trigger(Unregister>), - visit_mint_trigger_repetitions(Mint, u32>), + visit_mint_trigger_repetitions(Mint>), visit_execute_trigger(ExecuteTrigger), // Parameter validation @@ -180,7 +180,7 @@ pub fn validate_transaction( #[entrypoint] pub fn validate_instruction( authority: AccountId, - instruction: InstructionBox, + instruction: InstructionExpr, block_height: u64, ) -> Result { let mut validator = Validator::new(block_height); diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index 248ff170c81..ade55770432 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -730,7 +730,7 @@ ] }, "BlockSubscriptionRequest": "NonZero", - "BurnBox": { + "BurnExpr": { "Struct": [ { "name": "object", @@ -742,7 +742,7 @@ } ] }, - "Conditional": { + "ConditionalExpr": { "Struct": [ { "name": "condition", @@ -750,11 +750,11 @@ }, { "name": "then", - "type": "InstructionBox" + "type": "InstructionExpr" }, { "name": "otherwise", - "type": "Option" + "type": "Option" } ] }, @@ -1297,7 +1297,7 @@ { "tag": "Instructions", "discriminant": 0, - "type": "Vec" + "type": "Vec" }, { "tag": "Wasm", @@ -1306,14 +1306,6 @@ } ] }, - "ExecuteTriggerBox": { - "Struct": [ - { - "name": "trigger_id", - "type": "EvaluatesTo" - } - ] - }, "ExecuteTriggerEvent": { "Struct": [ { @@ -1338,6 +1330,14 @@ } ] }, + "ExecuteTriggerExpr": { + "Struct": [ + { + "name": "trigger_id", + "type": "EvaluatesTo" + } + ] + }, "ExecutionTime": { "Enum": [ { @@ -1455,7 +1455,7 @@ } ] }, - "FailBox": { + "Fail": { "Struct": [ { "name": "message", @@ -2143,7 +2143,7 @@ } ] }, - "GrantBox": { + "GrantExpr": { "Struct": [ { "name": "object", @@ -2151,7 +2151,7 @@ }, { "name": "destination_id", - "type": "EvaluatesTo" + "type": "EvaluatesTo" } ] }, @@ -2315,100 +2315,6 @@ } ] }, - "InstructionBox": { - "Enum": [ - { - "tag": "Register", - "discriminant": 0, - "type": "RegisterBox" - }, - { - "tag": "Unregister", - "discriminant": 1, - "type": "UnregisterBox" - }, - { - "tag": "Mint", - "discriminant": 2, - "type": "MintBox" - }, - { - "tag": "Burn", - "discriminant": 3, - "type": "BurnBox" - }, - { - "tag": "Transfer", - "discriminant": 4, - "type": "TransferBox" - }, - { - "tag": "If", - "discriminant": 5, - "type": "Conditional" - }, - { - "tag": "Pair", - "discriminant": 6, - "type": "Pair" - }, - { - "tag": "Sequence", - "discriminant": 7, - "type": "SequenceBox" - }, - { - "tag": "SetKeyValue", - "discriminant": 8, - "type": "SetKeyValueBox" - }, - { - "tag": "RemoveKeyValue", - "discriminant": 9, - "type": "RemoveKeyValueBox" - }, - { - "tag": "Grant", - "discriminant": 10, - "type": "GrantBox" - }, - { - "tag": "Revoke", - "discriminant": 11, - "type": "RevokeBox" - }, - { - "tag": "ExecuteTrigger", - "discriminant": 12, - "type": "ExecuteTriggerBox" - }, - { - "tag": "SetParameter", - "discriminant": 13, - "type": "SetParameterBox" - }, - { - "tag": "NewParameter", - "discriminant": 14, - "type": "NewParameterBox" - }, - { - "tag": "Upgrade", - "discriminant": 15, - "type": "UpgradeBox" - }, - { - "tag": "Log", - "discriminant": 16, - "type": "LogBox" - }, - { - "tag": "Fail", - "discriminant": 17, - "type": "FailBox" - } - ] - }, "InstructionEvaluationError": { "Enum": [ { @@ -2496,7 +2402,7 @@ "Struct": [ { "name": "instruction", - "type": "InstructionBox" + "type": "InstructionExpr" }, { "name": "reason", @@ -2504,6 +2410,100 @@ } ] }, + "InstructionExpr": { + "Enum": [ + { + "tag": "Register", + "discriminant": 0, + "type": "RegisterExpr" + }, + { + "tag": "Unregister", + "discriminant": 1, + "type": "UnregisterExpr" + }, + { + "tag": "Mint", + "discriminant": 2, + "type": "MintExpr" + }, + { + "tag": "Burn", + "discriminant": 3, + "type": "BurnExpr" + }, + { + "tag": "Transfer", + "discriminant": 4, + "type": "TransferExpr" + }, + { + "tag": "If", + "discriminant": 5, + "type": "ConditionalExpr" + }, + { + "tag": "Pair", + "discriminant": 6, + "type": "PairExpr" + }, + { + "tag": "Sequence", + "discriminant": 7, + "type": "SequenceExpr" + }, + { + "tag": "SetKeyValue", + "discriminant": 8, + "type": "SetKeyValueExpr" + }, + { + "tag": "RemoveKeyValue", + "discriminant": 9, + "type": "RemoveKeyValueExpr" + }, + { + "tag": "Grant", + "discriminant": 10, + "type": "GrantExpr" + }, + { + "tag": "Revoke", + "discriminant": 11, + "type": "RevokeExpr" + }, + { + "tag": "ExecuteTrigger", + "discriminant": 12, + "type": "ExecuteTriggerExpr" + }, + { + "tag": "SetParameter", + "discriminant": 13, + "type": "SetParameterExpr" + }, + { + "tag": "NewParameter", + "discriminant": 14, + "type": "NewParameterExpr" + }, + { + "tag": "Upgrade", + "discriminant": 15, + "type": "UpgradeExpr" + }, + { + "tag": "Log", + "discriminant": 16, + "type": "LogExpr" + }, + { + "tag": "Fail", + "discriminant": 17, + "type": "Fail" + } + ] + }, "InstructionType": { "Enum": [ { @@ -2694,7 +2694,7 @@ } ] }, - "LogBox": { + "LogExpr": { "Struct": [ { "name": "level", @@ -2847,7 +2847,7 @@ } ] }, - "MintBox": { + "MintExpr": { "Struct": [ { "name": "object", @@ -3004,7 +3004,7 @@ } ] }, - "NewParameterBox": { + "NewParameterExpr": { "Struct": [ { "name": "parameter", @@ -3087,7 +3087,7 @@ { "tag": "Instructions", "discriminant": 1, - "type": "Vec" + "type": "Vec" } ] }, @@ -3106,8 +3106,8 @@ "Option>": { "Option": "HashOf" }, - "Option": { - "Option": "InstructionBox" + "Option": { + "Option": "InstructionExpr" }, "Option": { "Option": "IpfsPath" @@ -3158,15 +3158,15 @@ "OriginFilter": "PeerId", "OriginFilter": "RoleId", "OriginFilter": "TriggerId", - "Pair": { + "PairExpr": { "Struct": [ { "name": "left_instruction", - "type": "InstructionBox" + "type": "InstructionExpr" }, { "name": "right_instruction", - "type": "InstructionBox" + "type": "InstructionExpr" } ] }, @@ -3629,10 +3629,6 @@ "tag": "Conversion", "discriminant": 3, "type": "String" - }, - { - "tag": "Unauthorized", - "discriminant": 4 } ] }, @@ -3668,7 +3664,7 @@ "Struct": [ { "name": "transactions", - "type": "Vec>" + "type": "Vec>" }, { "name": "validator", @@ -3676,7 +3672,7 @@ } ] }, - "RegisterBox": { + "RegisterExpr": { "Struct": [ { "name": "object", @@ -3723,7 +3719,7 @@ } ] }, - "RemoveKeyValueBox": { + "RemoveKeyValueExpr": { "Struct": [ { "name": "object_id", @@ -3760,7 +3756,7 @@ } ] }, - "RevokeBox": { + "RevokeExpr": { "Struct": [ { "name": "object", @@ -3768,7 +3764,7 @@ }, { "name": "destination_id", - "type": "EvaluatesTo" + "type": "EvaluatesTo" } ] }, @@ -3906,15 +3902,15 @@ } ] }, - "SequenceBox": { + "SequenceExpr": { "Struct": [ { "name": "instructions", - "type": "Vec" + "type": "Vec" } ] }, - "SetKeyValueBox": { + "SetKeyValueExpr": { "Struct": [ { "name": "object_id", @@ -3930,7 +3926,7 @@ } ] }, - "SetParameterBox": { + "SetParameterExpr": { "Struct": [ { "name": "parameter", @@ -4332,7 +4328,7 @@ } ] }, - "TransferBox": { + "TransferExpr": { "Struct": [ { "name": "source_id", @@ -4559,7 +4555,7 @@ ] }, "UniqueVec": "Vec", - "UnregisterBox": { + "UnregisterExpr": { "Struct": [ { "name": "object_id", @@ -4576,7 +4572,7 @@ } ] }, - "UpgradeBox": { + "UpgradeExpr": { "Struct": [ { "name": "object", @@ -4821,8 +4817,8 @@ "Vec>": { "Vec": "GenericPredicateBox" }, - "Vec": { - "Vec": "InstructionBox" + "Vec": { + "Vec": "InstructionExpr" }, "Vec": { "Vec": "Name" @@ -4842,8 +4838,8 @@ "Vec": { "Vec": "Value" }, - "Vec>": { - "Vec": "Vec" + "Vec>": { + "Vec": "Vec" }, "Vec": { "Vec": "u8" diff --git a/genesis/src/lib.rs b/genesis/src/lib.rs index 1cb890de02d..3fc8622663f 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -69,7 +69,7 @@ impl GenesisNetwork { // First instruction should be Validator upgrade. // This makes possible to grant permissions to users in genesis. let transactions_iter = std::iter::once(GenesisTransactionBuilder { - isi: vec![UpgradeBox::new(Validator::try_from(raw_block.validator)?).into()], + isi: vec![UpgradeExpr::new(Validator::try_from(raw_block.validator)?).into()], }) .chain(raw_block.transactions.into_iter()); @@ -198,7 +198,7 @@ impl ValidatorPath { #[repr(transparent)] pub struct GenesisTransactionBuilder { /// Instructions - isi: Vec, + isi: Vec, } impl GenesisTransactionBuilder { @@ -216,7 +216,7 @@ impl GenesisTransactionBuilder { } /// Add new instruction to the transaction. - pub fn append_instruction(&mut self, instruction: InstructionBox) { + pub fn append_instruction(&mut self, instruction: InstructionExpr) { self.isi.push(instruction); } } @@ -294,7 +294,7 @@ impl RawGenesisBlockBuilder { let new_domain = Domain::new(domain_id.clone()).with_metadata(metadata); self.transaction .isi - .push(RegisterBox::new(new_domain).into()); + .push(RegisterExpr::new(new_domain).into()); RawGenesisDomainBuilder { transaction: self.transaction, domain_id, @@ -329,7 +329,7 @@ impl RawGenesisDomainBuilder { let account_id = AccountId::new(account_name, self.domain_id.clone()); self.transaction .isi - .push(RegisterBox::new(Account::new(account_id, [])).into()); + .push(RegisterExpr::new(Account::new(account_id, [])).into()); self } @@ -347,7 +347,7 @@ impl RawGenesisDomainBuilder { ) -> Self { let account_id = AccountId::new(account_name, self.domain_id.clone()); let register = - RegisterBox::new(Account::new(account_id, [public_key]).with_metadata(metadata)); + RegisterExpr::new(Account::new(account_id, [public_key]).with_metadata(metadata)); self.transaction.isi.push(register.into()); self } @@ -363,7 +363,7 @@ impl RawGenesisDomainBuilder { }; self.transaction .isi - .push(RegisterBox::new(asset_definition).into()); + .push(RegisterExpr::new(asset_definition).into()); self } } @@ -427,11 +427,11 @@ mod tests { let domain_id: DomainId = "wonderland".parse().unwrap(); assert_eq!( finished_genesis_block.transactions[0].isi[0], - RegisterBox::new(Domain::new(domain_id.clone())).into() + RegisterExpr::new(Domain::new(domain_id.clone())).into() ); assert_eq!( finished_genesis_block.transactions[0].isi[1], - RegisterBox::new(Account::new( + RegisterExpr::new(Account::new( AccountId::new("alice".parse().unwrap(), domain_id.clone()), [] )) @@ -439,7 +439,7 @@ mod tests { ); assert_eq!( finished_genesis_block.transactions[0].isi[2], - RegisterBox::new(Account::new( + RegisterExpr::new(Account::new( AccountId::new("bob".parse().unwrap(), domain_id), [] )) @@ -450,11 +450,11 @@ mod tests { let domain_id: DomainId = "tulgey_wood".parse().unwrap(); assert_eq!( finished_genesis_block.transactions[0].isi[3], - RegisterBox::new(Domain::new(domain_id.clone())).into() + RegisterExpr::new(Domain::new(domain_id.clone())).into() ); assert_eq!( finished_genesis_block.transactions[0].isi[4], - RegisterBox::new(Account::new( + RegisterExpr::new(Account::new( AccountId::new("Cheshire_Cat".parse().unwrap(), domain_id), [] )) @@ -465,11 +465,11 @@ mod tests { let domain_id: DomainId = "meadow".parse().unwrap(); assert_eq!( finished_genesis_block.transactions[0].isi[5], - RegisterBox::new(Domain::new(domain_id.clone())).into() + RegisterExpr::new(Domain::new(domain_id.clone())).into() ); assert_eq!( finished_genesis_block.transactions[0].isi[6], - RegisterBox::new(Account::new( + RegisterExpr::new(Account::new( AccountId::new("Mad_Hatter".parse().unwrap(), domain_id), [public_key.parse().unwrap()], )) @@ -477,7 +477,7 @@ mod tests { ); assert_eq!( finished_genesis_block.transactions[0].isi[7], - RegisterBox::new(AssetDefinition::big_quantity( + RegisterExpr::new(AssetDefinition::big_quantity( "hats#meadow".parse().unwrap() )) .into() diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index 66bcf492255..766c76b0ef7 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -109,11 +109,11 @@ types!( BlockSubscriptionRequest, Box, Box>, - Box, + Box, Box, Box, - BurnBox, - Conditional, + BurnExpr, + ConditionalExpr, ConfigurationEvent, ConstString, Container, @@ -151,12 +151,12 @@ types!( EventMessage, EventSubscriptionRequest, Executable, - ExecuteTriggerBox, + ExecuteTriggerExpr, ExecuteTriggerEvent, ExecuteTriggerEventFilter, ExecutionTime, Expression, - FailBox, + Fail, FilterBox, FilterOpt, FilterOpt, @@ -223,7 +223,7 @@ types!( FixNum, Fixed, ForwardCursor, - GrantBox, + GrantExpr, Greater, Hash, HashOf>, @@ -232,7 +232,7 @@ types!( IdBox, IdentifiableBox, If, - InstructionBox, + InstructionExpr, InstructionExecutionFail, Interval, Interval, @@ -251,7 +251,7 @@ types!( MetadataChanged, MetadataChanged, MetadataLimits, - MintBox, + MintExpr, Mintable, Mod, Multiply, @@ -259,7 +259,7 @@ types!( NewAccount, NewAssetDefinition, NewDomain, - NewParameterBox, + NewParameterExpr, NewRole, NonTrivial, NonZeroU64, @@ -271,7 +271,7 @@ types!( Option, Option>>, Option>, - Option, + Option, Option, Option, Option, @@ -287,7 +287,7 @@ types!( OriginFilter, OriginFilter, OriginFilter, - Pair, + PairExpr, Parameter, ParameterId, Peer, @@ -311,11 +311,11 @@ types!( QueryExecutionFail, QueryPayload, RaiseTo, - RegisterBox, + RegisterExpr, RegistrableBox, - RemoveKeyValueBox, + RemoveKeyValueExpr, Repeats, - RevokeBox, + RevokeExpr, Role, RoleEvent, RoleEventFilter, @@ -325,9 +325,9 @@ types!( SemiInterval, SemiInterval, SemiRange, - SequenceBox, - SetKeyValueBox, - SetParameterBox, + SequenceExpr, + SetKeyValueExpr, + SetParameterExpr, Signature, SignatureCheckCondition, SignatureOf, @@ -354,7 +354,7 @@ types!( TransactionQueryOutput, TransactionRejectionReason, TransactionValue, - TransferBox, + TransferExpr, Trigger, TriggerCompletedEventFilter, TriggerCompletedOutcomeType, @@ -364,7 +364,7 @@ types!( TriggerId, TriggerNumberOfExecutionsChanged, TriggeringFilterBox, - UnregisterBox, + UnregisterExpr, UpgradableBox, ValidationFail, Validator, @@ -373,7 +373,7 @@ types!( ValueOfKey, ValuePredicate, Vec, - Vec, + Vec, Vec, Vec, Vec, diff --git a/tools/kagami/src/genesis.rs b/tools/kagami/src/genesis.rs index 70ab9699517..9caabb21eef 100644 --- a/tools/kagami/src/genesis.rs +++ b/tools/kagami/src/genesis.rs @@ -4,7 +4,7 @@ use clap::{ArgGroup, Parser, Subcommand}; use iroha_config::{sumeragi::default::*, wasm::default::*, wsv::default::*}; use iroha_data_model::{ asset::AssetValueType, - isi::{MintBox, RegisterBox}, + isi::{MintExpr, RegisterExpr}, metadata::Limits, parameter::{default::*, ParametersBuilder}, prelude::AssetId, @@ -147,22 +147,22 @@ pub fn generate_default(validator: ValidatorMode) -> color_eyre::Result::new( - vec![MintBox::new(1_u32, rose_id)], + vec![MintExpr::new(1_u32, rose_id)], Repeats::Indefinitely, account_id, FilterBox::Data(DataEventFilter::BySome(DataEntityFilter::ByAccount( diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 5f688e43fbe..29b467f7681 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -73,16 +73,16 @@ pub trait QueryHost: Query { fn execute(&self) -> Result; } -// TODO: Remove the Clone bound. It can be done by custom serialization to InstructionBox -impl + Encode + Clone> ExecuteOnHost for I { +// TODO: Remove the Clone bound. It can be done by custom serialization to InstructionExpr +impl ExecuteOnHost for I { fn execute(&self) -> Result<(), ValidationFail> { #[cfg(not(test))] use host::execute_instruction as host_execute_instruction; #[cfg(test)] use tests::_iroha_wasm_execute_instruction_mock as host_execute_instruction; - // TODO: Redundant conversion into `InstructionBox` - let isi_box: InstructionBox = self.clone().into(); + // TODO: Redundant conversion into `InstructionExpr` + let isi_box: InstructionExpr = self.clone().into(); // Safety: `host_execute_instruction` doesn't take ownership of it's pointer parameter unsafe { decode_with_length_prefix_from_raw(encode_and_execute( @@ -435,9 +435,9 @@ mod tests { const ISI_RESULT: Result<(), ValidationFail> = Ok(()); const EXPRESSION_RESULT: NumericValue = NumericValue::U32(5_u32); - fn get_test_instruction() -> InstructionBox { + fn get_test_instruction() -> InstructionExpr { let new_account_id = "mad_hatter@wonderland".parse().expect("Valid"); - let register_isi = RegisterBox::new(Account::new(new_account_id, [])); + let register_isi = RegisterExpr::new(Account::new(new_account_id, [])); register_isi.into() } @@ -457,7 +457,7 @@ mod tests { len: usize, ) -> *const u8 { let bytes = slice::from_raw_parts(ptr, len); - let instruction = InstructionBox::decode_all(&mut &*bytes); + let instruction = InstructionExpr::decode_all(&mut &*bytes); assert_eq!(get_test_instruction(), instruction.unwrap()); ManuallyDrop::new(encode_with_length_prefix(&ISI_RESULT)).as_ptr() diff --git a/wasm/validator/derive/src/lib.rs b/wasm/validator/derive/src/lib.rs index 8a789a78ee3..23d698cacac 100644 --- a/wasm/validator/derive/src/lib.rs +++ b/wasm/validator/derive/src/lib.rs @@ -35,7 +35,7 @@ mod validate; /// } /// /// #[entrypoint] -/// pub fn validate_instruction(authority: AccountId, instruction: InstructionBox, block_height: u64) -> Result { +/// pub fn validate_instruction(authority: AccountId, instruction: InstructionExpr, block_height: u64) -> Result { /// todo!() /// } /// diff --git a/wasm/validator/src/default.rs b/wasm/validator/src/default.rs index aadac443213..2ad6a85a32b 100644 --- a/wasm/validator/src/default.rs +++ b/wasm/validator/src/default.rs @@ -116,7 +116,7 @@ pub fn visit_transaction( } } -/// Default validation for [`InstructionBox`]. +/// Default validation for [`InstructionExpr`]. /// /// # Warning /// @@ -124,7 +124,7 @@ pub fn visit_transaction( pub fn visit_instruction( validator: &mut V, authority: &AccountId, - isi: &InstructionBox, + isi: &InstructionExpr, ) { macro_rules! isi_validators { ( @@ -136,7 +136,7 @@ pub fn visit_instruction( ),+ $(,)?} ) => { match isi { - InstructionBox::NewParameter(isi) => { + InstructionExpr::NewParameter(isi) => { let parameter = evaluate_expr!(validator, authority, ::parameter()); validator.visit_new_parameter(authority, NewParameter{parameter}); @@ -144,7 +144,7 @@ pub fn visit_instruction( isi_validators!(@execute isi); } } - InstructionBox::SetParameter(isi) => { + InstructionExpr::SetParameter(isi) => { let parameter = evaluate_expr!(validator, authority, ::parameter()); validator.visit_set_parameter(authority, SetParameter{parameter}); @@ -152,7 +152,7 @@ pub fn visit_instruction( isi_validators!(@execute isi); } } - InstructionBox::ExecuteTrigger(isi) => { + InstructionExpr::ExecuteTrigger(isi) => { let trigger_id = evaluate_expr!(validator, authority, ::trigger_id()); validator.visit_execute_trigger(authority, ExecuteTrigger{trigger_id}); @@ -160,16 +160,16 @@ pub fn visit_instruction( isi_validators!(@execute isi); } } - InstructionBox::Log(isi) => { - let msg = evaluate_expr!(validator, authority, ::msg()); - let level = evaluate_expr!(validator, authority, ::level()); + InstructionExpr::Log(isi) => { + let msg = evaluate_expr!(validator, authority, ::msg()); + let level = evaluate_expr!(validator, authority, ::level()); validator.visit_log(authority, Log{level, msg}); if validator.verdict().is_ok() { isi_validators!(@execute isi); } } $( - InstructionBox::$isi(isi) => { + InstructionExpr::$isi(isi) => { validator.$validator(authority, isi); if validator.verdict().is_ok() { @@ -177,7 +177,7 @@ pub fn visit_instruction( } } )+ $( // NOTE: `visit_and_execute_instructions` is reentrant, so don't execute composite instructions - InstructionBox::$composite_isi(isi) => validator.$composite_validator(authority, isi), )+ + InstructionExpr::$composite_isi(isi) => validator.$composite_validator(authority, isi), )+ } }; (@execute $isi:ident) => { @@ -285,8 +285,12 @@ pub fn visit_expression( } } -pub fn visit_if(validator: &mut V, authority: &AccountId, isi: &Conditional) { - let condition = evaluate_expr!(validator, authority, ::condition()); +pub fn visit_if( + validator: &mut V, + authority: &AccountId, + isi: &ConditionalExpr, +) { + let condition = evaluate_expr!(validator, authority, ::condition()); // TODO: Do we have to make sure both branches are syntactically valid? if condition { @@ -296,7 +300,7 @@ pub fn visit_if(validator: &mut V, authority: &AccountId, } } -pub fn visit_pair(validator: &mut V, authority: &AccountId, isi: &Pair) { +pub fn visit_pair(validator: &mut V, authority: &AccountId, isi: &PairExpr) { validator.visit_instruction(authority, isi.left_instruction()); if validator.verdict().is_ok() { @@ -307,7 +311,7 @@ pub fn visit_pair(validator: &mut V, authority: &AccountId pub fn visit_sequence( validator: &mut V, authority: &AccountId, - sequence: &SequenceBox, + sequence: &SequenceExpr, ) { for isi in sequence.instructions() { if validator.verdict().is_ok() { @@ -527,7 +531,7 @@ pub mod account { pub fn visit_mint_account_public_key( validator: &mut V, authority: &AccountId, - isi: Mint, + isi: Mint, ) { let account_id = isi.destination_id; @@ -548,7 +552,7 @@ pub mod account { pub fn visit_burn_account_public_key( validator: &mut V, authority: &AccountId, - isi: Burn, + isi: Burn, ) { let account_id = isi.destination_id; @@ -569,7 +573,7 @@ pub mod account { pub fn visit_mint_account_signature_check_condition( validator: &mut V, authority: &AccountId, - isi: Mint, + isi: Mint, ) { let account_id = isi.destination_id; @@ -966,7 +970,7 @@ pub mod asset { pub fn visit_mint_asset( validator: &mut V, authority: &AccountId, - isi: Mint, + isi: Mint, ) { let asset_id = isi.destination_id; @@ -994,7 +998,7 @@ pub mod asset { pub fn visit_burn_asset( validator: &mut V, authority: &AccountId, - isi: Burn, + isi: Burn, ) { let asset_id = isi.destination_id; @@ -1368,7 +1372,7 @@ pub mod role { pub fn visit_grant_account_role( validator: &mut V, authority: &AccountId, - isi: Grant, + isi: Grant, ) { impl_validate!(validator, isi, authority, validate_grant); } @@ -1376,7 +1380,7 @@ pub mod role { pub fn visit_revoke_account_role( validator: &mut V, authority: &AccountId, - isi: Revoke, + isi: Revoke, ) { impl_validate!(validator, isi, authority, validate_revoke); } @@ -1468,7 +1472,7 @@ pub mod trigger { pub fn visit_mint_trigger_repetitions( validator: &mut V, authority: &AccountId, - isi: Mint, u32>, + isi: Mint>, ) { let trigger_id = isi.destination_id; @@ -1553,7 +1557,7 @@ pub mod permission_token { pub fn visit_grant_account_permission( validator: &mut V, authority: &AccountId, - isi: Grant, + isi: Grant, ) { impl_validate!(validator, authority, isi, validate_grant); } @@ -1561,7 +1565,7 @@ pub mod permission_token { pub fn visit_revoke_account_permission( validator: &mut V, authority: &AccountId, - isi: Revoke, + isi: Revoke, ) { impl_validate!(validator, authority, isi, validate_revoke); } From 386f1e6b3e1ba418fe271b01446f26092fe13ed8 Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Thu, 28 Sep 2023 10:15:17 +0300 Subject: [PATCH 31/55] [refactor]: Move account roles to `WSV` Signed-off-by: Shanin Roman --- configs/peer/validator.wasm | Bin 493285 -> 488237 bytes core/src/lib.rs | 80 +++++++++++++++- core/src/smartcontracts/isi/account.rs | 54 ++++++----- core/src/smartcontracts/isi/world.rs | 20 ++-- core/src/wsv.rs | 27 +++++- data_model/src/account.rs | 86 ++++++++++-------- data_model/src/events/data/filters.rs | 2 - data_model/src/role.rs | 7 +- docs/source/references/schema.json | 15 +-- schema/gen/src/lib.rs | 1 - .../parity_scale_decoder/samples/account.bin | Bin 30 -> 30 bytes .../parity_scale_decoder/samples/trigger.bin | Bin 80 -> 80 bytes 12 files changed, 196 insertions(+), 96 deletions(-) diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index addfc5d3d8daa8ae4bce07a361f6b376f7262240..d0673e6c06a37f3346e6046ca0a2193d290cf847 100644 GIT binary patch delta 139096 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 /// API to work with a collections of [`AccountId`] [`Permissions`] mappings. pub type PermissionTokensMap = HashMap; +/// API to work with a collections of [`AccountId`] to [`RoleId`] mappings. +pub type AccountRolesSet = BTreeSet; + /// Type of `Sender` which should be used for channels of `Event` messages. pub type EventsSender = broadcast::Sender; @@ -101,6 +104,37 @@ pub mod handler { } } +pub mod role { + //! Module with extension for [`RoleId`] to be stored inside wsv. + + use derive_more::Constructor; + use serde::{Deserialize, Serialize}; + + use super::*; + + /// [`RoleId`] with owner [`AccountId`] attached to it. + #[derive( + Debug, + Clone, + Constructor, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Decode, + Encode, + Deserialize, + Serialize, + )] + pub struct RoleIdWithOwner { + /// [`AccountId`] of the owner. + pub account_id: AccountId, + /// [`RoleId`] of the given role. + pub role_id: RoleId, + } +} + pub mod prelude { //! Re-exports important traits and types. Meant to be glob imported when using `Iroha`. @@ -114,3 +148,47 @@ pub mod prelude { wsv::{World, WorldStateView}, }; } + +#[cfg(test)] +mod tests { + use std::cmp::Ordering; + + use iroha_data_model::{account::AccountId, role::RoleId}; + + use crate::role::RoleIdWithOwner; + + #[test] + fn cmp_role_id_with_owner() { + let role_id_a: RoleId = "a".parse().expect("failed to parse RoleId"); + let role_id_b: RoleId = "b".parse().expect("failed to parse RoleId"); + let account_id_a: AccountId = "a@domain".parse().expect("failed to parse AccountId"); + let account_id_b: AccountId = "b@domain".parse().expect("failed to parse AccountId"); + + let mut role_ids_with_owner = Vec::new(); + for account_id in [&account_id_a, &account_id_b] { + for role_id in [&role_id_a, &role_id_b] { + role_ids_with_owner.push(RoleIdWithOwner { + role_id: role_id.clone(), + account_id: account_id.clone(), + }) + } + } + + for role_id_with_owner_1 in &role_ids_with_owner { + for role_id_with_owner_2 in &role_ids_with_owner { + match ( + role_id_with_owner_1.account_id.cmp(&role_id_with_owner_2.account_id), + role_id_with_owner_1.role_id.cmp(&role_id_with_owner_2.role_id), + ) { + // `AccountId` take precedence in comparison + // if `AccountId`s are equal than comparison based on `RoleId`s + (Ordering::Equal, ordering) | (ordering, _) => assert_eq!( + role_id_with_owner_1.cmp(role_id_with_owner_2), + ordering, + "{role_id_with_owner_1:?} and {role_id_with_owner_2:?} are expected to be {ordering:?}" + ), + } + } + } + } +} diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index 18c63fe99d2..4a11b03a7f8 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -1,7 +1,7 @@ //! This module contains implementations of smart-contract traits and instructions for [`Account`] structure //! and implementations of [`Query`]'s to [`WorldStateView`] about [`Account`]. -use iroha_data_model::{asset::AssetsMap, prelude::*, query::error::FindError, role::RoleIds}; +use iroha_data_model::{asset::AssetsMap, prelude::*, query::error::FindError}; use iroha_telemetry::metrics; use super::prelude::*; @@ -19,7 +19,6 @@ impl Registrable for iroha_data_model::account::NewAccount { assets: AssetsMap::default(), signature_check_condition: SignatureCheckCondition::default(), metadata: self.metadata, - roles: RoleIds::default(), } } } @@ -40,6 +39,7 @@ pub mod isi { }; use super::*; + use crate::role::RoleIdWithOwner; #[allow(clippy::expect_used, clippy::unwrap_in_result)] impl Execute for Register { @@ -312,7 +312,7 @@ pub mod isi { let permission = self.object; // Check if account exists - wsv.account_mut(&account_id)?; + wsv.account(&account_id)?; if !wsv.remove_account_permission(&account_id, &permission) { return Err(FindError::PermissionToken(permission.definition_id).into()); @@ -345,18 +345,19 @@ pub mod isi { .into_iter() .map(|token| token.definition_id); - wsv.account_mut(&account_id) - .map_err(Error::from) - .and_then(|account| { - if !account.add_role(role_id.clone()) { - return Err(RepetitionError { - instruction_type: InstructionType::Grant, - id: IdBox::RoleId(role_id.clone()), - } - .into()); - } - Ok(()) - })?; + wsv.account(&account_id)?; + + if !wsv + .world + .account_roles + .insert(RoleIdWithOwner::new(account_id.clone(), role_id.clone())) + { + return Err(RepetitionError { + instruction_type: InstructionType::Grant, + id: IdBox::RoleId(role_id), + } + .into()); + } wsv.emit_events({ let account_id_clone = account_id.clone(); @@ -395,12 +396,14 @@ pub mod isi { .into_iter() .map(|token| token.definition_id); - wsv.account_mut(&account_id).and_then(|account| { - if !account.remove_role(&role_id) { - return Err(FindError::Role(role_id.clone())); - } - Ok(()) - })?; + // TODO: clone could be avoided through `borrow` + if !wsv + .world + .account_roles + .remove(&RoleIdWithOwner::new(account_id.clone(), role_id.clone())) + { + return Err(FindError::Role(role_id).into()); + } wsv.emit_events({ let account_id_clone = account_id.clone(); @@ -499,10 +502,17 @@ pub mod query { .evaluate(&self.id) .wrap_err("Failed to evaluate account id") .map_err(|e| Error::Evaluate(e.to_string()))?; + let account_id_clone = account_id.clone(); iroha_logger::trace!(%account_id, roles=?wsv.world.roles); Ok(Box::new( - wsv.map_account(&account_id, |account| &account.roles)? + // TODO: more effective through `.range` + // Use the fact that `BTreeSet` is ordered + wsv.world + .account_roles .iter() + .skip_while(move |role| role.account_id.ne(&account_id)) + .take_while(move |role| role.account_id.eq(&account_id_clone)) + .map(|role| &role.role_id) .cloned(), )) } diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index 97bbdf43b69..089c3f2e778 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -146,18 +146,14 @@ pub mod isi { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let role_id = self.object_id; - let mut accounts_with_role = vec![]; - for domain in wsv.domains().values() { - let account_ids = domain.accounts.values().filter_map(|account| { - if account.roles.contains(&role_id) { - return Some(account.id().clone()); - } - - None - }); - - accounts_with_role.extend(account_ids); - } + let accounts_with_role = wsv + .world + .account_roles + .iter() + .filter(|role| role.role_id.eq(&role_id)) + .map(|role| &role.account_id) + .cloned() + .collect::>(); for account_id in accounts_with_role { let revoke = Revoke { diff --git a/core/src/wsv.rs b/core/src/wsv.rs index 33e271dc1f6..37d3770a9e4 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -70,6 +70,8 @@ pub struct World { pub(crate) roles: crate::RolesMap, /// Permission tokens of an account. pub(crate) account_permission_tokens: crate::PermissionTokensMap, + /// Roles of an account. + pub(crate) account_roles: crate::AccountRolesSet, /// Registered permission token ids. pub(crate) permission_token_schema: PermissionTokenSchema, /// Triggers @@ -169,6 +171,7 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, World> { let mut domains = None; let mut roles = None; let mut account_permission_tokens = None; + let mut account_roles = None; let mut permission_token_schema = None; let mut triggers = None; let mut validator = None; @@ -190,6 +193,9 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, World> { "account_permission_tokens" => { account_permission_tokens = Some(map.next_value()?); } + "account_roles" => { + account_roles = Some(map.next_value()?); + } "permission_token_schema" => { permission_token_schema = Some(map.next_value()?); } @@ -213,6 +219,8 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, World> { account_permission_tokens: account_permission_tokens.ok_or_else(|| { serde::de::Error::missing_field("account_permission_tokens") })?, + account_roles: account_roles + .ok_or_else(|| serde::de::Error::missing_field("account_roles"))?, permission_token_schema: permission_token_schema.ok_or_else(|| { serde::de::Error::missing_field("permission_token_schema") })?, @@ -232,6 +240,7 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, World> { "domains", "roles", "account_permission_tokens", + "account_roles", "permission_token_schema", "triggers", "validator", @@ -419,14 +428,20 @@ impl WorldStateView { &self, account_id: &AccountId, ) -> Result, FindError> { - let account = self.account(account_id)?; + self.account(account_id)?; let mut tokens = self .account_inherent_permission_tokens(account_id) .collect::>(); - for role_id in &account.roles { - if let Some(role) = self.world.roles.get(role_id) { + for role in self + .world + .account_roles + .iter() + .skip_while(|role| role.account_id.ne(account_id)) + .take_while(|role| role.account_id.eq(account_id)) + { + if let Some(role) = self.world.roles.get(&role.role_id) { tokens.extend(role.permissions.iter()); } } @@ -974,7 +989,11 @@ impl WorldStateView { Ok(f(account)) } - fn account(&self, id: &AccountId) -> Result<&Account, FindError> { + /// Get `Account` and return reference to it. + /// + /// # Errors + /// Fails if there is no domain or account + pub fn account(&self, id: &AccountId) -> Result<&Account, FindError> { self.domain(&id.domain_id).and_then(|domain| { domain .accounts diff --git a/data_model/src/account.rs b/data_model/src/account.rs index aeb5269a829..b1c61a55fed 100644 --- a/data_model/src/account.rs +++ b/data_model/src/account.rs @@ -12,7 +12,7 @@ use core::str::FromStr; #[cfg(feature = "std")] use std::collections::{btree_map, btree_set}; -use derive_more::{Constructor, DebugCustom, Display}; +use derive_more::{DebugCustom, Display}; use getset::Getters; use iroha_data_model_derive::{model, IdEqOrdHash}; use iroha_primitives::{const_vec::ConstVec, must_use::MustUse}; @@ -29,8 +29,8 @@ use crate::{ }, domain::prelude::*, metadata::Metadata, - role::{prelude::RoleId, RoleIds}, - HasMetadata, Identifiable, Name, ParseError, PublicKey, Registered, + name::Name, + HasMetadata, Identifiable, ParseError, PublicKey, Registered, }; /// API to work with collections of [`Id`] : [`Account`] mappings. @@ -66,7 +66,6 @@ pub mod model { PartialOrd, Ord, Hash, - Constructor, Getters, Decode, Encode, @@ -79,10 +78,10 @@ pub mod model { #[getset(get = "pub")] #[ffi_type] pub struct AccountId { - /// [`Account`]'s name. - pub name: Name, /// [`Account`]'s [`Domain`](`crate::domain::Domain`) id. pub domain_id: DomainId, + /// [`Account`]'s name. + pub name: Name, } /// Account entity is an authority which is used to execute `Iroha Special Instructions`. @@ -113,8 +112,6 @@ pub mod model { pub signature_check_condition: SignatureCheckCondition, /// Metadata of this account as a key-value store. pub metadata: Metadata, - /// Roles of this account, they are tags for sets of permissions stored in `World`. - pub roles: RoleIds, } /// Builder which should be submitted in a transaction to create a new [`Account`] @@ -158,6 +155,14 @@ pub mod model { } } +impl AccountId { + /// Construct [`Self`]. + // NOTE: not derived to preserve order of fields in which [`Self`] is parsed from string + pub fn new(name: Name, domain_id: DomainId) -> Self { + Self { domain_id, name } + } +} + impl Account { /// Construct builder for [`Account`] identifiable by [`Id`] containing the given signatories. #[inline] @@ -187,23 +192,11 @@ impl Account { self.assets.values() } - /// Get an iterator over [`role ids`](RoleId) of the `Account` - #[inline] - pub fn roles(&self) -> impl ExactSizeIterator { - self.roles.iter() - } - /// Return `true` if the `Account` contains the given signatory #[inline] pub fn contains_signatory(&self, signatory: &PublicKey) -> bool { self.signatories.contains(signatory) } - - /// Return `true` if `Account` contains the given role - #[inline] - pub fn contains_role(&self, role_id: &RoleId) -> bool { - self.roles.contains(role_id) - } } #[cfg(feature = "transparent_api")] @@ -219,22 +212,6 @@ impl Account { pub fn remove_asset(&mut self, asset_id: &AssetId) -> Option { self.assets.remove(asset_id) } - - /// Add [`Role`](crate::role::Role) into the [`Account`]. - /// - /// If `Account` did not have this role present, `true` is returned. - /// If `Account` did have this role present, `false` is returned. - #[inline] - pub fn add_role(&mut self, role_id: RoleId) -> bool { - self.roles.insert(role_id) - } - - /// Remove a role from the `Account` and return whether the role was present in the `Account` - #[inline] - pub fn remove_role(&mut self, role_id: &RoleId) -> bool { - self.roles.remove(role_id) - } - /// Add [`signatory`](PublicKey) into the [`Account`]. /// /// If `Account` did not have this signatory present, `true` is returned. @@ -365,9 +342,12 @@ pub mod prelude { #[cfg(test)] mod tests { + use core::cmp::Ordering; + use iroha_crypto::{KeyPair, PublicKey}; - use super::SignatureCheckCondition; + use super::{AccountId, SignatureCheckCondition}; + use crate::{domain::DomainId, name::Name}; fn make_key() -> PublicKey { KeyPair::generate().unwrap().public_key().clone() @@ -458,4 +438,36 @@ mod tests { check_signature_check_condition(&condition, &[&key2], &[&key1, &key3], false); check_signature_check_condition(&condition, &[&key2], &[&key1, &key2, &key3], true); } + + #[test] + fn cmp_account_id() { + let domain_id_a: DomainId = "a".parse().expect("failed to parse DomainId"); + let domain_id_b: DomainId = "b".parse().expect("failed to parse DomainId"); + let name_a: Name = "a".parse().expect("failed to parse Name"); + let name_b: Name = "b".parse().expect("failed to parse Name"); + + let mut account_ids = Vec::new(); + for name in [&name_a, &name_b] { + for domain_id in [&domain_id_a, &domain_id_b] { + account_ids.push(AccountId::new(name.clone(), domain_id.clone())); + } + } + + for account_id_1 in &account_ids { + for account_id_2 in &account_ids { + match ( + account_id_1.domain_id.cmp(&account_id_2.domain_id), + account_id_1.name.cmp(&account_id_2.name), + ) { + // `DomainId` take precedence in comparison + // if `DomainId`s are equal than comparison based on `Name`s + (Ordering::Equal, ordering) | (ordering, _) => assert_eq!( + account_id_1.cmp(account_id_2), + ordering, + "{account_id_1:?} and {account_id_2:?} are expected to be {ordering:?}" + ), + } + } + } + } } diff --git a/data_model/src/events/data/filters.rs b/data_model/src/events/data/filters.rs index 28ef6df113e..b9d1cb52c44 100644 --- a/data_model/src/events/data/filters.rs +++ b/data_model/src/events/data/filters.rs @@ -212,7 +212,6 @@ mod tests { use crate::{ account::AccountsMap, asset::{AssetDefinitionsMap, AssetTotalQuantityMap, AssetsMap}, - role::RoleIds, }; #[test] @@ -238,7 +237,6 @@ mod tests { signatories: BTreeSet::default(), signature_check_condition: SignatureCheckCondition::default(), metadata: Metadata::default(), - roles: RoleIds::default(), }; let asset_id = AssetId::new( AssetDefinitionId::new(asset_name, domain_id), diff --git a/data_model/src/role.rs b/data_model/src/role.rs index 68f23499373..eedf399030c 100644 --- a/data_model/src/role.rs +++ b/data_model/src/role.rs @@ -1,9 +1,7 @@ //! Structures, traits and impls related to `Role`s. #[cfg(not(feature = "std"))] -use alloc::{collections::btree_set, format, string::String, vec::Vec}; -#[cfg(feature = "std")] -use std::collections::btree_set; +use alloc::{format, string::String, vec::Vec}; use derive_more::{Constructor, Display, FromStr}; use getset::Getters; @@ -18,9 +16,6 @@ use crate::{ Identifiable, Name, Registered, }; -/// Collection of [`RoleId`](Id)s -pub type RoleIds = btree_set::BTreeSet; - #[model] pub mod model { use super::*; diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index ade55770432..b149209bcd6 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -20,10 +20,6 @@ { "name": "metadata", "type": "Metadata" - }, - { - "name": "roles", - "type": "SortedVec" } ] }, @@ -149,13 +145,13 @@ }, "AccountId": { "Struct": [ - { - "name": "name", - "type": "Name" - }, { "name": "domain_id", "type": "DomainId" + }, + { + "name": "name", + "type": "Name" } ] }, @@ -4151,9 +4147,6 @@ "SortedVec": { "Vec": "PublicKey" }, - "SortedVec": { - "Vec": "RoleId" - }, "SortedVec>": { "Vec": "SignatureOf" }, diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index 766c76b0ef7..c6f384f62a9 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -98,7 +98,6 @@ types!( BTreeMap, BTreeSet, BTreeSet, - BTreeSet, BatchedResponse, BatchedResponse>, BatchedResponseV1, diff --git a/tools/parity_scale_decoder/samples/account.bin b/tools/parity_scale_decoder/samples/account.bin index 5a2dd9b72f1b7ac176fe54f269c92a4383c148a2..04aea960c0ea34cdacbcb9a926a181e98007dd34 100644 GIT binary patch literal 30 lcmdNW&(BLqEy_vEOA$%T$xKdVVByI~EMXEU&&VuE1puGN3GDy? literal 30 lcmWeh%*jkn)hN%;OGz!tNz6-OVByI~EMXEU&&VuE1pu6h3GDy? diff --git a/tools/parity_scale_decoder/samples/trigger.bin b/tools/parity_scale_decoder/samples/trigger.bin index 99b44b464041e5d82e98cce35e3d10a5bc67e3b0..ed5af47caea213d4ef2283aeb46e194b0250c15a 100644 GIT binary patch delta 45 lcmWFtn4qDdQJ$Zdl3J9Ln3p1wn3I{D%77ul$jHRN003vn4pjgE delta 45 lcmWFtn4qB{l9-d3oT^ctpO=zal#`g3!hj*d$jHRN003c44pjgE From fb19bb1e35b393c93feac5a07eedaf0c9628176d Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Tue, 26 Sep 2023 16:23:44 +0300 Subject: [PATCH 32/55] [refactor]: Range queries for roles Signed-off-by: Shanin Roman --- core/src/smartcontracts/isi/account.rs | 14 +-- core/src/wsv.rs | 107 ++++++++++++++++-- primitives/src/cmpext.rs | 144 +++++++++++++++++++++++++ primitives/src/lib.rs | 1 + 4 files changed, 245 insertions(+), 21 deletions(-) create mode 100644 primitives/src/cmpext.rs diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index 4a11b03a7f8..355e8a27299 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -502,19 +502,9 @@ pub mod query { .evaluate(&self.id) .wrap_err("Failed to evaluate account id") .map_err(|e| Error::Evaluate(e.to_string()))?; - let account_id_clone = account_id.clone(); iroha_logger::trace!(%account_id, roles=?wsv.world.roles); - Ok(Box::new( - // TODO: more effective through `.range` - // Use the fact that `BTreeSet` is ordered - wsv.world - .account_roles - .iter() - .skip_while(move |role| role.account_id.ne(&account_id)) - .take_while(move |role| role.account_id.eq(&account_id_clone)) - .map(|role| &role.role_id) - .cloned(), - )) + wsv.account(&account_id)?; + Ok(Box::new(wsv.account_roles(&account_id).cloned())) } } diff --git a/core/src/wsv.rs b/core/src/wsv.rs index 37d3770a9e4..7a5c9073de3 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -36,6 +36,7 @@ use iroha_data_model::{ use iroha_logger::prelude::*; use iroha_primitives::small::SmallVec; use parking_lot::Mutex; +use range_bounds::RoleIdByAccountBounds; use serde::{ de::{DeserializeSeed, MapAccess, Visitor}, Deserializer, Serialize, @@ -419,6 +420,14 @@ impl WorldStateView { self.map_account(id, |account| account.assets.values()) } + /// Get [`Account`]'s [`RoleId`]s + pub fn account_roles(&self, id: &AccountId) -> impl Iterator { + self.world + .account_roles + .range(RoleIdByAccountBounds::new(id)) + .map(|role| &role.role_id) + } + /// Return a set of all permission tokens granted to this account. /// /// # Errors @@ -434,14 +443,8 @@ impl WorldStateView { .account_inherent_permission_tokens(account_id) .collect::>(); - for role in self - .world - .account_roles - .iter() - .skip_while(|role| role.account_id.ne(account_id)) - .take_while(|role| role.account_id.eq(account_id)) - { - if let Some(role) = self.world.roles.get(&role.role_id) { + for role_id in self.account_roles(account_id) { + if let Some(role) = self.world.roles.get(role_id) { tokens.extend(role.permissions.iter()); } } @@ -1261,6 +1264,70 @@ impl WorldStateView { } } +/// Bounds for `range` queries +mod range_bounds { + use core::ops::{Bound, RangeBounds}; + + use iroha_primitives::{cmpext::MinMaxExt, impl_as_dyn_key}; + + use super::*; + use crate::role::RoleIdWithOwner; + + /// Key for range queries over account for roles + #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] + pub struct RoleIdByAccount<'role> { + account_id: &'role AccountId, + role_id: MinMaxExt<&'role RoleId>, + } + + /// Bounds for range quired over account for roles + pub struct RoleIdByAccountBounds<'role> { + start: RoleIdByAccount<'role>, + end: RoleIdByAccount<'role>, + } + + impl<'role> RoleIdByAccountBounds<'role> { + /// Create range bounds for range quires of roles over account + pub fn new(account_id: &'role AccountId) -> Self { + Self { + start: RoleIdByAccount { + account_id, + role_id: MinMaxExt::Min, + }, + end: RoleIdByAccount { + account_id, + role_id: MinMaxExt::Max, + }, + } + } + } + + impl<'role> RangeBounds for RoleIdByAccountBounds<'role> { + fn start_bound(&self) -> Bound<&(dyn AsRoleIdByAccount + 'role)> { + Bound::Excluded(&self.start) + } + + fn end_bound(&self) -> Bound<&(dyn AsRoleIdByAccount + 'role)> { + Bound::Excluded(&self.end) + } + } + + impl AsRoleIdByAccount for RoleIdWithOwner { + fn as_key(&self) -> RoleIdByAccount<'_> { + RoleIdByAccount { + account_id: &self.account_id, + role_id: (&self.role_id).into(), + } + } + } + + impl_as_dyn_key! { + target: RoleIdWithOwner, + key: RoleIdByAccount<'_>, + trait: AsRoleIdByAccount + } +} + #[cfg(test)] mod tests { #![allow(clippy::restriction)] @@ -1268,7 +1335,7 @@ mod tests { use iroha_primitives::unique_vec::UniqueVec; use super::*; - use crate::{block::ValidBlock, sumeragi::network_topology::Topology}; + use crate::{block::ValidBlock, role::RoleIdWithOwner, sumeragi::network_topology::Topology}; #[test] fn get_block_hashes_after_hash() { @@ -1324,4 +1391,26 @@ mod tests { &[8, 9, 10] ); } + + #[test] + fn role_account_range() { + let account_id: AccountId = "alice@wonderland".parse().unwrap(); + let roles = [ + RoleIdWithOwner::new(account_id.clone(), "1".parse().unwrap()), + RoleIdWithOwner::new(account_id.clone(), "2".parse().unwrap()), + RoleIdWithOwner::new("bob@wonderland".parse().unwrap(), "3".parse().unwrap()), + RoleIdWithOwner::new("a@wonderland".parse().unwrap(), "4".parse().unwrap()), + RoleIdWithOwner::new("0@0".parse().unwrap(), "5".parse().unwrap()), + RoleIdWithOwner::new("1@1".parse().unwrap(), "6".parse().unwrap()), + ]; + let map = BTreeSet::from(roles); + + let range = map + .range(RoleIdByAccountBounds::new(&account_id)) + .collect::>(); + assert_eq!(range.len(), 2); + for role in range { + assert_eq!(&role.account_id, &account_id); + } + } } diff --git a/primitives/src/cmpext.rs b/primitives/src/cmpext.rs new file mode 100644 index 00000000000..f0905a836a0 --- /dev/null +++ b/primitives/src/cmpext.rs @@ -0,0 +1,144 @@ +//! Utilities to work with [`BTreeMap`]/[`BTreeSet`] `get`/`range` functions. + +use core::cmp::Ordering; + +/// Type which adds two additional values for any type: +/// - `Min` which is smaller that any value of this type +/// - `Max` which is greater that any value of this type +/// +/// Used to enable query over prefix of the given key in the b-tree e.g. by account id in the asset id. +/// +/// Suppose compound key of three parts: `K = (A, B, C)`. +/// So that in sorting order keys will be sorted firstly by `A` then `B` and `C`. +/// This keys are stored in `BTreeMap` and it's required to extract all keys which have `A == a`. +/// To do this it's possible to use `range` provided by `BTreeMap`, +/// but it would't be enough to simply use `(a..=a)` bound for `K` because ranges bounds are found by binary search +/// and this way any key which has `A == a` can be treated as bound. +/// So `MinMaxExt` is used to express precise bound for such query: `(a, MIN, MIN)..(a, MAX, MAX)`. +#[derive(Debug, Clone, Copy)] +pub enum MinMaxExt { + /// Value that is greater than any value + Min, + /// Value that is smaller than any value + Max, + /// Regular value + Value(T), +} + +impl PartialEq for MinMaxExt { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Value(lhs), Self::Value(rhs)) => lhs.eq(rhs), + (Self::Min, Self::Min) | (Self::Max, Self::Max) => true, + _ => false, + } + } +} + +impl Eq for MinMaxExt {} + +impl PartialOrd for MinMaxExt { + fn partial_cmp(&self, other: &Self) -> Option { + match (self, other) { + (Self::Value(lhs), Self::Value(rhs)) => lhs.partial_cmp(rhs), + (lhs, rhs) if lhs == rhs => Some(Ordering::Equal), + (Self::Min, _) | (_, Self::Max) => Some(Ordering::Less), + (Self::Max, _) | (_, Self::Min) => Some(Ordering::Greater), + } + } +} + +impl Ord for MinMaxExt { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (Self::Value(lhs), Self::Value(rhs)) => lhs.cmp(rhs), + (lhs, rhs) if lhs == rhs => Ordering::Equal, + (Self::Min, _) | (_, Self::Max) => Ordering::Less, + (Self::Max, _) | (_, Self::Min) => Ordering::Greater, + } + } +} + +impl From for MinMaxExt { + fn from(value: T) -> Self { + MinMaxExt::Value(value) + } +} + +/// Helper macro to enable cast of key to dyn object and derive required traits for it. +/// Used to bypass limitation of [`Borrow`] which wouldn't allow to create object and return reference to it. +#[macro_export] +macro_rules! impl_as_dyn_key { + (target: $ty:ident, key: $key:ty, trait: $trait:ident) => { + /// Trait to key from type + pub trait $trait { + /// Extract key + fn as_key(&self) -> $key; + } + + impl $trait for $key { + fn as_key(&self) -> $key { + *self + } + } + + impl PartialEq for dyn $trait + '_ { + fn eq(&self, other: &Self) -> bool { + self.as_key() == other.as_key() + } + } + + impl Eq for dyn $trait + '_ {} + + impl PartialOrd for dyn $trait + '_ { + fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> { + self.as_key().partial_cmp(&other.as_key()) + } + } + + impl Ord for dyn $trait + '_ { + fn cmp(&self, other: &Self) -> ::core::cmp::Ordering { + self.as_key().cmp(&other.as_key()) + } + } + + impl<'lt> ::core::borrow::Borrow for $ty { + fn borrow(&self) -> &(dyn $trait + 'lt) { + self + } + } + }; +} + +/// TODO: good candidate for `prop_test` +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn any_larger_min() { + let values = [u64::MIN, u64::MAX]; + + for value in values { + assert!(MinMaxExt::Min < value.into()) + } + } + + #[test] + fn any_smaller_max() { + let values = [u64::MIN, u64::MAX]; + + for value in values { + assert!(MinMaxExt::Max > value.into()) + } + } + + #[test] + fn eq_still_eq() { + let values = [u64::MIN, u64::MAX]; + + for value in values { + assert!(MinMaxExt::from(value) == MinMaxExt::from(value)) + } + } +} diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index faf1990c37b..1ec497539f0 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -12,6 +12,7 @@ extern crate alloc; pub mod addr; +pub mod cmpext; #[cfg(not(feature = "ffi_import"))] pub mod const_vec; #[cfg(not(feature = "ffi_import"))] From 64acdbc0c42fb7afcf5972bb8dee8989112a71af Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Thu, 28 Sep 2023 10:48:47 +0300 Subject: [PATCH 33/55] [refactor]: Avoid clone in roles lookup Signed-off-by: Shanin Roman --- core/src/lib.rs | 25 +++++++++++++++++++++++++ core/src/smartcontracts/isi/account.rs | 5 ++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index 8516fe0aea1..80093250ece 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -108,6 +108,7 @@ pub mod role { //! Module with extension for [`RoleId`] to be stored inside wsv. use derive_more::Constructor; + use iroha_primitives::impl_as_dyn_key; use serde::{Deserialize, Serialize}; use super::*; @@ -133,6 +134,30 @@ pub mod role { /// [`RoleId`] of the given role. pub role_id: RoleId, } + + /// Reference to [`RoleIdWithOwner`]. + #[derive(Debug, Clone, Copy, Constructor, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct RoleIdWithOwnerRef<'role> { + /// [`AccountId`] of the owner. + pub account_id: &'role AccountId, + /// [`RoleId`] of the given role. + pub role_id: &'role RoleId, + } + + impl AsRoleIdWithOwnerRef for RoleIdWithOwner { + fn as_key(&self) -> RoleIdWithOwnerRef<'_> { + RoleIdWithOwnerRef { + account_id: &self.account_id, + role_id: &self.role_id, + } + } + } + + impl_as_dyn_key! { + target: RoleIdWithOwner, + key: RoleIdWithOwnerRef<'_>, + trait: AsRoleIdWithOwnerRef + } } pub mod prelude { diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index 355e8a27299..db01e02b787 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -39,7 +39,7 @@ pub mod isi { }; use super::*; - use crate::role::RoleIdWithOwner; + use crate::role::{AsRoleIdWithOwnerRef, RoleIdWithOwner, RoleIdWithOwnerRef}; #[allow(clippy::expect_used, clippy::unwrap_in_result)] impl Execute for Register { @@ -396,11 +396,10 @@ pub mod isi { .into_iter() .map(|token| token.definition_id); - // TODO: clone could be avoided through `borrow` if !wsv .world .account_roles - .remove(&RoleIdWithOwner::new(account_id.clone(), role_id.clone())) + .remove::(&RoleIdWithOwnerRef::new(&account_id, &role_id)) { return Err(FindError::Role(role_id).into()); } From be7fc65dacb1f07c5d736fb9153425bab2154b90 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Mon, 2 Oct 2023 09:01:04 +0300 Subject: [PATCH 34/55] [fix] #3939: Fix the usage of `Span::join` Actually, `Span::join` doesn't work on stable at all, so care should be taken to have a fallback This means that on stable we will have error spans that are slightly incorrect Signed-off-by: Nikita Strygin --- ffi/derive/src/attr_parse/getset.rs | 2 +- ffi/derive/src/attr_parse/repr.rs | 3 ++- ffi/derive/src/convert.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ffi/derive/src/attr_parse/getset.rs b/ffi/derive/src/attr_parse/getset.rs index 471f13af610..aaba372924e 100644 --- a/ffi/derive/src/attr_parse/getset.rs +++ b/ffi/derive/src/attr_parse/getset.rs @@ -144,7 +144,7 @@ impl syn2::parse::Parse for SpannedGetSetAttrToken { let span = ident .span() .join(options.span) - .expect("must be in the same file"); + .unwrap_or_else(|| ident.span()); Ok(SpannedGetSetAttrToken { span, diff --git a/ffi/derive/src/attr_parse/repr.rs b/ffi/derive/src/attr_parse/repr.rs index 770e0022753..5cd10492231 100644 --- a/ffi/derive/src/attr_parse/repr.rs +++ b/ffi/derive/src/attr_parse/repr.rs @@ -78,7 +78,8 @@ impl Parse for SpannedReprToken { let Some((inside_of_group, group_span, after_group)) = after_token.group(Delimiter::Parenthesis) else { return Err(cursor.error("Expected a number inside of a `repr(aligned()), found `repr(aligned)`")); }; - span = span.join(group_span.span()).expect("Spans must be in the same file"); + + span = span.join(group_span.span()).unwrap_or(span); let alignment = syn2::parse2::(inside_of_group.token_stream())?; let alignment = alignment.base10_parse::()?; diff --git a/ffi/derive/src/convert.rs b/ffi/derive/src/convert.rs index d8995fedc4f..5c835c9bd4a 100644 --- a/ffi/derive/src/convert.rs +++ b/ffi/derive/src/convert.rs @@ -59,7 +59,7 @@ impl syn2::parse::Parse for SpannedFfiTypeToken { let Some((inside_of_group, group_span, after_group)) = after_token.group(Delimiter::Brace) else { return Err(cursor.error("expected `{ ... }` after `unsafe`")) }; - span = span.join(group_span.span()).expect("Spans must be in the same file"); + span = span.join(group_span.span()).unwrap_or(span); let Some((token, after_token)) = inside_of_group.ident() else { return Err(cursor.error("expected ffi type kind")) From 24b51da66c0186052404bb11fc489d7a865beb81 Mon Sep 17 00:00:00 2001 From: AlexStroke <111361420+AlexStroke@users.noreply.github.com> Date: Wed, 4 Oct 2023 11:02:06 +0400 Subject: [PATCH 35/55] [ci] #3768: add client cli tests into CI (#3818) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [refactor] update name and place of consistency tests Signed-off-by: alexstroke <111361420+astrokov7@users.noreply.github.com> * [feature] add client cli tests to CI Signed-off-by: alexstroke <111361420+astrokov7@users.noreply.github.com> * [fix] debug workflow Signed-off-by: alexstroke <111361420+astrokov7@users.noreply.github.com> * [feature] activate debug build Signed-off-by: alexstroke <111361420+astrokov7@users.noreply.github.com> * [feature] add caсh for poetry depedencies Signed-off-by: alexstroke <111361420+astrokov7@users.noreply.github.com> * [refactor] revert general image after debug Signed-off-by: alexstroke <111361420+astrokov7@users.noreply.github.com> * Update iroha2-dev-pr.yml Signed-off-by: BAStos525 <66615487+BAStos525@users.noreply.github.com> * [ci]: use self-hosted runner Signed-off-by: BAStos525 <66615487+BAStos525@users.noreply.github.com> * [ci]: use hyperledger ci image Signed-off-by: BAStos525 <66615487+BAStos525@users.noreply.github.com> * [ci]: apply suggestions Signed-off-by: BAStos525 <66615487+BAStos525@users.noreply.github.com> --------- Signed-off-by: alexstroke <111361420+astrokov7@users.noreply.github.com> Signed-off-by: BAStos525 <66615487+BAStos525@users.noreply.github.com> Co-authored-by: astrokov7 <111361420+astrokov7@users.noreply.github.com> Co-authored-by: BAStos525 <66615487+BAStos525@users.noreply.github.com> --- .github/workflows/iroha2-dev-pr.yml | 57 +++++++++++++++++++--- Dockerfile.build | 15 +++++- scripts/{check.sh => tests/consistency.sh} | 0 3 files changed, 63 insertions(+), 9 deletions(-) rename scripts/{check.sh => tests/consistency.sh} (100%) diff --git a/.github/workflows/iroha2-dev-pr.yml b/.github/workflows/iroha2-dev-pr.yml index 5356fb282a9..9cd86bea4bf 100644 --- a/.github/workflows/iroha2-dev-pr.yml +++ b/.github/workflows/iroha2-dev-pr.yml @@ -20,7 +20,7 @@ env: CARGO_TERM_COLOR: always jobs: - check: + consistency: runs-on: [self-hosted, Linux, iroha2ci] container: image: hyperledger/iroha2-ci:nightly-2023-06-25 @@ -29,22 +29,22 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Check config.md if: always() - run: ./scripts/check.sh docs + run: ./scripts/tests/consistency.sh docs - name: Check genesis.json if: always() - run: ./scripts/check.sh genesis + run: ./scripts/tests/consistency.sh genesis - name: Check client/config.json if: always() - run: ./scripts/check.sh client + run: ./scripts/tests/consistency.sh client - name: Check peer/config.json if: always() - run: ./scripts/check.sh peer + run: ./scripts/tests/consistency.sh peer - name: Check schema.json if: always() - run: ./scripts/check.sh schema + run: ./scripts/tests/consistency.sh schema - name: Check Docker Compose configurations if: always() - run: ./scripts/check.sh docker-compose + run: ./scripts/tests/consistency.sh docker-compose - name: Wasm build check if: always() working-directory: wasm @@ -137,3 +137,46 @@ jobs: file: Dockerfile # This context specification is required context: . + + client-cli-test: + runs-on: [self-hosted, Linux, iroha2ci] + container: + image: hyperledger/iroha2-ci:nightly-2023-06-25 + timeout-minutes: 60 + + steps: + - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 + - name: Build binaries + run: | + cargo build --bin iroha_client_cli + cargo build --bin kagami + cargo build --bin iroha + + - name: Mark binaries as executable + run: | + chmod +x $CLIENT_CLI_DIR/ + + - name: Run Iroha 2 on bare metal + run: | + ./scripts/test_env.py setup + + - name: Copy Iroha 2 client config + run: | + cp ./configs/client/config.json $CLIENT_CLI_DIR/ + + - name: Set up .env for client_cli tests + run: | + echo "CLIENT_CLI_DIR=$CLIENT_CLI_DIR" >> ./client_cli/pytests/.env + echo "TORII_API_PORT_MIN=8080" >> ./client_cli/pytests/.env + echo "TORII_API_PORT_MAX=8083" >> ./client_cli/pytests/.env + + - name: Install dependencies using Poetry + working-directory: client_cli/pytests + run: | + poetry install + + - name: Run client cli tests + working-directory: client_cli/pytests + run: | + poetry run pytest diff --git a/Dockerfile.build b/Dockerfile.build index c1d97aaa77e..7ad68def7fd 100644 --- a/Dockerfile.build +++ b/Dockerfile.build @@ -2,9 +2,20 @@ FROM archlinux:base-devel ENV RUSTUP_HOME=/usr/local/rustup \ CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH + PATH=/usr/local/cargo/bin:$PATH \ + POETRY_HOME=/opt/poetry \ + CLIENT_CLI_DIR=/__w/iroha/iroha/target/debug -RUN pacman -Syu rustup mold musl rust-musl openssl libgit2 git docker docker-buildx docker-compose --noconfirm +ENV PATH=$POETRY_HOME/bin:$PATH + +RUN pacman -Syu rustup mold musl rust-musl openssl libgit2 \ + git docker docker-buildx docker-compose \ + python python-pip --noconfirm --disable-download-timeout && \ + curl -sSL https://install.python-poetry.org | python3 - + +WORKDIR /client_cli/pytests +COPY /client_cli/pytests/pyproject.toml /client_cli/pytests/poetry.lock $WORKDIR +RUN poetry install RUN rustup toolchain install nightly-2023-06-25-x86_64-unknown-linux-gnu RUN rustup default nightly-2023-06-25-x86_64-unknown-linux-gnu diff --git a/scripts/check.sh b/scripts/tests/consistency.sh similarity index 100% rename from scripts/check.sh rename to scripts/tests/consistency.sh From 0310e670196989c82a390d172aeed3a67e8de259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Wed, 4 Oct 2023 10:02:52 +0200 Subject: [PATCH 36/55] [refactor]: move expression len out of public API into core (#3949) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- core/src/tx.rs | 144 +++++++++++++++++++++++++++++++++++++ data_model/src/evaluate.rs | 133 +++------------------------------- 2 files changed, 155 insertions(+), 122 deletions(-) diff --git a/core/src/tx.rs b/core/src/tx.rs index 2ea863f19cf..199fe4ed258 100644 --- a/core/src/tx.rs +++ b/core/src/tx.rs @@ -44,7 +44,151 @@ pub enum AcceptTransactionFail { UnexpectedGenesisAccountSignature, } +mod len { + use iroha_data_model::{expression::*, query::QueryBox, Value}; + + pub trait ExprLen { + fn len(&self) -> usize; + } + + impl> ExprLen for EvaluatesTo { + fn len(&self) -> usize { + self.expression.len() + } + } + + impl ExprLen for Expression { + fn len(&self) -> usize { + use Expression::*; + + match self { + Add(add) => add.len(), + Subtract(subtract) => subtract.len(), + Greater(greater) => greater.len(), + Less(less) => less.len(), + Equal(equal) => equal.len(), + Not(not) => not.len(), + And(and) => and.len(), + Or(or) => or.len(), + If(if_expression) => if_expression.len(), + Raw(raw) => raw.len(), + Query(query) => query.len(), + Contains(contains) => contains.len(), + ContainsAll(contains_all) => contains_all.len(), + ContainsAny(contains_any) => contains_any.len(), + Where(where_expression) => where_expression.len(), + ContextValue(context_value) => context_value.len(), + Multiply(multiply) => multiply.len(), + Divide(divide) => divide.len(), + Mod(modulus) => modulus.len(), + RaiseTo(raise_to) => raise_to.len(), + } + } + } + impl ExprLen for ContextValue { + fn len(&self) -> usize { + 1 + } + } + impl ExprLen for QueryBox { + fn len(&self) -> usize { + 1 + } + } + + impl ExprLen for Add { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + impl ExprLen for Subtract { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + impl ExprLen for Multiply { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + impl ExprLen for RaiseTo { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + impl ExprLen for Divide { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + impl ExprLen for Mod { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + impl ExprLen for Greater { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + impl ExprLen for Less { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + impl ExprLen for Equal { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + impl ExprLen for And { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + impl ExprLen for Or { + fn len(&self) -> usize { + self.left.len() + self.right.len() + 1 + } + } + + impl ExprLen for Not { + fn len(&self) -> usize { + self.expression.len() + 1 + } + } + + impl ExprLen for Contains { + fn len(&self) -> usize { + self.collection.len() + self.element.len() + 1 + } + } + impl ExprLen for ContainsAll { + fn len(&self) -> usize { + self.collection.len() + self.elements.len() + 1 + } + } + impl ExprLen for ContainsAny { + fn len(&self) -> usize { + self.collection.len() + self.elements.len() + 1 + } + } + + impl ExprLen for If { + fn len(&self) -> usize { + // TODO: This is wrong because we don't evaluate both branches + self.condition.len() + self.then.len() + self.otherwise.len() + 1 + } + } + impl ExprLen for Where { + fn len(&self) -> usize { + self.expression.len() + self.values.values().map(EvaluatesTo::len).sum::() + 1 + } + } +} + fn instruction_size(isi: &InstructionExpr) -> usize { + use len::ExprLen as _; use InstructionExpr::*; match isi { diff --git a/data_model/src/evaluate.rs b/data_model/src/evaluate.rs index 3179515bc34..c7a566277af 100644 --- a/data_model/src/evaluate.rs +++ b/data_model/src/evaluate.rs @@ -69,9 +69,6 @@ pub trait Evaluate { /// # Errors /// Concrete to each implementer. fn evaluate(&self, context: &C) -> Result; - - /// Number of underneath expressions. - fn len(&self) -> usize; } impl> Evaluate for EvaluatesTo @@ -85,10 +82,6 @@ where V::try_from(expr).map_err(|error| EvaluationError::Conversion(error.to_string())) } - - fn len(&self) -> usize { - self.expression.len() - } } impl Evaluate for Expression { @@ -132,33 +125,6 @@ impl Evaluate for Expression { Ok(result) } - - fn len(&self) -> usize { - use Expression::*; - - match self { - Add(add) => add.len(), - Subtract(subtract) => subtract.len(), - Greater(greater) => greater.len(), - Less(less) => less.len(), - Equal(equal) => equal.len(), - Not(not) => not.len(), - And(and) => and.len(), - Or(or) => or.len(), - If(if_expression) => if_expression.len(), - Raw(raw) => raw.len(), - Query(query) => query.len(), - Contains(contains) => contains.len(), - ContainsAll(contains_all) => contains_all.len(), - ContainsAny(contains_any) => contains_any.len(), - Where(where_expression) => where_expression.len(), - ContextValue(context_value) => context_value.len(), - Multiply(multiply) => multiply.len(), - Divide(divide) => divide.len(), - Mod(modulus) => modulus.len(), - RaiseTo(raise_to) => raise_to.len(), - } - } } impl Evaluate for ContextValue { @@ -170,10 +136,6 @@ impl Evaluate for ContextValue { .cloned() .ok_or_else(|| EvaluationError::Find(self.value_name.to_string())) } - - fn len(&self) -> usize { - 1 - } } mod numeric { @@ -207,10 +169,6 @@ mod numeric { Ok(result) } - - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 - } } impl Evaluate for Subtract { @@ -241,10 +199,6 @@ mod numeric { Ok(result) } - - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 - } } impl Evaluate for Multiply { @@ -275,10 +229,6 @@ mod numeric { Ok(result) } - - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 - } } impl Evaluate for RaiseTo { @@ -306,10 +256,6 @@ mod numeric { Ok(result) } - - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 - } } impl Evaluate for Divide { @@ -340,10 +286,6 @@ mod numeric { Ok(result) } - - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 - } } impl Evaluate for Mod { @@ -370,10 +312,6 @@ mod numeric { Ok(result) } - - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 - } } } @@ -399,10 +337,6 @@ mod logical { Ok(result) } - - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 - } } impl Evaluate for Less { @@ -424,22 +358,15 @@ mod logical { Ok(result) } - - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 - } } - impl Evaluate for Not { + impl Evaluate for Equal { type Value = bool; fn evaluate(&self, context: &C) -> Result { - let expression = self.expression.evaluate(context)?; - Ok(!expression) - } - - fn len(&self) -> usize { - self.expression.len() + 1 + let left = self.left.evaluate(context)?; + let right = self.right.evaluate(context)?; + Ok(left == right) } } @@ -451,10 +378,6 @@ mod logical { let right = self.right.evaluate(context)?; Ok(left && right) } - - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 - } } impl Evaluate for Or { @@ -465,9 +388,14 @@ mod logical { let right = self.right.evaluate(context)?; Ok(left || right) } + } - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 + impl Evaluate for Not { + type Value = bool; + + fn evaluate(&self, context: &C) -> Result { + let expression = self.expression.evaluate(context)?; + Ok(!expression) } } @@ -479,10 +407,6 @@ mod logical { let element = self.element.evaluate(context)?; Ok(collection.contains(&element)) } - - fn len(&self) -> usize { - self.collection.len() + self.element.len() + 1 - } } impl Evaluate for ContainsAll { @@ -493,10 +417,6 @@ mod logical { let elements = self.elements.evaluate(context)?; Ok(elements.iter().all(|element| collection.contains(element))) } - - fn len(&self) -> usize { - self.collection.len() + self.elements.len() + 1 - } } impl Evaluate for ContainsAny { @@ -507,24 +427,6 @@ mod logical { let elements = self.elements.evaluate(context)?; Ok(elements.iter().any(|element| collection.contains(element))) } - - fn len(&self) -> usize { - self.collection.len() + self.elements.len() + 1 - } - } - - impl Evaluate for Equal { - type Value = bool; - - fn evaluate(&self, context: &C) -> Result { - let left = self.left.evaluate(context)?; - let right = self.right.evaluate(context)?; - Ok(left == right) - } - - fn len(&self) -> usize { - self.left.len() + self.right.len() + 1 - } } } @@ -539,11 +441,6 @@ impl Evaluate for If { self.otherwise.evaluate(context) } } - - fn len(&self) -> usize { - // TODO: This is wrong because we don't evaluate both branches - self.condition.len() + self.then.len() + self.otherwise.len() + 1 - } } impl Evaluate for Where { @@ -565,10 +462,6 @@ impl Evaluate for Where { combined_context.update(additional_context?); self.expression.evaluate(&combined_context) } - - fn len(&self) -> usize { - self.expression.len() + self.values.values().map(EvaluatesTo::len).sum::() + 1 - } } impl Evaluate for QueryBox { @@ -579,10 +472,6 @@ impl Evaluate for QueryBox { .query(self) .map_err(|err| EvaluationError::Validation(Box::new(err))) } - - fn len(&self) -> usize { - 1 - } } #[model] From c151da227b54bf5c947f0cccc62123f924ca3aff Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Thu, 28 Sep 2023 10:29:54 +0300 Subject: [PATCH 37/55] [fix] #3928: Make failing the wasm tests actually fail the CI Signed-off-by: Nikita Strygin --- .github/workflows/iroha2-dev-pr-wasm.yaml | 2 + Cargo.lock | 12 +++- Cargo.toml | 1 + Dockerfile.build | 1 - Dockerfile.build.glibc | 1 - ffi/.cargo/config.toml | 2 +- tools/wasm_test_runner/Cargo.toml | 16 +++++ tools/wasm_test_runner/src/main.rs | 82 +++++++++++++++++++++++ wasm/.cargo/config.toml | 2 +- wasm/README.md | 4 +- wasm/src/lib.rs | 2 +- 11 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 tools/wasm_test_runner/Cargo.toml create mode 100644 tools/wasm_test_runner/src/main.rs diff --git a/.github/workflows/iroha2-dev-pr-wasm.yaml b/.github/workflows/iroha2-dev-pr-wasm.yaml index d78d1d03e2c..1b310b41a0f 100644 --- a/.github/workflows/iroha2-dev-pr-wasm.yaml +++ b/.github/workflows/iroha2-dev-pr-wasm.yaml @@ -47,5 +47,7 @@ jobs: steps: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 + - name: Install iroha_wasm_test_runner + run: cd .. && cargo install --path tools/wasm_test_runner - name: Run tests run: mold --run cargo test --tests --no-fail-fast --quiet diff --git a/Cargo.lock b/Cargo.lock index c03b35cc834..dd799b31c3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,9 +192,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arbitrary" @@ -3542,6 +3542,14 @@ dependencies = [ "wasmtime", ] +[[package]] +name = "iroha_wasm_test_runner" +version = "2.0.0-pre-rc.19" +dependencies = [ + "anyhow", + "wasmtime", +] + [[package]] name = "is-terminal" version = "0.4.9" diff --git a/Cargo.toml b/Cargo.toml index cfad00e687a..4ad54b655e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -319,6 +319,7 @@ members = [ "tools/parity_scale_decoder", "tools/swarm", "tools/wasm_builder_cli", + "tools/wasm_test_runner", "version", "version/derive", "wasm_codec", diff --git a/Dockerfile.build b/Dockerfile.build index 7ad68def7fd..41f5632342f 100644 --- a/Dockerfile.build +++ b/Dockerfile.build @@ -23,7 +23,6 @@ RUN rustup component add llvm-tools-preview clippy RUN rustup component add rust-src RUN rustup component add rustfmt RUN rustup target add wasm32-unknown-unknown -RUN cargo install webassembly-test-runner RUN cargo install cargo-llvm-cov # TODO: Figure out a way to pull in libgit2, which doesn't crash if this useless variable is gone. diff --git a/Dockerfile.build.glibc b/Dockerfile.build.glibc index 8ae5ff306c0..41471d32972 100644 --- a/Dockerfile.build.glibc +++ b/Dockerfile.build.glibc @@ -12,7 +12,6 @@ RUN rustup component add llvm-tools-preview clippy RUN rustup component add rust-src RUN rustup component add rustfmt RUN rustup target add wasm32-unknown-unknown -RUN cargo install webassembly-test-runner RUN cargo install cargo-llvm-cov # TODO: Figure out a way to pull in libgit2, which doesn't crash if this useless variable is gone. diff --git a/ffi/.cargo/config.toml b/ffi/.cargo/config.toml index 4ca8f7bc93b..10c68cf82ce 100644 --- a/ffi/.cargo/config.toml +++ b/ffi/.cargo/config.toml @@ -1,2 +1,2 @@ [target.wasm32-unknown-unknown] -runner = "webassembly-test-runner" +runner = "iroha_wasm_test_runner" diff --git a/tools/wasm_test_runner/Cargo.toml b/tools/wasm_test_runner/Cargo.toml new file mode 100644 index 00000000000..682ad1ccce1 --- /dev/null +++ b/tools/wasm_test_runner/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "iroha_wasm_test_runner" + +edition.workspace = true +version.workspace = true +authors.workspace = true +license.workspace = true + +[lints] +workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +wasmtime = { workspace = true } +anyhow = "1.0.75" diff --git a/tools/wasm_test_runner/src/main.rs b/tools/wasm_test_runner/src/main.rs new file mode 100644 index 00000000000..fe6bd7478d6 --- /dev/null +++ b/tools/wasm_test_runner/src/main.rs @@ -0,0 +1,82 @@ +//! A tool to run `WebAssembly` tests +//! +//! This copies functionality of `webassembly-test-runner`, but with an ability to indicate failure with an exit code. + +use std::process::ExitCode; + +use anyhow::{bail, Result}; +use wasmtime::{Engine, Instance, Module, Store}; + +struct TestMeta<'a> { + name: &'a str, + ignore: bool, +} + +fn main() -> Result { + let argv0 = std::env::args().next().unwrap(); + + let file = match std::env::args().nth(1) { + Some(it) => it, + None => { + bail!("usage: {} tests.wasm", argv0); + } + }; + // Modules can be compiled through either the text or binary format + let engine = Engine::default(); + let module = Module::from_file(&engine, &file)?; + let mut tests = Vec::new(); + for export in module.exports() { + if let Some(name) = export.name().strip_prefix("$webassembly-test$") { + let mut ignore = true; + let name = name.strip_prefix("ignore$").unwrap_or_else(|| { + ignore = false; + name + }); + tests.push((export, TestMeta { name, ignore })); + } + } + let total = tests.len(); + + eprintln!("\nrunning {} tests", total); + let mut store = Store::new(&engine, ()); + let mut instance = Instance::new(&mut store, &module, &[])?; + let mut passed = 0; + let mut failed = 0; + let mut ignored = 0; + for (export, meta) in tests { + eprint!("test {} ...", meta.name); + if meta.ignore { + ignored += 1; + eprintln!(" ignored") + } else { + let f = instance.get_typed_func::<(), ()>(&mut store, export.name())?; + + let pass = f.call(&mut store, ()).is_ok(); + if pass { + passed += 1; + eprintln!(" ok") + } else { + // Reset instance on test failure. WASM uses `panic=abort`, so + // `Drop`s are not called after test failures, and a failed test + // might leave an instance in an inconsistent state. + store = Store::new(&engine, ()); + instance = Instance::new(&mut store, &module, &[])?; + + failed += 1; + eprintln!(" FAILED") + } + } + } + eprintln!( + "\ntest result: {}. {} passed; {} failed; {} ignored;", + if failed > 0 { "FAILED" } else { "ok" }, + passed, + failed, + ignored, + ); + Ok(if failed > 0 { + ExitCode::FAILURE + } else { + ExitCode::SUCCESS + }) +} diff --git a/wasm/.cargo/config.toml b/wasm/.cargo/config.toml index 00ec8ee28dc..0134e4439a2 100644 --- a/wasm/.cargo/config.toml +++ b/wasm/.cargo/config.toml @@ -2,4 +2,4 @@ target = "wasm32-unknown-unknown" [target.wasm32-unknown-unknown] -runner = "webassembly-test-runner" +runner = "iroha_wasm_test_runner" diff --git a/wasm/README.md b/wasm/README.md index 8629f9966fd..b221dcc903a 100644 --- a/wasm/README.md +++ b/wasm/README.md @@ -8,10 +8,10 @@ Check the [WASM section of our tutorial](https://hyperledger.github.io/iroha-2-d ## Running tests -To be able to run tests compiled for `wasm32-unknown-unknown` target install `webassembly-test-runner`: +To be able to run tests compiled for `wasm32-unknown-unknown` target install `iroha_wasm_test_runner` from the root of the iroha repository: ```bash -cargo install webassembly-test-runner +cargo install --path tools/wasm_test_runner ``` Then run tests: diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 29b467f7681..fb97b6bac78 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -448,7 +448,7 @@ mod tests { } fn get_test_expression() -> EvaluatesTo { - Add::new(1_u32, 2_u32).into() + Add::new(2_u32, 3_u32).into() } #[no_mangle] From 604fafdf4a8a0bac0926f4686a201c5da4e57733 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Thu, 28 Sep 2023 15:31:04 +0300 Subject: [PATCH 38/55] [fix] #3928: Fix double free in wasm tests The `log` and `dbg` functions do not take the pointer ownership, but their mock versions used for testing did Signed-off-by: Nikita Strygin --- wasm/src/debug.rs | 8 +++++--- wasm/src/log.rs | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/wasm/src/debug.rs b/wasm/src/debug.rs index 0f81f10336d..ed88fa048f1 100644 --- a/wasm/src/debug.rs +++ b/wasm/src/debug.rs @@ -169,15 +169,17 @@ mod tests { use webassembly_test::webassembly_test; - use crate::_decode_from_raw; - fn get_dbg_message() -> &'static str { "dbg_message" } #[no_mangle] pub unsafe extern "C" fn _dbg_mock(ptr: *const u8, len: usize) { - assert_eq!(_decode_from_raw::(ptr, len), get_dbg_message()); + use parity_scale_codec::DecodeAll; + + // can't use _decode_from_raw here, because we must NOT take the ownership + let bytes = core::slice::from_raw_parts(ptr, len); + assert_eq!(String::decode_all(&mut &*bytes).unwrap(), get_dbg_message()); } #[webassembly_test] diff --git a/wasm/src/log.rs b/wasm/src/log.rs index 30cf22d3c58..2adcfede7f2 100644 --- a/wasm/src/log.rs +++ b/wasm/src/log.rs @@ -88,7 +88,6 @@ mod tests { use webassembly_test::webassembly_test; use super::*; - use crate::_decode_from_raw; fn get_log_message() -> &'static str { "log_message" @@ -96,7 +95,9 @@ mod tests { #[no_mangle] pub unsafe extern "C" fn _log_mock(ptr: *const u8, len: usize) { - let (log_level, msg) = _decode_from_raw::<(u8, String)>(ptr, len); + // can't use _decode_from_raw here, because we must NOT take the ownership + let bytes = core::slice::from_raw_parts(ptr, len); + let (log_level, msg) = <(u8, String)>::decode_all(&mut &*bytes).unwrap(); assert_eq!(log_level, 3); assert_eq!(msg, get_log_message()); } From 872276e9e424f95a94de45f1002a662ade07416d Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Wed, 4 Oct 2023 18:53:58 +0300 Subject: [PATCH 39/55] [refactor] #3950: Merge API and Telemetry endpoints into a single server Signed-off-by: Nikita Strygin --- cli/src/samples.rs | 3 +- cli/src/torii/routing.rs | 86 ++++++------------- client/src/client.rs | 15 +--- client/src/lib.rs | 7 +- client/tests/integration/asset_propagation.rs | 2 +- client/tests/integration/connected_peers.rs | 2 +- .../integration/multiple_blocks_created.rs | 2 +- .../integration/multisignature_account.rs | 2 +- .../integration/multisignature_transaction.rs | 5 +- client/tests/integration/restart_peer.rs | 2 +- client/tests/integration/unstable_network.rs | 5 +- config/iroha_test_config.json | 1 - config/src/client.rs | 29 +------ config/src/torii.rs | 9 +- configs/client/config.json | 1 - configs/peer/config.json | 1 - core/test_network/src/lib.rs | 58 ++++--------- docker-compose.dev.local.yml | 8 -- docker-compose.dev.single.yml | 2 - docker-compose.dev.yml | 8 -- docs/source/references/config.md | 16 +--- scripts/test_env.py | 4 +- scripts/tests/panic_on_invalid_genesis.sh | 1 - tools/kagami/src/config.rs | 3 +- tools/kagami/src/docs.rs | 2 +- tools/swarm/src/compose.rs | 79 +++++++---------- 26 files changed, 91 insertions(+), 262 deletions(-) diff --git a/cli/src/samples.rs b/cli/src/samples.rs index d023905d9db..eabd3bf784b 100644 --- a/cli/src/samples.rs +++ b/cli/src/samples.rs @@ -5,7 +5,7 @@ use std::{collections::HashSet, path::Path, str::FromStr}; use iroha_config::{ iroha::{Configuration, ConfigurationProxy}, sumeragi::TrustedPeers, - torii::{uri::DEFAULT_API_ADDR, DEFAULT_TORII_P2P_ADDR, DEFAULT_TORII_TELEMETRY_ADDR}, + torii::{uri::DEFAULT_API_ADDR, DEFAULT_TORII_P2P_ADDR}, }; use iroha_crypto::{KeyPair, PublicKey}; use iroha_data_model::{peer::PeerId, prelude::*}; @@ -69,7 +69,6 @@ pub fn get_config_proxy(peers: UniqueVec, key_pair: Option) -> torii: Some(iroha_config::torii::ConfigurationProxy { p2p_addr: Some(DEFAULT_TORII_P2P_ADDR.clone()), api_url: Some(DEFAULT_API_ADDR.clone()), - telemetry_url: Some(DEFAULT_TORII_TELEMETRY_ADDR.clone()), ..iroha_config::torii::ConfigurationProxy::default() }), block_sync: Some(iroha_config::block_sync::ConfigurationProxy { diff --git a/cli/src/torii/routing.rs b/cli/src/torii/routing.rs index c1ee5061f11..b61cd81cd78 100644 --- a/cli/src/torii/routing.rs +++ b/cli/src/torii/routing.rs @@ -475,11 +475,28 @@ impl Torii { } } - #[cfg(feature = "telemetry")] /// Helper function to create router. This router can tested without starting up an HTTP server - fn create_telemetry_router( - &self, - ) -> impl warp::Filter + Clone + Send { + #[allow(clippy::too_many_lines)] + fn create_api_router(&self) -> impl warp::Filter + Clone + Send { + let health_route = warp::get() + .and(warp::path(uri::HEALTH)) + .and_then(|| async { Ok::<_, Infallible>(handle_health()) }); + + let get_router = warp::get().and( + endpoint3( + handle_pending_transactions, + warp::path(uri::PENDING_TRANSACTIONS) + .and(add_state!(self.queue, self.sumeragi,)) + .and(paginate()), + ) + .or(endpoint2( + handle_get_configuration, + warp::path(uri::CONFIGURATION) + .and(add_state!(self.iroha_cfg)) + .and(warp::body::json()), + )), + ); + let status_path = warp::path(uri::STATUS); let get_router_status_precise = endpoint2( handle_status_precise, @@ -502,33 +519,11 @@ impl Torii { .and(add_state!(self.sumeragi.clone())) .and_then(|sumeragi| async { Ok::<_, Infallible>(handle_version(sumeragi).await) }); - warp::get() + #[cfg(feature = "telemetry")] + let get_router = get_router.or(warp::any() .and(get_router_status_precise.or(get_router_status_bare)) .or(get_router_metrics) - .or(get_api_version) - .with(warp::trace::request()) - } - - /// Helper function to create router. This router can tested without starting up an HTTP server - fn create_api_router(&self) -> impl warp::Filter + Clone + Send { - let health_route = warp::get() - .and(warp::path(uri::HEALTH)) - .and_then(|| async { Ok::<_, Infallible>(handle_health()) }); - - let get_router = warp::get().and( - endpoint3( - handle_pending_transactions, - warp::path(uri::PENDING_TRANSACTIONS) - .and(add_state!(self.queue, self.sumeragi,)) - .and(paginate()), - ) - .or(endpoint2( - handle_get_configuration, - warp::path(uri::CONFIGURATION) - .and(add_state!(self.iroha_cfg)) - .and(warp::body::json()), - )), - ); + .or(get_api_version)); #[cfg(feature = "schema-endpoint")] let get_router = get_router.or(warp::path(uri::SCHEMA) @@ -617,37 +612,6 @@ impl Torii { .with(warp::trace::request())) } - /// Start status and metrics endpoints. - /// - /// # Errors - /// Can fail due to listening to network or if http server fails - #[cfg(feature = "telemetry")] - fn start_telemetry(self: Arc) -> eyre::Result>> { - let telemetry_url = &self.iroha_cfg.torii.telemetry_url; - - let mut handles = vec![]; - match telemetry_url.to_socket_addrs() { - Ok(addrs) => { - for addr in addrs { - let torii = Arc::clone(&self); - - let telemetry_router = torii.create_telemetry_router(); - let signal_fut = async move { torii.notify_shutdown.notified().await }; - let (_, serve_fut) = - warp::serve(telemetry_router).bind_with_graceful_shutdown(addr, signal_fut); - - handles.push(task::spawn(serve_fut)); - } - - Ok(handles) - } - Err(error) => { - iroha_logger::error!(%telemetry_url, ?error, "Telemetry address configuration parse error"); - Err(eyre::Error::new(error)) - } - } - } - /// Start main api endpoints. /// /// # Errors @@ -689,8 +653,6 @@ impl Torii { let torii = Arc::new(self); let mut handles = vec![]; - #[cfg(feature = "telemetry")] - handles.extend(Arc::clone(&torii).start_telemetry()?); handles.extend(Arc::clone(&torii).start_api()?); handles.push( Arc::clone(&torii.query_store) diff --git a/client/src/client.rs b/client/src/client.rs index ee61666141c..6703547e811 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -340,15 +340,13 @@ impl_query_result! { /// Iroha client #[derive(Clone, DebugCustom, Display)] #[debug( - fmt = "Client {{ torii: {torii_url}, telemetry_url: {telemetry_url}, public_key: {} }}", + fmt = "Client {{ torii: {torii_url}, public_key: {} }}", "key_pair.public_key()" )] #[display(fmt = "{}@{torii_url}", "key_pair.public_key()")] pub struct Client { /// Url for accessing iroha node torii_url: Url, - /// Url to report status for administration - telemetry_url: Url, /// Accounts keypair key_pair: KeyPair, /// Transaction time to live in milliseconds @@ -432,7 +430,6 @@ impl Client { Ok(Self { torii_url: configuration.torii_api_url.clone(), - telemetry_url: configuration.torii_telemetry_url.clone(), key_pair: KeyPair::new( configuration.public_key.clone(), configuration.private_key.clone(), @@ -1225,7 +1222,7 @@ impl Client { pub fn prepare_status_request(&self) -> B { B::new( HttpMethod::GET, - self.telemetry_url.join(uri::STATUS).expect("Valid URI"), + self.torii_url.join(uri::STATUS).expect("Valid URI"), ) .headers(self.headers.clone()) } @@ -1737,7 +1734,7 @@ mod tests { use iroha_config::{ client::{BasicAuth, ConfigurationProxy, WebLogin}, - torii::{uri::DEFAULT_API_ADDR, DEFAULT_TORII_TELEMETRY_ADDR}, + torii::uri::DEFAULT_API_ADDR, }; use iroha_primitives::small::SmallStr; @@ -1761,11 +1758,6 @@ mod tests { .expect("This account ID should be valid"), ), torii_api_url: Some(format!("http://{DEFAULT_API_ADDR}").parse().unwrap()), - torii_telemetry_url: Some( - format!("http://{DEFAULT_TORII_TELEMETRY_ADDR}") - .parse() - .unwrap(), - ), add_transaction_nonce: Some(true), ..ConfigurationProxy::default() } @@ -1816,7 +1808,6 @@ mod tests { .expect("This account ID should be valid"), ), torii_api_url: Some(format!("http://{DEFAULT_API_ADDR}").parse().unwrap()), - torii_telemetry_url: Some(format!("http://{DEFAULT_TORII_TELEMETRY_ADDR}").parse().unwrap()), basic_auth: Some(Some(basic_auth)), ..ConfigurationProxy::default() } diff --git a/client/src/lib.rs b/client/src/lib.rs index 37f5ee07156..0011dd63202 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -10,7 +10,7 @@ mod http_default; pub mod samples { use iroha_config::{ client::{Configuration, ConfigurationProxy}, - torii::{uri::DEFAULT_API_ADDR, DEFAULT_TORII_TELEMETRY_ADDR}, + torii::uri::DEFAULT_API_ADDR, }; use iroha_crypto::KeyPair; @@ -31,11 +31,6 @@ pub mod samples { .parse() .expect("Should be a valid url"), ), - torii_telemetry_url: Some( - format!("http://{DEFAULT_TORII_TELEMETRY_ADDR}") - .parse() - .expect("Should be a valid url"), - ), ..ConfigurationProxy::default() } .build() diff --git a/client/tests/integration/asset_propagation.rs b/client/tests/integration/asset_propagation.rs index 22d86427629..c9efa82a0c8 100644 --- a/client/tests/integration/asset_propagation.rs +++ b/client/tests/integration/asset_propagation.rs @@ -48,7 +48,7 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount_on_a //Then let peer = network.peers.values().last().unwrap(); - client::Client::test(&peer.api_address, &peer.telemetry_address).poll_request( + client::Client::test(&peer.api_address).poll_request( client::asset::by_account_id(account_id), |result| { let assets = result.collect::>>().expect("Valid"); diff --git a/client/tests/integration/connected_peers.rs b/client/tests/integration/connected_peers.rs index 03ba2e995d3..dcde0f1c2aa 100644 --- a/client/tests/integration/connected_peers.rs +++ b/client/tests/integration/connected_peers.rs @@ -52,7 +52,7 @@ fn connected_peers_with_f(faults: u64, start_port: Option) -> Result<()> { // Unregister a peer: committed with f = `faults` // then `status.peers` decrements let peer = network.peers.values().last().unwrap(); - let peer_client = Client::test(&peer.api_address, &peer.telemetry_address); + let peer_client = Client::test(&peer.api_address); let unregister_peer = UnregisterExpr::new(IdBox::PeerId(peer.id.clone())); client.submit_blocking(unregister_peer)?; thread::sleep(pipeline_time * 2); // Wait for some time to allow peers to connect diff --git a/client/tests/integration/multiple_blocks_created.rs b/client/tests/integration/multiple_blocks_created.rs index 79abff38095..762a30ccaf2 100644 --- a/client/tests/integration/multiple_blocks_created.rs +++ b/client/tests/integration/multiple_blocks_created.rs @@ -60,7 +60,7 @@ fn long_multiple_blocks_created() -> Result<()> { //Then let peer = network.peers().last().unwrap(); - Client::test(&peer.api_address, &peer.telemetry_address).poll_request( + Client::test(&peer.api_address).poll_request( client::asset::by_account_id(account_id), |result| { let assets = result.collect::>>().expect("Valid"); diff --git a/client/tests/integration/multisignature_account.rs b/client/tests/integration/multisignature_account.rs index 3e3e4bcaf41..cf0dc9608ca 100644 --- a/client/tests/integration/multisignature_account.rs +++ b/client/tests/integration/multisignature_account.rs @@ -38,7 +38,7 @@ fn transaction_signed_by_new_signatory_of_account_should_pass() -> Result<()> { account_id.clone(), )), ); - Client::test_with_key(&peer.api_address, &peer.telemetry_address, key_pair).submit_till( + Client::test_with_key(&peer.api_address, key_pair).submit_till( mint_asset, client::asset::by_account_id(account_id), |result| { diff --git a/client/tests/integration/multisignature_transaction.rs b/client/tests/integration/multisignature_transaction.rs index ca061ccf50f..b05bce7f898 100644 --- a/client/tests/integration/multisignature_transaction.rs +++ b/client/tests/integration/multisignature_transaction.rs @@ -39,10 +39,7 @@ fn multisignature_transactions_should_wait_for_all_signatures() -> Result<()> { IdBox::AccountId(alice_id.clone()), ); - let mut client_configuration = ClientConfiguration::test( - &network.genesis.api_address, - &network.genesis.telemetry_address, - ); + let mut client_configuration = ClientConfiguration::test(&network.genesis.api_address); let client = Client::new(&client_configuration)?; let instructions: [InstructionExpr; 2] = [create_asset.into(), set_signature_condition.into()]; client.submit_all_blocking(instructions)?; diff --git a/client/tests/integration/restart_peer.rs b/client/tests/integration/restart_peer.rs index 6a6c3a95be1..7560dad0f72 100644 --- a/client/tests/integration/restart_peer.rs +++ b/client/tests/integration/restart_peer.rs @@ -25,7 +25,7 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { let create_asset = RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); let quantity: u32 = 200; - let iroha_client = client::Client::test(&peer.api_address, &peer.telemetry_address); + let iroha_client = client::Client::test(&peer.api_address); { let rt = Runtime::test(); diff --git a/client/tests/integration/unstable_network.rs b/client/tests/integration/unstable_network.rs index 327c3905496..bcfa52ea249 100644 --- a/client/tests/integration/unstable_network.rs +++ b/client/tests/integration/unstable_network.rs @@ -68,10 +68,7 @@ fn unstable_network( ) .await .expect("Failed to init peers"); - let client = Client::test( - &network.genesis.api_address, - &network.genesis.telemetry_address, - ); + let client = Client::test(&network.genesis.api_address); (network, client) }); wait_for_genesis_committed(&network.clients(), n_offline_peers); diff --git a/config/iroha_test_config.json b/config/iroha_test_config.json index d31823402e1..3c55e840892 100644 --- a/config/iroha_test_config.json +++ b/config/iroha_test_config.json @@ -42,7 +42,6 @@ "TORII": { "P2P_ADDR": "127.0.0.1:1337", "API_URL": "127.0.0.1:8080", - "TELEMETRY_URL": "127.0.0.1:8180", "MAX_TRANSACTION_SIZE": 32768, "MAX_CONTENT_LEN": 16384000, "FETCH_SIZE": 10, diff --git a/config/src/client.rs b/config/src/client.rs index fea87d4f3a6..602bfbda465 100644 --- a/config/src/client.rs +++ b/config/src/client.rs @@ -81,8 +81,6 @@ pub struct Configuration { pub basic_auth: Option, /// Torii URL. pub torii_api_url: Url, - /// Status URL. - pub torii_telemetry_url: Url, /// Proposed transaction TTL in milliseconds. pub transaction_time_to_live_ms: Option, /// Transaction status wait timeout in milliseconds. @@ -106,7 +104,6 @@ impl Default for ConfigurationProxy { account_id: None, basic_auth: Some(None), torii_api_url: None, - torii_telemetry_url: None, transaction_time_to_live_ms: Some(Some(DEFAULT_TRANSACTION_TIME_TO_LIVE_MS)), transaction_status_timeout_ms: Some(DEFAULT_TRANSACTION_STATUS_TIMEOUT_MS), transaction_limits: Some(DEFAULT_TRANSACTION_LIMITS), @@ -124,8 +121,8 @@ impl ConfigurationProxy { /// /// # Errors /// - If the [`self.transaction_time_to_live_ms`] field is too small - /// - If the [`self.transaction_status_timeout_ms`] field was smaller than [`self.transaction_time_to_live_ms`] - /// - If the [`self.torii_api_url`] or [`self.torii_telemetry_url`] were malformed or had the wrong protocol + /// - If the [`self.transaction_status_timeout_ms`] field is smaller than [`self.transaction_time_to_live_ms`] + /// - If the [`self.torii_api_url`] is malformed or had the wrong protocol pub fn finish(&mut self) -> Result<()> { if let Some(Some(tx_ttl)) = self.transaction_time_to_live_ms { // Really small TTL would be detrimental to performance @@ -156,22 +153,6 @@ impl ConfigurationProxy { }); } } - if let Some(telemetry_url) = &self.torii_telemetry_url { - if telemetry_url.scheme() != "http" { - eyre::bail!(ConfigError::InsaneValue { - value: telemetry_url.to_string(), - field: "TORII_TELEMETRY_URL", - message: ", because we only support HTTP".to_owned(), - }); - } - if telemetry_url.port().is_none() { - eyre::bail!(ConfigError::InsaneValue{ - value: telemetry_url.to_string(), - field: "TORII_TELEMETRY_URL", - message: ". You haven't provided a connection port, e.g. `8180` in `http://127.0.0.1:8180`".to_owned(), - }); - } - } Ok(()) } @@ -199,7 +180,7 @@ mod tests { use proptest::prelude::*; use super::*; - use crate::torii::{uri::DEFAULT_API_ADDR, DEFAULT_TORII_TELEMETRY_ADDR}; + use crate::torii::uri::DEFAULT_API_ADDR; const CONFIGURATION_PATH: &str = "../configs/client/config.json"; @@ -235,14 +216,13 @@ mod tests { account_id in prop::option::of(Just(placeholder_account())), basic_auth in prop::option::of(Just(None)), torii_api_url in prop::option::of(Just(format!("http://{DEFAULT_API_ADDR}").parse().unwrap())), - torii_telemetry_url in prop::option::of(Just(format!("http://{DEFAULT_TORII_TELEMETRY_ADDR}").parse().unwrap())), transaction_time_to_live_ms in prop::option::of(Just(Some(DEFAULT_TRANSACTION_TIME_TO_LIVE_MS))), transaction_status_timeout_ms in prop::option::of(Just(DEFAULT_TRANSACTION_STATUS_TIMEOUT_MS)), transaction_limits in prop::option::of(Just(DEFAULT_TRANSACTION_LIMITS)), add_transaction_nonce in prop::option::of(Just(DEFAULT_ADD_TRANSACTION_NONCE)), ) -> ConfigurationProxy { - ConfigurationProxy { public_key, private_key, account_id, basic_auth, torii_api_url, torii_telemetry_url, transaction_time_to_live_ms, transaction_status_timeout_ms, transaction_limits, add_transaction_nonce } + ConfigurationProxy { public_key, private_key, account_id, basic_auth, torii_api_url, transaction_time_to_live_ms, transaction_status_timeout_ms, transaction_limits, add_transaction_nonce } } } @@ -258,7 +238,6 @@ mod tests { let arb_cfg = cfg.expect("Config generated by proptest was checked to be ok by the surrounding if clause"); // Skipping keys and `basic_auth` check as they're different from the file assert_eq!(arb_cfg.torii_api_url, example_cfg.torii_api_url); - assert_eq!(arb_cfg.torii_telemetry_url, example_cfg.torii_telemetry_url); assert_eq!(arb_cfg.account_id, example_cfg.account_id); assert_eq!(arb_cfg.transaction_time_to_live_ms, example_cfg.transaction_time_to_live_ms); assert_eq!(arb_cfg.transaction_status_timeout_ms, example_cfg.transaction_status_timeout_ms); diff --git a/config/src/torii.rs b/config/src/torii.rs index 1797d8e7e07..764c369ddd4 100644 --- a/config/src/torii.rs +++ b/config/src/torii.rs @@ -8,8 +8,6 @@ use serde::{Deserialize, Serialize}; /// Default socket for p2p communication pub const DEFAULT_TORII_P2P_ADDR: SocketAddr = socket_addr!(127.0.0.1:1337); -/// Default socket for reporting internal status and metrics -pub const DEFAULT_TORII_TELEMETRY_ADDR: SocketAddr = socket_addr!(127.0.0.1:8180); /// Default maximum size of single transaction pub const DEFAULT_TORII_MAX_TRANSACTION_SIZE: u32 = 2_u32.pow(15); /// Default upper bound on `content-length` specified in the HTTP request header @@ -34,9 +32,6 @@ pub struct Configuration { /// Torii address for client API. #[config(serde_as_str)] pub api_url: SocketAddr, - /// Torii address for reporting internal status and metrics for administration. - #[config(serde_as_str)] - pub telemetry_url: SocketAddr, /// Maximum number of bytes in raw transaction. Used to prevent from DOS attacks. pub max_transaction_size: u32, /// Maximum number of bytes in raw message. Used to prevent from DOS attacks. @@ -52,7 +47,6 @@ impl Default for ConfigurationProxy { Self { p2p_addr: None, api_url: None, - telemetry_url: None, max_transaction_size: Some(DEFAULT_TORII_MAX_TRANSACTION_SIZE), max_content_len: Some(DEFAULT_TORII_MAX_CONTENT_LENGTH), fetch_size: Some(*DEFAULT_TORII_FETCH_SIZE), @@ -107,14 +101,13 @@ pub mod tests { ( p2p_addr in prop::option::of(Just(DEFAULT_TORII_P2P_ADDR)), api_url in prop::option::of(Just(uri::DEFAULT_API_ADDR)), - telemetry_url in prop::option::of(Just(DEFAULT_TORII_TELEMETRY_ADDR)), max_transaction_size in prop::option::of(Just(DEFAULT_TORII_MAX_TRANSACTION_SIZE)), max_content_len in prop::option::of(Just(DEFAULT_TORII_MAX_CONTENT_LENGTH)), fetch_size in prop::option::of(Just(*DEFAULT_TORII_FETCH_SIZE)), query_idle_time_ms in prop::option::of(Just(*DEFAULT_TORII_QUERY_IDLE_TIME_MS)), ) -> ConfigurationProxy { - ConfigurationProxy { p2p_addr, api_url, telemetry_url, max_transaction_size, max_content_len, fetch_size, query_idle_time_ms } + ConfigurationProxy { p2p_addr, api_url, max_transaction_size, max_content_len, fetch_size, query_idle_time_ms } } } } diff --git a/configs/client/config.json b/configs/client/config.json index 88dfd179898..5ed2399d626 100644 --- a/configs/client/config.json +++ b/configs/client/config.json @@ -10,7 +10,6 @@ "password": "ilovetea" }, "TORII_API_URL": "http://127.0.0.1:8080/", - "TORII_TELEMETRY_URL": "http://127.0.0.1:8180/", "TRANSACTION_TIME_TO_LIVE_MS": 100000, "TRANSACTION_STATUS_TIMEOUT_MS": 15000, "TRANSACTION_LIMITS": { diff --git a/configs/peer/config.json b/configs/peer/config.json index e28996bdf9b..ef36a9f525c 100644 --- a/configs/peer/config.json +++ b/configs/peer/config.json @@ -23,7 +23,6 @@ "TORII": { "P2P_ADDR": null, "API_URL": null, - "TELEMETRY_URL": null, "MAX_TRANSACTION_SIZE": 32768, "MAX_CONTENT_LEN": 16384000, "FETCH_SIZE": 10, diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 73cd37cf123..a8f8ad9f58f 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -181,10 +181,7 @@ impl Network { ) .await .expect("Failed to init peers"); - let client = Client::test( - &network.genesis.api_address, - &network.genesis.telemetry_address, - ); + let client = Client::test(&network.genesis.api_address); (network, client) } @@ -202,8 +199,7 @@ impl Network { /// Adds peer to network and waits for it to start block /// synchronization. pub async fn add_peer(&self) -> (Peer, Client) { - let genesis_client = - Client::test(&self.genesis.api_address, &self.genesis.telemetry_address); + let genesis_client = Client::test(&self.genesis.api_address); let mut config = Configuration::test(); config.sumeragi.trusted_peers.peers = @@ -222,7 +218,7 @@ impl Network { .submit(add_peer) .expect("Failed to add new peer."); - let client = Client::test(&peer.api_address, &peer.telemetry_address); + let client = Client::test(&peer.api_address); (peer, client) } @@ -310,7 +306,7 @@ impl Network { /// Get active clients pub fn clients(&self) -> Vec { self.peers() - .map(|peer| Client::test(&peer.api_address, &peer.telemetry_address)) + .map(|peer| Client::test(&peer.api_address)) .collect() } @@ -358,8 +354,6 @@ pub struct Peer { pub api_address: SocketAddr, /// P2P address pub p2p_address: SocketAddr, - /// Telemetry address - pub telemetry_address: SocketAddr, /// The key-pair for the peer pub key_pair: KeyPair, /// Shutdown handle @@ -403,7 +397,6 @@ impl Peer { torii: ToriiConfiguration { p2p_addr: self.p2p_address.clone(), api_url: self.api_address.clone(), - telemetry_url: self.telemetry_address.clone(), ..configuration.torii }, logger: LoggerConfiguration { @@ -432,7 +425,6 @@ impl Peer { "test-peer", p2p_addr = %self.p2p_address, api_addr = %self.api_address, - telemetry_addr = %self.telemetry_address ); let telemetry = iroha_logger::init(&configuration.logger).expect("Failed to initialize telemetry"); @@ -481,13 +473,11 @@ impl Peer { /// * If can't get a unique port for /// - `p2p_address` /// - `api_address` - /// - `telemetry_address` /// * If keypair generation fails pub fn new() -> Result { let key_pair = KeyPair::generate()?; let p2p_address = local_unique_port()?; let api_address = local_unique_port()?; - let telemetry_address = local_unique_port()?; let id = PeerId { address: p2p_address.clone(), public_key: key_pair.public_key().clone(), @@ -498,7 +488,6 @@ impl Peer { key_pair, p2p_address, api_address, - telemetry_address, shutdown, iroha: None, temp_dir: None, @@ -600,7 +589,6 @@ impl PeerBuilder { if let Some(port) = self.port.take() { peer.p2p_address = socket_addr!(127.0.0 .1: port); peer.api_address = socket_addr!(127.0.0 .1: port + 1); - peer.telemetry_address = socket_addr!(127.0.0 .1: port + 2); // prevent field desync peer.id.address = peer.p2p_address.clone(); } @@ -642,7 +630,7 @@ impl PeerBuilder { let peer = self.start().await; - let client = Client::test(&peer.api_address, &peer.telemetry_address); + let client = Client::test(&peer.api_address); time::sleep(Duration::from_millis( configuration.sumeragi.pipeline_time_ms(), @@ -685,24 +673,19 @@ pub trait TestConfiguration { /// Client configuration mocking trait. pub trait TestClientConfiguration { /// Creates test client configuration - fn test(api_url: &SocketAddr, telemetry_url: &SocketAddr) -> Self; + fn test(api_url: &SocketAddr) -> Self; } /// Client mocking trait pub trait TestClient: Sized { /// Create test client from api url - fn test(api_url: &SocketAddr, telemetry_url: &SocketAddr) -> Self; + fn test(api_url: &SocketAddr) -> Self; /// Create test client from api url and keypair - fn test_with_key(api_url: &SocketAddr, telemetry_url: &SocketAddr, keys: KeyPair) -> Self; + fn test_with_key(api_url: &SocketAddr, keys: KeyPair) -> Self; /// Create test client from api url, keypair, and account id - fn test_with_account( - api_url: &SocketAddr, - telemetry_url: &SocketAddr, - keys: KeyPair, - account_id: &AccountId, - ) -> Self; + fn test_with_account(api_url: &SocketAddr, keys: KeyPair, account_id: &AccountId) -> Self; /// Loop for events with filter and handler function fn for_each_event(self, event_filter: FilterBox, f: impl Fn(Result)); @@ -802,39 +785,30 @@ impl TestConfiguration for Configuration { } impl TestClientConfiguration for ClientConfiguration { - fn test(api_url: &SocketAddr, telemetry_url: &SocketAddr) -> Self { + fn test(api_url: &SocketAddr) -> Self { let mut configuration = iroha_client::samples::get_client_config(&get_key_pair()); configuration.torii_api_url = format!("http://{api_url}") .parse() .expect("Should be valid url"); - configuration.torii_telemetry_url = format!("http://{telemetry_url}") - .parse() - .expect("Should be valid url"); configuration } } impl TestClient for Client { - fn test(api_url: &SocketAddr, telemetry_url: &SocketAddr) -> Self { - Client::new(&ClientConfiguration::test(api_url, telemetry_url)) - .expect("Invalid client configuration") + fn test(api_url: &SocketAddr) -> Self { + Client::new(&ClientConfiguration::test(api_url)).expect("Invalid client configuration") } - fn test_with_key(api_url: &SocketAddr, telemetry_url: &SocketAddr, keys: KeyPair) -> Self { - let mut configuration = ClientConfiguration::test(api_url, telemetry_url); + fn test_with_key(api_url: &SocketAddr, keys: KeyPair) -> Self { + let mut configuration = ClientConfiguration::test(api_url); let (public_key, private_key) = keys.into(); configuration.public_key = public_key; configuration.private_key = private_key; Client::new(&configuration).expect("Invalid client configuration") } - fn test_with_account( - api_url: &SocketAddr, - telemetry_url: &SocketAddr, - keys: KeyPair, - account_id: &AccountId, - ) -> Self { - let mut configuration = ClientConfiguration::test(api_url, telemetry_url); + fn test_with_account(api_url: &SocketAddr, keys: KeyPair, account_id: &AccountId) -> Self { + let mut configuration = ClientConfiguration::test(api_url); configuration.account_id = account_id.clone(); let (public_key, private_key) = keys.into(); configuration.public_key = public_key; diff --git a/docker-compose.dev.local.yml b/docker-compose.dev.local.yml index 622a526966d..162572d7dd7 100644 --- a/docker-compose.dev.local.yml +++ b/docker-compose.dev.local.yml @@ -11,14 +11,12 @@ services: IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"8f4c15e5d664da3f13778801d23d4e89b76e94c1b94b389544168b6cb894f84f8ba62848cf767d72e7f7f4b9d2d7ba07fee33760f79abe5597a51520e292a0cb"}' TORII_P2P_ADDR: iroha0:1337 TORII_API_URL: iroha0:8080 - TORII_TELEMETRY_URL: iroha0:8180 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01204164BF554923ECE1FD412D241036D863A6AE430476C898248B8237D77534CFC4 IROHA_GENESIS_ACCOUNT_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"82b3bde54aebeca4146257da0de8d59d8e46d5fe34887dcd8072866792fcb3ad4164bf554923ece1fd412d241036d863a6ae430476c898248b8237d77534cfc4"}' SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha1:1338","public_key":"ed0120815BBDC9775D28C3633269B25F22D048E2AA2E36017CBE5AD85F15220BEB6F6F"},{"address":"iroha0:1337","public_key":"ed01208BA62848CF767D72E7F7F4B9D2D7BA07FEE33760F79ABE5597A51520E292A0CB"},{"address":"iroha3:1340","public_key":"ed0120A66522370D60B9C09E79ADE2E9BB1EF2E78733A944B999B3A6AEE687CE476D61"},{"address":"iroha2:1339","public_key":"ed0120F417E0371E6ADB32FD66749477402B1AB67F84A8E9B082E997980CC91F327736"}]' ports: - 1337:1337 - 8080:8080 - - 8180:8180 volumes: - ./configs/peer:/config init: true @@ -31,13 +29,11 @@ services: IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"c02ffad5e455e7ec620d74de5769681e4d8385906bce5a437eb67452a9efbbc2815bbdc9775d28c3633269b25f22d048e2aa2e36017cbe5ad85f15220beb6f6f"}' TORII_P2P_ADDR: iroha1:1338 TORII_API_URL: iroha1:8081 - TORII_TELEMETRY_URL: iroha1:8181 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01204164BF554923ECE1FD412D241036D863A6AE430476C898248B8237D77534CFC4 SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha1:1338","public_key":"ed0120815BBDC9775D28C3633269B25F22D048E2AA2E36017CBE5AD85F15220BEB6F6F"},{"address":"iroha0:1337","public_key":"ed01208BA62848CF767D72E7F7F4B9D2D7BA07FEE33760F79ABE5597A51520E292A0CB"},{"address":"iroha3:1340","public_key":"ed0120A66522370D60B9C09E79ADE2E9BB1EF2E78733A944B999B3A6AEE687CE476D61"},{"address":"iroha2:1339","public_key":"ed0120F417E0371E6ADB32FD66749477402B1AB67F84A8E9B082E997980CC91F327736"}]' ports: - 1338:1338 - 8081:8081 - - 8181:8181 volumes: - ./configs/peer:/config init: true @@ -49,13 +45,11 @@ services: IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"29c5ed1409cb10fd791bc4ff8a6cb5e22a5fae7e36f448ef3ea2988b1319a88bf417e0371e6adb32fd66749477402b1ab67f84a8e9b082e997980cc91f327736"}' TORII_P2P_ADDR: iroha2:1339 TORII_API_URL: iroha2:8082 - TORII_TELEMETRY_URL: iroha2:8182 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01204164BF554923ECE1FD412D241036D863A6AE430476C898248B8237D77534CFC4 SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha1:1338","public_key":"ed0120815BBDC9775D28C3633269B25F22D048E2AA2E36017CBE5AD85F15220BEB6F6F"},{"address":"iroha0:1337","public_key":"ed01208BA62848CF767D72E7F7F4B9D2D7BA07FEE33760F79ABE5597A51520E292A0CB"},{"address":"iroha3:1340","public_key":"ed0120A66522370D60B9C09E79ADE2E9BB1EF2E78733A944B999B3A6AEE687CE476D61"},{"address":"iroha2:1339","public_key":"ed0120F417E0371E6ADB32FD66749477402B1AB67F84A8E9B082E997980CC91F327736"}]' ports: - 1339:1339 - 8082:8082 - - 8182:8182 volumes: - ./configs/peer:/config init: true @@ -67,13 +61,11 @@ services: IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"5eed4855fad183c451aac39dfc50831607e4cf408c98e2b977f3ce4a2df42ce2a66522370d60b9c09e79ade2e9bb1ef2e78733a944b999b3a6aee687ce476d61"}' TORII_P2P_ADDR: iroha3:1340 TORII_API_URL: iroha3:8083 - TORII_TELEMETRY_URL: iroha3:8183 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01204164BF554923ECE1FD412D241036D863A6AE430476C898248B8237D77534CFC4 SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha1:1338","public_key":"ed0120815BBDC9775D28C3633269B25F22D048E2AA2E36017CBE5AD85F15220BEB6F6F"},{"address":"iroha0:1337","public_key":"ed01208BA62848CF767D72E7F7F4B9D2D7BA07FEE33760F79ABE5597A51520E292A0CB"},{"address":"iroha3:1340","public_key":"ed0120A66522370D60B9C09E79ADE2E9BB1EF2E78733A944B999B3A6AEE687CE476D61"},{"address":"iroha2:1339","public_key":"ed0120F417E0371E6ADB32FD66749477402B1AB67F84A8E9B082E997980CC91F327736"}]' ports: - 1340:1340 - 8083:8083 - - 8183:8183 volumes: - ./configs/peer:/config init: true diff --git a/docker-compose.dev.single.yml b/docker-compose.dev.single.yml index 70e045ced3f..9a4891ff227 100644 --- a/docker-compose.dev.single.yml +++ b/docker-compose.dev.single.yml @@ -11,14 +11,12 @@ services: IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"8f4c15e5d664da3f13778801d23d4e89b76e94c1b94b389544168b6cb894f84f8ba62848cf767d72e7f7f4b9d2d7ba07fee33760f79abe5597a51520e292a0cb"}' TORII_P2P_ADDR: iroha0:1337 TORII_API_URL: iroha0:8080 - TORII_TELEMETRY_URL: iroha0:8180 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01204164BF554923ECE1FD412D241036D863A6AE430476C898248B8237D77534CFC4 IROHA_GENESIS_ACCOUNT_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"82b3bde54aebeca4146257da0de8d59d8e46d5fe34887dcd8072866792fcb3ad4164bf554923ece1fd412d241036d863a6ae430476c898248b8237d77534cfc4"}' SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha0:1337","public_key":"ed01208BA62848CF767D72E7F7F4B9D2D7BA07FEE33760F79ABE5597A51520E292A0CB"}]' ports: - 1337:1337 - 8080:8080 - - 8180:8180 volumes: - ./configs/peer:/config init: true diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index b02503e45bc..9c45d746a06 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -11,14 +11,12 @@ services: IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"8f4c15e5d664da3f13778801d23d4e89b76e94c1b94b389544168b6cb894f84f8ba62848cf767d72e7f7f4b9d2d7ba07fee33760f79abe5597a51520e292a0cb"}' TORII_P2P_ADDR: iroha0:1337 TORII_API_URL: iroha0:8080 - TORII_TELEMETRY_URL: iroha0:8180 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01204164BF554923ECE1FD412D241036D863A6AE430476C898248B8237D77534CFC4 IROHA_GENESIS_ACCOUNT_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"82b3bde54aebeca4146257da0de8d59d8e46d5fe34887dcd8072866792fcb3ad4164bf554923ece1fd412d241036d863a6ae430476c898248b8237d77534cfc4"}' SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha1:1338","public_key":"ed0120815BBDC9775D28C3633269B25F22D048E2AA2E36017CBE5AD85F15220BEB6F6F"},{"address":"iroha0:1337","public_key":"ed01208BA62848CF767D72E7F7F4B9D2D7BA07FEE33760F79ABE5597A51520E292A0CB"},{"address":"iroha3:1340","public_key":"ed0120A66522370D60B9C09E79ADE2E9BB1EF2E78733A944B999B3A6AEE687CE476D61"},{"address":"iroha2:1339","public_key":"ed0120F417E0371E6ADB32FD66749477402B1AB67F84A8E9B082E997980CC91F327736"}]' ports: - 1337:1337 - 8080:8080 - - 8180:8180 volumes: - ./configs/peer:/config init: true @@ -31,13 +29,11 @@ services: IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"c02ffad5e455e7ec620d74de5769681e4d8385906bce5a437eb67452a9efbbc2815bbdc9775d28c3633269b25f22d048e2aa2e36017cbe5ad85f15220beb6f6f"}' TORII_P2P_ADDR: iroha1:1338 TORII_API_URL: iroha1:8081 - TORII_TELEMETRY_URL: iroha1:8181 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01204164BF554923ECE1FD412D241036D863A6AE430476C898248B8237D77534CFC4 SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha1:1338","public_key":"ed0120815BBDC9775D28C3633269B25F22D048E2AA2E36017CBE5AD85F15220BEB6F6F"},{"address":"iroha0:1337","public_key":"ed01208BA62848CF767D72E7F7F4B9D2D7BA07FEE33760F79ABE5597A51520E292A0CB"},{"address":"iroha3:1340","public_key":"ed0120A66522370D60B9C09E79ADE2E9BB1EF2E78733A944B999B3A6AEE687CE476D61"},{"address":"iroha2:1339","public_key":"ed0120F417E0371E6ADB32FD66749477402B1AB67F84A8E9B082E997980CC91F327736"}]' ports: - 1338:1338 - 8081:8081 - - 8181:8181 volumes: - ./configs/peer:/config init: true @@ -49,13 +45,11 @@ services: IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"29c5ed1409cb10fd791bc4ff8a6cb5e22a5fae7e36f448ef3ea2988b1319a88bf417e0371e6adb32fd66749477402b1ab67f84a8e9b082e997980cc91f327736"}' TORII_P2P_ADDR: iroha2:1339 TORII_API_URL: iroha2:8082 - TORII_TELEMETRY_URL: iroha2:8182 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01204164BF554923ECE1FD412D241036D863A6AE430476C898248B8237D77534CFC4 SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha1:1338","public_key":"ed0120815BBDC9775D28C3633269B25F22D048E2AA2E36017CBE5AD85F15220BEB6F6F"},{"address":"iroha0:1337","public_key":"ed01208BA62848CF767D72E7F7F4B9D2D7BA07FEE33760F79ABE5597A51520E292A0CB"},{"address":"iroha3:1340","public_key":"ed0120A66522370D60B9C09E79ADE2E9BB1EF2E78733A944B999B3A6AEE687CE476D61"},{"address":"iroha2:1339","public_key":"ed0120F417E0371E6ADB32FD66749477402B1AB67F84A8E9B082E997980CC91F327736"}]' ports: - 1339:1339 - 8082:8082 - - 8182:8182 volumes: - ./configs/peer:/config init: true @@ -67,13 +61,11 @@ services: IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"5eed4855fad183c451aac39dfc50831607e4cf408c98e2b977f3ce4a2df42ce2a66522370d60b9c09e79ade2e9bb1ef2e78733a944b999b3a6aee687ce476d61"}' TORII_P2P_ADDR: iroha3:1340 TORII_API_URL: iroha3:8083 - TORII_TELEMETRY_URL: iroha3:8183 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01204164BF554923ECE1FD412D241036D863A6AE430476C898248B8237D77534CFC4 SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha1:1338","public_key":"ed0120815BBDC9775D28C3633269B25F22D048E2AA2E36017CBE5AD85F15220BEB6F6F"},{"address":"iroha0:1337","public_key":"ed01208BA62848CF767D72E7F7F4B9D2D7BA07FEE33760F79ABE5597A51520E292A0CB"},{"address":"iroha3:1340","public_key":"ed0120A66522370D60B9C09E79ADE2E9BB1EF2E78733A944B999B3A6AEE687CE476D61"},{"address":"iroha2:1339","public_key":"ed0120F417E0371E6ADB32FD66749477402B1AB67F84A8E9B082E997980CC91F327736"}]' ports: - 1340:1340 - 8083:8083 - - 8183:8183 volumes: - ./configs/peer:/config init: true diff --git a/docs/source/references/config.md b/docs/source/references/config.md index 215f3e38627..b43fe9111f2 100644 --- a/docs/source/references/config.md +++ b/docs/source/references/config.md @@ -8,7 +8,7 @@ In this document we provide a reference and detailed descriptions of Iroha's con A type wrapped in a single `Option<..>` signifies that in the corresponding `json` block there is a fallback value for this type, and that it only serves as a reference. If a default for such a type has a `null` value, it means that there is no meaningful fallback available for this particular value. -All the default values can be freely obtained from a provided [sample configuration file](../../../configs/peer/config.json), but it should only serve as a starting point. If left unchanged, the sample configuration file would still fail to build due to it having `null` in place of [public](#public_key) and [private](#private_key) keys as well as [endpoint](#torii.api_url) [URLs](#torii.telemetry_url). These should be provided either by modifying the sample config file or as environment variables. No other overloading of configuration values happens besides reading them from a file and capturing the environment variables. +All the default values can be freely obtained from a provided [sample configuration file](../../../configs/peer/config.json), but it should only serve as a starting point. If left unchanged, the sample configuration file would still fail to build due to it having `null` in place of [public](#public_key) and [private](#private_key) keys as well as [API endpoint URL](#torii.api_url). These should be provided either by modifying the sample config file or as environment variables. No other overloading of configuration values happens besides reading them from a file and capturing the environment variables. For both types of configuration options wrapped in a single `Option<..>` (i.e. both those that have meaningful defaults and those that have `null`), failure to provide them in any of the above two ways results in an error. @@ -54,7 +54,6 @@ The following is the default configuration used by Iroha. "TORII": { "P2P_ADDR": null, "API_URL": null, - "TELEMETRY_URL": null, "MAX_TRANSACTION_SIZE": 32768, "MAX_CONTENT_LEN": 16384000, "FETCH_SIZE": 10, @@ -679,8 +678,7 @@ Has type `Option`[^1]. Can be configured via environm "MAX_CONTENT_LEN": 16384000, "MAX_TRANSACTION_SIZE": 32768, "P2P_ADDR": null, - "QUERY_IDLE_TIME_MS": 30000, - "TELEMETRY_URL": null + "QUERY_IDLE_TIME_MS": 30000 } ``` @@ -744,16 +742,6 @@ Has type `Option`[^1]. Can be configured via environment variable `T 30000 ``` -### `torii.telemetry_url` - -Torii address for reporting internal status and metrics for administration. - -Has type `Option`[^1]. Can be configured via environment variable `TORII_TELEMETRY_URL` - -```json -null -``` - ## `wsv` `WorldStateView` configuration diff --git a/scripts/test_env.py b/scripts/test_env.py index 2e848d153ce..7fe2007a4e0 100755 --- a/scripts/test_env.py +++ b/scripts/test_env.py @@ -55,7 +55,7 @@ def wait_for_genesis(self, n_tries: int): for i in range(n_tries): logging.info(f"Waiting for genesis block to be created... Attempt {i+1}/{n_tries}") try: - with urllib.request.urlopen(f"http://{self.peers[0].host_ip}:{self.peers[0].telemetry_port}/status/blocks") as response: + with urllib.request.urlopen(f"http://{self.peers[0].host_ip}:{self.peers[0].api_port}/status/blocks") as response: block_count = int(response.read()) if block_count >= 1: logging.info(f"Genesis block created. Block count: {block_count}") @@ -85,7 +85,6 @@ def __init__(self, args: argparse.Namespace, nth: int): self.name = f"iroha{nth}" self.p2p_port = 1337 + nth self.api_port = 8080 + nth - self.telemetry_port = 8180 + nth self.tokio_console_port = 5555 + nth self.out_dir = args.out_dir self.root_dir = args.root_dir @@ -123,7 +122,6 @@ def run(self, is_genesis: bool = False): os.environ["SUMERAGI_DEBUG_FORCE_SOFT_FORK"] = "false" os.environ["TORII_P2P_ADDR"] = f"{self.host_ip}:{self.p2p_port}" os.environ["TORII_API_URL"] = f"{self.host_ip}:{self.api_port}" - os.environ["TORII_TELEMETRY_URL"] = f"{self.host_ip}:{self.telemetry_port}" os.environ["TOKIO_CONSOLE_ADDR"] = f"{self.host_ip}:{self.tokio_console_port}" genesis_arg = "--submit-genesis" if is_genesis else "" diff --git a/scripts/tests/panic_on_invalid_genesis.sh b/scripts/tests/panic_on_invalid_genesis.sh index 21cdd103c2c..ed95926b645 100755 --- a/scripts/tests/panic_on_invalid_genesis.sh +++ b/scripts/tests/panic_on_invalid_genesis.sh @@ -3,7 +3,6 @@ set -ex # Setup env export TORII_P2P_ADDR='127.0.0.1:1341' export TORII_API_URL='127.0.0.1:8084' -export TORII_TELEMETRY_URL='127.0.0.1:8184' export IROHA_PUBLIC_KEY='ed01201C61FAF8FE94E253B93114240394F79A607B7FA55F9E5A41EBEC74B88055768B' export IROHA_PRIVATE_KEY='{"digest_function": "ed25519", "payload": "282ED9F3CF92811C3818DBC4AE594ED59DC1A2F78E4241E31924E101D6B1FB831C61FAF8FE94E253B93114240394F79A607B7FA55F9E5A41EBEC74B88055768B"}' export IROHA_GENESIS_ACCOUNT_PUBLIC_KEY='ed01203F4E3E98571B55514EDC5CCF7E53CA7509D89B2868E62921180A6F57C2F4E255' diff --git a/tools/kagami/src/config.rs b/tools/kagami/src/config.rs index 2479ffc7994..de4937d7003 100644 --- a/tools/kagami/src/config.rs +++ b/tools/kagami/src/config.rs @@ -30,7 +30,7 @@ impl RunArgs for Args { mod client { use iroha_config::{ client::{BasicAuth, ConfigurationProxy, WebLogin}, - torii::{uri::DEFAULT_API_ADDR, DEFAULT_TORII_TELEMETRY_ADDR}, + torii::uri::DEFAULT_API_ADDR, }; use super::*; @@ -42,7 +42,6 @@ mod client { fn run(self, writer: &mut BufWriter) -> Outcome { let config = ConfigurationProxy { torii_api_url: Some(format!("http://{DEFAULT_API_ADDR}").parse()?), - torii_telemetry_url: Some(format!("http://{DEFAULT_TORII_TELEMETRY_ADDR}").parse()?), account_id: Some("alice@wonderland".parse()?), basic_auth: Some(Some(BasicAuth { web_login: WebLogin::new("mad_hatter")?, diff --git a/tools/kagami/src/docs.rs b/tools/kagami/src/docs.rs index cf548b5debb..0e5814a0743 100644 --- a/tools/kagami/src/docs.rs +++ b/tools/kagami/src/docs.rs @@ -47,7 +47,7 @@ where and that it only serves as a reference. If a default for such a type has a `null` value, it means that there is no meaningful fallback \ available for this particular value.\n\nAll the default values can be freely obtained from a provided [sample configuration file](../../../configs/peer/config.json), \ but it should only serve as a starting point. If left unchanged, the sample configuration file would still fail to build due to it having `null` in place of \ - [public](#public_key) and [private](#private_key) keys as well as [endpoint](#torii.api_url) [URLs](#torii.telemetry_url). \ + [public](#public_key) and [private](#private_key) keys as well as [API endpoint URL](#torii.api_url). \ These should be provided either by modifying the sample config file or as environment variables. \ No other overloading of configuration values happens besides reading them from a file and capturing the environment variables.\n\n\ For both types of configuration options wrapped in a single `Option<..>` (i.e. both those that have meaningful defaults and those that have `null`), \ diff --git a/tools/swarm/src/compose.rs b/tools/swarm/src/compose.rs index 697658750ac..e08ab109e91 100644 --- a/tools/swarm/src/compose.rs +++ b/tools/swarm/src/compose.rs @@ -111,7 +111,6 @@ impl DockerComposeService { let ports = vec![ PairColon(peer.port_p2p, peer.port_p2p), PairColon(peer.port_api, peer.port_api), - PairColon(peer.port_telemetry, peer.port_telemetry), ]; let command = if genesis_private_key.is_some() { @@ -127,7 +126,6 @@ impl DockerComposeService { key_pair: peer.key_pair.clone(), p2p_addr: peer.addr(peer.port_p2p), api_addr: peer.addr(peer.port_api), - telemetry_addr: peer.addr(peer.port_telemetry), }; Self { @@ -213,7 +211,6 @@ struct FullPeerEnv { iroha_private_key: SerializeAsJsonStr, torii_p2p_addr: SocketAddr, torii_api_url: SocketAddr, - torii_telemetry_url: SocketAddr, #[serde(skip_serializing_if = "Option::is_none")] iroha_genesis_account_public_key: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -228,7 +225,6 @@ struct CompactPeerEnv { genesis_private_key: Option, p2p_addr: SocketAddr, api_addr: SocketAddr, - telemetry_addr: SocketAddr, trusted_peers: BTreeSet, } @@ -241,7 +237,6 @@ impl From for FullPeerEnv { iroha_genesis_account_private_key: value.genesis_private_key.map(SerializeAsJsonStr), torii_p2p_addr: value.p2p_addr, torii_api_url: value.api_addr, - torii_telemetry_url: value.telemetry_addr, sumeragi_trusted_peers: SerializeAsJsonStr(value.trusted_peers), } } @@ -377,14 +372,12 @@ mod peer_generator { const BASE_PORT_P2P: u16 = 1337; const BASE_PORT_API: u16 = 8080; - const BASE_PORT_TELEMETRY: u16 = 8180; const BASE_SERVICE_NAME: &'_ str = "iroha"; pub struct Peer { pub name: String, pub port_p2p: u16, pub port_api: u16, - pub port_telemetry: u16, pub key_pair: KeyPair, } @@ -416,7 +409,6 @@ mod peer_generator { name: service_name.clone(), port_p2p: BASE_PORT_P2P + i, port_api: BASE_PORT_API + i, - port_telemetry: BASE_PORT_TELEMETRY + i, key_pair, }; @@ -543,7 +535,6 @@ mod tests { genesis_private_key: Some(keypair.private_key().clone()), p2p_addr: SocketAddr::from_str("127.0.0.1:1337").unwrap(), api_addr: SocketAddr::from_str("127.0.0.1:1338").unwrap(), - telemetry_addr: SocketAddr::from_str("127.0.0.1:1339").unwrap(), trusted_peers: BTreeSet::new(), } .into(); @@ -589,7 +580,6 @@ mod tests { genesis_private_key: Some(key_pair.private_key().clone()), p2p_addr: SocketAddr::from_str("iroha1:1339").unwrap(), api_addr: SocketAddr::from_str("iroha1:1338").unwrap(), - telemetry_addr: SocketAddr::from_str("iroha1:1337").unwrap(), trusted_peers: BTreeSet::new(), } .into(), @@ -613,29 +603,28 @@ mod tests { let actual = serde_yaml::to_string(&compose).expect("Should be serialisable"); let expected = expect_test::expect![[r#" - version: '3.8' - services: - iroha0: - build: . - platform: linux/amd64 - environment: - IROHA_PUBLIC_KEY: ed012039E5BF092186FACC358770792A493CA98A83740643A3D41389483CF334F748C8 - IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"db9d90d20f969177bd5882f9fe211d14d1399d5440d04e3468783d169bbc4a8e39e5bf092186facc358770792a493ca98a83740643a3d41389483cf334f748c8"}' - TORII_P2P_ADDR: iroha1:1339 - TORII_API_URL: iroha1:1338 - TORII_TELEMETRY_URL: iroha1:1337 - IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed012039E5BF092186FACC358770792A493CA98A83740643A3D41389483CF334F748C8 - IROHA_GENESIS_ACCOUNT_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"db9d90d20f969177bd5882f9fe211d14d1399d5440d04e3468783d169bbc4a8e39e5bf092186facc358770792a493ca98a83740643a3d41389483cf334f748c8"}' - SUMERAGI_TRUSTED_PEERS: '[]' - ports: - - 1337:1337 - - 8080:8080 - - 8081:8081 - volumes: - - ./configs/peer/legacy_stable:/config - init: true - command: iroha --submit-genesis - "#]]; + version: '3.8' + services: + iroha0: + build: . + platform: linux/amd64 + environment: + IROHA_PUBLIC_KEY: ed012039E5BF092186FACC358770792A493CA98A83740643A3D41389483CF334F748C8 + IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"db9d90d20f969177bd5882f9fe211d14d1399d5440d04e3468783d169bbc4a8e39e5bf092186facc358770792a493ca98a83740643a3d41389483cf334f748c8"}' + TORII_P2P_ADDR: iroha1:1339 + TORII_API_URL: iroha1:1338 + IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed012039E5BF092186FACC358770792A493CA98A83740643A3D41389483CF334F748C8 + IROHA_GENESIS_ACCOUNT_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"db9d90d20f969177bd5882f9fe211d14d1399d5440d04e3468783d169bbc4a8e39e5bf092186facc358770792a493ca98a83740643a3d41389483cf334f748c8"}' + SUMERAGI_TRUSTED_PEERS: '[]' + ports: + - 1337:1337 + - 8080:8080 + - 8081:8081 + volumes: + - ./configs/peer/legacy_stable:/config + init: true + command: iroha --submit-genesis + "#]]; expected.assert_eq(&actual); } @@ -651,21 +640,19 @@ mod tests { genesis_private_key: None, p2p_addr: SocketAddr::from_str("iroha0:1337").unwrap(), api_addr: SocketAddr::from_str("iroha0:1337").unwrap(), - telemetry_addr: SocketAddr::from_str("iroha0:1337").unwrap(), trusted_peers: BTreeSet::new(), } .into(); let actual = serde_yaml::to_string(&env).unwrap(); let expected = expect_test::expect![[r#" - IROHA_PUBLIC_KEY: ed0120415388A90FA238196737746A70565D041CFB32EAA0C89FF8CB244C7F832A6EBD - IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"6bf163fd75192b81a78cb20c5f8cb917f591ac6635f2577e6ca305c27a456a5d415388a90fa238196737746a70565d041cfb32eaa0c89ff8cb244c7f832a6ebd"}' - TORII_P2P_ADDR: iroha0:1337 - TORII_API_URL: iroha0:1337 - TORII_TELEMETRY_URL: iroha0:1337 - IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed0120415388A90FA238196737746A70565D041CFB32EAA0C89FF8CB244C7F832A6EBD - SUMERAGI_TRUSTED_PEERS: '[]' - "#]]; + IROHA_PUBLIC_KEY: ed0120415388A90FA238196737746A70565D041CFB32EAA0C89FF8CB244C7F832A6EBD + IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"6bf163fd75192b81a78cb20c5f8cb917f591ac6635f2577e6ca305c27a456a5d415388a90fa238196737746a70565d041cfb32eaa0c89ff8cb244c7f832a6ebd"}' + TORII_P2P_ADDR: iroha0:1337 + TORII_API_URL: iroha0:1337 + IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed0120415388A90FA238196737746A70565D041CFB32EAA0C89FF8CB244C7F832A6EBD + SUMERAGI_TRUSTED_PEERS: '[]' + "#]]; expected.assert_eq(&actual); } @@ -702,14 +689,12 @@ mod tests { IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"5f8d1291bf6b762ee748a87182345d135fd167062857aa4f20ba39f25e74c4b0f0321eb4139163c35f88bf78520ff7071499d7f4e79854550028a196c7b49e13"}' TORII_P2P_ADDR: iroha0:1337 TORII_API_URL: iroha0:8080 - TORII_TELEMETRY_URL: iroha0:8180 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01203420F48A9EEB12513B8EB7DAF71979CE80A1013F5F341C10DCDA4F6AA19F97A9 IROHA_GENESIS_ACCOUNT_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"5a6d5f06a90d29ad906e2f6ea8b41b4ef187849d0d397081a4a15ffcbe71e7c73420f48a9eeb12513b8eb7daf71979ce80a1013f5f341c10dcda4f6aa19f97a9"}' SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha2:1339","public_key":"ed0120312C1B7B5DE23D366ADCF23CD6DB92CE18B2AA283C7D9F5033B969C2DC2B92F4"},{"address":"iroha3:1340","public_key":"ed0120854457B2E3D6082181DA73DC01C1E6F93A72D0C45268DC8845755287E98A5DEE"},{"address":"iroha1:1338","public_key":"ed0120A88554AA5C86D28D0EEBEC497235664433E807881CD31E12A1AF6C4D8B0F026C"},{"address":"iroha0:1337","public_key":"ed0120F0321EB4139163C35F88BF78520FF7071499D7F4E79854550028A196C7B49E13"}]' ports: - 1337:1337 - 8080:8080 - - 8180:8180 volumes: - ./config:/config init: true @@ -722,13 +707,11 @@ mod tests { IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"8d34d2c6a699c61e7a9d5aabbbd07629029dfb4f9a0800d65aa6570113edb465a88554aa5c86d28d0eebec497235664433e807881cd31e12a1af6c4d8b0f026c"}' TORII_P2P_ADDR: iroha1:1338 TORII_API_URL: iroha1:8081 - TORII_TELEMETRY_URL: iroha1:8181 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01203420F48A9EEB12513B8EB7DAF71979CE80A1013F5F341C10DCDA4F6AA19F97A9 SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha2:1339","public_key":"ed0120312C1B7B5DE23D366ADCF23CD6DB92CE18B2AA283C7D9F5033B969C2DC2B92F4"},{"address":"iroha3:1340","public_key":"ed0120854457B2E3D6082181DA73DC01C1E6F93A72D0C45268DC8845755287E98A5DEE"},{"address":"iroha1:1338","public_key":"ed0120A88554AA5C86D28D0EEBEC497235664433E807881CD31E12A1AF6C4D8B0F026C"},{"address":"iroha0:1337","public_key":"ed0120F0321EB4139163C35F88BF78520FF7071499D7F4E79854550028A196C7B49E13"}]' ports: - 1338:1338 - 8081:8081 - - 8181:8181 volumes: - ./config:/config init: true @@ -740,13 +723,11 @@ mod tests { IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"cf4515a82289f312868027568c0da0ee3f0fde7fef1b69deb47b19fde7cbc169312c1b7b5de23d366adcf23cd6db92ce18b2aa283c7d9f5033b969c2dc2b92f4"}' TORII_P2P_ADDR: iroha2:1339 TORII_API_URL: iroha2:8082 - TORII_TELEMETRY_URL: iroha2:8182 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01203420F48A9EEB12513B8EB7DAF71979CE80A1013F5F341C10DCDA4F6AA19F97A9 SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha2:1339","public_key":"ed0120312C1B7B5DE23D366ADCF23CD6DB92CE18B2AA283C7D9F5033B969C2DC2B92F4"},{"address":"iroha3:1340","public_key":"ed0120854457B2E3D6082181DA73DC01C1E6F93A72D0C45268DC8845755287E98A5DEE"},{"address":"iroha1:1338","public_key":"ed0120A88554AA5C86D28D0EEBEC497235664433E807881CD31E12A1AF6C4D8B0F026C"},{"address":"iroha0:1337","public_key":"ed0120F0321EB4139163C35F88BF78520FF7071499D7F4E79854550028A196C7B49E13"}]' ports: - 1339:1339 - 8082:8082 - - 8182:8182 volumes: - ./config:/config init: true @@ -758,13 +739,11 @@ mod tests { IROHA_PRIVATE_KEY: '{"digest_function":"ed25519","payload":"ab0e99c2b845b4ac7b3e88d25a860793c7eb600a25c66c75cba0bae91e955aa6854457b2e3d6082181da73dc01c1e6f93a72d0c45268dc8845755287e98a5dee"}' TORII_P2P_ADDR: iroha3:1340 TORII_API_URL: iroha3:8083 - TORII_TELEMETRY_URL: iroha3:8183 IROHA_GENESIS_ACCOUNT_PUBLIC_KEY: ed01203420F48A9EEB12513B8EB7DAF71979CE80A1013F5F341C10DCDA4F6AA19F97A9 SUMERAGI_TRUSTED_PEERS: '[{"address":"iroha2:1339","public_key":"ed0120312C1B7B5DE23D366ADCF23CD6DB92CE18B2AA283C7D9F5033B969C2DC2B92F4"},{"address":"iroha3:1340","public_key":"ed0120854457B2E3D6082181DA73DC01C1E6F93A72D0C45268DC8845755287E98A5DEE"},{"address":"iroha1:1338","public_key":"ed0120A88554AA5C86D28D0EEBEC497235664433E807881CD31E12A1AF6C4D8B0F026C"},{"address":"iroha0:1337","public_key":"ed0120F0321EB4139163C35F88BF78520FF7071499D7F4E79854550028A196C7B49E13"}]' ports: - 1340:1340 - 8083:8083 - - 8183:8183 volumes: - ./config:/config init: true From 6c2445d3858b59eca4852429790408cd3b56dfdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Mon, 9 Oct 2023 10:36:10 +0200 Subject: [PATCH 40/55] [refactor]: Include smart contract code into the workspace (#3944) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- .github/dependabot.yml | 6 - .github/workflows/iroha2-dev-pr-static.yml | 3 - .github/workflows/iroha2-dev-pr-wasm.yaml | 39 +- .github/workflows/iroha2-dev-pr.yml | 9 +- Cargo.lock | 71 +++ Cargo.toml | 22 +- cli/derive/src/lib.rs | 2 +- client/tests/integration/events/data.rs | 2 +- .../smartcontracts/.cargo/config.toml | 2 + .../integration/smartcontracts/Cargo.toml | 9 +- .../Cargo.toml | 2 + .../src/lib.rs | 13 +- .../mint_rose_trigger/Cargo.toml | 2 + .../mint_rose_trigger/src/lib.rs | 4 + .../validator_with_admin/Cargo.toml | 1 + .../validator_with_admin/src/lib.rs | 15 +- .../validator_with_custom_token/Cargo.toml | 4 +- .../validator_with_custom_token/src/lib.rs | 19 +- .../validator_with_migration_fail/Cargo.toml | 4 +- .../validator_with_migration_fail/src/lib.rs | 11 +- client/tests/wasm/utils.rs | 4 +- config/base/Cargo.toml | 1 + config/base/src/runtime_upgrades.rs | 10 +- configs/peer/validator.wasm | Bin 488237 -> 487587 bytes core/src/smartcontracts/wasm.rs | 227 ++++---- crypto/src/hash.rs | 2 + data_model/src/lib.rs | 2 +- data_model/src/name.rs | 16 +- data_model/src/predicate.rs | 2 +- data_model/src/smart_contract.rs | 43 ++ data_model/src/wasm.rs | 120 ----- default_validator/Cargo.toml | 3 +- default_validator/src/lib.rs | 15 +- ffi/derive/src/convert.rs | 6 +- schema/Cargo.toml | 2 +- {wasm => smart_contract}/.cargo/config.toml | 3 - smart_contract/Cargo.toml | 26 + {wasm => smart_contract}/LICENSE | 0 {wasm => smart_contract}/README.md | 2 +- {wasm => smart_contract}/derive/Cargo.toml | 3 +- .../derive/src/entrypoint.rs | 9 +- {wasm => smart_contract}/derive/src/lib.rs | 0 smart_contract/src/lib.rs | 268 ++++++++++ {wasm => smart_contract}/trigger/Cargo.toml | 11 +- .../trigger/derive/Cargo.toml | 1 - .../trigger/derive/src/entrypoint.rs | 13 +- .../trigger/derive/src/lib.rs | 0 smart_contract/trigger/src/lib.rs | 45 ++ smart_contract/utils/Cargo.toml | 19 + {wasm => smart_contract/utils}/src/debug.rs | 5 +- smart_contract/utils/src/lib.rs | 120 +++++ {wasm => smart_contract/utils}/src/log.rs | 1 + smart_contract/validator/Cargo.toml | 24 + .../validator/derive/Cargo.toml | 1 - .../validator/derive/src/conversion.rs | 0 .../validator/derive/src/entrypoint.rs | 37 +- .../validator/derive/src/lib.rs | 0 .../validator/derive/src/token.rs | 10 +- .../validator/derive/src/validate.rs | 0 .../validator/src/default.rs | 14 +- smart_contract/validator/src/lib.rs | 291 ++++++++++ .../validator/src/permission.rs | 1 + wasm/Cargo.toml | 207 -------- wasm/src/lib.rs | 495 ------------------ wasm/trigger/src/lib.rs | 13 - wasm/validator/Cargo.toml | 25 - wasm/validator/src/lib.rs | 170 ------ wasm_codec/src/lib.rs | 9 +- 68 files changed, 1226 insertions(+), 1290 deletions(-) create mode 100644 client/tests/integration/smartcontracts/.cargo/config.toml create mode 100644 data_model/src/smart_contract.rs delete mode 100644 data_model/src/wasm.rs rename {wasm => smart_contract}/.cargo/config.toml (60%) create mode 100644 smart_contract/Cargo.toml rename {wasm => smart_contract}/LICENSE (100%) rename {wasm => smart_contract}/README.md (96%) rename {wasm => smart_contract}/derive/Cargo.toml (80%) rename {wasm => smart_contract}/derive/src/entrypoint.rs (86%) rename {wasm => smart_contract}/derive/src/lib.rs (100%) create mode 100644 smart_contract/src/lib.rs rename {wasm => smart_contract}/trigger/Cargo.toml (54%) rename {wasm => smart_contract}/trigger/derive/Cargo.toml (89%) rename {wasm => smart_contract}/trigger/derive/src/entrypoint.rs (79%) rename {wasm => smart_contract}/trigger/derive/src/lib.rs (100%) create mode 100644 smart_contract/trigger/src/lib.rs create mode 100644 smart_contract/utils/Cargo.toml rename {wasm => smart_contract/utils}/src/debug.rs (98%) create mode 100644 smart_contract/utils/src/lib.rs rename {wasm => smart_contract/utils}/src/log.rs (99%) create mode 100644 smart_contract/validator/Cargo.toml rename {wasm => smart_contract}/validator/derive/Cargo.toml (89%) rename {wasm => smart_contract}/validator/derive/src/conversion.rs (100%) rename {wasm => smart_contract}/validator/derive/src/entrypoint.rs (77%) rename {wasm => smart_contract}/validator/derive/src/lib.rs (100%) rename {wasm => smart_contract}/validator/derive/src/token.rs (84%) rename {wasm => smart_contract}/validator/derive/src/validate.rs (100%) rename {wasm => smart_contract}/validator/src/default.rs (99%) create mode 100644 smart_contract/validator/src/lib.rs rename {wasm => smart_contract}/validator/src/permission.rs (99%) delete mode 100644 wasm/Cargo.toml delete mode 100644 wasm/src/lib.rs delete mode 100644 wasm/trigger/src/lib.rs delete mode 100644 wasm/validator/Cargo.toml delete mode 100644 wasm/validator/src/lib.rs diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3085bf1ac2f..ab66c60c668 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -25,12 +25,6 @@ updates: schedule: interval: "daily" - - package-ecosystem: "cargo" - target-branch: "iroha2-dev" - directory: "/wasm/" - schedule: - interval: "daily" - - package-ecosystem: "cargo" target-branch: "iroha2-dev" directory: "/default_validator/" diff --git a/.github/workflows/iroha2-dev-pr-static.yml b/.github/workflows/iroha2-dev-pr-static.yml index 88b71c134c7..f52c204935c 100644 --- a/.github/workflows/iroha2-dev-pr-static.yml +++ b/.github/workflows/iroha2-dev-pr-static.yml @@ -9,9 +9,6 @@ on: - '**.toml' - '.github/workflows/**.yml' - # Not part of the workspace - - '!wasm/**' - concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true diff --git a/.github/workflows/iroha2-dev-pr-wasm.yaml b/.github/workflows/iroha2-dev-pr-wasm.yaml index 1b310b41a0f..2e77e2a7c63 100644 --- a/.github/workflows/iroha2-dev-pr-wasm.yaml +++ b/.github/workflows/iroha2-dev-pr-wasm.yaml @@ -1,20 +1,19 @@ name: I2::Dev::Wasm -defaults: - run: - working-directory: wasm - on: pull_request: branches: [iroha2-dev] paths: - - 'wasm/**.rs' - - 'wasm/**.json' - - 'wasm/**.toml' - - 'wasm/**.yml' - 'data_model/**.rs' + - 'data_model/**.yml' + - 'data_model/**.json' - 'data_model/**.toml' + - 'smart_contract/**.rs' + - 'smart_contract/**.yml' + - 'smart_contract/**.json' + - 'smart_contract/**.toml' + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -23,23 +22,6 @@ env: RUSTUP_TOOLCHAIN: nightly-2023-06-25 jobs: - static-analysis: - runs-on: ubuntu-latest - container: - image: hyperledger/iroha2-ci:nightly-2023-06-25 - steps: - - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 - - - name: Format - run: cargo fmt --all -- --check - - name: Lints - if: always() - run: cargo clippy -Zlints --workspace --benches --tests --examples --quiet - - name: Documentation - if: always() - run: cargo doc --no-deps --quiet - tests: runs-on: ubuntu-latest #[self-hosted, Linux] container: @@ -48,6 +30,7 @@ jobs: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 - name: Install iroha_wasm_test_runner - run: cd .. && cargo install --path tools/wasm_test_runner - - name: Run tests - run: mold --run cargo test --tests --no-fail-fast --quiet + run: cargo install --path tools/wasm_test_runner + - name: Run smart contract tests on WebAssembly VM + working-directory: smart_contract + run: mold --run cargo test --tests --target wasm32-unknown-unknown --no-fail-fast --quiet diff --git a/.github/workflows/iroha2-dev-pr.yml b/.github/workflows/iroha2-dev-pr.yml index 9cd86bea4bf..aaaa4fcd79f 100644 --- a/.github/workflows/iroha2-dev-pr.yml +++ b/.github/workflows/iroha2-dev-pr.yml @@ -9,9 +9,6 @@ on: - '**.toml' - '.github/workflows/**.yml' - # Not part of the workspace - - '!wasm/**' - concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -45,10 +42,6 @@ jobs: - name: Check Docker Compose configurations if: always() run: ./scripts/tests/consistency.sh docker-compose - - name: Wasm build check - if: always() - working-directory: wasm - run: mold --run cargo build --target wasm32-unknown-unknown --quiet with_coverage: runs-on: [self-hosted, Linux, iroha2ci] @@ -159,7 +152,7 @@ jobs: - name: Run Iroha 2 on bare metal run: | - ./scripts/test_env.py setup + ./scripts/test_env.py setup - name: Copy Iroha 2 client config run: | diff --git a/Cargo.lock b/Cargo.lock index dd799b31c3a..02aba7e1cbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3054,6 +3054,7 @@ dependencies = [ "iroha_config_derive", "iroha_crypto", "json5", + "parking_lot", "serde", "serde_json", "thiserror", @@ -3418,6 +3419,35 @@ dependencies = [ "iroha_schema", ] +[[package]] +name = "iroha_smart_contract" +version = "2.0.0-pre-rc.19" +dependencies = [ + "iroha_data_model", + "iroha_smart_contract_derive", + "iroha_smart_contract_utils", + "parity-scale-codec", + "webassembly-test", +] + +[[package]] +name = "iroha_smart_contract_derive" +version = "2.0.0-pre-rc.19" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "iroha_smart_contract_utils" +version = "2.0.0-pre-rc.19" +dependencies = [ + "iroha_data_model", + "parity-scale-codec", + "webassembly-test", +] + [[package]] name = "iroha_substrate" version = "2.0.0-pre-rc.19" @@ -3478,6 +3508,47 @@ dependencies = [ "trybuild", ] +[[package]] +name = "iroha_trigger" +version = "2.0.0-pre-rc.19" +dependencies = [ + "iroha_data_model", + "iroha_smart_contract", + "iroha_smart_contract_utils", + "iroha_trigger_derive", +] + +[[package]] +name = "iroha_trigger_derive" +version = "2.0.0-pre-rc.19" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "iroha_validator" +version = "2.0.0-pre-rc.19" +dependencies = [ + "iroha_data_model", + "iroha_schema", + "iroha_smart_contract", + "iroha_smart_contract_utils", + "iroha_validator_derive", + "serde", + "serde_json", +] + +[[package]] +name = "iroha_validator_derive" +version = "2.0.0-pre-rc.19" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "iroha_version" version = "2.0.0-pre-rc.19" diff --git a/Cargo.toml b/Cargo.toml index 4ad54b655e1..69532e90459 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,15 +18,14 @@ iroha = { path = "cli" } iroha_dsl = { version = "=2.0.0-pre-rc.19", path = "dsl" } iroha_cli_derive = { version = "=2.0.0-pre-rc.19", path = "cli/derive" } iroha_macro_utils = { version = "=2.0.0-pre-rc.19", path = "macro/utils" } -iroha_wasm_builder = { version = "=2.0.0-pre-rc.19", path = "wasm_builder" } iroha_telemetry = { version = "=2.0.0-pre-rc.19", path = "telemetry" } iroha_telemetry_derive = { version = "=2.0.0-pre-rc.19", path = "telemetry/derive" } iroha_p2p = { version = "=2.0.0-pre-rc.19", path = "p2p" } -iroha_data_model_derive = { version = "=2.0.0-pre-rc.19", path = "data_model/derive" } iroha_core = { version = "=2.0.0-pre-rc.19 ", path = "core" } iroha_primitives = { version = "=2.0.0-pre-rc.19", path = "primitives", default-features = false } iroha_primitives_derive = { version = "=2.0.0-pre-rc.19", path = "primitives/derive" } -iroha_data_model = { version = "=2.0.0-pre-rc.19", path = "data_model" } +iroha_data_model = { version = "=2.0.0-pre-rc.19", path = "data_model", default-features = false } +iroha_data_model_derive = { version = "=2.0.0-pre-rc.19", path = "data_model/derive" } iroha_client = { version = "=2.0.0-pre-rc.19", path = "client" } iroha_config = { version = "=2.0.0-pre-rc.19", path = "config" } iroha_config_base = { version = "=2.0.0-pre-rc.19", path = "config/base" } @@ -46,6 +45,16 @@ iroha_ffi_derive = { version = "=2.0.0-pre-rc.19", path = "ffi/derive" } iroha_version = { version = "=2.0.0-pre-rc.19", path = "version", default-features = false } iroha_version_derive = { version = "=2.0.0-pre-rc.19", path = "version/derive", default-features = false } iroha_wasm_codec = { version = "=2.0.0-pre-rc.19", path = "wasm_codec" } +iroha_wasm_builder = { version = "=2.0.0-pre-rc.19", path = "wasm_builder" } + +iroha_smart_contract = { version = "=2.0.0-pre-rc.19", path = "smart_contract" } +iroha_smart_contract_derive = { version = "=2.0.0-pre-rc.19", path = "smart_contract/derive" } +iroha_smart_contract_utils = { version = "=2.0.0-pre-rc.19", path = "smart_contract/utils" } +iroha_validator = { version = "=2.0.0-pre-rc.19", path = "smart_contract/validator" } +iroha_validator_derive = { version = "=2.0.0-pre-rc.19", path = "smart_contract/validator/derive" } +iroha_trigger = { version = "=2.0.0-pre-rc.19", path = "smart_contract/trigger" } +iroha_trigger_derive = { version = "=2.0.0-pre-rc.19", path = "smart_contract/trigger/derive" } + test_network = { version = "=2.0.0-pre-rc.19", path = "core/test_network" } proc-macro-error = "1.0.4" @@ -312,6 +321,13 @@ members = [ "schema", "schema/derive", "schema/gen", + "smart_contract", + "smart_contract/derive", + "smart_contract/trigger", + "smart_contract/trigger/derive", + "smart_contract/utils", + "smart_contract/validator", + "smart_contract/validator/derive", "substrate", "telemetry", "tools/kagami", diff --git a/cli/derive/src/lib.rs b/cli/derive/src/lib.rs index 84e4dc8d0ca..4def3d9b105 100644 --- a/cli/derive/src/lib.rs +++ b/cli/derive/src/lib.rs @@ -133,7 +133,7 @@ impl Parse for EndpointList { fn parse(input: ParseStream) -> SynResult { let items = Punctuated::::parse_terminated(input)?; let mut seen_arg_counts = Vec::new(); - for item in items.iter() { + for item in &items { match item { EndpointItem::NameAndArgCount { arg_count, .. } | EndpointItem::ArgCount(arg_count) => { diff --git a/client/tests/integration/events/data.rs b/client/tests/integration/events/data.rs index 03a0ecf96aa..f5cd354731b 100644 --- a/client/tests/integration/events/data.rs +++ b/client/tests/integration/events/data.rs @@ -82,7 +82,7 @@ fn wasm_execution_should_produce_events() -> Result<()> { (func (export "{main_fn_name}") (param) {isi_calls})) "#, - main_fn_name = iroha_data_model::wasm::export::fn_names::SMART_CONTRACT_MAIN, + main_fn_name = "_iroha_smart_contract_main", wasm_template = wasm_template(&isi_hex.concat()), isi_calls = isi_calls ); diff --git a/client/tests/integration/smartcontracts/.cargo/config.toml b/client/tests/integration/smartcontracts/.cargo/config.toml new file mode 100644 index 00000000000..f4e8c002fc2 --- /dev/null +++ b/client/tests/integration/smartcontracts/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "wasm32-unknown-unknown" diff --git a/client/tests/integration/smartcontracts/Cargo.toml b/client/tests/integration/smartcontracts/Cargo.toml index ae766717c1b..55420704b94 100644 --- a/client/tests/integration/smartcontracts/Cargo.toml +++ b/client/tests/integration/smartcontracts/Cargo.toml @@ -27,13 +27,14 @@ opt-level = "z" # Optimize for size vs speed with "s"/"z"(removes vectorizat codegen-units = 1 # Further reduces binary size but increases compilation time [workspace.dependencies] -iroha_wasm = { version = "=2.0.0-pre-rc.19", path = "../../../../wasm", features = ["debug"]} -iroha_trigger = { version = "=2.0.0-pre-rc.19", path = "../../../../wasm/trigger", features = ["debug"]} -iroha_validator = { version = "=2.0.0-pre-rc.19", path = "../../../../wasm/validator" } +iroha_trigger = { version = "=2.0.0-pre-rc.19", path = "../../../../smart_contract/trigger", features = ["debug"]} +iroha_validator = { version = "=2.0.0-pre-rc.19", path = "../../../../smart_contract/validator" } iroha_schema = { version = "=2.0.0-pre-rc.19", path = "../../../../schema" } parity-scale-codec = { version = "3.2.1", default-features = false } -panic-halt = "0.2.0" anyhow = { version = "1.0.71", default-features = false } serde = { version = "1.0.151", default-features = false } serde_json = { version = "1.0.91", default-features = false } + +lol_alloc = "0.4.0" +panic-halt = "0.2.0" diff --git a/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/Cargo.toml b/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/Cargo.toml index b13b19b0d81..a01eeabcb9e 100644 --- a/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/Cargo.toml +++ b/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/Cargo.toml @@ -12,4 +12,6 @@ crate-type = ['cdylib'] [dependencies] iroha_trigger.workspace = true + panic-halt.workspace = true +lol_alloc.workspace = true diff --git a/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs b/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs index 325e732dda0..e5cf1a30c5a 100644 --- a/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs +++ b/client/tests/integration/smartcontracts/create_nft_for_every_user_trigger/src/lib.rs @@ -1,5 +1,4 @@ //! Smartcontract which creates new nft for every user - #![no_std] extern crate alloc; @@ -9,13 +8,15 @@ extern crate panic_halt; use alloc::{format, string::ToString}; use iroha_trigger::prelude::*; +use lol_alloc::{FreeListAllocator, LockedAllocator}; + +#[global_allocator] +static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); #[iroha_trigger::main] fn main(_owner: AccountId, _event: Event) { - iroha_trigger::info!("Executing trigger"); - + iroha_trigger::log::info!("Executing trigger"); let accounts = FindAllAccounts.execute().dbg_unwrap(); - let limits = MetadataLimits::new(256, 256); for account in accounts { @@ -42,7 +43,7 @@ fn main(_owner: AccountId, _event: Event) { RegisterExpr::new(account_nft).execute().dbg_unwrap(); } - iroha_trigger::info!("Smart contract executed successfully"); + iroha_trigger::log::info!("Smart contract executed successfully"); } fn generate_new_nft_id(account_id: &AccountId) -> AssetDefinitionId { @@ -56,7 +57,7 @@ fn generate_new_nft_id(account_id: &AccountId) -> AssetDefinitionId { .count() .checked_add(1) .dbg_unwrap(); - iroha_trigger::debug!(&format!("New number: {}", new_number)); + iroha_trigger::log::debug!(&format!("New number: {}", new_number)); format!( "nft_number_{}_for_{}#{}", diff --git a/client/tests/integration/smartcontracts/mint_rose_trigger/Cargo.toml b/client/tests/integration/smartcontracts/mint_rose_trigger/Cargo.toml index 98c7c9992bd..cf5deba651d 100644 --- a/client/tests/integration/smartcontracts/mint_rose_trigger/Cargo.toml +++ b/client/tests/integration/smartcontracts/mint_rose_trigger/Cargo.toml @@ -12,4 +12,6 @@ crate-type = ['cdylib'] [dependencies] iroha_trigger.workspace = true + panic-halt.workspace = true +lol_alloc.workspace = true diff --git a/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs b/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs index a617b3ffd63..7dd2d5c7c0d 100644 --- a/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs +++ b/client/tests/integration/smartcontracts/mint_rose_trigger/src/lib.rs @@ -8,6 +8,10 @@ extern crate panic_halt; use core::str::FromStr as _; use iroha_trigger::prelude::*; +use lol_alloc::{FreeListAllocator, LockedAllocator}; + +#[global_allocator] +static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); /// Mint 1 rose for owner #[iroha_trigger::main] diff --git a/client/tests/integration/smartcontracts/validator_with_admin/Cargo.toml b/client/tests/integration/smartcontracts/validator_with_admin/Cargo.toml index 1b465081974..eeb3d61804a 100644 --- a/client/tests/integration/smartcontracts/validator_with_admin/Cargo.toml +++ b/client/tests/integration/smartcontracts/validator_with_admin/Cargo.toml @@ -15,3 +15,4 @@ iroha_validator.workspace = true iroha_schema.workspace = true panic-halt.workspace = true +lol_alloc.workspace = true diff --git a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs index 80ba91b749d..8c68022219d 100644 --- a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs @@ -4,19 +4,24 @@ #![no_std] #![allow(missing_docs, clippy::missing_errors_doc)] +#[cfg(not(test))] +extern crate panic_halt; + use iroha_validator::{ data_model::evaluate::{EvaluationError, ExpressionEvaluator}, - iroha_wasm, parse, + parse, prelude::*, + smart_contract, }; +use lol_alloc::{FreeListAllocator, LockedAllocator}; -#[cfg(not(test))] -extern crate panic_halt; +#[global_allocator] +static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); struct Validator { verdict: Result, block_height: u64, - host: iroha_wasm::Host, + host: smart_contract::Host, } impl Validator { @@ -25,7 +30,7 @@ impl Validator { Self { verdict: Ok(()), block_height, - host: iroha_wasm::Host, + host: smart_contract::Host, } } } diff --git a/client/tests/integration/smartcontracts/validator_with_custom_token/Cargo.toml b/client/tests/integration/smartcontracts/validator_with_custom_token/Cargo.toml index 431eae19798..8fd8e8f3cc7 100644 --- a/client/tests/integration/smartcontracts/validator_with_custom_token/Cargo.toml +++ b/client/tests/integration/smartcontracts/validator_with_custom_token/Cargo.toml @@ -15,7 +15,9 @@ iroha_validator.workspace = true iroha_schema.workspace = true parity-scale-codec.workspace = true -panic-halt.workspace = true anyhow.workspace = true serde_json.workspace = true serde.workspace = true + +panic-halt.workspace = true +lol_alloc.workspace = true diff --git a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs index 30f205b7bd5..30a6e6d7873 100644 --- a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs @@ -14,24 +14,27 @@ #![allow(missing_docs, clippy::missing_errors_doc)] extern crate alloc; +#[cfg(not(test))] +extern crate panic_halt; -use alloc::string::String; +use alloc::{borrow::ToOwned, string::String}; use anyhow::anyhow; use iroha_schema::IntoSchema; use iroha_validator::{ data_model::evaluate::{EvaluationError, ExpressionEvaluator}, default::default_permission_token_schema, - iroha_wasm, permission::Token as _, prelude::*, + smart_contract, }; +use lol_alloc::{FreeListAllocator, LockedAllocator}; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; use serde_json::json; -#[cfg(not(test))] -extern crate panic_halt; +#[global_allocator] +static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); use alloc::format; @@ -59,7 +62,7 @@ mod token { struct Validator { verdict: Result, block_height: u64, - host: iroha_wasm::Host, + host: smart_contract::Host, } impl Validator { @@ -68,7 +71,7 @@ impl Validator { Self { verdict: Ok(()), block_height, - host: iroha_wasm::Host, + host: smart_contract::Host, } } @@ -157,7 +160,7 @@ impl Validator { }) }) .map_err(|error| { - iroha_validator::iroha_wasm::error!(&error); + iroha_validator::log::error!(&error); format!( "{:?}", anyhow!(error).context(format!( @@ -293,7 +296,7 @@ pub fn migrate(_block_height: u64) -> MigrationResult { schema.insert::(); let (token_ids, schema_str) = schema.serialize(); - iroha_validator::iroha_wasm::set_permission_token_schema( + iroha_validator::set_permission_token_schema( &iroha_validator::data_model::permission::PermissionTokenSchema::new(token_ids, schema_str), ); diff --git a/client/tests/integration/smartcontracts/validator_with_migration_fail/Cargo.toml b/client/tests/integration/smartcontracts/validator_with_migration_fail/Cargo.toml index abb13de0a70..fb8aa79e97c 100644 --- a/client/tests/integration/smartcontracts/validator_with_migration_fail/Cargo.toml +++ b/client/tests/integration/smartcontracts/validator_with_migration_fail/Cargo.toml @@ -12,5 +12,7 @@ crate-type = ['cdylib'] [dependencies] iroha_validator.workspace = true -panic-halt.workspace = true anyhow.workspace = true + +panic-halt.workspace = true +lol_alloc.workspace = true diff --git a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs index 86e532012b6..9bbf0ff22ff 100644 --- a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs @@ -15,14 +15,19 @@ use iroha_validator::{ evaluate::{EvaluationError, ExpressionEvaluator}, ValidationFail, }, - iroha_wasm, parse, + parse, prelude::*, + smart_contract, }; +use lol_alloc::{FreeListAllocator, LockedAllocator}; + +#[global_allocator] +static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); struct Validator { verdict: Result, block_height: u64, - host: iroha_wasm::Host, + host: smart_contract::Host, } impl Validator { @@ -31,7 +36,7 @@ impl Validator { Self { verdict: Ok(()), block_height, - host: iroha_wasm::Host, + host: smart_contract::Host, } } } diff --git a/client/tests/wasm/utils.rs b/client/tests/wasm/utils.rs index 5aefbd7dd06..cf65d51eb20 100644 --- a/client/tests/wasm/utils.rs +++ b/client/tests/wasm/utils.rs @@ -41,8 +41,8 @@ pub fn wasm_template(hex_val: &str) -> String { nop) "#, memory_name = "memory", - alloc_fn_name = "_iroha_wasm_alloc", - dealloc_fn_name = "_iroha_wasm_dealloc", + alloc_fn_name = "_iroha_smart_contract_alloc", + dealloc_fn_name = "_iroha_smart_contract_dealloc", execute_instruction = "execute_instruction", execute_query = "execute_query", hex_val = escape_hex(hex_val), diff --git a/config/base/Cargo.toml b/config/base/Cargo.toml index 93241f408b7..b11b28ea577 100644 --- a/config/base/Cargo.toml +++ b/config/base/Cargo.toml @@ -16,6 +16,7 @@ iroha_crypto = { workspace = true, features = ["std"] } serde = { workspace = true, default-features = false, features = ["derive"] } serde_json = { workspace = true, features = ["alloc"] } +parking_lot = { workspace = true } json5 = { workspace = true } thiserror = { workspace = true } displaydoc = { workspace = true } diff --git a/config/base/src/runtime_upgrades.rs b/config/base/src/runtime_upgrades.rs index ac539aad6ab..b2312f3f774 100644 --- a/config/base/src/runtime_upgrades.rs +++ b/config/base/src/runtime_upgrades.rs @@ -144,10 +144,11 @@ pub trait Reload { pub mod handle { use std::{ fmt::{Debug, Formatter}, - sync::{Arc, Mutex}, + sync::Arc, }; use crossbeam::atomic::AtomicCell; + use parking_lot::Mutex; use serde::{Deserialize, Serialize}; use super::{Reload, ReloadError, ReloadMut, Result}; @@ -179,10 +180,7 @@ pub mod handle { /// # Errors /// [`ReloadError::Poisoned`] When the [`Mutex`] storing the reload handle is poisoned. pub fn set(&self, handle: impl ReloadMut + Send + Sync + 'static) { - *self - .inner - .lock() - .expect("Mutex in `Singleton::set` got poisoned") = Some(Box::new(handle)); + *self.inner.lock() = Some(Box::new(handle)); } } @@ -194,7 +192,7 @@ pub mod handle { impl Reload for Singleton { fn reload(&self, item: T) -> Result<()> { - match &mut *self.inner.lock().expect("Valid") { + match &mut *self.inner.lock() { Some(handle) => { handle.reload(item)?; Ok(()) diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index d0673e6c06a37f3346e6046ca0a2193d290cf847..744cbc09a101a2f680e5e393795c4fddd802bdf2 100644 GIT binary patch literal 487587 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

a&v4|55>Z?5Kv| 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 V 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

bmb`@ATty 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 delta 48627 zcmeGFd0-XQ*$0l_GjnF{nq;zXkj%Y=kgz4JK{go_5CKu^Rz-{JivblZYSrS6iWU_# z80x`2R{Kh;RxGv`D`HUJ78MmMT53__POVy~g1l~gKhJaK-rR(s?eF*g_x%#RGjrxF z&w0*sp6xv6%p7Pi>wfQC)m}?}j2+TE;SKwAAlUH1^^5U9EP`^aJ zM{eCN%zs68wJkQri2QXA8A6DHwuj9{qav{Y{t1bMK7FG>O9rX})qzMLU9GDJWaxHnL-6j6O2$bQi2LRkDC@)~%Z z16VGxHj5%*Nhu`#Gjaogk^zB$UC?%H@akAzUY>yl20NzXw7nhtQ2eXy*^nzfYx^j4 zx_G&5X82OEb=@DsMMm43(TcOL4s8r>kvD}}Ln}fzhHjRdg71Xi4Zjt>GqO5zcjW%a z?U7$bZi-wVc`)+dkzYh^i2OYA>&Ws*TjZX|ipZ^zTO#d|Uq$YVJP^4pa#!TW$U~7e zkyVj2aykFVh=*Km+ z8qIDss;Ws>-Hrr2xN%Bo8&Wk-=j#+b^6f%GSHAUCrxtL19Y{t|U3}eu>i;oD?uk^O z3+sc;_-&6gC&J#ofWwKdH8!w3=$dYIld%+6Zv`@iyg|;MHaBsY&g1P2HM_b<+avw^ zial*B6Vvl_ogI12uHfu{PyAz)PFrUB?POZ{<8cfxi*`s2b^s`ElvmuH~&4Xc527 zaXh*C{M>f$;ER#HV#tL8WmgQH+K02ukB4J{Xdvo_-B@$H$}Mt(u8ltYbLc>1t7sUB z-`Nc{VsG2xh7)nWrD1YUoUZHJcrMj>=x{>%FNfWlxj%LIt@*l#t+~w!0nE~f>3sc1 z3`V|VM>OI0`VoyKfCjkJKNW7ks~v3wV&mJqk$wFtXmAXF&@UKCP4yW$`JnGsj6AEF znhtoeX4e=S2)F@Pj5b0@$Y}0$8LIDU^ByN<_9U|7(u zw-yLpmp{&=ZWfOp3}7qVs2c*R*NO$GpDyUxiQ@^Zi^d;=-#?8Xk6$^V1;5u!7(ASc z*se$yk-A6(BL=*T6QAaxDPRe|AXe`|G}!j;gwZHmF>wTbkD53fzgJG222h`!I74(J z;x(2gDKuevOXYVE@$^XpqFI=3yL=MipGRcf%afi4ajpCLl-~#w(6;S7Z2Y>brY+PD zJ0_2B8#cYue=)9Y_K`U#c*m_F&pZ?Hw44HCQr92Ki21pe zFidG-b_h4*gr?+_#`2_cAUqR4&g>~U zMX^|R$`7XG6vm=mDeE?z_(wy0(RTI8Q;o-Mbx)pAysq=)BB8ckXwO`C#GIhfKsW=> z>4s%WBBI_!WD4XY1aT`y;kqkMvoff^?ngHyKM#*KWULZB@no~}c{pxhCNRee(IX}s z@N7_?3dXq3MbG6up38bXm-cur>G51l&q=>os<5a>hQc1t1wEeg{|%s>9%V30nD1Sk zNMe+}x91qO@6Cg8{N6km*=~(TqM8059PQyAg+e`^gFT+@9?w>fXW1Rl-pAVPQOM}= z48fM}N!u}Je8_X%@HRtqgXNi8{0o3ZF;rS z95nscW4{0f{(&nGQ%ljoEGfLqQv6+G(mb1ukC zopa~?RBThN&x+!djTwI11zF!)Jj5XZ`+OwhL-P%#0&7wgucXY zqjX6`(P+PgH7I_>!VxtDi*R%BhDBk%ThQzlHGxk=+$bqul-_pt!kS`g2OJ1>8H+LI zP_-<)*}kw5V22l#i0DIAhLx08^b2^M>b(B;#I|`Co>9J*RU?e$Hv)Lb_Zd*VxmG>0 z#C|o|3UmtMvHMAF$Yj3Sz|%8a6f`u#HR{b)5f379i_r|O9!KsvW33T4@ydAAh==I< zj1doeW?X{jdJ+;htHOJz`VOwJsM%Rc)uSf&a6yEL`tb}cu-*(bp&_b!i$QJZI_bK> zpytzU>9%8-@rJiSiIiQM><&9sp03;5Zje@FjuT+L-fHSGx zhRn0jOR$oz9wwb@P+RYCdNy){(RAf@u0-a4uajO7g~63b+GY(^W^k_6oj8(S)-*dm zqsJZG`^IKx89jB!%uXN!;>;Tlyn7)YB|?coSYrGK)FY4EPjD7ue-9|No~zsI)N%9{{Buy2`FkVg{o17|qVnMl1%AV|c8I3y1+U4Wg!rPIo~P z5{3sg1QvBBjoE96EitNxW~FCR7EJy!niBP<6K6uy^nxM9Txl|CQniaDk&vD~I%y3P z6>!uwLNt5R^BcT_<~QgmKv4s@kF(>DLI%H#&>BigXM!6ZAhfJ~3zd+7BF z$^dcz??E$?X}E<^yA^MlOxJU3KrAC{1HW7j*l6@y@x)5L-vAzVGHM`{K}ShF&@==F zsm$qt_A#1`KaEk$ag!?XkQ~8MgSzNv(-R}ZFu#MP=YVE;#-LdY z7ZA8#IA4o2n}C0VFzyV3z$T4=Wjla}6b*T~aZFq&e4~w|i)*;aD8nV#WH`8ln#g)~ zG4muYG9$2CMUzp3lt_~?36gv;Ass|SOofaJZzLtOXC;j1VexxQIW{w)qjTxb=0w%+ z|1A3F1@V$JByGM2RrNBvtZnO(JY$#9_V$v(Bu%u;#JVRvA&J?gCuAe@72+mi2)m4h zXBaUgW-y@WP6rKasL5PU*Q~h+-Y>llJzx^bq8>Z11eFL(oaTgjeVOgm0&bQPJ3zUu zMAy)cOs|Fz>p5{V%?rKj?21zgsq3I@8t4Fvd783KfvA^{oXi@jI?I*LN>nu@pfwpi zm&Ao$6Hg~*lA0E%(T}O)9c{CdeJ1y#`ZuTR_X@ecmGF1aXi$S*8iI6!W*UG%6U|yh za2}h^bs(HY@idgE4CKiWk=D&D1vHl?@qqW&%&;Ppy7GE^Zri0TWn!(m=PA2TIZxY` z*wFSsOHCZ=SB6?J+>D`g0>js~tEFfd>7xO!3UsHnj`hqE(4un_VV!0f4Gc!Ujh=T2 zwfhFUe9YH8+MfeYKd0nn%vLb%om=RUuuazUGCdJ|lXx|r)b6M4KZ?$Ev#!b~ugH(C z{Q&y6y5L>Aq;1Z!KOm*_x|~9>udV+b=R;v$b;teq9e?K&`2F(E!|{9QU2lj@ZGG=9 zw>L*z;p}f4fA=sXpMN*0=fAxhZXtF46{585$abd~>bM19FmU(<=)M0cRif5ZpZ#F#k!9kdQ^xP*WLXvT)JD@o?N@B?WO$< z={#rt_B--yZ+mNfOy_&xv4iHD{iI*lXB`L4^W@s?Z5RB>uWQ`qgXVkd1;4JVUrOis zjhWrO?QQ#C^{aXQwcfH^u;YF4yjp3Ar`yWj+^zD8MNVpYxoDT-#gtPlRsu_@C#$g( z&^GIXS-Nj0f7p9Pf6e)u;Sv*xfp0s0rT2e&@JcI1&Km|Ctz5!%p8xF^KNJ2)_3XvC zZ~a~b_aChBx3e2hp+}F3@92)YE?3m}Jy(nJ#KEDIg7TKBjimxGFsjszW#3U?fTlb3 z-*M3!tQgyzzh`$FG^#$WJ6K-T+(7M8rqPWD$+St`K3en_&!;wx7K??NG)}mw3nq$x z7~)0cjT3(nTU7aYu?f&4!&BfV`Xe~)^0 zrZ_xZ`mR~&T*-7&=TYgTALo4A6NFZkIJ)a~3pD+15Voqbj!C~hBem}sF%SM}b@~qk z7y*I1QvKjKfbMtWgX2UM(zl)>9#xMWFV?Fk=3s<)_r&STs$Fl*2K{t|ysJV-0LpXo<0JR>oL==iC#f#)`0!$3URK{5>Z7-aX($3NQ&EYNd;$}0X=Z`rOs&)zZGI% zs{AU^H;QJPR*0_&StD-}PZx=;YTvzLIm8iUzgm5ts69=f`uPcZPMF$fZu&m+EdRK- zB{1K)SF$(UxlfV@TtKm#@BC7d?_2Qu)#QQk??;i71j(u3FU2bsI+g#3-I6-x0kId$ zFzVRfh_?y(q#naxCdjS53!NlQV*0~`E%jdyi)#S&Cl8CAHrBE#yfI$Ld0LW!OZp;~ z!)Pc_AhrAV;u7lMx$8wpG?E^H&UA!XIqHNLjrFH68JO%yqxYn+0=gXr+Pmj5QHl1R zcue#`C9gjw{zVYJut8LWsaZ2_#iDBW@ONIC%HSZ~bHPDu>y#CW_{CvO%XiNC2S&x#|}AD6C9`BXkVl@Zxher{;r$s^VI%V#q((U`Pak^ zG+Za{5F?VmD==!35%TP{3y??+YzL4@ypkAIoe@eDJGWSFvDX<`5buMAC(Vx+;sWg} zUVj!rYdU`-h_D7!0!*guMz@6T(49KtB&<7yE{?l&|I>J! zE{1-*h4A^6^M^18s1PZ(&BI=cE z4+p!RJ7I8>Lo(nN5*Q{KQ1t;;@C!)~H-YH%vzqy)s2<&*v5DWtW`8-_^+Jo?;DzX2 zJf7<&;1BK>&vS>w2f7t;#~m84b!*h36?Q3>%xLBZ)z&vfc`_gC#I%IQe!_ZVaiVsz zyX^jWgy3IDKD&BzUc8PjbK?Var!2Sj{&*B_#`K`*D_4_{RJYJvMfhB$+rk@D0hr`w z;Jn^UE{qSRS{HCrz~3N3llS9a-qkL;ckR-6Jv>1c3^^|u<2H1ia7F!r>I5_l)I8n)xeSzf5&;Et zyM29V*lx;{B)4`wW%6=RWq%m$%%L;ypF_=cM$amf^{~+`ZK{1w)_N~5&OSpn%re71 z*dMRK7!y~<`@4fMT=nq*F?OKoIx)P2?kqIZhyu+6aP{$AZ!Tn{p>`kLgexWm8gBK{ z+oCiXq6wlYm6u3E+NY=8GcJ{6hZ#S+AA?gwep zo33e_O^NVzKNWUMQEeZ-W9*h;SOJc9!k4A_-uH0>v`;*aHH(wt`I;-hQ{{IKDSED_ zdoW;f3;r#PpP0Yp}TuKbptpOi-1 z4HEWkEUdV>`VP~nK;QLgcJuUIQL{UcoNzXI(Lf4xhY1V+9^F9~aP(bWGX{sntqxVP z>E6vDHOeO4(rutAYHN>9U7(SCSGEV=6H1L}t_!d;s|Yh8UgX9g?VIB<@F;R67IVmr zTdkdj<2VKF3r?AABt6oC`o=OteNu9AzjOW!^s8*@_{#V@bUFv=6ysx1zhti=W%DqGssg2)=-+qTlkh=3*5$Rdx z>HXrw?f7BtY*{6gb;s%&qWu@#p; zl^f89)vO9*3B`js2(+O^U(~_ANZit(26c_`n7Xpos7!?_jWIS#d2yo(RnCnYdrA2_ zvA=O0E^qfYmXQ6T>msJ=*A?nkms&X;Roz}|^oj7u8EV21qe{KrXpr8#x6$|;s{ZpZ zV<1)i%}8Te5OsRtcu?g(WR<4w9c2t6jrye~;}Tq^jX^{xG}$r6u_*S+7~?Hgb+MQL zK91FFsaGvh|1;M36KVA;#v3P7@tqTm6Gc)k}M%-s7y}5{!x~iY4K4>?7j9f?k!XO)&3qEv@(SBf( zquTE^>ecJNFpg2zUSz;@QtmI&%mu&T`%M=cv(>Zr8qEi$Kc!L_MAZ%z1HadG+RCPNILr@b=p-t5xC|F*BE!B;2YP_>suZ* zw&3A~NBxIkYVMVoIJf=ofU++wGYBn1Q^sUm7Nv|waJk}oe%f@s@q0Y=eT?VLBR3f9 zx;-7OK3#5{sgwGs^H+c`?NP{ew0d)eaU1TdHlzzSs?Js;sy?~VxC-eDZ!&(RFB8<) zPZ$gI{Q%Xvk$9SVa;1T|AEll&j!#Xy*(fGdp4w)7{r?)eJ`WxK&qx}*Z>9OCgM>ZKQqay4p`F%hJ_c$4uDlH_xrHI9?a z(qoxS#J2~$XzanI?@KhNQYXA*EGO~t?#sqYbX~WNpVg$l5X(%x{TJhOh=`?n&wX;KiKU~|@=|jSO|rk2nWy41t=v2VmtU8g^;nqN zR&Lgbr&8aPn-L+dQlU!o(!whvTIf3u(+!*i&LgQ+l_=HsHxVy@P(*TpS#dU3B*iLV zP1tarRfT=c!Qxppsjsz>^d@GOVxEwiB&2b`}(8)g|raH?aZkQ6n&`0P>Z=LH@PTZ_6 z=+RsRo;hw{JvAV80|fZZaR&T_xY=BIZ3K09at1fYO}KIAV|8T0JgwkbcqrkZm`9BO z{sjR44~gCyiBKaY>c#$MVQ2$YWTK@${miNI%1A7%U;eZoF!nQbXFqe6`k!jEP<_+S z+^iFt)HgL|39wSs-`s|zzxOw*@D!@W0yHYHbr)VvSNx+|a|T}T8ekTwCu_}e+*j2B zEDSecE{*C)%+f8p1I!`FbJPH{8l!Ul0CN=DKqaHpUjenQi84?nwLL5G3|hcu-7$-d z)R}eWgL%lyBLmz#Lt|T2Z{E=}G4*Uc+7OSYItQB9h!}=5ltJ>M!RDVSC7MZ@J;YpE zj1&VY5jerzi1rv@MBZ#L<0?GVEFwsUGTe;~W{vvcP_ybFMfm;NgTLo0WkZiDCx2IM z4>TOKHPm+QcNJ}EG;bDKa>85>zc`;`VQC8P2;;gwk>yVM=39JK4QkFw77%29{`JK9D zq&Y$SUTqs`HkCaZNrWiw0r3u!oh6(Nnfi?~Uq(ZFMw$JPw|um@RCK7jMw^RqDQq&& z=FJw|Y}CyMc!2G?CUcB2fM8&5@tA`yngp=KQr z2)FNA7+HCMW(;s0!Y>Lwd8l~^^8D|iW|Med4Vz?=igVT^Ot?L2?Ic8MexN>{WS)zs z6Fe|n^vyGiarwE2S+z$!kH9qF2652$bWcB2MU#Oi7-y5sGO<&gGZ{>9kGgrXSyT2w z7`qbSoo}a5U7!csZ-5@>L-pch^9W=rJSGfuDGIL%C?o}Xb}WQdNGca*s$D0ZZBPcW?z zu0^Mr=aYSM^%>^S0!AQNO}yo42dxl1eFnO`N9{kuycCy9&t!<6I@7!u*gxbf^KvTt zyLsk6aJlDPb0sb#noY87pKCU;XDId0X0zUabSgg&EC?d&Jo5<-7q+m^D38O1-@_Py zkW%I6n=8l=y??PeaHyUM@FQ?U2d!1`*j6=h=#k#6z=1)$j*;5G*n|siPb&8(=AeAB zKQ;C`^XCqX@2$6jD)*!+Z!;$eJkGh@BoD$Jx0?$RF|4^5dW@?8Ip z`5IDBf7c|v^`&Dr z+E@sl)`@s^tm;I7+t`$xzB&aFGVdV9s?O*PCUU&msX63QYYjJp6H;tDh9B>+UO`cq zY_G?|7(91=qO>MpOoCT~_?(>NNm31D!t%soOe-6ILEiQQcUy8+WrCvC7hqFd$Xou# zPHVbnE{9ACi=?L`d~1mUVbLrC3fM7=+_KKAgIRx~NWby$wik?XY#-k6NhPLfz|& zUI7c~AvQWVL8e14`tmGF0O24AK%p99`!61=dS~YH^92J}O4b zcS{kcOW=PU)FABhLD;41H+Sm#%}%O6ilYB2ku!ABWxA-@64FIc#lb;?TTWeADo;I* zTm6rU!qFAOCMl+T;P78*Iv1WXHD{oQz;(5vR90E+NLOo1W%aQCxDj<}nRI){myP-# zDU(Ixvap#oT6G3S3oD_T0_cj-8Vc`pkTz;D(DA%m%4L(tQ)9~I1QAphm&;+etSOhn zg{5-)$`ZA^TuzJxVPo)I4XQ&bxfrX$Qi>+@wgdYI)tFY zpXV1V^^9pbtZibatg`~ME{_7e1EhiGsr?o5x+FLTl;S$0#frnGsWZNo7=G#P!^{!R zQp8OT2`DRJVM@lJDctItHv09qcwJ}glL>6(LyQ$y0uZ?pRxzaaC+wXhsM`Rw_G%*n z6lvs=U2ZkkCv{voV7IV68Hwl~4;yuFE7CBh{RJ=S{RPiKHz!>Yf-nJYliA^e0e8Oi z?g!w(bPlf_Pj;sKYCMJ0PZYx0VX15T$cc5}7Kf9TG#ac+5~mrDOKh|;1{Y*&MI%Sx z)>0q$k#Rjj$7K)Bg1&OpaXxCXI3+2DmN<5Lps134h;nWx1rY(0U{E|->2U&1Fp>x~ zNCQXlzSLEpg0gc<+;{qqYp072g+~(&@Bi>j^RD@&K$qWJn&xdPM^Z^$knS?8o37Q zD9X&!#p{~DXY(jL!L`%HHQt+yWx}n^qaaf~z*L%g&G8OIq99gH;1P9swX7~8*E<4N zIQ|{Cgs`CcO|=|&5(zVn)*Qqf_<*4-5Q8yDqmWKktvoV$njit3f z*lOH!hz!Ha$ly5aIDzM4Oh1Wo&=W(PS3&yoZc4_g~ZQTd%%uatXb?N zRrbQTtivQ&rnQNnx-Txrh>&_CF6R{2LYHU_=>Qf)AJecVqUxvwm|j#}n~*0Ik;8$A zE{70mc*{VRA+;+Z2Q~KbL_8ntvK;!1;k8)&+Qtqi3$qgu+^v=;DR?B`EuRLql&@y= zlYRS^dqt#&lzSg;xpl;JXu<&5aPuYB;oLszntt+#WInhQs>t_>XR~61mFA043NbY` ziK;0%VGlGTa1U-423$q+<2AT6HpgMq#jBxq*`&R?`6vxbu-fU5Wy)fwmKH;EKuf5} zY9{SR{{cQ5Q81n{Jx4244Om7*7)!Hrop!wJ7rGbre9wR)Lj0vU4xKq3Ml(1(KwVxV zt82qh#L_1UP>l!4+kw2v?7Y}J*c`_k!kQH=9@3I|RthGDm=2DfKjT7F`mySG0M!80yD28eyKsDk} zxRvRPbTpBTax}4R4~J2pb;=KIGUnRT0R|LYLK&(DAi@)~DxDiF+AI`ts|i(*>nIG3 zG~&s{7^mPA6pBDGjaQ>=$W2C|ezLfPo5Sf(6;cZEJ7~%hm0~7iTLod1lx2hMRb+DW z9UY(dsGx8uY&k^h)M5~_Fb4Aj*o(M*XHj#AJ^^nKbPu-5)jLp8UHl{i36~lRA`dlN zNQ!gObhN9{>_8oj$3ZJagkwlMWC$b*h;U%!z)Zp&qOB&O#|0=<0BauvGy`zhZVhk@ za?_a-H04NKV1#Lq-0&>qx9wRMLJa4^TPVwtWzZ|9CPE0-qB0A-fJ-UU@GRUA^mY=m zKt?Y6EAZn_$6T6@9PE*Pk3r_qCG|Ro!pN#f87Ba8U4Tsh2sd{YpeUP7?T2xf>n7Q{ zquP9OhowLO*_8>7>q66EYPzJWY4Sd1BESeVzyXMv9&=GC%`id}=q@uOED)d_$0lab zA%QWUhd=HXji-@zfJ3*L?g|muh1zNKl0R-HGNC=TpoIBxoQ?xK1C|EZ!7S+HIp8QG z>SV+D?EGu7z*NY2)~7iE1AxecY>Q=d#o{{@Bz|te)%z=E97W;XgLzzp>#dl1h+Obi z;~A$bc&&J*D7;oYBWS_9IoKR8gcdK@qT5<0D5Ev&~F)P3;b1>s_P~-A?*o=;|60p`8 z?ZE_2t)aX7f{A?1+R(B{gc`&Gi+YUa31o?E0#Y86w!C64gGjfDyxv==* zU}LrbACRA?NLMoh)fAyWh4T}|<501x87Q4(Aq^#pIJojiP)sA*D5Kerxio(oibc>n zXo?XKF6FlHn+Rik@uHYgFmsq}p|=)joWzHM3xFTtT`m&`RL8gd3qu-rL#Qp8 z!0|;?YAdSOZ>jlZb^?RYfi)Mm023eqC1{s)OWY7)p@cxu#b~HD^VWc|f$avi=GjcF z*q%C_nQaI-CSrA6v3k*SLhtDARQDPBCnZG6tFIsqC#G2vm5t29rB8y zz%&350s_-*nICqv+=>^II@3-P(U^q6Cl#4|F200vZPh+R_6su~S|j4N+A>5|kB>}+ zP6J()P=p?#Mw;<;1{Q5oi)b1gnvhizIA$MiOQ!vs#{hpj$u5E#$jp;O2ESRlsM} zrwuZcEYfZ-rzT*~{KGs6(R^@=GHx#nI}QDeN{CzpdBN)y@vOyA4I&=m>0DMeA-37+ z1*S+&F9$VQi^+^~s3K^(?DKMbpO-`RfhWM{H4{!R=nm}kB1M9oUUY-;Dk63SNJxFb z3}dGkf!`U#K;XI^C$*7ELT!=#QlK_9%A!g(ae*1z!vPbyH0k*P{;d+Vt5F_}A@YXF zqLL_Df%<+vGy+t%TmWMNG%|mftR>fCW@yN_$U_s(9-7a1P%$(iI2m|oi1H%X&df46 zgJl}D?T~aO8qWn?cm}Bh&n1NCTyif`coqH!p2bn1Jwmhv_(-j{yxng<9c1^S0H$-% z9(X=sx&RCxc?i`7R970+1wN`tld{zXjk5Yw0an1aT#4qW1-&5@tdp8Um8>Zd;^}xA zbOPPWbPhQ{D5wm~H%wA8tX>~3M+39@BV=JQW41HkWA>+@PUt4;kP*<)DTbM95}>w=fPtJ20^nvs?3o*e}|2f@gY%X zHE3)|00V4!B~x=qfx$3BCSwB#Z+}4qy;e(5GC5KXptv>?N#L=VWz@NLIHox_?s-0| z%_C)%lZNOBf+%cEQoARMB6Y!LX(y-WMgk%l3DY4_c{t~YgPha(%P4;lb&&uo&ox8< zMv!CZq)c4elHt ziuiMp0TqzyGE@Y6Jq}VN7eyE<%}?L=Cv6V&RE-IEe}y|d-sp})L&;L0swukwe5;Hq zq7z`1bXa##mpWj$gIMX*Y_&I_srZ9dd;ne7T5%3Jhd*=_wZFlNH+nJBLhCU~XqJLz zHK4aKKA5`%c^tT9_;xel@9scWXLQRLTOMPKEznhGtnph!%haNYmZ?Q^J+&A`i{sP# z5ke2qhJ?h>_;|cenynTc&y|Ma_B0gONij8tNSgXznGHo{78D1gG_=nBN52^wK*7*- z02+d7wH3n|V1`$RqczgRUPq*pIY5obraqU6CX3|n=mJj11mk6#hh|=gITETUI^N0k3yJ0ZeEhXWLz|M zp`wvck+0_vA!1lAO&<8t)5DaZYQRDjFSSTzYzIa7)bxfA@su23jM$PhDuzSS(yue+ zlYq;w0E<4$VE+KBhWqut7fqO-re_dE*Aq1i1~stQf!^T`#%xG%QB(tBijO9@5mf z7{aW9h5=fyoq%NoA;OI_UxsQ*Gv92bH7%M2ST93GSk2@BC$)4OEJa>3$&ATFqt$jt zr?)XQV0+Bc_-LRVqm98Lk{ycO7tBvk`%rguyus_%gFCxs3=A!To0{uoLX+|Xkdogc zLol;r)IH2>?4o1-GRl)0BRv?I@W9AO)P8r1-5X3EAhmjJ(bNQ?TkOuXX#dWC(qi`p z2Wzfd~TP9>n_IqYSJfKR{diK#4B%! zy2GN4DlDe4ACbAj1g03@P6A7h(=#NX+eOcr%F5D}g{Y&l`A2Rdn>{BmtB4tpm>@FQ z4%6fz*J7p*9{{?6dST(!8Gxf09J8N00fa+BF%EKaq2=epMZ}%tZm4k+NI)b>~D`fy?^L`*J*eIZ^h<#XS@g8XGq2Nc*TkH+V)sbDo+5ZSx_wrVAir70(CA zbDkei%wf8D769u5K$vDH&DUaL3?Qurq_7n{;BrX7qn}CO1sB3KTET3K^_Pj%(Gg%r zhtLglim^T@5b2CrauKY?47S{Q!k%7~Gu(Rh?V+-20#7InR=shDO?ZRbh%L){bB#^- zBhiVqh!C#z!9G8A$?=>{u*z8MLN@brUQt z{P!d|EkDRR2;ioxg$hiY3DmcfWFpzvWc<{HPLCygeFi9&6Pdn3lc zj!U;3)_)A{zy@FwW*o{4BkIP&YNAA~o-9Wvd3HQQz8FFcbp8I?f~u$qV1mKwfQN}K zsQzR@!7aTQ!$;oNFf1tY(vtz@0HF)u+i|?te*J2M4JdNJ^hKo=+JLHnPZW8`fU0m& zRoZ~cflrD9G_d~zR^iEq!Fa*GO4{KhabZ__MaF{K34*u`Cc`PoGR=}VJ|Z8uClzk=J`ZdyCnH3EQ*IK zA$sEngyOn~=vz#VvHA|jB5}-yg>^%>jDgTwtm*>)khJ598PZPN{tzTf2pw%~mar#b z&*iG~4##w^Rm%>S{fZ;xqvDl&y$q(wvEy(=?nG2*ihOMv@8>effWp9JdX8%L{X1$^tVh;PoTuOvIM-pDNc@QCtC*RUuC~S_AiNQgg*vmi%n0 z94Ks6HBDCM=VTT*Q3Q)BL3PwL=?)KdmD$cqE$QV~9J++(P*$nUc!p)bC7Cks(cnUXm4ExRT{ zMhDo%8mw2+VNQTAeFy{+=tLpZo~djNbBpv+IdG0=F|w<6s%;GxdRH4RqILL;Ef3q} z0zfmY+ze*05TqVELgGv;pNazB9dJ$AsZWlOQVc}c70FG24G7?$!chjkXG1T93h%!3 z!e`}?^6n(Uj{fI$&X5Jkki8f8px72?VS zKdOdVa0TvBN6eDbC>+Y$$I(W5CbYwaj&AC&6j4M?HL!yonFz;jnH(FI`s_#YG=w~=W6$I!C!8g(#M6^! zN!kK9iCVnr|qy43bb8v5rg`Ri{zgOJI$BKrAYnfC2|ffGk*f_-yU`6PvlQ< zDY;a>hAf|4iV@qZ?8_vD-!@z(E6cEFl8%oc7d)L$fWV6d%^U`N#$|FX&eVmmZNddi zfx%Um%PA;!*5&drT-IDJ6Fy3E5UWe00IuQYA>&(@%d3EaGkz+uv1xDWCrc#G+uEas zB<0lPbF+=gq)DeFWNj1}iRvbEEff@v#1Ou#`6R?N zLFmun14*ztwiy{H6dDZ1AgOjAEfHYuwbRw`DiIDc+IWy&Qmcm7j%cY@SUR+-oEBL< z56S6c*x*$&DbE^{XCS$oNi4O4<8;!Ib{xBq2h&L}G3yFDxk3X_LlrT!!!+XNQTzh3 zA}V)E4i>c$ll8`OS*9Lrk;NzHap(fp8nJ|7AlFus(fgz)5h4&BZG4VY3iTpyCGPM= z0}7u+^=l<#2Q~@qhc@GRymUy975Wt27FBtryg)cg+$Kwd4sStFMx$;r@%OLXh49>?a_^MGh|Q@OBS=^WHDi^!nYCLk z24}54iZ4wjErU%N$Jgn35wS$6~ zplZv-&@(Vq5T!z41{RWRBtebF)!D1=S|*2102eJr5+c<2Wdy&82u6S?pL(Atz&lCr zJjBA2$Y9)J@yi6C2w#VQCSVma9Nk8ygsHQ!Bq``BLI#DYHRT>Oh;tp%*^1m^j3`K) z^bS_3F}!J28|z#+2_c;oUL0Bg--k7~dJ`SP0ynfOeO7sTftyGcYs`Qg*<436|6-MU zy&Q1(W}?pQkz5P%=m4ULJlatY^&Z@oiO~%<0JC~omJLJ{HoSIq>GcqK+ttI@!zLj{ zNM(0Hj>aYCI086nB2z>V>?U1;sH=`SX&pGH^CpcsksLDlEayE_vz$&uY{&2=B-GZ- zi~{PGX0LD1LTvzlXb%h+afGz&KG67_ZV&^oOVGMIZNy+ZfFm>YyzYQH0~V1v=2f!@fn!$H zt{Y^03b+GpxY$YH03QdDbvt_zb#M7T8^|Vg!g62SZAlZ|cZs_#2N!o#DIxv)#NChs zB;A((J4tue3i)G5C|}ZTfuih7x|$o)l8)XVe$&B)-0yEf1TG7?R(4p@-PFpG z?)la(Nk=GCeOC66bXDrsl`^+?arZ8Bm|n#li#dop7IP4HB<4u`ZNc^55qCM=#oeHT zio0#TxZ9o)cj}m%Wl547{{LCL{YTPm3`sYdS6R}nEDNq~;!PcWvn;8AxLc zq}diovk#eoh$avRVmLbq=nV8E%;0i|6ch;Y;+#9wj8*b*&~xi5>5>eKjuX%MGK{Xi z^deD}mR=q{#F5Cui}8rULU1^);AJ1Jl6B{^C6EWPsIx$@BTEFoT9U!L=u0x%6o_{j zZ2@>?L5A=&h%O4MPL%rURUWR0!lbQ!^e(CuFPv4Er&@k4i>I}K*+SlgxISu^lp_EF z;}lX#iw*5ZJDAu5D43@^el9DfX=f4w%1FZLvMk_&-WCYB?~-rO-5}qPt4qEed&_?y z-}K-@zCG8Ae0$;+IWmc0Kj$MJw82_5)nSj5^NyvB8f^jmr-JVvL?3Cvre1fN={ zqA+3 z#nN=sNOh=M7J2HM)$)j$VA}hnX4+6rLOtv@3-o$WyDiIR<6yWJwenVZSP9~X;<@;r zLj~Ok1){^XoBHThSta@djzkgWh3*IW4(W~*8SP#uqGvVac6lzQzq(yk#V8Dk0=Ow^ zT5Y;rV#^{~amPyd8|u_ct+GVhaCFMXVRs_DWsmX=xV!I^gVp^jWe#*uZMf}XN`)k2 z(+P$f7!Qpw47W#p$+ecQAeaaJ=QX%`@FQm%Ze#`ZG~9ySBpDYl(sr9V`C=Kv+5U)K z0-t*{Bf=2GMvMc>ENi`Cc#lWpD>eW?ZvcV~h9FBa*eIO%-!j-pqH)-ww$~u8*jtbK z)H`>94)ff;zgrk$YL zuuDvzN6OoUXT-F1gU`41;NqoRod6oT{A?2ziwdtrm1<(-(!g(JwoX@By znJ$rF1f|s(J4K>U3&xMt*X{C}3bxm1UjT+M>Xnf=1BH~4#Jl|-S$8S~O&*eBoFyN# zjk4t6H&H@Dh`eSvm>7lgfeyS&j2jBKMI;$qut-eD@=^?8q8y2^4if26GTbVd-0Hz!$jWm&fxG}J*LEO<)9M)k z!t{L+5x3k=&C$_)nF1$%4!Ud(4y|lFqUq_Yyr3 zogfh`cmdf2_Ks2<3}cVh6+f(N?aj{AkE4!h?_CXj0_T`j$) z>Ci6R0Dbp12J@PN^ZoarGq`a%f}L;aGb}~Og7rzTStc+}r#+Ea(7_igDI&xI zm<_ZL@yL42sXgk0^=tsUkFl$F%470Gxcl#XOr~tnnL55hJ`_eK^Eo+ufOcxV3vh*} zk5t4$6$SPOK-vJh6Q>9c0MK)ullbhz9u<92{?}k#2y0$&K|)jla9Xv3GoMziu+~PU zW3&&NPIkQOMR_h3lvL}6`*ND1>geBoZ_8Y@Ur|h6)N3^?TUNU>}{E{ zO92)>e52dsoz&^FExL4omb@#dd-{-m7h6v{i||bSbU;B zdlO4ZThy?(V8*?Yy7(>mnPt2ZQSQB>#CSELCao6r;#Kv~`_TJdN&WMEtT$n}Pu(e( z(rU{)f0yUua?D5aWLzHnh!<^keI#e&Y0^LBZ!+IYq@^i*FR`yG{TS{KoMry8!~rX* zvp>d?Hy$6}C;O$geu8rikofth@&wNc1u51b~d?N+5^47O|-tYeCQ&Nw}OAwpJSW!VHle{A@n?;B#=Gw@;#073GQLS{rew znR>q1q6N&~msnTfa!9E~hajd(En2|bQEH9nqg*PiK3EeOT|up>A5~a=aamGfonJsa z-+;DJpw}|X(7-np)+4k*%@{~2edaeLTTMx0ysq4gkYBb-* zLGm=!)VGINKL8}hjk~{y={s&RG-7G2An7~^Kh#iolTuH)mmZEhcs!q+<<-q z^@-FRno{cHcjQH>D`r~P%Gd)%!lu(?8sTMEi~8H6Qd5qxF0s{(=U8F2?L^D-h}?r&{lb)a5_2n#-K`BQ9hS4(q3%nDcIG z&m~qL1Ik9hW!4qAth~&6F8+@Q1r^zp69X)rzemXA>w5ku_0!9(>xFnz1(#T(#an9P z66;0LsdBEcHi);?b5~dsaS11_L%>uIOIp`a))!i=S>nS~<(1anAc_=RXPtq!7hPw4 zU^?&gglhf@Ye<2y`U#ah!mLWIzuTH!g~PN$8?7O^+dDQf2Qnc0yv^#cjn;YL)ktF= znR;TQb&OS;dSVkk{OxtV-4XEcVGR#r+92w(dVoYbewc*;&WE9Q0KXJBz5xh){#NcqJH^jE0NQ>2^A3O0<=5SHY6Dj zZc?Xzf!rOb+*hp64V=6c6Ly8_`*_b!G_nYO56Ck zp@#j-Dp8$(vE)FP4l&}Bj4;ud9-(y}NRNm~QKvs=Rip;KVU-FM+-T*g3Sq~RU$02x zd@uql9#22iG<(Z{C}J}_8v8b+ABwOIKm9;QE7gIL0{B=QMVrtaZG1&oAMT29M|SlF zt`$q7NQ)s21d6*cxEt?6tXPHN^{5aTfkNjk>z!(&{Ry?`QL8W&+;2%E1MDwoVFep| zKQz_!N36}MR>MBUt=>w=B}%9V$oJ#ElM+ZM*8$Q^sYpNjBqREEA0szuXTDr}1y0Vn z=S92dmRdV6$sd$shDw?k0%c^3w}2qhi?-nO{H`r$;3)8PhO4MQd}cSR02CpeR>U$j za@cpezzF2mF)%;~ZPo2jK(*J}$Cu+o4V;xm5PVCF1G<8*ceE}1@c=byfE_1a9dckh z7abH&Axt_ye_WRv)8E#mGs&4ZjMPSFBUudC2VrPy6yHCD3QamJf(WpzslTpE3UeCZ zd#HNdSo-6-)Ywdc;ij+ejlxjkXS?99EO4whDo4+7D2<_;?i9W!m}1+}_(5@qYk?hcijF>m?1z1|Jf&d%i3_oxA&g(M|;I@Gb{#2mIj)-Hy6xfhajt zH*hT(>$1zedwoFY&=pjB_5Ah^TJY$$bOdPs3$S!u;F=SaEi|tUggE0BF!VKpx z!}9k6G~s|$H&XMkAYms^{ILI_Qyz3!4{1jTf25Va_moK?lNW|#R~{Pq?Jyk4Ag23C zh$qJl-Oge@3To8`e2Nj8srW$J+bIDrWrapBru-3JR~rI5YQkd5<2LkCD?#N zA4kUTnyz>e+TDyWNn~h;;Y%b7@}bj|GLV9V6S>$-;q62>^U}#wg3Mq-Iej(((}~VW z13E^*^+>ypy$dAccS{0iUCO zVkmSsM^ZQI%`r3xbw;E1=rSdyKaWdepkKzL2%!Q#=)0}#Jl)6a8*OJ%5D1tlNK=>o zP;L^KLss5*o(76=j}(BP0USh!6m&6@(#lBd<^g3*TPW+DG% zSW98x-OHtqvm#Ph2jzxvX0Cli5~DplgZ_^{D`RwAEeT*TvojaDVcc^ z@aVWH!k&+7uFvHIr|-T`rUYbeBIXO19#D#gx~PCt+OtwR)WgH<%H(=)9fbPEU{OPiaz-G)qD=`IRpKe?N8fH0_ytNb3S+k#+IF`T9{8DD z?n5g)bNrcHs79K6&Yb)?rX+vL#_(K(~$09y2F}645@Z4x66WXBI5fmXRFso*vF?PjH^LiL!w|JxxpoqYP+v9>}xM~<@xT76!@$sGWbEfpQt zPP^cE*j`bslk5ryIY>XpAk(=L&MWEoJrYPft zzhD0fj`p?7)Ns!(h0p6q&u$hK-<`StxbJS4pddX|!`~C|p@-R(2X^O&NKK;wX9v>6 zr|^E#z0znn%&rixs0VNvg!TzvSn$YXgae@W_I4d+Zxk=6hYz>^hL3{YFvXsI%!^^F zmyHoFgJg_8jB(5|;HtAW$(+590! z?PKLxrH=lSRpfB|K}d<{yCLxzfJYNUb@_{%Z+-25ArG}>J2%_t60<< zdXQJqsMnDF3LMdEjGM>w+SPE>8CE11q+EhS|74-*#iDhph29dA_cbOZ+EjXuaLGwL-Rc}~EOg(k7 zeU92N2OmhAa*AyU@mDot4r=>r>WMiJfcR+aTc_GLh}Tmn_q@ROWT_FgY_6S)dsKZ> zs`hky9(@1mrZeq#!*7HW1|p?Bsb0R+Mg-_t_8d59_nu|H<-8fD6DF}Sn$|$*bGYxH zZ6A)81JALsNRWEy9DAb)Pw#?e`}&HvVWfbiC15Q=H$t!n{S+mrlr!I602lC*`Sw>R zb?E~8zYOtr_4fJp1m`0pZ!iYF}ixiBHw*%3hV)dZE2SXBRR;i)?o+n0&R zr#^Jfr^>z99xwi>PQBRvbi{5XBPRjicm;Ik5WM(QmTIYSYN6r^#zI!Ica8gRoH2OLqNxv*8Kx2Lq>A^kULcQskM4K49*MVn7 z0k2s*pJudG6t1 zdGD`Sl=uFMMS1V9v?%ZW9gFhbU$H3f{S}My-e0jO&w8arxj4PouCgf4%AAED7UjLZ zLMDtBkQUHhP-dp!73y+mQCPjZ+#YvS50o;~?zJ)~kYL)qze*44=jw+)wXZFwg-3RZ z)F4DG`ll*GCS}IQKe27zg=dt*0im_qZ>UB@0fLc`dbn0Svc!Hh$+~0Of1b(9zUODS zq;{aAl`Xy}gQ7p6U6PxSBI-aw@UlJ18^&<305*_8Lm{&idI_A;fgPmQpi>|oH6Jz#@tT_2Lrg$i=5 zQ{`J=Z816-ZwKp~7eoc@T<gNq6dDTMGxM`NTWkOVUHh(I-(8jn%}_fgX)+j zG9z>yK}z0Otm*p{l7Snp5Ue8jy&BVlU@~yhyo0Y0z0V|(yCu^RLUAv{OmL6VVE0a6 zP?*`C#9Ce&^mYL-$2T{K0L_3b1T+3KeZtyMSC_cEz2mwY&_t&@2^rc~)D7>wb|4$s z#oD>ggc{_Uj~u})G_UQijk#icoe~-KE2BBn}kjR;SEO&&K82GptVNq z>Er^m#zjs6RDiE^(A20mojBsD(lGjNH};m(D0Fwj>OR9`LtY-rL*>_|r#6^L5cWn= z0w9CJSrMK)2{mZn%`*6I@MU5g)x-g7?1#94y1`%ECSJh4;jD!S!WwfG_9MexiYI>^ z!nHXJO^+AO!_hu3L}|j?2g1QDN<&CKBUBA?%%lJkq;z(rP%k#47l?bK?&zf|toIRr zGCM%-blqvtbO0_1Py~hW=5u@$m~gk6VFPy1LnC(*ImYKEOx^jmVV4#62R8)p*$#Y7 zSzl*4`JZWwcO3UY#cL=XzrP3X3ZTG1dkr4kRx5iBs6 z*mXAT#?Ek_EY{wWv*%!X@i?Mcjkx{7`C6nI0xf_6)6O34W6{Aj1bwRj!RN-wapZ=Y z)R8~4YmTF+M;FiGCQJbia%8qlV3NotUn+2|;pPN(e}mLBIkcxAaQoej<*48NS=1_L z8KU!c8EtPbDJ-Pff-(RWLYLW5t2%#~-EaIeoJb-87{^5KAk5=v5cr3U>`4QcYi9Q< zg* zJWVeUfKbX%iMr=0yAu4Z3CazsU>|!&W)6{ViCjQedZ>M1*;7k?dF^fIY6_L}G_2?i zZ4b26#8F4ONbhyD?P@7H(9h2E9w2HzJ8sf`_BP@%yI_&sV3&{inkgpZXkW&>19MwD z+G+R>?rHxc!lS|~>?1`4!`sdOSb@ocQRKSUqB1<%AfrxL-Us+3-!ovskf)cdK9Drq zE%eMWW!j1%e6rfaR*tXzQXU;+#!CA^^Ki^rx*leXWGJCV3O zsYr-QKDi5Us8U|rg(Dg+RRkCA@hTEA#=noBEYn;lc$P-<_A>Mr^>AW2&4gG`PN~X0 zR=FbpT)E4NavCRu^Q z)eiVYADYia^IayB=DSQL&3Bnhn(s12(0rH8r1>tBN%LJMljgfjCe2qShvo;+=(reM z&L+)wnM|4=X+lXr0ML2WyBbyl!z~OUu>9>_jQ}*=hc%M!D}|BKr2E>}r2AT7(tWKk z>AqH&bYCkX=)TsNbYCk>x~~-`-Pa0}?kk0{(AjANkQ@vbRr?}wQ79e8Me6BXKZ}EC=m+w@z(s@k zgmIDfaf*n*MV@LOXK$w4Z-B>jUUbCA#hYo22l9)}R2Gj5HpYNOP%Bt8_HPSCndi5l z_hzs?3)7;(e8RM7FrNWh6lysY3K_yb)w6Wd4$z{I!vHM`rNgx7PnGb&t#mIRK88rr z8a{oD)RekO$7#aI>s{P9&xqsKb6xY?<1`h)H*X#%5hL2U@Fb}zd-LkROuFTsI_mI> zdimig!c4afJoh`=p^L%7ewZFnO&p@8`2feECfbJS3`?8nBEpU~eDC;S0YDnydR@6%{wjh(J+|t3a61!6W@I{ zjD(6r&(>C|QDaL1>(z)?d|<>Yf89#+MXQ{Aj$(weVt$8#@vuCjjh+&%yrGR!J?DIz z)^1Pc?lwehxr>nt&r^axbXWET`W)d)$rlm8bxEdPq=!X(XaFtFx~e+a>%YX?FVTLb zR?#H`YPs|>trp_4Y-y(!fzh!wom4AC8*>-pr@CeAj}#E1L%#eIH4D)xAN_?=Rlw=S zZa}pw{8cwSOW)w9;O~?ZdypeR4_*g`3yo(0DZIiT|4MH;PMp$9yHR>$FTE{}ae5!k z8(-(sU|hAqGirft&up4*B_(6dUo@D%oooAmX6o73Pd9N|AK9GJkC51Q-q?>;tmAY2 zln1fsD!5*UTy>S6@Q5yX@EWxX$UVO+;`Z}rNA0XwaY)|dwHLkMX%k$OZYS~HbbBga zP#=>5_O$pcVOdXGmKE!4*}NiP-}=~6fyJ6Jwl;2hW-uowJ3lQyxIDNl_{tjVRb&|E zI4{HZ{FQ;+yg+7tb}%;S~c!9o|b9f_IN%_!PU7-UP{YYGv`6S<$>D?ROf?i zh8zOfwAinkZC`3A-RtOAA#b>a3WR(w)9#r#c{z-0u|2mi Self::Target { + fn build(self, authority: &AccountId) -> Self::Target { Self::Target { id: self.id, accounts: AccountsMap::default(), @@ -24,6 +24,7 @@ impl Registrable for iroha_data_model::domain::NewDomain { asset_total_quantities: AssetTotalQuantityMap::default(), metadata: self.metadata, logo: self.logo, + owned_by: authority.clone(), } } } diff --git a/data_model/src/domain.rs b/data_model/src/domain.rs index 19e078c6847..72214b21f4f 100644 --- a/data_model/src/domain.rs +++ b/data_model/src/domain.rs @@ -85,6 +85,9 @@ pub mod model { pub logo: Option, /// [`Metadata`] of this `Domain` as a key-value store. pub metadata: Metadata, + /// The account that owns this domain. Usually the [`Account`] that registered it. + #[getset(get = "pub")] + pub owned_by: AccountId, } /// Builder which can be submitted in a transaction to create a new [`Domain`] diff --git a/data_model/src/events/data/filters.rs b/data_model/src/events/data/filters.rs index b9d1cb52c44..30d4029e018 100644 --- a/data_model/src/events/data/filters.rs +++ b/data_model/src/events/data/filters.rs @@ -220,6 +220,7 @@ mod tests { let domain_name = "wonderland".parse().expect("Valid"); let account_name = "alice".parse().expect("Valid"); let asset_name = "rose".parse().expect("Valid"); + let domain_owner_id = "genesis@genesis".parse().expect("Valid"); let domain_id = DomainId::new(domain_name); let domain = Domain { @@ -229,6 +230,7 @@ mod tests { asset_total_quantities: AssetTotalQuantityMap::default(), logo: None, metadata: Metadata::default(), + owned_by: domain_owner_id, }; let account_id = AccountId::new(account_name, domain_id.clone()); let account = Account { diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index b149209bcd6..6bd01d92386 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -976,6 +976,10 @@ { "name": "metadata", "type": "Metadata" + }, + { + "name": "owned_by", + "type": "AccountId" } ] }, From 4cd1824d499a7b29cecb1cfe4bb8e62d29166fe7 Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Wed, 4 Oct 2023 16:50:10 +0300 Subject: [PATCH 45/55] [feature] #3953: `Domain` owner permissions Signed-off-by: Shanin Roman --- client/tests/integration/domain_owner.rs | 273 ++++++++++++++++++ client/tests/integration/mod.rs | 1 + configs/peer/validator.wasm | Bin 494641 -> 496544 bytes .../validator/derive/src/conversion.rs | 13 + smart_contract/validator/derive/src/lib.rs | 12 + smart_contract/validator/src/default.rs | 137 +++++---- smart_contract/validator/src/permission.rs | 119 +++++++- 7 files changed, 492 insertions(+), 63 deletions(-) create mode 100644 client/tests/integration/domain_owner.rs diff --git a/client/tests/integration/domain_owner.rs b/client/tests/integration/domain_owner.rs new file mode 100644 index 00000000000..a7badedd658 --- /dev/null +++ b/client/tests/integration/domain_owner.rs @@ -0,0 +1,273 @@ +#![allow(clippy::restriction)] + +use eyre::Result; +use iroha_crypto::KeyPair; +use iroha_data_model::{account::SignatureCheckCondition, prelude::*}; +use serde_json::json; +use test_network::*; + +#[test] +fn domain_owner_domain_permissions() -> Result<()> { + let (_rt, _peer, test_client) = ::new().with_port(11_080).start_with_runtime(); + wait_for_genesis_committed(&[test_client.clone()], 0); + + let kingdom_id: DomainId = "kingdom".parse()?; + + // "alice@wonderland" is owner of "kingdom" domain + let kingdom = Domain::new(kingdom_id.clone()); + test_client.submit_blocking(RegisterExpr::new(kingdom))?; + + // check that "alice@wonderland" as owner of domain can edit metadata in her domain + let key: Name = "key".parse()?; + let value: Name = "value".parse()?; + test_client.submit_blocking(SetKeyValueExpr::new(kingdom_id.clone(), key.clone(), value))?; + test_client.submit_blocking(RemoveKeyValueExpr::new(kingdom_id.clone(), key))?; + + // check that "alice@wonderland" as owner of domain can grant and revoke domain related permission tokens + let bob_id: AccountId = "bob@wonderland".parse()?; + let token = PermissionToken::new( + "CanUnregisterDomain".parse().unwrap(), + &json!({ "domain_id": kingdom_id }), + ); + test_client.submit_blocking(GrantExpr::new(token.clone(), bob_id.clone()))?; + test_client.submit_blocking(RevokeExpr::new(token, bob_id))?; + + // check that "alice@wonderland" as owner of domain can unregister her domain + test_client.submit_blocking(UnregisterExpr::new(kingdom_id))?; + + Ok(()) +} + +#[test] +fn domain_owner_account_permissions() -> Result<()> { + let (_rt, _peer, test_client) = ::new().with_port(11_075).start_with_runtime(); + wait_for_genesis_committed(&[test_client.clone()], 0); + + let kingdom_id: DomainId = "kingdom".parse()?; + let mad_hatter_id: AccountId = "mad_hatter@kingdom".parse()?; + + // "alice@wonderland" is owner of "kingdom" domain + let kingdom = Domain::new(kingdom_id); + test_client.submit_blocking(RegisterExpr::new(kingdom))?; + + let mad_hatter_keypair = KeyPair::generate()?; + let mad_hatter = Account::new( + mad_hatter_id.clone(), + [mad_hatter_keypair.public_key().clone()], + ); + test_client.submit_blocking(RegisterExpr::new(mad_hatter))?; + + // check that "alice@wonderland" as owner of domain can burn and mint public keys for accounts in her domain + let mad_hatter_new_keypair = KeyPair::generate()?; + test_client.submit_blocking(MintExpr::new( + mad_hatter_new_keypair.public_key().clone(), + mad_hatter_id.clone(), + ))?; + test_client.submit_blocking(BurnExpr::new( + mad_hatter_new_keypair.public_key().clone(), + mad_hatter_id.clone(), + ))?; + + // check that "alice@wonderland" as owner of domain can change signature check condition for accounts in her domain + test_client.submit_blocking(MintExpr::new( + SignatureCheckCondition::AnyAccountSignatureOr(Vec::new().into()), + mad_hatter_id.clone(), + ))?; + + // check that "alice@wonderland" as owner of domain can edit metadata of account in her domain + let key: Name = "key".parse()?; + let value: Name = "value".parse()?; + test_client.submit_blocking(SetKeyValueExpr::new( + mad_hatter_id.clone(), + key.clone(), + value, + ))?; + test_client.submit_blocking(RemoveKeyValueExpr::new(mad_hatter_id.clone(), key))?; + + // check that "alice@wonderland" as owner of domain can grant and revoke account related permission tokens in her domain + let bob_id: AccountId = "bob@wonderland".parse()?; + let token = PermissionToken::new( + "CanUnregisterAccount".parse().unwrap(), + &json!({ "account_id": mad_hatter_id }), + ); + test_client.submit_blocking(GrantExpr::new(token.clone(), bob_id.clone()))?; + test_client.submit_blocking(RevokeExpr::new(token, bob_id))?; + + // check that "alice@wonderland" as owner of domain can unregister accounts in her domain + test_client.submit_blocking(UnregisterExpr::new(mad_hatter_id))?; + + Ok(()) +} + +#[test] +fn domain_owner_asset_definition_permissions() -> Result<()> { + let (_rt, _peer, test_client) = ::new().with_port(11_085).start_with_runtime(); + wait_for_genesis_committed(&[test_client.clone()], 0); + + let kingdom_id: DomainId = "kingdom".parse()?; + let bob_id: AccountId = "bob@kingdom".parse()?; + let rabbit_id: AccountId = "rabbit@kingdom".parse()?; + let coin_id: AssetDefinitionId = "coin#kingdom".parse()?; + + // "alice@wonderland" is owner of "kingdom" domain + let kingdom = Domain::new(kingdom_id); + test_client.submit_blocking(RegisterExpr::new(kingdom))?; + + let bob_keypair = KeyPair::generate()?; + let bob = Account::new(bob_id.clone(), [bob_keypair.public_key().clone()]); + test_client.submit_blocking(RegisterExpr::new(bob))?; + + let rabbit = Account::new(rabbit_id.clone(), []); + test_client.submit_blocking(RegisterExpr::new(rabbit))?; + + // register asset definitions by "bob@kingdom" so he is owner of it + let coin = AssetDefinition::quantity(coin_id.clone()); + let transaction = TransactionBuilder::new(bob_id.clone()) + .with_instructions([RegisterExpr::new(coin)]) + .sign(bob_keypair)?; + test_client.submit_transaction_blocking(&transaction)?; + + // check that "alice@wonderland" as owner of domain can transfer asset definitions in her domain + test_client.submit_blocking(TransferExpr::new(bob_id, coin_id.clone(), rabbit_id))?; + + // check that "alice@wonderland" as owner of domain can edit metadata of asset definition in her domain + let key: Name = "key".parse()?; + let value: Name = "value".parse()?; + test_client.submit_blocking(SetKeyValueExpr::new(coin_id.clone(), key.clone(), value))?; + test_client.submit_blocking(RemoveKeyValueExpr::new(coin_id.clone(), key))?; + + // check that "alice@wonderland" as owner of domain can grant and revoke asset definition related permission tokens in her domain + let bob_id: AccountId = "bob@wonderland".parse()?; + let token = PermissionToken::new( + "CanUnregisterAssetDefinition".parse().unwrap(), + &json!({ "asset_definition_id": coin_id }), + ); + test_client.submit_blocking(GrantExpr::new(token.clone(), bob_id.clone()))?; + test_client.submit_blocking(RevokeExpr::new(token, bob_id))?; + + // check that "alice@wonderland" as owner of domain can unregister asset definitions in her domain + test_client.submit_blocking(UnregisterExpr::new(coin_id))?; + + Ok(()) +} + +#[test] +fn domain_owner_asset_permissions() -> Result<()> { + let (_rt, _peer, test_client) = ::new().with_port(11_090).start_with_runtime(); + wait_for_genesis_committed(&[test_client.clone()], 0); + + let alice_id: AccountId = "alice@wonderland".parse()?; + let kingdom_id: DomainId = "kingdom".parse()?; + let bob_id: AccountId = "bob@kingdom".parse()?; + let coin_id: AssetDefinitionId = "coin#kingdom".parse()?; + let store_id: AssetDefinitionId = "store#kingdom".parse()?; + + // "alice@wonderland" is owner of "kingdom" domain + let kingdom = Domain::new(kingdom_id); + test_client.submit_blocking(RegisterExpr::new(kingdom))?; + + let bob_keypair = KeyPair::generate()?; + let bob = Account::new(bob_id.clone(), [bob_keypair.public_key().clone()]); + test_client.submit_blocking(RegisterExpr::new(bob))?; + + // register asset definitions by "bob@kingdom" so he is owner of it + let coin = AssetDefinition::quantity(coin_id.clone()); + let store = AssetDefinition::store(store_id.clone()); + let transaction = TransactionBuilder::new(bob_id.clone()) + .with_instructions([RegisterExpr::new(coin), RegisterExpr::new(store)]) + .sign(bob_keypair)?; + test_client.submit_transaction_blocking(&transaction)?; + + // check that "alice@wonderland" as owner of domain can register and unregister assets in her domain + let bob_coin_id = AssetId::new(coin_id, bob_id.clone()); + let bob_coin = Asset::new(bob_coin_id.clone(), 30u32); + test_client.submit_blocking(RegisterExpr::new(bob_coin))?; + test_client.submit_blocking(UnregisterExpr::new(bob_coin_id.clone()))?; + + // check that "alice@wonderland" as owner of domain can burn, mint and transfer assets in her domain + test_client.submit_blocking(MintExpr::new(10u32.to_value(), bob_coin_id.clone()))?; + test_client.submit_blocking(BurnExpr::new(5u32.to_value(), bob_coin_id.clone()))?; + test_client.submit_blocking(TransferExpr::new(bob_coin_id, 5u32.to_value(), alice_id))?; + + // check that "alice@wonderland" as owner of domain can edit metadata of store asset in her domain + let key: Name = "key".parse()?; + let value: Name = "value".parse()?; + let bob_store_id = AssetId::new(store_id, bob_id); + test_client.submit_blocking(SetKeyValueExpr::new( + bob_store_id.clone(), + key.clone(), + value, + ))?; + test_client.submit_blocking(RemoveKeyValueExpr::new(bob_store_id.clone(), key))?; + + // check that "alice@wonderland" as owner of domain can grant and revoke asset related permission tokens in her domain + let bob_id: AccountId = "bob@wonderland".parse()?; + let token = PermissionToken::new( + "CanUnregisterUserAsset".parse().unwrap(), + &json!({ "asset_id": bob_store_id }), + ); + test_client.submit_blocking(GrantExpr::new(token.clone(), bob_id.clone()))?; + test_client.submit_blocking(RevokeExpr::new(token, bob_id))?; + + Ok(()) +} + +#[test] +fn domain_owner_trigger_permissions() -> Result<()> { + let (_rt, _peer, test_client) = ::new().with_port(11_095).start_with_runtime(); + wait_for_genesis_committed(&[test_client.clone()], 0); + + let alice_id: AccountId = "alice@wonderland".parse()?; + let kingdom_id: DomainId = "kingdom".parse()?; + let bob_id: AccountId = "bob@kingdom".parse()?; + + // "alice@wonderland" is owner of "kingdom" domain + let kingdom = Domain::new(kingdom_id); + test_client.submit_blocking(RegisterExpr::new(kingdom))?; + + let bob_keypair = KeyPair::generate()?; + let bob = Account::new(bob_id.clone(), [bob_keypair.public_key().clone()]); + test_client.submit_blocking(RegisterExpr::new(bob))?; + + let asset_definition_id = "rose#wonderland".parse()?; + let asset_id = AssetId::new(asset_definition_id, alice_id.clone()); + let trigger_id: TriggerId = "trigger$kingdom".parse()?; + + let trigger_instructions = vec![MintExpr::new(1_u32, asset_id)]; + let register_trigger = RegisterExpr::new(Trigger::new( + trigger_id.clone(), + Action::new( + trigger_instructions, + Repeats::from(2_u32), + bob_id, + // FIXME: due to restriction in `ExecuteTriggerEventFilter` it's impossible to execute trigger on behalf of multiple users + TriggeringFilterBox::ExecuteTrigger(ExecuteTriggerEventFilter::new( + trigger_id.clone(), + alice_id, + )), + ), + )); + test_client.submit_blocking(register_trigger)?; + + // check that "alice@wonderland" as owner of domain can edit repetitions of triggers in her domain + test_client.submit_blocking(MintExpr::new(1_u32, trigger_id.clone()))?; + test_client.submit_blocking(BurnExpr::new(1_u32, trigger_id.clone()))?; + + // check that "alice@wonderland" as owner of domain can call triggers in her domain + let execute_trigger = ExecuteTriggerExpr::new(trigger_id.clone()); + let _result = test_client.submit_blocking(execute_trigger)?; + + // check that "alice@wonderland" as owner of domain can grant and revoke trigger related permission tokens in her domain + let bob_id: AccountId = "bob@wonderland".parse()?; + let token = PermissionToken::new( + "CanUnregisterUserTrigger".parse().unwrap(), + &json!({ "trigger_id": trigger_id }), + ); + test_client.submit_blocking(GrantExpr::new(token.clone(), bob_id.clone()))?; + test_client.submit_blocking(RevokeExpr::new(token, bob_id))?; + + // check that "alice@wonderland" as owner of domain can unregister triggers in her domain + test_client.submit_blocking(UnregisterExpr::new(trigger_id))?; + + Ok(()) +} diff --git a/client/tests/integration/mod.rs b/client/tests/integration/mod.rs index c1dc262a0de..5bb44460bb0 100644 --- a/client/tests/integration/mod.rs +++ b/client/tests/integration/mod.rs @@ -10,6 +10,7 @@ mod asset_propagation; mod burn_public_keys; mod config; mod connected_peers; +mod domain_owner; mod events; mod multiple_blocks_created; mod multisignature_account; diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index 3f5e655c055c17beefb92f06db4fe9db350e2a89..66cb85821a81032b3a5c59d6454bea056e7c3538 100644 GIT binary patch delta 92929 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%0DXGUD=E&By$ESv-^?c8CB&a`5=*_6I4jM&_4Vdm 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�%0`7bFpyrI#+WisL1;DuHIO5tv9&(Aeg%W^kxkm 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 Cw+Oue delta 89073 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�q=;+7Y=>BIL-d-qaB`9&s~@^eg&oMp%a9pS|aELJ#{6}HuJCRSic7^=W3 zdrp??0`Y*JH83urUzesKCPuR3gB3Q4CVc3s?^-gsU{*Ypx>bLH&ej-s9|pMs6$KuM z35|j)e;MVFTtQgM3W{4(cy%-o z#p-P*l^vP~KH;=K@Co%t;1jO;1D^@OPxe{vj69ULflp{=@regHWtc3?P{0O~MZGFO z+36||AG?UW2xOVA^0{QXY#lO9v=m2Cg4HAne3%5*z z&B(*fu4-HkO#-^O5X=z;Ur5PAG}x%I-fuyg{7w0Z_E9w99aEQ@ zhpU^j3S|8>bU}{j5W_Mx3Vy*W2*-FGVu0wf*SC_4@;Fpt%(rY9Y ztJd%7fX$TDxR!hosz$4yT;5p3G<3mEPnd#_zz{eJv=rA$nNRrg5mh^kMR2A8ZvU(UQmzkASV^=yd*Yn9LGZBY>km|De)d4;#WHkqzCgZVi`ZQTJO5_{1ka=RT7lEB54sT_D;qvXL ze~^sk>ZM>XifKR!dU}8+rKo0=4@#M$aC^^wx#0S6e>QdJYzA-XM9)vpuG z#_E&B5IcXwqJZWB1$sv};m@LQ2IVj^Gw0$%a12~nYWdhSC(sKSajZ$i=G&wD0NH9WB#hp>sHzwRz`&NM9;OPZ?_2!Qv z9JGE*&8n**n9fhDtHxY?adpf{3DwS0wSlv@XQ>(xYG24wY3~1Y-i$2Z8(RIohN^~E zkJKn@wLXilsv{^YpUzf=)#(c5L{nNy@TLTEj1p&^VzDY zm>$TZ0oaDPpp3!ZWOcS;Td>2~ijC9mtPKn;r6IM|GTv-qye6`)*S{Ql|Lt-@%nyso zG+-=F$b>D&y>@=?Q}D&6Wg2)5mGfi{mtd>70Q8NF&SC&~56&myC3RF&tgPyF)$J)_$`B(} z;Gkq86bL}dfH}h(b=5Q2I)v9#gR$Cj>nS#8$gYo(A4~Vv$GDB9IrSBrGsHJgY|b#E z0n$q8^9HIJ%o+Y{pxB&YRzt<+3>zCNHfN~c2()J`-PH)Rpp-T=!q}apBaKv=7IOxw z&{(D6t;PC{K?EGLg

N7@^s0As%K6FEvqYwovsd5WiBo?kcq!zg$gKW&EnzRI#N( zY%>+KR2YMWn3wlhGgZq~)mkdxmMh3`w)+EDMisVIc>8MQ*eW0|Gz<~2RXBJx0DXge z%~k(o*eb+8iQw2OYzHDUk>3u5-VU1HTwMhUzNxuNi{a_FFJwmhcGBtQs9_4Fx4=mK zNsqQrzhe|{x<<{xM(gl3svhPbt|c&ODqY)BU7rHX07$ty6R)o`b8`C`7~>zo+u^rc zDn40i(F*jnl&BTf+FV-EN-8fA<7iI%ABh@{TsD#&zf(|JE(T#u#XG zu$2tAPiu3p`8};@AKW~k);Sv7UEueQ$zD}q67 z!Iw(t%eJbacZSS%E(uwyu6=U7dJ)jqxdFi}diMsEi|T830BXENw{=jR5X|YI1~9ypfEjHjLhrzs zaszw@+fjy}3dne3nZm6BJL`w_;(rf-K>b^81VPT)H(Rd;%)q3 zMC8K=V+ZxQ6$`$UCf}-hq+=&69L+Zs`NI4)`Lw-8kf)raN}a(_OX%*-;P0nsYG?I@ z>oj%iqEhiZ@lza}rEy&pdnQ`dMZJpP#;zEUQkr6ey*6mjO|fh5QQg#Cn3Be~scQ6Z zH&D4<{JlV^swK-V|9oCff82(e|DlN6(fD@ie7l;#ugU;Grje2}K)NyW0hatPMcpCd zM~yqMPRcc7Ak^!y#_P8f@A=3l$%$Q|k@K(h8umF!2A*x#T$oG6Ln?-15Yk+1|r zP63y21%5)yfT0oj)oFh}^5rGprK-9hZZ^JK4L}=j-z_Zhz};ZHd#HYQ)xx`!ku;qN z`!X8P9Rt6NW_1USEu+=lRa)#s#d9}~xJTXR{!h`8dsJ^wt;BoPO^`_+z88rbY3#k=5?|4O_hOd5 zruz4(PjEx6@IFW%-%Pt-wZ@M&_p5U_k!|q+$WZ#6Fg(`>_15h4s zTDp9jG*sc6Y1M<^=O^ioUcw`W^->eWv<+$-+!|ohw%0}biKieQ!hCI}a}TMOK)hxT ztMiqA5DLW3yijFCMuZnF-tdUJs=^i?YbIp4oZTh4dM6^^%N98sgJ6wT|d$t zk3!TbCnFcL9pMAO@qZpwZ4tD5OkIoM<;PTm=4SwW{jdS>o9oUF8z`oH7=4%TG+Jut zis1N$uBZ&<5950&V&lW9wC^z>_i2jntx~J)kpUPWM@jD5?q@P#ygY{algPiP>Gs|b ztF}`?Z#CVum>%x~{<@FG^ik<)m~iO5?33j!!{ed7K&^7&4cc8=@{ed7K z(6auD?^`B3DG1W$Nr(>%*cy@^d=i*3KJVox)gvx!GWI>CuBtr)c7Es{vwQx(SpMJ7 zpO5%v+cf_NfN?vu9RMu&kX{&op*l&i0|j~74^;UqU<|SX#vrxDv3F$4eN+N5nOiuE)aA8DXXY(R!+hvkQ%fv@BRROuPWSGn}+Gpeubgi=%$ zih353)InMw#&t$<0UdJW3?9WMfzS5n27ASbP)J6=*lx^G4$ zoFRFkwJxQimsMt!l~ztNxaHX)GbPzpANLAm&r<68ipt7jdsrVg?~_VUO{Cv-E6^#L zKYU*R=~mJ7SFom5=jFWu0SuVZCRdF>`7d+T{c^)ah5=qdY7Yh3E~NoORYJ^62k*Xt z!RuO@I#jW%y2C?NdSbo|>=-!^eBJF^ho3x*D4#h@y@~4chk*m1q~C_AY>ZO|?xm*3 z@D3_7(zzECj(ahgap+>&a21DYn+;cs!P7I~rYpUY+_gDA9DJ{onvVcGDW#W2s7!}C z#-IwOjs*|}E20Ll_p0>u2-TlyMS4U-*AL--?@d_ati?EnLogU#q6c5nZ6j6F%IgL6 zDgX(~!pDSj70no_+Em!Uoj_Mn3@`l9{*j<4>nVB^=;2AaWt3{3j9y2>NMapR`TAi5 z8)IG`cx&FbmEIgBo9%*8K%svqW;EoHgLK1awel*5!9ttEv`d=sy`lId&PFlGWcYYP zj#E{zw5`-+4ER(rFOY`7B-mBld$$Ed`(aorzvdzedFtb!slKG3javi<5X=06fU57GgLh0Y45wh*dHy% z@_)ftf#{uag0Y3;gdBFB33B)|F!L80h)>wLOq{8bsKabA1RQl+w_Nz{njkJVk<$``x~sJeju4%8BZoD%NDYqTk?^COj&I z(07ssP7;}I?j%(e4@dECi+#^!#$uKg=k!DSg+sncst-0zvbJMw)Y!LRT92{kqISAAm8Gt)X3{=4VDhl3=@+#$lwmFJ*AOZ{sDA!QqW*;VgGfwjo56W!q60`$bITS#<{bb%$Zzc)a z`Iq7l(+63jHSPoYfPAf=0P?MVQ)M?5g6G4@uFaw(OBDWRMnTer-9Z2&eV}ygFsTH4O^=lr;3HfAfAW@$*>7)!pduc_1|n|?qT*u#Ed1`WSa_JG%mJ1BL;6+E zVqrF8;XaFnM?$gicgDh6u;S@FSCDVqTvaz2L&C^+$RgjF5aj!Tewr)DXXc4=u=_lf zTG=8W-z2uwi=Ux@@^r>m#gsaY4cSt$h8m67ah=)`5=F<6NI?Rv}?X7*Fe`&XyUu70$Q2#uBwH~ z{Mlvf8DRF!h{dg5oW}!BM$5_<6Fcre+qAsD^XJS;SY@0g2LGA+=6&`dbP^6VvC61$Du5Xk(hZF9hJP${{)3Mpj-8|fAFIa6=t)d^ zCGGIpJ7i7gQ2^Y+Oq<5 zq7e@foQDf@%C@S}NlRt5=PktspoF?E!>m*artEjqm%kd#o*>vS?TU4hev zp>*d8NU%d`(hAiHU7YM6ly2|(ys!;-eS9mi|0$+xRzhwlq{mmPuQLwuT$P?(3)|1f2;%HbV3%Xh7zK?6gk`pj zsVEUNbuDD|@pN{r2s$BJfdgcp*ie0DfVj+Dwia0`gczRUdjEd>8kR(`0AF&QI zTuLj}2`4(SPVheAOTaRouK5x}f071#sb*qeyz8+GDxvK4qGs!|9?Is!^!a+gIgt*p zR}0aVX&Zo+8!3MSMjOwxZUCYDnmT`lgRTO~{|chU6gu)1%89xqo*v%_G5!>lY*d>d z+<);kwy0p*+27*8Zacm8Es*oKyiMP#wafxv{~pYHETwExxvsH!Z*EfevDW77W@rZT z=&<$Gvea!@@-8YxkCCsN_eLB=2my{l9ZTzkO{P#u3N~&5H6BtM_t^5fRWFhVT3DUt)I`xx!m_g-ES(+!%TbkFRFJvW=x`- z$;3u604Bd03Y$YeTf%68zuTyDLG4Q`;{x1-^CbbdQp zoJWbjspQnR11l;DHNs#sj2#j=E9!0PhAhCi{x%rP1+2CfOVAxCfWvyHz;W&cAG_}S z4RYO^^v`c9)fsO9>k=^-9SdUxtD_y{l5)E+uiXxuKe1AH;ZA6D_tVjxY6cJWyft`l zZq_b!b>e)1HP?j=8)zcWRW2xSJ&eE~yHvGDub3=N3Jn!=0Ukb9WQr;W*z=czTz+NG zDb9fXF}s1H$GODl_K#rwnh0}G7OME9vYndLC76iZTo=tLRH^Ol^pzD70D=lB3peH( z3RRS~6AFcc?GS3orGHTi@HuI>N^u6Td}W~n$b-O$^T2NPT*e$nbCm#NxZEj6c8RS3 zvl8q|n8wec(%n$LuBJ!#U~TTFF?&E=C(>_wRO3W@RFKY$1Z=^bmFa2j!6k1vB&c4b zCL-69dx74?^wwTAknY@zeY+D?$Wde6hZXJEgVX8%SDP!B6@y!zq&>wTcpp&X18QW%2RJ)m!*g1^ zNj0L91FCoQc6c<81dgGuh1Bbyssbwa+(Den{7D-RLeTi0)FIxCwM8ba3a;;cs>PTQlV*MYe3rN7hPjRON5z|Nf#E{syTprDcC(w^T}5C)B+Na!!cWWBm#A zt&}R4sv0%dYOgoT<$?_qdjBKt46@fRm6Psfu8FfV++KkafqImxPSvf-2pMj~2#Wg; zM@@y3Uyv73P;D+%b*h%j$V5q!qEE`%af_26k{js$lhA*zpzltCv8|=QP6BD*(Bu?2 z{svlb3UE4%!h0I$BBk{8X%N8ebjumFE5I4romFE%Ilnmz+Ixy_KZmo3Z)m|e)ywmZ zzJa>c(N7`gx;i?JCjX;mj$_qbx=i@ z9t1Ejbk(6f_#hlN6+UulXZ(2RK62~6;2m)u-4?v#PLF29nB>viqt88>d!!Xw#ly5p zbB}r|T?0}xdQ^?(D_#H6Zt*6WRU6zb*)adD^kupwNewjji|*FkF?vbs{;-xgtaWnS z%*%D?03{hc00o>5{cF&nr6$m!G>Qw?vyl90xPAh?suqD>oyzMGp=Y|v!|5O>Z`Uk- z@)io{nVOyrOKk^#f%1&-&W!O?aIU+e1mv73+$-NeZ$|;-qvZ4I0{q(REdwR*x@cT# zV7{~WLsz{JcDg=B*8{R1i_wEpt;E{s23*yKAtXx~c)Qun?vGs1ujEwFEPu{I!0c>! z1w98;r+Y>Hx`-xXCMShpCFc|>rSnL}2q5T8+kLw2HI|5?jqpGlFqLz%m$lCeTB?#m zX=#5Vb*Y5*55o`&K`xE1q~CCr<|W1I+oW3oVJn8FR@V1oksYh7Z${9niXKpvhZT0@ zW!%{%+%><7j)zpXy$X=Bgl?&d0Xk3Ps_G1|kx!~>*~mN&If$CZ0ReZ@J#qS}_%mSE z^~19LG0aqXf0W%wp#xqTdiQWn#h)OrB-VO^VRqt)zt`Q%laSLvVz&F zm&=w@zOU7T`7+DpE1wN!Jb@v}_#fGz0t#eHzc^d09pD@uVVoue@>RP+KF-EAtjz&t2^o7<2uz^Hi|&C5WRoMdTtW?O^6J!(YHP>|lu#ih#2(hkmvS*c!HUIJ z*2$LqKeDkMt&@#!GGoT4gWd9hbC?fXs*)t#G2w!6_+#uk7^i|Uuo;8$yb%ai=VX14 z`+}wg$@*n1m|7{ijw?6swiKP_#&&mL8t4PmkZB;ruhWh+y$HX?R@1`}M5m(!-tI}q z@;FJKr0cYrLvhMB%w&Y2b;xqt07W{&0)__24o6oIl5r?|B3+kY>%A{S*Nz@xpkA~C zIFjNsbyngi!@>yspx{6Jpy06Bj`VQ4BUAH%@t>JG1wmwWosD}CtR+m3g-;o-pEb{! zQS5dMAuDmZR@YC)vKrD2B~YwAQcgg8L3L1$(NsN4UsV}~GH9v_NG-c|;*-K*^mvwT zR$(j>cxs`vRRDWomaYX;t8H1jZ)G5bCnhQy#>xU5MtUE0tD)OqKql1CkHggGYz>g# zLTXb}x2%CK@%7S8kk4JPyb;?Z+#Cba9D@4BCC*Kj(d?SK7C)8locGe^nz|wCJ6}`R z#WdEg1zz_mb*ZKAzy@-DExiKM1)puBal&yRTi?ZP)dm$hPj}VU?Oh}DsJ5=nJ6s4B zwXe!GUb#*TT0X<=cRg+SHSPjH;sfS-t6jpcM^b8CuoDqRlIgv==({86Kq4sCzWP4&}_1|4yE-ZK>z1t{}UbQs)jmFY+sn6vo=E*B@Jo_EGeD5^9i>3Tia0g zt1%8mfLURD-+}vhCl<-YBFQA`(n!Ap7ltPq>GlyN?5D`%Zckla^u$+kyTWkH29*cv z*Dz}P>EXuu2D>4JhLqjBeAgJv7iPGPbw<2n%q9AB?8lsg{SvC%MAyu;wmvwb9LQEa z^}{MMt#k!SX{Gz2(J`$c^Gv6&Tj`k8BlbR7fv zu%dpL3nLtUll2_bs4tAg-)^s;LD6`><{BRGqZ1Qpq+fT(uibtb-|%boi(O}kau;uj zc-YjJO}8cjUN=xpt|f|U1tHIiqeE7%j^=^ohAGYZc`1cVkBAeeW9j(_YeA+ZslKawjAs|70s>2u1el)VOG z*15b$1~soA7Qvn*L$5m7sx6ZbdTt_O=g&gOuShi z(?M5D+`#t?_!?%|t+GvUKLe)%Sg%Et-$5r`=%bWCrC^qXRy&600dv4ZE zabIox%@6`l(0e!Q_OX1g9A&j%E|}xi;2An|v#t|W>Vd|e?*x}py<2nx?0)aNMW4Xd zpi3uRH@yfa7tl1L;Vgf|O)=sAov6l-LCtoj!)oUY&FrMBA@j;kx@qNIQRs2|ew^sz ze^q?v$#ttv4NZ`u(MV`~s~(TW@^3{yw@&K}=r>ZY&Uzj?;pqaxaFVX+qO+5WAfvc( zLlAc(GR2TgE=)q(;rpD1bb%E75q;f7cf+PXv8&FAU@skD!V~G*u2=&fQQxj$rVD9w zSN$nA^ewyTitbjhR};&8e{Gt_v1u1w>)Yj2LleMkzvHHMX2 ze1($Z*uyUuws%o~GrZivPbAH@vV-A6oM5zQ`WPs$_h!~r-(W2eB5;%XC(3t28d z6a~n@lg*yy?9FB)9F5@Ai9f|>88av)9 zqzmhv@h%%Tl-*$Xf| z%hhSoV{792nXlj%Gf`NKI_tx!V!uRw&oUCS1o)7^VXs#R9Kx;y4r?olSrUwh3JzzE z4`VDC;kA)cMpnN}&?dvOkjo!Z1PqWLC~*0m5|VF);S)S~&IqYxGmiiZ2m(IT6)t~F zuw~y&gDaR_5LqE4a=eF+_gwyp9Ea|+>nlND_AkJr03&g5WJ$Heg~tdZ%EZ78e)>WW z{n$-!8gZJ&l;EuZ;ggR2;LH?qGe1PpV{#*%i!uq+<(+=6r|h1(UYsP239M)k5nj-n zsc%p4yLmLDr@q$<7`21x^j}ZitRqL@DmS#;c4irD#wkns>@=d5EzZ0$EoAZxTYKpy zX4WA*#~YfeH1R>5%~XmZmf5z0B7MSwkO@ScwBtdYZkMzq6*z0a!5WF%>Z}2W`pWEK z{Ro1Fu07B-L6*?9_oLHP=-NY^U`QD?zZyM2!-67Cg@J|zMVtyH?kB@{D})HrC%trf zH<@cm+UQgf3OnMYin6xQ)HbJz(54WF6Dpwxl>U%T4H*)kyR;ZuExIb%L#ve~;Lt^j zlA(lTJg?Ifo+}`%prnwL%S{g|H$usozF4M+c4+fMIuT%5u4jQkZ9ik)9eVh);e(<8 zM?{(sA)&j=9Ofz`86Z``9P&&F+r~Q>CtuQp`1=pit=0y;&mR2&M^9AC>*Z1-bRID^+p@T+}EyHo_z~{C_kMga(IsAF7}80hKvL`pT!or zy&y|p+I8?w#&VY7^D2OWy1g^YZxI3_3Sg8+Zdu4<;wA6Z$iW^&Yi=MSGmKt)6q~)7 zwC7P>=T7Ms6a_BdFPz`>4W&4KN%)l$V*A?eI7sgRBrSMx;~3?OIGZ5c9P06yPGF&s z$4uCs2%V!I(~mXyOoUEfK&Ku49@<-1VVTn915*y< zYFd_SQE&Zl&YsJOvr-1wCE_fKi?AYO6GChl&Xu|A$mGUW0`hDt3=$ukTh?4Z>>7Nr zFj7B^k2(1Zfz%<(S?b8P+3)Z+C@ak5;Qu(8*IYc~Xj;bgdy7px_p%n!?T%4!!yUj4 zcYvQU_QyZ2uLgNw5drHYvz%CB=S>iaIovvfmku1ESc~f~?9Ok**`Fh}d9dMjSal6f z20~iO;-Dg||Cr?jvD593f)#PJN9Y-6 zL2?sVUeva)PHBn?Y&Y!c43rJ7kC1*jC1=t2zB&$Cws-sLx)=_Dkr7rtcvZ`XvzBF+ z_uGy*Ygq_*v5g8vbSGCRU2t-R(uD(|b!F%9dri{Q;P6T3+2;C+o!=-FJwfILz2c!$ zUR!|`?b%<4GcIL2Ca(69aS0WzX3>s*I>oZJbSwMVqkpbnHdoH%Cdi(P(PSsD4oga4 zjKF3B7v<$WhRs+ux&izZ)*~B&Wp+q-qAPk611JX6K!n$ewS*$+P@#-}LdUZob#(a| z-kO!|%#PB^Cv;lvFN`-2zEN{ruY_nt0t+CFuPCuV#|jcxfBjGn1UlZ+deD!6KnME< z{E{t^16evR<*!Ao#$}UC!|#1uf|E>fRvWnN;Pu=nQ@osAl8M_{BNJzL$2n4|IOn;- zTwAGo3(7eA=;y+C*9HIt#M+*Y^2N>8536>`++y?u`tK}c{&vnnb>Pn~w=~l2f`z0| z+tanIf$sc8W1rORTL=pf!n4;-7bAnkIlBmu^{e0-3e56Ray_N1R9zQbRJK`OOOv}! zt%9o@)cz^m+M=B!zX`55$Ri8Tjz?Z>p1+&m`cjOv|-GV3MF0>$&rWM-GhRQk;?;xP|sDr7Ki z2Ljp+iL!%#vBpS}9C9r~x`SE`!qHkjJvaz*;#wLy2uifoG-nW0mid%72 z-W?*I4x@EV@aSNEV@RgAKNq0TGVRX%$WkoZ#Mr%v%#`d(1f^szA}AHu#5e+N=nlk@ zSwn?UM`o2ZBkL&2cU=G(SOBmX>aY=kX$~X9Wzf=DM0V>=ji1+p?3$NC`*io zuR?J!m?S%%&~+3{x@4yrOp;j+#n!T<9J|L2MccA8yZ>}n-bEnFE;Mx9f~8~i+U}iFfCBgj(>>xvThO?;di+XlIaueLI#Um+HO1=d5YjB+4epVTGsLo$Jse%+d zh4LZ10VWHg!gR4!f}Iz(F0d*oc`iZ}QEVc>Iw!Or4Ko0%X|i8DlJ2hJ)vd7SJQ zZ+NXjlRIOzz`VH?2zWii|_Dl3q!M&P3+r^(#c;;%X)l4sl0G8{o?%D!bq^DNSn zLv(6&E7f0KN^zJNEgGWZ+}O{Eero3so%N_QK0LQFP&~Er!80o#ynN;3^7AT5yzJz| zS#8359Z4KqoAO`Qi6Co`q%JSJIeo$goJFlFnRvNVycAjC5*sBT0u&7Y*A?a2in36V zxqL+_ujpx=4w($an<9@ts%02FSBqsB+BwYeAQ2wF_tJPwDSHQZ!A&I}kbJ|3V;|HW{3}}!dkgPp`jOZbP^udnwo>- zkw59n9Pr7b^hb`aW7`8Q0awfd%>2cjz_Br2rfrmq6YW3g!CcK&{Lkg;Ykm8pcp&9S z5yy)_op0dJ1J-91hJr88r>lm->TW*WH53Qq^J&;n=t|GhlA*do)ia{=^!WAFIOhvP zD>#8XL(#*K|132ehC})@bmuUf%b%gQh9UpKD8^-vKbrH~LpI+bIy(&JkO%3J;rhFb zKcX01CSPpGqI`#>MDX`v>M}yF!>M?skvQnyK%+)NUxG_6BXwrgd>4uZ=73?rGT2R( zM(F`P0Vpuh?a%bR?!3!_x0&z>=H~V{JAZS45XhhTvRL>i?YY4!mBviKTgeG z#jitj_pADe9H6m_`vRd3GkXbUnoQiw5+(3O83KqY88r9&q6|U2L=7?^?Zt8GJrTHjh+dtDMRJH%PSoEsl1;+t?ipG! z383w!;z_!@7qiQP8LHny9p6CHXQX(Zhr6~I%tesWq{CG79R~?08D#eybL)WC+jU{=+xlJ`U5lM_TR8xxKPF^ zK`w!2yHhYgqUM4ZmcQTD?Cr4nJ76gA`1ej=-K5Z@cVyzQc$yhOq2qMooxlpJ6Xk>Y z28C&>)guA_+!Sz}nM(xQ{pdGCVwx ze2b=FTgShIm}5W9bli=NYSjBWtEvUa-7*Z;9ng_U(kQy_eSKr~SHtlu@B+gwmZC0x zmfFEVkIw#dY|PULNUUw`8QADp=W<6lTW+rams{JO;kqinFw2LIZi`A3pv&_^&e zJ3zDTuU~BtyHMYPOGZ5w>I<-h>+vz>r0A8rk4>8$4%&88%pD zgFQBIe zAG(=DuBBl9JLsjQXlM_;wG_hKceG+DY`)G?8c1gHIoXjoLhzb!>)KbgerxHTWzyOd z1QiQC!se|spC3Ls_vvIhvkb;m#nj?+>BW6Ec*O?uY_P!w2W=3QCpqieplcpD8XSFLS454XR9)J)T;~9whgRs}83)8x zm95I;M1?J&@xsQ`GKchIs9O=P7^SS#-?*o{Y3?Cin<{>xBQyTwf+FUDr7{JPW2NAn zOrdMO&?~VF=H~0_6u$~a#s{d;D*Z@o(XRlPAHjpO+%viBSnwLUUT4z}t3an9l5zfo z)snyQYW=LOB8$FX4HcHHF0p6~sz{b6di_zhrrdwg@dH$C4XiT{(BL)t-9TObwNlr; zYhhhl$W7Izzt)1lI^S*cwMj23LWPwvR)!oV+wljvTV7>G`dV{_`cK>M<t!xn0>A%T{kZ##haUf4-(oh{ zwegzAbfd?=(?ekvdgMD$ir2_|uRlW@lH%Q@`zBrSjR=o8e5MaK=}PWm4^^yevS{xn z@Wn!k-mIUv77r6GUV~w&2wW(FHE%wC@M}c{92t#BHu2r%MCPtVB>O7?U!0C_`-;)Z z&H6czt;X>XvWcgsf6yHO>B=8uG=lu7rG; zHMktuqATLw^V}_v?F(t`7MT_d+kNRl@kv~bNYX2no(#Zx-*vo-%c)3yiHQYPKP4j-%RVcq01n`#M zbS36Onlkq4Br|50)SmmB)cy_vPIS|~g*qv+;0Pyz+|$eW8R7i&Ql;IxIo+^B*Gk|Q zitWr-gj9wehyVtMzF+}OY55Lp0I23sVMd07)~ z*IM;mx>8(mSrb9zIwfNnPep~=Q14w3x(aF1E`2}7tYnu|TB*?XMA>dSwC8TbBF~F9 zc+&f00*Mw%2lwp-8TeZ(I9 z5E_xim{24=ty83vqgMra>tg1u+0omBG2d8jJF7_d#{DcDqaHYENcRkPbHs$QsaS4~=Hs@~Cmx>R8?tV_a ziuF}7Q6GQ$L*ED# zNj@Uke)z#3x-iq3h6=6ZpEP6kIKe z)_tHG(5I!kF4g9&F(;v$Lv7cc5}EmxQ+k>=Nar4+C97fdK1Z7h)c&+?4yXs8#x(** z{yBPDC@hN=i8CRu0nO(A4U}?3xP^#<2q#j^T|Rspn**m!Fe8!I^VVqCu4YM-~1zKP5!kQ8%Zt04Q~Vn zBLcxJ8?3RxUK^{VpSAYdY(Aob4 zhte-V{&N*iZ6OeGGFTfp@zjq@?q%6;KDBq5D(=P8=%pf^9$Su{uZ{4IQ&)VD!b8$4};X*O741F&u$1aNH*z_3%PoyRaEzriC>eQW@c ztQ3*CN+RE}!A2V#R;C-$T4_n^VS}OC+~y6kz}w0&($HybSS}Tr=tg52)Cgt^qQdBi zkQY=}M|i)rNYGxH7+PaY6Et|-;1mJ0$xSc)3-bIyA=4ndgJLq1ie-B$LQuJ(`!s?o zt%u|~KHMZ!4We(b*|qdVxcU5Q!QC;|(GnZk%T+?`vi>Lb7SQ_%rIZ(P%RT^7^nC^FTB| zo*G~$wEK5Gw>IpY>=hPV3DKq)+!ZE3tWA@wW4`Z!I!!1 ze(VH(sm0lR&fX^zccP+UdAqOAr1^rxL52;F0Qk(E_BGezKJ!7H%L4Lc*cBkDL5C`t z=9-^{^-#BDlSv(7FB<)qV`cQ;k2OqVj>Zawh^cJ4VoG{cHiMzd`?a#UkI~ITtABug zuJmJ(ac{38SpS?2%9uyQVwTAh9hux+=(HPMRoYFfY92;2$Stytp%1D`^N7!&6IIQ% zNZcBa?Zdrs2856(&h%w%1Jnq(P$7@8`*W9~0jQUG*Ea^=K>f^kyC4+x$dV59K?I7w zW`jjGK*h|s1k@q5Az~*H274SsTMPW%G3{MrqQ|-^AHV46xsl3s*#y^ zOs1_;4O5N2Pc-cVb&4R|EGbxLPExSWxxqRol6_;ZeYUAY6_TX_RNM^pNS&{wnpU(Y zSsD~zO$w7t3upI~vO3|8Wmgi$ZE>2p)f`(UBOw4f(sZD*G60KGgY`5?E2}5^-ym$b z$CzRsHbtKYYjcFwKy9r|flU<9q|aYglRirhJlu!&@@`5uQ$hD>PljP}Sit&VS8&|8 zk7h2!In16^Bop#aX0RfEb<;jNgp8cCbZ~xk^EoQKFH0sE)!%K3ED}f?Q|vYcp!7s8 z)ZE1m9RJFwX~rS=q^1ltWb10AY605)yd|whkJK`4Bg-13w%OS2ep#z*lw#)N*>$#l z1XrIvy=(@-0A#bUIfCZyf#bD}*`}EXwNU;RXxfu%n^ZK}qP9RA=x7687UMjo3;k2u zya52m*D=pyp^4y8yRKnPl@&tlH>BKWkz88W?BTnk^-M!GKEm6RmSDFN1#Rqs*ULiflQ7c_B*($u?vAlW%v!~X1mYgctCg3kCqPbhy zcQRO!2wjD57~ignrGc$M>2GXkUW@sUOF)|{{@G|xLvwq@3oK?$cRMA9lfRMafxGH+ z8=05k#UZV+xzjz;P2HN{7SF4VO)T6-yxG{afrIazjm=#57m-xd7@PZD?wq5m4Wn}Vya$!pToz-QWQ7tLvA*1E<~&#QrEYx1UEZ3boS{she7wimr8ZPfM^Uco=F4EdP>|Q>n*x zRfFocG6{9rD?yk)jXkL0EW}>L2xKZz$#y=zMYZA_LL6}hP<#b$fojhS^ynB5lwcli(r@LC4CmW&{_7(!JBKSt} zgs}Z9{`p4p4>ktHKi?SqfcAGdooH=3RvpVp*_@Q!*Ehl@W#_dw{7B@A_U0;{w37B_3^y>?kBKg&5U&WmaVKPk^QfN9aSrYSBA|9-8x3Jyh?GUaRX(clL5I;@kGW?H=61YVou*^+Q*NFUY?!I@f%Q$ z;5ggX^%ZsQXs!wW4kHo)&#mJ-niU;>jFdeJ_-bG=+q6ZPy@*I zBaOSsB;SAn~m``p!tp1s)&$b6S`OOI_4-$owH_Wj_sQJk!8 zjHE9sUE?204&UXQ~E~Q($n(G>`z6gX|w*?`9bx22Vg5$lKc6T;) zDm%C2L83u)aHe#%y9yOeHGe=6RJhsP2(O=wZ!?vnHUTwYsRB}w*N7mP!Vv1g+fCK# zSbuK6c#p)o#;b0TuwC-t1q62c;%EJ+?_FB5!}SOq+hT5Vy+JKEvdi~i~NUG%Z*Ss=u!#_O+tg`{Y&zrhufyk399&?KO|zfp$gq04qP((7*=npsfH4p4;G z-{kU1$i&nO^ocn!KQqpjN-HAiflpk`fzh2;m|PxiH+*`*I}fjYXJ|u8R`UWCLXu!O z3x6%45vg83>|26`VMdGRQ9>h<;o;@{n6zj;=TTu zauM*lRUtGY1n8<>f5p%wh-rRbxd@eMuap7B&i;n1cdO{u+{>!~$XPUwwrnn4~nnLXtyQ?J{=Ik#1UL8ZjApX%$FUDK+h3nkM}O zItXJe)gEL5uE>~yg5Cjn#?Y`HrV&dfZmxwb7hw|ShEo!jCL(-4(WV|IB?(^B!u?@h zyl2I4#qd)?umH!KCcd%c?rCm@+wxm`n$#+&MsYRaOitnBJUtv1JFoOKw}B6D?FowX zGo9;c2EtM66A!{T^bH#KplRg$nfW(bHMYrZwE01kk}yu&CZlbWEG>oOVYSbPq zK=gVqh-%~M-CodO{6eRCp}zGL|Bz{#42tNHH@38IwNtetXZ=ELdz+NBRd6(8d&5uq zh#+PQ@S|KCXzoL%TXW<=jTss@$iPbZ)tWABr^lH^J_|IG8G$aN83X7d@QO|L!=@LW zOL_HS$Z3VN=wZ{=_XPt1nb`pXZ>cF-9yJNRRpo2jZfo0TYdb>UK8o7*QSxJ`4Owk%hpFphrdRdfP&9xA z8$5j>WwBTrf(<7%r98wZOOKgbp;Y6+f(zXHdIQc=^n7nb{zYH)Hg^H7Qu>(Nomr*n zeK4mxLg$q3dmL)H9slQ6<42?+J?UZyI=aMZzYNpD@kPaHO9?PxOasqmaJsZ}#{KBQxQK z8%8tivlZe3Eq~HnkHqs&8aN%y%YDk+>2f_lzYH*+0*aRf%llD-%r_HNLMZ5*UT|215u=!>GO!!v?UNcJR_ovMhuwL%^jQI!i z(&<@fAokKz&zftK*$T36!?3VcVQj9e`axFNANHi*^^AWzZF&}h+IEV44ocDO)b2U+ z7BrK)pTl119G!a3tcC$*y}>xB*z&x|^c{{wQDBOo6KvbbHQ3a#Ii_)9m?Vnl9wh!a z*tB$=q?i{>Z}j5X7v$IC7fgp1WnPt9Ji%Ldh-GlI6c=Vy7A%l31z=M2XQV{)H&9_0 zHF(kVuQUw;K4)O2%2RsRia3*Mfb$Q9uP29{R7_!k1 z95&*|DG);TDVY4nebpkj@-J*(f21#7f=01`cD`h;tMo0$^81Co5n@a79W@+cTE^l% zaQp^FNj%8scl6Q_)7rO#vm+blM(nrr^$>Flh+VgrO#(H1+vu2*NHGQk?e+Z?N&dG@ z6ME`pAoT%PI+wK_I!LqLHmN*#d4ANV`09Z zsrkFEZtlG<$}a*s)$@c~)vSfn@K<8n=2SE26Yxv#Yq&}?-9!@H0cc+)FW zA8eF2yB9}Y+C1-QFV4jl_S}__x}v>s|9w#$EY~iMa!l?}GGK5QS_$@<7Z(r<*m6xF zi*#Ph?tDkf_E7zNj(7WVx$O?Bd{jVm2m#;O%9R1b&Odo&`)Ya|TSh5shDzBzuj^C&^yp@=3DSxO|e` zYg|4}_8ON@lD)>|lVq=P`6StEge2L$hO5_QyDEE)kj%&w7$DheTs8@rFvS=&N9$+z z8hFuc1o&ksy)(kJ>U`0ViV%6(%Gj>CdB)|F0+?`u>Wwt5SaN)PB>XrsYlTY94U@2R zOqICWnOwbe*kG6rmB zC>>jC+O-mW?KUZpAPPk{Hr~7?&Jv9xd{a6KP0(s672W=j%KPSTaD zVn~*J^1o_6M8p5BGqZ6QYSx#gq>?Cd;Ubgw?L6|Y(aiNYe^^87)A|lcdz4b2 zugurt0+uf|iNF3<8_iJGUb3-z2&ghDNpyIliA}%Y@?jydb^)DbMHZ_UN+GU+Z;RqF z`D?Qfm4EZKsR5z4Jq)!&#}P($|k#&nd1*@Lb4$e%mO+#3TWh1*{@ zpfOMU*4$R_B(xv(!}6^<19G*7Ys<1nyURdiUUe#x=v%X(Ci7{*TBKqirFzjy|0Z`Q z05q4U$G$WD7=hMJ#^k>-`IB6{G(Ne)(8NljsOA}P6xEZd;CqwQMikZaWhToM)r;jP zxR+H_^LVh@^zxc&*W|o*o6MW8i_|{o;APc57*UKc->PPTg$MZmU$sx;pUiBKOsGzU zH32N4ll)sQXTEKrYNKNDslE+`BN19=n5*s9d^ zO`}qv;tJKoA}bG&Xkt%UP3$Sw#Ll=>344mSB|#-D5C=-wTWgGSv*Ixb<>er704Vy| zM0Q7uSL|*;1N*=7fK>(?V={}MOlzs(923{Y4mGPh1G#vpS>+k}oAr&Mzp-pDTW2Ii zEO%Y)nI8^HxD*F;N9LHjvMv!)1JXp3z{i=$$zAVjW#!h>|DVdOb?NbWrb6~IJA%H8 zh1jz!YC%Nw2`IjEG-sY^;@$>D;}CP5`=7|k84sjH{~Hukr%?O1&DAxw2V^yfk0OtX z2Q1(J50dNTt+V2&{yV0Vdl@WZ-ZAYsT=kAwbnEXHMxgWl0JI@rPAXPGv7~~y`dzoM z`)yut%iLaX7Z-fgiW@`xoZS2VT9=CYXX)5{lglj*de^LpI?aR0MC7y;o&OclIrY2@ zpA~-p;Vh0g%nhBP1@9TZ`+Q`XC|!vX-Z%Al=+UzZY{%o9?=b24bnpA7i}MaqfkU!* zzvPBOBHN8ulT+-=Nl5eENd@nlcdr>5Wgj~6pZ#{7bK=_+9rH71;T;0JPX8B30gA)> zPda>4DV*6Y`oJVt!T~XSz`^G+9il64^8!0p1?pQ<4cj8C|TVnVB_$iNj9Gx zL|i5m= z<`S>de_Z19UZm7?;5>%!2KJlwm&Lm$9F|tyxkoK18RlC5U;34B+RZ_LmVWW!rZKYVPu{=d7Q7J-)_ zy}!C$hAJIZ_tM5iX0iJdd1)!0CVXOI`NxuZuC%;$pO}d*G;!M!Ce8{=|-$=ukNNA;JY zWjTIIZt(HjV(c;%t-pd~SZK zJlpFIw~n)l+&Fg33iJJ&hm)3kS9=fyES&XdI@_J^f*us%D(sLrTOt(!lby3j!vKVpFG@LL2qencBh0bZYu#oMyUC zVw!4|HdAO!ipr-#uyhenR*{d2+TVQ-Y~0Bo{iEshkMaliopbLy_rCk~-ut`voOe#J zaeJtz?Om~5U7}Yd*S5rQ;d*5du2%-(ru2nId;kd{r8G=I@_=?`z}sATN-PVDGU^15 z3rz3eKc5os{U6~2AATVSKTslkzF&utJIMb@FrRV`HqHMYn6KkQABvy<4`X=-mVYNP z$@pIRj71_r19_dX7$Xoy2JEXBy?$^XUGRBupL0GE@p{CP|Gq}o18Dz*n&5}0@k|f! zbe)9@kBE3vo#pcZbsZk+Gk_Y!C7=$JfSMm~6btyHpTM%Q=YqK9{#eB-4>x|l4=|z| znB?pMUq8~?9oAJE)>^~5Dhdp%+=R(pt`?`oODJK*bYx0z#1sLq6-846WL!fDGfd0T z`O|ffAfb)ik5KqfR(V)T`fiObxq0=9maSrjoT|{gPpp2K( zTl6}zTZ9bZ_S+V$DhR3Ef(7adf4LQ^jRSnNRmd-k##+TjBrmp!O?;Ka`7&0T+im#APhz7dxR+xX1@S6-VVs3)Ck;h=wGCU5CqP*s$d45{Ciky1GOU zKug2b@p7S9?PK(EderPe-u*Y@Fa>KCwxwok6kMcCjY9aom~J$ug)6%O9-8=aH;l2G zJ-54|901qk#d*&qp6SKwzvy|<3*ASkM+XQx=4j=g^@y{Qql}}ARxZ8v0A2j)nkdIJ ztmuVhS0}gjirLaT2Q(8{l;uC^dnc|BM>3@l&W6 zrwxjFP&Ws~UVPwJaU0s>5k7YtrrO;cJOmKw<7q?aTrXD*!NStZpALz+!4F&}O&%6A zf+xJt@H3K{a5;ldb1+hS`Pi^Xg^_H_Fosq?$Bl?72#tbHfuc<&P*MTc4f5&{aSW9W zjOc?saul|9US2&aq`#PLqarQBt9w<))Put(RqOM-HHudS<>A$T;6eKNdv~Cr^l|4M zeRPM6iMfHe11rZcegyrzZA@%7>Xk9IP_KsfBkOG(6APdM3B3y=%nO)(p%uxwi(7nL zb60Q5Z|>sg)ysW%acbye?VjGSl}57To=92QuRG0HZ-`whr$1@Fj>#CcWWbrK{LWu zrbZLsm}90&k0D~$b1F?y>-pO%<;0+*ZnorCvPY$5_-!Ve=&R_oLKDqO_yqgUS^DZN zH=F81E=T%2Cr$KqlX}Aw7({(4QlB8$KHc<01k?6FwcfKMl%7@949~eRBBb09PHT`P zM4&~Hp7aPhonX$`sVVX=gF|N1BPcv$Hf=CZdcdB@_EgWO{6IC5?=M1c#cpXLy2^k(Q7;A*3-)Qvzij(l_&Toj8LBH2aRVeVW_c^nd-MH<7Y z{fVDInkG5s=z*4uhP6G#YIF zpp+it@0XI@d;zQ{!P?7XrBoWWC0|ogL0XYM!l`b8Zf^&r@bVpG;q$l(>q1T%O4K4v ziBfjI}Y?cqP{rp=Za<(iTV za;%J#t7wyX-#DGg`>JTM`z**vWN$5V+O4*tB3s$k{QO+I&0)>Vv{Yz{8F`UNRirr% zr#;(VWX;6&m;Ca!<>uR*IgV^=K|YFEGnXS@j-!ctv$orcY*|kI?o8x`7zzan=hrQHUR$#Y6jw{QF-!b^% z;1}BqU3N#7y%BUU=sa72auwGBxVAf7c>@(G#yA|Ws3^zgaE|#2EwSlrMdKTLC^kMB zLpDsx*6Tt$j9g{8C+RzM++yl_jn7xpRCDlmjW)#aooZTQsjWVvgs9(ymmyBCp;=n( e4 TokenStream { .into() } +/// [`derive_ref_into_domain_owner`](crate::derive_ref_into_domain_owner) macro implementation +pub fn impl_derive_ref_into_domain_owner(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + impl_from( + &input.ident, + &input.generics, + &syn::parse_quote!(::iroha_validator::permission::domain::Owner), + &syn::parse_quote!(domain_id), + ) + .into() +} + fn impl_from( ident: &syn::Ident, generics: &syn::Generics, diff --git a/smart_contract/validator/derive/src/lib.rs b/smart_contract/validator/derive/src/lib.rs index 23d698cacac..bf0ff4c00ab 100644 --- a/smart_contract/validator/derive/src/lib.rs +++ b/smart_contract/validator/derive/src/lib.rs @@ -185,3 +185,15 @@ pub fn derive_ref_into_asset_owner(input: TokenStream) -> TokenStream { pub fn derive_ref_into_account_owner(input: TokenStream) -> TokenStream { conversion::impl_derive_ref_into_account_owner(input) } + +/// Should be used together with [`ValidateGrantRevoke`] derive macro to derive a conversion +/// from your token to a `permission::domain::Owner` type. +/// +/// Requires `domain_id` field in the token. +/// +/// Implements [`From`] for `permission::domain::Owner` +/// and not [`Into`] for your type. [`Into`] will be implemented automatically. +#[proc_macro_derive(RefIntoDomainOwner)] +pub fn derive_ref_into_domain_owner(input: TokenStream) -> TokenStream { + conversion::impl_derive_ref_into_domain_owner(input) +} diff --git a/smart_contract/validator/src/default.rs b/smart_contract/validator/src/default.rs index f33eb3b29f2..2cf2c0f05fc 100644 --- a/smart_contract/validator/src/default.rs +++ b/smart_contract/validator/src/default.rs @@ -355,6 +355,8 @@ pub mod peer { } pub mod domain { + use permission::domain::is_domain_owner; + use super::*; declare_tokens! { @@ -368,24 +370,24 @@ pub mod domain { use super::*; token! { - #[derive(ValidateGrantRevoke)] - #[validate(permission::OnlyGenesis)] + #[derive(ValidateGrantRevoke, permission::derive_conversions::domain::Owner)] + #[validate(permission::domain::Owner)] pub struct CanUnregisterDomain { pub domain_id: DomainId, } } token! { - #[derive(ValidateGrantRevoke)] - #[validate(permission::OnlyGenesis)] + #[derive(ValidateGrantRevoke, permission::derive_conversions::domain::Owner)] + #[validate(permission::domain::Owner)] pub struct CanSetKeyValueInDomain { pub domain_id: DomainId, } } token! { - #[derive(ValidateGrantRevoke)] - #[validate(permission::OnlyGenesis)] + #[derive(ValidateGrantRevoke, permission::derive_conversions::domain::Owner)] + #[validate(permission::domain::Owner)] pub struct CanRemoveKeyValueInDomain { pub domain_id: DomainId, } @@ -402,6 +404,11 @@ pub mod domain { if is_genesis(validator) { pass!(validator); } + match is_domain_owner(&domain_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} + } let can_unregister_domain_token = tokens::CanUnregisterDomain { domain_id }; if can_unregister_domain_token.is_owned_by(authority) { pass!(validator); @@ -420,6 +427,11 @@ pub mod domain { if is_genesis(validator) { pass!(validator); } + match is_domain_owner(&domain_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} + } let can_set_key_value_in_domain_token = tokens::CanSetKeyValueInDomain { domain_id }; if can_set_key_value_in_domain_token.is_owned_by(authority) { pass!(validator); @@ -438,6 +450,11 @@ pub mod domain { if is_genesis(validator) { pass!(validator); } + match is_domain_owner(&domain_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} + } let can_remove_key_value_in_domain_token = tokens::CanRemoveKeyValueInDomain { domain_id }; if can_remove_key_value_in_domain_token.is_owned_by(authority) { pass!(validator); @@ -448,6 +465,8 @@ pub mod domain { } pub mod account { + use permission::account::is_account_owner; + use super::*; declare_tokens! { @@ -516,10 +535,11 @@ pub mod account { if is_genesis(validator) { pass!(validator); } - if account_id == *authority { - pass!(validator); + match is_account_owner(&account_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } - let can_unregister_user_account = tokens::CanUnregisterAccount { account_id }; if can_unregister_user_account.is_owned_by(authority) { pass!(validator); @@ -538,8 +558,10 @@ pub mod account { if is_genesis(validator) { pass!(validator); } - if account_id == *authority { - pass!(validator); + match is_account_owner(&account_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } let can_mint_user_public_keys = tokens::CanMintUserPublicKeys { account_id }; if can_mint_user_public_keys.is_owned_by(authority) { @@ -559,8 +581,10 @@ pub mod account { if is_genesis(validator) { pass!(validator); } - if account_id == *authority { - pass!(validator); + match is_account_owner(&account_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } let can_burn_user_public_keys = tokens::CanBurnUserPublicKeys { account_id }; if can_burn_user_public_keys.is_owned_by(authority) { @@ -580,8 +604,10 @@ pub mod account { if is_genesis(validator) { pass!(validator); } - if account_id == *authority { - pass!(validator); + match is_account_owner(&account_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } let can_mint_user_signature_check_conditions_token = tokens::CanMintUserSignatureCheckConditions { account_id }; @@ -605,8 +631,10 @@ pub mod account { if is_genesis(validator) { pass!(validator); } - if account_id == *authority { - pass!(validator); + match is_account_owner(&account_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } let can_set_key_value_in_user_account_token = tokens::CanSetKeyValueInUserAccount { account_id }; @@ -630,8 +658,10 @@ pub mod account { if is_genesis(validator) { pass!(validator); } - if account_id == *authority { - pass!(validator); + match is_account_owner(&account_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } let can_remove_key_value_in_user_account_token = tokens::CanRemoveKeyValueInUserAccount { account_id }; @@ -647,6 +677,8 @@ pub mod account { } pub mod asset_definition { + use permission::{account::is_account_owner, asset_definition::is_asset_definition_owner}; + use super::*; declare_tokens! { @@ -683,13 +715,6 @@ pub mod asset_definition { } } - pub(super) fn is_asset_definition_owner( - asset_definition_id: &AssetDefinitionId, - authority: &AccountId, - ) -> Result { - IsAssetDefinitionOwner::new(asset_definition_id.clone(), authority.clone()).execute() - } - pub fn visit_unregister_asset_definition( validator: &mut V, authority: &AccountId, @@ -729,8 +754,10 @@ pub mod asset_definition { if is_genesis(validator) { pass!(validator); } - if &source_id == authority { - pass!(validator); + match is_account_owner(&source_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } match is_asset_definition_owner(&destination_id, authority) { Err(err) => deny!(validator, err), @@ -803,6 +830,8 @@ pub mod asset_definition { } pub mod asset { + use permission::{asset::is_asset_owner, asset_definition::is_asset_definition_owner}; + use super::*; declare_tokens! { @@ -902,10 +931,6 @@ pub mod asset { } } - fn is_asset_owner(asset_id: &AssetId, authority: &AccountId) -> bool { - asset_id.account_id() == authority - } - pub fn visit_register_asset( validator: &mut V, authority: &AccountId, @@ -916,7 +941,7 @@ pub mod asset { if is_genesis(validator) { pass!(validator); } - match asset_definition::is_asset_definition_owner(asset.id().definition_id(), authority) { + match is_asset_definition_owner(asset.id().definition_id(), authority) { Err(err) => deny!(validator, err), Ok(true) => pass!(validator), Ok(false) => {} @@ -944,10 +969,12 @@ pub mod asset { if is_genesis(validator) { pass!(validator); } - if is_asset_owner(&asset_id, authority) { - pass!(validator); + match is_asset_owner(&asset_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } - match asset_definition::is_asset_definition_owner(asset_id.definition_id(), authority) { + match is_asset_definition_owner(asset_id.definition_id(), authority) { Err(err) => deny!(validator, err), Ok(true) => pass!(validator), Ok(false) => {} @@ -977,7 +1004,7 @@ pub mod asset { if is_genesis(validator) { pass!(validator); } - match asset_definition::is_asset_definition_owner(asset_id.definition_id(), authority) { + match is_asset_definition_owner(asset_id.definition_id(), authority) { Err(err) => deny!(validator, err), Ok(true) => pass!(validator), Ok(false) => {} @@ -1005,10 +1032,12 @@ pub mod asset { if is_genesis(validator) { pass!(validator); } - if is_asset_owner(&asset_id, authority) { - pass!(validator); + match is_asset_owner(&asset_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } - match asset_definition::is_asset_definition_owner(asset_id.definition_id(), authority) { + match is_asset_definition_owner(asset_id.definition_id(), authority) { Err(err) => deny!(validator, err), Ok(true) => pass!(validator), Ok(false) => {} @@ -1037,10 +1066,12 @@ pub mod asset { if is_genesis(validator) { pass!(validator); } - if is_asset_owner(&asset_id, authority) { - pass!(validator); + match is_asset_owner(&asset_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } - match asset_definition::is_asset_definition_owner(asset_id.definition_id(), authority) { + match is_asset_definition_owner(asset_id.definition_id(), authority) { Err(err) => deny!(validator, err), Ok(true) => pass!(validator), Ok(false) => {} @@ -1069,8 +1100,10 @@ pub mod asset { if is_genesis(validator) { pass!(validator); } - if is_asset_owner(&asset_id, authority) { - pass!(validator); + match is_asset_owner(&asset_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } let can_set_key_value_in_user_asset_token = tokens::CanSetKeyValueInUserAsset { asset_id }; @@ -1094,8 +1127,10 @@ pub mod asset { if is_genesis(validator) { pass!(validator); } - if is_asset_owner(&asset_id, authority) { - pass!(validator); + match is_asset_owner(&asset_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} } let can_remove_key_value_in_user_asset_token = tokens::CanRemoveKeyValueInUserAsset { asset_id }; @@ -1462,7 +1497,7 @@ pub mod trigger { if is_genesis(validator) { pass!(validator); } - match is_trigger_owner(trigger_id.clone(), authority) { + match is_trigger_owner(&trigger_id, authority) { Err(err) => deny!(validator, err), Ok(true) => pass!(validator), Ok(false) => {} @@ -1488,7 +1523,7 @@ pub mod trigger { if is_genesis(validator) { pass!(validator); } - match is_trigger_owner(trigger_id.clone(), authority) { + match is_trigger_owner(&trigger_id, authority) { Err(err) => deny!(validator, err), Ok(true) => pass!(validator), Ok(false) => {} @@ -1514,7 +1549,7 @@ pub mod trigger { if is_genesis(validator) { pass!(validator); } - match is_trigger_owner(trigger_id.clone(), authority) { + match is_trigger_owner(&trigger_id, authority) { Err(err) => deny!(validator, err), Ok(true) => pass!(validator), Ok(false) => {} @@ -1540,7 +1575,7 @@ pub mod trigger { if is_genesis(validator) { pass!(validator); } - match is_trigger_owner(trigger_id.clone(), authority) { + match is_trigger_owner(&trigger_id, authority) { Err(err) => deny!(validator, err), Ok(true) => pass!(validator), Ok(false) => {} diff --git a/smart_contract/validator/src/permission.rs b/smart_contract/validator/src/permission.rs index 12cab95c2ce..d3aeb1d4286 100644 --- a/smart_contract/validator/src/permission.rs +++ b/smart_contract/validator/src/permission.rs @@ -75,6 +75,12 @@ pub mod derive_conversions { pub use iroha_validator_derive::RefIntoAccountOwner as Owner; } + + pub mod domain { + //! Module with derives related to domain tokens + + pub use iroha_validator_derive::RefIntoDomainOwner as Owner; + } } pub mod asset { @@ -82,6 +88,19 @@ pub mod asset { use super::*; + /// Check if `authority` is the owner of `asset_id`. + /// + /// `authority` is owner of `asset_id` if: + /// - `asset_id.account_id` is `account_id` + /// - `asset_id.account_id.domain_id` domain is owned by `authority` + /// + /// # Errors + /// + /// Fails if `is_account_owner` fails + pub fn is_asset_owner(asset_id: &AssetId, authority: &AccountId) -> Result { + crate::permission::account::is_account_owner(asset_id.account_id(), authority) + } + /// Pass condition that checks if `authority` is the owner of `asset_id`. #[derive(Debug, Clone)] pub struct Owner<'asset> { @@ -91,7 +110,7 @@ pub mod asset { impl PassCondition for Owner<'_> { fn validate(&self, authority: &AccountId, _block_height: u64) -> Result { - if self.asset_id.account_id() == authority { + if is_asset_owner(self.asset_id, authority)? { return Ok(()); } @@ -107,11 +126,26 @@ pub mod asset_definition { use super::*; - fn is_asset_definition_owner( + /// Check if `authority` is the owner of `asset_definition_id` + + /// `authority` is owner of `asset_definition_id` if: + /// - `asset_definition.owned_by` is `authority` + /// - `asset_definition.domain_id` domain is owned by `authority` + /// + /// # Errors + /// - if `FindAssetDefinitionById` fails + /// - if `is_domain_owner` fails + pub fn is_asset_definition_owner( asset_definition_id: &AssetDefinitionId, authority: &AccountId, ) -> Result { - IsAssetDefinitionOwner::new(asset_definition_id.clone(), authority.clone()).execute() + let asset_definition = + FindAssetDefinitionById::new(asset_definition_id.clone()).execute()?; + if asset_definition.owned_by() == authority { + Ok(true) + } else { + crate::permission::domain::is_domain_owner(asset_definition_id.domain_id(), authority) + } } /// Pass condition that checks if `authority` is the owner of `asset_definition_id`. @@ -139,6 +173,23 @@ pub mod account { use super::*; + /// Check if `authority` is the owner of `account_id`. + /// + /// `authority` is owner of `account_id` if: + /// - `account_id` is `authority` + /// - `account_id.domain_id` is owned by `authority` + /// + /// # Errors + /// + /// Fails if `is_domain_owner` fails + pub fn is_account_owner(account_id: &AccountId, authority: &AccountId) -> Result { + if account_id == authority { + Ok(true) + } else { + crate::permission::domain::is_domain_owner(account_id.domain_id(), authority) + } + } + /// Pass condition that checks if `authority` is the owner of `account_id`. #[derive(Debug, Clone)] pub struct Owner<'asset> { @@ -148,7 +199,7 @@ pub mod account { impl PassCondition for Owner<'_> { fn validate(&self, authority: &AccountId, _block_height: u64) -> Result { - if self.account_id == authority { + if is_account_owner(self.account_id, authority)? { return Ok(()); } @@ -165,15 +216,25 @@ pub mod trigger { /// Check if `authority` is the owner of `trigger_id`. /// - /// Wrapper around [`FindTriggerById`](crate::data_model::prelude::FindTriggerById) query. + /// `authority` is owner of `trigger_id` if: + /// - `trigger.action.authority` is `authority` + /// - `trigger.domain_id` is not none and domain is owned by `authority` /// /// # Errors - /// - /// Fails if query fails - pub fn is_trigger_owner(trigger_id: TriggerId, authority: &AccountId) -> Result { - FindTriggerById::new(trigger_id) - .execute() - .map(|trigger| trigger.action().authority() == authority) + /// - `FindTrigger` fails + /// - `is_domain_owner` fails + pub fn is_trigger_owner(trigger_id: &TriggerId, authority: &AccountId) -> Result { + let trigger = FindTriggerById::new(trigger_id.clone()).execute()?; + if trigger.action().authority() == authority { + Ok(true) + } else { + trigger_id + .domain_id() + .as_ref() + .map_or(Ok(false), |domain_id| { + crate::permission::domain::is_domain_owner(domain_id, authority) + }) + } } /// Pass condition that checks if `authority` is the owner of `trigger_id`. @@ -185,7 +246,7 @@ pub mod trigger { impl PassCondition for Owner<'_> { fn validate(&self, authority: &AccountId, _block_height: u64) -> Result { - if is_trigger_owner(self.trigger_id.clone(), authority)? { + if is_trigger_owner(self.trigger_id, authority)? { return Ok(()); } @@ -196,6 +257,40 @@ pub mod trigger { } } +pub mod domain { + //! Module with pass conditions for domain related tokens + use super::*; + + /// Check if `authority` is owner of `domain_id` + /// + /// # Errors + /// Fails if query fails + pub fn is_domain_owner(domain_id: &DomainId, authority: &AccountId) -> Result { + FindDomainById::new(domain_id.clone()) + .execute() + .map(|domain| domain.owned_by() == authority) + } + + /// Pass condition that checks if `authority` is the owner of `domain_id`. + #[derive(Debug, Clone)] + pub struct Owner<'domain> { + /// Domain id to check against + pub domain_id: &'domain DomainId, + } + + impl PassCondition for Owner<'_> { + fn validate(&self, authority: &AccountId, _block_height: u64) -> Result { + if is_domain_owner(self.domain_id, authority)? { + return Ok(()); + } + + Err(ValidationFail::NotPermitted( + "Can't access domain owned by another account".to_owned(), + )) + } + } +} + /// Pass condition that always passes. #[derive(Debug, Default, Copy, Clone)] pub struct AlwaysPass; From 83e87f2dafa1253bbf0c7a004b3cef2c08655e7b Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Thu, 5 Oct 2023 16:57:49 +0300 Subject: [PATCH 46/55] [feature] #3953: Transfer `Domain` ownership Signed-off-by: Shanin Roman --- client/tests/integration/domain_owner.rs | 34 ++++++++++++++++++ .../validator_with_admin/src/lib.rs | 1 + .../validator_with_custom_token/src/lib.rs | 1 + .../validator_with_migration_fail/src/lib.rs | 1 + configs/peer/validator.wasm | Bin 496544 -> 497224 bytes core/src/smartcontracts/isi/domain.rs | 13 +++++++ core/src/smartcontracts/isi/mod.rs | 10 ++++++ data_model/src/events/data/events.rs | 32 ++++++++++++++++- data_model/src/visit.rs | 14 ++++++++ docs/source/references/schema.json | 25 +++++++++++-- smart_contract/validator/src/default.rs | 22 +++++++++++- 11 files changed, 149 insertions(+), 4 deletions(-) diff --git a/client/tests/integration/domain_owner.rs b/client/tests/integration/domain_owner.rs index a7badedd658..b82b9847080 100644 --- a/client/tests/integration/domain_owner.rs +++ b/client/tests/integration/domain_owner.rs @@ -271,3 +271,37 @@ fn domain_owner_trigger_permissions() -> Result<()> { Ok(()) } + +#[test] +fn domain_owner_transfer() -> Result<()> { + let (_rt, _peer, test_client) = ::new().with_port(11_100).start_with_runtime(); + wait_for_genesis_committed(&[test_client.clone()], 0); + + let alice_id: AccountId = "alice@wonderland".parse()?; + let kingdom_id: DomainId = "kingdom".parse()?; + let bob_id: AccountId = "bob@kingdom".parse()?; + + // "alice@wonderland" is owner of "kingdom" domain + let kingdom = Domain::new(kingdom_id.clone()); + test_client.submit_blocking(RegisterExpr::new(kingdom))?; + + let bob_keypair = KeyPair::generate()?; + let bob = Account::new(bob_id.clone(), [bob_keypair.public_key().clone()]); + test_client.submit_blocking(RegisterExpr::new(bob))?; + + let domain = test_client.request(FindDomainById::new(kingdom_id.clone()))?; + assert_eq!(domain.owned_by(), &alice_id); + + test_client + .submit_blocking(TransferExpr::new( + alice_id, + kingdom_id.clone(), + bob_id.clone(), + )) + .expect("Failed to submit transaction"); + + let asset_definition = test_client.request(FindDomainById::new(kingdom_id))?; + assert_eq!(asset_definition.owned_by(), &bob_id); + + Ok(()) +} diff --git a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs index 62bd93fe8fd..1140d74e853 100644 --- a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs @@ -66,6 +66,7 @@ impl Visit for Validator { // Domain validation visit_unregister_domain(Unregister), + visit_transfer_domain(Transfer), visit_set_domain_key_value(SetKeyValue), visit_remove_domain_key_value(RemoveKeyValue), diff --git a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs index 44f001d650a..a543863d26b 100644 --- a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs @@ -217,6 +217,7 @@ impl Visit for Validator { visit_unregister_peer(Unregister), // Domain validation + visit_transfer_domain(Transfer), visit_set_domain_key_value(SetKeyValue), visit_remove_domain_key_value(RemoveKeyValue), diff --git a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs index 04b756e3ca6..bfde7231e38 100644 --- a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs @@ -71,6 +71,7 @@ impl Visit for Validator { // Domain validation visit_unregister_domain(Unregister), + visit_transfer_domain(Transfer), visit_set_domain_key_value(SetKeyValue), visit_remove_domain_key_value(RemoveKeyValue), diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index 66cb85821a81032b3a5c59d6454bea056e7c3538..a88798ad1b6e04c4ae4f2edbf3f286c04c0f6886 100644 GIT binary patch delta 53395 zcmd>nd3+Q_^Y`{l&+hDIH`#<-5J+Y>2_)PIB-}74AeVr6pWul>c>wWv9*+b?1i1o> zG-!mND5$8xsEf)G5G5izFl3SzpTHazp5|QU(;XL z-_YOGKh>A%-|6LizW$T`rn@vW+ubUEvuCmU8~uCNcdi%R8(mvmPwHRmi}bHuM_upo z@AZB9kNR$X3*W1M>N@WF&GiAFvUhJOlu5ulA9dv!hPU#o%(pb)%Ah?hikR|vummQkp7l?nY+aOhWmB*L4B9&N7wJJ za@R)ot-i$lKCjYO@R!}MxSvs9bx&hET(7wg>)*J(a&6W(>2K*T=`ZS^>tE>G^h$lZ z{-(3SwM+j>-=QCJ9pSF0`DdXIJXh!ctiQ<@AhS$g?^>ak>+AK8^vU|i`V}G9C;A5c zLw%jTMqj0`)Zf?N)tBqDUC+CJ(|^&A=nM59T)SQ0y1sDzuKubY)vNVAt}XftdWF7- zKd-;!UgUnkz1{VttH?da{il9RpXYws{kwizU*LYy{kZ#-KH2@O`wxBa6YlZuDeh_R zneG|x+$6O~|&*>rk7uNyTPp*Bgy{?V=MEzO4NS~)aqYHhm z{)ArU+OL1+`p~sU|3QDAZw>tzl`?dX`v>=K_k7PhPqAl-r^xe?r_eLS^O|R|=LOGH z&m7OIo@t)hp65N&JRG`?tU8n$ zyx4E$@7MDTD3FAZFCZutf9b_7vzRwwzDx- zD0wCyYj8>kxiW6av`SW@BGp{t$up}!hNpp-Md7;ysmyE*$mtmwK^qdRU}lz$&Z=>V zD^J!K+Lp0C-U1`aWy`D#i~3EOSK8E9ahv+mHjTS+w0U&X#`qOYJFx1~il(o#bV9>T zHZs5sr=gk48EV9DUI1T4to#lwY<@q$lUs~sC_ANP?}id&WWeopL^+}ix8cnTq#E&t z%W$F%2U|7;SaPd&_#N0P16pistE&;;(5mOzJS|OWeHYpA8 zLw1*FmLy5poxuM_cKh^b5>$&|lea_OtR=1?R3{koRs_Zfp| z>5)rQt(1Nmdd{na#`k$Nw5wl#TX2^^zEudVEzw>2C!@@j{U2gZtG3V=1G*z6ao{{= zSfbIPZUHGQ5ND{Aqf}>U>p`zD<_vv3xRNC1HVp{lbifD8l|1H!N%8sZa~$x08Enuf_iGn4cD&nt$OrTBxq zmyaO@Wa)OA9#kleho)Z908CwcMF;#=UQs{J=|4f^*vP|Ra8lq5MP1pmvl9eB`=~&V z$jG1y7CH^?U!XuuO+pUzlnk9d=JiAo?~y7yE;Q-NR!(PcDiB(EWi@k!mR*&A-}P6G zzeDK(rm>OHPNt|_b3$t=M5T%!zuwE2?Df}8>D$Yf2shb7wW0`D=3YiS1K|FNCu zihqRh{u4|yw1Sq;ko%QWJ>svePTaM{}=tuReG7uYwkywXG zQl6~u&~>-$lhUM^!z47D;IJt?8JbpsvX-Y1{{6 zNulvwvu1tF6QBokMvcWqI-XPnbSLaAYZ_Q^ z$Bh^%r|$Sy%}5zL;$ikh=v8CRo{B0aX3nUBMnG zLUh3-(JjFJEH9`6K?y)DLr*b_Fpm-52w@J>OQh07UV2I1HH^&*JvTDY77IJG0zWMr zj-X;f@uhTfV0`i(YL7^|&k==cP@}>8y^$C?GIFuBid1MmvdhG#qr6dQ&E54u-`96H zW7T4HE3JO1aZf!4Bdgu0tCA$eiaFb9P3UDXL8L{oa1^m~?Wl|K>-^WpfUfvgJbr)p zSIhdaDB_@DRT#h}?Cv}xih^Ji?2zW8GXOtibX!RUGknsX2^Ee`Lh_Q)83{+hQeo!H&^TZ1?Ea=!Lj3*XjVf``@qNH|akU@LTksVfa1upIs84({P#FVFZWvKJ+-6 zvhpKmgHX-`aiKX6qj+fj!z+0c2?QrBm#2ALJISt@h4o8ms_UD;T;JYSY&ofVb z5t_T;Qd$1SXd)>mf;p!S;^&L+K%e->v!sx*&=2S~3+v&x*TTi%$H9fG8T7%JeXB#` z-y6j$Lc^9`D~56AE6qFp2V*-!T^CPc?}rZmF&gm|Z!BjU!^1hl>T!b@udy|ut*;ET zi+3y?rL5Q$8ouO)qW0zPWI0={BaFpVnYX zU3>3^Qgo`!rYLl6#g(DdwGCM1g_6>;JVHuQEh*DW>nr8EFBBE=Xxf$tMTfrW3n}rKeVX5g}+}grK&{qJ0;FWJf6V8;~IuCbJKelhjwE z*#6MX-xh?X?(vl#__npe_JtaKSHa#59s2Hlwoe$T>^ruxblRSo5SY@my+bTnD+?X| zrju;Mq8~4;{?`sg>JJ@xwX;}IpS4pa{B$8Ca3+OeN6 zgq$@Y^o(yeY-kKuFXkA(97w|3hK*7R4_pYUA8f9&BCuwZa`M0hHtFUVmJ#Wgsnosq zC`S)oIF4lBKG^G4Yn*=B(d$BO_IDyiw`Yeg5Fz+%iCh`0mAL)iT?k(!i^Z`l7Lopi zUyf3aet+R8dbEz95bLthJ(GU8ARJ;$F3V&ehnIC_?GQ00y9vQ4 zlikObiw&LG0Jc%I>B+u?iagwftwFb-)LOPxT-Sk(WM7HOZmib@p%^cox|nJwJZqF9 zi6~Fm_Vxb+)8xLa5ioTdzzRjyl`QC=4hu*1A8-a$EcX=uhB*V-E#i}YthEir4u~xS zSm4}n#()U6nQV)w7{H8k!9B>z#lHu#RQ*#-Q3uHsSTK-X62ZUm@A1cq`h%$JB*|>& zKLKAqxEA>2KLI~Cqy|`-dVczE32(lf4QKi`kiVD6&%J_S){_(|EB>aOSaBsw1z?w3 z*;~ra3NiC4mIq5@_|j$~btE&y>QT%W?mv=Mz~dsSZU)b1ioh^7nuW!xd)UoLOdZ7* zLY&G*vCR;t8UJGMiOX+bLv5UFsW@^g%TuQQ`oF~4=++3GZ?jK{%)6AT{|h+deA8fe z*C@v@_>jhwZNL4msQog+`J%t${FE`Q1v@U@9m57e`rKn7eV?KG4x#(Pt;VuRO#d98 z`{;A^z3f%Xt342{20^?b{ibaDE_p`^Hma{5sJirQ6_JLUVAJ!F}^zDCG z6We25snIH;O3e$pOo*Z;95AvRqI#;!)O>Y;2_m{S&+Y!xGY$ ztH7}wi^&Kc55A8{fA}Pr)l`kx`zY&())@H=2D#{)4{@v(|H)@52x5u+32yS|e6-9$QTB|B% zfs*Gx5!N4PZ!&g5ygz|`7My>g4EDUa{5S$~mK~!=AtgqmfH%*q6eUlvJ;5qU|6925 zI}_O<7Y0tHhc^vxnaSuFWUt4!H!=Pa3T&SFgfcGoP)&u3<_Hu%~&i?u}X$1HYH zdnsQ-l(65hHWS`bw!58N_sPXLBbPuG*J1jo6t;qCWK=ry%qBp-U@g;Ckh$bT_HV|14F}gV?7saP zzPy~>#?ZL%$IzF*hQIunO;Mv)z|n00r7oBAV)Q09i%TlVka=MVT6{;-gF_0yWBXiId%(t+Lz!xV)sB*3todENLln$|&TG zmswKb_5GB=zY)&+l+n(EIAl7pnIK#}or6WMZBpOdxsBZeb^rM`@TXb~`W(~lm*JAn z*>Z4Av=+|$#5X%&g;k3&bDj5ygs<5rz_kshdLWMU7Xb)dP? z7^4MF5iXW}swJeUyOdL>&O9cV#A>Fz)>1;c23WhplVV#LfnEcp@=+GagZMp>PC-WGO@w7!~IyMHwjwxBe$? zF=QWWBwpLgycab`4m@1W8Uk&OH-lAjv7l{lq#(B>{m!WdilY z@}F1})?8Hn#Nr3QeQwv}e*!yEfWrO?u`x?|5VDV8T!5Ggk<6yA5f}{kx&h+>U)KaU z^bF>FaMr7d9zU~dV{0-rWL&h^%f;XWFkNFr#SfTQ*9v7X%gp!7B4-N-(IQ=ot@CW& z`(HESUz2QaYP7J~-U4hlk^^o-3p6oe0v-b!cSf^7R-`3_!zyknAi)j#n}T?6Aj$Bd zNg7&^(I(K+$U+-DQP8n2Ye&yzX5<-3#8VeoWz-WN{LI?aYo03;vPdaH&Iqw^9bg?| z6QOPciAJ1R3AGf5{rd1d2iOZfXt&rCERm@gtfEbkGc|naAM7wG&km;;_Fcmdo?>03 z7ah}1_`N?_(LWlt;m4WMp6Qll3#@CLO1#*nC~r!O_HQiWaH*M8XUVC|fsYy-GI zQF#}s8xo;dks3Q$X&^G|EBQ!!vA)vKPKy_dQ}wNu2qsm#g$4xRAwqqB0q42g54N_^Z~-#IiZdUxlb&*o|*Yu~vBW;z2NIyLsfF(IHz9~m( zD*iQG$rLH=l)Up~&al#x#Z&FiD)d`>DEq%)EJM=tT*)g0oy52f$`~uj5YCQDwLI>? z#MX97Ju&|dB`e&qlkx<0+3L>9as&&zD%T?zewVWGjITjrKsV))vy$%Xt}H;(FjJNp z(?dCQ#@8Sb)iY8CI@MHYjRnkuM7xV+!QrE2_P3*DWof-4Uv0$ZUXWx-&6x!g`Y2Z?3{X40I#iXl$*Q*K4_@cuZd zVnNE}gZ-6f@I7fj1Oe^x40}jvA_iZkB#IRSmAmUCJZ8nmLHaKp1Rhq4&4c6sW`mV< z;wYrQvFJYpV_XWz|KB6vB{1QCD*QOBC29xD|61&2T|-pC)_{ z%2G5;{x1r@fbcgBFMn8(E50@PN{Nc`G4^peGP5TrH)2+Ja)R=UJ&!yhexIl`Mq28V zHEAzM6%`*Ea((?!WwbZ^&1B^(ETY5jPF3!vWn|+*Wil;{N+=qdb7%#2h(}+Y04!6q_iNZy7uo4Y1HlrbTTDydSj18-8#eR5>7eJPWl6 zY7Z1CucP?0&nZ{i@N?nvpi&mRHec!F0YHx>q+G)5mSE~bvBFmrnrK_RsvNgJuM;gw zl)i(}RiJ%jPGNOzIQ(}Q z!BUn=+I z+O%-95M4(H6f9N*V5gdNU{{hz2OuF2+19Y!~A{I}Ul^6P{I>x!?N4ffM<8><&5ug67J`97EV1-}~v?WN4BjDu5$? zaHJS6|H~{2X_`!Db^E)9ZlbOj3>ia_LgGxMfVieoY1ADCD|swOMtIVOuR-#Yg z^aXnIw`%fCp9%Wl!UOZ&y?i86^nIr&s+7jcu}THgO1Q;tWgM6OT$N7VVC_bJIXZY?4xgz|?J_QGCrTu%iIPoLa6V>6?Kf(S(c>mAJ#Wbb7cR(6tHy>1* zrB5J_XI#YNY5QImZCHbyC@h5F;hlS2ymnB@Xi_x|X)$KO^9XzfozXFuKaF_77eL^$ zU<;pLBYfXzK~eRm=FZwkUeuU#qo%V;=1~GzvO)Aeq;yCxIf)OPn1r-MDPqgC z=0QP#?!N;RM-M3l4L>3EG)Xn!=*v-N)7ieZIm%KB7i|)Shn0=7J8^^qa^!HpHwZN} zX{VU^n=)DaR;3(1Utaz%=g-rRo^~$YSllZeMeQl*ZvtyHfpL{{Vy9O zf>HksXt=dky^qE2sKZjQaPAJ#HAbB*x<{)A|C$#@-g(P}2gIrmYq8a5A}p^aIZ6+o zOjL)k^JEHS-X?xXRuB9wz+DYM)49=04B(8Bnv?QSo#@%>wAEfck494RGfF0B*{FPX1JAs!RNji;siqzw15bfgXYj#9u-Y z_)z_ChObNqrbcggp#BwjT2y#fq-KP|BA*;~tJjNd8ESL3Ua(Ac6`L%|GSz_cj$6dO zrDchz#%gzVNc3;4wnp%9V>Jz)+M>p4dKMAl^iM)fSxN;9>hN6o-*J;71YRBI;=JU{ z@=p-^8mpZ=li>uyr+IpVXx2ncYlJaw(wz}M0U=D5z;DB4WL9nvcLF4E*d4^VYC1VC zU1@$~qN)*;gxTtD|6^h?z)~i9462*bwlV)>9@=;zrkE!-h}{4H*(^(q_dVqykD|;0 z5okiNaVfPyJAWJCG@}OOWvQLB54qvbB9}7gInBnHthXO+a#MoaB2eb~pAwt1&P5em zk9F(LUQTuM^VeO=zoFS`Cv?m7Y_$n^5ALN7ol5K@H80tQP&y8YLvTmKNrsb_{wF<> zmy*vuBWMKthyKD)n!f6EOKQ%4hgdeHZbv-S^juBG$<|1d-)^b~uA>&Kc8f;@C37J# z6b2aPTz3lxBZ+3_v(!9~f09emXTC_EE_}j&Nc^^X-$UDE5&W&2sZCM|KT1i7EMr0H zERskHN$%!12gmkp5M|BPcrmew>Q4c`6!T{)7VUouwp$%R7GE?|JEy=<&THjxbjC!Z znS3OAdXEEVRK{UnQ#5amA+bTA=9I>e`ZAaZ9}}vGJe`|@0E!R+&CnUdc{za*p^}z8 z7K>_VA^G>eBThG0JJzKI=bX=^WoQevB@lzlMw87J4vP)7Z1x%MY?X$kpUf)%A@Okw z)$n1sz`q>fA`ObPt#!*|VAt&@V&lWD)YN?2&Nv&XTQVJHPR)pAFcXL=20$ULs2ZVR zk?>azfRH+3<*DgzYhc5~i%`0)rP{0uA$AgCYM2ynDIVlqwmEthK53_tYOobR+E)@q z?I1iyThsDM`jkjDHT*kQQ=hPg<^R5^rec}Yq{}_E%3Nf$R@=iwyskAw4>o#hwO0&u zzSK$>6zib=#J8>0Oyp^8BuGx1zk-CHYNIAHwj#XnBJ~O8g<{juI;kMUMeWp2DJ7~V z#ou0?kbo58fQK0Esga-sxoSXcXs^aY#eUl!I1h;DtA>+g!19n@KDh1k|X9gGtRnH|-}?0qqyqdFVG?vCoibfz2{0y|mt z&}=Ubh^zR;I&NGi%+l|PPdlm8+1p}xXZ3ywsuQST#7od<3-nND^(wi}=MaC)i%#rb z2b~zyS9ejn;*8SMUDVv{XS#J2fzTowX*Z7=}s>7s5$MelS~(*gTcS9JngBW~`d zjzh4mn|iyvxhJcQGGaj!gVj{=$tCL7xJQTkh-e+Hx|j7*N3y-5QE!-8 za4+;$Z^zf?y^&Zg%sy%sm>G9 z)&2;^T&i|v`^9UQs(0ZlsV__>w6m|8fZ(dW7&qAL=&R<~J{K_A8)@~A;`6@XS+$7n zrzW$XM3a7MGkgv0r)DJYcL(L>Q!!l-1*>q)6Rh(8C}#9iacEp@@26r{LtN7z6#XO$ z`(uvYCzkie;Cn;-*k8S~j$JBuy)1C|{Mte4b)x%V^&;^DVmOfkh$(Ehm3e9~lJ-(ORop*B{p=hSUU#`# zfTK33a2nM${|+@MrVa(pu~(>R;-chaTUZw72KZ?q$)G6Zkt3l~=SA(pdEfTY@LHvLff1Bb5h5uT# z;GmVX=~^Tmw&K@bhxm6^{0EAEFM3=L&>yU%Q`aMD2gOsv_uru6hRHW#%Z=)TI1nni z_V1gJ|Fsp@ZbtmD7s>i4ND<)s%5mz`rwy7aOK0~8u3{MCKxG&(ml;$gKZkq4ED z9ar2IqT^B4$sHp#SK%1{*4;cT4WLOWFI@JpTFtB#|6r>HD;UD>(Sjn1e7Q+%c~m_O znz!VuE8IBGGj%cs=_lbAC#$P;*gQCumK~lpOTF63=7oQltFCmThhKOe$`5Y6=Sd4y ziB^lSh^Y?$Ymr*5C%~q&?jMq|X}+?mj1I?zA9zhIB@bY;Womr{y_P{a9~X}=Q(GY@ zT?S=xJiK$6dbtx-wpy-kx_HJ~2btNO9N1e&L;3w?%ouZ9O{!0(>Sv{TWvbUs72V%e z6Ow9*z}x|%csnyZ@?G^XM?e4;*w5p?rL42$F9=Z%-|gj5aqz*&Y}7Y?k)Q{LN}AzE*CAIz29a-K^#yXud^# zI_g*mW|(f&GgnL(8@H&-qNiIO0QKxNf0-_(RH*OOq|tp@qz&Dwjz_w_skjzM6*b@$y9Gk+3+{VJ3++OSGKu2R`1DDIcy8Q)4iMTF3AQXm?{t zEMLJkiQD6NAGRs{S{xst)&B^~AjrC@jOpc5Xy#Ys5_s-MqGd9F8-?~H^RCL54=+xy z&ly&IuqXPa_1h4H>M&g*-ks5U=(yqI&rnSt+>gw+DCIvXn|!&}BC6 z?Mp>^p*s&Y6kXmU@y7WU!`&O}Lg_pWMB_HQF*4}Oa41+ZlG&nR7;_^!OW`;@#>U}R zJ5Jjf&b}$~eml<}m=cVGF>yD}vc#EFckS2un(DZK6UAeJ)o1ECN<56)Sb`xv>LXlW ztDjoxqalS$zCJVxix`X~|8d*~1ORz~5%LD)2&V{6z(pHzxHOBvNrzN?Sm*RM2V>>{5RHCJl>H1Cn45= zX5QlpV8CZ9E1ZE`Qw_L9TqC|Q7KaLZ`>?3=ALP_UK}{TP#2?6PM>L=Wl~k8I18pfR zb6ObQ(ttq&hAFB1qDB(=Q5*RImjtDvxuy#sU#0RimMc!A^7hFKPFH$~MV(NGnBvHhs@p}2$lx=b6oQ!e; z6t~IM_R2b3Ky9y-Xz~zM9oRaZmZhN6aIn_uZVJ(9?QyWnO&8GR*b4YCFe2v2fcq~+!@NHX(J#4`yk96}4a zF+?yVux)2;3t8C(c+wzCImUx=&?YvLcpFJ9jX7?v$EzIiVs!>@f`ixlGI%D77rsnh zA3>8$o{q%+nS4N2e2#Jn)+SIeJrH2%bwLnK?>k^WDO)Y%x$32ey2a{D9i!H0IbV7E2rR6tJhfF^a^BpBnSr^f)74Y6LKr@D{UNn0YAI z0mX0>jo2nGX~H`JKEDZXn(w1WCa|ccql8ccL{dWp7|*0#fS~}Un-}?5jm6oRNm)Sa z*QjroA znM=2?i_d5fIt+fxMA;(hK-?IC)LYYtTWrnd$*_W;f2P{{2YN`3CMXlB0-=XUd8*Ju zQWZiE)u^zVVO%jOVx;nk+zPz#EC*oAET9CvDUR!zD_jHs_5p8=3KU zV?JqQ?%O!8ZC_a182yS7#q;soFb6yJ2&2WY=DbaQw7dh7rL0qFQeqWcmXE>=L*zLA#77l!mki{F#Pf zr1=}u0FFkl0h5Na-bxSaAL#YB;2BtvxJH@^UPZzrnVLr%vH=h9xDAiEtOZZY_h6z9 zc&sOr&JT+V88ml;DE}18%YK^mfucbQaKZ&si^O9pc>%~WJP>&SAF-frO3-JpzBs_^ z>pNCny~tSwAI?#gG z7YUp>3*#&aW+KDTc7lD;0S&+K4s~)AYorX&W2c!|(S}F)+`Xa6aHAU|Cm1cZwZWyJ zB(c984_=B=QeBzbp}~`FwqZ{o32jxZ^)z+^jb!3B9Eyn6qx~0F=mIA>6eMXO=q)k) zBA%3=><^(SSxT`h=qCl4r7UsI0i3M!P2R)GPSqNEa{fk;I) zN^6TWy+#(jdBF}cIS0w@X=p%c0TK;^jA@p;MfRcLA(2wdNw`~?L)T2|ixq8o@<=P$ zXbX!5!b)ozCOL$mkJdxiLr9Yl0|ByW9&n)6`-3M>a6--@ML{#2y)n2w#8gZJomnLV zui%m*qM%khqI)}@+zyt}PI4OiF^joq^9e%N3jIraY$R_GjG(l8Kw~0gB3R!@5>wjo zv~IKr#C(ZyOgc6qUQ)cZ77jl#DFP8KwJperupr>s5I15V z#zKS~5=kSe1vz<0C_R>>Q)_6A6=QJ!3DyfSaMhXTe-}=2Y^~EPHh5DA23C|21M4RU z))L4s=)pJzY@gDeXIzyCsSbiiRh-lgwcSsZxvZK{q#Uz5R4$4GqA4a;;Ejs7&l->;?mw|?)uJQs=)?}*C(z=okAR*iiJ#9MtGs$>rhS$%z{EnM(xq#F-$*f`)KvKQ_L(p8USb+vvP-${h z%=z*;phPn>MaN%vFgbE_RZUC`vlOc@bl|8|q~^6wG2Y zsx5az49%Qi;a}Vh@HY5OZ5+hRkEd-53~9WPvq1+v^-R1U7Y`ZJ0Ya;RdIk`o`O?== z&-OLc!~CoP7QTi7a5m5!OpT<;S~?pj0^=}-#t=s!oelM*vw^x~yUXgDN>>1Eq}TB@ zO!ZFm((I173WVKK$p|OyM{)5%M}EJC!x_l#)`@q%-cy&Kzk;8%$b%kJEPj#{IL!%` zZw7f7%NjXnWG4mu7Ps`Xx#cHraj~rvZ&9C1*^^Ee96K~8Sxy(-@QVhWc?aE3P7#a> zab0Jg-4wH!0~!g-N-2Of7291Q@@LOXMUX~=TqVB!qaZVWhjzalZ}=07X*Z& zNk}cmltxbKMF^WBoQkj+K_d(z+y-q`PsNm`Jc|GAON=s3Y4``~p6bH8GcGoC;rD7u z@-A)9t~@sx>QJhtPL4^iv4E=>UN79k6*If?u3}?Xo;e^EZ_Lrb4T$RzMp6!IZH$j@ z%7BY49QC6W=D@RbXN$C{_V$7JY;~>{=s>+PTMNYDi42}Z3P-NQUAR1Yb2pwUns?)V zsDZy^mUQC{^AoH#M1HBxK(x!LaTOIetgU#T-S@r}Xd+xFo1g{T<*Jy7Bb3d;aSE!p zmyfQ37GjLHr#JZ`+0RNnLD}GSHjEL{R9Q;gBrO0S(h-3i*b}NQD zL^XtvmIfIprb5D70ZnJHq6hHCV)k!bx6DzScvF#FBWuQJT00vkMpJ2Fpp$^Ih&Y;S zu@pU0OKV+HiFP<$nozi03*e3T_(lVLS^Q)?+MvYQ@sny%hHvZ|>522{Uw z`c*L+$e65O_NeSE;z1TXK~^oOjcQR*TNe|jy^Nlbi=|F^;VzgH=t=OiHE*NZx}U49 zJF2%2=HNfqO-Kr1*%_i!PZ%`kC4z`4(*oTv;p@i5e<9{#n;0oWS+(+=Me-eASKhLt zrLfhJ^7#>}U8dLSGAZEAZ5cMb0j!4tPH#hTH7qJzjkIK2rYlHK5xY#Dj9HA*T~RWf zi5(_y*US2V(Mpd$%FX=9z-vu})w2krVbCU;h5(*?jEHcJK$T@7)lQx1!^5E7^NT;yYX+7QGB*$OOi1jJ(O$v1h6{{@x(ZN@Xh2dH za@?d*h;frja2Pl3;Z)YW(ITxEPi{fX{_hY+@ZNTQydL1if;l1%HKWdDV$^vqxTZVK zUlSeAkpoZGM-430a3~&c_-!~5M@?kUJlmPYC-W) zZ*HX3$5`b?BiKOEFh3hYY|I& zQr-b8s{o4oU{uQoYI}^7QzqP0wer*kxGw_k?vT8A2wo=|$0q&sz*rjF%NN~%ZU$IV z)0INByB&pSZ+pAC`gVIsS^t4o|Pw5^uoG?WcM zXkEGLcKPTB@zM#?kbLOmHN$rq4{CU^H(Cto3y*fS_;+7EKtAi33EPHl1Bk7Cc}t(X zuwRCS)(d!tRe1aH25!_TyM~F%OL+s)w;!)}xx9SdF$&G-L~UzpkF~Zm)?(`LriLfv zw~q|K=5X(HBC<##KkcTBy` zgezi(r`TqA3ZVqFwdI#$Tj2;TE1V)&jAj@u$zIK{7T75@R(Lrw?al{Ds0dV(rA`Jr zj9fZ%8aYsE0# zLI|t41<^XsNF?EuKsW|Yih|%Vf~1om2G3?&-liDrVYD$4EF|&~?JUR7JjX%gp%?Ze zdM!o(F+E2qhgnXxwqNuZ$Q!`%ef>b5o)Ak*U{z{X=_j`YIy4ab$FbqB2l7ff(XwI? zzXBF%>|owro&;0P?QoICiy?z~pi7)Rknp@xwp!`QRmR)KI` zMs{NG9xA@$#p{DP9Rk}un5V?Z-3AO<6vp~HUPKLn=c!t>9D)UIytod5i%{W>jqubV zSV-E4$+^$WMfemyUCv+VM)#eJs7{U+2;kmojsOhIpmOvUxPzF8<2KYEegwI>*z0jn zKgkm=;*+7gp}h0skXs-YQ{=Y6A47RI&H!Xyfo%iOwfah)VuBzV#n@cHfWQ_XZK*^+((F$tHtHw`Er%?udjJbYV#rwxq9hVvQnP>+gbw{&-zQyG{6tc`EskI|u?mq&2iEDwJ)g5N~f zA~Wxn$o=>5@%Wl`52u^S$)hCluA}%iIx!SCMk4PqhL_=sjpcYLHJmV(KLhH*CHM1j zbPyu*LEe?ZTmQ}PQSh{X1B^EGF*O{kLP!~o1z-&<`F8LjPPg74eV89YaL*(BYWgb- z+a0(bVYw1K^j8>S;huoU8@*Wh2&dzIiH~wREjaj5N!@*q^7Yj8t_6GoQr8yn8xW+8 z=eR;CMvvzYBKUDU{{kRokHMBaDt0`^v*?cwz~h7+s7m;v+;CvfaYPq>gNdjq^>Li6 zz&*vsc?lFcCL=*o*>pw;5c3q zZvO;N0EyxL6Zu=<%{!C06M-1~G!KNcCiC5NKEpGWA4YIuD!-b82^C`DJf4Jv-7oTs zcm>!eUYI7Ey=xjZTU_=GPYoN>d1q?-4Kp}hD_K2*)1~L5R*+rD>9vIMg?wi`IhZwQ z3g9{dJ95M9i35$5>O(I_t8 zo2x&c-$wF*agH5QdVvnCq0>fh%qNW?cFeEC73rEbH`a3H4lv*WhzYe|S}{L?0#YPi zUdX#BDKvC&cvzl5s2w@+^gU-04*_`gB93!PBr**};fp*6Ma-<4v4eeT+ViPrz>@>Q zAV(w{i7)XS1a*a|@Fk8tMvFf@FJ7?AD2Q6Jh@FHp+R``Qm89*{NC62E)w^3C42~7I;JC!TQQR<=F7}_ z*^KnKJcUX^AI@FIJ9xpT(JQ%bsS}JvlU@#oZ;R9kR4e+E62#N1r8;R`#_8~5+!}sW zcnMuX!9cuLx9xDgf)^S@2-&|RlP=ztK_winWN#+Yxyf0`#79Z&b^F%7tZ>a zzvc$kFFxfLHKDG-6J{X0_6ajTxp*CzPmzO-aQTE;tIzoBB;DV9!S8Ht6~e3?ga)*4 zSj*W3lZ+`{ee#)gPFdkGU-G+%O<(WeUG3_;R2vOBRPG>C#-1@GujHA_?qBg&sL)S4 zc`kzBF5Xo>0Irx5Ncl_sHENgCDie3{92;*O9b=?$@KTT_|S6#*CoOR z4&V3m?tfA(j#RvTjh0R10d;!#MW&Go6R#@T4+v(e8linh)yR>pagESs zbB!jfo4Hm8t<+<`aO@JmgwY6Z_-ajSTZ8y@r=}9&Z@RP_6w9gtG4%Qoy_GL=JX#t` zUgeP`^F7+_8i0R@(b^FQ8^mcdl>{jx)_Z-jFBzT62$#icsRZ+FqPEHf6!TLxGAJge zX^$cB8rmZWo-)vmqv1CUtqaZh2ZCBd1nzV#i~hzB)F2cc49cJ)wS3S+XZW$9L<4l?OsyL85T>LIa=FMHN)uaqYItTToO!Y4(Qv4}^`+V(9CrQuQVoML?CYz2 z#XQs3()v@Qv#dw@X?bjV_=f&kYsRLFX#=$3IO%?P0Jb>47HI>ug-Bd8Q0opDb{SBh zZ#oXr6g=q=?lM>#NsmD+8LFkSL@=K0TLlUlni-}t>Bt6R_0Rmi@Q^FDiJW~D-hQpN z#)(r_&kWNB;*Cs06G!gS67y-n!Tg^(z4$99P^$j*3>rqJedZ)*77kKaY4RA@M^3N& zYbR=*wC9|(mWM;XPTDr7^=_tiW}19I(`lvQoD}mv=W(Jsi8>sALSq?Po*CdYP0Y(y+Gaq2|i4A#Lx@h=_=7tqdN79*puT#F@=?tIB(@xX_ zM~^+KwL#D{U%Lp5y)j?Ap83D`7>pK2u!HdQqkp$3FVK49{BO*7tq+?KzIwbijp0Vd z508Pez2dgVwGDwEJ+$P;YDS7Y_wV!2E_m(t{_vm))MqorlTT=u|62NlUg?fJD=1#;&wseByBQXu_>Oc4aEJ3LzA_GpmgU`knZW?lnlbD zQ?wCI!a7sC5$JxHsojE-m(J4ms{YEeni1|cM@uF#xq6lbMSZZznb7opAK zXGG4s$4J8v=iRr>5MREe4Pl>zvlnX@Gq#E@F{FwqOSI-Vf4qE&wtRTSYin@j)2v*C z0E;7Zo>@#u$0&h%#*e=fh6Mk&D#;XGSf@Zl|)Y|E^kkX|YbxvcD9~KR;8+MOmk8 z5tZftUA6T5Vx6J|OHouiqo{n`7hNfCeN{8^=UVKj+E<2KxK`IrK$3sIN`K;}E~?oU zWL>G)`3FkXl?quDQh~L2-J%6l6oykBfwGJCC-Ul4i?UD%RMu-tRKcsVYz0;2MmmI1 zmOVfT)PFeLC!16y1}??0FBkbswM|0{3Q&wrCO}qK6rn-;R4@6GWdTc83+sSvv_YDm z2~tcTaI_MZonpaj(597?L>mT3I$)P-dSQ=L9)*TDI*YCbpT}Qa~647 zXM$7_2ri@$NRbWFB#O56YKL3FV}PLzOTa9BP7Hb-!>X9l>~bsYa+znME+Y`yQ$?|j zHb};qAe96{CyfBI(*{XD6QtmAfY@y~V1opsx}8B_F~QgjJZZzwMq-^dlo3e0Rnye@ zBJc*tjB zjW$TbD6(;CnOsI_z<0?CvE>b14_WYrrsZc^NeAp=atpb(R3%}C&z?%1v_WVqs}AC- zIv`UQSgoYpwK^aLPXY@({Dh^*2BF;~fFwqAZZW~o{tIB1E)e-8q+2H=Eg}SVIod(0 zi~1>m&>1om+h~K3kGBp;F@e}T-f4rJrSJ==A{)yA8zk;*As`r=fhTR4vlMz6fkehb zu^6%pZKyn5<}k50B->tWvF9v>Tt*<+2#`&;LC#XVmBbxe)>qgdXX)31NdU2R#YP*% zdzKIs6HJXJIK7NC0VUb8bHFZkmd-5u6ZF|#bJ7MmOE*>!h%F~m7h0{fRbZrpD+$CN zi$ykw>nu%BOq{Ss(b9$DjW@Lfv1OU2<SvC!+v1Y+M1c{PJb1ucp=!b;Y z$TOFS8EOq%qkj0w4T62TE*h<`&w3_HLlLcIr?Xr zC|s+>JFQ_UcE93G!nORHS77r1wbjBN@3b_vSie?l8ZY(w85ov7C1$ME5}XBcR*>y>T9b$swA0?dr$0}*|ng^1oD6AM;r zT53uy;7*#7&jFZj&F5ypcgU{?p_LfVWQU-BNU&^!2u4ZT_VL8TtORLToRL%VnC#}} z>C!BTNPyjNyDl5W8Zo>~YZ5PQnh0Q|;nYP5mPHhyuujEI;w^*f%-)ldnqXOD=A=*1 zEW69`PFxj)I9{4^XHaXkqe;AF2%eEuBBq1+&H^fwYzcRjSi4qhnP3^D=OQb?GH1`( z7|R$wo32Mb(3+=PrgNlrjEI82c9|RzmKh!alnjZ;tXfd8Mi}d~?D&EgP+B)997mv9 zg1uebxK7Io7E+GWoJ)ZVJubC%F@2F@#{k$S7O%s4w@Mserv;UQnWE8$T0kkDDSA-2 ze5SY+AqL$OA8J8o#Y_}*i#FS}MtHH|6C^1Gv&3OQ_=-s8c@zh(12cOz~XhtC({EZkS`ikXsK!VuyPAX)g_n}n3$nX9Oh1nREe^Ww3a=V zKv|IsSTUR9!8FWL)<*{LtciRy%rp1be8krUn>$amT(4c`E~Xly%;jsu6YI4R%JS#M z;q}@zP?MLIYu83?f1WUrS<#qo7Pk~%m4gra#mRE*ab@bW;qf2Cbp;2>fel)>vu`Xn z3Fm#HJ;)lbLIv1k+YQx96ZItc&Gt}Q-A4+Kt`hntIAT_d&YQH>m##)Od4%R7;{O_s zEJ}z$LZt(n3U*=zC3=wvf1J6~PAn)xBC#7r%G@$hx(Ut}>+jo$_|4kv{JAvu)3gG1 zpG2Ix17|2OlUfWfp?rJvOnt-3x2zT`e_fsYB0JwQP3#V%=M%|N1OBCUzU*!bzu&AP z1Z3?2V8t72#F1~cCUJ$ONF**Ju@Z6rJ~93S%@BoKG(GqRWhR(q)d+}zCubv4PKh*K zqeO*xZ;RGiDJ~TUwrFX}l2ZI76Rl0AC8m*ahf3|oA?waf<>J-~ZMM6LrgR;kbGB+% zCry3}U-izaup%Vh_y$h3nOn7B(#{eN4IN< zzA{R(&6N_daJ$wrSU@Cz)H9^6m=bOKXj}NmcC9CC4{pI$DWSl2y&QWFaeLyW*G#N8 zN$tnNWHZaeh_B#LEf*zUX*XmNxYw-Mhk!Q1@GgqPFp2ui7J|a}MVqg+KGAC>jKr~R z>KakJLrd^cn%&wJYsH{=XF_xp8IR;LLU(UmD;E9%xu_&KJ8i}EHKJ;pmL!}zwNzGW65$lMyv zKp)H3TI=F2!vx~rYmfeKGF(!SzbtrZ^hneeSP+qa&UNwyGFh|EfyF03`4D=g#r&PuIboz(p@HT-NPHoMNz zwhA%|FQjdH(hd@*xQH!-^%J3}S}u-%r*%mAoidZp$}FU@;uB-Oz-W82nKMZ|_`Md> zt){oo-4aLPhXA7q1iY9_@dEmx1xgkMEyc^|r#=#PekeZt9(=J!$fJ9-L2SdEpR`$G z*biDi<#k0Y{9KC{B|EhYanWbk33G};pW!v#`##iSL@VeP(I?4?*lx`$ZrZEq;@VwW zic;{aFjZ%Qn6eAWS}tDQr!{d~n%FE`DZbu^ z?J0{h^Y?3a+R?c`QuLjlwA)x*nWdkKVKZ3D>v?hi&)Rhu=39T(R%X(ej5fcbz;>xu zQoP(skOtDEk3{JK?7Ni<{U9dpa?$;uc4yX)G`rwV{F?}<59u$#Or?)v`k`)KLXqua z^Fi%eX9+=jM9U0kQh*GsGWxb9y&Q4d0F$e~N^$!k?UG;#tx`z?z($)}3sPeg6iySL z9MVR`RMOkZw#9h#=`~{Xhgy8g!Z}o*rE7{1|BFRYCx68pYmTaAfnkbA1@=0#a~ ze_DBgqq6uz2x^OaEfDXovUsasCCFq1wIH1=kOseL{`j5rs5DGd>-A~r(b+G${iY>0 zK1Mk%Q;@MmCI+VBf>VgkrUWwmF_H>TiU0hjHK|42*+RYJH!VGW3E}kCq6W*$g#UM~ zb=wuRWe{W5Y$d?`aOPHm#bj%zLH5;2aW4uceN4>9t`-Hf>nPz0{t)l|uCs? zy~i-c+P3dC$F<9p#kw%loGIdi*EW_z`7E=Nae^=1ENq=Z# zT2zsdVh_tmg>?<-W0Y^3c1K0=AG9JZl1L?vPyf&^Yh4$|q?auUZ09QZtZ4MlMRH`; zKPd*E)Do3~A~E8m7Ko`^L-ETPguAu)p(O-wkLDFNO8PTh2A%7%P*xC#-R_+>NF9$U z)p~$HY~riLY1A5RElw>47Q7M$X~ zBxbX?N>rZGt`XP&i31BuPn8LFN=s-&gTN*YX|hYOdXZgHaZ0dcXFW0XPb~(^)}lW# z2&=^EKebN5KdG48oJ8I)Qm2I!DYm|3k1r7^r?ucC$;v(Oj3 zxJIM~oDG!X7e&cwOo1gYicJWeWiO&sjEIFkc2-c_MY=g9y5J?mGrPn3yOjg6&)1RIH&~I?|0vOoxE;>=ljn2 zzH>efFI9E#ty_E5t=m<%Vs>o;uuseHf@eA0^w<-ktMszhv+1$@;>P5iyqm|kWrv3! z#Lfox>#~79uzD&YEu5OQge!@his%~pdYJ9ukmiLxY+Ze1IMpcP5!Q~5G>a~%ulZ)t z)eLpz0|+KJt2Hqi{Ax|Tm-suLx0;S|%p>$IVk-3%)do%@4TM95p(2zo0PtwiHxEc+ zSsU>~Wc3zg+P|D^;eHYm$soN|_iWKt3(>&9c9bGTV#E*Z*SlL2oedEg{TsL{c^`_Y zu@QcKaQZdI+=?C+RaxhX26%L{DkMjG*8rvu^G%y+MX2Z(vy17%9CfOLnpH(mFYON% z!>_ZLLwOTN)qkFVk zP@1TR#C;~i%+R(i4#nX>KmI2v_E*9vYJX^a*m+(eqqTK2j%uW^rlZXh{7PU*K+wSi zbZlFij#S$k4gZxC4*zs|YnYgfqidVPL}GW(dPKJSZ6RauaM;U#^gYFv_4}x@gXlq# z7Ez35uCjG6=`NDdFEI}56d|aVv$+-1U+mOx8# z+UJcF_bC1%Pqd5IVX6?@$b2PP`w755w$S&W>{yE=_V6EF^;SpET_bKtyYPq(LN9BC zUzci{Wh>8W;Ps*K&}y=@6McGWTm2UHcokLCdQ`Ijrf&(iJVv**6Me`01?9%BxSAc_ zQ?rW5!zz**hVUl3mOb_Shc~G8z^j{t28Qr-hn$_GG^2LN3q=iQ)~Nk4YKL~c zsO~i*j2fXMw4}YjT+hq1t^_*yB7GV!l2uhsY~xNO+0nn)>#7`0v(k}f#f!LzJ*-mU zpBXVT9HWlWI2G!xp~=yrb7T|iQS=padku5#P7NQ2iXIxm;o+z(4MF%(buKFz;NL*k z(7&UFFJk>GEwDOT8zbhVZ(((hU)cgb7h0RlwDqoz@qPh%mnQW_)c=Sg>dgjQz_DCv zRwC$g$D=<{POKOl*}!pivJ1PkImTni!pc|Zc&wNjY0OrQPph%JdW$f+y@MzdU4h!2en}XCG-$g0Ue;uP{}8Hh`|GDd6(L* zWgmNt!wvk0H*c8ZF0kMDlija0vZpu`-qM)08=AY^0&{&BdC!D)5{+vSExbk8Ztvll zO;-*>O~xbIMs;t6CQw{&5gu9nD9|i!qBgvbs)Mp^4a4+y-2O`)z13Cp?Wxi^>ex}W zmF#KYKmHL7KYm}Qhueru`lYv6bj8fgN5WNowQ=TN{}`?6Bl>0p&)mF%wanU>#R4a8 zp4bB?ZfFYeQv_IrX$obm@BLH6K#TTUxWoG-6{Lv48QQPsEz1d}R#k>+WQ`yftT)zG z7EU}+n_;F?wM48!a~xw89xE&A_t5zivDkWm*I2H)G~P`1pa)XL=tti1S zEFl9#DSpaYHbD54eZFf4iuq=^j|~!vS$W+@gT*6?*v~6v94#3pI??zcqOEd(W(|SN zgR|~K#0-H)k#W$4=9~;kroKbfXUWG56}@5lylAKxtKK-^Wfc++#fuWRyt~eq?kYx!R13c~ub!@^7e|SI zK}0GTE%>t7{i6k;>Jx7gWeQ&1c{D>f?V!aC9@t}HiPVB8c|ymC{mLHS(J{ip64$$9 z#WFaP#)->gPFT7qs99Ba3-J@z4z+XExHzn%)GMPpN;__?qFAn1>l+5nPSC^SMSKP# z1VB}LEBLigz00Us$W+f^YrNS$HOIAd;qIA;vxhntUp?{uL&bW30 z+@DorS(OPQp0gcLR!Rl*dO*20!&wuqR~h!{Y;wk5n-K;Seg)J}boT@im!d~*YoK7| zh8{UEwfz&s-pIEsny9Ff9HrG0#lNGDTlj!1%g0*Gy;Lws+&H=3!uLX3zz8Gtmhjsu ztAH@lZVA7mn#nSR>Gw$@14H|!Oz~`ocX@Ea7?Fv!F)c*z(r=l9Z_iB35~DHx*JO## z{p<9U{Cx-EfJpBJrSzWf(=3s#Sl>cx<3&N7(Q28$y`iWr+C(g-kQI@;!FYed1CvV$!N zwy;OHVk-$IzWc&e#ADiDS?E{S7>Nxi^s9DPL7`to8&SCY;)pQ<3~bPu;xv@M{OCgo zMq<2a=12?xpucnq0HD8g2>_szbTtAD38Is9GosKT96cD&Tz>5OFwl%ugnLofwcfG# zuGFBbpm2Zc`m3Py$wlkidUvGpd&F||#es9gK;?bPog*eiqdEBEJZvPG9Rt~p4Xo3> zPsiqnzbPlEXs&n=PjUP_S1eIJpuBlvvi&5lKA;vF=?A{!^F%KNBGOMzG0$G7WA!EY zLmIJAB+xzc#YW77owLQAcw}T%wwO;Imq?`!IpPW2c-ff)_$lh-67%i3qR{JjJirETuRWlZgLs3wo_A;5+ z4nrH(n;bYwX?bFRl`p~JekO(|rRPIf^W=$xwlkKlX4qiBXbWBEC{Ccfd~pXfNJsO< z8GD1JYgk4EmKVOMhXR=i5&ru&{wL+cb1AFxQiH3Ar_$wWfkHEgla0pn8D3=-}n-L8(x`k z87{`8Nz=RvstQ3=)OQvY42EVradL*zmWh+l%f8?hxxS+1qE3nU-hzX#_+=O`bp6*t zj_1U+zQPp{(yWbocI=HbwbGMJ++dB}U(sI6nj~CaQ}TTOD+E>-I&atn>bLL}d#%zOctd28llk z%aOq#$dADwwcvpfAtVM<;b?p?DBM3=Rfi)d~V3tQMYi zR3>|4vnZ8ekMm1W#&Sb_7sS9X;TWkDKNa16kEp5q$)e6*Xd3uJGy#O?Mbu0XN)nK$KX&t2rAg$w60i<=5DuA?(QU#FKQK|r9KxqPq;%v33ssLgj29dvlQ~{(_ z6o}ATs5JGLBC{@lT%tSggHQ;A7WavvlY**LU0GUX1_2u@OY12A%JLJX-Y@v7HQ&## zH?#5hP~Y2oL{*5g-{)8*aLIfh?b|Q-ZuS@Z#glNV4v2f-IFc1TRMUDAYLzGX}ChsAclj~vE~x1SP^hzHepe63l% zL+)LJ>G&dbJSwK7HbGYIYpOG&kC}OA7z*o^Y)KNAj8O`R(U^r5b^5t%Av!9y_Tafp zt!`lXMRI0|0-78js#lQ_f#drYydiFcq`fY(suLY}Q%q}RBYw9(lLyll7ZNl}~Flg^C0DqEdv!wF%TsS&nt19+|~u^GYpd*ETTtF)?JM!%Q8vif9NpX7a zm}P#@O8qy7woh-5bok8xs1uvhw%L$R&KK+S65#UHlMfn^Txa!wz4^dbe61rP^a4Qf z+GUD=oQ1!)=3jNX8E(Gx6P0We>7hRY)KQDQ?lY>}CK8l$^f8>!Z-7bCFz3%OC|>-? z3=%Zh!7pj@^Pv8o3gCoZY{rPSKQ;3db^mRFpZWy;K3eSU-_ai&?Q?*7s37t4_wc7_ ze%}|(aPy9@)x^!-Z>f4a5^SIs;Dnw6g_b>WnSl7ZBq=G=iOv*ohY# zJ_JRamd>6Z;MXcoG;vn-0)P6k@2wZaX2txHYG5RmR__qkaNwn9l}^5WJ4Cgj?4&6# zLB`zaTk#UQa@$%~0rz786ozE%uhOxXS;kzKxiW?lcZv!Kn6y(2hjU`57|+xpObz=n zOzrEtOC%~vE$w|-bflbDM7kbz+bj5?w3a&WLPwcHHD8I2zOlPSp;EbD-}c^Vhc8gM z5ri@-H-b<`Rya7N`u5Xz|B2tpZ^8$l?ea)VKU%8ejmqjDn%WmIki zqR?!REdUEpZXB=%C^vu(RBkZ95YwpKP-%_I4HaNiZm0mGazh0el^ZG`K)InpjLHoa zU{r3X0Hbn41sIhZ3@~KcsN7I#jmixb5TM)$ifvSG1fh(|jUbd!xuGUuRBi;(1}HaF zVxw|H1sIhZD!{1RPyt5eh6*q$HyB{35TkNKr43MSs1T!aLj@R>8vw9aiG^N88I>DB zD5G*C2;~<+RdAqk!*_6xc=-Rm1bV=#N^$?E5@^an95DLdlRyvA<447|{|5pnvJfbM zqAW%M6v00eK=)e%1yC*Q7eKiY)#k*)t+uH_c!PkV3Q>PX;}<|x8l6Re0BYWErJ7fi zo{^wv7CsMIX~|Qfqxq0kl|B!lga+voSe8EHugX(ni5uBZi?Er0mOH=r`DZkK@iUl) z9PdN?)M~3m{M5oN;-?mF5kIxCU;GT_X;sBf-|6?o*JiwweE37bwj6hVgk==g52Q#2wh${UxaBPq)c!mzP``X)2Qp}ek7y41pmrzZ9K%abx-!D)4 ze*6-<20+c{L=SN9eGY286Ta!^uwx8=6@rg0^?XE|zY+%+f+sFjsp%ss|GHUfI`TD? zWk1m9^Wq?zB7&NYEh^y;TU6?BK}?0-G4F!dsjQ=Qd!5Vj^gcew8+jz8C&0$`$1+U-A!PI&6l~T|Yvh`-Ly;Ct+iYT9`98}OWer(X} z5JOBIlGUC34^7I~XA)Ypjn)%1k(kZDlve%Z|2k zU!tYyF1v~UHIc0^_%``^_LVa%QO#gK+P8X;EDV9P{l^g5S=mjUhcXiyJyfQfD_rCr zDnA438N=j4^W83A-7pF3XHE3|aM=z#Lr2K<()^V|&t%Bzh)GB;ME|NOb&QOUT7#ew zyq0E;k)18;uXUkCGR}%44(#PM60Kr@hXGg5s}7#7opP29>#i`j3_A zAy44&Fy)Muldw15Iaa15Zq%c4PM*RS5T;+o%3DA=cAQL!3c%n<=+AWTIN1w7Hf$d! zJ9OtO0=5%v@>~ntb8`zy+{LBY?%cwHr@@kImf1f;=f=soeFOQJOzuUlf;=8^fz3eqQBiNGeVx^!@d`8Mh(|d*e&t_dting4fOOavZL8kMX%l>Q$X~^Eix6# z_G>1{0&EAXCdgQ`=U#eZ0yubS_XIiA?75FFPLQd=oa!ijqD(M*?x%?pWjZ*mn21+n zgOc++KszS37We!_^z;U@Ov0$BquG;W2ZYKd$xa>F)Pk+;nB0P#X~nq<7rKf^RgBL; zsaDbplVtbcTr|+9lVqaV^Wfu|D3EDZSPVF+9HL16|>mcz{6N60-{_NA95%l4JVzVRZMO>ve7FxvrG zW|2ELKX)1O5!k{t2=l*5uJW4-^PRZ`?8oOHgD)`>|A2R7XBUxCQ=DXakVziVGF~jh2&T8?Mp|ctjcond6XGy*h_D`E_7|Ah}pI&++EXC3^h_&CXZls*lU8?K#BL;v1S z%Mpq?0K`Fj{;B2=JwHvxUw0TFV>XT;Y|Q@AAp9E$*V8Z4WY3H@(c(D%Zo6Run#(}u`TkGGpFAn*>io5JBX0^Sy`X`j}X*6K%`>iQWNSf|K0LynF(4NfcZF~^Td&Xk>fgJw#%d4#dNLID>4+=Yu> z1#@$AO5m4(arU^~!*qN}_99ol6SeRhoxDwUsk8v@%*iQsm6VvQ@cX-f4SxRu`QAXg z%EKQ%85BN^uv%<=A^jBLHb}E}j23UA-VZ&KwQ5oO1Tu&=pryCV-re{PjBSKrWtr=) zC~}1(3;3^o5p>{o+0E?TL|@%5$3<|(cHmOsi=+{E$gX^gXZ{^>xY>i7Id{mxxH81` z_{klZ%o^xtP|(QPGK7+5%cQ6%ur*fRH8gp)j2&f6uw4*IdxSS3HUHr22!AwSHF_>$ zkX-c^+BO?=Tr3@)Ejx#H0H}e^&z609cMRedhw$W5S8)Ym8#5A5BjzB(33S^W**Q58 zR1=-!fT+TdONL|izi|ORvp?q7k#UNKAwyB zpaL=d=E=(8T@n8#%o@g2y8$*WH{WH1bq~r(GP2M}7v{-M6z7x!`x|Nd=<&xFU=qZP zSCU(h&Ef#JBiAUmV+s{Iu~5P+j#I|dM@|_*hn=!rW||&1qs)a_TQ%We8&p*6D#Q5I zxao|NbVlij;71uV(GMA{d5L<@m%Zln=eEJcSzFBL!hCII%gQZs<>eN*^mIHg1N*)i zY38~s<}Sv1YclqaYmo^5D{(vBrRd885FU&$mt-LAm@i|88_BN=Ait8`AmEL8y`I`+ z%c)U=gTOb?!fcs2a|pnrDzt^p7;7k(Y8UeTS({N6{uMot@i09jqbk(pDN=Zjb+1VP}M@&o@T)}-dJx=#LFvO zSa=WO`X|i!fH^f$p#;`Uoh}>6_>;_m-(?6dfPbMOya@hWL-Ybk1SA8pT-2~&E_vzr7m)(|5WIiSm=lr~YwWu5s{motE zw41CT^}yxYyjnBYj%#Z-Nf3C^UQrmO`|0eRvX@wj40;dHHH+ooE_b`^Y9X$luN8D0 zT&{rZe%!TS5rP&kmI+-eki5UgEQ5c!A$%9u)g7d*i)B*s3IqIZ_(y`3e+9n))&QA2 z^zCBV>*hl!x}C%P&&=Hzj>&O};R-xY9cB-B*ZMu{j{tJs?&s%st7u*x)~`ys3r@0e zcJP4xnB1jT2<}z1Cr_qWb}rX4RPAfbld+0rJL-Z9S?jYG$U?=px=^+^N6b=lrZx2@ zpLdD;!)zXyN6)&k=zd6h-Ewl=&OE!RH^{i9xj}f${T*o+%BSzk)7? z`Y)3))G1mDsx6h7*1rRZ$8b$~`4m+qi!I3oc2ggO&(cF>GTXWa!4w4N70~4}Ip6-9 z9zF&)8gTkox$H)dluMWO{zALy27m?^(r@LmEFz-FZt9P4J>c=wzY;54-BOuCBbQ1m z)x#ID4ip1Hkp;ICODo_NFa8(>}&ZLaHd~R6PL@sSo2Hlrt1;xUP7NNmt~e8 z5l%&T7tOv)mRpy&wG0n*(6TLn_fXNpR{%Y^R71BfrM)ZUJ(dp z5gs`gnyY*d_SrWrrEMNLUGb1oC1>C`<*X_>z}&Bb9;uQ;%sCbGMit~5em6(XiukfZ zYbr0?X!>+HX8jZQ$S88(Bga^8UuHL@A*t@m=)gVlHp^jzdm+4$dfqEOyVZPRd->PUssg`=7hfKcZVMCOU76f04ZI%`4h z0FGh2NiHnVpyL4JfrNFHW$GkNd1Er&0eB?fC9Wl>s@zL&t(M&^ zTmGVDVK@DW5z`}v-)hJNbi zr5SdU2j5D358%9y9Y+ z`0?f8E5f%Fp9kN4_*UYp#^=RXgRd5!X_(zqH`H!w#8-!~9pUg1^uk(sZKwyZYC5}C Wmba~$2{gV2e2(`v(4Fh#p#KGWprEn< delta 53212 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 T#j}9MQ;)}Sw2nG%l!N~VO=E~& diff --git a/core/src/smartcontracts/isi/domain.rs b/core/src/smartcontracts/isi/domain.rs index 95fa4f314d1..b7930106a04 100644 --- a/core/src/smartcontracts/isi/domain.rs +++ b/core/src/smartcontracts/isi/domain.rs @@ -284,6 +284,19 @@ pub mod isi { Ok(()) } } + + impl Execute for Transfer { + fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { + wsv.domain_mut(&self.object)?.owned_by = self.destination_id.clone(); + + wsv.emit_events(Some(DomainEvent::OwnerChanged(DomainOwnerChanged { + domain_id: self.object, + new_owner: self.destination_id, + }))); + + Ok(()) + } + } } /// Query module provides [`Query`] Domain related implementations. diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index 212a6a55ff2..f354b8eb8fc 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -272,6 +272,16 @@ impl Execute for TransferExpr { destination_id, } .execute(authority, wsv), + ( + IdBox::AccountId(source_id), + Value::Id(IdBox::DomainId(object)), + IdBox::AccountId(destination_id), + ) => Transfer { + source_id, + object, + destination_id, + } + .execute(authority, wsv), _ => Err(Error::Evaluate(InstructionType::Transfer.into())), } } diff --git a/data_model/src/events/data/events.rs b/data_model/src/events/data/events.rs index c6dfe09c0fe..145f7e6baa8 100644 --- a/data_model/src/events/data/events.rs +++ b/data_model/src/events/data/events.rs @@ -440,6 +440,7 @@ mod account { mod domain { //! This module contains `DomainEvent` and its impls + pub use self::model::*; use super::*; // type alias required by `Filter` macro @@ -459,6 +460,35 @@ mod domain { MetadataInserted(DomainMetadataChanged), #[has_origin(metadata_changed => &metadata_changed.target_id)] MetadataRemoved(DomainMetadataChanged), + #[has_origin(owner_changed => &owner_changed.domain_id)] + OwnerChanged(DomainOwnerChanged), + } + } + + #[model] + pub mod model { + use super::*; + + /// Event indicate that owner of the [`Domain`] is changed + #[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Getters, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + )] + #[getset(get = "pub")] + #[ffi_type] + pub struct DomainOwnerChanged { + pub domain_id: DomainId, + pub new_owner: AccountId, } } } @@ -675,7 +705,7 @@ pub mod prelude { AssetEventFilter, AssetFilter, }, config::ConfigurationEvent, - domain::{DomainEvent, DomainEventFilter, DomainFilter}, + domain::{DomainEvent, DomainEventFilter, DomainFilter, DomainOwnerChanged}, peer::{PeerEvent, PeerEventFilter, PeerFilter}, permission::PermissionTokenSchemaUpdateEvent, role::{PermissionRemoved, RoleEvent, RoleEventFilter, RoleFilter}, diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index 56a823f23eb..0853d8188a3 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -141,6 +141,7 @@ pub trait Visit: ExpressionEvaluator { // Visit TransferExpr visit_transfer_asset_definition(Transfer), visit_transfer_asset(Transfer), + visit_transfer_domain(Transfer), // Visit SetKeyValueExpr visit_set_domain_key_value(SetKeyValue), @@ -518,6 +519,18 @@ pub fn visit_transfer( destination_id, }, ), + ( + IdBox::AccountId(source_id), + Value::Id(IdBox::DomainId(object)), + IdBox::AccountId(destination_id), + ) => visitor.visit_transfer_domain( + authority, + Transfer { + source_id, + object, + destination_id, + }, + ), _ => visitor.visit_unsupported(authority, isi), } } @@ -706,6 +719,7 @@ leaf_visitors! { visit_remove_asset_definition_key_value(RemoveKeyValue), visit_register_domain(Register), visit_unregister_domain(Unregister), + visit_transfer_domain(Transfer), visit_set_domain_key_value(SetKeyValue), visit_remove_domain_key_value(RemoveKeyValue), visit_register_peer(Register), diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index 6bd01d92386..4e875a7cfef 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -1014,6 +1014,11 @@ "tag": "MetadataRemoved", "discriminant": 5, "type": "MetadataChanged" + }, + { + "tag": "OwnerChanged", + "discriminant": 6, + "type": "DomainOwnerChanged" } ] }, @@ -1035,14 +1040,18 @@ "tag": "ByMetadataRemoved", "discriminant": 3 }, + { + "tag": "ByOwnerChanged", + "discriminant": 4 + }, { "tag": "ByAccount", - "discriminant": 4, + "discriminant": 5, "type": "FilterOpt" }, { "tag": "ByAssetDefinition", - "discriminant": 5, + "discriminant": 6, "type": "FilterOpt" } ] @@ -1067,6 +1076,18 @@ } ] }, + "DomainOwnerChanged": { + "Struct": [ + { + "name": "domain_id", + "type": "DomainId" + }, + { + "name": "new_owner", + "type": "AccountId" + } + ] + }, "Duration": { "Tuple": [ "u64", diff --git a/smart_contract/validator/src/default.rs b/smart_contract/validator/src/default.rs index 2cf2c0f05fc..167ece90e14 100644 --- a/smart_contract/validator/src/default.rs +++ b/smart_contract/validator/src/default.rs @@ -17,7 +17,8 @@ pub use asset_definition::{ visit_transfer_asset_definition, visit_unregister_asset_definition, }; pub use domain::{ - visit_remove_domain_key_value, visit_set_domain_key_value, visit_unregister_domain, + visit_remove_domain_key_value, visit_set_domain_key_value, visit_transfer_domain, + visit_unregister_domain, }; pub use parameter::{visit_new_parameter, visit_set_parameter}; pub use peer::visit_unregister_peer; @@ -417,6 +418,25 @@ pub mod domain { deny!(validator, "Can't unregister domain"); } + pub fn visit_transfer_domain( + validator: &mut V, + authority: &AccountId, + isi: Transfer, + ) { + let destination_id = isi.object; + + if is_genesis(validator) { + pass!(validator); + } + match is_domain_owner(&destination_id, authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} + } + + deny!(validator, "Can't transfer domain of another account"); + } + pub fn visit_set_domain_key_value( validator: &mut V, authority: &AccountId, From 9861f46e4e894620edfb06825e12dab9c83e0753 Mon Sep 17 00:00:00 2001 From: benhhack <51188827+benhhack@users.noreply.github.com> Date: Wed, 11 Oct 2023 14:13:16 +0100 Subject: [PATCH 47/55] [refactor] #3874: Remove `IsAssetDefinitionOwner` (#3979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: benhhack Signed-off-by: Marin Veršić --- configs/peer/validator.wasm | Bin 497224 -> 504437 bytes core/src/smartcontracts/isi/asset.rs | 21 ++------- core/src/smartcontracts/isi/query.rs | 1 - data_model/derive/src/filter.rs | 15 +++++-- data_model/derive/src/has_origin.rs | 4 +- data_model/derive/src/lib.rs | 2 +- data_model/src/lib.rs | 1 - data_model/src/query/mod.rs | 30 +------------ data_model/src/visit.rs | 3 -- docs/source/references/schema.json | 63 ++++++++++----------------- ffi/derive/src/attr_parse/derive.rs | 10 +++-- ffi/derive/src/attr_parse/getset.rs | 15 +++++-- ffi/derive/src/attr_parse/repr.rs | 2 +- ffi/derive/src/convert.rs | 49 +++++++++++++-------- schema/gen/src/lib.rs | 1 - 15 files changed, 93 insertions(+), 124 deletions(-) diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index a88798ad1b6e04c4ae4f2edbf3f286c04c0f6886..86354b764b7b14072056766520b4c2091e1667c4 100644 GIT binary patch delta 153060 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

!;n3QC*VY4sQ_p21_8FB&Zc^USo^df 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 _Ig?_Ehu7u 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 Sh%Q-do#PFxq~s;m8UG7f73xX= delta 145208 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 HJpca!$W@~< diff --git a/core/src/smartcontracts/isi/asset.rs b/core/src/smartcontracts/isi/asset.rs index d3709c6ab59..d53e614b50b 100644 --- a/core/src/smartcontracts/isi/asset.rs +++ b/core/src/smartcontracts/isi/asset.rs @@ -422,7 +422,9 @@ pub mod query { use eyre::{Result, WrapErr as _}; use iroha_data_model::{ asset::{Asset, AssetDefinition}, - query::{asset::IsAssetDefinitionOwner, error::QueryExecutionFail as Error, MetadataValue}, + query::{ + asset::FindAssetDefinitionById, error::QueryExecutionFail as Error, MetadataValue, + }, }; use super::*; @@ -698,21 +700,4 @@ pub mod query { .map(Into::into) } } - - impl ValidQuery for IsAssetDefinitionOwner { - #[metrics("is_asset_definition_owner")] - fn execute(&self, wsv: &WorldStateView) -> Result { - let asset_definition_id = wsv - .evaluate(&self.asset_definition_id) - .wrap_err("Failed to get asset definition id") - .map_err(|e| Error::Evaluate(e.to_string()))?; - let account_id = wsv - .evaluate(&self.account_id) - .wrap_err("Failed to get account id") - .map_err(|e| Error::Evaluate(e.to_string()))?; - - let entry = wsv.asset_definition(&asset_definition_id)?; - Ok(entry.owned_by == account_id) - } - } } diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 988474ef6d7..a1f6c513515 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -127,7 +127,6 @@ impl ValidQuery for QueryBox { FindAssetDefinitionById, FindAssetQuantityById, FindTotalAssetQuantityByAssetDefinitionId, - IsAssetDefinitionOwner, FindDomainById, FindBlockHeaderByHash, FindTransactionByHash, diff --git a/data_model/derive/src/filter.rs b/data_model/derive/src/filter.rs index 42a79a93270..1cfbb9ce2bb 100644 --- a/data_model/derive/src/filter.rs +++ b/data_model/derive/src/filter.rs @@ -35,7 +35,10 @@ enum EventVariant { impl FromVariant for EventVariant { fn from_variant(variant: &Variant) -> darling::Result { let syn2::Fields::Unnamed(fields) = &variant.fields else { - return Err(darling::Error::custom("Expected an enum with unnamed fields").with_span(&variant.fields)); + return Err( + darling::Error::custom("Expected an enum with unnamed fields") + .with_span(&variant.fields), + ); }; // note: actually, we have only one field in the event variants // this is not enforced by this macro, but by `IntoSchema` @@ -43,10 +46,16 @@ impl FromVariant for EventVariant { return Err(darling::Error::custom("Expected at least one field").with_span(&fields)); }; let syn2::Type::Path(path) = first_field_ty else { - return Err(darling::Error::custom("Only identifiers supported as event types").with_span(first_field_ty)); + return Err( + darling::Error::custom("Only identifiers supported as event types") + .with_span(first_field_ty), + ); }; let Some(first_field_ty_name) = path.path.get_ident() else { - return Err(darling::Error::custom("Only identifiers supported as event types").with_span(first_field_ty)); + return Err( + darling::Error::custom("Only identifiers supported as event types") + .with_span(first_field_ty), + ); }; // What clippy suggests is much less readable in this case diff --git a/data_model/derive/src/has_origin.rs b/data_model/derive/src/has_origin.rs index 31033128b42..fdac1780f4d 100644 --- a/data_model/derive/src/has_origin.rs +++ b/data_model/derive/src/has_origin.rs @@ -31,7 +31,9 @@ impl FromDeriveInput for HasOriginEnum { let ident = input.ident.clone(); let generics = input.generics.clone(); - let Some(variants) = darling::ast::Data::::try_from(&input.data)?.take_enum() else { + let Some(variants) = + darling::ast::Data::::try_from(&input.data)?.take_enum() + else { return Err(darling::Error::custom("Expected enum")); }; diff --git a/data_model/derive/src/lib.rs b/data_model/derive/src/lib.rs index 6351fa41329..7811b70bbf0 100644 --- a/data_model/derive/src/lib.rs +++ b/data_model/derive/src/lib.rs @@ -602,7 +602,7 @@ pub fn has_origin_derive(input: TokenStream) -> TokenStream { let mut emitter = Emitter::new(); let Some(input) = emitter.handle(syn2::parse2(input)) else { - return emitter.finish_token_stream() + return emitter.finish_token_stream(); }; let result = has_origin::impl_has_origin(&mut emitter, &input); diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 88713128a6a..d8d6a7b1dfe 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -137,7 +137,6 @@ mod seal { FindAssetsByDomainIdAndAssetDefinitionId, FindAssetQuantityById, FindTotalAssetQuantityByAssetDefinitionId, - IsAssetDefinitionOwner, FindAssetKeyValueByIdAndKey, FindAssetDefinitionKeyValueByIdAndKey, FindAllDomains, diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index fb0d78ad468..95cbbcb66ad 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -110,7 +110,6 @@ pub mod model { FindAssetsByDomainIdAndAssetDefinitionId(FindAssetsByDomainIdAndAssetDefinitionId), FindAssetQuantityById(FindAssetQuantityById), FindTotalAssetQuantityByAssetDefinitionId(FindTotalAssetQuantityByAssetDefinitionId), - IsAssetDefinitionOwner(IsAssetDefinitionOwner), FindAssetKeyValueByIdAndKey(FindAssetKeyValueByIdAndKey), FindAssetDefinitionKeyValueByIdAndKey(FindAssetDefinitionKeyValueByIdAndKey), FindAllDomains(FindAllDomains), @@ -672,16 +671,6 @@ pub mod asset { pub key: EvaluatesTo, } - /// [`IsAssetDefinitionOwner`] Iroha Query checks if provided account is the asset definition owner. - #[derive(Display)] - #[display(fmt = "Check if `{account_id}` is creator of `{asset_definition_id}` asset")] - #[ffi_type] - pub struct IsAssetDefinitionOwner { - /// `Id` of an [`AssetDefinition`] to check. - pub asset_definition_id: EvaluatesTo, - /// `Id` of a possible owner [`Account`]. - pub account_id: EvaluatesTo, - } } impl Query for FindAllAssets { type Output = Vec; @@ -735,10 +724,6 @@ pub mod asset { type Output = MetadataValue; } - impl Query for IsAssetDefinitionOwner { - type Output = bool; - } - impl FindAssetById { /// Construct [`FindAssetById`]. pub fn new(id: impl Into>) -> Self { @@ -837,19 +822,6 @@ pub mod asset { } } - impl IsAssetDefinitionOwner { - /// Construct [`IsAssetDefinitionOwner`]. - pub fn new( - asset_definition_id: impl Into>, - account_id: impl Into>, - ) -> Self { - Self { - asset_definition_id: asset_definition_id.into(), - account_id: account_id.into(), - } - } - } - /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { pub use super::{ @@ -857,7 +829,7 @@ pub mod asset { FindAssetDefinitionKeyValueByIdAndKey, FindAssetKeyValueByIdAndKey, FindAssetQuantityById, FindAssetsByAccountId, FindAssetsByAssetDefinitionId, FindAssetsByDomainId, FindAssetsByDomainIdAndAssetDefinitionId, FindAssetsByName, - FindTotalAssetQuantityByAssetDefinitionId, IsAssetDefinitionOwner, + FindTotalAssetQuantityByAssetDefinitionId, }; } } diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index 0853d8188a3..bbcd47ba70e 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -106,7 +106,6 @@ pub trait Visit: ExpressionEvaluator { visit_find_trigger_by_id(&FindTriggerById), visit_find_trigger_key_value_by_id_and_key(&FindTriggerKeyValueByIdAndKey), visit_find_triggers_by_domain_id(&FindTriggersByDomainId), - visit_is_asset_definition_owner(&IsAssetDefinitionOwner), // Visit RegisterExpr visit_register_peer(Register), @@ -242,7 +241,6 @@ pub fn visit_query(visitor: &mut V, authority: &AccountId, qu visit_find_trigger_by_id(FindTriggerById), visit_find_trigger_key_value_by_id_and_key(FindTriggerKeyValueByIdAndKey), visit_find_triggers_by_domain_id(FindTriggersByDomainId), - visit_is_asset_definition_owner(IsAssetDefinitionOwner), } } @@ -782,5 +780,4 @@ leaf_visitors! { visit_find_trigger_by_id(&FindTriggerById), visit_find_trigger_key_value_by_id_and_key(&FindTriggerKeyValueByIdAndKey), visit_find_triggers_by_domain_id(&FindTriggersByDomainId), - visit_is_asset_definition_owner(&IsAssetDefinitionOwner), } diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index 4e875a7cfef..94ba2b4686d 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -2643,18 +2643,6 @@ "Ipv4Predicate": "Array, 4>", "Ipv6Addr": "Array", "Ipv6Predicate": "Array, 8>", - "IsAssetDefinitionOwner": { - "Struct": [ - { - "name": "asset_definition_id", - "type": "EvaluatesTo" - }, - { - "name": "account_id", - "type": "EvaluatesTo" - } - ] - }, "LengthLimits": { "Struct": [ { @@ -3507,124 +3495,119 @@ "discriminant": 16, "type": "FindTotalAssetQuantityByAssetDefinitionId" }, - { - "tag": "IsAssetDefinitionOwner", - "discriminant": 17, - "type": "IsAssetDefinitionOwner" - }, { "tag": "FindAssetKeyValueByIdAndKey", - "discriminant": 18, + "discriminant": 17, "type": "FindAssetKeyValueByIdAndKey" }, { "tag": "FindAssetDefinitionKeyValueByIdAndKey", - "discriminant": 19, + "discriminant": 18, "type": "FindAssetDefinitionKeyValueByIdAndKey" }, { "tag": "FindAllDomains", - "discriminant": 20, + "discriminant": 19, "type": "FindAllDomains" }, { "tag": "FindDomainById", - "discriminant": 21, + "discriminant": 20, "type": "FindDomainById" }, { "tag": "FindDomainKeyValueByIdAndKey", - "discriminant": 22, + "discriminant": 21, "type": "FindDomainKeyValueByIdAndKey" }, { "tag": "FindAllPeers", - "discriminant": 23, + "discriminant": 22, "type": "FindAllPeers" }, { "tag": "FindAllBlocks", - "discriminant": 24, + "discriminant": 23, "type": "FindAllBlocks" }, { "tag": "FindAllBlockHeaders", - "discriminant": 25, + "discriminant": 24, "type": "FindAllBlockHeaders" }, { "tag": "FindBlockHeaderByHash", - "discriminant": 26, + "discriminant": 25, "type": "FindBlockHeaderByHash" }, { "tag": "FindAllTransactions", - "discriminant": 27, + "discriminant": 26, "type": "FindAllTransactions" }, { "tag": "FindTransactionsByAccountId", - "discriminant": 28, + "discriminant": 27, "type": "FindTransactionsByAccountId" }, { "tag": "FindTransactionByHash", - "discriminant": 29, + "discriminant": 28, "type": "FindTransactionByHash" }, { "tag": "FindPermissionTokensByAccountId", - "discriminant": 30, + "discriminant": 29, "type": "FindPermissionTokensByAccountId" }, { "tag": "FindPermissionTokenSchema", - "discriminant": 31, + "discriminant": 30, "type": "FindPermissionTokenSchema" }, { "tag": "FindAllActiveTriggerIds", - "discriminant": 32, + "discriminant": 31, "type": "FindAllActiveTriggerIds" }, { "tag": "FindTriggerById", - "discriminant": 33, + "discriminant": 32, "type": "FindTriggerById" }, { "tag": "FindTriggerKeyValueByIdAndKey", - "discriminant": 34, + "discriminant": 33, "type": "FindTriggerKeyValueByIdAndKey" }, { "tag": "FindTriggersByDomainId", - "discriminant": 35, + "discriminant": 34, "type": "FindTriggersByDomainId" }, { "tag": "FindAllRoles", - "discriminant": 36, + "discriminant": 35, "type": "FindAllRoles" }, { "tag": "FindAllRoleIds", - "discriminant": 37, + "discriminant": 36, "type": "FindAllRoleIds" }, { "tag": "FindRoleByRoleId", - "discriminant": 38, + "discriminant": 37, "type": "FindRoleByRoleId" }, { "tag": "FindRolesByAccountId", - "discriminant": 39, + "discriminant": 38, "type": "FindRolesByAccountId" }, { "tag": "FindAllParameters", - "discriminant": 40, + "discriminant": 39, "type": "FindAllParameters" } ] diff --git a/ffi/derive/src/attr_parse/derive.rs b/ffi/derive/src/attr_parse/derive.rs index f33a62f592b..eb244cb5b19 100644 --- a/ffi/derive/src/attr_parse/derive.rs +++ b/ffi/derive/src/attr_parse/derive.rs @@ -70,13 +70,15 @@ impl FromAttributes for DeriveAttrs { for attr in attrs { if attr.path().is_ident("derive") { - let Some(list) = accumulator.handle(attr.meta.require_list().map_err(Into::into)) else { - continue + let Some(list) = accumulator.handle(attr.meta.require_list().map_err(Into::into)) + else { + continue; }; let Some(paths) = accumulator.handle( - list.parse_args_with(Punctuated::::parse_terminated).map_err(Into::into) + list.parse_args_with(Punctuated::::parse_terminated) + .map_err(Into::into), ) else { - continue + continue; }; for path in paths { diff --git a/ffi/derive/src/attr_parse/getset.rs b/ffi/derive/src/attr_parse/getset.rs index aaba372924e..0b63b0b5385 100644 --- a/ffi/derive/src/attr_parse/getset.rs +++ b/ffi/derive/src/attr_parse/getset.rs @@ -211,10 +211,17 @@ impl GetSetRawFieldAttr { // iroha doesn't use the latter form, so it is not supported by `iroha_ffi_derive` if attr.path().is_ident("getset") { let Some(list) = accumulator.handle(attr.meta.require_list().map_err(Into::into)) - else { continue }; - let Some(tokens): Option> - = accumulator.handle(list.parse_args_with(Punctuated::parse_terminated).map_err(Into::into)) - else { continue }; + else { + continue; + }; + let Some(tokens): Option> = + accumulator.handle( + list.parse_args_with(Punctuated::parse_terminated) + .map_err(Into::into), + ) + else { + continue; + }; for token in tokens { match token.token { diff --git a/ffi/derive/src/attr_parse/repr.rs b/ffi/derive/src/attr_parse/repr.rs index 5cd10492231..f845fbd3393 100644 --- a/ffi/derive/src/attr_parse/repr.rs +++ b/ffi/derive/src/attr_parse/repr.rs @@ -137,7 +137,7 @@ impl FromAttributes for Repr { ), Meta::List(list) => { let Some(tokens) = accumulator.handle( - syn2::parse2::(list.tokens.clone()).map_err(Into::into) + syn2::parse2::(list.tokens.clone()).map_err(Into::into), ) else { continue; }; diff --git a/ffi/derive/src/convert.rs b/ffi/derive/src/convert.rs index 3f0ea4b2cd3..374055ebd3a 100644 --- a/ffi/derive/src/convert.rs +++ b/ffi/derive/src/convert.rs @@ -47,7 +47,7 @@ impl syn2::parse::Parse for SpannedFfiTypeToken { fn parse(input: ParseStream) -> syn2::Result { let (span, token) = input.step(|cursor| { let Some((token, after_token)) = cursor.ident() else { - return Err(cursor.error("expected ffi type kind")) + return Err(cursor.error("expected ffi type kind")); }; let mut span = token.span(); @@ -56,26 +56,35 @@ impl syn2::parse::Parse for SpannedFfiTypeToken { "opaque" => Ok(((span, FfiTypeToken::Opaque), after_token)), "local" => Ok(((span, FfiTypeToken::Local), after_token)), "unsafe" => { - let Some((inside_of_group, group_span, after_group)) = after_token.group(Delimiter::Brace) else { - return Err(cursor.error("expected `{ ... }` after `unsafe`")) + let Some((inside_of_group, group_span, after_group)) = + after_token.group(Delimiter::Brace) + else { + return Err(cursor.error("expected `{ ... }` after `unsafe`")); }; span = span.join(group_span.span()).unwrap_or(span); let Some((token, after_token)) = inside_of_group.ident() else { - return Err(cursor.error("expected ffi type kind")) + return Err(cursor.error("expected ffi type kind")); }; if !after_token.eof() { - return Err(cursor.error("`unsafe { ... }` should only contain one identifier inside")) + return Err(cursor + .error("`unsafe { ... }` should only contain one identifier inside")); } let token = token.to_string(); match token.as_str() { "robust" => Ok(((span, FfiTypeToken::UnsafeRobust), after_group)), "non_owning" => Ok(((span, FfiTypeToken::UnsafeNonOwning), after_group)), - other => Err(syn2::Error::new(token.span(), format!("unknown unsafe ffi type kind: {}", other))), + other => Err(syn2::Error::new( + token.span(), + format!("unknown unsafe ffi type kind: {}", other), + )), } } - other => Err(syn2::Error::new(span, format!("unknown unsafe ffi type kind: {}", other))), + other => Err(syn2::Error::new( + span, + format!("unknown unsafe ffi type kind: {}", other), + )), } })?; @@ -581,12 +590,10 @@ fn derive_ffi_type_for_data_carrying_enum( let mut non_local_where_clause = where_clause.unwrap().clone(); for variant in variants { - let Some(ty) = variant_mapper( - emitter, variant, - || None, - |field| Some(field.ty.clone()) - ) else { - continue + let Some(ty) = + variant_mapper(emitter, variant, || None, |field| Some(field.ty.clone())) + else { + continue; }; non_local_where_clause.predicates.push( @@ -872,14 +879,22 @@ fn get_enum_repr_type( // it's an error to use an `#[derive(FfiType)]` on them // but we still want to generate a reasonable error message, so we check for it here if !is_empty { - emit!(emitter, enum_name, "Enum representation is not specified. Try adding `#[repr(u32)]` or similar"); + emit!( + emitter, + enum_name, + "Enum representation is not specified. Try adding `#[repr(u32)]` or similar" + ); } - return syn2::parse_quote! {u32} + return syn2::parse_quote! {u32}; }; let ReprKind::Primitive(primitive) = &*kind else { - emit!(emitter, &kind.span(), "Enum should have a primitive representation (like `#[repr(u32)]`)"); - return syn2::parse_quote! {u32} + emit!( + emitter, + &kind.span(), + "Enum should have a primitive representation (like `#[repr(u32)]`)" + ); + return syn2::parse_quote! {u32}; }; match primitive { diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index c6f384f62a9..88f2ce3c292 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -240,7 +240,6 @@ types!( Ipv4Predicate, Ipv6Addr, Ipv6Predicate, - IsAssetDefinitionOwner, LengthLimits, Less, MerkleTree, From afe47851084a3d3ece09d4bdf08d60b6452efeef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Wed, 11 Oct 2023 15:56:07 +0200 Subject: [PATCH 48/55] [refactor] #3918: Rename validator to executor (#3976) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- Cargo.lock | 44 +- Cargo.toml | 8 +- README.md | 2 +- cli/build.rs | 12 +- cli/src/samples.rs | 12 +- cli/src/torii/mod.rs | 2 +- client/benches/torii.rs | 10 +- client/examples/million_accounts_genesis.rs | 6 +- .../integration/smartcontracts/Cargo.toml | 8 +- .../Cargo.toml | 4 +- .../src/lib.rs | 42 +- .../Cargo.toml | 4 +- .../src/lib.rs | 66 +- .../Cargo.toml | 4 +- .../src/lib.rs | 42 +- client/tests/integration/upgrade.rs | 31 +- configs/peer/executor.wasm | Bin 0 -> 504366 bytes configs/peer/genesis.json | 2 +- configs/peer/validator.wasm | Bin 504437 -> 0 bytes core/benches/blocks/common.rs | 16 +- core/benches/kura.rs | 10 +- core/benches/validation.rs | 20 +- core/src/block.rs | 16 +- core/src/{validator.rs => executor.rs} | 143 ++-- core/src/lib.rs | 2 +- core/src/smartcontracts/isi/mod.rs | 4 +- core/src/smartcontracts/isi/query.rs | 4 +- core/src/smartcontracts/isi/triggers/mod.rs | 2 +- core/src/smartcontracts/isi/world.rs | 18 +- core/src/smartcontracts/mod.rs | 2 +- core/src/smartcontracts/wasm.rs | 280 ++++---- core/src/sumeragi/main_loop.rs | 6 +- core/src/tx.rs | 18 +- core/src/wsv.rs | 32 +- core/test_network/src/lib.rs | 6 +- data_model/src/events/data/events.rs | 28 +- data_model/src/{validator.rs => executor.rs} | 14 +- data_model/src/isi.rs | 6 +- data_model/src/lib.rs | 34 +- data_model/src/permission.rs | 2 +- data_model/src/query/mod.rs | 2 +- data_model/src/smart_contract.rs | 2 +- data_model/src/visit.rs | 10 +- .../.cargo/config.toml | 0 .../Cargo.toml | 4 +- .../LICENSE | 0 .../README.md | 4 +- .../src/lib.rs | 61 +- docs/source/lts_selection.org | 8 +- docs/source/references/schema.json | 76 +-- genesis/src/lib.rs | 84 +-- schema/gen/src/lib.rs | 6 +- scripts/test_env.py | 2 +- scripts/tests/consistency.sh | 4 +- scripts/update_configs.sh | 2 +- .../{validator => executor}/Cargo.toml | 4 +- .../{validator => executor}/derive/Cargo.toml | 2 +- .../derive/src/conversion.rs | 8 +- .../derive/src/entrypoint.rs | 49 +- .../{validator => executor}/derive/src/lib.rs | 12 +- .../derive/src/token.rs | 22 +- .../derive/src/validate.rs | 10 +- .../{validator => executor}/src/default.rs | 626 +++++++++--------- .../{validator => executor}/src/lib.rs | 56 +- .../{validator => executor}/src/permission.rs | 10 +- tools/kagami/src/genesis.rs | 73 +- tools/parity_scale_decoder/src/main.rs | 2 +- wasm_builder/src/lib.rs | 4 +- 68 files changed, 1050 insertions(+), 1055 deletions(-) rename client/tests/integration/smartcontracts/{validator_with_admin => executor_with_admin}/Cargo.toml (79%) rename client/tests/integration/smartcontracts/{validator_with_admin => executor_with_admin}/src/lib.rs (80%) rename client/tests/integration/smartcontracts/{validator_with_custom_token => executor_with_custom_token}/Cargo.toml (83%) rename client/tests/integration/smartcontracts/{validator_with_custom_token => executor_with_custom_token}/src/lib.rs (82%) rename client/tests/integration/smartcontracts/{validator_with_migration_fail => executor_with_migration_fail}/Cargo.toml (76%) rename client/tests/integration/smartcontracts/{validator_with_migration_fail => executor_with_migration_fail}/src/lib.rs (82%) create mode 100644 configs/peer/executor.wasm delete mode 100644 configs/peer/validator.wasm rename core/src/{validator.rs => executor.rs} (65%) rename data_model/src/{validator.rs => executor.rs} (81%) rename {default_validator => default_executor}/.cargo/config.toml (100%) rename {default_validator => default_executor}/Cargo.toml (84%) rename {default_validator => default_executor}/LICENSE (100%) rename {default_validator => default_executor}/README.md (55%) rename {default_validator => default_executor}/src/lib.rs (74%) rename smart_contract/{validator => executor}/Cargo.toml (87%) rename smart_contract/{validator => executor}/derive/Cargo.toml (88%) rename smart_contract/{validator => executor}/derive/src/conversion.rs (89%) rename smart_contract/{validator => executor}/derive/src/entrypoint.rs (67%) rename smart_contract/{validator => executor}/derive/src/lib.rs (95%) rename smart_contract/{validator => executor}/derive/src/token.rs (58%) rename smart_contract/{validator => executor}/derive/src/validate.rs (93%) rename smart_contract/{validator => executor}/src/default.rs (75%) rename smart_contract/{validator => executor}/src/lib.rs (84%) rename smart_contract/{validator => executor}/src/permission.rs (96%) diff --git a/Cargo.lock b/Cargo.lock index 02aba7e1cbd..0c25dea84be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3217,6 +3217,28 @@ dependencies = [ "serde_json", ] +[[package]] +name = "iroha_executor" +version = "2.0.0-pre-rc.19" +dependencies = [ + "iroha_data_model", + "iroha_executor_derive", + "iroha_schema", + "iroha_smart_contract", + "iroha_smart_contract_utils", + "serde", + "serde_json", +] + +[[package]] +name = "iroha_executor_derive" +version = "2.0.0-pre-rc.19" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "iroha_ffi" version = "2.0.0-pre-rc.19" @@ -3527,28 +3549,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "iroha_validator" -version = "2.0.0-pre-rc.19" -dependencies = [ - "iroha_data_model", - "iroha_schema", - "iroha_smart_contract", - "iroha_smart_contract_utils", - "iroha_validator_derive", - "serde", - "serde_json", -] - -[[package]] -name = "iroha_validator_derive" -version = "2.0.0-pre-rc.19" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "iroha_version" version = "2.0.0-pre-rc.19" diff --git a/Cargo.toml b/Cargo.toml index 69532e90459..cc3ebecb5fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,8 +50,8 @@ iroha_wasm_builder = { version = "=2.0.0-pre-rc.19", path = "wasm_builder" } iroha_smart_contract = { version = "=2.0.0-pre-rc.19", path = "smart_contract" } iroha_smart_contract_derive = { version = "=2.0.0-pre-rc.19", path = "smart_contract/derive" } iroha_smart_contract_utils = { version = "=2.0.0-pre-rc.19", path = "smart_contract/utils" } -iroha_validator = { version = "=2.0.0-pre-rc.19", path = "smart_contract/validator" } -iroha_validator_derive = { version = "=2.0.0-pre-rc.19", path = "smart_contract/validator/derive" } +iroha_executor = { version = "=2.0.0-pre-rc.19", path = "smart_contract/executor" } +iroha_executor_derive = { version = "=2.0.0-pre-rc.19", path = "smart_contract/executor/derive" } iroha_trigger = { version = "=2.0.0-pre-rc.19", path = "smart_contract/trigger" } iroha_trigger_derive = { version = "=2.0.0-pre-rc.19", path = "smart_contract/trigger/derive" } @@ -326,8 +326,8 @@ members = [ "smart_contract/trigger", "smart_contract/trigger/derive", "smart_contract/utils", - "smart_contract/validator", - "smart_contract/validator/derive", + "smart_contract/executor", + "smart_contract/executor/derive", "substrate", "telemetry", "tools/kagami", diff --git a/README.md b/README.md index 6e5a3f3512b..dcf33bf4aa5 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ Iroha project mainly consists of the following crates: * [`iroha_logger`](logger) uses `tracing` to provide logging facilities. * [`iroha_macro`](macro) provides the convenience macros. * [`iroha_p2p`](p2p) defines peer creation and handshake logic. -* [`iroha_default_validator`](default_validator) defines runtime validation logic. +* [`iroha_default_executor`](default_executor) defines runtime validation logic. * [`iroha_substrate`](substrate) is the bridge substrate `XClaim` external module. * [`iroha_telemetry`](telemetry) is used for monitoring and analysis of telemetry data. * [`iroha_version`](version) provides message versioning for non-simultaneous system updates. diff --git a/cli/build.rs b/cli/build.rs index 4cc489aa580..23ce6a29d23 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -1,12 +1,12 @@ -//! Build script to extract git hash of iroha build and to check runtime validator +//! Build script to extract git hash of iroha build and to check runtime executor use eyre::{eyre, Result, WrapErr}; -const DEFAULT_VALIDATOR_PATH: &str = "../default_validator"; +const DEFAULT_EXECUTOR_PATH: &str = "../default_executor"; fn main() -> Result<()> { println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed={DEFAULT_VALIDATOR_PATH}"); + println!("cargo:rerun-if-changed={DEFAULT_EXECUTOR_PATH}"); extract_git_hash()?; @@ -14,7 +14,7 @@ fn main() -> Result<()> { // the checks are a process that's hard to accomodate // in Nix environment if std::option_env!("IROHA_SKIP_WASM_CHECKS").is_none() { - check_default_validator()?; + check_default_executor()?; } Ok(()) @@ -30,8 +30,8 @@ fn extract_git_hash() -> Result<()> { } /// Apply `cargo check` to the smartcontract. -fn check_default_validator() -> Result<()> { - iroha_wasm_builder::Builder::new(DEFAULT_VALIDATOR_PATH) +fn check_default_executor() -> Result<()> { + iroha_wasm_builder::Builder::new(DEFAULT_EXECUTOR_PATH) .format() .check() } diff --git a/cli/src/samples.rs b/cli/src/samples.rs index eabd3bf784b..1b46b2c0556 100644 --- a/cli/src/samples.rs +++ b/cli/src/samples.rs @@ -100,16 +100,16 @@ pub fn get_config(trusted_peers: UniqueVec, key_pair: Option) - .expect("Iroha config should build as all required fields were provided") } -/// Construct validator from path. +/// Construct executor from path. /// /// `relative_path` should be relative to `CARGO_MANIFEST_DIR`. /// /// # Errors /// -/// - Failed to create temp dir for validator output -/// - Failed to build validator -/// - Failed to optimize validator -pub fn construct_validator

(relative_path: &P) -> color_eyre::Result +/// - Failed to create temp dir for executor output +/// - Failed to build executor +/// - Failed to optimize executor +pub fn construct_executor

(relative_path: &P) -> color_eyre::Result where P: AsRef + ?Sized, { @@ -118,5 +118,5 @@ where .optimize()? .into_bytes()?; - Ok(Validator::new(WasmSmartContract::from_compiled(wasm_blob))) + Ok(Executor::new(WasmSmartContract::from_compiled(wasm_blob))) } diff --git a/cli/src/torii/mod.rs b/cli/src/torii/mod.rs index 5a2dc45bb9d..a478fe4f554 100644 --- a/cli/src/torii/mod.rs +++ b/cli/src/torii/mod.rs @@ -131,7 +131,7 @@ fn query_status_code(validation_error: &iroha_data_model::ValidationFail) -> Sta InstructionFailed(error) => { iroha_logger::error!( ?error, - "Query validation failed with unexpected error. This means a bug inside Runtime Validator", + "Query validation failed with unexpected error. This means a bug inside Runtime Executor", ); StatusCode::INTERNAL_SERVER_ERROR } diff --git a/client/benches/torii.rs b/client/benches/torii.rs index c4674134bc7..a59ee916570 100644 --- a/client/benches/torii.rs +++ b/client/benches/torii.rs @@ -3,7 +3,7 @@ use std::thread; use criterion::{criterion_group, criterion_main, Criterion, Throughput}; -use iroha::samples::{construct_validator, get_config}; +use iroha::samples::{construct_executor, get_config}; use iroha_client::client::{asset, Client}; use iroha_config::base::runtime_upgrades::Reload; use iroha_crypto::KeyPair; @@ -29,8 +29,8 @@ fn query_requests(criterion: &mut Criterion) { get_key_pair().public_key().clone(), ) .finish_domain() - .validator( - construct_validator("../default_validator").expect("Failed to construct validator"), + .executor( + construct_executor("../default_executor").expect("Failed to construct executor"), ) .build(), Some(&configuration.genesis), @@ -124,8 +124,8 @@ fn instruction_submits(criterion: &mut Criterion) { configuration.public_key.clone(), ) .finish_domain() - .validator( - construct_validator("../default_validator").expect("Failed to construct validator"), + .executor( + construct_executor("../default_executor").expect("Failed to construct executor"), ) .build(), Some(&configuration.genesis), diff --git a/client/examples/million_accounts_genesis.rs b/client/examples/million_accounts_genesis.rs index 1ee815fd1de..5cba2ca88a9 100644 --- a/client/examples/million_accounts_genesis.rs +++ b/client/examples/million_accounts_genesis.rs @@ -2,7 +2,7 @@ use std::{thread, time::Duration}; -use iroha::samples::{construct_validator, get_config}; +use iroha::samples::{construct_executor, get_config}; use iroha_data_model::prelude::*; use iroha_genesis::{GenesisNetwork, RawGenesisBlock, RawGenesisBlockBuilder}; use iroha_primitives::unique_vec; @@ -30,9 +30,7 @@ fn generate_genesis(num_domains: u32) -> RawGenesisBlock { } builder - .validator( - construct_validator("../default_validator").expect("Failed to construct validator"), - ) + .executor(construct_executor("../default_executor").expect("Failed to construct executor")) .build() } diff --git a/client/tests/integration/smartcontracts/Cargo.toml b/client/tests/integration/smartcontracts/Cargo.toml index 55420704b94..b193147bb9b 100644 --- a/client/tests/integration/smartcontracts/Cargo.toml +++ b/client/tests/integration/smartcontracts/Cargo.toml @@ -11,9 +11,9 @@ resolver = "2" members = [ "create_nft_for_every_user_trigger", "mint_rose_trigger", - "validator_with_admin", - "validator_with_custom_token", - "validator_with_migration_fail", + "executor_with_admin", + "executor_with_custom_token", + "executor_with_migration_fail", ] [profile.dev] @@ -28,7 +28,7 @@ codegen-units = 1 # Further reduces binary size but increases compilation time [workspace.dependencies] iroha_trigger = { version = "=2.0.0-pre-rc.19", path = "../../../../smart_contract/trigger", features = ["debug"]} -iroha_validator = { version = "=2.0.0-pre-rc.19", path = "../../../../smart_contract/validator" } +iroha_executor = { version = "=2.0.0-pre-rc.19", path = "../../../../smart_contract/executor" } iroha_schema = { version = "=2.0.0-pre-rc.19", path = "../../../../schema" } parity-scale-codec = { version = "3.2.1", default-features = false } diff --git a/client/tests/integration/smartcontracts/validator_with_admin/Cargo.toml b/client/tests/integration/smartcontracts/executor_with_admin/Cargo.toml similarity index 79% rename from client/tests/integration/smartcontracts/validator_with_admin/Cargo.toml rename to client/tests/integration/smartcontracts/executor_with_admin/Cargo.toml index eeb3d61804a..c48ea913d35 100644 --- a/client/tests/integration/smartcontracts/validator_with_admin/Cargo.toml +++ b/client/tests/integration/smartcontracts/executor_with_admin/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "validator_with_admin" +name = "executor_with_admin" edition.workspace = true version.workspace = true @@ -11,7 +11,7 @@ license.workspace = true crate-type = ['cdylib'] [dependencies] -iroha_validator.workspace = true +iroha_executor.workspace = true iroha_schema.workspace = true panic-halt.workspace = true diff --git a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs similarity index 80% rename from client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs rename to client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs index 1140d74e853..572742d85ec 100644 --- a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs @@ -1,4 +1,4 @@ -//! Runtime Validator which allows any instruction executed by `admin@admin` account. +//! Runtime Executor which allows any instruction executed by `admin@admin` account. //! If authority is not `admin@admin` then default validation is used as a backup. #![no_std] @@ -7,7 +7,7 @@ #[cfg(not(test))] extern crate panic_halt; -use iroha_validator::{ +use iroha_executor::{ data_model::evaluate::{EvaluationError, ExpressionEvaluator}, parse, prelude::*, @@ -18,13 +18,13 @@ use lol_alloc::{FreeListAllocator, LockedAllocator}; #[global_allocator] static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); -struct Validator { +struct Executor { verdict: Result, block_height: u64, host: smart_contract::Host, } -impl Validator { +impl Executor { /// Construct [`Self`] pub fn new(block_height: u64) -> Self { Self { @@ -36,20 +36,20 @@ impl Validator { } macro_rules! defaults { - ( $($validator:ident $(<$param:ident $(: $bound:path)?>)?($operation:ty)),+ $(,)? ) => { $( - fn $validator $(<$param $(: $bound)?>)?(&mut self, authority: &AccountId, operation: $operation) { - iroha_validator::default::$validator(self, authority, operation) + ( $($executor:ident $(<$param:ident $(: $bound:path)?>)?($operation:ty)),+ $(,)? ) => { $( + fn $executor $(<$param $(: $bound)?>)?(&mut self, authority: &AccountId, operation: $operation) { + iroha_executor::default::$executor(self, authority, operation) } )+ }; } -impl Visit for Validator { +impl Visit for Executor { fn visit_instruction(&mut self, authority: &AccountId, isi: &InstructionExpr) { if parse!("admin@admin" as AccountId) == *authority { pass!(self); } - iroha_validator::default::visit_instruction(self, authority, isi); + iroha_executor::default::visit_instruction(self, authority, isi); } defaults! { @@ -114,11 +114,11 @@ impl Visit for Validator { visit_new_parameter(NewParameter), // Upgrade validation - visit_upgrade_validator(Upgrade), + visit_upgrade_executor(Upgrade), } } -impl Validate for Validator { +impl Validate for Executor { fn verdict(&self) -> &Result { &self.verdict } @@ -132,7 +132,7 @@ impl Validate for Validator { } } -impl ExpressionEvaluator for Validator { +impl ExpressionEvaluator for Executor { fn evaluate(&self, expression: &E) -> Result { self.host.evaluate(expression) } @@ -149,9 +149,9 @@ pub fn validate_transaction( transaction: SignedTransaction, block_height: u64, ) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_transaction(&authority, &transaction); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_transaction(&authority, &transaction); + executor.verdict } #[entrypoint] @@ -160,14 +160,14 @@ pub fn validate_instruction( instruction: InstructionExpr, block_height: u64, ) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_instruction(&authority, &instruction); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_instruction(&authority, &instruction); + executor.verdict } #[entrypoint] pub fn validate_query(authority: AccountId, query: QueryBox, block_height: u64) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_query(&authority, &query); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_query(&authority, &query); + executor.verdict } diff --git a/client/tests/integration/smartcontracts/validator_with_custom_token/Cargo.toml b/client/tests/integration/smartcontracts/executor_with_custom_token/Cargo.toml similarity index 83% rename from client/tests/integration/smartcontracts/validator_with_custom_token/Cargo.toml rename to client/tests/integration/smartcontracts/executor_with_custom_token/Cargo.toml index 8fd8e8f3cc7..1b305798354 100644 --- a/client/tests/integration/smartcontracts/validator_with_custom_token/Cargo.toml +++ b/client/tests/integration/smartcontracts/executor_with_custom_token/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "validator_with_custom_token" +name = "executor_with_custom_token" edition.workspace = true version.workspace = true @@ -11,7 +11,7 @@ license.workspace = true crate-type = ['cdylib'] [dependencies] -iroha_validator.workspace = true +iroha_executor.workspace = true iroha_schema.workspace = true parity-scale-codec.workspace = true diff --git a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs similarity index 82% rename from client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs rename to client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs index a543863d26b..bf54a6c8503 100644 --- a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs @@ -1,11 +1,11 @@ -//! Runtime Validator which allows domain (un-)registration only for users who own +//! Runtime Executor which allows domain (un-)registration only for users who own //! [`token::CanControlDomainLives`] permission token. //! -//! This validator should be applied on top of the blockchain with default validation. +//! This executor should be applied on top of the blockchain with default validation. //! -//! It also doesn't have [`iroha_validator::default::domain::tokens::CanUnregisterDomain`]. +//! It also doesn't have [`iroha_executor::default::domain::tokens::CanUnregisterDomain`]. //! -//! In migration it replaces [`iroha_validator::default::domain::tokens::CanUnregisterDomain`] +//! In migration it replaces [`iroha_executor::default::domain::tokens::CanUnregisterDomain`] //! with [`token::CanControlDomainLives`] for all accounts. //! So it doesn't matter which domain user was able to unregister before migration, they will //! get access to control all domains. Remember that this is just a test example. @@ -20,14 +20,14 @@ extern crate panic_halt; use alloc::{borrow::ToOwned, string::String}; use anyhow::anyhow; -use iroha_schema::IntoSchema; -use iroha_validator::{ +use iroha_executor::{ data_model::evaluate::{EvaluationError, ExpressionEvaluator}, default::default_permission_token_schema, permission::Token as _, prelude::*, smart_contract, }; +use iroha_schema::IntoSchema; use lol_alloc::{FreeListAllocator, LockedAllocator}; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; @@ -55,17 +55,17 @@ mod token { Serialize, Deserialize, )] - #[validate(iroha_validator::permission::OnlyGenesis)] + #[validate(iroha_executor::permission::OnlyGenesis)] pub struct CanControlDomainLives; } -struct Validator { +struct Executor { verdict: Result, block_height: u64, host: smart_contract::Host, } -impl Validator { +impl Executor { /// Construct [`Self`] pub fn new(block_height: u64) -> Self { Self { @@ -98,7 +98,7 @@ impl Validator { for token in permission_tokens { if let Ok(can_unregister_domain_token) = - iroha_validator::default::domain::tokens::CanUnregisterDomain::try_from(token) + iroha_executor::default::domain::tokens::CanUnregisterDomain::try_from(token) { found_accounts.push((account, can_unregister_domain_token.domain_id)); break; @@ -111,7 +111,7 @@ impl Validator { fn replace_token(accounts: &[(Account, DomainId)]) -> MigrationResult { let can_unregister_domain_definition_id = PermissionTokenId::try_from( - iroha_validator::default::domain::tokens::CanUnregisterDomain::type_name(), + iroha_executor::default::domain::tokens::CanUnregisterDomain::type_name(), ) .unwrap(); @@ -160,7 +160,7 @@ impl Validator { }) }) .map_err(|error| { - iroha_validator::log::error!(&error); + iroha_executor::log::error!(&error); format!( "{:?}", anyhow!(error).context(format!( @@ -173,14 +173,14 @@ impl Validator { } macro_rules! defaults { - ( $($validator:ident $(<$param:ident $(: $bound:path)?>)?($operation:ty)),+ $(,)? ) => { $( - fn $validator $(<$param $(: $bound)?>)?(&mut self, authority: &AccountId, operation: $operation) { - iroha_validator::default::$validator(self, authority, operation) + ( $($executor:ident $(<$param:ident $(: $bound:path)?>)?($operation:ty)),+ $(,)? ) => { $( + fn $executor $(<$param $(: $bound)?>)?(&mut self, authority: &AccountId, operation: $operation) { + iroha_executor::default::$executor(self, authority, operation) } )+ }; } -impl Visit for Validator { +impl Visit for Executor { fn visit_register_domain(&mut self, authority: &AccountId, _isi: Register) { if self.block_height() == 0 { pass!(self); @@ -265,11 +265,11 @@ impl Visit for Validator { visit_new_parameter(NewParameter), // Upgrade validation - visit_upgrade_validator(Upgrade), + visit_upgrade_executor(Upgrade), } } -impl Validate for Validator { +impl Validate for Executor { fn verdict(&self) -> &Result { &self.verdict } @@ -283,7 +283,7 @@ impl Validate for Validator { } } -impl ExpressionEvaluator for Validator { +impl ExpressionEvaluator for Executor { fn evaluate(&self, expression: &E) -> Result { self.host.evaluate(expression) } @@ -291,18 +291,18 @@ impl ExpressionEvaluator for Validator { #[entrypoint] pub fn migrate(_block_height: u64) -> MigrationResult { - let accounts = Validator::get_all_accounts_with_can_unregister_domain_permission()?; + let accounts = Executor::get_all_accounts_with_can_unregister_domain_permission()?; let mut schema = default_permission_token_schema(); - schema.remove::(); + schema.remove::(); schema.insert::(); let (token_ids, schema_str) = schema.serialize(); - iroha_validator::set_permission_token_schema( - &iroha_validator::data_model::permission::PermissionTokenSchema::new(token_ids, schema_str), + iroha_executor::set_permission_token_schema( + &iroha_executor::data_model::permission::PermissionTokenSchema::new(token_ids, schema_str), ); - Validator::replace_token(&accounts) + Executor::replace_token(&accounts) } #[entrypoint] @@ -311,9 +311,9 @@ pub fn validate_transaction( transaction: SignedTransaction, block_height: u64, ) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_transaction(&authority, &transaction); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_transaction(&authority, &transaction); + executor.verdict } #[entrypoint] @@ -322,14 +322,14 @@ pub fn validate_instruction( instruction: InstructionExpr, block_height: u64, ) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_instruction(&authority, &instruction); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_instruction(&authority, &instruction); + executor.verdict } #[entrypoint] pub fn validate_query(authority: AccountId, query: QueryBox, block_height: u64) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_query(&authority, &query); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_query(&authority, &query); + executor.verdict } diff --git a/client/tests/integration/smartcontracts/validator_with_migration_fail/Cargo.toml b/client/tests/integration/smartcontracts/executor_with_migration_fail/Cargo.toml similarity index 76% rename from client/tests/integration/smartcontracts/validator_with_migration_fail/Cargo.toml rename to client/tests/integration/smartcontracts/executor_with_migration_fail/Cargo.toml index fb8aa79e97c..813a5d74ef2 100644 --- a/client/tests/integration/smartcontracts/validator_with_migration_fail/Cargo.toml +++ b/client/tests/integration/smartcontracts/executor_with_migration_fail/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "validator_with_migration_fail" +name = "executor_with_migration_fail" edition.workspace = true version.workspace = true @@ -11,7 +11,7 @@ license.workspace = true crate-type = ['cdylib'] [dependencies] -iroha_validator.workspace = true +iroha_executor.workspace = true anyhow.workspace = true panic-halt.workspace = true diff --git a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs similarity index 82% rename from client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs rename to client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs index bfde7231e38..23c5c957db8 100644 --- a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs @@ -1,4 +1,4 @@ -//! Runtime Validator which copies default validation logic but forbids any queries and fails to migrate. +//! Runtime Executor which copies default validation logic but forbids any queries and fails to migrate. #![no_std] #![allow(missing_docs, clippy::missing_errors_doc)] @@ -10,7 +10,7 @@ extern crate panic_halt; use alloc::{borrow::ToOwned as _, format}; use anyhow::anyhow; -use iroha_validator::{ +use iroha_executor::{ data_model::{ evaluate::{EvaluationError, ExpressionEvaluator}, ValidationFail, @@ -24,13 +24,13 @@ use lol_alloc::{FreeListAllocator, LockedAllocator}; #[global_allocator] static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); -struct Validator { +struct Executor { verdict: Result, block_height: u64, host: smart_contract::Host, } -impl Validator { +impl Executor { /// Construct [`Self`] pub fn new(block_height: u64) -> Self { Self { @@ -42,14 +42,14 @@ impl Validator { } macro_rules! defaults { - ( $($validator:ident $(<$param:ident $(: $bound:path)?>)?($operation:ty)),+ $(,)? ) => { $( - fn $validator $(<$param $(: $bound)?>)?(&mut self, authority: &AccountId, operation: $operation) { - iroha_validator::default::$validator(self, authority, operation) + ( $($executor:ident $(<$param:ident $(: $bound:path)?>)?($operation:ty)),+ $(,)? ) => { $( + fn $executor $(<$param $(: $bound)?>)?(&mut self, authority: &AccountId, operation: $operation) { + iroha_executor::default::$executor(self, authority, operation) } )+ }; } -impl Visit for Validator { +impl Visit for Executor { fn visit_query(&mut self, _authority: &AccountId, _query: &QueryBox) { self.deny(ValidationFail::NotPermitted( "All queries are forbidden".to_owned(), @@ -119,11 +119,11 @@ impl Visit for Validator { visit_new_parameter(NewParameter), // Upgrade validation - visit_upgrade_validator(Upgrade), + visit_upgrade_executor(Upgrade), } } -impl Validate for Validator { +impl Validate for Executor { fn verdict(&self) -> &Result { &self.verdict } @@ -137,7 +137,7 @@ impl Validate for Validator { } } -impl ExpressionEvaluator for Validator { +impl ExpressionEvaluator for Executor { fn evaluate(&self, expression: &E) -> Result { self.host.evaluate(expression) } @@ -158,7 +158,7 @@ pub fn migrate(_block_height: u64) -> MigrationResult { ) })?; - Err("This validator always fails to migrate".to_owned()) + Err("This executor always fails to migrate".to_owned()) } #[entrypoint] @@ -167,9 +167,9 @@ pub fn validate_transaction( transaction: SignedTransaction, block_height: u64, ) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_transaction(&authority, &transaction); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_transaction(&authority, &transaction); + executor.verdict } #[entrypoint] @@ -178,14 +178,14 @@ pub fn validate_instruction( instruction: InstructionExpr, block_height: u64, ) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_instruction(&authority, &instruction); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_instruction(&authority, &instruction); + executor.verdict } #[entrypoint] pub fn validate_query(authority: AccountId, query: QueryBox, block_height: u64) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_query(&authority, &query); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_query(&authority, &query); + executor.verdict } diff --git a/client/tests/integration/upgrade.rs b/client/tests/integration/upgrade.rs index f14c960a778..ba33272b403 100644 --- a/client/tests/integration/upgrade.rs +++ b/client/tests/integration/upgrade.rs @@ -11,7 +11,7 @@ use serde_json::json; use test_network::*; #[test] -fn validator_upgrade_should_work() -> Result<()> { +fn executor_upgrade_should_work() -> Result<()> { let (_rt, _peer, client) = ::new().with_port(10_795).start_with_runtime(); wait_for_genesis_committed(&vec![client.clone()], 0); @@ -37,9 +37,9 @@ fn validator_upgrade_should_work() -> Result<()> { .submit_transaction_blocking(&transfer_rose_tx) .expect_err("Should fail"); - upgrade_validator( + upgrade_executor( &client, - "tests/integration/smartcontracts/validator_with_admin", + "tests/integration/smartcontracts/executor_with_admin", )?; // Check that admin can transfer alice's rose now @@ -55,7 +55,7 @@ fn validator_upgrade_should_work() -> Result<()> { } #[test] -fn validator_upgrade_should_run_migration() -> Result<()> { +fn executor_upgrade_should_run_migration() -> Result<()> { let (_rt, _peer, client) = ::new().with_port(10_990).start_with_runtime(); wait_for_genesis_committed(&vec![client.clone()], 0); @@ -79,9 +79,9 @@ fn validator_upgrade_should_run_migration() -> Result<()> { &json!({ "domain_id": DomainId::from_str("wonderland").unwrap() }), ))); - upgrade_validator( + upgrade_executor( &client, - "tests/integration/smartcontracts/validator_with_custom_token", + "tests/integration/smartcontracts/executor_with_custom_token", )?; // Check that `CanUnregisterDomain` doesn't exist @@ -128,32 +128,31 @@ fn migration_fail_should_not_cause_any_effects() { "failed_migration_test_domain".parse().expect("Valid"); assert_domain_does_not_exist(&client, &domain_registered_in_migration); - let _err = upgrade_validator( + let _err = upgrade_executor( &client, - "tests/integration/smartcontracts/validator_with_migration_fail", + "tests/integration/smartcontracts/executor_with_migration_fail", ) .expect_err("Upgrade should fail due to migration failure"); // Checking that things registered in migration does not exist after failed migration assert_domain_does_not_exist(&client, &domain_registered_in_migration); - // The fact that query in previous assertion does not fail means that validator haven't - // been changed, because `validator_with_migration_fail` does not allow any queries + // The fact that query in previous assertion does not fail means that executor haven't + // been changed, because `executor_with_migration_fail` does not allow any queries } -fn upgrade_validator(client: &Client, validator: impl AsRef) -> Result<()> { - info!("Building validator"); +fn upgrade_executor(client: &Client, executor: impl AsRef) -> Result<()> { + info!("Building executor"); - let wasm = iroha_wasm_builder::Builder::new(validator.as_ref()) + let wasm = iroha_wasm_builder::Builder::new(executor.as_ref()) .build()? .optimize()? .into_bytes()?; info!("WASM size is {} bytes", wasm.len()); - let upgrade_validator = - UpgradeExpr::new(Validator::new(WasmSmartContract::from_compiled(wasm))); - client.submit_blocking(upgrade_validator)?; + let upgrade_executor = UpgradeExpr::new(Executor::new(WasmSmartContract::from_compiled(wasm))); + client.submit_blocking(upgrade_executor)?; Ok(()) } diff --git a/configs/peer/executor.wasm b/configs/peer/executor.wasm new file mode 100644 index 0000000000000000000000000000000000000000..9d5028a64b721cf2fca2409455b8a6ce87d5f4a8 GIT binary patch literal 504366 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 z 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

?@X9$+y*z;A&#C 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 z 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

1{N<)-f^!4rED&Sj(dkl>%oMhk5vlzh=& znh+HYJgI>2HxB| zS_C{~mr)9>fh(Ej@5tvRvepE1(g7+nI}KDTwHU*MlFPmecQ7A@f^82gs$Rf((cg)JHRrKsUs?=|W4JMpQakDB#;rmE^39Bor^?<$U%xoj)w|AI(K7*S74FCODUv@ zPIOe3zeAGAfnU5Bt`RW|{#Gf0-zcUEv zZ94REOmZddsSnF2$hJAdd5~ynS18c5tmU!nYL51czu-pLp+bo~Ki`eo&!@v5WBe3z z01_mHPC$(;hgiowCJI2#^`p9Cz*x=|SlLo@!HI=L1X!p>>;+L-)L0k?(E%aUbRufc zA(Tk&s#X&GGB^eAV0F)x1*;k|MtV5g)1gz)rcXl})3+v)Xr6p|tV#B76k7(xP?x0y zp=(6cnIN&xt{}xkz@VIV6eU7JvLJaGCE~&*l!)gX;-wl-wiF2oQPru76^W*XpEPbEd-xie49T~?8x(AQ6q_)9AiIbB|@NYKdT6p5#jBJos9k(hr` zWkMBpucS;+-OE)b_~dI>CN8Sv>#IyK?#n9^8&)Y30<4q?0rnfDO#IJpurh(oqOD8Z z7`nvnZ?rBUAdhtkp&A0Z^fPW>f-a#CUPPC8EOZH`2u8@?OY0IYwMv&THPHuOFI}Rp zu&qmI_(_-W?Kf1H0ELRby0R{ToC~qNq%L9E9bLjY1iHjoF(!ULBaRZH>J@c~xtFL* zJezchbC=g8SZ1jo|NrO``=m?2A=|n{tD7&PORVkfC3T5?UyUx|kAS}9@h?i|cqzJs zKf1Io@z?!Em-w5PsY}dM(V3Pm0fekefH>$9PoYaZZ|oAnaHf1-{H?m&^j*3Ho)5G% zX%H@nF0o;aF7aDyb&02tP!*6l)+H#iT9C%t(y*?&1-Dhfi(BeYL5XA|9A{%)Li&Qmd^mHhMGW|8HdTT?Cr=rF zLzhtg%FrbW1U%j~N@A@_Oj>D>J9@M^X%cdgqdv^?h186h(6-Sbs3YkRo8$a%yRgt9 zaHzqeRK3O`4H@l5*1q*kdsosT=$UX7nRYRnYm^99My*6lqhU1lS%(-@nxQM{5OSg& zR;erN5T~U>5UGkE^=s520#nfke(RDt#FyGS#3|CyuF@g&%~*$6l29xa;>$+Z>qE$2 zk_s`Vv|o)1aY1XNRw05aUsi=E)d{H(Uv8-oP-d$Tgm7Ag(DBZ>>;n;B63RhKg@8K= z(HB^#YgGs<3~Lkzmhv2m!{3JDaG|9*{I@lV!`aIz4st5g5n{3^Y3*-GiUWIikV|pM zX~W8wudFzH`4Wo5-?bG7$Cr|tM%LHK>ZG^*;(>_3M(9uM;-Rf8=?$2`s-^Hh;D?BK zFuvt0W~oqn>iFb~- ztgYi~(-Js^aFxqp$pYML*s|WV(A_swM*v-l7aASmg+zHpWhALF z?oRQKW_9QYHu>XkKxz{+Kqh}O=>#jf!f~ERzaQsX;l(#6Qx`5UxE*7_S1+G;9_ z3Yb2qi3ySQI

8I7m=fC^PwHsv)qjoU!xc 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 literal 0 HcmV?d00001 diff --git a/configs/peer/genesis.json b/configs/peer/genesis.json index fa69236b6d5..2ca5d0365ed 100644 --- a/configs/peer/genesis.json +++ b/configs/peer/genesis.json @@ -197,5 +197,5 @@ } ] ], - "validator": "./validator.wasm" + "executor": "./executor.wasm" } diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm deleted file mode 100644 index 86354b764b7b14072056766520b4c2091e1667c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 504437 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

iOAYvK}ory@-1B^DU_th0ll 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 diff --git a/core/benches/blocks/common.rs b/core/benches/blocks/common.rs index 8bdbef1a5e7..56f769b1778 100644 --- a/core/benches/blocks/common.rs +++ b/core/benches/blocks/common.rs @@ -32,7 +32,7 @@ pub fn create_block( .with_instructions(instructions) .sign(key_pair.clone()) .unwrap(); - let limits = wsv.transaction_validator().transaction_limits; + let limits = wsv.transaction_executor().transaction_limits; let topology = Topology::new(UniqueVec::new()); let block = BlockBuilder::new( @@ -192,14 +192,14 @@ pub fn build_wsv(account_id: &AccountId, key_pair: &KeyPair) -> WorldStateView { } { - let path_to_validator = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../configs/peer/validator.wasm"); - let wasm = std::fs::read(&path_to_validator) - .unwrap_or_else(|_| panic!("Failed to read file: {}", path_to_validator.display())); - let validator = Validator::new(WasmSmartContract::from_compiled(wasm)); - UpgradeExpr::new(validator) + let path_to_executor = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../configs/peer/executor.wasm"); + let wasm = std::fs::read(&path_to_executor) + .unwrap_or_else(|_| panic!("Failed to read file: {}", path_to_executor.display())); + let executor = Executor::new(WasmSmartContract::from_compiled(wasm)); + UpgradeExpr::new(executor) .execute(account_id, &mut wsv) - .expect("Failed to load validator"); + .expect("Failed to load executor"); } wsv diff --git a/core/benches/kura.rs b/core/benches/kura.rs index eff64c3ba29..2f74c5ce1e4 100644 --- a/core/benches/kura.rs +++ b/core/benches/kura.rs @@ -16,7 +16,7 @@ use iroha_data_model::{prelude::*, transaction::TransactionLimits}; use iroha_primitives::unique_vec::UniqueVec; use tokio::{fs, runtime::Runtime}; -async fn measure_block_size_for_n_validators(n_validators: u32) { +async fn measure_block_size_for_n_executors(n_executors: u32) { let alice_id = AccountId::from_str("alice@test").expect("tested"); let bob_id = AccountId::from_str("bob@test").expect("tested"); let xor_id = AssetDefinitionId::from_str("xor#test").expect("tested"); @@ -49,7 +49,7 @@ async fn measure_block_size_for_n_validators(n_validators: u32) { .sign(KeyPair::generate().unwrap()) .unwrap(); - for _ in 1..n_validators { + for _ in 1..n_executors { block = block .sign(KeyPair::generate().expect("Failed to generate KeyPair.")) .unwrap(); @@ -60,14 +60,14 @@ async fn measure_block_size_for_n_validators(n_validators: u32) { let metadata = fs::metadata(dir.path().join("blocks.data")).await.unwrap(); let file_size = Byte::from_bytes(u128::from(metadata.len())).get_appropriate_unit(false); - println!("For {n_validators} validators: {file_size}"); + println!("For {n_executors} executors: {file_size}"); } async fn measure_block_size_async() { println!("File size of a block with 1 transaction with 1 Transfer instruction is:",); for max_faults in 0_u32..5_u32 { - let n_validators = 3 * max_faults + 1; - measure_block_size_for_n_validators(n_validators).await; + let n_executors = 3 * max_faults + 1; + measure_block_size_for_n_executors(n_executors).await; } } diff --git a/core/benches/validation.rs b/core/benches/validation.rs index 4e2af6e771e..d2617396271 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -8,7 +8,7 @@ use iroha_core::{ prelude::*, smartcontracts::{isi::Registrable as _, Execute}, sumeragi::network_topology::Topology, - tx::TransactionValidator, + tx::TransactionExecutor, wsv::World, }; use iroha_data_model::{prelude::*, transaction::TransactionLimits}; @@ -73,15 +73,15 @@ fn build_test_and_transient_wsv(keys: KeyPair) -> WorldStateView { ); { - let path_to_validator = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../configs/peer/validator.wasm"); - let wasm = std::fs::read(&path_to_validator) - .unwrap_or_else(|_| panic!("Failed to read file: {}", path_to_validator.display())); - let validator = Validator::new(WasmSmartContract::from_compiled(wasm)); + let path_to_executor = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../configs/peer/executor.wasm"); + let wasm = std::fs::read(&path_to_executor) + .unwrap_or_else(|_| panic!("Failed to read file: {}", path_to_executor.display())); + let executor = Executor::new(WasmSmartContract::from_compiled(wasm)); let authority = "genesis@genesis".parse().expect("Valid"); - UpgradeExpr::new(validator) + UpgradeExpr::new(executor) .execute(&authority, &mut wsv) - .expect("Failed to load validator"); + .expect("Failed to load executor"); } wsv @@ -127,10 +127,10 @@ fn validate_transaction(criterion: &mut Criterion) { let mut failure_count = 0; let wsv = build_test_and_transient_wsv(keys); let _ = criterion.bench_function("validate", move |b| { - let transaction_validator = TransactionValidator::new(TRANSACTION_LIMITS); + let transaction_executor = TransactionExecutor::new(TRANSACTION_LIMITS); b.iter(|| { let mut wsv = wsv.clone(); - match transaction_validator.validate(transaction.clone(), &mut wsv) { + match transaction_executor.validate(transaction.clone(), &mut wsv) { Ok(_) => success_count += 1, Err(_) => failure_count += 1, } diff --git a/core/src/block.rs b/core/src/block.rs index b880f428c55..177d8e90118 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -169,7 +169,7 @@ mod pending { ) -> Vec { transactions .into_iter() - .map(|tx| match wsv.transaction_validator().validate(tx, wsv) { + .map(|tx| match wsv.transaction_executor().validate(tx, wsv) { Ok(tx) => TransactionValue { value: tx, error: None, @@ -358,8 +358,8 @@ mod valid { // TODO: Unnecessary clone? .cloned() .try_for_each(|TransactionValue{value, error}| { - let transaction_validator = wsv.transaction_validator(); - let limits = &transaction_validator.transaction_limits; + let transaction_executor = wsv.transaction_executor(); + let limits = &transaction_executor.transaction_limits; if error.is_none() { let tx = if is_genesis { @@ -368,7 +368,7 @@ mod valid { AcceptedTransaction::accept(value, limits)? }; - transaction_validator.validate(tx, wsv).map_err(|(_tx, error)| { + transaction_executor.validate(tx, wsv).map_err(|(_tx, error)| { TransactionValidationError::NotValid(error) })?; } else { @@ -378,7 +378,7 @@ mod valid { AcceptedTransaction::accept(value, limits)? }; - match transaction_validator.validate(tx, wsv) { + match transaction_executor.validate(tx, wsv) { Err(rejected_transaction) => Ok(rejected_transaction), Ok(_) => Err(TransactionValidationError::RejectedIsValid), }?; @@ -745,7 +745,7 @@ mod tests { RegisterExpr::new(AssetDefinition::quantity(asset_definition_id)); // Making two transactions that have the same instruction - let transaction_limits = &wsv.transaction_validator().transaction_limits; + let transaction_limits = &wsv.transaction_executor().transaction_limits; let tx = TransactionBuilder::new(alice_id) .with_instructions([create_asset_definition]) .sign(alice_keys.clone()) @@ -787,7 +787,7 @@ mod tests { RegisterExpr::new(AssetDefinition::quantity(asset_definition_id.clone())); // Making two transactions that have the same instruction - let transaction_limits = &wsv.transaction_validator().transaction_limits; + let transaction_limits = &wsv.transaction_executor().transaction_limits; let tx = TransactionBuilder::new(alice_id.clone()) .with_instructions([create_asset_definition]) .sign(alice_keys.clone()) @@ -850,7 +850,7 @@ mod tests { let world = World::with([domain], UniqueVec::new()); let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(world, kura); - let transaction_limits = &wsv.transaction_validator().transaction_limits; + let transaction_limits = &wsv.transaction_executor().transaction_limits; let domain_id = DomainId::from_str("domain").expect("Valid"); let create_domain = RegisterExpr::new(Domain::new(domain_id)); diff --git a/core/src/validator.rs b/core/src/executor.rs similarity index 65% rename from core/src/validator.rs rename to core/src/executor.rs index e6eef59580c..971f7dd7867 100644 --- a/core/src/validator.rs +++ b/core/src/executor.rs @@ -1,12 +1,13 @@ -//! Structures and impls related to *runtime* `Validator`s processing. +//! Structures and impls related to *runtime* `Executor`s processing. use derive_more::DebugCustom; use iroha_data_model::{ account::AccountId, + executor as data_model_executor, isi::InstructionExpr, query::QueryBox, transaction::{Executable, SignedTransaction}, - validator as data_model_validator, ValidationFail, + ValidationFail, }; use iroha_logger::trace; use serde::{ @@ -37,7 +38,7 @@ impl From for ValidationFail { } } -/// Error used in [`migrate()`](Validator::migrate). +/// Error used in [`migrate()`](Executor::migrate). #[derive(Debug, thiserror::Error)] pub enum MigrationError { /// Error during WASM blob loading or runtime preparation. @@ -45,40 +46,40 @@ pub enum MigrationError { Wasm(#[from] wasm::error::Error), /// Error returned by entrypoint during execution. #[error("Entrypoint returned error: {0}")] - EntrypointExecution(data_model_validator::MigrationError), + EntrypointExecution(data_model_executor::MigrationError), } -/// Validator that verifies that operation is valid and executes it. +/// Executor that verifies that operation is valid and executes it. /// /// Executing is done in order to verify dependent instructions in transaction. /// So in fact it's more like an **Executor**, and it probably will be renamed soon. /// /// Can be upgraded with [`Upgrade`](iroha_data_model::isi::Upgrade) instruction. #[derive(Debug, Default, Clone, Serialize)] -pub enum Validator { - /// Initial validator that allows all operations and performs no permission checking. +pub enum Executor { + /// Initial executor that allows all operations and performs no permission checking. #[default] Initial, - /// User-provided validator with arbitrary logic. - UserProvided(UserProvidedValidator), + /// User-provided executor with arbitrary logic. + UserProvided(UserProvidedExecutor), } -/// Validator provided by user. +/// Executor provided by user. /// /// Used to not to leak private data to the user. #[derive(Debug, Clone, Serialize)] #[serde(transparent)] -pub struct UserProvidedValidator(LoadedValidator); +pub struct UserProvidedExecutor(LoadedExecutor); -impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Validator> { - type Value = Validator; +impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Executor> { + type Value = Executor; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { - struct ValidatorVisitor<'l> { - loader: &'l WasmSeed<'l, Validator>, + struct ExecutorVisitor<'l> { + loader: &'l WasmSeed<'l, Executor>, } #[derive(Deserialize)] @@ -88,8 +89,8 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Validator> { UserProvided, } - impl<'de> Visitor<'de> for ValidatorVisitor<'_> { - type Value = Validator; + impl<'de> Visitor<'de> for ExecutorVisitor<'_> { + type Value = Executor; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("an enum variant") @@ -102,12 +103,12 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Validator> { match data.variant()? { ("Initial", variant) => { variant.unit_variant()?; - Ok(Validator::Initial) + Ok(Executor::Initial) } ("UserProvided", variant) => { let loaded = - variant.newtype_variant_seed(self.loader.cast::())?; - Ok(Validator::UserProvided(UserProvidedValidator(loaded))) + variant.newtype_variant_seed(self.loader.cast::())?; + Ok(Executor::UserProvided(UserProvidedExecutor(loaded))) } (other, _) => Err(serde::de::Error::unknown_variant( other, @@ -118,21 +119,21 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Validator> { } deserializer.deserialize_enum( - "Validator", + "Executor", &["Initial", "UserProvided"], - ValidatorVisitor { loader: &self }, + ExecutorVisitor { loader: &self }, ) } } -impl Validator { +impl Executor { /// Validate [`SignedTransaction`]. /// /// # Errors /// /// - Failed to prepare runtime for WASM execution; /// - Failed to execute the entrypoint of the WASM blob; - /// - Validator denied the operation. + /// - Executor denied the operation. pub fn validate_transaction( &self, wsv: &mut WorldStateView, @@ -152,17 +153,17 @@ impl Validator { } Ok(()) } - Self::UserProvided(UserProvidedValidator(loaded_validator)) => { + Self::UserProvided(UserProvidedExecutor(loaded_executor)) => { let runtime = - wasm::RuntimeBuilder::::new() + wasm::RuntimeBuilder::::new() .with_engine(wsv.engine.clone()) // Cloning engine is cheap, see [`wasmtime::Engine`] docs .with_configuration(wsv.config.wasm_runtime_config) .build()?; - runtime.execute_validator_validate_transaction( + runtime.execute_executor_validate_transaction( wsv, authority, - &loaded_validator.module, + &loaded_executor.module, transaction, )? } @@ -175,7 +176,7 @@ impl Validator { /// /// - Failed to prepare runtime for WASM execution; /// - Failed to execute the entrypoint of the WASM blob; - /// - Validator denied the operation. + /// - Executor denied the operation. pub fn validate_instruction( &self, wsv: &mut WorldStateView, @@ -186,17 +187,17 @@ impl Validator { match self { Self::Initial => instruction.execute(authority, wsv).map_err(Into::into), - Self::UserProvided(UserProvidedValidator(loaded_validator)) => { + Self::UserProvided(UserProvidedExecutor(loaded_executor)) => { let runtime = - wasm::RuntimeBuilder::::new() + wasm::RuntimeBuilder::::new() .with_engine(wsv.engine.clone()) // Cloning engine is cheap, see [`wasmtime::Engine`] docs .with_configuration(wsv.config.wasm_runtime_config) .build()?; - runtime.execute_validator_validate_instruction( + runtime.execute_executor_validate_instruction( wsv, authority, - &loaded_validator.module, + &loaded_executor.module, instruction, )? } @@ -209,7 +210,7 @@ impl Validator { /// /// - Failed to prepare runtime for WASM execution; /// - Failed to execute the entrypoint of the WASM blob; - /// - Validator denied the operation. + /// - Executor denied the operation. pub fn validate_query( &self, wsv: &WorldStateView, @@ -220,96 +221,96 @@ impl Validator { match self { Self::Initial => Ok(()), - Self::UserProvided(UserProvidedValidator(loaded_validator)) => { - let runtime = wasm::RuntimeBuilder::::new() + Self::UserProvided(UserProvidedExecutor(loaded_executor)) => { + let runtime = wasm::RuntimeBuilder::::new() .with_engine(wsv.engine.clone()) // Cloning engine is cheap, see [`wasmtime::Engine`] docs .with_configuration(wsv.config.wasm_runtime_config) .build()?; - runtime.execute_validator_validate_query( + runtime.execute_executor_validate_query( wsv, authority, - &loaded_validator.module, + &loaded_executor.module, query, )? } } } - /// Migrate validator to a new user-provided one. + /// Migrate executor to a new user-provided one. /// - /// Execute `migrate()` entrypoint of the `raw_validator` and set `self` to - /// [`UserProvided`](Validator::UserProvided) with `raw_validator`. + /// Execute `migrate()` entrypoint of the `raw_executor` and set `self` to + /// [`UserProvided`](Executor::UserProvided) with `raw_executor`. /// /// # Errors /// - /// - Failed to load `raw_validator`; + /// - Failed to load `raw_executor`; /// - Failed to prepare runtime for WASM execution; /// - Failed to execute entrypoint of the WASM blob. pub fn migrate( &mut self, - raw_validator: data_model_validator::Validator, + raw_executor: data_model_executor::Executor, wsv: &mut WorldStateView, authority: &AccountId, ) -> Result<(), MigrationError> { - trace!("Running validator migration"); + trace!("Running executor migration"); - let loaded_validator = LoadedValidator::load(&wsv.engine, raw_validator)?; + let loaded_executor = LoadedExecutor::load(&wsv.engine, raw_executor)?; - let runtime = wasm::RuntimeBuilder::::new() + let runtime = wasm::RuntimeBuilder::::new() .with_engine(wsv.engine.clone()) // Cloning engine is cheap, see [`wasmtime::Engine`] docs .with_configuration(wsv.config.wasm_runtime_config) .build()?; runtime - .execute_validator_migration(wsv, authority, &loaded_validator.module)? + .execute_executor_migration(wsv, authority, &loaded_executor.module)? .map_err(MigrationError::EntrypointExecution)?; - *self = Self::UserProvided(UserProvidedValidator(loaded_validator)); + *self = Self::UserProvided(UserProvidedExecutor(loaded_executor)); Ok(()) } } -/// [`Validator`] with [`Module`](wasmtime::Module) for execution. +/// [`Executor`] with [`Module`](wasmtime::Module) for execution. /// -/// Creating a [`wasmtime::Module`] is expensive, so we do it once on [`migrate()`](Validator::migrate) +/// Creating a [`wasmtime::Module`] is expensive, so we do it once on [`migrate()`](Executor::migrate) /// step and reuse it later on validating steps. #[derive(DebugCustom, Clone, Serialize)] -#[debug(fmt = "LoadedValidator {{ module: }}")] -struct LoadedValidator { +#[debug(fmt = "LoadedExecutor {{ module: }}")] +struct LoadedExecutor { #[serde(skip)] module: wasmtime::Module, - raw_validator: data_model_validator::Validator, + raw_executor: data_model_executor::Executor, } -impl LoadedValidator { +impl LoadedExecutor { pub fn load( engine: &wasmtime::Engine, - raw_validator: data_model_validator::Validator, + raw_executor: data_model_executor::Executor, ) -> Result { Ok(Self { - module: wasm::load_module(engine, &raw_validator.wasm)?, - raw_validator, + module: wasm::load_module(engine, &raw_executor.wasm)?, + raw_executor, }) } } -impl<'de> DeserializeSeed<'de> for WasmSeed<'_, LoadedValidator> { - type Value = LoadedValidator; +impl<'de> DeserializeSeed<'de> for WasmSeed<'_, LoadedExecutor> { + type Value = LoadedExecutor; fn deserialize(self, deserializer: D) -> Result where D: serde::Deserializer<'de>, { - struct LoadedValidatorVisitor<'l> { - loader: &'l WasmSeed<'l, LoadedValidator>, + struct LoadedExecutorVisitor<'l> { + loader: &'l WasmSeed<'l, LoadedExecutor>, } - impl<'de> Visitor<'de> for LoadedValidatorVisitor<'_> { - type Value = LoadedValidator; + impl<'de> Visitor<'de> for LoadedExecutorVisitor<'_> { + type Value = LoadedExecutor; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("struct LoadedValidator") + formatter.write_str("struct LoadedExecutor") } fn visit_map(self, mut map: M) -> Result @@ -317,19 +318,19 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, LoadedValidator> { M: MapAccess<'de>, { while let Some(key) = map.next_key::()? { - if key.as_str() == "raw_validator" { - let validator: data_model_validator::Validator = map.next_value()?; - return Ok(LoadedValidator::load(self.loader.engine, validator).unwrap()); + if key.as_str() == "raw_executor" { + let executor: data_model_executor::Executor = map.next_value()?; + return Ok(LoadedExecutor::load(self.loader.engine, executor).unwrap()); } } - Err(serde::de::Error::missing_field("raw_validator")) + Err(serde::de::Error::missing_field("raw_executor")) } } deserializer.deserialize_struct( - "LoadedValidator", - &["raw_validator"], - LoadedValidatorVisitor { loader: &self }, + "LoadedExecutor", + &["raw_executor"], + LoadedExecutorVisitor { loader: &self }, ) } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 80093250ece..7337b88851e 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -2,6 +2,7 @@ pub mod block; pub mod block_sync; +pub mod executor; pub mod gossiper; pub mod kura; pub mod modules; @@ -10,7 +11,6 @@ pub mod smartcontracts; pub mod snapshot; pub mod sumeragi; pub mod tx; -pub mod validator; pub mod wsv; use core::time::Duration; diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index f354b8eb8fc..c633adad28c 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -450,8 +450,8 @@ impl Execute for UpgradeExpr { fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let object = wsv.evaluate(&self.object)?; match object { - UpgradableBox::Validator(object) => { - Upgrade:: { object }.execute(authority, wsv) + UpgradableBox::Executor(object) => { + Upgrade:: { object }.execute(authority, wsv) } } } diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index a1f6c513515..5b7795495f5 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -79,7 +79,7 @@ impl ValidQueryRequest { )) .into()); } - wsv.validator() + wsv.executor() .validate_query(wsv, query.authority(), query.query().clone())?; Ok(Self(query)) } @@ -420,7 +420,7 @@ mod tests { .with_instructions(instructions) .sign(ALICE_KEYS.clone())?; - let tx_limits = &wsv.transaction_validator().transaction_limits; + let tx_limits = &wsv.transaction_executor().transaction_limits; let va_tx = AcceptedTransaction::accept(tx, tx_limits)?; let topology = Topology::new(UniqueVec::new()); diff --git a/core/src/smartcontracts/isi/triggers/mod.rs b/core/src/smartcontracts/isi/triggers/mod.rs index 2b35c7e1b0d..c0bf5e49721 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -177,7 +177,7 @@ pub mod isi { if allow_execute { Ok(()) } else { - // TODO: We should check authority on Runtime Validator level + // TODO: We should check authority on Runtime Executor level // so currently the error message is not exhaustive Err(Error::InvariantViolation(String::from( "Trigger can't be executed manually", diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index 089c3f2e778..64199fd9eb8 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -214,16 +214,16 @@ pub mod isi { } } - impl Execute for Upgrade { - #[metrics(+"upgrade_validator")] + impl Execute for Upgrade { + #[metrics(+"upgrade_executor")] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { - let raw_validator = self.object; + let raw_executor = self.object; - // Cloning validator to avoid multiple mutable borrows of `wsv`. + // Cloning executor to avoid multiple mutable borrows of `wsv`. // Also it's a cheap operation. - let mut upgraded_validator = wsv.validator().clone(); - upgraded_validator - .migrate(raw_validator, wsv, authority) + let mut upgraded_executor = wsv.executor().clone(); + upgraded_executor + .migrate(raw_executor, wsv, authority) .map_err(|migration_error| { InvalidParameterError::Wasm(format!( "{:?}", @@ -231,9 +231,9 @@ pub mod isi { )) })?; - wsv.world_mut().validator = upgraded_validator; + wsv.world_mut().executor = upgraded_executor; - wsv.emit_events(std::iter::once(ValidatorEvent::Upgraded)); + wsv.emit_events(std::iter::once(ExecutorEvent::Upgraded)); Ok(()) } diff --git a/core/src/smartcontracts/mod.rs b/core/src/smartcontracts/mod.rs index 056dc8a6ab8..05d0195defd 100644 --- a/core/src/smartcontracts/mod.rs +++ b/core/src/smartcontracts/mod.rs @@ -77,7 +77,7 @@ impl iroha_data_model::evaluate::Context for Context<'_> { .map(|value| match value { LazyValue::Value(value) => value, // NOTE: This will only be executed when evaluating an expression for an - // instruction, i.e. it will only be executed from the validator/executor. + // instruction, i.e. it will only be executed from the executor. LazyValue::Iter(iter) => Value::Vec(iter.collect()), }) .map_err(Into::into) diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index af233d52446..c307455a06f 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -5,7 +5,7 @@ use error::*; use import_traits::{ - ExecuteOperations as _, GetValidatorPayloads as _, SetPermissionTokenSchema as _, + ExecuteOperations as _, GetExecutorPayloads as _, SetPermissionTokenSchema as _, }; use iroha_config::{ base::proxy::Builder, @@ -13,12 +13,12 @@ use iroha_config::{ }; use iroha_data_model::{ account::AccountId, + executor::{self, MigrationResult}, isi::InstructionExpr, permission::PermissionTokenSchema, prelude::*, query::QueryBox, smart_contract::payloads::{self, Validate}, - validator::{self, MigrationResult}, Level as LogLevel, ValidationFail, }; use iroha_logger::debug; @@ -63,10 +63,10 @@ mod import { pub const TRIGGER_MAIN: &str = "_iroha_trigger_main"; - pub const VALIDATOR_VALIDATE_TRANSACTION: &str = "_iroha_validator_validate_transaction"; - pub const VALIDATOR_VALIDATE_INSTRUCTION: &str = "_iroha_validator_validate_instruction"; - pub const VALIDATOR_VALIDATE_QUERY: &str = "_iroha_validator_validate_query"; - pub const VALIDATOR_MIGRATE: &str = "_iroha_validator_migrate"; + pub const EXECUTOR_VALIDATE_TRANSACTION: &str = "_iroha_executor_validate_transaction"; + pub const EXECUTOR_VALIDATE_INSTRUCTION: &str = "_iroha_executor_validate_instruction"; + pub const EXECUTOR_VALIDATE_QUERY: &str = "_iroha_executor_validate_query"; + pub const EXECUTOR_MIGRATE: &str = "_iroha_executor_migrate"; } mod import_traits { @@ -89,7 +89,7 @@ mod import_traits { ) -> Result<(), ValidationFail>; } - pub trait GetValidatorPayloads { + pub trait GetExecutorPayloads { #[codec::wrap_trait_fn] fn get_migrate_payload(state: &S) -> payloads::Migrate; @@ -269,15 +269,15 @@ fn create_config() -> Result { /// Limits checker for smartcontracts. #[derive(Copy, Clone)] -struct LimitsValidator { +struct LimitsExecutor { /// Number of instructions in the smartcontract instruction_count: u64, /// Max allowed number of instructions in the smartcontract max_instruction_count: u64, } -impl LimitsValidator { - /// Create new [`LimitsValidator`] +impl LimitsExecutor { + /// Create new [`LimitsExecutor`] pub fn new(max_instruction_count: u64) -> Self { Self { instruction_count: 0, @@ -390,7 +390,7 @@ pub mod state { pub struct SmartContract<'wrld> { pub(super) common: Common<'wrld>, /// Should be set for smart contract validation only. - pub(super) limits_validator: Option, + pub(super) limits_executor: Option, } impl LogSpan for SmartContract<'_> { @@ -460,8 +460,8 @@ pub mod state { } } - pub mod validator { - //! States related to *Validator* execution. + pub mod executor { + //! States related to *Executor* execution. use super::*; @@ -504,13 +504,13 @@ pub mod state { } } - /// State for executing `validate_transaction()` entrypoint of validator + /// State for executing `validate_transaction()` entrypoint of executor pub type ValidateTransaction<'wrld> = ValidateMut<'wrld, SignedTransaction>; - /// State for executing `validate_instruction()` entrypoint of validator + /// State for executing `validate_instruction()` entrypoint of executor pub type ValidateInstruction<'wrld> = ValidateMut<'wrld, InstructionExpr>; - /// State for executing `validate_query()` entrypoint of validator + /// State for executing `validate_query()` entrypoint of executor /// /// Does not implement [`WsvMut`] because it contains immutable reference to /// [`WorldStateView`] since it shouldn't be changed during *query* validation. @@ -546,7 +546,7 @@ pub mod state { } } - /// State for executing `migrate()` entrypoint of validator + /// State for executing `migrate()` entrypoint of executor pub struct Migrate<'wrld>(pub(in super::super) Common<'wrld>); impl LimitsMut for Migrate<'_> { @@ -739,12 +739,12 @@ impl Runtime { store } - fn execute_validator_validate_internal( + fn execute_executor_validate_internal( &self, module: &wasmtime::Module, state: S, validate_fn_name: &'static str, - ) -> Result { + ) -> Result { let mut store = self.create_store(state); let instance = self.instantiate_module(module, &mut store)?; @@ -772,12 +772,12 @@ impl Runtime { let wsv = state.wsv(); - // NOTE: Smart contract (not validator) is trying to execute the query, validate it first + // NOTE: Smart contract (not executor) is trying to execute the query, validate it first // TODO: Validation should be skipped when executing smart contract. // There should be two steps validation and execution. First smart contract // is validated and then it's executed. Here it's validating in both steps. // Add a flag indicating whether smart contract is being validated or executed - wsv.validator() + wsv.executor() .validate_query(wsv, state.authority(), query.clone())?; query @@ -801,8 +801,8 @@ impl Runtime { // Add a flag indicating whether smart contract is being validated or executed let authority = state.authority().clone(); let wsv = state.wsv_mut(); - wsv.validator() - .clone() // Cloning validator is a cheap operation + wsv.executor() + .clone() // Cloning executor is a cheap operation .validate_instruction(wsv, &authority, instruction) } } @@ -824,7 +824,7 @@ impl<'wrld> Runtime> { let span = wasm_log_span!("Smart contract execution", %authority); let state = state::SmartContract { common: state::Common::new(wsv, authority, self.config, span), - limits_validator: None, + limits_executor: None, }; self.execute_smart_contract_with_state(bytes, state) @@ -847,7 +847,7 @@ impl<'wrld> Runtime> { let span = wasm_log_span!("Smart contract validation", %authority); let state = state::SmartContract { common: state::Common::new(wsv, authority, self.config, span), - limits_validator: Some(LimitsValidator::new(max_instruction_count)), + limits_executor: Some(LimitsExecutor::new(max_instruction_count)), }; self.execute_smart_contract_with_state(bytes, state) @@ -895,8 +895,8 @@ impl<'wrld> import_traits::ExecuteOperations> instruction: InstructionExpr, state: &mut state::SmartContract<'wrld>, ) -> Result<(), ValidationFail> { - if let Some(limits_validator) = state.limits_validator.as_mut() { - limits_validator.check_instruction_limits()?; + if let Some(limits_executor) = state.limits_executor.as_mut() { + limits_executor.check_instruction_limits()?; } Self::default_execute_instruction(instruction, state) @@ -966,19 +966,19 @@ impl<'wrld> import_traits::ExecuteOperations> } /// Marker trait to auto-implement [`import_traits::ExecuteOperations`] for a concrete -/// *Validator* [`Runtime`]. +/// *Executor* [`Runtime`]. /// /// *Mut* means that [`WorldStateView`] will be mutated. -trait ExecuteOperationsAsValidatorMut {} +trait ExecuteOperationsAsExecutorMut {} impl import_traits::ExecuteOperations for R where - R: ExecuteOperationsAsValidatorMut, + R: ExecuteOperationsAsExecutorMut, S: state::Wsv + state::WsvMut + state::Authority, { #[codec::wrap] fn execute_query(query: QueryBox, state: &S) -> Result { - debug!(%query, "Executing as validator"); + debug!(%query, "Executing as executor"); query .execute(state.wsv()) @@ -994,7 +994,7 @@ where instruction: InstructionExpr, state: &mut S, ) -> Result<(), ValidationFail> { - debug!(%instruction, "Executing as validator"); + debug!(%instruction, "Executing as executor"); instruction .execute(&state.authority().clone(), state.wsv_mut()) @@ -1004,7 +1004,7 @@ where /// Marker trait to auto-implement [`import_traits::SetPermissionTokenSchema`] for a concrete [`Runtime`]. /// -/// Useful because in *Validator* exist more entrypoints than just `migrate()` which is the +/// Useful because *Executor* exposes more entrypoints than just `migrate()` which is the /// only entrypoint allowed to execute operations on permission tokens. trait FakeSetPermissionTokenSchema { /// Entrypoint function name for panic message @@ -1018,59 +1018,59 @@ where #[codec::wrap] fn set_permission_token_schema(_schema: PermissionTokenSchema, _state: &mut S) { panic!( - "Validator `{}()` entrypoint should not set permission token schema", + "Executor `{}()` entrypoint should not set permission token schema", Self::ENTRYPOINT_FN_NAME ) } } -impl<'wrld> Runtime> { - /// Execute `validate_transaction()` entrypoint of the given module of runtime validator +impl<'wrld> Runtime> { + /// Execute `validate_transaction()` entrypoint of the given module of runtime executor /// /// # Errors /// /// - if failed to instantiate provided `module` /// - if unable to find expected function export /// - if the execution of the smartcontract fails - /// - if unable to decode [`validator::Result`] - pub fn execute_validator_validate_transaction( + /// - if unable to decode [`executor::Result`] + pub fn execute_executor_validate_transaction( &self, wsv: &'wrld mut WorldStateView, authority: &AccountId, module: &wasmtime::Module, transaction: SignedTransaction, - ) -> Result { + ) -> Result { let span = wasm_log_span!("Running `validate_transaction()`"); - self.execute_validator_validate_internal( + self.execute_executor_validate_internal( module, - state::validator::ValidateTransaction { + state::executor::ValidateTransaction { common: state::Common::new(wsv, authority.clone(), self.config, span), to_validate: transaction, }, - import::VALIDATOR_VALIDATE_TRANSACTION, + import::EXECUTOR_VALIDATE_TRANSACTION, ) } } -impl<'wrld> ExecuteOperationsAsValidatorMut> - for Runtime> +impl<'wrld> ExecuteOperationsAsExecutorMut> + for Runtime> { } -impl<'wrld> import_traits::GetValidatorPayloads> - for Runtime> +impl<'wrld> import_traits::GetExecutorPayloads> + for Runtime> { #[codec::wrap] fn get_migrate_payload( - _state: &state::validator::ValidateTransaction<'wrld>, + _state: &state::executor::ValidateTransaction<'wrld>, ) -> payloads::Migrate { - panic!("Validator `validate_transaction()` entrypoint should not query payload for `migrate()` entrypoint") + panic!("Executor `validate_transaction()` entrypoint should not query payload for `migrate()` entrypoint") } #[codec::wrap] fn get_validate_transaction_payload( - state: &state::validator::ValidateTransaction<'wrld>, + state: &state::executor::ValidateTransaction<'wrld>, ) -> Validate { Validate { authority: state.authority().clone(), @@ -1081,79 +1081,79 @@ impl<'wrld> import_traits::GetValidatorPayloads, + _state: &state::executor::ValidateTransaction<'wrld>, ) -> Validate { - panic!("Validator `validate_transaction()` entrypoint should not query payload for `validate_instruction()` entrypoint") + panic!("Executor `validate_transaction()` entrypoint should not query payload for `validate_instruction()` entrypoint") } #[codec::wrap] fn get_validate_query_payload( - _state: &state::validator::ValidateTransaction<'wrld>, + _state: &state::executor::ValidateTransaction<'wrld>, ) -> Validate { - panic!("Validator `validate_transaction()` entrypoint should not query payload for `validate_query()` entrypoint") + panic!("Executor `validate_transaction()` entrypoint should not query payload for `validate_query()` entrypoint") } } -impl<'wrld> FakeSetPermissionTokenSchema> - for Runtime> +impl<'wrld> FakeSetPermissionTokenSchema> + for Runtime> { const ENTRYPOINT_FN_NAME: &'static str = "validate_transaction"; } -impl<'wrld> Runtime> { - /// Execute `validate_instruction()` entrypoint of the given module of runtime validator +impl<'wrld> Runtime> { + /// Execute `validate_instruction()` entrypoint of the given module of runtime executor /// /// # Errors /// /// - if failed to instantiate provided `module` /// - if unable to find expected function export /// - if the execution of the smartcontract fails - /// - if unable to decode [`validator::Result`] - pub fn execute_validator_validate_instruction( + /// - if unable to decode [`executor::Result`] + pub fn execute_executor_validate_instruction( &self, wsv: &'wrld mut WorldStateView, authority: &AccountId, module: &wasmtime::Module, instruction: InstructionExpr, - ) -> Result { + ) -> Result { let span = wasm_log_span!("Running `validate_instruction()`"); - self.execute_validator_validate_internal( + self.execute_executor_validate_internal( module, - state::validator::ValidateInstruction { + state::executor::ValidateInstruction { common: state::Common::new(wsv, authority.clone(), self.config, span), to_validate: instruction, }, - import::VALIDATOR_VALIDATE_INSTRUCTION, + import::EXECUTOR_VALIDATE_INSTRUCTION, ) } } -impl<'wrld> ExecuteOperationsAsValidatorMut> - for Runtime> +impl<'wrld> ExecuteOperationsAsExecutorMut> + for Runtime> { } -impl<'wrld> import_traits::GetValidatorPayloads> - for Runtime> +impl<'wrld> import_traits::GetExecutorPayloads> + for Runtime> { #[codec::wrap] fn get_migrate_payload( - _state: &state::validator::ValidateInstruction<'wrld>, + _state: &state::executor::ValidateInstruction<'wrld>, ) -> payloads::Migrate { - panic!("Validator `validate_instruction()` entrypoint should not query payload for `migrate()` entrypoint") + panic!("Executor `validate_instruction()` entrypoint should not query payload for `migrate()` entrypoint") } #[codec::wrap] fn get_validate_transaction_payload( - _state: &state::validator::ValidateInstruction<'wrld>, + _state: &state::executor::ValidateInstruction<'wrld>, ) -> Validate { - panic!("Validator `validate_instruction()` entrypoint should not query payload for `validate_transaction()` entrypoint") + panic!("Executor `validate_instruction()` entrypoint should not query payload for `validate_transaction()` entrypoint") } #[codec::wrap] fn get_validate_instruction_payload( - state: &state::validator::ValidateInstruction<'wrld>, + state: &state::executor::ValidateInstruction<'wrld>, ) -> Validate { Validate { authority: state.authority().clone(), @@ -1164,59 +1164,59 @@ impl<'wrld> import_traits::GetValidatorPayloads, + _state: &state::executor::ValidateInstruction<'wrld>, ) -> Validate { - panic!("Validator `validate_instruction()` entrypoint should not query payload for `validate_query()` entrypoint") + panic!("Executor `validate_instruction()` entrypoint should not query payload for `validate_query()` entrypoint") } } -impl<'wrld> FakeSetPermissionTokenSchema> - for Runtime> +impl<'wrld> FakeSetPermissionTokenSchema> + for Runtime> { const ENTRYPOINT_FN_NAME: &'static str = "validate_instruction"; } -impl<'wrld> Runtime> { - /// Execute `validate_query()` entrypoint of the given module of runtime validator +impl<'wrld> Runtime> { + /// Execute `validate_query()` entrypoint of the given module of runtime executor /// /// # Errors /// /// - if failed to instantiate provided `module` /// - if unable to find expected function export /// - if the execution of the smartcontract fails - /// - if unable to decode [`validator::Result`] - pub fn execute_validator_validate_query( + /// - if unable to decode [`executor::Result`] + pub fn execute_executor_validate_query( &self, wsv: &'wrld WorldStateView, authority: &AccountId, module: &wasmtime::Module, query: QueryBox, - ) -> Result { + ) -> Result { let span = wasm_log_span!("Running `validate_query()`"); - self.execute_validator_validate_internal( + self.execute_executor_validate_internal( module, - state::validator::ValidateQuery { + state::executor::ValidateQuery { wsv, authority: authority.clone(), store_limits: state::store_limits_from_config(&self.config), log_span: span, query, }, - import::VALIDATOR_VALIDATE_QUERY, + import::EXECUTOR_VALIDATE_QUERY, ) } } -impl<'wrld> import_traits::ExecuteOperations> - for Runtime> +impl<'wrld> import_traits::ExecuteOperations> + for Runtime> { #[codec::wrap] fn execute_query( query: QueryBox, - state: &state::validator::ValidateQuery<'wrld>, + state: &state::executor::ValidateQuery<'wrld>, ) -> Result { - debug!(%query, "Executing as validator"); + debug!(%query, "Executing as executor"); query .execute(state.wsv()) @@ -1230,37 +1230,37 @@ impl<'wrld> import_traits::ExecuteOperations, + _state: &mut state::executor::ValidateQuery<'wrld>, ) -> Result<(), ValidationFail> { - panic!("Validator `validate_query()` entrypoint should not execute instructions") + panic!("Executor `validate_query()` entrypoint should not execute instructions") } } -impl<'wrld> import_traits::GetValidatorPayloads> - for Runtime> +impl<'wrld> import_traits::GetExecutorPayloads> + for Runtime> { #[codec::wrap] - fn get_migrate_payload(_state: &state::validator::ValidateQuery<'wrld>) -> payloads::Migrate { - panic!("Validator `validate_query()` entrypoint should not query payload for `migrate()` entrypoint") + fn get_migrate_payload(_state: &state::executor::ValidateQuery<'wrld>) -> payloads::Migrate { + panic!("Executor `validate_query()` entrypoint should not query payload for `migrate()` entrypoint") } #[codec::wrap] fn get_validate_transaction_payload( - _state: &state::validator::ValidateQuery<'wrld>, + _state: &state::executor::ValidateQuery<'wrld>, ) -> Validate { - panic!("Validator `validate_query()` entrypoint should not query payload for `validate_transaction()` entrypoint") + panic!("Executor `validate_query()` entrypoint should not query payload for `validate_transaction()` entrypoint") } #[codec::wrap] fn get_validate_instruction_payload( - _state: &state::validator::ValidateQuery<'wrld>, + _state: &state::executor::ValidateQuery<'wrld>, ) -> Validate { - panic!("Validator `validate_query()` entrypoint should not query payload for `validate_instruction()` entrypoint") + panic!("Executor `validate_query()` entrypoint should not query payload for `validate_instruction()` entrypoint") } #[codec::wrap] fn get_validate_query_payload( - state: &state::validator::ValidateQuery<'wrld>, + state: &state::executor::ValidateQuery<'wrld>, ) -> Validate { Validate { authority: state.authority().clone(), @@ -1270,14 +1270,14 @@ impl<'wrld> import_traits::GetValidatorPayloads FakeSetPermissionTokenSchema> - for Runtime> +impl<'wrld> FakeSetPermissionTokenSchema> + for Runtime> { const ENTRYPOINT_FN_NAME: &'static str = "validate_query"; } -impl<'wrld> Runtime> { - /// Execute `migrate()` entrypoint of *Validator* +impl<'wrld> Runtime> { + /// Execute `migrate()` entrypoint of *Executor* /// /// # Errors /// @@ -1285,14 +1285,14 @@ impl<'wrld> Runtime> { /// - if failed to get export function for `migrate()` /// - if failed to call export function /// - if failed to decode [`MigrationResult`] - pub fn execute_validator_migration( + pub fn execute_executor_migration( &self, wsv: &'wrld mut WorldStateView, authority: &AccountId, module: &wasmtime::Module, ) -> Result { let span = wasm_log_span!("Running migration"); - let state = state::validator::Migrate(state::Common::new( + let state = state::executor::Migrate(state::Common::new( wsv, authority.clone(), self.config, @@ -1302,7 +1302,7 @@ impl<'wrld> Runtime> { let mut store = self.create_store(state); let instance = self.instantiate_module(module, &mut store)?; - let migrate_fn = Self::get_typed_func(&instance, &mut store, import::VALIDATOR_MIGRATE)?; + let migrate_fn = Self::get_typed_func(&instance, &mut store, import::EXECUTOR_MIGRATE)?; let offset = migrate_fn .call(&mut store, ()) @@ -1318,8 +1318,8 @@ impl<'wrld> Runtime> { } } -impl<'wrld> ExecuteOperationsAsValidatorMut> - for Runtime> +impl<'wrld> ExecuteOperationsAsExecutorMut> + for Runtime> { } @@ -1332,11 +1332,11 @@ impl<'wrld> ExecuteOperationsAsValidatorMut> /// /// Panics with error message if called, because it should never be called from /// `migrate()` entrypoint. -impl<'wrld> import_traits::GetValidatorPayloads> - for Runtime> +impl<'wrld> import_traits::GetExecutorPayloads> + for Runtime> { #[codec::wrap] - fn get_migrate_payload(state: &state::validator::Migrate<'wrld>) -> payloads::Migrate { + fn get_migrate_payload(state: &state::executor::Migrate<'wrld>) -> payloads::Migrate { payloads::Migrate { block_height: state.wsv().height(), } @@ -1344,31 +1344,31 @@ impl<'wrld> import_traits::GetValidatorPayloads #[codec::wrap] fn get_validate_transaction_payload( - _state: &state::validator::Migrate<'wrld>, + _state: &state::executor::Migrate<'wrld>, ) -> Validate { - panic!("Validator `migrate()` entrypoint should not query payload for `validate_transaction()` entrypoint") + panic!("Executor `migrate()` entrypoint should not query payload for `validate_transaction()` entrypoint") } #[codec::wrap] fn get_validate_instruction_payload( - _state: &state::validator::Migrate<'wrld>, + _state: &state::executor::Migrate<'wrld>, ) -> Validate { - panic!("Validator `migrate()` entrypoint should not query payload for `validate_instruction()` entrypoint") + panic!("Executor `migrate()` entrypoint should not query payload for `validate_instruction()` entrypoint") } #[codec::wrap] - fn get_validate_query_payload(_state: &state::validator::Migrate<'wrld>) -> Validate { - panic!("Validator `migrate()` entrypoint should not query payload for `validate_query()` entrypoint") + fn get_validate_query_payload(_state: &state::executor::Migrate<'wrld>) -> Validate { + panic!("Executor `migrate()` entrypoint should not query payload for `validate_query()` entrypoint") } } -impl<'wrld> import_traits::SetPermissionTokenSchema> - for Runtime> +impl<'wrld> import_traits::SetPermissionTokenSchema> + for Runtime> { #[codec::wrap] fn set_permission_token_schema( schema: PermissionTokenSchema, - state: &mut state::validator::Migrate<'wrld>, + state: &mut state::executor::Migrate<'wrld>, ) { debug!(%schema, "Setting permission token schema"); @@ -1499,19 +1499,19 @@ impl<'wrld> RuntimeBuilder> { } } -impl<'wrld> RuntimeBuilder> { - /// Builds the [`Runtime`] for *Validator* `validate_transaction()` execution +impl<'wrld> RuntimeBuilder> { + /// Builds the [`Runtime`] for *Executor* `validate_transaction()` execution /// /// # Errors /// /// Fails if failed to create default linker. - pub fn build(self) -> Result>> { + pub fn build(self) -> Result>> { self.finalize(|engine| { let mut linker = Linker::new(engine); create_imports!(linker, - export::EXECUTE_ISI => Runtime::>::execute_instruction, - export::EXECUTE_QUERY => Runtime::>::execute_query, + export::EXECUTE_ISI => Runtime::>::execute_instruction, + export::EXECUTE_QUERY => Runtime::>::execute_query, export::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, export::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, export::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, @@ -1523,19 +1523,19 @@ impl<'wrld> RuntimeBuilder> { } } -impl<'wrld> RuntimeBuilder> { - /// Builds the [`Runtime`] for *Validator* `validate_instruction()` execution +impl<'wrld> RuntimeBuilder> { + /// Builds the [`Runtime`] for *Executor* `validate_instruction()` execution /// /// # Errors /// /// Fails if failed to create default linker. - pub fn build(self) -> Result>> { + pub fn build(self) -> Result>> { self.finalize(|engine| { let mut linker = Linker::new(engine); create_imports!(linker, - export::EXECUTE_ISI => Runtime::>::execute_instruction, - export::EXECUTE_QUERY => Runtime::>::execute_query, + export::EXECUTE_ISI => Runtime::>::execute_instruction, + export::EXECUTE_QUERY => Runtime::>::execute_query, export::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, export::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, export::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, @@ -1547,19 +1547,19 @@ impl<'wrld> RuntimeBuilder> { } } -impl<'wrld> RuntimeBuilder> { - /// Builds the [`Runtime`] for *Validator* `validate_query()` execution +impl<'wrld> RuntimeBuilder> { + /// Builds the [`Runtime`] for *Executor* `validate_query()` execution /// /// # Errors /// /// Fails if failed to create default linker. - pub fn build(self) -> Result>> { + pub fn build(self) -> Result>> { self.finalize(|engine| { let mut linker = Linker::new(engine); create_imports!(linker, - export::EXECUTE_ISI => Runtime::>::execute_instruction, - export::EXECUTE_QUERY => Runtime::>::execute_query, + export::EXECUTE_ISI => Runtime::>::execute_instruction, + export::EXECUTE_QUERY => Runtime::>::execute_query, export::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, export::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, export::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, @@ -1571,19 +1571,19 @@ impl<'wrld> RuntimeBuilder> { } } -impl<'wrld> RuntimeBuilder> { - /// Builds the [`Runtime`] to execute `permission_tokens()` entrypoint of *Validator* +impl<'wrld> RuntimeBuilder> { + /// Builds the [`Runtime`] to execute `permission_tokens()` entrypoint of *Executor* /// /// # Errors /// /// Fails if failed to create default linker. - pub fn build(self) -> Result>> { + pub fn build(self) -> Result>> { self.finalize(|engine| { let mut linker = Linker::new(engine); create_imports!(linker, - export::EXECUTE_ISI => Runtime::>::execute_instruction, - export::EXECUTE_QUERY => Runtime::>::execute_query, + export::EXECUTE_ISI => Runtime::>::execute_instruction, + export::EXECUTE_QUERY => Runtime::>::execute_query, export::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, export::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, export::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index 2866fdb7927..3a0aef20b68 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -1190,7 +1190,7 @@ mod tests { .with_instructions([fail_box]) .sign(alice_keys.clone()) .expect("Valid"); - let tx = AcceptedTransaction::accept(tx, &wsv.transaction_validator().transaction_limits) + let tx = AcceptedTransaction::accept(tx, &wsv.transaction_executor().transaction_limits) .expect("Valid"); // Creating a block of two identical transactions and validating it @@ -1215,14 +1215,14 @@ mod tests { .with_instructions([create_asset_definition1]) .sign(alice_keys.clone()) .expect("Valid"); - let tx1 = AcceptedTransaction::accept(tx1, &wsv.transaction_validator().transaction_limits) + let tx1 = AcceptedTransaction::accept(tx1, &wsv.transaction_executor().transaction_limits) .map(Into::into) .expect("Valid"); let tx2 = TransactionBuilder::new(alice_id) .with_instructions([create_asset_definition2]) .sign(alice_keys) .expect("Valid"); - let tx2 = AcceptedTransaction::accept(tx2, &wsv.transaction_validator().transaction_limits) + let tx2 = AcceptedTransaction::accept(tx2, &wsv.transaction_executor().transaction_limits) .map(Into::into) .expect("Valid"); diff --git a/core/src/tx.rs b/core/src/tx.rs index 199fe4ed258..18404d6bd4e 100644 --- a/core/src/tx.rs +++ b/core/src/tx.rs @@ -316,13 +316,13 @@ impl From for (AccountId, Executable) { /// /// Validation is skipped for genesis. #[derive(Clone, Copy)] -pub struct TransactionValidator { +pub struct TransactionExecutor { /// [`TransactionLimits`] field pub transaction_limits: TransactionLimits, } -impl TransactionValidator { - /// Construct [`TransactionValidator`] +impl TransactionExecutor { + /// Construct [`TransactionExecutor`] pub fn new(transaction_limits: TransactionLimits) -> Self { Self { transaction_limits } } @@ -372,7 +372,7 @@ impl TransactionValidator { let mut wsv_for_validation = wsv.clone(); debug!("Validating transaction: {:?}", tx); - Self::validate_with_runtime_validator(tx.clone(), &mut wsv_for_validation)?; + Self::validate_with_runtime_executor(tx.clone(), &mut wsv_for_validation)?; if let (authority, Executable::Wasm(bytes)) = tx.into() { self.validate_wasm(authority, &mut wsv_for_validation, bytes)? @@ -409,25 +409,25 @@ impl TransactionValidator { .map_err(TransactionRejectionReason::WasmExecution) } - /// Validate transaction with runtime validators. + /// Validate transaction with runtime executors. /// /// Note: transaction instructions will be executed on the given `wsv`. - fn validate_with_runtime_validator( + fn validate_with_runtime_executor( tx: AcceptedTransaction, wsv: &mut WorldStateView, ) -> Result<(), TransactionRejectionReason> { let tx: SignedTransaction = tx.into(); let authority = tx.payload().authority.clone(); - wsv.validator() - .clone() // Cloning validator is a cheap operation + wsv.executor() + .clone() // Cloning executor is a cheap operation .validate_transaction(wsv, &authority, tx) .map_err(|error| { if let ValidationFail::InternalError(msg) = &error { error!( error = msg, "Internal error occurred during transaction validation, \ - is Runtime Validator correct?" + is Runtime Executor correct?" ) } error.into() diff --git a/core/src/wsv.rs b/core/src/wsv.rs index 7a5c9073de3..049947db282 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -44,6 +44,7 @@ use serde::{ use crate::{ block::CommittedBlock, + executor::Executor, kura::Kura, smartcontracts::{ triggers::{ @@ -52,8 +53,7 @@ use crate::{ }, wasm, Execute, }, - tx::TransactionValidator, - validator::Validator, + tx::TransactionExecutor, DomainsMap, Parameters, PeersIds, }; @@ -77,8 +77,8 @@ pub struct World { pub(crate) permission_token_schema: PermissionTokenSchema, /// Triggers pub(crate) triggers: TriggerSet, - /// Runtime Validator - pub(crate) validator: Validator, + /// Runtime Executor + pub(crate) executor: Executor, } // Loader for [`Set`] @@ -175,7 +175,7 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, World> { let mut account_roles = None; let mut permission_token_schema = None; let mut triggers = None; - let mut validator = None; + let mut executor = None; while let Some(key) = map.next_key::()? { match key.as_str() { @@ -203,8 +203,8 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, World> { "triggers" => { triggers = Some(map.next_value_seed(self.loader.cast::())?); } - "validator" => { - validator = Some(map.next_value_seed(self.loader.cast::())?); + "executor" => { + executor = Some(map.next_value_seed(self.loader.cast::())?); } _ => { /* Skip unknown fields */ } } @@ -227,8 +227,8 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, World> { })?, triggers: triggers .ok_or_else(|| serde::de::Error::missing_field("triggers"))?, - validator: validator - .ok_or_else(|| serde::de::Error::missing_field("validator"))?, + executor: executor + .ok_or_else(|| serde::de::Error::missing_field("executor"))?, }) } } @@ -244,7 +244,7 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, World> { "account_roles", "permission_token_schema", "triggers", - "validator", + "executor", ], WorldVisitor { loader: &self }, ) @@ -701,9 +701,9 @@ impl WorldStateView { } } - /// Get transaction validator - pub fn transaction_validator(&self) -> TransactionValidator { - TransactionValidator::new(self.config.transaction_limits) + /// Get transaction executor + pub fn transaction_executor(&self) -> TransactionExecutor { + TransactionExecutor::new(self.config.transaction_limits) } /// Get a reference to the latest block. Returns none if genesis is not committed. @@ -1228,9 +1228,9 @@ impl WorldStateView { self.events_buffer.push(event.into()); } - /// Get [`Validator`]. - pub fn validator(&self) -> &Validator { - &self.world.validator + /// Get [`Executor`]. + pub fn executor(&self) -> &Executor { + &self.world.executor } /// The function puts events produced by iterator into `events_buffer`. diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index a8f8ad9f58f..b0e58df14d3 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -105,8 +105,8 @@ impl TestGenesis for GenesisNetwork { "CanUnregisterDomain".parse().unwrap(), &json!({ "domain_id": DomainId::from_str("wonderland").unwrap() } ), ); - let upgrade_validator_permission = - PermissionToken::new("CanUpgradeValidator".parse().unwrap(), &json!(null)); + let upgrade_executor_permission = + PermissionToken::new("CanUpgradeExecutor".parse().unwrap(), &json!(null)); let first_transaction = genesis .first_transaction_mut() @@ -117,7 +117,7 @@ impl TestGenesis for GenesisNetwork { unregister_any_peer_permission, unregister_any_role_permission, unregister_wonderland_domain, - upgrade_validator_permission, + upgrade_executor_permission, ] { first_transaction .append_instruction(GrantExpr::new(permission, alice_id.clone()).into()); diff --git a/data_model/src/events/data/events.rs b/data_model/src/events/data/events.rs index 145f7e6baa8..54536767a41 100644 --- a/data_model/src/events/data/events.rs +++ b/data_model/src/events/data/events.rs @@ -74,7 +74,7 @@ pub mod model { Trigger(trigger::TriggerEvent), PermissionTokenSchemaUpdate(permission::PermissionTokenSchemaUpdateEvent), Configuration(config::ConfigurationEvent), - Validator(validator::ValidatorEvent), + Executor(executor::ExecutorEvent), } /// Event @@ -112,8 +112,8 @@ pub mod model { PermissionToken(permission::PermissionTokenSchemaUpdateEvent), /// Configuration event Configuration(config::ConfigurationEvent), - /// Validator event - Validator(validator::ValidatorEvent), + /// Executor event + Executor(executor::ExecutorEvent), } } @@ -315,7 +315,7 @@ mod permission { use super::*; /// Information about permission tokens update. - /// Only happens when registering new validator + /// Only happens when registering new executor #[derive( Debug, Clone, @@ -554,7 +554,7 @@ mod config { } } -mod validator { +mod executor { use iroha_data_model_derive::model; pub use self::model::*; @@ -581,19 +581,19 @@ mod validator { #[ffi_type] #[serde(untagged)] // Unaffected by #3330, as single unit variant #[repr(transparent)] - pub enum ValidatorEvent { + pub enum ExecutorEvent { Upgraded, } - /// Filter for [`ValidatorEvent`]. - pub enum ValidatorFilter { + /// Filter for [`ExecutorEvent`]. + pub enum ExecutorFilter { Upgraded, } } #[cfg(feature = "transparent_api")] - impl super::Filter for ValidatorFilter { - type Event = ValidatorEvent; + impl super::Filter for ExecutorFilter { + type Event = ExecutorEvent; fn matches(&self, event: &Self::Event) -> bool { match (self, event) { @@ -648,8 +648,8 @@ impl WorldEvent { WorldEvent::Configuration(config_event) => { events.push(DataEvent::Configuration(config_event)); } - WorldEvent::Validator(validator_event) => { - events.push(DataEvent::Validator(validator_event)); + WorldEvent::Executor(executor_event) => { + events.push(DataEvent::Executor(executor_event)); } } @@ -688,7 +688,7 @@ impl DataEvent { | Self::Configuration(_) | Self::Role(_) | Self::PermissionToken(_) - | Self::Validator(_) => None, + | Self::Executor(_) => None, } } } @@ -706,13 +706,13 @@ pub mod prelude { }, config::ConfigurationEvent, domain::{DomainEvent, DomainEventFilter, DomainFilter, DomainOwnerChanged}, + executor::{ExecutorEvent, ExecutorFilter}, peer::{PeerEvent, PeerEventFilter, PeerFilter}, permission::PermissionTokenSchemaUpdateEvent, role::{PermissionRemoved, RoleEvent, RoleEventFilter, RoleFilter}, trigger::{ TriggerEvent, TriggerEventFilter, TriggerFilter, TriggerNumberOfExecutionsChanged, }, - validator::{ValidatorEvent, ValidatorFilter}, DataEvent, HasOrigin, MetadataChanged, WorldEvent, }; } diff --git a/data_model/src/validator.rs b/data_model/src/executor.rs similarity index 81% rename from data_model/src/validator.rs rename to data_model/src/executor.rs index 9167efa2033..8207dcb6250 100644 --- a/data_model/src/validator.rs +++ b/data_model/src/executor.rs @@ -1,4 +1,4 @@ -//! Structures, traits and impls related to *runtime* `Validator`s. +//! Structures, traits and impls related to *runtime* `Executor`s. #[cfg(not(feature = "std"))] use alloc::{format, string::String, vec::Vec}; @@ -17,7 +17,7 @@ use crate::transaction::WasmSmartContract; pub mod model { use super::*; - /// validator that checks if an operation satisfies some conditions. + /// executor that checks if an operation satisfies some conditions. /// /// Can be used with things like [`Transaction`]s, /// [`InstructionExpr`]s, etc. @@ -42,8 +42,8 @@ pub mod model { #[repr(transparent)] // TODO: Derive with getset once FFI impl is fixed //#[getset(get = "pub")] - pub struct Validator { - /// WASM code of the validator + pub struct Executor { + /// WASM code of the executor pub wasm: WasmSmartContract, } @@ -51,16 +51,16 @@ pub mod model { // implemented use: #[cfg(any(feature = "transparent_api", feature = "ffi_import"))] } -/// Result type that every validator should return. +/// Result type that every executor should return. pub type Result = core::result::Result; /// Migration error type. pub type MigrationError = String; -/// Result type for a validator's `migrate()` entrypoint. +/// Result type for a executor's `migrate()` entrypoint. pub type MigrationResult = Result<(), MigrationError>; pub mod prelude { //! The prelude re-exports most commonly used traits, structs and macros from this crate. - pub use super::Validator; + pub use super::Executor; } diff --git a/data_model/src/isi.rs b/data_model/src/isi.rs index 3424fa5bf41..e9541a3b0a3 100644 --- a/data_model/src/isi.rs +++ b/data_model/src/isi.rs @@ -147,7 +147,7 @@ mod transparent { // because they are never shared between client and server(http)/host(wasm) use super::*; - use crate::validator::Validator; + use crate::executor::Executor; /// Generic instruction to set key value at the object. #[derive(Debug, Clone)] @@ -337,8 +337,8 @@ mod transparent { } } - impl From> for UpgradeExpr { - fn from(source: Upgrade) -> Self { + impl From> for UpgradeExpr { + fn from(source: Upgrade) -> Self { Self::new(source.object) } } diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index d8d6a7b1dfe..614e2d8d625 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -64,6 +64,7 @@ pub mod block; pub mod domain; pub mod evaluate; pub mod events; +pub mod executor; pub mod expression; pub mod ipfs; pub mod isi; @@ -79,7 +80,6 @@ pub mod role; pub mod smart_contract; pub mod transaction; pub mod trigger; -pub mod validator; pub mod visit; mod seal { @@ -730,14 +730,14 @@ pub mod model { Serialize, IntoSchema, )] - // SAFETY: `UpgradableBox` has no trap representations in `validator::Validator` + // SAFETY: `UpgradableBox` has no trap representations in `executor::Executor` #[ffi_type(unsafe {robust})] #[serde(untagged)] // Unaffected by #3330, because stores binary data with no `u128` #[repr(transparent)] pub enum UpgradableBox { - /// [`Validator`](`validator::Validator`) variant. - #[display(fmt = "Validator")] - Validator(validator::Validator), + /// [`Executor`](`executor::Executor`) variant. + #[display(fmt = "Executor")] + Executor(executor::Executor), } /// Sized container for all possible values. @@ -787,7 +787,7 @@ pub mod model { #[serde_partially_tagged(untagged)] #[debug(fmt = "{_0:?}")] Numeric(NumericValue), - Validator(validator::Validator), + Executor(executor::Executor), LogLevel(Level), } @@ -901,10 +901,10 @@ pub mod model { /// # Note /// /// Keep in mind that *Validation* is not the right term - /// (because *Runtime Validator* actually does execution too) and other names + /// (because *Runtime Executor* actually does execution too) and other names /// (like *Verification* or *Execution*) are being discussed. /// - /// TODO: Move to `validator` module + /// TODO: Move to `executor` module #[derive( Debug, displaydoc::Display, @@ -941,11 +941,11 @@ pub mod model { /// For example it's a very big WASM binary. /// /// It's different from [`TransactionRejectionReason::LimitCheck`] because it depends on - /// validator. + /// executor. TooComplex, /// Internal error occurred, please contact the support or check the logs if you are the node owner /// - /// Usually means a bug inside **Runtime Validator** or **Iroha** implementation. + /// Usually means a bug inside **Runtime Executor** or **Iroha** implementation. InternalError( /// Contained error message if its used internally. Empty for external users. /// Never serialized to not to expose internal errors to the end user. @@ -1094,7 +1094,7 @@ impl fmt::Display for Value { Value::MetadataLimits(v) => fmt::Display::fmt(&v, f), Value::TransactionLimits(v) => fmt::Display::fmt(&v, f), Value::LengthLimits(v) => fmt::Display::fmt(&v, f), - Value::Validator(v) => write!(f, "Validator({} bytes)", v.wasm.as_ref().len()), + Value::Executor(v) => write!(f, "Executor({} bytes)", v.wasm.as_ref().len()), Value::LogLevel(v) => fmt::Display::fmt(&v, f), } } @@ -1125,7 +1125,7 @@ impl Value { | TransactionLimits(_) | LengthLimits(_) | Numeric(_) - | Validator(_) + | Executor(_) | LogLevel(_) | SignatureCheckCondition(_) => 1_usize, Vec(v) => v.iter().map(Self::len).sum::() + 1_usize, @@ -1510,7 +1510,7 @@ impl TryFrom for UpgradableBox { fn try_from(value: Value) -> Result { match value { - Value::Validator(validator) => Ok(Self::Validator(validator)), + Value::Executor(executor) => Ok(Self::Executor(executor)), _ => Err(Self::Error::default()), } } @@ -1944,10 +1944,10 @@ pub mod prelude { pub use super::current_time; pub use super::{ account::prelude::*, asset::prelude::*, domain::prelude::*, evaluate::prelude::*, - events::prelude::*, expression::prelude::*, isi::prelude::*, metadata::prelude::*, - name::prelude::*, parameter::prelude::*, peer::prelude::*, permission::prelude::*, - query::prelude::*, role::prelude::*, transaction::prelude::*, trigger::prelude::*, - validator::prelude::*, EnumTryAsError, HasMetadata, IdBox, Identifiable, IdentifiableBox, + events::prelude::*, executor::prelude::*, expression::prelude::*, isi::prelude::*, + metadata::prelude::*, name::prelude::*, parameter::prelude::*, peer::prelude::*, + permission::prelude::*, query::prelude::*, role::prelude::*, transaction::prelude::*, + trigger::prelude::*, EnumTryAsError, HasMetadata, IdBox, Identifiable, IdentifiableBox, LengthLimits, NumericValue, PredicateTrait, RegistrableBox, ToValue, TriggerBox, TryAsMut, TryAsRef, TryToValue, UpgradableBox, ValidationFail, Value, }; diff --git a/data_model/src/permission.rs b/data_model/src/permission.rs index 2e1fcd025b5..ce3fd423e28 100644 --- a/data_model/src/permission.rs +++ b/data_model/src/permission.rs @@ -46,7 +46,7 @@ pub mod model { pub payload: StringWithJson, } - /// Description of tokens defined in the validator + /// Description of tokens defined in the executor #[derive( Debug, Display, diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index 95cbbcb66ad..ca6d7e67651 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -1409,7 +1409,7 @@ pub mod error { pub use self::model::*; use super::*; - use crate::{block::SignedBlock, permission, prelude::*, validator}; + use crate::{block::SignedBlock, executor, permission, prelude::*}; #[model] pub mod model { diff --git a/data_model/src/smart_contract.rs b/data_model/src/smart_contract.rs index 471d7bd777f..f159fa69531 100644 --- a/data_model/src/smart_contract.rs +++ b/data_model/src/smart_contract.rs @@ -30,7 +30,7 @@ pub mod payloads { pub block_height: u64, } - /// Generic payload for `validate_*()` entrypoints of validator. + /// Generic payload for `validate_*()` entrypoints of executor. #[derive(Debug, Clone, Encode, Decode)] pub struct Validate { /// Authority which executed the operation to be validated diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index bbcd47ba70e..b6b8d3a676c 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -163,7 +163,7 @@ pub trait Visit: ExpressionEvaluator { visit_revoke_account_role(Revoke), // Visit UpgradeExpr - visit_upgrade_validator(Upgrade), + visit_upgrade_executor(Upgrade), } } @@ -653,8 +653,8 @@ pub fn visit_upgrade(visitor: &mut V, authority: &AccountId, let object = evaluate_expr!(visitor, authority, ::object()); match object { - UpgradableBox::Validator(object) => { - visitor.visit_upgrade_validator(authority, Upgrade { object }) + UpgradableBox::Executor(object) => { + visitor.visit_upgrade_executor(authority, Upgrade { object }) } } } @@ -662,7 +662,7 @@ pub fn visit_upgrade(visitor: &mut V, authority: &AccountId, pub fn visit_if(visitor: &mut V, authority: &AccountId, isi: &ConditionalExpr) { let condition = evaluate_expr!(visitor, authority, ::condition()); - // TODO: Should visit both by default or not? It will affect Validator behavior + // TODO: Should visit both by default or not? It will affect Executor behavior // because only one branch needs to be executed. IMO both should be validated if condition { visitor.visit_instruction(authority, isi.then()); @@ -732,7 +732,7 @@ leaf_visitors! { visit_unregister_trigger(Unregister>), visit_mint_trigger_repetitions(Mint>), visit_burn_trigger_repetitions(Burn>), - visit_upgrade_validator(Upgrade), + visit_upgrade_executor(Upgrade), visit_new_parameter(NewParameter), visit_set_parameter(SetParameter), visit_execute_trigger(ExecuteTrigger), diff --git a/default_validator/.cargo/config.toml b/default_executor/.cargo/config.toml similarity index 100% rename from default_validator/.cargo/config.toml rename to default_executor/.cargo/config.toml diff --git a/default_validator/Cargo.toml b/default_executor/Cargo.toml similarity index 84% rename from default_validator/Cargo.toml rename to default_executor/Cargo.toml index 31f69bf876f..d3aea570a32 100644 --- a/default_validator/Cargo.toml +++ b/default_executor/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "iroha_default_validator" +name = "iroha_default_executor" edition = "2021" version = "2.0.0-pre-rc.19" @@ -24,7 +24,7 @@ opt-level = "z" # Optimize for size vs speed with "s"/"z"(removes vectorizat codegen-units = 1 # Further reduces binary size but increases compilation time [dependencies] -iroha_validator = { version = "2.0.0-pre-rc.19", path = "../smart_contract/validator", features = ["debug"]} +iroha_executor = { version = "2.0.0-pre-rc.19", path = "../smart_contract/executor", features = ["debug"]} lol_alloc = "0.4.0" panic-halt = "0.2.0" diff --git a/default_validator/LICENSE b/default_executor/LICENSE similarity index 100% rename from default_validator/LICENSE rename to default_executor/LICENSE diff --git a/default_validator/README.md b/default_executor/README.md similarity index 55% rename from default_validator/README.md rename to default_executor/README.md index 98d12732107..a404dd83950 100644 --- a/default_validator/README.md +++ b/default_executor/README.md @@ -1,8 +1,8 @@ -# `iroha_default_validator` +# `iroha_default_executor` Use the [Wasm Builder CLI](../tools/wasm_builder_cli) in order to build it: ```bash cargo run --bin iroha_wasm_builder_cli -- \ - build ./default_validator --optimize --outfile ./configs/peer/validator.wasm + build ./default_executor --optimize --outfile ./configs/peer/executor.wasm ``` \ No newline at end of file diff --git a/default_validator/src/lib.rs b/default_executor/src/lib.rs similarity index 74% rename from default_validator/src/lib.rs rename to default_executor/src/lib.rs index 0925c89ed11..9bb8c2e77d4 100644 --- a/default_validator/src/lib.rs +++ b/default_executor/src/lib.rs @@ -1,4 +1,4 @@ -//! Iroha default validator. +//! Iroha default executor. #![no_std] #![allow(missing_docs, clippy::missing_errors_doc)] @@ -9,7 +9,7 @@ extern crate panic_halt; use alloc::borrow::ToOwned as _; -use iroha_validator::{ +use iroha_executor::{ data_model::evaluate::ExpressionEvaluator, default::default_permission_token_schema, prelude::*, smart_contract, }; @@ -18,19 +18,19 @@ use lol_alloc::{FreeListAllocator, LockedAllocator}; #[global_allocator] static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); -/// Validator that replaces some of [`Validate`]'s methods with sensible defaults +/// Executor that replaces some of [`Validate`]'s methods with sensible defaults /// /// # Warning /// /// The defaults are not guaranteed to be stable. #[derive(Debug, Clone)] -pub struct Validator { +pub struct Executor { verdict: Result, block_height: u64, host: smart_contract::Host, } -impl Validator { +impl Executor { /// Construct [`Self`] pub fn new(block_height: u64) -> Self { Self { @@ -42,8 +42,8 @@ impl Validator { fn ensure_genesis(block_height: u64) -> MigrationResult { if block_height != 0 { - return Err("Default Validator is intended to be used only in genesis. \ - Write your own validator if you need to upgrade validator on existing chain." + return Err("Default Executor is intended to be used only in genesis. \ + Write your own executor if you need to upgrade executor on existing chain." .to_owned()); } @@ -52,14 +52,14 @@ impl Validator { } macro_rules! defaults { - ( $($validator:ident $(<$param:ident $(: $bound:path)?>)?($operation:ty)),+ $(,)? ) => { $( - fn $validator $(<$param $(: $bound)?>)?(&mut self, authority: &AccountId, operation: $operation) { - iroha_validator::default::$validator(self, authority, operation) + ( $($executor:ident $(<$param:ident $(: $bound:path)?>)?($operation:ty)),+ $(,)? ) => { $( + fn $executor $(<$param $(: $bound)?>)?(&mut self, authority: &AccountId, operation: $operation) { + iroha_executor::default::$executor(self, authority, operation) } )+ }; } -impl Visit for Validator { +impl Visit for Executor { defaults! { visit_unsupported(T), @@ -122,11 +122,11 @@ impl Visit for Validator { visit_new_parameter(NewParameter), // Upgrade validation - visit_upgrade_validator(Upgrade), + visit_upgrade_executor(Upgrade), } } -impl Validate for Validator { +impl Validate for Executor { fn verdict(&self) -> &Result { &self.verdict } @@ -140,33 +140,32 @@ impl Validate for Validator { } } -impl ExpressionEvaluator for Validator { +impl ExpressionEvaluator for Executor { fn evaluate( &self, expression: &E, - ) -> core::result::Result - { + ) -> core::result::Result { self.host.evaluate(expression) } } -/// Migrate previous validator to the current version. -/// Called by Iroha once just before upgrading validator. +/// Migrate previous executor to the current version. +/// Called by Iroha once just before upgrading executor. /// /// # Errors /// /// Concrete errors are specific to the implementation. /// /// If `migrate()` entrypoint fails then the whole `Upgrade` instruction -/// will be denied and previous validator will stay unchanged. +/// will be denied and previous executor will stay unchanged. #[entrypoint] pub fn migrate(block_height: u64) -> MigrationResult { - Validator::ensure_genesis(block_height)?; + Executor::ensure_genesis(block_height)?; let schema = default_permission_token_schema(); let (token_ids, schema_str) = schema.serialize(); - iroha_validator::set_permission_token_schema( - &iroha_validator::data_model::permission::PermissionTokenSchema::new(token_ids, schema_str), + iroha_executor::set_permission_token_schema( + &iroha_executor::data_model::permission::PermissionTokenSchema::new(token_ids, schema_str), ); Ok(()) @@ -178,9 +177,9 @@ pub fn validate_transaction( transaction: SignedTransaction, block_height: u64, ) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_transaction(&authority, &transaction); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_transaction(&authority, &transaction); + executor.verdict } #[entrypoint] @@ -189,14 +188,14 @@ pub fn validate_instruction( instruction: InstructionExpr, block_height: u64, ) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_instruction(&authority, &instruction); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_instruction(&authority, &instruction); + executor.verdict } #[entrypoint] pub fn validate_query(authority: AccountId, query: QueryBox, block_height: u64) -> Result { - let mut validator = Validator::new(block_height); - validator.visit_query(&authority, &query); - validator.verdict + let mut executor = Executor::new(block_height); + executor.visit_query(&authority, &query); + executor.verdict } diff --git a/docs/source/lts_selection.org b/docs/source/lts_selection.org index 9ad06ad2f6d..45bde0cc9dd 100644 --- a/docs/source/lts_selection.org +++ b/docs/source/lts_selection.org @@ -65,7 +65,7 @@ for selecting a particular version as an LTS candidate This is different to point 1, because while RC10 and RC13 were free from major problems, they did not offer sufficiently full coverage - of the features required for the major project stakeholders. + of the features required for the major project stakeholders. 4. The release must be compatible with all SDKs. @@ -73,7 +73,7 @@ for selecting a particular version as an LTS candidate candidates, creating a catch 22 situation, it is an exception. The two other major SDKs, namely Kotlin, and TypeScript must be compatible with LTS candidate. If the SDK cannot be made compatible - with the candidate, the candidate release is disqualified. + with the candidate, the candidate release is disqualified. 5. The release must be well-tested. @@ -84,7 +84,7 @@ for selecting a particular version as an LTS candidate This generally applies to all releases after RC6 and until RC17, as the development team was told of a way of restructuring the integration tests, but the process only ended with RC17 and the - introduction of the =pytest= framework. + introduction of the =pytest= framework. While passing integration tests is necessary it is not sufficient, the following minimal testing is required to qualify a release as @@ -186,4 +186,4 @@ because rather than a misapplication of an existing term, this is an invention of a term that /could/ have subtle differences from a release candidate. In reality these should have been called *development snapshots*. But in order not to break continuity too -much with the existing SDKs a compromise was chosen. +much with the existing SDKs a compromise was chosen. diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index 94ba2b4686d..f7f2fe68aaf 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -933,9 +933,9 @@ "type": "ConfigurationEvent" }, { - "tag": "Validator", + "tag": "Executor", "discriminant": 9, - "type": "ValidatorEvent" + "type": "ExecutorEvent" } ] }, @@ -1372,6 +1372,36 @@ } ] }, + "Executor": { + "Struct": [ + { + "name": "wasm", + "type": "WasmSmartContract" + } + ] + }, + "ExecutorEvent": { + "Enum": [ + { + "tag": "Upgraded", + "discriminant": 0 + } + ] + }, + "ExecutorMode": { + "Enum": [ + { + "tag": "Path", + "discriminant": 0, + "type": "String" + }, + { + "tag": "Inline", + "discriminant": 1, + "type": "Executor" + } + ] + }, "Expression": { "Enum": [ { @@ -3671,8 +3701,8 @@ "type": "Vec>" }, { - "name": "validator", - "type": "ValidatorMode" + "name": "executor", + "type": "ExecutorMode" } ] }, @@ -4567,9 +4597,9 @@ "UpgradableBox": { "Enum": [ { - "tag": "Validator", + "tag": "Executor", "discriminant": 0, - "type": "Validator" + "type": "Executor" } ] }, @@ -4608,36 +4638,6 @@ } ] }, - "Validator": { - "Struct": [ - { - "name": "wasm", - "type": "WasmSmartContract" - } - ] - }, - "ValidatorEvent": { - "Enum": [ - { - "tag": "Upgraded", - "discriminant": 0 - } - ] - }, - "ValidatorMode": { - "Enum": [ - { - "tag": "Path", - "discriminant": 0, - "type": "String" - }, - { - "tag": "Inline", - "discriminant": 1, - "type": "Validator" - } - ] - }, "Value": { "Enum": [ { @@ -4746,9 +4746,9 @@ "type": "NumericValue" }, { - "tag": "Validator", + "tag": "Executor", "discriminant": 21, - "type": "Validator" + "type": "Executor" }, { "tag": "LogLevel", diff --git a/genesis/src/lib.rs b/genesis/src/lib.rs index 3fc8622663f..3ea5510a364 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -21,8 +21,8 @@ use iroha_config::genesis::Configuration; use iroha_crypto::{KeyPair, PublicKey}; use iroha_data_model::{ asset::AssetDefinition, + executor::Executor, prelude::{Metadata, *}, - validator::Validator, }; use iroha_schema::IntoSchema; use once_cell::sync::Lazy; @@ -66,10 +66,10 @@ impl GenesisNetwork { .ok_or_else(|| eyre!("Genesis account private key is empty."))?, )?; #[cfg(not(test))] - // First instruction should be Validator upgrade. + // First instruction should be Executor upgrade. // This makes possible to grant permissions to users in genesis. let transactions_iter = std::iter::once(GenesisTransactionBuilder { - isi: vec![UpgradeExpr::new(Validator::try_from(raw_block.validator)?).into()], + isi: vec![UpgradeExpr::new(Executor::try_from(raw_block.executor)?).into()], }) .chain(raw_block.transactions.into_iter()); @@ -101,8 +101,8 @@ impl GenesisNetwork { pub struct RawGenesisBlock { /// Transactions transactions: Vec, - /// Runtime Validator - validator: ValidatorMode, + /// Runtime Executor + executor: ExecutorMode, } impl RawGenesisBlock { @@ -127,7 +127,7 @@ impl RawGenesisBlock { "Failed to deserialize raw genesis block from {:?}", &path ))?; - raw_genesis_block.validator.set_genesis_path(path); + raw_genesis_block.executor.set_genesis_path(path); Ok(raw_genesis_block) } @@ -137,18 +137,18 @@ impl RawGenesisBlock { } } -/// Ways to provide validator either directly as base64 encoded string or as path to wasm file +/// Ways to provide executor either directly as base64 encoded string or as path to wasm file #[derive(Debug, Clone, From, Deserialize, Serialize, IntoSchema)] #[serde(untagged)] -pub enum ValidatorMode { - /// Path to validator wasm file +pub enum ExecutorMode { + /// Path to executor wasm file // In the first place to initially try to parse path - Path(ValidatorPath), - /// Validator encoded as base64 string - Inline(Validator), + Path(ExecutorPath), + /// Executor encoded as base64 string + Inline(Executor), } -impl ValidatorMode { +impl ExecutorMode { fn set_genesis_path(&mut self, genesis_path: impl AsRef) { if let Self::Path(path) = self { path.set_genesis_path(genesis_path); @@ -156,38 +156,38 @@ impl ValidatorMode { } } -impl TryFrom for Validator { +impl TryFrom for Executor { type Error = ErrReport; - fn try_from(value: ValidatorMode) -> Result { + fn try_from(value: ExecutorMode) -> Result { match value { - ValidatorMode::Inline(validator) => Ok(validator), - ValidatorMode::Path(ValidatorPath(relative_validator_path)) => { - let wasm = fs::read(&relative_validator_path) - .wrap_err(format!("Failed to open {:?}", &relative_validator_path))?; - Ok(Validator::new(WasmSmartContract::from_compiled(wasm))) + ExecutorMode::Inline(executor) => Ok(executor), + ExecutorMode::Path(ExecutorPath(relative_executor_path)) => { + let wasm = fs::read(&relative_executor_path) + .wrap_err(format!("Failed to open {:?}", &relative_executor_path))?; + Ok(Executor::new(WasmSmartContract::from_compiled(wasm))) } } } } -/// Path to the validator relative to genesis location +/// Path to the executor relative to genesis location /// /// If path is absolute it will be used directly otherwise it will be treated as relative to genesis location. #[derive(Debug, Clone, Deserialize, Serialize, IntoSchema)] #[schema(transparent = "String")] #[serde(transparent)] #[repr(transparent)] -pub struct ValidatorPath(pub PathBuf); +pub struct ExecutorPath(pub PathBuf); -impl ValidatorPath { +impl ExecutorPath { fn set_genesis_path(&mut self, genesis_path: impl AsRef) { - let path_to_validator = genesis_path + let path_to_executor = genesis_path .as_ref() .parent() .expect("Genesis must be in some directory") .join(&self.0); - self.0 = path_to_validator; + self.0 = path_to_executor; } } @@ -241,17 +241,17 @@ pub struct RawGenesisDomainBuilder { state: S, } -mod validator_state { - use super::ValidatorMode; +mod executor_state { + use super::ExecutorMode; #[cfg_attr(test, derive(Clone))] - pub struct Set(pub ValidatorMode); + pub struct Set(pub ExecutorMode); #[derive(Clone, Copy)] pub struct Unset; } -impl RawGenesisBlockBuilder { +impl RawGenesisBlockBuilder { /// Initiate the building process. pub fn new() -> Self { // Do not add `impl Default`. While it can technically be @@ -260,18 +260,18 @@ impl RawGenesisBlockBuilder { // be called. Self { transaction: GenesisTransactionBuilder { isi: Vec::new() }, - state: validator_state::Unset, + state: executor_state::Unset, } } - /// Set the validator. - pub fn validator( + /// Set the executor. + pub fn executor( self, - validator: impl Into, - ) -> RawGenesisBlockBuilder { + executor: impl Into, + ) -> RawGenesisBlockBuilder { RawGenesisBlockBuilder { transaction: self.transaction, - state: validator_state::Set(validator.into()), + state: executor_state::Set(executor.into()), } } } @@ -303,12 +303,12 @@ impl RawGenesisBlockBuilder { } } -impl RawGenesisBlockBuilder { +impl RawGenesisBlockBuilder { /// Finish building and produce a `RawGenesisBlock`. pub fn build(self) -> RawGenesisBlock { RawGenesisBlock { transactions: vec![self.transaction], - validator: self.state.0, + executor: self.state.0, } } } @@ -374,8 +374,8 @@ mod tests { use super::*; - fn dummy_validator() -> ValidatorMode { - ValidatorMode::Path(ValidatorPath("./validator.wasm".into())) + fn dummy_executor() -> ExecutorMode { + ExecutorMode::Path(ExecutorPath("./executor.wasm".into())) } #[test] @@ -388,7 +388,7 @@ mod tests { .domain("wonderland".parse()?) .account("alice".parse()?, alice_public_key) .finish_domain() - .validator(dummy_validator()) + .executor(dummy_executor()) .build(), Some( &ConfigurationProxy { @@ -421,8 +421,8 @@ mod tests { .asset("hats".parse().unwrap(), AssetValueType::BigQuantity) .finish_domain(); - // In real cases validator should be constructed from a wasm blob - let finished_genesis_block = genesis_builder.validator(dummy_validator()).build(); + // In real cases executor should be constructed from a wasm blob + let finished_genesis_block = genesis_builder.executor(dummy_executor()).build(); { let domain_id: DomainId = "wonderland".parse().unwrap(); assert_eq!( diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index 88f2ce3c292..b89d32ff949 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -365,8 +365,8 @@ types!( UnregisterExpr, UpgradableBox, ValidationFail, - Validator, - ValidatorEvent, + Executor, + ExecutorEvent, Value, ValueOfKey, ValuePredicate, @@ -412,6 +412,7 @@ mod tests { BlockHeader, SignedBlock, SignedBlockV1, }, domain::NewDomain, + executor::Executor, http::{BatchedResponse, BatchedResponseV1}, ipfs::IpfsPath, predicate::{ @@ -427,7 +428,6 @@ mod tests { ForwardCursor, }, transaction::{error::TransactionLimitError, SignedTransactionV1, TransactionLimits}, - validator::Validator, SignedBlockWrapper, }; use iroha_genesis::RawGenesisBlock; diff --git a/scripts/test_env.py b/scripts/test_env.py index 7fe2007a4e0..66b0490ab06 100755 --- a/scripts/test_env.py +++ b/scripts/test_env.py @@ -30,7 +30,7 @@ def __init__(self, args: argparse.Namespace): try: shutil.copy2(f"{args.root_dir}/configs/peer/config.json", peers_dir) shutil.copy2(f"{args.root_dir}/configs/peer/genesis.json", peers_dir) - shutil.copy2(f"{args.root_dir}/configs/peer/validator.wasm", peers_dir) + shutil.copy2(f"{args.root_dir}/configs/peer/executor.wasm", peers_dir) except FileNotFoundError: logging.error(f"Some of the config files are missing. \ Please provide them in the `{args.root_dir}/configs/peer` directory") diff --git a/scripts/tests/consistency.sh b/scripts/tests/consistency.sh index 3e2a833e998..dd5a5291a5c 100755 --- a/scripts/tests/consistency.sh +++ b/scripts/tests/consistency.sh @@ -8,8 +8,8 @@ case $1 in exit 1 };; "genesis") - cargo run --release --bin kagami -- genesis --validator-path-in-genesis ./validator.wasm | diff - configs/peer/genesis.json || { - echo 'Please re-generate the genesis with `cargo run --release --bin kagami -- genesis --validator-path-in-genesis ./validator.wasm > configs/peer/genesis.json`' + cargo run --release --bin kagami -- genesis --executor-path-in-genesis ./executor.wasm | diff - configs/peer/genesis.json || { + echo 'Please re-generate the genesis with `cargo run --release --bin kagami -- genesis --executor-path-in-genesis ./executor.wasm > configs/peer/genesis.json`' exit 1 };; "client") diff --git a/scripts/update_configs.sh b/scripts/update_configs.sh index 876ad654ceb..1c4af8a9bc7 100755 --- a/scripts/update_configs.sh +++ b/scripts/update_configs.sh @@ -22,4 +22,4 @@ curl https://raw.githubusercontent.com/hyperledger/iroha/iroha2-lts/configs/peer curl https://raw.githubusercontent.com/hyperledger/iroha/iroha2-stable/configs/peer/config.json -o ./configs/peer/$1/config.json curl https://raw.githubusercontent.com/hyperledger/iroha/iroha2-stable/configs/peer/genesis.json -o ./configs/peer/$1/genesis.json -curl https://raw.githubusercontent.com/hyperledger/iroha/iroha2-stable/configs/peer/genesis.json -o ./configs/peer/$1/validator.wasm +curl https://raw.githubusercontent.com/hyperledger/iroha/iroha2-stable/configs/peer/genesis.json -o ./configs/peer/$1/executor.wasm diff --git a/smart_contract/validator/Cargo.toml b/smart_contract/executor/Cargo.toml similarity index 87% rename from smart_contract/validator/Cargo.toml rename to smart_contract/executor/Cargo.toml index 22cca4dd92a..6e0eb5bcda7 100644 --- a/smart_contract/validator/Cargo.toml +++ b/smart_contract/executor/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "iroha_validator" +name = "iroha_executor" version.workspace = true authors.workspace = true @@ -16,7 +16,7 @@ debug = ["iroha_smart_contract/debug"] [dependencies] iroha_smart_contract_utils.workspace = true iroha_smart_contract.workspace = true -iroha_validator_derive.workspace = true +iroha_executor_derive.workspace = true iroha_data_model.workspace = true iroha_schema.workspace = true diff --git a/smart_contract/validator/derive/Cargo.toml b/smart_contract/executor/derive/Cargo.toml similarity index 88% rename from smart_contract/validator/derive/Cargo.toml rename to smart_contract/executor/derive/Cargo.toml index a2c930c1eda..5c9503883c9 100644 --- a/smart_contract/validator/derive/Cargo.toml +++ b/smart_contract/executor/derive/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "iroha_validator_derive" +name = "iroha_executor_derive" version.workspace = true authors.workspace = true diff --git a/smart_contract/validator/derive/src/conversion.rs b/smart_contract/executor/derive/src/conversion.rs similarity index 89% rename from smart_contract/validator/derive/src/conversion.rs rename to smart_contract/executor/derive/src/conversion.rs index 2e743cddc6b..87b27becbb5 100644 --- a/smart_contract/validator/derive/src/conversion.rs +++ b/smart_contract/executor/derive/src/conversion.rs @@ -9,7 +9,7 @@ pub fn impl_derive_ref_into_asset_owner(input: TokenStream) -> TokenStream { impl_from( &input.ident, &input.generics, - &syn::parse_quote!(::iroha_validator::permission::asset::Owner), + &syn::parse_quote!(::iroha_executor::permission::asset::Owner), &syn::parse_quote!(asset_id), ) .into() @@ -23,7 +23,7 @@ pub fn impl_derive_ref_into_asset_definition_owner(input: TokenStream) -> TokenS impl_from( &input.ident, &input.generics, - &syn::parse_quote!(::iroha_validator::permission::asset_definition::Owner), + &syn::parse_quote!(::iroha_executor::permission::asset_definition::Owner), &syn::parse_quote!(asset_definition_id), ) .into() @@ -36,7 +36,7 @@ pub fn impl_derive_ref_into_account_owner(input: TokenStream) -> TokenStream { impl_from( &input.ident, &input.generics, - &syn::parse_quote!(::iroha_validator::permission::account::Owner), + &syn::parse_quote!(::iroha_executor::permission::account::Owner), &syn::parse_quote!(account_id), ) .into() @@ -49,7 +49,7 @@ pub fn impl_derive_ref_into_domain_owner(input: TokenStream) -> TokenStream { impl_from( &input.ident, &input.generics, - &syn::parse_quote!(::iroha_validator::permission::domain::Owner), + &syn::parse_quote!(::iroha_executor::permission::domain::Owner), &syn::parse_quote!(domain_id), ) .into() diff --git a/smart_contract/validator/derive/src/entrypoint.rs b/smart_contract/executor/derive/src/entrypoint.rs similarity index 67% rename from smart_contract/validator/derive/src/entrypoint.rs rename to smart_contract/executor/derive/src/entrypoint.rs index 0baa04cb8f2..d89414f4e23 100644 --- a/smart_contract/validator/derive/src/entrypoint.rs +++ b/smart_contract/executor/derive/src/entrypoint.rs @@ -1,12 +1,12 @@ -//! Module [`validator_entrypoint`](crate::validator_entrypoint) macro implementation +//! Module [`executor_entrypoint`](crate::executor_entrypoint) macro implementation use super::*; mod export { - pub const VALIDATOR_VALIDATE_TRANSACTION: &str = "_iroha_validator_validate_transaction"; - pub const VALIDATOR_VALIDATE_INSTRUCTION: &str = "_iroha_validator_validate_instruction"; - pub const VALIDATOR_VALIDATE_QUERY: &str = "_iroha_validator_validate_query"; - pub const VALIDATOR_MIGRATE: &str = "_iroha_validator_migrate"; + pub const EXECUTOR_VALIDATE_TRANSACTION: &str = "_iroha_executor_validate_transaction"; + pub const EXECUTOR_VALIDATE_INSTRUCTION: &str = "_iroha_executor_validate_instruction"; + pub const EXECUTOR_VALIDATE_QUERY: &str = "_iroha_executor_validate_query"; + pub const EXECUTOR_MIGRATE: &str = "_iroha_executor_migrate"; } mod import { @@ -15,14 +15,14 @@ mod import { pub const GET_VALIDATE_QUERY_PAYLOAD: &str = "get_validate_query_payload"; } -/// [`validator_entrypoint`](crate::validator_entrypoint()) macro implementation +/// [`executor_entrypoint`](crate::executor_entrypoint()) macro implementation #[allow(clippy::needless_pass_by_value)] pub fn impl_entrypoint(attr: TokenStream, item: TokenStream) -> TokenStream { let fn_item = parse_macro_input!(item as syn::ItemFn); assert!( attr.is_empty(), - "`#[entrypoint]` macro for Validator entrypoints accepts no attributes" + "`#[entrypoint]` macro for Executor entrypoints accepts no attributes" ); macro_rules! match_entrypoints { @@ -44,7 +44,7 @@ pub fn impl_entrypoint(attr: TokenStream, item: TokenStream) -> TokenStream { })* $(fn_name if fn_name == stringify!($other_user_entrypoint_name) => $branch),* _ => panic!( - "Validator entrypoint name must be one of: {:?}", + "Executor entrypoint name must be one of: {:?}", [ $(stringify!($user_entrypoint_name),)* $(stringify!($other_user_entrypoint_name),)* @@ -56,9 +56,9 @@ pub fn impl_entrypoint(attr: TokenStream, item: TokenStream) -> TokenStream { match_entrypoints! { validate: { - validate_transaction => VALIDATOR_VALIDATE_TRANSACTION(GET_VALIDATE_TRANSACTION_PAYLOAD), - validate_instruction => VALIDATOR_VALIDATE_INSTRUCTION(GET_VALIDATE_INSTRUCTION_PAYLOAD), - validate_query => VALIDATOR_VALIDATE_QUERY(GET_VALIDATE_QUERY_PAYLOAD), + validate_transaction => EXECUTOR_VALIDATE_TRANSACTION(GET_VALIDATE_TRANSACTION_PAYLOAD), + validate_instruction => EXECUTOR_VALIDATE_INSTRUCTION(GET_VALIDATE_INSTRUCTION_PAYLOAD), + validate_query => EXECUTOR_VALIDATE_QUERY(GET_VALIDATE_QUERY_PAYLOAD), } other: { migrate => { impl_migrate_entrypoint(fn_item) } @@ -82,13 +82,13 @@ fn impl_validate_entrypoint( assert!( matches!(sig.output, syn::ReturnType::Type(_, _)), - "Validator `{user_entrypoint_name}` entrypoint must have `Result` return type" + "Executor `{user_entrypoint_name}` entrypoint must have `Result` return type" ); block.stmts.insert( 0, parse_quote!( - use ::iroha_validator::smart_contract::{ExecuteOnHost as _, QueryHost as _}; + use ::iroha_executor::smart_contract::{ExecuteOnHost as _, QueryHost as _}; ), ); @@ -101,19 +101,19 @@ fn impl_validate_entrypoint( ); quote! { - /// Validator `validate` entrypoint + /// Executor `validate` entrypoint /// /// # Memory safety /// /// This function transfers the ownership of allocated - /// [`Result`](::iroha_validator::data_model::validator::Result) + /// [`Result`](::iroha_executor::data_model::executor::Result) #[no_mangle] #[doc(hidden)] unsafe extern "C" fn #generated_entrypoint_ident() -> *const u8 { - let payload = ::iroha_validator::#get_validation_payload_fn_ident(); - let verdict: ::iroha_validator::data_model::validator::Result = + let payload = ::iroha_executor::#get_validation_payload_fn_ident(); + let verdict: ::iroha_executor::data_model::executor::Result = #fn_name(payload.authority, payload.to_validate, payload.block_height); - let bytes_box = ::core::mem::ManuallyDrop::new(::iroha_validator::utils::encode_with_length_prefix(&verdict)); + let bytes_box = ::core::mem::ManuallyDrop::new(::iroha_executor::utils::encode_with_length_prefix(&verdict)); bytes_box.as_ptr() } @@ -138,14 +138,13 @@ fn impl_migrate_entrypoint(fn_item: syn::ItemFn) -> TokenStream { assert!( matches!(sig.output, syn::ReturnType::Type(_, _)), - "Validator `migrate()` entrypoint must have `MigrationResult` return type" + "Executor `migrate()` entrypoint must have `MigrationResult` return type" ); - let migrate_fn_name = - syn::Ident::new(export::VALIDATOR_MIGRATE, proc_macro2::Span::call_site()); + let migrate_fn_name = syn::Ident::new(export::EXECUTOR_MIGRATE, proc_macro2::Span::call_site()); quote! { - /// Validator `permission_token_schema` entrypoint + /// Executor `permission_token_schema` entrypoint /// /// # Memory safety /// @@ -153,9 +152,9 @@ fn impl_migrate_entrypoint(fn_item: syn::ItemFn) -> TokenStream { #[no_mangle] #[doc(hidden)] unsafe extern "C" fn #migrate_fn_name() -> *const u8 { - let payload = ::iroha_validator::get_migrate_payload(); - let res: ::iroha_validator::data_model::validator::MigrationResult = #fn_name(payload.block_height); - let bytes = ::core::mem::ManuallyDrop::new(::iroha_validator::utils::encode_with_length_prefix(&res)); + let payload = ::iroha_executor::get_migrate_payload(); + let res: ::iroha_executor::data_model::executor::MigrationResult = #fn_name(payload.block_height); + let bytes = ::core::mem::ManuallyDrop::new(::iroha_executor::utils::encode_with_length_prefix(&res)); ::core::mem::ManuallyDrop::new(bytes).as_ptr() } diff --git a/smart_contract/validator/derive/src/lib.rs b/smart_contract/executor/derive/src/lib.rs similarity index 95% rename from smart_contract/validator/derive/src/lib.rs rename to smart_contract/executor/derive/src/lib.rs index bf0ff4c00ab..186f01e7be8 100644 --- a/smart_contract/validator/derive/src/lib.rs +++ b/smart_contract/executor/derive/src/lib.rs @@ -1,4 +1,4 @@ -//! Crate with validator-related derive macros. +//! Crate with executor-related derive macros. #![allow(clippy::panic)] @@ -11,14 +11,14 @@ mod entrypoint; mod token; mod validate; -/// Annotate the user-defined function that starts the execution of a validator. +/// Annotate the user-defined function that starts the execution of a executor. /// /// There are 4 acceptable forms of this macro usage. See examples. /// /// # Examples /// /// ```ignore -/// use iroha_validator::prelude::*; +/// use iroha_executor::prelude::*; /// /// #[entrypoint] /// pub fn migrate(block_height: u64) -> MigrationResult { @@ -54,7 +54,7 @@ pub fn entrypoint(attr: TokenStream, item: TokenStream) -> TokenStream { /// # Example /// /// ```ignore -/// use iroha_validator::{permission, prelude::*}; +/// use iroha_executor::{permission, prelude::*}; /// /// #[derive(Token, ValidateGrantRevoke, permission::derive_conversions::asset::Owner)] /// #[validate(permission::asset::Owner)] @@ -100,7 +100,7 @@ pub fn derive_token(input: TokenStream) -> TokenStream { /// /// # Pass conditions /// -/// You can pass any type implementing `iroha_validator::permission::PassCondition` +/// You can pass any type implementing `iroha_executor::permission::PassCondition` /// and `From<&YourToken>` traits. /// /// ## Builtin @@ -114,7 +114,7 @@ pub fn derive_token(input: TokenStream) -> TokenStream { /// - `OnlyGenesis` - checks that block height is 0. /// /// -/// Also check out `iroha_validator::permission::derive_conversion` module +/// Also check out `iroha_executor::permission::derive_conversion` module /// for conversion derive macros from your token to this *Pass Conditions*. /// /// ## Why *Pass Conditions*? diff --git a/smart_contract/validator/derive/src/token.rs b/smart_contract/executor/derive/src/token.rs similarity index 58% rename from smart_contract/validator/derive/src/token.rs rename to smart_contract/executor/derive/src/token.rs index 748797ee14f..97b1b3b4edb 100644 --- a/smart_contract/validator/derive/src/token.rs +++ b/smart_contract/executor/derive/src/token.rs @@ -24,11 +24,11 @@ fn impl_token(ident: &syn::Ident, generics: &syn::Generics) -> proc_macro2::Toke let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); quote! { - impl #impl_generics ::iroha_validator::permission::Token for #ident #ty_generics #where_clause { - fn is_owned_by(&self, account_id: &::iroha_validator::data_model::account::AccountId) -> bool { - let all_account_tokens: Vec = ::iroha_validator::smart_contract::debug::DebugExpectExt::dbg_expect( - ::iroha_validator::smart_contract::QueryHost::execute( - &::iroha_validator::data_model::query::permission::FindPermissionTokensByAccountId::new( + impl #impl_generics ::iroha_executor::permission::Token for #ident #ty_generics #where_clause { + fn is_owned_by(&self, account_id: &::iroha_executor::data_model::account::AccountId) -> bool { + let all_account_tokens: Vec = ::iroha_executor::smart_contract::debug::DebugExpectExt::dbg_expect( + ::iroha_executor::smart_contract::QueryHost::execute( + &::iroha_executor::data_model::query::permission::FindPermissionTokensByAccountId::new( account_id.clone(), ) ), @@ -49,20 +49,20 @@ fn impl_try_from_permission_token( generics: &syn::Generics, ) -> proc_macro2::TokenStream { let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let token_id = quote! { ::name() }; + let token_id = quote! { ::name() }; quote! { - impl #impl_generics ::core::convert::TryFrom<::iroha_validator::data_model::permission::PermissionToken> for #ident #ty_generics #where_clause { - type Error = ::iroha_validator::permission::PermissionTokenConversionError; + impl #impl_generics ::core::convert::TryFrom<::iroha_executor::data_model::permission::PermissionToken> for #ident #ty_generics #where_clause { + type Error = ::iroha_executor::permission::PermissionTokenConversionError; - fn try_from(token: ::iroha_validator::data_model::permission::PermissionToken) -> ::core::result::Result { + fn try_from(token: ::iroha_executor::data_model::permission::PermissionToken) -> ::core::result::Result { if #token_id != *token.definition_id() { - return Err(::iroha_validator::permission::PermissionTokenConversionError::Id( + return Err(::iroha_executor::permission::PermissionTokenConversionError::Id( ToOwned::to_owned(token.definition_id()) )); } ::serde_json::from_str::(token.payload()) - .map_err(::iroha_validator::permission::PermissionTokenConversionError::Deserialize) + .map_err(::iroha_executor::permission::PermissionTokenConversionError::Deserialize) } } } diff --git a/smart_contract/validator/derive/src/validate.rs b/smart_contract/executor/derive/src/validate.rs similarity index 93% rename from smart_contract/validator/derive/src/validate.rs rename to smart_contract/executor/derive/src/validate.rs index 0ffc97afad8..7f5e59276b9 100644 --- a/smart_contract/validator/derive/src/validate.rs +++ b/smart_contract/executor/derive/src/validate.rs @@ -15,7 +15,7 @@ pub fn impl_derive_validate(input: TokenStream) -> TokenStream { let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); quote! { - impl #impl_generics ::iroha_validator::permission::ValidateGrantRevoke for #ident #ty_generics + impl #impl_generics ::iroha_executor::permission::ValidateGrantRevoke for #ident #ty_generics #where_clause { #validate_grant_impl @@ -181,10 +181,10 @@ fn gen_validate_impl(isi_name: IsiName, pass_condition: &Type) -> proc_macro2::T let doc_intro = match isi_name { IsiName::Grant => { - "Validate [`Grant`](::iroha_validator::data_model::prelude::Grant) instruction.\n" + "Validate [`Grant`](::iroha_executor::data_model::prelude::Grant) instruction.\n" } IsiName::Revoke => { - "Validate [`Revoke`](::iroha_validator::data_model::prelude::Revoke) instruction.\n" + "Validate [`Revoke`](::iroha_executor::data_model::prelude::Revoke) instruction.\n" } }; @@ -196,12 +196,12 @@ fn gen_validate_impl(isi_name: IsiName, pass_condition: &Type) -> proc_macro2::T #[doc = #pass_condition_str] #[doc = "`]"] #[inline] - fn #fn_name(&self, authority: &::iroha_validator::data_model::account::AccountId, block_height: u64) -> ::iroha_validator::data_model::validator::Result { + fn #fn_name(&self, authority: &::iroha_executor::data_model::account::AccountId, block_height: u64) -> ::iroha_executor::data_model::executor::Result { let condition = <#pass_condition as ::core::convert::From<&Self>>::from(&self); < #pass_condition as - ::iroha_validator::permission::PassCondition + ::iroha_executor::permission::PassCondition >::validate(&condition, authority, block_height) } } diff --git a/smart_contract/validator/src/default.rs b/smart_contract/executor/src/default.rs similarity index 75% rename from smart_contract/validator/src/default.rs rename to smart_contract/executor/src/default.rs index 167ece90e14..816e9e58ab3 100644 --- a/smart_contract/validator/src/default.rs +++ b/smart_contract/executor/src/default.rs @@ -1,4 +1,4 @@ -//! Definition of Iroha default validator and accompanying validation functions +//! Definition of Iroha default executor and accompanying validation functions #![allow(missing_docs, clippy::missing_errors_doc)] use alloc::{borrow::ToOwned, format, string::String}; @@ -20,6 +20,7 @@ pub use domain::{ visit_remove_domain_key_value, visit_set_domain_key_value, visit_transfer_domain, visit_unregister_domain, }; +pub use executor::visit_upgrade_executor; pub use parameter::{visit_new_parameter, visit_set_parameter}; pub use peer::visit_unregister_peer; pub use permission_token::{visit_grant_account_permission, visit_revoke_account_permission}; @@ -30,7 +31,6 @@ pub use trigger::{ visit_burn_trigger_repetitions, visit_execute_trigger, visit_mint_trigger_repetitions, visit_unregister_trigger, }; -pub use validator::visit_upgrade_validator; use crate::{permission, permission::Token as _, prelude::*}; @@ -64,7 +64,7 @@ macro_rules! map_all_crate_tokens { $crate::default::peer::map_tokens!($callback); $crate::default::role::map_tokens!($callback); $crate::default::trigger::map_tokens!($callback); - $crate::default::validator::map_tokens!($callback); + $crate::default::executor::map_tokens!($callback); }; } @@ -81,7 +81,7 @@ macro_rules! token { pub(crate) use map_all_crate_tokens; pub fn default_permission_token_schema() -> PermissionTokenSchema { - let mut schema = iroha_validator::PermissionTokenSchema::default(); + let mut schema = iroha_executor::PermissionTokenSchema::default(); macro_rules! add_to_schema { ($token_ty:ty) => { @@ -89,7 +89,7 @@ pub fn default_permission_token_schema() -> PermissionTokenSchema { }; } - iroha_validator::default::map_all_crate_tokens!(add_to_schema); + iroha_executor::default::map_all_crate_tokens!(add_to_schema); schema } @@ -101,16 +101,16 @@ pub fn default_permission_token_schema() -> PermissionTokenSchema { /// Each instruction is executed in sequence following successful validation. /// [`Executable::Wasm`] is not executed because it is validated on the host side. pub fn visit_transaction( - validator: &mut V, + executor: &mut V, authority: &AccountId, transaction: &SignedTransaction, ) { match transaction.payload().instructions() { - Executable::Wasm(wasm) => validator.visit_wasm(authority, wasm), + Executable::Wasm(wasm) => executor.visit_wasm(authority, wasm), Executable::Instructions(instructions) => { for isi in instructions { - if validator.verdict().is_ok() { - validator.visit_instruction(authority, isi); + if executor.verdict().is_ok() { + executor.visit_instruction(authority, isi); } } } @@ -123,73 +123,73 @@ pub fn visit_transaction( /// /// Instruction is executed following successful validation pub fn visit_instruction( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: &InstructionExpr, ) { - macro_rules! isi_validators { + macro_rules! isi_executors { ( single {$( - $validator:ident($isi:ident) + $executor:ident($isi:ident) ),+ $(,)?} composite {$( - $composite_validator:ident($composite_isi:ident) + $composite_executor:ident($composite_isi:ident) ),+ $(,)?} ) => { match isi { InstructionExpr::NewParameter(isi) => { - let parameter = evaluate_expr!(validator, authority, ::parameter()); - validator.visit_new_parameter(authority, NewParameter{parameter}); + let parameter = evaluate_expr!(executor, authority, ::parameter()); + executor.visit_new_parameter(authority, NewParameter{parameter}); - if validator.verdict().is_ok() { - isi_validators!(@execute isi); + if executor.verdict().is_ok() { + isi_executors!(@execute isi); } } InstructionExpr::SetParameter(isi) => { - let parameter = evaluate_expr!(validator, authority, ::parameter()); - validator.visit_set_parameter(authority, SetParameter{parameter}); + let parameter = evaluate_expr!(executor, authority, ::parameter()); + executor.visit_set_parameter(authority, SetParameter{parameter}); - if validator.verdict().is_ok() { - isi_validators!(@execute isi); + if executor.verdict().is_ok() { + isi_executors!(@execute isi); } } InstructionExpr::ExecuteTrigger(isi) => { - let trigger_id = evaluate_expr!(validator, authority, ::trigger_id()); - validator.visit_execute_trigger(authority, ExecuteTrigger{trigger_id}); + let trigger_id = evaluate_expr!(executor, authority, ::trigger_id()); + executor.visit_execute_trigger(authority, ExecuteTrigger{trigger_id}); - if validator.verdict().is_ok() { - isi_validators!(@execute isi); + if executor.verdict().is_ok() { + isi_executors!(@execute isi); } } InstructionExpr::Log(isi) => { - let msg = evaluate_expr!(validator, authority, ::msg()); - let level = evaluate_expr!(validator, authority, ::level()); - validator.visit_log(authority, Log{level, msg}); + let msg = evaluate_expr!(executor, authority, ::msg()); + let level = evaluate_expr!(executor, authority, ::level()); + executor.visit_log(authority, Log{level, msg}); - if validator.verdict().is_ok() { - isi_validators!(@execute isi); + if executor.verdict().is_ok() { + isi_executors!(@execute isi); } } $( InstructionExpr::$isi(isi) => { - validator.$validator(authority, isi); + executor.$executor(authority, isi); - if validator.verdict().is_ok() { - isi_validators!(@execute isi); + if executor.verdict().is_ok() { + isi_executors!(@execute isi); } } )+ $( // NOTE: `visit_and_execute_instructions` is reentrant, so don't execute composite instructions - InstructionExpr::$composite_isi(isi) => validator.$composite_validator(authority, isi), )+ + InstructionExpr::$composite_isi(isi) => executor.$composite_executor(authority, isi), )+ } }; (@execute $isi:ident) => { // TODO: Execution should be infallible after successful validation if let Err(err) = isi.execute() { - validator.deny(err); + executor.deny(err); } } } - isi_validators! { + isi_executors! { single { visit_burn(Burn), visit_fail(Fail), @@ -213,24 +213,24 @@ pub fn visit_instruction( } pub fn visit_unsupported( - validator: &mut V, + executor: &mut V, _authority: &AccountId, isi: T, ) { - deny!(validator, "{isi:?}: Unsupported operation"); + deny!(executor, "{isi:?}: Unsupported operation"); } pub fn visit_expression( - validator: &mut V, + executor: &mut V, authority: &AccountId, expression: &EvaluatesTo, ) { macro_rules! visit_binary_expression { ($e:ident) => {{ - validator.visit_expression(authority, $e.left()); + executor.visit_expression(authority, $e.left()); - if validator.verdict().is_ok() { - validator.visit_expression(authority, $e.right()); + if executor.verdict().is_ok() { + executor.visit_expression(authority, $e.right()); } }}; } @@ -245,78 +245,78 @@ pub fn visit_expression( Expression::Greater(expr) => visit_binary_expression!(expr), Expression::Less(expr) => visit_binary_expression!(expr), Expression::Equal(expr) => visit_binary_expression!(expr), - Expression::Not(expr) => validator.visit_expression(authority, expr.expression()), + Expression::Not(expr) => executor.visit_expression(authority, expr.expression()), Expression::And(expr) => visit_binary_expression!(expr), Expression::Or(expr) => visit_binary_expression!(expr), Expression::If(expr) => { - validator.visit_expression(authority, expr.condition()); + executor.visit_expression(authority, expr.condition()); - if validator.verdict().is_ok() { - validator.visit_expression(authority, expr.then()); + if executor.verdict().is_ok() { + executor.visit_expression(authority, expr.then()); } - if validator.verdict().is_ok() { - validator.visit_expression(authority, expr.otherwise()); + if executor.verdict().is_ok() { + executor.visit_expression(authority, expr.otherwise()); } } Expression::Contains(expr) => { - validator.visit_expression(authority, expr.collection()); + executor.visit_expression(authority, expr.collection()); - if validator.verdict().is_ok() { - validator.visit_expression(authority, expr.element()); + if executor.verdict().is_ok() { + executor.visit_expression(authority, expr.element()); } } Expression::ContainsAll(expr) => { - validator.visit_expression(authority, expr.collection()); + executor.visit_expression(authority, expr.collection()); - if validator.verdict().is_ok() { - validator.visit_expression(authority, expr.elements()); + if executor.verdict().is_ok() { + executor.visit_expression(authority, expr.elements()); } } Expression::ContainsAny(expr) => { - validator.visit_expression(authority, expr.collection()); + executor.visit_expression(authority, expr.collection()); - if validator.verdict().is_ok() { - validator.visit_expression(authority, expr.elements()); + if executor.verdict().is_ok() { + executor.visit_expression(authority, expr.elements()); } } - Expression::Where(expr) => validator.visit_expression(authority, expr.expression()), - Expression::Query(query) => validator.visit_query(authority, query), + Expression::Where(expr) => executor.visit_expression(authority, expr.expression()), + Expression::Query(query) => executor.visit_query(authority, query), Expression::ContextValue(_) | Expression::Raw(_) => (), } } pub fn visit_if( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: &ConditionalExpr, ) { - let condition = evaluate_expr!(validator, authority, ::condition()); + let condition = evaluate_expr!(executor, authority, ::condition()); // TODO: Do we have to make sure both branches are syntactically valid? if condition { - validator.visit_instruction(authority, isi.then()); + executor.visit_instruction(authority, isi.then()); } else if let Some(otherwise) = isi.otherwise() { - validator.visit_instruction(authority, otherwise); + executor.visit_instruction(authority, otherwise); } } -pub fn visit_pair(validator: &mut V, authority: &AccountId, isi: &PairExpr) { - validator.visit_instruction(authority, isi.left_instruction()); +pub fn visit_pair(executor: &mut V, authority: &AccountId, isi: &PairExpr) { + executor.visit_instruction(authority, isi.left_instruction()); - if validator.verdict().is_ok() { - validator.visit_instruction(authority, isi.right_instruction()) + if executor.verdict().is_ok() { + executor.visit_instruction(authority, isi.right_instruction()) } } pub fn visit_sequence( - validator: &mut V, + executor: &mut V, authority: &AccountId, sequence: &SequenceExpr, ) { for isi in sequence.instructions() { - if validator.verdict().is_ok() { - validator.visit_instruction(authority, isi); + if executor.verdict().is_ok() { + executor.visit_instruction(authority, isi); } } } @@ -340,18 +340,18 @@ pub mod peer { #[allow(clippy::needless_pass_by_value)] pub fn visit_unregister_peer( - validator: &mut V, + executor: &mut V, authority: &AccountId, _isi: Unregister, ) { - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } if tokens::CanUnregisterAnyPeer.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't unregister peer"); + deny!(executor, "Can't unregister peer"); } } @@ -396,91 +396,91 @@ pub mod domain { } pub fn visit_unregister_domain( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Unregister, ) { let domain_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_domain_owner(&domain_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_unregister_domain_token = tokens::CanUnregisterDomain { domain_id }; if can_unregister_domain_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't unregister domain"); + deny!(executor, "Can't unregister domain"); } pub fn visit_transfer_domain( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Transfer, ) { let destination_id = isi.object; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_domain_owner(&destination_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } - deny!(validator, "Can't transfer domain of another account"); + deny!(executor, "Can't transfer domain of another account"); } pub fn visit_set_domain_key_value( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: SetKeyValue, ) { let domain_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_domain_owner(&domain_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_set_key_value_in_domain_token = tokens::CanSetKeyValueInDomain { domain_id }; if can_set_key_value_in_domain_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't set key value in domain metadata"); + deny!(executor, "Can't set key value in domain metadata"); } pub fn visit_remove_domain_key_value( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: RemoveKeyValue, ) { let domain_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_domain_owner(&domain_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_remove_key_value_in_domain_token = tokens::CanRemoveKeyValueInDomain { domain_id }; if can_remove_key_value_in_domain_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't remove key value in domain metadata"); + deny!(executor, "Can't remove key value in domain metadata"); } } @@ -546,151 +546,151 @@ pub mod account { } pub fn visit_unregister_account( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Unregister, ) { let account_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_account_owner(&account_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_unregister_user_account = tokens::CanUnregisterAccount { account_id }; if can_unregister_user_account.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't unregister another account"); + deny!(executor, "Can't unregister another account"); } pub fn visit_mint_account_public_key( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Mint, ) { let account_id = isi.destination_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_account_owner(&account_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_mint_user_public_keys = tokens::CanMintUserPublicKeys { account_id }; if can_mint_user_public_keys.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't mint public keys of another account"); + deny!(executor, "Can't mint public keys of another account"); } pub fn visit_burn_account_public_key( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Burn, ) { let account_id = isi.destination_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_account_owner(&account_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_burn_user_public_keys = tokens::CanBurnUserPublicKeys { account_id }; if can_burn_user_public_keys.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't burn public keys of another account"); + deny!(executor, "Can't burn public keys of another account"); } pub fn visit_mint_account_signature_check_condition( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Mint, ) { let account_id = isi.destination_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_account_owner(&account_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_mint_user_signature_check_conditions_token = tokens::CanMintUserSignatureCheckConditions { account_id }; if can_mint_user_signature_check_conditions_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't mint signature check conditions of another account" ); } pub fn visit_set_account_key_value( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: SetKeyValue, ) { let account_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_account_owner(&account_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_set_key_value_in_user_account_token = tokens::CanSetKeyValueInUserAccount { account_id }; if can_set_key_value_in_user_account_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't set value to the metadata of another account" ); } pub fn visit_remove_account_key_value( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: RemoveKeyValue, ) { let account_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_account_owner(&account_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_remove_key_value_in_user_account_token = tokens::CanRemoveKeyValueInUserAccount { account_id }; if can_remove_key_value_in_user_account_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't remove value from the metadata of another account" ); } @@ -736,102 +736,102 @@ pub mod asset_definition { } pub fn visit_unregister_asset_definition( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Unregister, ) { let asset_definition_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_asset_definition_owner(&asset_definition_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_unregister_asset_definition_token = tokens::CanUnregisterAssetDefinition { asset_definition_id, }; if can_unregister_asset_definition_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't unregister assets registered by other accounts" ); } pub fn visit_transfer_asset_definition( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Transfer, ) { let source_id = isi.source_id; let destination_id = isi.object; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_account_owner(&source_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } match is_asset_definition_owner(&destination_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } deny!( - validator, + executor, "Can't transfer asset definition of another account" ); } pub fn visit_set_asset_definition_key_value( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: SetKeyValue, ) { let asset_definition_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_asset_definition_owner(&asset_definition_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_set_key_value_in_asset_definition_token = tokens::CanSetKeyValueInAssetDefinition { asset_definition_id, }; if can_set_key_value_in_asset_definition_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't set value to the asset definition metadata created by another account" ); } pub fn visit_remove_asset_definition_key_value( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: RemoveKeyValue, ) { let asset_definition_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_asset_definition_owner(&asset_definition_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_remove_key_value_in_asset_definition_token = @@ -839,11 +839,11 @@ pub mod asset_definition { asset_definition_id, }; if can_remove_key_value_in_asset_definition_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't remove value from the asset definition metadata created by another account" ); } @@ -952,51 +952,51 @@ pub mod asset { } pub fn visit_register_asset( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Register, ) { let asset = isi.object; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_asset_definition_owner(asset.id().definition_id(), authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_register_assets_with_definition_token = tokens::CanRegisterAssetsWithDefinition { asset_definition_id: asset.id().definition_id().clone(), }; if can_register_assets_with_definition_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't register assets with definitions registered by other accounts" ); } pub fn visit_unregister_asset( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Unregister, ) { let asset_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_asset_owner(&asset_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } match is_asset_definition_owner(asset_id.definition_id(), authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_unregister_assets_with_definition_token = @@ -1004,162 +1004,162 @@ pub mod asset { asset_definition_id: asset_id.definition_id().clone(), }; if can_unregister_assets_with_definition_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } let can_unregister_user_asset_token = tokens::CanUnregisterUserAsset { asset_id }; if can_unregister_user_asset_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't unregister asset from another account"); + deny!(executor, "Can't unregister asset from another account"); } pub fn visit_mint_asset( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Mint, ) { let asset_id = isi.destination_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_asset_definition_owner(asset_id.definition_id(), authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_mint_assets_with_definition_token = tokens::CanMintAssetsWithDefinition { asset_definition_id: asset_id.definition_id().clone(), }; if can_mint_assets_with_definition_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't mint assets with definitions registered by other accounts" ); } pub fn visit_burn_asset( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Burn, ) { let asset_id = isi.destination_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_asset_owner(&asset_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } match is_asset_definition_owner(asset_id.definition_id(), authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_burn_assets_with_definition_token = tokens::CanBurnAssetsWithDefinition { asset_definition_id: asset_id.definition_id().clone(), }; if can_burn_assets_with_definition_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } let can_burn_user_asset_token = tokens::CanBurnUserAsset { asset_id }; if can_burn_user_asset_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't burn assets from another account"); + deny!(executor, "Can't burn assets from another account"); } pub fn visit_transfer_asset( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Transfer, ) { let asset_id = isi.source_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_asset_owner(&asset_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } match is_asset_definition_owner(asset_id.definition_id(), authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_transfer_assets_with_definition_token = tokens::CanTransferAssetsWithDefinition { asset_definition_id: asset_id.definition_id().clone(), }; if can_transfer_assets_with_definition_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } let can_transfer_user_asset_token = tokens::CanTransferUserAsset { asset_id }; if can_transfer_user_asset_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't transfer assets of another account"); + deny!(executor, "Can't transfer assets of another account"); } pub fn visit_set_asset_key_value( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: SetKeyValue, ) { let asset_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_asset_owner(&asset_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_set_key_value_in_user_asset_token = tokens::CanSetKeyValueInUserAsset { asset_id }; if can_set_key_value_in_user_asset_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't set value to the asset metadata of another account" ); } pub fn visit_remove_asset_key_value( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: RemoveKeyValue, ) { let asset_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_asset_owner(&asset_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_remove_key_value_in_user_asset_token = tokens::CanRemoveKeyValueInUserAsset { asset_id }; if can_remove_key_value_in_user_asset_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't remove value from the asset metadata of another account" ); } @@ -1267,38 +1267,38 @@ pub mod parameter { #[allow(clippy::needless_pass_by_value)] pub fn visit_new_parameter( - validator: &mut V, + executor: &mut V, authority: &AccountId, _isi: NewParameter, ) { - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } if tokens::CanCreateParameters.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't create new configuration parameters outside genesis without permission" ); } #[allow(clippy::needless_pass_by_value)] pub fn visit_set_parameter( - validator: &mut V, + executor: &mut V, authority: &AccountId, _isi: SetParameter, ) { - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } if tokens::CanSetParameters.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't set configuration parameters without permission" ); } @@ -1322,13 +1322,13 @@ pub mod role { } macro_rules! impl_validate { - ($validator:ident, $isi:ident, $authority:ident, $method:ident) => { + ($executor:ident, $isi:ident, $authority:ident, $method:ident) => { let role_id = $isi.object; let find_role_query_res = match FindRoleByRoleId::new(role_id).execute() { Ok(res) => res, Err(error) => { - deny!($validator, error); + deny!($executor, error); } }; let role = Role::try_from(find_role_query_res).unwrap(); @@ -1339,17 +1339,17 @@ pub mod role { if let Ok(concrete_token) = <$token_ty as TryFrom<_>>::try_from(token.clone()) { - if is_genesis($validator) { + if is_genesis($executor) { continue; } if let Err(error) = <$token_ty as permission::ValidateGrantRevoke>::$method( &concrete_token, $authority, - $validator.block_height(), + $executor.block_height(), ) { - deny!($validator, error); + deny!($executor, error); } // Continue because token can correspond to only one concrete token @@ -1360,18 +1360,18 @@ pub mod role { map_all_crate_tokens!(visit_internal); deny!( - $validator, - "Incorrect validator implementation: Role contains unknown permission tokens" + $executor, + "Incorrect executor implementation: Role contains unknown permission tokens" ) } - pass!($validator); + pass!($executor); }; } #[allow(clippy::needless_pass_by_value)] pub fn visit_register_role( - validator: &mut V, + executor: &mut V, _authority: &AccountId, isi: Register, ) { @@ -1397,46 +1397,46 @@ pub mod role { if !unknown_tokens.is_empty() { deny!( - validator, + executor, ValidationFail::NotPermitted(format!( "{unknown_tokens:?}: Unrecognised permission tokens" )) ); } - pass!(validator); + pass!(executor); } #[allow(clippy::needless_pass_by_value)] pub fn visit_unregister_role( - validator: &mut V, + executor: &mut V, authority: &AccountId, _isi: Unregister, ) { - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } if tokens::CanUnregisterAnyRole.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't unregister role"); + deny!(executor, "Can't unregister role"); } pub fn visit_grant_account_role( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Grant, ) { - impl_validate!(validator, isi, authority, validate_grant); + impl_validate!(executor, isi, authority, validate_grant); } pub fn visit_revoke_account_role( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Revoke, ) { - impl_validate!(validator, isi, authority, validate_revoke); + impl_validate!(executor, isi, authority, validate_revoke); } } @@ -1508,104 +1508,104 @@ pub mod trigger { ); pub fn visit_unregister_trigger( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Unregister>, ) { let trigger_id = isi.object_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_trigger_owner(&trigger_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_unregister_user_trigger_token = tokens::CanUnregisterUserTrigger { trigger_id }; if can_unregister_user_trigger_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't unregister trigger owned by another account" ); } pub fn visit_mint_trigger_repetitions( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Mint>, ) { let trigger_id = isi.destination_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_trigger_owner(&trigger_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_mint_user_trigger_token = tokens::CanMintUserTrigger { trigger_id }; if can_mint_user_trigger_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't mint execution count for trigger owned by another account" ); } pub fn visit_burn_trigger_repetitions( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Burn>, ) { let trigger_id = isi.destination_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_trigger_owner(&trigger_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_mint_user_trigger_token = tokens::CanMintUserTrigger { trigger_id }; if can_mint_user_trigger_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } deny!( - validator, + executor, "Can't burn execution count for trigger owned by another account" ); } pub fn visit_execute_trigger( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: ExecuteTrigger, ) { let trigger_id = isi.trigger_id; - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } match is_trigger_owner(&trigger_id, authority) { - Err(err) => deny!(validator, err), - Ok(true) => pass!(validator), + Err(err) => deny!(executor, err), + Ok(true) => pass!(executor), Ok(false) => {} } let can_execute_trigger_token = tokens::CanExecuteUserTrigger { trigger_id }; if can_execute_trigger_token.is_owned_by(authority) { - pass!(validator); + pass!(executor); } - deny!(validator, "Can't execute trigger owned by another account"); + deny!(executor, "Can't execute trigger owned by another account"); } } @@ -1613,24 +1613,24 @@ pub mod permission_token { use super::*; macro_rules! impl_validate { - ($validator:ident, $authority:ident, $self:ident, $method:ident) => { + ($executor:ident, $authority:ident, $self:ident, $method:ident) => { let token = $self.object; macro_rules! visit_internal { ($token_ty:ty) => { if let Ok(token) = <$token_ty as TryFrom<_>>::try_from(token.clone()) { - if is_genesis($validator) { - pass!($validator); + if is_genesis($executor) { + pass!($executor); } if let Err(error) = <$token_ty as permission::ValidateGrantRevoke>::$method( &token, $authority, - $validator.block_height(), + $executor.block_height(), ) { - deny!($validator, error); + deny!($executor, error); } - pass!($validator); + pass!($executor); } }; } @@ -1638,34 +1638,34 @@ pub mod permission_token { map_all_crate_tokens!(visit_internal); deny!( - $validator, + $executor, ValidationFail::NotPermitted(format!("{token:?}: Unknown permission token")) ); }; } pub fn visit_grant_account_permission( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Grant, ) { - impl_validate!(validator, authority, isi, validate_grant); + impl_validate!(executor, authority, isi, validate_grant); } pub fn visit_revoke_account_permission( - validator: &mut V, + executor: &mut V, authority: &AccountId, isi: Revoke, ) { - impl_validate!(validator, authority, isi, validate_revoke); + impl_validate!(executor, authority, isi, validate_revoke); } } -pub mod validator { +pub mod executor { use super::*; declare_tokens! { - crate::default::validator::tokens::CanUpgradeValidator, + crate::default::executor::tokens::CanUpgradeExecutor, } pub mod tokens { @@ -1674,27 +1674,27 @@ pub mod validator { token! { #[derive(Copy, ValidateGrantRevoke)] #[validate(permission::OnlyGenesis)] - pub struct CanUpgradeValidator; + pub struct CanUpgradeExecutor; } } #[allow(clippy::needless_pass_by_value)] - pub fn visit_upgrade_validator( - validator: &mut V, + pub fn visit_upgrade_executor( + executor: &mut V, authority: &AccountId, - _isi: Upgrade, + _isi: Upgrade, ) { - if is_genesis(validator) { - pass!(validator); + if is_genesis(executor) { + pass!(executor); } - if tokens::CanUpgradeValidator.is_owned_by(authority) { - pass!(validator); + if tokens::CanUpgradeExecutor.is_owned_by(authority) { + pass!(executor); } - deny!(validator, "Can't upgrade validator"); + deny!(executor, "Can't upgrade executor"); } } -fn is_genesis(validator: &V) -> bool { - validator.block_height() == 0 +fn is_genesis(executor: &V) -> bool { + executor.block_height() == 0 } diff --git a/smart_contract/validator/src/lib.rs b/smart_contract/executor/src/lib.rs similarity index 84% rename from smart_contract/validator/src/lib.rs rename to smart_contract/executor/src/lib.rs index e10a2d04465..f61e3643c0c 100644 --- a/smart_contract/validator/src/lib.rs +++ b/smart_contract/executor/src/lib.rs @@ -1,15 +1,15 @@ -//! API for *Runtime Validators*. +//! API for *Runtime Executors*. #![no_std] #![allow(unsafe_code)] extern crate alloc; -extern crate self as iroha_validator; +extern crate self as iroha_executor; use alloc::vec::Vec; pub use iroha_data_model as data_model; use iroha_data_model::{ - permission::PermissionTokenId, validator::Result, visit::Visit, ValidationFail, + executor::Result, permission::PermissionTokenId, visit::Visit, ValidationFail, }; #[cfg(not(test))] use iroha_data_model::{prelude::*, smart_contract::payloads}; @@ -37,7 +37,7 @@ pub mod log { /// # Traps /// /// Host side will generate a trap if this function was called not from a -/// validator `validate_transaction()` entrypoint. +/// executor `validate_transaction()` entrypoint. #[cfg(not(test))] pub fn get_validate_transaction_payload() -> payloads::Validate { // Safety: ownership of the returned result is transferred into `_decode_from_raw` @@ -49,7 +49,7 @@ pub fn get_validate_transaction_payload() -> payloads::Validate payloads::Validate { // Safety: ownership of the returned result is transferred into `_decode_from_raw` @@ -61,7 +61,7 @@ pub fn get_validate_instruction_payload() -> payloads::Validate /// # Traps /// /// Host side will generate a trap if this function was called not from a -/// validator `validate_query()` entrypoint. +/// executor `validate_query()` entrypoint. #[cfg(not(test))] pub fn get_validate_query_payload() -> payloads::Validate { // Safety: ownership of the returned result is transferred into `_decode_from_raw` @@ -73,7 +73,7 @@ pub fn get_validate_query_payload() -> payloads::Validate { /// # Traps /// /// Host side will generate a trap if this function was called not from a -/// validator `migrate()` entrypoint. +/// executor `migrate()` entrypoint. #[cfg(not(test))] pub fn get_migrate_payload() -> payloads::Migrate { // Safety: ownership of the returned result is transferred into `_decode_from_raw` @@ -89,7 +89,7 @@ pub fn get_migrate_payload() -> payloads::Migrate { /// # Traps /// /// Host side will generate a trap if this function was not called from a -/// validator's `migrate()` entrypoint. +/// executor's `migrate()` entrypoint. #[cfg(not(test))] pub fn set_permission_token_schema(schema: &data_model::permission::PermissionTokenSchema) { // Safety: - ownership of the returned result is transferred into `_decode_from_raw` @@ -136,10 +136,10 @@ mod host { /// Shortcut for `return Ok(())`. #[macro_export] macro_rules! pass { - ($validator:ident) => {{ + ($executor:ident) => {{ #[cfg(debug_assertions)] - if let Err(_error) = $validator.verdict() { - unreachable!("Validator already denied"); + if let Err(_error) = $executor.verdict() { + unreachable!("Executor already denied"); } return; @@ -151,22 +151,22 @@ macro_rules! pass { /// Supports [`format!`](alloc::fmt::format) syntax as well as any expression returning [`String`](alloc::string::String). #[macro_export] macro_rules! deny { - ($validator:ident, $l:literal $(,)?) => {{ + ($executor:ident, $l:literal $(,)?) => {{ #[cfg(debug_assertions)] - if let Err(_error) = $validator.verdict() { - unreachable!("Validator already denied"); + if let Err(_error) = $executor.verdict() { + unreachable!("Executor already denied"); } - $validator.deny($crate::data_model::ValidationFail::NotPermitted( + $executor.deny($crate::data_model::ValidationFail::NotPermitted( ::alloc::fmt::format(::core::format_args!($l)), )); return; }}; - ($validator:ident, $e:expr $(,)?) => {{ + ($executor:ident, $e:expr $(,)?) => {{ #[cfg(debug_assertions)] - if let Err(_error) = $validator.verdict() { - unreachable!("Validator already denied"); + if let Err(_error) = $executor.verdict() { + unreachable!("Executor already denied"); } - $validator.deny($e); + $executor.deny($e); return; }}; } @@ -176,7 +176,7 @@ macro_rules! deny { /// # Example /// /// ```no_run -/// use iroha_validator::parse; +/// use iroha_executor::parse; /// use iroha_data_model::prelude::*; /// /// let account_id = parse!("alice@wonderland" as AccountId); @@ -208,11 +208,11 @@ macro_rules! parse { /// use std::borrow::ToOwned; /// /// use iroha_schema::IntoSchema; -/// use iroha_validator_derive::{Token, ValidateGrantRevoke}; +/// use iroha_executor_derive::{Token, ValidateGrantRevoke}; /// use serde::{Deserialize, Serialize}; /// /// #[derive(Clone, PartialEq, Deserialize, Serialize, IntoSchema, Token, ValidateGrantRevoke)] -/// #[validate(iroha_validator::permission::OnlyGenesis)] +/// #[validate(iroha_executor::permission::OnlyGenesis)] /// pub struct MyToken; /// } /// ``` @@ -229,7 +229,7 @@ macro_rules! declare_tokens { } } -/// Collection of all permission tokens defined by the validator +/// Collection of all permission tokens defined by the executor #[derive(Debug, Clone, Default)] pub struct PermissionTokenSchema(Vec, MetaMap); @@ -261,15 +261,15 @@ impl PermissionTokenSchema { } } -/// Validator of Iroha operations +/// Executor of Iroha operations pub trait Validate: Visit { - /// Validator verdict. + /// Executor verdict. fn verdict(&self) -> &Result; /// Current block height. fn block_height(&self) -> u64; - /// Set validator verdict to deny + /// Set executor verdict to deny fn deny(&mut self, reason: ValidationFail); } @@ -279,13 +279,13 @@ pub mod prelude { pub use alloc::vec::Vec; pub use iroha_data_model::{ + executor::{MigrationError, MigrationResult, Result}, prelude::*, - validator::{MigrationError, MigrationResult, Result}, visit::Visit, ValidationFail, }; + pub use iroha_executor_derive::{entrypoint, Token, ValidateGrantRevoke}; pub use iroha_smart_contract::{prelude::*, Context}; - pub use iroha_validator_derive::{entrypoint, Token, ValidateGrantRevoke}; pub use super::{declare_tokens, deny, pass, PermissionTokenSchema, Validate}; } diff --git a/smart_contract/validator/src/permission.rs b/smart_contract/executor/src/permission.rs similarity index 96% rename from smart_contract/validator/src/permission.rs rename to smart_contract/executor/src/permission.rs index d3aeb1d4286..a0f60a6c35e 100644 --- a/smart_contract/validator/src/permission.rs +++ b/smart_contract/executor/src/permission.rs @@ -56,30 +56,30 @@ pub enum PermissionTokenConversionError { pub mod derive_conversions { //! Module with derive macros to generate conversion from custom strongly-typed token - //! to some pass condition to successfully derive [`ValidateGrantRevoke`](iroha_validator_derive::ValidateGrantRevoke) + //! to some pass condition to successfully derive [`ValidateGrantRevoke`](iroha_executor_derive::ValidateGrantRevoke) pub mod asset { //! Module with derives related to asset tokens - pub use iroha_validator_derive::RefIntoAssetOwner as Owner; + pub use iroha_executor_derive::RefIntoAssetOwner as Owner; } pub mod asset_definition { //! Module with derives related to asset definition tokens - pub use iroha_validator_derive::RefIntoAssetDefinitionOwner as Owner; + pub use iroha_executor_derive::RefIntoAssetDefinitionOwner as Owner; } pub mod account { //! Module with derives related to account tokens - pub use iroha_validator_derive::RefIntoAccountOwner as Owner; + pub use iroha_executor_derive::RefIntoAccountOwner as Owner; } pub mod domain { //! Module with derives related to domain tokens - pub use iroha_validator_derive::RefIntoDomainOwner as Owner; + pub use iroha_executor_derive::RefIntoDomainOwner as Owner; } } diff --git a/tools/kagami/src/genesis.rs b/tools/kagami/src/genesis.rs index 9caabb21eef..8f4424b1574 100644 --- a/tools/kagami/src/genesis.rs +++ b/tools/kagami/src/genesis.rs @@ -10,31 +10,31 @@ use iroha_data_model::{ prelude::AssetId, IdBox, }; -use iroha_genesis::{RawGenesisBlock, RawGenesisBlockBuilder, ValidatorMode, ValidatorPath}; +use iroha_genesis::{ExecutorMode, ExecutorPath, RawGenesisBlock, RawGenesisBlockBuilder}; use serde_json::json; use super::*; -const INLINED_VALIDATOR_WARNING: &str = r#"WARN: You're using genesis with inlined validator. -Consider specifying a separate validator file using `--validator-path-in-genesis` instead. +const INLINED_EXECUTOR_WARNING: &str = r#"WARN: You're using genesis with inlined executor. +Consider specifying a separate executor file using `--executor-path-in-genesis` instead. Use `--help` for more information."#; #[derive(Parser, Debug, Clone)] -#[clap(group = ArgGroup::new("validator").required(true))] +#[clap(group = ArgGroup::new("executor").required(true))] pub struct Args { - /// Reads the validator from the file at (relative to CWD) + /// Reads the executor from the file at (relative to CWD) /// and includes the content into the genesis. /// /// WARN: This approach can lead to reproducibility issues, as WASM builds are currently not - /// guaranteed to be reproducible. Additionally, inlining the validator bloats the genesis JSON - /// and makes it less readable. Consider specifying a separate validator file - /// using `--validator-path-in-genesis` instead. For more details, refer to + /// guaranteed to be reproducible. Additionally, inlining the executor bloats the genesis JSON + /// and makes it less readable. Consider specifying a separate executor file + /// using `--executor-path-in-genesis` instead. For more details, refer to /// the related PR: https://github.com/hyperledger/iroha/pull/3434 - #[clap(long, group = "validator", value_name = "PATH")] - inline_validator_from_file: Option, + #[clap(long, group = "executor", value_name = "PATH")] + inline_executor_from_file: Option, /// Specifies the that will be directly inserted into the genesis JSON as-is. - #[clap(long, group = "validator", value_name = "PATH")] - validator_path_in_genesis: Option, + #[clap(long, group = "executor", value_name = "PATH")] + executor_path_in_genesis: Option, #[clap(subcommand)] mode: Option, } @@ -67,53 +67,52 @@ pub enum Mode { impl RunArgs for Args { fn run(self, writer: &mut BufWriter) -> Outcome { let Self { - inline_validator_from_file, - validator_path_in_genesis, + inline_executor_from_file, + executor_path_in_genesis, mode, } = self; - let validator: ValidatorMode = - match (inline_validator_from_file, validator_path_in_genesis) { - (Some(path), None) => { - eprintln!("{INLINED_VALIDATOR_WARNING}"); - ParsedValidatorArgs::Inline(path) - } - (None, Some(path)) => ParsedValidatorArgs::Path(path), - _ => unreachable!("clap invariant"), + let executor: ExecutorMode = match (inline_executor_from_file, executor_path_in_genesis) { + (Some(path), None) => { + eprintln!("{INLINED_EXECUTOR_WARNING}"); + ParsedExecutorArgs::Inline(path) } - .try_into()?; + (None, Some(path)) => ParsedExecutorArgs::Path(path), + _ => unreachable!("clap invariant"), + } + .try_into()?; let genesis = match mode.unwrap_or_default() { - Mode::Default => generate_default(validator), + Mode::Default => generate_default(executor), Mode::Synthetic { domains, accounts_per_domain, assets_per_domain, - } => generate_synthetic(validator, domains, accounts_per_domain, assets_per_domain), + } => generate_synthetic(executor, domains, accounts_per_domain, assets_per_domain), }?; writeln!(writer, "{}", serde_json::to_string_pretty(&genesis)?) .wrap_err("Failed to write serialized genesis to the buffer.") } } -enum ParsedValidatorArgs { +enum ParsedExecutorArgs { Inline(PathBuf), Path(PathBuf), } -impl TryFrom for ValidatorMode { +impl TryFrom for ExecutorMode { type Error = color_eyre::Report; - fn try_from(value: ParsedValidatorArgs) -> Result { + fn try_from(value: ParsedExecutorArgs) -> Result { let mode = match value { - ParsedValidatorArgs::Path(path) => ValidatorMode::Path(ValidatorPath(path)), - ParsedValidatorArgs::Inline(path) => { - let validator = ValidatorMode::Path(ValidatorPath(path.clone())) + ParsedExecutorArgs::Path(path) => ExecutorMode::Path(ExecutorPath(path)), + ParsedExecutorArgs::Inline(path) => { + let executor = ExecutorMode::Path(ExecutorPath(path.clone())) .try_into() .wrap_err_with(|| { - format!("Failed to read the validator located at {}", path.display()) + format!("Failed to read the executor located at {}", path.display()) })?; - ValidatorMode::Inline(validator) + ExecutorMode::Inline(executor) } }; Ok(mode) @@ -121,7 +120,7 @@ impl TryFrom for ValidatorMode { } #[allow(clippy::too_many_lines)] -pub fn generate_default(validator: ValidatorMode) -> color_eyre::Result { +pub fn generate_default(executor: ExecutorMode) -> color_eyre::Result { let mut meta = Metadata::new(); meta.insert_with_limits( "key".parse()?, @@ -143,7 +142,7 @@ pub fn generate_default(validator: ValidatorMode) -> color_eyre::Result color_eyre::Result Date: Thu, 12 Oct 2023 16:27:31 +0300 Subject: [PATCH 49/55] [fix] #0000: proper rustc in devShell Signed-off-by: Artemii Gerasimovich --- flake.nix | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/flake.nix b/flake.nix index dc8f5c417e2..3b067fee410 100755 --- a/flake.nix +++ b/flake.nix @@ -161,8 +161,11 @@ inherit mkIroha; packages.default = mkIroha {}; - - packages.appimage = nix-appimage.mkappimage.${system} { drv = mkIroha {}; name="iroha"; }; + + packages.appimage = nix-appimage.mkappimage.${system} { + drv = mkIroha {}; + name = "iroha"; + }; packages.targets = builtins.listToAttrs (map (target: { name = target; @@ -193,16 +196,27 @@ formatter = alejandra.packages.${system}.default; - devShells.default = pkgs.mkShell { - nativeBuildInputs = with pkgs; [ - pkg-config - openssl.dev - libiconvReal - zlib - (fenix'.toolchainOf toolchainSpec).completeToolchain + devShells.default = let + toolchainPkgs = fenix'.toolchainOf toolchainSpec; + toolchain = fenix'.combine [ + toolchainPkgs.rustc + toolchainPkgs.cargo + toolchainPkgs.clippy + toolchainPkgs.rustfmt + toolchainPkgs.rust-std ]; + in + pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + pkg-config + openssl.dev + libiconvReal + zlib + toolchain + fenix'.rust-analyzer + ]; - IROHA_SKIP_WASM_CHECKS = true; - }; + IROHA_SKIP_WASM_CHECKS = true; + }; }); } From 8dee8d21cb71cb20987b2de653350de0857a11ad Mon Sep 17 00:00:00 2001 From: 0x009922 Date: Fri, 13 Oct 2023 07:02:31 +0000 Subject: [PATCH 50/55] [docs]: Remove `api_spec.md` (#3968) --- .github/workflows/iroha2-dev-pr-label.yml | 3 +- README.md | 48 +-- docs/README.md | 4 +- docs/source/iroha_2_whitepaper.md | 2 +- docs/source/references/api_spec.md | 381 ---------------------- 5 files changed, 28 insertions(+), 410 deletions(-) delete mode 100644 docs/source/references/api_spec.md diff --git a/.github/workflows/iroha2-dev-pr-label.yml b/.github/workflows/iroha2-dev-pr-label.yml index 946adb60e76..166621dee97 100644 --- a/.github/workflows/iroha2-dev-pr-label.yml +++ b/.github/workflows/iroha2-dev-pr-label.yml @@ -5,7 +5,6 @@ on: branches: [iroha-dev] paths: - 'docs/source/references/schema.json' - - 'docs/source/references/api_spec.md' - 'docs/source/references/config.md' jobs: @@ -17,7 +16,7 @@ jobs: continue-on-error: true id: api_label - uses: actions-ecosystem/action-add-labels@v1 - if: contains(steps.api_label.outputs.added_modified, 'docs/source/references/schema.json') || contains(steps.api_label.outputs.added_modified, 'docs/source/references/api_spec.md') + if: contains(steps.api_label.outputs.added_modified, 'docs/source/references/schema.json') with: github_token: ${{ secrets.github_token }} labels: | diff --git a/README.md b/README.md index dcf33bf4aa5..237481c5a48 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Engage with the community: - [Contribute](./CONTRIBUTING.md) to the repository - [Contact us](./CONTRIBUTING.md#contact) to get help -# System Requirements +## System Requirements RAM and storage requirements depend on your use case: whether you need to build or deploy a network, how big it is, and so on. This table summarises the requirements: @@ -60,7 +60,7 @@ CPU considerations: * Rust compilation highly favours multi-core CPUs such as Apple M1™, AMD Ryzen™/Threadripper™/Epyc™, and Intel Alder Lake™. * On systems with restricted memory and many CPU cores, Iroha compilation may sometimes fail with `SIGKILL`. To avoid it, restrict the number of CPU cores using `cargo build -j `, where `` (without the angle brackets) is half of your RAM capacity rounded down. -# Build, Test, and Run Iroha +## Build, Test, and Run Iroha Prerequisites: @@ -90,7 +90,7 @@ bash ./scripts/test_env.sh cleanup -## Build Iroha +### Build Iroha - Build Iroha and accompanying binaries: @@ -106,7 +106,7 @@ bash ./scripts/test_env.sh cleanup If you skip this step, the Iroha container will be built using the latest available image. -## Run Iroha +### Run Iroha Once you have built Iroha, you can instantiate the minimum viable network: @@ -122,7 +122,7 @@ cd target/debug ./iroha_client_cli --help ``` -# Integration +## Integration Iroha project mainly consists of the following crates: @@ -144,7 +144,7 @@ Iroha project mainly consists of the following crates: * [`iroha_telemetry`](telemetry) is used for monitoring and analysis of telemetry data. * [`iroha_version`](version) provides message versioning for non-simultaneous system updates. -# Maintenance +## Maintenance A brief overview on how to configure and maintain an Iroha instance: @@ -155,17 +155,17 @@ A brief overview on how to configure and maintain an Iroha instance: - [Storage](#storage) - [Scalability](#scalability) -## Configuration +### Configuration You can provide configuration parameters either as a `config.json` or using environment variables. Refer to the [detailed list](./docs/source/references/config.md) of all available configuration parameters. Configuration example you may use as a reference point: [cli/src/samples.rs](./cli/src/samples.rs) -## Endpoints +### Endpoints -You can find the detailed list of all available endpoints in the [API specifications](./docs/source/references/api_spec.md#endpoints). +For a list of all endpoints, available operations, and ways to customize them with parameters, see [API Reference > Torii Endpoints](https://hyperledger.github.io/iroha-2-docs/api/torii-endpoints) -## Logging +### Logging By default, Iroha provides logs in a human-readable format and prints them out to `stdout`. @@ -182,7 +182,7 @@ curl -X POST \ ``` -### JSON Logging Mode +#### JSON Logging Mode Additionally, Iroha supports a JSON logging mode. @@ -190,9 +190,9 @@ To enable it, provide the [logging file](./docs/source/references/config.md#logg [Log rotation](https://www.commandlinux.com/man-page/man5/logrotate.conf.5.html) is the responsibility of the peer administrator. -## Monitoring +### Monitoring -The details of the `Health` endpoint can be found in the [API specifications](./docs/source/references/api_spec.md#health). +The details of the `Health` endpoint can be found in the [API Reference > Torii Endpoints](https://hyperledger.github.io/iroha-2-docs/api/torii-endpoints#health). Iroha can produce both JSON-formatted as well as `prometheus`-readable metrics at the `status` and `metrics` endpoints respectively. @@ -202,28 +202,28 @@ The [`prometheus`](https://prometheus.io/docs/introduction/overview/) monitoring prometheus --config.file=configs/prometheus.yml ``` -## Storage +### Storage The blocks are written to the `blocks` sub-folder, which is created automatically by Iroha in the working directory of the peer. Additionally, if specified, the logging file must also be stored in a user-specified directory. No additional storage is necessary. -## Scalability +### Scalability Multiple instances of Iroha peer and client binaries can be run on the same physical machine and in the same working directory. However, we recommend to give each instance a clean new working directory. The provided `docker-compose` file showcases a minimum viable network and the general methods of using the `hyperledger/iroha2:dev` docker image for deploying a network of peers. -# Further Reading +## Further Reading We encourage you to check out our [Iroha 2 Tutorial](https://hyperledger.github.io/iroha-2-docs/) first. It is suitable for both experienced developers and prospective users of Iroha 2, and it provides language-specific guides for Bash, Python, Rust, Kotlin/Java, and Javascript/TypeScript. -* [Iroha 2 Tutorial](https://hyperledger.github.io/iroha-2-docs/) +* [Iroha 2 Documentation](https://hyperledger.github.io/iroha-2-docs/) + * [Glossary](https://hyperledger.github.io/iroha-2-docs/guide/glossary) + * [Iroha Special Instructions](https://hyperledger.github.io/iroha-2-docs/guide/blockchain/instructions) + * [API Reference](https://hyperledger.github.io/iroha-2-docs/api/torii-endpoints) +* [Configuration Reference](./docs/source/references/config.md) * [Iroha 2 Whitepaper](./docs/source/iroha_2_whitepaper.md) -* [Glossary](https://hyperledger.github.io/iroha-2-docs/guide/glossary.html) -* [Configuration](./docs/source/references/config.md) -* [Iroha Special Instructions](https://hyperledger.github.io/iroha-2-docs/guide/blockchain/instructions.html) -* [API specification](./docs/source/references/api_spec.md) Iroha SDKs: @@ -232,17 +232,17 @@ Iroha SDKs: * [Iroha Javascript](https://github.com/hyperledger/iroha-javascript) * [Iroha iOS Swift](https://github.com/hyperledger/iroha-ios) -# How to Contribute +## How to Contribute We welcome community contributions! Report bugs and suggest improvements via GitHub issues and pull requests. Check out our [contributing guide](./CONTRIBUTING.md) to learn more. -# Get Help +## Get Help Check out the channels you could use to [get help or engage with the community](./CONTRIBUTING.md#contact). -# License +## License Iroha codebase is licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except diff --git a/docs/README.md b/docs/README.md index 8074f170ec7..11e941c5e8f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,8 +3,8 @@ This is the main Iroha 2 documentation that you will find useful: - [Tutorial](https://hyperledger.github.io/iroha-2-docs/) -- [API Specification](./source/references/api_spec.md) -- [Configuration Options](./source/references/config.md) +- [API Reference](https://hyperledger.github.io/iroha-2-docs/api/torii-endpoints) +- [Configuration Reference](./source/references/config.md) - [Iroha 2 Whitepaper](./source/iroha_2_whitepaper.md) ## Tools diff --git a/docs/source/iroha_2_whitepaper.md b/docs/source/iroha_2_whitepaper.md index 877e45a9e1f..10f762f111f 100644 --- a/docs/source/iroha_2_whitepaper.md +++ b/docs/source/iroha_2_whitepaper.md @@ -339,7 +339,7 @@ To retrieve information about World State View of the Peer clients will use Iroh ### 2.14 Client API -Client libraries interact with Iroha over the HTTP and WebSocket. Check the up to date API reference [here](./references/api_spec.md). +Client libraries interact with Iroha over the HTTP and WebSocket. For details about the available endpoints, see [API Reference > Torii Endpoints](https://hyperledger.github.io/iroha-2-docs/api/torii-endpoints). ### 2.15 Versioning diff --git a/docs/source/references/api_spec.md b/docs/source/references/api_spec.md deleted file mode 100644 index 8c4ccafb248..00000000000 --- a/docs/source/references/api_spec.md +++ /dev/null @@ -1,381 +0,0 @@ -# API Specification for Client Libraries - -## Endpoints for API - -### Transaction - -**Protocol**: HTTP - -**Encoding**: [Parity Scale Codec](#parity-scale-codec) - -**Endpoint**: `/transaction` - -**Method**: `POST` - -**Expects**: Body: `SignedTransaction` - -**Responses**: - -| Status | Description | -|--------|------------------------------------------------------------------------| -| 200 | Transaction Accepted (But not guaranteed to have passed consensus yet) | -| 400 | Transaction Rejected (Malformed) | -| 401 | Transaction Rejected (Improperly signed) | - -### Query - -**Protocol**: HTTP - -**Encoding**: [Parity Scale Codec](#parity-scale-codec) - -**Endpoint**: `/query` - -**Method**: `POST` - -**Expects**: - -- Body: `SignedQuery` -- Query parameters: - - `start`: Optional parameter in queries where results can be indexed. Use to return results from specified point. - Results are ordered where can be by id which uses - rust's [PartialOrd](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html#derivable) - and [Ord](https://doc.rust-lang.org/std/cmp/trait.Ord.html) traits. - - `limit`: Optional parameter in queries where results can be indexed. Use to return specific number of results. - - `sort_by_metadata_key`: Optional parameter in queries. Use to sort results containing metadata with a given key. - -**Responses**: - -| Response | Status | Body | -|-----------------|--------|--------------------------------------------| -| Signature err. | 401 | `QueryExecutionFail::Signature(String)` | -| Permission err. | 403 | `QueryExecutionFail::Permission(String)` | -| Evaluate err. | 400 | `QueryExecutionFail::Evaluate(String)` | -| Find err. | 404 | `QueryExecutionFail::Find(Box)` | -| Conversion err. | 400 | `QueryExecutionFail::Conversion(String)` | -| Success | 200 | `VersionedPaginatedQueryResult` | - -#### Account Not Found 404 - -Whether each prerequisite object was found and `FindError`: - -| Domain | Account | `FindError` | -|--------|---------|---------------------------------| -| N | - | `FindError::Domain(DomainId)` | -| Y | N | `FindError::Account(AccountId)` | - -#### Asset Not Found 404 - -Whether each prerequisite object was found and `FindError`: - -| Domain | Account | Asset Definition | Asset | `FindError` | -|--------|---------|------------------|-------|-------------------------------------------------| -| N | - | - | - | `FindError::Domain(DomainId)` | -| Y | N | - | - | `FindError::Account(AccountId)` | -| Y | - | N | - | `FindError::AssetDefinition(AssetDefinitionId)` | -| Y | Y | Y | N | `FindError::Asset(AssetId)` | - -### Events - -**Protocol**: HTTP - -**Protocol Upgrade**: `WebSocket` - -**Encoding**: [Parity Scale Codec](#parity-scale-codec) - -**Endpoint**: `/events` - -**Communication**: - -After handshake, client should send `VersionedEventSubscriptionRequest`. Then server sends `VersionedEventMessage`. - -**Notes**: - -Usually, the client waits for Transaction events. - -Transaction event statuses can be either `Validating`, `Committed` or `Rejected`. - -Transaction statuses proceed from `Validating` to either `Committed` or `Rejected`. -However, due to the distributed nature of the network, some peers might receive events out of order (e.g. `Committed` -before `Validating`). - -It's possible that some peers in the network are offline for the validation round. If the client connects to them while -they are offline, the peers might not respond with the `Validating` status. -But when the offline peers come back online they will synchronize the blocks. They are then guaranteed to respond with -the `Committed` (or `Rejected`) status depending on the information found in the block. - -### Pending Transactions - -**Protocol**: HTTP - -**Encoding**: [Parity Scale Codec](#parity-scale-codec) - -**Endpoint**: `/pending_transactions` - -**Method**: `GET` - -**Expects**: - -_Internal use only._ Returns the transactions pending at the moment. - -### Blocks Stream - -**Protocol**: HTTP - -**Protocol Upgrade**: `WebSocket` - -**Encoding**: [Parity Scale Codec](#parity-scale-codec) - -**Endpoint**: `/block/stream` - -**Communication**: - -Client should send `VersionedBlockSubscriptionRequest` to initiate communication after WebSocket handshake. Then server sends `VersionedBlockMessage`. - -**Notes**: - -Via this endpoint client first provides the starting block number (i.e. height) in the subscription request. After -sending the confirmation message, server starts streaming all the blocks from the given block number up to the current -block and continues to stream blocks as they are added to the blockchain. - -### Get Configuration - -**Protocol**: HTTP - -**Encoding**: JSON - -**Endpoint**: `/configuration` - -**Method**: `GET` - -**Expects**: -There are 2 options: - -- Expects: a JSON body `"Value"`. Returns: configuration value as JSON. -- Expects: a JSON body that specifies the field (see example below). Returns: documentation for a specific field (as - JSON string) or `null`. - -Note that if the requested field has more fields inside of it, then all the documentation for its inner members is -returned as well. -Here is an example for getting a field `a.b.c`: - -```json -{ - "Docs": [ - "a", - "b", - "c" - ] -} -``` - -**Examples**: -To get the top-level configuration docs for [`Torii`] and all the fields within it: - -```bash -curl -X GET -H 'content-type: application/json' http://127.0.0.1:8080/configuration -d '{"Docs" : ["torii"]} ' -i -``` - -**Responses**: - -- 200 OK: Field was found and either doc or value is returned in json body. -- 404 Not Found: Field wasn't found - -### Configuration - -**Protocol**: HTTP - -**Encoding**: JSON - -**Endpoint**: `/configuration` - -**Method**: `POST` - -**Expects**: -One configuration option is currently supported: `LogLevel`. It is set to the log-level in uppercase. - -```json -{ - "LogLevel": "WARN" -} -``` - -Acceptable values are `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, corresponding to -the [respective configuration options](./config.md#loggermaxloglevel). - -**Responses**: - -- 200 OK: Log level has changed successfully. The confirmed new log level is returned in the body. -- 400 Bad Request: request body malformed. -- 500 Internal Server Error: Request body valid, but changing the log level failed (lock contention). - -### Health - -**Protocol**: HTTP - -**Encoding**: JSON - -**Endpoint**: `/health` - -**Method**: `GET` - -**Expects**: - - -**Responses**: - -- 200 OK: The peer is up. - Also returns current status of peer in json string: - -``` -"Healthy" -``` - -## Endpoints for Status/Metrics - -### Status - -**Protocol**: HTTP - -**Encoding**: JSON - -**Endpoint**: `/status` - -**Method**: `GET` - -**Expects**: - - -**Responses**: - -200 OK reports status as JSON: - -```json5 -// Note: while this snippet is JSON5 (for better readability), -// the actual response is JSON -{ - /** - * Number of connected peers, except for the reporting peer itself - */ - peers: 3, - /** - * Number of committed blocks (block height) - */ - blocks: 1, - /** - * Total number of accepted transactions - */ - txs_accepted: 3, - /** - * Total number of rejected transactions - */ - txs_rejected: 0, - /** - * Uptime with nanosecond precision since creation of the genesis block - */ - uptime: { - secs: 5, - nanos: 937000000, - }, - /** - * Number of view changes in the current round - */ - view_changes: 0, -} -``` - -**CAUTION**: Almost all fields are 64-bit integers and should be handled with care in JavaScript. Only the `nanos` field -is a 32-bit integer. See `iroha_telemetry::metrics::Status`. - -**Sub-routing**: To obtain the value of a specific field, one can append the name of the field to the path, -e.g. `status/peers`. This returns the corresponding JSON value, inline, so strings are quoted, numbers are not and maps -are presented as above. - -### Metrics - -**Protocol**: HTTP - -**Encoding**: Prometheus - -**Endpoint**: `/metrics` - -**Method**: `GET` - -**Expects**: - - -**Responses**: - -- 200 OK reports 8 of 10 metrics: - -```bash -# HELP accounts User accounts registered at this time -# TYPE accounts gauge -accounts{domain="genesis"} 1 -accounts{domain="wonderland"} 1 -# HELP block_height Current block height -# TYPE block_height counter -block_height 1 -# HELP connected_peers Total number of currently connected peers -# TYPE connected_peers gauge -connected_peers 0 -# HELP domains Total number of domains -# TYPE domains gauge -domains 2 -# HELP tx_amount average amount involved in a transaction on this peer -# TYPE tx_amount histogram -tx_amount_bucket{le="0.005"} 0 -tx_amount_bucket{le="0.01"} 0 -tx_amount_bucket{le="0.025"} 0 -tx_amount_bucket{le="0.05"} 0 -tx_amount_bucket{le="0.1"} 0 -tx_amount_bucket{le="0.25"} 0 -tx_amount_bucket{le="0.5"} 0 -tx_amount_bucket{le="1"} 0 -tx_amount_bucket{le="2.5"} 0 -tx_amount_bucket{le="5"} 0 -tx_amount_bucket{le="10"} 0 -tx_amount_bucket{le="+Inf"} 2 -tx_amount_sum 26 -tx_amount_count 2 -# HELP txs Transactions committed -# TYPE txs counter -txs{type="accepted"} 1 -txs{type="rejected"} 0 -txs{type="total"} 1 -# HELP uptime_since_genesis_ms Network up-time, from creation of the genesis block -# TYPE uptime_since_genesis_ms gauge -uptime_since_genesis_ms 54572974 -# HELP view_changes Number of view_changes in the current round -# TYPE view_changes gauge -view_changes 0 -``` - -Learn [how to use metrics](https://hyperledger.github.io/iroha-2-docs/guide/advanced/metrics.html). - -### API Version - -**Protocol**: HTTP - -**Encoding**: JSON - -**Endpoint**: `/api_version` - -**Method**: `GET` - -**Expects**: - - -**Responses**: - -- 200 OK: The current version of API used by Iroha returned as a json string. - Grabbed from the genesis block's version, so at least a minimal subnet of 4 peers - should be running and the genesis be submitted at the time of request. - -``` -"1" -``` - -## Parity Scale Codec - -For more information on codec check [Substrate Dev Hub](https://substrate.dev/docs/en/knowledgebase/advanced/codec) and -codec's [GitHub repository](https://github.com/paritytech/parity-scale-codec). - -## Reference Iroha Client Implementation - -[Iroha client in Rust.](../../../client) From 42c1a0f2c73125bbb3a3d8130f5fe651252f420e Mon Sep 17 00:00:00 2001 From: Daniil Polyakov Date: Fri, 13 Oct 2023 11:04:35 +0300 Subject: [PATCH 51/55] [fix] #0000: Fix executor downloading in update_configs.sh (#3990) Signed-off-by: Daniil Polyakov --- scripts/update_configs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_configs.sh b/scripts/update_configs.sh index 1c4af8a9bc7..ad20cd9f8b8 100755 --- a/scripts/update_configs.sh +++ b/scripts/update_configs.sh @@ -22,4 +22,4 @@ curl https://raw.githubusercontent.com/hyperledger/iroha/iroha2-lts/configs/peer curl https://raw.githubusercontent.com/hyperledger/iroha/iroha2-stable/configs/peer/config.json -o ./configs/peer/$1/config.json curl https://raw.githubusercontent.com/hyperledger/iroha/iroha2-stable/configs/peer/genesis.json -o ./configs/peer/$1/genesis.json -curl https://raw.githubusercontent.com/hyperledger/iroha/iroha2-stable/configs/peer/genesis.json -o ./configs/peer/$1/executor.wasm +curl https://raw.githubusercontent.com/hyperledger/iroha/iroha2-stable/configs/peer/executor.wasm -o ./configs/peer/$1/executor.wasm From ee62def2aec0ec0e09c385e71742e3080e6f3d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Fri, 13 Oct 2023 10:24:43 +0200 Subject: [PATCH 52/55] [refactor]: bump dependencies (#3981) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- Cargo.lock | 1721 +++++++---------- Cargo.toml | 234 +-- cli/Cargo.toml | 2 +- cli/derive/src/lib.rs | 1 - cli/src/event.rs | 5 - cli/src/lib.rs | 6 - cli/src/main.rs | 4 - cli/src/samples.rs | 1 - client/Cargo.toml | 10 +- client/benches/torii.rs | 13 +- client/benches/tps/dev.rs | 8 - client/benches/tps/oneshot.rs | 1 - client/benches/tps/utils.rs | 11 - client/examples/million_accounts_genesis.rs | 5 +- client/examples/tutorial.rs | 14 +- client/src/client.rs | 15 +- client/src/http_default.rs | 27 +- client/src/lib.rs | 1 - client/tests/integration/add_account.rs | 2 - client/tests/integration/add_domain.rs | 2 - client/tests/integration/asset.rs | 2 - client/tests/integration/asset_propagation.rs | 2 - client/tests/integration/burn_public_keys.rs | 2 - client/tests/integration/config.rs | 2 - client/tests/integration/connected_peers.rs | 3 - client/tests/integration/domain_owner.rs | 2 - client/tests/integration/events/data.rs | 1 - .../tests/integration/events/notification.rs | 2 - client/tests/integration/events/pipeline.rs | 2 - .../integration/multiple_blocks_created.rs | 2 - .../integration/multisignature_account.rs | 2 - .../integration/multisignature_transaction.rs | 2 - client/tests/integration/non_mintable.rs | 2 - client/tests/integration/offline_peers.rs | 2 - client/tests/integration/pagination.rs | 2 - client/tests/integration/permissions.rs | 2 - client/tests/integration/queries/account.rs | 2 - client/tests/integration/queries/asset.rs | 1 - client/tests/integration/queries/role.rs | 2 - client/tests/integration/query_errors.rs | 2 - client/tests/integration/restart_peer.rs | 2 - client/tests/integration/roles.rs | 2 - client/tests/integration/set_parameter.rs | 2 - client/tests/integration/sorting.rs | 47 +- client/tests/integration/transfer_asset.rs | 12 +- .../integration/triggers/by_call_trigger.rs | 5 +- .../integration/triggers/data_trigger.rs | 2 - .../integration/triggers/event_trigger.rs | 2 - .../integration/triggers/time_trigger.rs | 2 - client/tests/integration/tx_history.rs | 2 - client/tests/integration/tx_rollback.rs | 2 - client/tests/integration/unregister_peer.rs | 3 - client/tests/integration/unstable_network.rs | 2 - client/tests/integration/upgrade.rs | 2 - client/tests/wasm/utils.rs | 6 - client_cli/Cargo.toml | 8 +- client_cli/src/main.rs | 13 - config/Cargo.toml | 5 +- config/base/derive/src/lib.rs | 2 - config/base/derive/src/proxy.rs | 2 - config/base/derive/src/utils.rs | 7 +- config/base/derive/src/view.rs | 1 - config/base/src/runtime_upgrades.rs | 4 +- config/base/tests/simple.rs | 9 +- config/src/block_sync.rs | 1 - config/src/client.rs | 5 - config/src/genesis.rs | 3 - config/src/iroha.rs | 6 - config/src/kura.rs | 3 - config/src/logger.rs | 11 +- config/src/network.rs | 1 - config/src/path.rs | 1 - config/src/queue.rs | 1 - config/src/sumeragi.rs | 4 +- config/src/telemetry.rs | 1 - config/src/torii.rs | 1 - config/src/wasm.rs | 1 - config/src/wsv.rs | 2 - configs/peer/executor.wasm | Bin 504366 -> 504337 bytes core/Cargo.toml | 2 +- core/benches/blocks/apply_blocks.rs | 2 - core/benches/blocks/apply_blocks_benchmark.rs | 2 +- core/benches/blocks/apply_blocks_oneshot.rs | 1 - core/benches/blocks/common.rs | 2 - core/benches/blocks/validate_blocks.rs | 2 - .../blocks/validate_blocks_benchmark.rs | 2 +- .../benches/blocks/validate_blocks_oneshot.rs | 1 - core/benches/kura.rs | 2 +- core/benches/validation.rs | 2 +- core/src/block.rs | 11 +- core/src/block_sync.rs | 5 - core/src/gossiper.rs | 1 - core/src/kura.rs | 5 - core/src/queue.rs | 58 +- core/src/smartcontracts/isi/account.rs | 1 - core/src/smartcontracts/isi/mod.rs | 7 - core/src/smartcontracts/isi/query.rs | 7 - core/src/smartcontracts/isi/triggers/mod.rs | 1 - core/src/smartcontracts/wasm.rs | 8 +- core/src/snapshot.rs | 7 - core/src/sumeragi/main_loop.rs | 2 - core/src/sumeragi/message.rs | 7 - core/src/sumeragi/mod.rs | 7 +- core/src/sumeragi/network_topology.rs | 7 - core/src/sumeragi/view_change.rs | 7 - core/src/tx.rs | 8 - core/src/wsv.rs | 12 +- core/test_network/Cargo.toml | 2 +- core/test_network/src/lib.rs | 3 - crypto/Cargo.toml | 2 +- crypto/build.rs | 1 - crypto/src/hash.rs | 8 +- crypto/src/lib.rs | 18 +- crypto/src/merkle.rs | 10 +- crypto/src/multihash.rs | 8 +- crypto/src/signature.rs | 13 +- crypto/src/varint.rs | 2 - data_model/benches/time_event_filter.rs | 2 +- data_model/build.rs | 1 - data_model/derive/src/filter.rs | 5 - data_model/derive/src/has_origin.rs | 6 - data_model/derive/src/id.rs | 2 - data_model/derive/src/lib.rs | 2 - data_model/derive/src/model.rs | 2 - data_model/derive/src/partially_tagged/mod.rs | 2 +- data_model/derive/tests/has_origin.rs | 3 +- .../derive/tests/has_origin_generics.rs | 3 +- .../derive/tests/partial_tagged_serde.rs | 10 +- .../derive/tests/partial_tagged_serde_self.rs | 10 +- data_model/src/account.rs | 2 - data_model/src/asset.rs | 2 - data_model/src/domain.rs | 2 - data_model/src/evaluate.rs | 2 - data_model/src/events/pipeline.rs | 2 - data_model/src/events/time.rs | 2 - data_model/src/ipfs.rs | 4 +- data_model/src/isi.rs | 4 +- data_model/src/lib.rs | 16 +- data_model/src/metadata.rs | 2 - data_model/src/name.rs | 2 - data_model/src/numeric.rs | 2 +- data_model/src/predicate.rs | 10 +- data_model/src/query/mod.rs | 4 +- data_model/src/transaction.rs | 12 +- data_model/src/trigger.rs | 3 +- data_model/src/visit.rs | 18 +- data_model/tests/data_model.rs | 2 - docs/source/references/schema.json | 8 +- ffi/derive/src/attr_parse/derive.rs | 6 +- ffi/derive/src/attr_parse/getset.rs | 17 +- ffi/derive/src/convert.rs | 4 +- ffi/derive/src/ffi_fn.rs | 2 +- ffi/derive/src/impl_visitor.rs | 4 +- ffi/derive/src/lib.rs | 2 - ffi/derive/src/wrapper.rs | 6 +- ffi/src/option.rs | 2 +- ffi/src/primitives.rs | 21 +- ffi/src/repr_c.rs | 13 +- ffi/tests/export_getset.rs | 2 +- ffi/tests/export_shared_fns.rs | 2 +- ffi/tests/ffi_export.rs | 10 +- ffi/tests/ffi_export_import_u128_i128.rs | 12 +- ffi/tests/ffi_import.rs | 4 +- ffi/tests/ffi_import_opaque.rs | 10 +- ffi/tests/generics.rs | 2 +- ffi/tests/import_getset.rs | 2 +- ffi/tests/import_shared_fns.rs | 2 +- ffi/tests/transparent.rs | 5 +- ffi/tests/unambiguous.rs | 4 +- futures/Cargo.toml | 2 +- futures/derive/src/lib.rs | 9 +- futures/src/lib.rs | 3 - futures/tests/basic.rs | 2 - genesis/src/lib.rs | 21 +- logger/Cargo.toml | 3 +- logger/src/layer.rs | 1 - logger/src/lib.rs | 6 - logger/src/telemetry.rs | 6 - logger/tests/configuration.rs | 4 +- logger/tests/log_level.rs | 3 +- logger/tests/setting_logger.rs | 2 - logger/tests/telemetry.rs | 2 - macro/derive/src/lib.rs | 2 - macro/src/lib.rs | 2 - p2p/src/lib.rs | 1 - p2p/src/network.rs | 2 - p2p/src/peer.rs | 5 +- p2p/tests/integration/p2p.rs | 3 - primitives/Cargo.toml | 2 +- primitives/src/cmpext.rs | 6 +- primitives/src/conststr.rs | 11 +- primitives/src/fixed.rs | 6 +- primitives/src/small.rs | 4 +- primitives/src/unique_vec.rs | 2 +- schema/derive/src/lib.rs | 5 +- schema/gen/src/lib.rs | 2 - schema/src/lib.rs | 2 + schema/src/serialize.rs | 4 +- .../tests/enum_with_various_discriminants.rs | 6 - schema/tests/fieldless_enum.rs | 6 - schema/tests/schema_json.rs | 4 +- smart_contract/derive/src/entrypoint.rs | 8 +- smart_contract/derive/src/lib.rs | 2 +- smart_contract/executor/derive/src/lib.rs | 2 - smart_contract/executor/derive/src/token.rs | 2 - .../executor/derive/src/validate.rs | 7 +- smart_contract/src/lib.rs | 3 - smart_contract/trigger/derive/src/lib.rs | 2 - smart_contract/utils/src/debug.rs | 5 - telemetry/Cargo.toml | 2 +- telemetry/derive/src/lib.rs | 7 +- telemetry/src/futures.rs | 4 +- telemetry/src/metrics.rs | 4 +- telemetry/src/retry_period.rs | 2 - telemetry/src/ws.rs | 3 - tools/kagami/src/docs.rs | 6 - tools/kagami/src/genesis.rs | 4 +- tools/kagami/src/main.rs | 6 - tools/kura_inspector/src/main.rs | 16 +- tools/parity_scale_decoder/Cargo.toml | 2 +- tools/parity_scale_decoder/build.rs | 2 - tools/parity_scale_decoder/src/main.rs | 8 - tools/wasm_builder_cli/src/main.rs | 4 +- tools/wasm_test_runner/src/main.rs | 8 +- version/derive/src/lib.rs | 1 - version/derive/tests/json.rs | 10 +- version/derive/tests/scale.rs | 9 +- version/src/lib.rs | 6 +- wasm_builder/Cargo.toml | 2 +- wasm_builder/src/lib.rs | 1 + wasm_codec/derive/src/lib.rs | 2 +- wasm_codec/src/lib.rs | 3 - 232 files changed, 1103 insertions(+), 2011 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c25dea84be..2e42401fc1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" -dependencies = [ - "gimli", -] - -[[package]] -name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -94,9 +85,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -141,32 +132,37 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstream" -version = "0.3.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" dependencies = [ "utf8parse", ] @@ -182,9 +178,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -239,33 +235,31 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "async-trait" -version = "0.1.72" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "attohttpc" -version = "0.18.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69e13a99a7e6e070bb114f7ff381e58c7ccc188630121fc4c2fe4bcf24cd072" +checksum = "0f77d243921b0979fbbd728dd2d5162e68ac8252976797c24eb5b3a6af9090dc" dependencies = [ "flate2", "http", "log", "native-tls", - "openssl", "url", - "wildmatch", ] [[package]] @@ -296,9 +290,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a1de45611fdb535bfde7b7de4fd54f4fd2b17b1737c0a59b69bf9b92074b8c" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", @@ -341,16 +335,16 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ - "addr2line 0.20.0", + "addr2line", "cc", "cfg-if", "libc", "miniz_oxide", - "object 0.31.1", + "object", "rustc-demangle", ] @@ -362,9 +356,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "basic-toml" @@ -407,9 +401,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bitvec" @@ -492,12 +486,12 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bstr" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019" dependencies = [ "memchr", - "regex-automata 0.3.4", + "regex-automata 0.4.1", "serde", ] @@ -512,9 +506,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byte-slice-cast" @@ -540,15 +534,15 @@ dependencies = [ [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "c2-chacha" @@ -567,11 +561,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -605,37 +600,52 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", - "time 0.1.45", "wasm-bindgen", - "winapi", + "windows-targets 0.48.5", ] [[package]] -name = "cipher" -version = "0.2.5" +name = "ciborium" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" dependencies = [ - "generic-array 0.14.7", + "ciborium-io", + "ciborium-ll", + "serde", ] [[package]] -name = "clap" -version = "2.34.0" +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" dependencies = [ - "bitflags 1.3.2", - "textwrap 0.11.0", - "unicode-width", + "ciborium-io", + "half", +] + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array 0.14.7", ] [[package]] @@ -652,30 +662,28 @@ dependencies = [ "once_cell", "strsim", "termcolor", - "textwrap 0.16.0", + "textwrap", ] [[package]] name = "clap" -version = "4.3.19" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" +checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" dependencies = [ "clap_builder", - "clap_derive 4.3.12", - "once_cell", + "clap_derive 4.4.2", ] [[package]] name = "clap_builder" -version = "4.3.19" +version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" +checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" dependencies = [ "anstream", "anstyle", - "clap_lex 0.5.0", - "once_cell", + "clap_lex 0.5.1", "strsim", ] @@ -694,14 +702,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.12" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -715,9 +723,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "clru" @@ -794,10 +802,11 @@ dependencies = [ [[package]] name = "console-api" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2895653b4d9f1538a83970077cb01dfc77a4810524e51a110944688e916b18e" +checksum = "fd326812b3fd01da5bb1af7d340d0d555fd3d4b641e7f1dfcf5962a902952787" dependencies = [ + "futures-core", "prost", "prost-types", "tonic", @@ -806,14 +815,14 @@ dependencies = [ [[package]] name = "console-subscriber" -version = "0.1.10" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4cf42660ac07fcebed809cfe561dd8730bcd35b075215e6479c516bcd0d11cb" +checksum = "7481d4c57092cd1c19dd541b92bdce883de840df30aa5d03fd48a3935c01842e" dependencies = [ "console-api", "crossbeam-channel", "crossbeam-utils", - "futures", + "futures-task", "hdrhistogram", "humantime", "prost-types", @@ -876,18 +885,18 @@ checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" [[package]] name = "cranelift-bforest" -version = "0.98.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1380172556902242d32f78ed08c98aac4f5952aef22d3684aed5c66a5db0a6fc" +checksum = "03b9d1a9e776c27ad55d7792a380785d1fe8c2d7b099eed8dbd8f4af2b598192" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.98.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037cca234e1ad0766fdfe43b527ec14e100414b4ccf4bb614977aa9754958f57" +checksum = "5528483314c2dd5da438576cd8a9d0b3cedad66fb8a4727f90cd319a81950038" dependencies = [ "bumpalo", "cranelift-bforest", @@ -897,7 +906,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.13.2", + "hashbrown 0.14.1", "log", "regalloc2", "smallvec", @@ -906,42 +915,43 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.98.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d375e6afa8b9a304999ea8cf58424414b8e55e004571265a4f0826eba8b74f18" +checksum = "0f46a8318163f7682e35b8730ba93c1b586a2da8ce12a0ed545efc1218550f70" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.98.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca590e72ccb8da963def6e36460cce4412032b1f03c31d1a601838d305abdc39" +checksum = "37d1239cfd50eecfaed468d46943f8650e32969591868ad50111613704da6c70" [[package]] name = "cranelift-control" -version = "0.98.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2d38eea4373639f4b6236a40f69820fed16c5511093cd3783bf8491a93d9cf" +checksum = "bcc530560c8f16cc1d4dd7ea000c56f519c60d1a914977abe849ce555c35a61d" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.98.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3173c1434af23c00e4964722cf93ca8f0e6287289bf5d52110597c3ba2ea09" +checksum = "f333fa641a9ad2bff0b107767dcb972c18c2bfab7969805a1d7e42449ccb0408" dependencies = [ "serde", + "serde_derive", ] [[package]] name = "cranelift-frontend" -version = "0.98.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aec4a3a33825062eccf6eec73e852c8773220f6e4798925e19696562948beb1f" +checksum = "06abf6563015a80f03f8bc4df307d0a81363f4eb73108df3a34f6e66fb6d5307" dependencies = [ "cranelift-codegen", "log", @@ -951,15 +961,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.98.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5146b5cea4b21095a021d964b0174cf6ff5530f83e8d0a822683c7559e360b66" +checksum = "0eb29d0edc8a5c029ed0f7ca77501f272738e3c410020b4a00f42ffe8ad2a8aa" [[package]] name = "cranelift-native" -version = "0.98.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cec3717ce554d3936b2101aa8eae1a2a410bd6da0f4df698a4b008fe9cf1e9" +checksum = "006056a7fa920870bad06bf8e1b3033d70cbb7ee625b035efa9d90882a931868" dependencies = [ "cranelift-codegen", "libc", @@ -968,14 +978,14 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.98.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fd2f9f1bf29ce6639ae2f477a2fe20bad0bd09289df13efeb890e8e4b9f807" +checksum = "7b3d08c05f82903a1f6a04d89c4b9ecb47a4035710f89a39a21a147a80214672" dependencies = [ "cranelift-codegen", "cranelift-entity", "cranelift-frontend", - "itertools", + "itertools 0.10.5", "log", "smallvec", "wasmparser", @@ -993,24 +1003,24 @@ dependencies = [ [[package]] name = "criterion" -version = "0.3.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ - "atty", + "anes", "cast", - "clap 2.34.0", + "ciborium", + "clap 4.4.6", "criterion-plot", - "csv", - "itertools", - "lazy_static", + "is-terminal", + "itertools 0.10.5", "num-traits", + "once_cell", "oorandom", "plotters", "rayon", "regex", "serde", - "serde_cbor", "serde_derive", "serde_json", "tinytemplate", @@ -1019,12 +1029,12 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -1071,7 +1081,7 @@ dependencies = [ "autocfg 1.1.0", "cfg-if", "crossbeam-utils", - "memoffset 0.9.0", + "memoffset", "scopeguard", ] @@ -1161,27 +1171,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "csv" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - [[package]] name = "ctr" version = "0.6.0" @@ -1206,9 +1195,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.102" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f68e12e817cb19eaab81aaec582b4052d07debd3c3c6b083b9d361db47c7dc9d" +checksum = "292b4841d939b20ba44fff686a35808b0ab31a3256e3629917d9aedd43eb7b3a" dependencies = [ "cc", "cxxbridge-flags", @@ -1218,9 +1207,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.102" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e789217e4ab7cf8cc9ce82253180a9fe331f35f5d339f0ccfe0270b39433f397" +checksum = "8e7e35cf85fd4e90dcaba251f3ee95e08fb6f9d66e5c0588816f16a6ab939b40" dependencies = [ "cc", "codespan-reporting", @@ -1228,24 +1217,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "cxxbridge-flags" -version = "1.0.102" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78a19f4c80fd9ab6c882286fa865e92e07688f4387370a209508014ead8751d0" +checksum = "d7030aff1908ba2b7eb639466df50792b2a3fdf02bea9557c4ee1a531975554b" [[package]] name = "cxxbridge-macro" -version = "1.0.102" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcfa71f66c8563c4fa9dd2bb68368d50267856f831ac5d85367e0805f9606c" +checksum = "79418ecb0c2322a7926a5fa5a9660535432b5b3588b947e1eb484cc509edbe3c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -1269,7 +1258,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -1280,22 +1269,28 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "dashmap" -version = "5.5.0" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.0", + "hashbrown 0.14.1", "lock_api", "once_cell", "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" + [[package]] name = "debugid" version = "0.8.0" @@ -1316,9 +1311,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" [[package]] name = "derive_more" @@ -1333,12 +1328,13 @@ dependencies = [ [[package]] name = "dialoguer" -version = "0.10.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" dependencies = [ "console", "shell-words", + "thiserror", ] [[package]] @@ -1398,7 +1394,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -1421,9 +1417,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "dyn-clone" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" +checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" [[package]] name = "ecdsa" @@ -1490,26 +1486,13 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] -[[package]] -name = "env_logger" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -1518,34 +1501,23 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erased-serde" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da96524cc884f6558f1769b6c46686af2fe8e8b4cd253bd5a3cdba8181b8e070" +checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" dependencies = [ "serde", ] [[package]] name = "errno" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ - "errno-dragonfly", "libc", "windows-sys 0.48.0", ] -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "expect-test" version = "1.4.1" @@ -1590,15 +1562,24 @@ dependencies = [ [[package]] name = "fallible-iterator" -version = "0.2.0" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "faster-hex" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +checksum = "239f7bfb930f820ab16a9cd95afc26f88264cf6905c960b340a615384aa3338a" +dependencies = [ + "serde", +] [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "ff" @@ -1610,25 +1591,15 @@ dependencies = [ "subtle", ] -[[package]] -name = "file-per-thread-logger" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3cc21c33af89af0930c8cae4ade5e6fdc17b5d2c97b3d2e2edb67a1cf683f3" -dependencies = [ - "env_logger", - "log", -] - [[package]] name = "filetime" -version = "0.2.21" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "windows-sys 0.48.0", ] @@ -1654,9 +1625,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", "miniz_oxide", @@ -1754,7 +1725,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -1802,7 +1773,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "debugid", "fxhash", "serde", @@ -1886,47 +1857,43 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" dependencies = [ "fallible-iterator", - "indexmap 1.9.3", + "indexmap 2.0.2", "stable_deref_trait", ] [[package]] name = "gix" -version = "0.48.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e74cea676de7f53a79f3c0365812b11f6814b81e671b8ee4abae6ca09c7881" +checksum = "06a8c9f9452078f474fecd2880de84819b8c77224ab62273275b646bf785f906" dependencies = [ "gix-actor", - "gix-attributes", "gix-commitgraph", "gix-config", - "gix-credentials", "gix-date", "gix-diff", "gix-discover", - "gix-features 0.31.1", - "gix-fs 0.3.0", + "gix-features", + "gix-fs", "gix-glob", "gix-hash", "gix-hashtable", - "gix-ignore", "gix-index", "gix-lock", - "gix-mailmap", - "gix-negotiate", + "gix-macros", "gix-object", "gix-odb", "gix-pack", "gix-path", - "gix-prompt", "gix-ref", "gix-refspec", "gix-revision", + "gix-revwalk", "gix-sec", "gix-tempfile", "gix-trace", @@ -1934,9 +1901,8 @@ dependencies = [ "gix-url", "gix-utils", "gix-validate", - "gix-worktree", - "log", "once_cell", + "parking_lot", "signal-hook", "smallvec", "thiserror", @@ -1945,40 +1911,23 @@ dependencies = [ [[package]] name = "gix-actor" -version = "0.23.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1969b77b9ee4cc1755c841987ec6f7622aaca95e952bcafb76973ae59d1b8716" +checksum = "8e8c6778cc03bca978b2575a03e04e5ba6f430a9dd9b0f1259f0a8a9a5e5cc66" dependencies = [ "bstr", "btoi", "gix-date", "itoa", - "nom", - "thiserror", -] - -[[package]] -name = "gix-attributes" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3772b0129dcd1fc73e985bbd08a1482d082097d2915cb1ee31ce8092b8e4434" -dependencies = [ - "bstr", - "gix-glob", - "gix-path", - "gix-quote", - "kstring", - "log", - "smallvec", "thiserror", - "unicode-bom", + "winnow", ] [[package]] name = "gix-bitmap" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa8bbde7551a9e3e783a2871f53bbb0f50aac7a77db5680c8709f69e8ce724f" +checksum = "0ccab4bc576844ddb51b78d81b4a42d73e6229660fa614dfc3d3999c874d1959" dependencies = [ "thiserror", ] @@ -1992,24 +1941,15 @@ dependencies = [ "thiserror", ] -[[package]] -name = "gix-command" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2783ad148fb16bf9cfd46423706ba552a62a4d4a18fda5dd07648eb0228862dd" -dependencies = [ - "bstr", -] - [[package]] name = "gix-commitgraph" -version = "0.17.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed42baa50075d41c1a0931074ce1a97c5797c7c6fe7591d9f1f2dcd448532c26" +checksum = "4676ede3a7d37e7028e2889830349a6aca22efc1d2f2dd9fa3351c1a8ddb0c6a" dependencies = [ "bstr", "gix-chunk", - "gix-features 0.31.1", + "gix-features", "gix-hash", "memmap2", "thiserror", @@ -2017,84 +1957,66 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.25.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "817688c7005a716d9363e267913526adea402dabd947f4ba63842d10cc5132af" +checksum = "1108c4ac88248dd25cc8ab0d0dae796e619fb72d92f88e30e00b29d61bb93cc4" dependencies = [ "bstr", "gix-config-value", - "gix-features 0.31.1", + "gix-features", "gix-glob", "gix-path", "gix-ref", "gix-sec", - "log", "memchr", - "nom", "once_cell", "smallvec", "thiserror", "unicode-bom", + "winnow", ] [[package]] name = "gix-config-value" -version = "0.12.5" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e874f41437441c02991dcea76990b9058fadfc54b02ab4dd06ab2218af43897" +checksum = "ea7505b97f4d8e7933e29735a568ba2f86d8de466669d9f0e8321384f9972f47" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "bstr", "gix-path", "libc", "thiserror", ] -[[package]] -name = "gix-credentials" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a75565e0e6e7f80cfa4eb1b05cc448c6846ddd48dcf413a28875fbc11ee9af" -dependencies = [ - "bstr", - "gix-command", - "gix-config-value", - "gix-path", - "gix-prompt", - "gix-sec", - "gix-url", - "thiserror", -] - [[package]] name = "gix-date" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b0312dba1ad003d9b8c502bed52fbcf106f8de3a9a26bfa7b45642a6f94b72" +checksum = "fc7df669639582dc7c02737642f76890b03b5544e141caba68a7d6b4eb551e0d" dependencies = [ "bstr", "itoa", "thiserror", - "time 0.3.24", + "time 0.3.29", ] [[package]] name = "gix-diff" -version = "0.32.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf5d9b9b521b284ebe53ee69eee33341835ec70edc314f36b2100ea81396121" +checksum = "b45e342d148373bd9070d557e6fb1280aeae29a3e05e32506682d027278501eb" dependencies = [ "gix-hash", "gix-object", - "imara-diff", "thiserror", ] [[package]] name = "gix-discover" -version = "0.21.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "272aad20dc63dedba76615373dd8885fb5aebe4795e5b5b0aa2a24e63c82085c" +checksum = "da4cacda5ee9dd1b38b0e2506834e40e66c08cf050ef55c344334c76745f277b" dependencies = [ "bstr", "dunce", @@ -2107,9 +2029,9 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.31.1" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06142d8cff5d17509399b04052b64d2f9b3a311d5cff0b1a32b220f62cd0d595" +checksum = "f414c99e1a7abc69b21f3225a6539d203b0513f1d1d448607c4ea81cdcf9ee59" dependencies = [ "crc32fast", "flate2", @@ -2123,92 +2045,61 @@ dependencies = [ "walkdir", ] -[[package]] -name = "gix-features" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882695cccf38da4c3cc7ee687bdb412cf25e37932d7f8f2c306112ea712449f1" -dependencies = [ - "gix-hash", - "gix-trace", - "libc", -] - [[package]] name = "gix-fs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb15956bc0256594c62a2399fcf6958a02a11724217eddfdc2b49b21b6292496" -dependencies = [ - "gix-features 0.31.1", -] - -[[package]] -name = "gix-fs" -version = "0.4.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5b6e9d34a2c61ea4a02bbca94c409ab6dbbca1348cbb67298cd7fed8758761" +checksum = "404795da3d4c660c9ab6c3b2ad76d459636d1e1e4b37b0c7ff68eee898c298d4" dependencies = [ - "gix-features 0.32.1", + "gix-features", ] [[package]] name = "gix-glob" -version = "0.9.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c18bdff83143d61e7d60da6183b87542a870d026b2a2d0b30170b8e9c0cd321a" +checksum = "e3ac79c444193b0660fe0c0925d338bd338bd643e32138784dccfb12c628b892" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "bstr", - "gix-features 0.31.1", + "gix-features", "gix-path", ] [[package]] name = "gix-hash" -version = "0.11.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b422ff2ad9a0628baaad6da468cf05385bf3f5ab495ad5a33cce99b9f41092f" +checksum = "2ccf425543779cddaa4a7c62aba3fa9d90ea135b160be0a72dd93c063121ad4a" dependencies = [ - "hex", + "faster-hex", "thiserror", ] [[package]] name = "gix-hashtable" -version = "0.2.4" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385f4ce6ecf3692d313ca3aa9bd3b3d8490de53368d6d94bedff3af8b6d9c58d" +checksum = "409268480841ad008e81c17ca5a293393fbf9f2b6c2f85b8ab9de1f0c5176a16" dependencies = [ "gix-hash", - "hashbrown 0.14.0", + "hashbrown 0.14.1", "parking_lot", ] -[[package]] -name = "gix-ignore" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca801f2d0535210f77b33e2c067d565aedecacc82f1b3dbce26da1388ebc4634" -dependencies = [ - "bstr", - "gix-glob", - "gix-path", - "unicode-bom", -] - [[package]] name = "gix-index" -version = "0.20.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68099abdf6ee50ae3c897e8b05de96871cbe54d52a37cdf559101f911b883562" +checksum = "0e9599fc30b3d6aad231687a403f85dfa36ae37ccf1b68ee1f621ad5b7fc7a0d" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "bstr", "btoi", "filetime", "gix-bitmap", - "gix-features 0.31.1", + "gix-features", + "gix-fs", "gix-hash", "gix-lock", "gix-object", @@ -2221,9 +2112,9 @@ dependencies = [ [[package]] name = "gix-lock" -version = "7.0.2" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e82ec23c8a281f91044bf3ed126063b91b59f9c9340bf0ae746f385cc85a6fa" +checksum = "1568c3d90594c60d52670f325f5db88c2d572e85c8dd45fabc23d91cadb0fd52" dependencies = [ "gix-tempfile", "gix-utils", @@ -2231,62 +2122,44 @@ dependencies = [ ] [[package]] -name = "gix-mailmap" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1787e3c37fc43b1f7c0e3be6196c6837b3ba5f869190dfeaa444b816f0a7f34b" -dependencies = [ - "bstr", - "gix-actor", - "gix-date", - "thiserror", -] - -[[package]] -name = "gix-negotiate" -version = "0.4.0" +name = "gix-macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7bce64d4452dd609f44d04b14b29da2e0ad2c45fcdf4ce1472a5f5f8ec21c2" +checksum = "9d8acb5ee668d55f0f2d19a320a3f9ef67a6999ad483e11135abcc2464ed18b6" dependencies = [ - "bitflags 2.3.3", - "gix-commitgraph", - "gix-date", - "gix-hash", - "gix-object", - "gix-revwalk", - "smallvec", - "thiserror", + "proc-macro2", + "quote", + "syn 2.0.38", ] [[package]] name = "gix-object" -version = "0.32.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953f3d7ffad16734aa3ab1d05807972c80e339d1bd9dde03e0198716b99e2a6" +checksum = "3e5528d5b2c984044d547e696e44a8c45fa122e83cd8c2ac1da69bd474336be8" dependencies = [ "bstr", "btoi", "gix-actor", "gix-date", - "gix-features 0.31.1", + "gix-features", "gix-hash", "gix-validate", - "hex", "itoa", - "nom", "smallvec", "thiserror", + "winnow", ] [[package]] name = "gix-odb" -version = "0.49.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6418cff00ecc2713b58c8e04bff30dda808fbba1a080e7248b299d069894a01" +checksum = "d0446eca295459deb3d6dd6ed7d44a631479f1b7381d8087166605c7a9f717c6" dependencies = [ "arc-swap", "gix-date", - "gix-features 0.31.1", + "gix-features", "gix-hash", "gix-object", "gix-pack", @@ -2299,20 +2172,18 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.39.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414935138d90043ea5898de7a93f02c2558e52652492719470e203ef26a8fd0a" +checksum = "be19ee650300d7cbac5829b637685ec44a8d921a7c2eaff8a245d8f2f008870c" dependencies = [ "clru", "gix-chunk", - "gix-diff", - "gix-features 0.31.1", + "gix-features", "gix-hash", "gix-hashtable", "gix-object", "gix-path", "gix-tempfile", - "gix-traverse", "memmap2", "parking_lot", "smallvec", @@ -2321,9 +2192,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.8.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18609c8cbec8508ea97c64938c33cd305b75dfc04a78d0c3b78b8b3fd618a77c" +checksum = "6a1d370115171e3ae03c5c6d4f7d096f2981a40ddccb98dfd704c773530ba73b" dependencies = [ "bstr", "gix-trace", @@ -2332,24 +2203,11 @@ dependencies = [ "thiserror", ] -[[package]] -name = "gix-prompt" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f755e8eb83ee9a06642a8fbd3009b033db2b5bd774f3aaf3de0b07f9b6ebdc5" -dependencies = [ - "gix-command", - "gix-config-value", - "parking_lot", - "rustix 0.38.4", - "thiserror", -] - [[package]] name = "gix-quote" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfd80d3d0c733508df9449b1d3795da36083807e31d851d7d61d29af13bd4b0a" +checksum = "475c86a97dd0127ba4465fbb239abac9ea10e68301470c9791a6dd5351cdc905" dependencies = [ "bstr", "btoi", @@ -2358,14 +2216,14 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.32.1" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39453f4e5f23cddc2e6e4cca2ba20adfdbec29379e3ca829714dfe98ae068ccd" +checksum = "3cccbfa8d5cd9b86465f27a521e0c017de54b92d9fd37c143e49c658a2f04f3a" dependencies = [ "gix-actor", "gix-date", - "gix-features 0.31.1", - "gix-fs 0.3.0", + "gix-features", + "gix-fs", "gix-hash", "gix-lock", "gix-object", @@ -2373,15 +2231,15 @@ dependencies = [ "gix-tempfile", "gix-validate", "memmap2", - "nom", "thiserror", + "winnow", ] [[package]] name = "gix-refspec" -version = "0.13.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e76ff1f82fba295a121e31ab02f69642994e532c45c0c899aa393f4b740302" +checksum = "678ba30d95baa5462df9875628ed40655d5f5b8aba7028de86ed57f36e762c6c" dependencies = [ "bstr", "gix-hash", @@ -2393,9 +2251,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.17.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237428a7d3978e8572964e1e45d984027c2acc94df47e594baa6c4b0da7c9922" +checksum = "b3e80a5992ae446fe1745dd26523b86084e3f1b6b3e35377fe09b4f35ac8f151" dependencies = [ "bstr", "gix-date", @@ -2403,14 +2261,15 @@ dependencies = [ "gix-hashtable", "gix-object", "gix-revwalk", + "gix-trace", "thiserror", ] [[package]] name = "gix-revwalk" -version = "0.3.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028d50fcaf8326a8f79a359490d9ca9fb4e2b51ac9ac86503560d0bcc888d2eb" +checksum = "b806349bc1f668e09035800e07ac8045da4e39a8925a245d93142c4802224ec1" dependencies = [ "gix-commitgraph", "gix-date", @@ -2423,11 +2282,11 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.8.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9615cbd6b456898aeb942cd75e5810c382fbfc48dbbff2fa23ebd2d33dcbe9c7" +checksum = "92b9542ac025a8c02ed5d17b3fc031a111a384e859d0be3532ec4d58c40a0f28" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "gix-path", "libc", "windows", @@ -2435,11 +2294,11 @@ dependencies = [ [[package]] name = "gix-tempfile" -version = "7.0.2" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa28d567848cec8fdd77d36ad4f5f78ecfaba7d78f647d4f63c8ae1a2cec7243" +checksum = "2762b91ff95e27ff3ea95758c0d4efacd7435a1be3629622928b8276de0f72a8" dependencies = [ - "gix-fs 0.4.1", + "gix-fs", "libc", "once_cell", "parking_lot", @@ -2456,9 +2315,9 @@ checksum = "96b6d623a1152c3facb79067d6e2ecdae48130030cf27d6eb21109f13bd7b836" [[package]] name = "gix-traverse" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3cdfd54598db4fae57d5ae6f52958422b2d13382d2745796bfe5c8015ffa86e" +checksum = "3ec6358f8373fb018af8fc96c9d2ec6a5b66999e2377dc40b7801351fec409ed" dependencies = [ "gix-commitgraph", "gix-date", @@ -2472,12 +2331,12 @@ dependencies = [ [[package]] name = "gix-url" -version = "0.20.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beaede6dbc83f408b19adfd95bb52f1dbf01fb8862c3faf6c6243e2e67fcdfa1" +checksum = "1c79d595b99a6c7ab274f3c991735a0c0f5a816a3da460f513c48edf1c7bf2cc" dependencies = [ "bstr", - "gix-features 0.31.1", + "gix-features", "gix-path", "home", "thiserror", @@ -2495,32 +2354,11 @@ dependencies = [ [[package]] name = "gix-validate" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba9b3737b2cef3dcd014633485f0034b0f1a931ee54aeb7d8f87f177f3c89040" -dependencies = [ - "bstr", - "thiserror", -] - -[[package]] -name = "gix-worktree" -version = "0.21.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1363b9aa66b9e14412ac04e1f759827203f491729d92172535a8ce6cde02efa" +checksum = "e05cab2b03a45b866156e052aa38619f4ece4adcb2f79978bfc249bc3b21b8c5" dependencies = [ "bstr", - "filetime", - "gix-attributes", - "gix-features 0.31.1", - "gix-fs 0.3.0", - "gix-glob", - "gix-hash", - "gix-ignore", - "gix-index", - "gix-object", - "gix-path", - "io-close", "thiserror", ] @@ -2543,9 +2381,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -2583,9 +2421,12 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +dependencies = [ + "ahash", +] [[package]] name = "hdrhistogram" @@ -2602,12 +2443,11 @@ dependencies = [ [[package]] name = "headers" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.13.1", - "bitflags 1.3.2", + "base64 0.21.4", "bytes", "headers-core", "http", @@ -2642,9 +2482,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -2657,9 +2497,9 @@ dependencies = [ [[package]] name = "hex-literal" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hkdf" @@ -2720,9 +2560,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -2747,7 +2587,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -2811,16 +2651,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "imara-diff" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e98c1d0ad70fc91b8b9654b1f33db55e59579d3b3de2bffdced0fdb810570cb8" -dependencies = [ - "ahash", - "hashbrown 0.12.3", -] - [[package]] name = "impl-trait-for-tuples" version = "0.2.2" @@ -2852,17 +2682,17 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg 1.1.0", "hashbrown 0.12.3", - "serde", ] [[package]] name = "indexmap" -version = "2.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.1", + "serde", ] [[package]] @@ -2887,27 +2717,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b33c9a5c599d67d051c4dc25eb1b6b4ef715d1763c20c85c688717a1734f204e" -[[package]] -name = "io-close" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cadcf447f06744f8ce713d2d6239bb5bde2c357a452397a9ed90c625da390bc" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.2", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "iroha" version = "2.0.0-pre-rc.19" @@ -2939,7 +2748,7 @@ dependencies = [ "serde", "serde_json", "serial_test", - "supports-color 2.0.0", + "supports-color 2.1.0", "tempfile", "thiserror", "thread-local-panic-hook", @@ -2965,7 +2774,7 @@ name = "iroha_client" version = "2.0.0-pre-rc.19" dependencies = [ "attohttpc", - "base64 0.13.1", + "base64 0.21.4", "color-eyre", "criterion", "derive_more", @@ -2993,10 +2802,9 @@ dependencies = [ "test_network", "thiserror", "tokio", - "tokio-tungstenite 0.16.1", + "tokio-tungstenite", "tracing-flame", "tracing-subscriber", - "tungstenite 0.16.0", "url", ] @@ -3037,7 +2845,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "strum", + "strum 0.25.0", "thiserror", "tracing", "tracing-subscriber", @@ -3097,7 +2905,7 @@ dependencies = [ "iroha_telemetry", "iroha_version", "iroha_wasm_codec", - "itertools", + "itertools 0.11.0", "once_cell", "parity-scale-codec", "parking_lot", @@ -3145,7 +2953,7 @@ dependencies = [ name = "iroha_data_model" version = "2.0.0-pre-rc.19" dependencies = [ - "base64 0.13.1", + "base64 0.21.4", "criterion", "dashmap", "derive_more", @@ -3163,7 +2971,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "strum", + "strum 0.25.0", "thiserror", "tokio", "trybuild", @@ -3185,7 +2993,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.28", + "syn 2.0.38", "trybuild", ] @@ -3199,7 +3007,7 @@ dependencies = [ "manyhow", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", "trybuild", ] @@ -3262,7 +3070,7 @@ dependencies = [ "proc-macro2", "quote", "rustc-hash", - "syn 2.0.28", + "syn 2.0.38", "trybuild", ] @@ -3288,7 +3096,7 @@ dependencies = [ "manyhow", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -3346,7 +3154,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -3402,7 +3210,7 @@ dependencies = [ "manyhow", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -3426,7 +3234,7 @@ dependencies = [ "manyhow", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", "trybuild", ] @@ -3478,7 +3286,7 @@ version = "2.0.0-pre-rc.19" name = "iroha_swarm" version = "2.0.0-pre-rc.19" dependencies = [ - "clap 4.3.19", + "clap 4.4.6", "color-eyre", "derive_more", "expect-test", @@ -3513,7 +3321,7 @@ dependencies = [ "streaming-stats", "tokio", "tokio-stream", - "tokio-tungstenite 0.17.2", + "tokio-tungstenite", "url", "vergen", ] @@ -3577,7 +3385,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.28", + "syn 2.0.38", "trybuild", ] @@ -3596,7 +3404,7 @@ dependencies = [ name = "iroha_wasm_builder_cli" version = "2.0.0-pre-rc.19" dependencies = [ - "clap 4.3.19", + "clap 4.4.6", "color-eyre", "iroha_wasm_builder", "owo-colors", @@ -3627,8 +3435,8 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.2", - "rustix 0.38.4", + "hermit-abi 0.3.3", + "rustix", "windows-sys 0.48.0", ] @@ -3647,6 +3455,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -3655,9 +3472,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "ittapi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e0d0b7b3b53d92a7e8b80ede3400112a6b8b4c98d1f5b8b16bb787c780582c" +checksum = "25a5c0b993601cad796222ea076565c5d9f337d35592f8622c753724f06d7271" dependencies = [ "anyhow", "ittapi-sys", @@ -3666,9 +3483,9 @@ dependencies = [ [[package]] name = "ittapi-sys" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f8763c96e54e6d6a0dccc2990d8b5e33e3313aaeae6185921a3f4c1614a77c" +checksum = "cb7b5e473765060536a660eed127f758cf1a810c73e49063264959c60d1727d9" dependencies = [ "cc", ] @@ -3718,7 +3535,7 @@ dependencies = [ name = "kagami" version = "2.0.0-pre-rc.19" dependencies = [ - "clap 4.3.19", + "clap 4.4.6", "color-eyre", "derive_more", "iroha_config", @@ -3741,20 +3558,11 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "kstring" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" -dependencies = [ - "static_assertions", -] - [[package]] name = "kura_inspector" version = "2.0.0-pre-rc.19" dependencies = [ - "clap 4.3.19", + "clap 4.4.6", "iroha_core", "iroha_data_model", "iroha_version", @@ -3774,15 +3582,15 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "link-cplusplus" @@ -3795,15 +3603,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "litrs" @@ -3826,9 +3628,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "mach" @@ -3841,23 +3643,23 @@ dependencies = [ [[package]] name = "manyhow" -version = "0.5.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd36e9fda56207708aaa550916d2b3fa2eb59fc4eeb711aabdcb995e29f27d6" +checksum = "516b76546495d933baa165075b95c0a15e8f7ef75e53f56b19b7144d80fd52bd" dependencies = [ "darling_core", "manyhow-macros", "proc-macro2", "quote", "syn 1.0.109", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "manyhow-macros" -version = "0.5.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f77799897bae27ab96fc15f4a1139b0ae27bdcc9fa103032dae75112c1e781d1" +checksum = "8ba072c0eadade3160232e70893311f1f8903974488096e2eb8e48caba2f0cf1" dependencies = [ "proc-macro-utils", "proc-macro2", @@ -3875,23 +3677,23 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67827e6ea8ee8a7c4a72227ef4fc08957040acffdb5f122733b24fa12daff41b" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memfd" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.37.23", + "rustix", ] [[package]] @@ -3903,15 +3705,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg 1.1.0", -] - [[package]] name = "memoffset" version = "0.9.0" @@ -4037,9 +3830,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg 1.1.0", "libm", @@ -4051,7 +3844,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi 0.3.3", "libc", ] @@ -4066,22 +3859,13 @@ dependencies = [ [[package]] name = "object" -version = "0.30.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "crc32fast", - "hashbrown 0.13.2", - "indexmap 1.9.3", - "memchr", -] - -[[package]] -name = "object" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" -dependencies = [ + "hashbrown 0.14.1", + "indexmap 2.0.2", "memchr", ] @@ -4111,11 +3895,11 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cfg-if", "foreign-types", "libc", @@ -4132,7 +3916,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -4143,18 +3927,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "111.26.0+1.1.1u" +version = "300.1.5+3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc62c9f12b22b8f5208c23a7200a442b2e5999f8bdf80233852122b5a4f6f37" +checksum = "559068e4c12950d7dcaa1857a61725c0d38d4fc03ff8e070ab31a75d6e316491" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" dependencies = [ "cc", "libc", @@ -4186,9 +3970,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" dependencies = [ "arrayvec", "bitvec", @@ -4200,9 +3984,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4214,7 +3998,7 @@ dependencies = [ name = "parity_scale_decoder" version = "2.0.0-pre-rc.19" dependencies = [ - "clap 4.3.19", + "clap 4.4.6", "colored", "eyre", "iroha_crypto", @@ -4252,7 +4036,7 @@ dependencies = [ "redox_syscall 0.3.5", "smallvec", "thread-id", - "windows-targets 0.48.1", + "windows-targets 0.48.5", ] [[package]] @@ -4276,9 +4060,9 @@ dependencies = [ "proc-macro2", "quote", "regex", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", "structmeta", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -4289,18 +4073,18 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "path-absolutize" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43eb3595c63a214e1b37b44f44b0a84900ef7ae0b4c5efce59e123d246d7a0de" +checksum = "e4af381fe79fa195b4909485d99f73a80792331df0625188e707854f0b3383f5" dependencies = [ "path-dedot", ] [[package]] name = "path-dedot" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d55e486337acb9973cdea3ec5638c1b3bcb22e573b2b7b41969e0c744d5a15e" +checksum = "07ba0ad7e047712414213ff67533e6dd477af0a4e1d14fb52343e53d30ea9397" dependencies = [ "once_cell", ] @@ -4319,19 +4103,20 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5" +checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" dependencies = [ + "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f94bca7e7a599d89dea5dfa309e217e7906c3c007fb9c3299c40b10d6a315d3" +checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" dependencies = [ "pest", "pest_generator", @@ -4339,63 +4124,63 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d490fe7e8556575ff6911e45567ab95e71617f43781e5c05490dc8d75c965c" +checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "pest_meta" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674c66ebb4b4d9036012091b537aae5878970d6999f81a265034d85b136b341" +checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" dependencies = [ "once_cell", "pest", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 1.9.3", + "indexmap 2.0.2", ] [[package]] name = "pin-project" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -4521,18 +4306,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "prodash" -version = "25.0.1" +version = "26.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c236e70b7f9b9ea00d33c69f63ec1ae6e9ae96118923cd37bd4e9c7396f0b107" +checksum = "794b5bf8e2d19b53dcdcec3e4bba628e20f5b6062503ba89281fa7037dd7bbcf" [[package]] name = "prometheus" @@ -4550,19 +4335,19 @@ dependencies = [ [[package]] name = "proptest" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" +checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e" dependencies = [ "bit-set", - "bitflags 1.3.2", - "byteorder", + "bit-vec", + "bitflags 2.4.0", "lazy_static", "num-traits", "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift 0.3.0", - "regex-syntax 0.6.29", + "regex-syntax 0.7.5", "rusty-fork", "tempfile", "unarray", @@ -4570,9 +4355,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.9" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d" dependencies = [ "bytes", "prost-derive", @@ -4580,22 +4365,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.9" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32" dependencies = [ "anyhow", - "itertools", + "itertools 0.11.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.38", ] [[package]] name = "prost-types" -version = "0.11.9" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +checksum = "e081b29f63d83a4bc75cfc9f3fe424f9156cf92d8a4f0c9407cce9a1b67327cf" dependencies = [ "prost", ] @@ -4611,9 +4396,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.8.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" dependencies = [ "bitflags 1.3.2", "memchr", @@ -4628,9 +4413,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -4814,9 +4599,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -4824,14 +4609,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] @@ -4865,9 +4648,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b4dcbd3a2ae7fb94b5813fa0e957c6ab51bf5d0a8ee1b69e0c2d0f1e6eb8485" +checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" dependencies = [ "hashbrown 0.13.2", "log", @@ -4878,14 +4661,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "d119d7c7ca818f8a53c300863d4f87566aac09943aef5b355bb83969dae75d87" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.4", - "regex-syntax 0.7.4", + "regex-automata 0.4.1", + "regex-syntax 0.8.0", ] [[package]] @@ -4899,13 +4682,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" +checksum = "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.0", ] [[package]] @@ -4916,9 +4699,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "regex-syntax" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c3cbb081b9784b07cceb8824c8583f86db4814d172ab043f3c23f7dc600bf83d" [[package]] name = "rustc-demangle" @@ -4934,28 +4723,14 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.37.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.4" +version = "0.38.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "5a74ee2d7c2581cd139b42447d7d9389b889bdaad3a73f1ebb16f2a3237bb19c" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys", "windows-sys 0.48.0", ] @@ -4965,7 +4740,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.2", + "base64 0.21.4", ] [[package]] @@ -5073,15 +4848,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.179" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5bf42b8d227d4abf38a1ddb08602e229108a517cd4e5bb28f9c7eaafdce5c0" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] @@ -5095,32 +4870,22 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.179" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "741e124f5485c7e60c03b043f79f320bff3527f4bbf12cf3831750dc46a0ec2c" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -5141,9 +4906,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "2.3.3" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237" dependencies = [ "serde", "serde_with_macros", @@ -5151,14 +4916,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "2.3.3" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -5167,7 +4932,7 @@ version = "0.9.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.0.2", "itoa", "ryu", "serde", @@ -5176,10 +4941,11 @@ dependencies = [ [[package]] name = "serial_test" -version = "0.8.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eec42e7232e5ca56aa59d63af3c7f991fe71ee6a3ddd2d3480834cf3902b007" +checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" dependencies = [ + "dashmap", "futures", "lazy_static", "log", @@ -5189,46 +4955,20 @@ dependencies = [ [[package]] name = "serial_test_derive" -version = "0.8.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b95bb2f4f624565e8fe8140c789af7e2082c0e0561b5a82a1b678baa9703dc" +checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ - "proc-macro-error", "proc-macro2", "quote", - "rustversion", - "syn 1.0.109", -] - -[[package]] -name = "sha-1" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "syn 2.0.38", ] [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -5256,9 +4996,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -5267,14 +5007,14 @@ dependencies = [ [[package]] name = "sha256" -version = "1.2.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "386f700b0c798d92ac20a53342c240ff9d58030c3b845fbaeb92eead3a774792" +checksum = "7895c8ae88588ccead14ff438b939b0c569cd619116f14b4d13fdff7b8333386" dependencies = [ "async-trait", "bytes", "hex", - "sha2 0.10.7", + "sha2 0.10.8", "tokio", ] @@ -5305,9 +5045,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -5360,9 +5100,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg 1.1.0", ] @@ -5385,9 +5125,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" dependencies = [ "serde", ] @@ -5402,6 +5142,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "spin" version = "0.9.8" @@ -5410,9 +5160,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spinoff" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee259f96b31e7a18657d11741fe30d63f98e07de70e7a19d2b705ab9b331cdc" +checksum = "20aa2ed67fbb202e7b716ff8bfc6571dd9301617767380197d701c31124e88f6" dependencies = [ "colored", "once_cell", @@ -5470,7 +5220,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -5481,7 +5231,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -5489,8 +5239,14 @@ name = "strum" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" dependencies = [ - "strum_macros", + "strum_macros 0.25.2", ] [[package]] @@ -5506,6 +5262,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.38", +] + [[package]] name = "subtle" version = "2.4.1" @@ -5533,9 +5302,9 @@ dependencies = [ [[package]] name = "supports-color" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4950e7174bffabe99455511c39707310e7e9b440364a2fcb1cc21521be57b354" +checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" dependencies = [ "is-terminal", "is_ci", @@ -5554,9 +5323,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -5589,28 +5358,28 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.10" +version = "0.12.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2faeef5759ab89935255b1a4cd98e0baf99d1085e37d36599c625dac49ae8e" +checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "tempfile" -version = "3.7.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.38.4", + "rustix", "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" dependencies = [ "winapi-util", ] @@ -5638,15 +5407,6 @@ dependencies = [ "unique_port", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "textwrap" version = "0.16.0" @@ -5655,29 +5415,29 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "thread-id" -version = "4.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee93aa2b8331c0fec9091548843f2c90019571814057da3b783f9de09349d73" +checksum = "79474f573561cdc4871a0de34a51c92f7f5a56039113fbb5b9c9f96bdb756669" dependencies = [ "libc", "redox_syscall 0.2.16", @@ -5713,9 +5473,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.24" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b" +checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" dependencies = [ "deranged", "itoa", @@ -5728,15 +5488,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] @@ -5768,11 +5528,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" dependencies = [ - "autocfg 1.1.0", "backtrace", "bytes", "libc", @@ -5780,7 +5539,7 @@ dependencies = [ "num_cpus", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.4", "tokio-macros", "tracing", "windows-sys 0.48.0", @@ -5804,7 +5563,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] @@ -5830,47 +5589,23 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.16.1" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e80b39df6afcc12cdf752398ade96a6b9e99c903dfdc36e53ad10b9c366bca72" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", "native-tls", "tokio", "tokio-native-tls", - "tungstenite 0.16.0", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.17.3", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.18.0", + "tungstenite", ] [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" dependencies = [ "bytes", "futures-core", @@ -5897,27 +5632,26 @@ checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.0.2", "toml_datetime", "winnow", ] [[package]] name = "tonic" -version = "0.9.2" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" +checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" dependencies = [ + "async-stream", "async-trait", "axum", - "base64 0.21.2", + "base64 0.21.4", "bytes", - "futures-core", - "futures-util", "h2", "http", "http-body", @@ -5987,21 +5721,21 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] name = "tracing-bunyan-formatter" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464ce79ea7f689ca56d90a9c5563e803a4b61b2695e789205644ed8e8101e6bf" +checksum = "b5c266b9ac83dedf0e0385ad78514949e6d89491269e7065bee51d2bb8ec7373" dependencies = [ "ahash", "gethostname", "log", "serde", "serde_json", - "time 0.3.24", + "time 0.3.29", "tracing", "tracing-core", "tracing-log", @@ -6085,9 +5819,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "trybuild" -version = "1.0.82" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84e0202ea606ba5ebee8507ab2bfbe89b98551ed9b8f0be198109275cff284b" +checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1" dependencies = [ "basic-toml", "glob", @@ -6100,56 +5834,18 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.16.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad3713a14ae247f22a728a0456a545df14acf3867f905adff84be99e23b3ad1" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ - "base64 0.13.1", "byteorder", "bytes", + "data-encoding", "http", "httparse", "log", "native-tls", "rand 0.8.5", - "sha-1 0.9.8", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "tungstenite" -version = "0.17.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand 0.8.5", - "sha-1 0.10.1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand 0.8.5", "sha1", "thiserror", "url", @@ -6158,9 +5854,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" @@ -6176,9 +5872,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] @@ -6197,9 +5893,9 @@ checksum = "98e90c70c9f0d4d1ee6d0a7d04aa06cb9bbd53d8cfbdd62a0269a7c2eb640552" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -6218,9 +5914,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unicode-xid" @@ -6255,9 +5951,9 @@ checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", @@ -6345,14 +6041,14 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "8.2.4" +version = "8.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc5ad0d9d26b2c49a5ab7da76c3e79d3ee37e7821799f8223fcb8f2f391a2e7" +checksum = "85e7dc29b3c54a2ea67ef4f953d5ec0c4085035c0ae2d325be1c0d2144bd9f16" dependencies = [ "anyhow", "gix", "rustversion", - "time 0.3.24", + "time 0.3.29", ] [[package]] @@ -6372,9 +6068,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", @@ -6391,9 +6087,9 @@ dependencies = [ [[package]] name = "warp" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba431ef570df1287f7f8b07e376491ad54f84d26ac473489427231e1718e1f69" +checksum = "c1e92e22e03ff1230c03a1a8ee37d2f89cd489e2e541b7550d6afad96faed169" dependencies = [ "bytes", "futures-channel", @@ -6414,7 +6110,7 @@ dependencies = [ "serde_urlencoded", "tokio", "tokio-stream", - "tokio-tungstenite 0.18.0", + "tokio-tungstenite", "tokio-util", "tower-service", "tracing", @@ -6459,7 +6155,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -6481,7 +6177,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6494,9 +6190,18 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-encoder" -version = "0.31.1" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba64e81215916eaeb48fee292f29401d69235d62d8b8fd92a7b2844ec5ae5f7" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-encoder" +version = "0.33.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" +checksum = "34180c89672b3e4825c3a8db4b61a674f1447afd5fe2445b2d22c3d8b6ea086c" dependencies = [ "leb128", ] @@ -6509,8 +6214,8 @@ checksum = "4d005a95f934878a1fb446a816d51c3601a0120ff929005ba3bab3c749cfd1c7" dependencies = [ "anyhow", "libc", - "strum", - "strum_macros", + "strum 0.24.1", + "strum_macros 0.24.3", "tempfile", "thiserror", "wasm-opt-cxx-sys", @@ -6543,19 +6248,19 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.107.0" +version = "0.112.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" +checksum = "e986b010f47fcce49cf8ea5d5f9e5d2737832f12b53ae8ae785bbe895d0877bf" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.0.2", "semver", ] [[package]] name = "wasmtime" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b1f817f2ca5070983c71f1205fbab5848c9073df7f4e1af9fdceb4cc4a1b8e5" +checksum = "16ed7db409c1acf60d33128b2a38bee25aaf38c4bd955ab98a5b623c8294593c" dependencies = [ "anyhow", "async-trait", @@ -6563,17 +6268,19 @@ dependencies = [ "bumpalo", "cfg-if", "fxprof-processed-profile", - "indexmap 1.9.3", + "indexmap 2.0.2", "libc", "log", - "object 0.30.4", + "object", "once_cell", "paste", "psm", "rayon", "serde", + "serde_derive", "serde_json", "target-lexicon", + "wasm-encoder 0.32.0", "wasmparser", "wasmtime-cache", "wasmtime-component-macro", @@ -6588,28 +6295,28 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f82fbfda4610e9225238c62574ecded8e9d6ad3a12f387ac45819ecad5c3f9b" +checksum = "53af0f8f6271bd687fe5632c8fe0a0f061d0aa1b99a0cd4e1df8e4cbeb809d2f" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f5b87f1ed383d6c219c04467ab6ae87990d6c2815d5a990138990a7fcbab95" +checksum = "41376a7c094335ee08abe6a4eff79a32510cc805a249eff1b5e7adf0a42e7cdf" dependencies = [ "anyhow", - "base64 0.21.2", + "base64 0.21.4", "bincode", "directories-next", - "file-per-thread-logger", "log", - "rustix 0.37.23", + "rustix", "serde", - "sha2 0.10.7", + "serde_derive", + "sha2 0.10.8", "toml", "windows-sys 0.48.0", "zstd", @@ -6617,14 +6324,14 @@ dependencies = [ [[package]] name = "wasmtime-component-macro" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27b96c540c78e12b60025fcbc0ba8a55bff1b32885a5e8eae2df765a6bc97ac" +checksum = "74ab5b291f2dad56f1e6929cc61fb7cac68845766ca77c3838b5d05d82c33976" dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.38", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -6632,17 +6339,18 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0928fe66c22bf8887e2fb524b7647308b8ce836a333af8504e4f1d80b8ea849f" +checksum = "21436177bf19f6b60dc0b83ad5872e849892a4a90c3572785e1a28c0e2e1132c" [[package]] name = "wasmtime-cranelift" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659f6e58662d1131f250339acd03aa49377f9351474282699985b79ca4d4a7c" +checksum = "920e42058862d1f7a3dd3fca73cb495a20d7506e3ada4bbc0a9780cd636da7ca" dependencies = [ "anyhow", + "cfg-if", "cranelift-codegen", "cranelift-control", "cranelift-entity", @@ -6651,43 +6359,45 @@ dependencies = [ "cranelift-wasm", "gimli", "log", - "object 0.30.4", + "object", "target-lexicon", "thiserror", "wasmparser", "wasmtime-cranelift-shared", "wasmtime-environ", + "wasmtime-versioned-export-macros", ] [[package]] name = "wasmtime-cranelift-shared" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74171de083bf2ecb716c507900f825e2b858346c714fbf48f4763ea760f998a8" +checksum = "516d63bbe18219e64a9705cf3a2c865afe1fb711454ea03091dc85a1d708194d" dependencies = [ "anyhow", "cranelift-codegen", "cranelift-control", "cranelift-native", "gimli", - "object 0.30.4", + "object", "target-lexicon", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b124cbac1a3e04a744c76b3f77919343ef16dc4c818a2406dd7b689b16a54639" +checksum = "59cef239d663885f1427f8b8f4fde7be6075249c282580d94b480f11953ca194" dependencies = [ "anyhow", "cranelift-entity", "gimli", - "indexmap 1.9.3", + "indexmap 2.0.2", "log", - "object 0.30.4", + "object", "serde", + "serde_derive", "target-lexicon", "thiserror", "wasmparser", @@ -6696,24 +6406,25 @@ dependencies = [ [[package]] name = "wasmtime-fiber" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92ffb8869395c63100ffefbd71cf9489e7e9218e63a3798dcfe93fa8945f9cf" +checksum = "2ef118b557df6193cd82cfb45ab57cd12388fedfe2bb76f090b2d77c96c1b56e" dependencies = [ "cc", "cfg-if", - "rustix 0.37.23", + "rustix", "wasmtime-asm-macros", + "wasmtime-versioned-export-macros", "windows-sys 0.48.0", ] [[package]] name = "wasmtime-jit" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ff15f426c2378f32ffb6d9b4370e3504231492e93f6968e8b5102c3256bbc4" +checksum = "c8089d5909b8f923aad57702ebaacb7b662aa9e43a3f71e83e025c5379a1205f" dependencies = [ - "addr2line 0.19.0", + "addr2line", "anyhow", "bincode", "cfg-if", @@ -6721,10 +6432,11 @@ dependencies = [ "gimli", "ittapi", "log", - "object 0.30.4", + "object", "rustc-demangle", - "rustix 0.37.23", + "rustix", "serde", + "serde_derive", "target-lexicon", "wasmtime-environ", "wasmtime-jit-debug", @@ -6735,20 +6447,21 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c549e219102426aa1f90bd18e56a3195ed1e696c318abb3f501c1f4924b530ac" +checksum = "9b13924aedf6799ad66edb25500a20e3226629978b30a958c55285352bad130a" dependencies = [ - "object 0.30.4", + "object", "once_cell", - "rustix 0.37.23", + "rustix", + "wasmtime-versioned-export-macros", ] [[package]] name = "wasmtime-jit-icache-coherence" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cf02fedda287a409cff80ad40a7c6c0f0771e99b0cd5e2b79d9cb7ecdc1b2f4" +checksum = "c6ff5f3707a5e3797deeeeac6ac26b2e1dd32dbc06693c0ab52e8ac4d18ec706" dependencies = [ "cfg-if", "libc", @@ -6757,70 +6470,92 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc38c6229a5d3b8a2528eb33eb11d3e7ebf570259c7cd2f01e8668fe783ea443" +checksum = "11ab4ce04ac05342edfa7f42895f2a5d8b16ee914330869acb865cd1facf265f" dependencies = [ "anyhow", "cc", "cfg-if", - "indexmap 1.9.3", + "indexmap 2.0.2", "libc", "log", "mach", "memfd", - "memoffset 0.8.0", + "memoffset", "paste", "rand 0.8.5", - "rustix 0.37.23", + "rustix", "sptr", + "wasm-encoder 0.32.0", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-fiber", "wasmtime-jit-debug", + "wasmtime-versioned-export-macros", + "wasmtime-wmemcheck", "windows-sys 0.48.0", ] [[package]] name = "wasmtime-types" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "768f6c5e7afc3a02eff2753196741db8e5ac5faf26a1e2204d7341b30a637c6f" +checksum = "ecf61e21d5bd95e1ad7fa42b7bdabe21220682d6a6046d376edca29760849222" dependencies = [ "cranelift-entity", "serde", + "serde_derive", "thiserror", "wasmparser", ] +[[package]] +name = "wasmtime-versioned-export-macros" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe877472cbdd6d96b4ecdc112af764e3b9d58c2e4175a87828f892ab94c60643" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "wasmtime-wit-bindgen" -version = "11.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a4a005a6a2d5faa7cd953d389da8ae979cb571fe40edec7769649d8c98d874" +checksum = "62003d48822f89cc393e93643366ddbee1766779c0874353b8ba2ede4679fbf9" dependencies = [ "anyhow", "heck", + "indexmap 2.0.2", "wit-parser", ] +[[package]] +name = "wasmtime-wmemcheck" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5412bb464066d64c3398c96e6974348f90fa2a55110ad7da3f9295438cd4de84" + [[package]] name = "wast" -version = "62.0.1" +version = "66.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ae06f09dbe377b889fbd620ff8fa21e1d49d1d9d364983c0cdbf9870cb9f1f" +checksum = "0da7529bb848d58ab8bf32230fc065b363baee2bd338d5e58c589a1e7d83ad07" dependencies = [ "leb128", "memchr", "unicode-width", - "wasm-encoder", + "wasm-encoder 0.33.2", ] [[package]] name = "wat" -version = "1.0.69" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "842e15861d203fb4a96d314b0751cdeaf0f6f8b35e8d81d2953af2af5e44e637" +checksum = "4780374047c65b6b6e86019093fe80c18b66825eb684df778a4e068282a780e7" dependencies = [ "wast", ] @@ -6845,12 +6580,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "wildmatch" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee583bdc5ff1cf9db20e9db5bb3ff4c3089a8f6b8b31aff265c9aba85812db86" - [[package]] name = "winapi" version = "0.3.9" @@ -6869,9 +6598,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -6888,7 +6617,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.5", ] [[package]] @@ -6906,7 +6635,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.5", ] [[package]] @@ -6926,17 +6655,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -6947,9 +6676,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" @@ -6959,9 +6688,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" @@ -6971,9 +6700,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" @@ -6983,9 +6712,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" @@ -6995,9 +6724,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" @@ -7007,9 +6736,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" @@ -7019,31 +6748,33 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.2" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd122eb777186e60c3fdf765a58ac76e41c582f1f535fbf3314434c6b58f3f7" +checksum = "037711d82167854aff2018dfd193aa0fef5370f456732f0d5a0c59b0f1b4b907" dependencies = [ "memchr", ] [[package]] name = "wit-parser" -version = "0.8.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6daec9f093dbaea0e94043eeb92ece327bbbe70c86b1f41aca9bbfefd7f050f0" +checksum = "a39edca9abb16309def3843af73b58d47d243fe33a9ceee572446bcc57556b9a" dependencies = [ "anyhow", "id-arena", - "indexmap 1.9.3", + "indexmap 2.0.2", "log", "pulldown-cmark", "semver", + "serde", + "serde_json", "unicode-xid", "url", ] @@ -7085,7 +6816,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.38", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cc3ebecb5fb..577997a76fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,112 +58,89 @@ iroha_trigger_derive = { version = "=2.0.0-pre-rc.19", path = "smart_contract/tr test_network = { version = "=2.0.0-pre-rc.19", path = "core/test_network" } proc-macro-error = "1.0.4" -proc-macro2 = "1.0.49" +proc-macro2 = "1.0.69" syn = { package = "syn", version = "1.0.109", default-features = false } -syn2 = { package = "syn", version = "2.0.25", default-features = false } -quote = "1.0.23" -manyhow = { version = "0.5.1", features = ["darling"] } -darling = "0.20.1" +syn2 = { package = "syn", version = "2.0.38", default-features = false } +quote = "1.0.33" +manyhow = { version = "0.8.1", features = ["darling"] } +darling = "0.20.3" -futures = { version = "0.3.25", default-features = false } -async-stream = "0.3.3" -tokio = "1.23.0" -tokio-stream = "0.1.11" -tokio-tungstenite = "0.17.2" +futures = { version = "0.3.28", default-features = false } +async-stream = "0.3.5" +tokio = "1.33.0" +tokio-stream = "0.1.14" +tokio-tungstenite = "0.20.1" crossbeam = "0.8.2" crossbeam-queue = "0.3.8" parking_lot = { version = "0.12.1" } -once_cell = "1.16.0" -tempfile = "3.3.0" -path-absolutize = "3.1.0" +once_cell = "1.18.0" +tempfile = "3.8.0" +path-absolutize = "3.1.1" pathdiff = "0.2.1" -itertools = "0.10.5" -bytes = "1.4.0" +itertools = "0.11.0" +bytes = "1.5.0" -vergen = { version = "8.1.1", default-features = false } -trybuild = "1.0.73" +vergen = { version = "8.2.5", default-features = false } +trybuild = "1.0.85" impls = "1.0.3" -base64 = { version = "0.13.1", default-features = false } +base64 = { version = "0.21.4", default-features = false } hex = { version = "0.4.3", default-features = false } -fixnum = { version = "0.9.1", default-features = false } -url = "2.3.1" +fixnum = { version = "0.9.2", default-features = false } +url = "2.4.1" prometheus = { version = "0.13.3", default-features = false } -clap = "4.2.1" +clap = "4.4.6" owo-colors = "3.5.0" -supports-color = "2.0.0" +supports-color = "2.1.0" inquire = "0.6.2" -spinoff = "0.7.0" +spinoff = "0.8.0" duct = "0.13.6" -criterion = "0.3.6" -proptest = "1.0.0" +criterion = "0.5.1" +proptest = "1.3.1" expect-test = "1.4.1" eyre = "0.6.8" color-eyre = "0.6.2" -thiserror = { version = "1.0.38", default-features = false } +thiserror = { version = "1.0.49", default-features = false } displaydoc = { version = "0.2.4", default-features = false } cfg-if = "1.0.0" derive_more = { version = "0.99.17", default-features = false } -async-trait = "0.1.60" -strum = { version = "0.24.1", default-features = false } +async-trait = "0.1.73" +strum = { version = "0.25.0", default-features = false } getset = "0.1.2" -hex-literal = "0.3.4" +hex-literal = "0.4.1" ursa = "0.3.7" aead = "0.3.2" rand = "0.8.5" -warp = { version = "0.3.5", default-features = false } -wasmtime = "11.0.1" +warp = { version = "0.3.6", default-features = false } +wasmtime = "13.0.0" tracing = "0.1.37" -tracing-core = "0.1.30" -tracing-subscriber = { version = "0.3.16", default-features = false } +tracing-core = "0.1.31" +tracing-subscriber = { version = "0.3.17", default-features = false } tracing-futures = { version = "0.2.5", default-features = false } -tracing-bunyan-formatter = { version = "0.3.4", default-features = false } +tracing-bunyan-formatter = { version = "0.3.9", default-features = false } -dashmap = "5.4.0" +dashmap = "5.5.3" rustc-hash = "1.1.0" -serde = { version = "1.0.151", default-features = false } -serde_json = { version = "1.0.91", default-features = false } -serde_yaml = "0.9.21" -serde_with = { version = "2.2.0", default-features = false } -parity-scale-codec = { version = "3.2.1", default-features = false } +serde = { version = "1.0.188", default-features = false } +serde_json = { version = "1.0.107", default-features = false } +serde_yaml = "0.9.25" +serde_with = { version = "3.3.0", default-features = false } +parity-scale-codec = { version = "3.6.5", default-features = false } json5 = "0.4.1" [workspace.lints] rust.anonymous_parameters = "deny" - -# lower the priority to allow overriding later -clippy.pedantic = { level = "deny", priority = -1 } -clippy.all = { level = "deny", priority = -1 } -clippy.dbg_macro = "deny" - -# clippy.nursery = "deny" -clippy.debug_assert_with_mut_call = "deny" -clippy.derive_partial_eq_without_eq = "deny" -clippy.empty_line_after_outer_attr = "deny" -clippy.fallible_impl_from = "deny" -clippy.future_not_send = "deny" -clippy.iter_with_drain = "deny" -clippy.mutex_integer = "deny" -clippy.needless_collect = "deny" -clippy.path_buf_push_overwrite = "deny" -clippy.suboptimal_flops = "deny" -clippy.trailing_empty_array = "deny" -clippy.transmute_undefined_repr = "deny" -clippy.trivial_regex = "deny" -clippy.unused_peekable = "deny" -clippy.unused_rounding = "deny" - rust.future_incompatible = "deny" rust.missing_copy_implementations = "deny" rust.missing_docs = "deny" @@ -180,104 +157,45 @@ rust.variant_size_differences = "deny" rust.unused_tuple_struct_fields = "deny" rust.explicit_outlives_requirements = "deny" rust.non_ascii_idents = "deny" +rust.elided_lifetimes_in_paths = "allow" +rust.unknown_lints = "warn" +rust.single_use_lifetimes = "warn" +rust.unused_lifetimes = "warn" # TODO: reenable -# rust.unreachable_pub = "deny" # rust.unsafe_op_in_unsafe_fn = "deny" -# These are up to personal taste. We don't want these to be enabled ever. -clippy.string_add = "allow" -clippy.as_conversions = "allow" -clippy.else_if_without_else = "allow" -clippy.enum_glob_use = "allow" -clippy.exhaustive_enums = "allow" -clippy.exhaustive_structs = "allow" -clippy.implicit_return = "allow" -clippy.inconsistent_struct_constructor = "allow" -clippy.indexing_slicing = "allow" -clippy.arithmetic_side_effects = "allow" -clippy.let_underscore_must_use = "allow" -clippy.match_wildcard_for_single_variants = "allow" -clippy.missing_docs_in_private_items = "allow" -clippy.module_name_repetitions = "allow" -clippy.shadow_reuse = "allow" -clippy.shadow_same = "allow" +# lower the priority to allow overriding later +clippy.all = { level = "deny", priority = -1 } -# These are normally decisions, which need to be audited by a human. -clippy.unwrap_in_result = "allow" -clippy.expect_used = "allow" -clippy.unreachable = "allow" -clippy.wildcard_enum_match_arm = "allow" +# pedantic +clippy.pedantic = { level = "warn", priority = -1 } +clippy.match_wildcard_for_single_variants = "allow" +clippy.semicolon_if_nothing_returned = "allow" clippy.wildcard_imports = "allow" -# Our preferred style. -clippy.non-ascii-literal = "allow" -clippy.std_instead_of_core = "allow" - -# This lint could be useful in theory. The trade-off of making -# refactoring away from references difficult isn't worth it in all -# cases, so if it is enabled, it should be enabled locally. -clippy.pattern_type_mismatch = "allow" - -# Style guide. -clippy.mod-module-files = "allow" -clippy.separated-literal-suffix = "allow" -# Most trybuild code triggers a false-positive. - -# Not all public items should be inline. We only inline **trivial** functions. -clippy.missing_inline_in_public_items = "allow" - -# --- Re-enable candidates ----- - -# Lots of false-positives. -clippy.self-named-module-files = "allow" clippy.manual_let_else = "allow" - -# We often need to shadow the name of the method to specialise. -# As soon as trait specialisation is stable we need to remove it. -clippy.same_name_method = "allow" -clippy.pub_use = "allow" - -# Style guide candidate. Explicitly converting the return value to -# () is good for refactoring, and if there is necessary -# processing of the data returned by a function, it should -# **really** be marked as #[must_use] -clippy.semicolon_if_nothing_returned = "allow" - -# This lint has way too many false-positives, so even enabling it -# as a warning is too much. Instead prefer adding explicit -# `#[deny]` directives +clippy.enum_glob_use = "allow" +clippy.module_name_repetitions = "allow" clippy.must_use_candidate = "allow" -# Unstable and many false-positives -## https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn -clippy.missing_const_for_fn = "allow" - -# Too much affected code. Often impossible to apply suggestion on stable rust. -rust.elided_lifetimes_in_paths = "allow" - -# This lint produces a lot of false positives. Recommend local #[deny] directives -clippy.use_self = "allow" - -# We don't want to manually deny every `clippy.restriction.*` lint. -clippy.blanket-clippy-restriction-lints = "allow" - -# A lot of false-positive. -clippy.partial_pub_fields = "allow" - -# Should be enabled per trait impl rather than globally. -clippy.missing_trait_methods = "allow" - -# We allow this and deny `clippy.semicolon_inside_block`. -clippy.semicolon_outside_block = "allow" - -# It is debatable whether it's actually easier to read, -# additionally, not all patterns are covered by the inlined syntax -clippy.uninlined_format_args = "allow" +# restriction +clippy.dbg_macro = "deny" -rust.unknown_lints = "warn" -# these lints were duplicated, with `allow` taking precedence -# clippy.inconsistent_struct_constructor = "warn" -# clippy.match_wildcard_for_single_variants = "warn" -# clippy.arithmetic_side_effects = "warn" +# nursery +clippy.debug_assert_with_mut_call = "deny" +clippy.derive_partial_eq_without_eq = "deny" +clippy.empty_line_after_outer_attr = "deny" +clippy.fallible_impl_from = "deny" +clippy.future_not_send = "deny" +clippy.iter_with_drain = "deny" +clippy.mutex_integer = "deny" +clippy.needless_collect = "deny" +clippy.path_buf_push_overwrite = "deny" +clippy.suboptimal_flops = "deny" +clippy.trailing_empty_array = "deny" +clippy.transmute_undefined_repr = "deny" +clippy.trivial_regex = "deny" +clippy.unused_peekable = "deny" +clippy.unused_rounding = "deny" clippy.option_if_let_else = "warn" clippy.or_fun_call = "warn" clippy.redundant_pub_crate = "warn" @@ -285,11 +203,9 @@ clippy.string_lit_as_bytes = "warn" clippy.suspicious_operation_groupings = "warn" clippy.useless_let_if_seq = "warn" -# unstable -# rust.non_exhaustive_omitted_patterns = "warn" - -rust.single_use_lifetimes = "warn" -rust.unused_lifetimes = "warn" +#cargo +clippy.redundant_feature_names = "deny" +clippy.wildcard_dependencies = "deny" [workspace] resolver = "2" @@ -345,9 +261,5 @@ members = [ [profile.deploy] inherits = "release" -opt-level = 3 -debug = false strip = "symbols" -debug-assertions = false lto = true -incremental = false diff --git a/cli/Cargo.toml b/cli/Cargo.toml index a1b3f06cca9..56b2d7bc1c4 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -81,7 +81,7 @@ thread-local-panic-hook = { version = "0.1.0", optional = true } uuid = { version = "1.4.1", features = ["v4"] } [dev-dependencies] -serial_test = "0.8.0" +serial_test = "2.0.0" [build-dependencies] iroha_wasm_builder = { workspace = true } diff --git a/cli/derive/src/lib.rs b/cli/derive/src/lib.rs index 4def3d9b105..00438a1df47 100644 --- a/cli/derive/src/lib.rs +++ b/cli/derive/src/lib.rs @@ -1,5 +1,4 @@ //! Crate with a proc macro for torii endpoint generation -#![allow(clippy::arithmetic_side_effects)] // We should remove `clippy::restriction`. use proc_macro::TokenStream; use proc_macro2::Span; diff --git a/cli/src/event.rs b/cli/src/event.rs index 817310f1aab..9a9dcc0ff1d 100644 --- a/cli/src/event.rs +++ b/cli/src/event.rs @@ -1,11 +1,6 @@ //! Iroha is a quite dynamic system so many events can happen. //! This module contains descriptions of such an events and //! utility Iroha Special Instructions to work with them. -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] use futures::TryStreamExt; use iroha_data_model::events::prelude::*; use iroha_macro::error::ErrorTryFromEnum; diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 44efca1113f..3d86d1cfdda 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -4,11 +4,6 @@ //! //! `Iroha` is the main instance of the peer program. `Arguments` //! should be constructed externally: (see `main.rs`). -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] #[cfg(debug_assertions)] use core::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -495,7 +490,6 @@ mod tests { use super::*; - #[allow(clippy::panic, clippy::print_stdout)] #[tokio::test] #[serial] async fn iroha_should_notify_on_panic() { diff --git a/cli/src/main.rs b/cli/src/main.rs index 61f4295fd5a..e2a07e6ae74 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,5 +1,4 @@ //! Iroha peer command-line interface. -#![allow(clippy::print_stdout)] use std::env; use color_eyre::eyre::WrapErr as _; @@ -148,13 +147,11 @@ async fn main() -> Result<(), color_eyre::Report> { Ok(()) } -#[allow(clippy::print_stdout)] fn print_help(styling: &Styling) -> Result<(), std::io::Error> { use std::io::Write; let stdout = std::io::stdout(); let lock = stdout.lock(); - #[allow(clippy::arithmetic_side_effects)] // No overflow let mut buffer = std::io::BufWriter::with_capacity(1024 * REQUIRED_ENV_VARS.len(), lock); writeln!(buffer, "{}", "Iroha 2".bold().green())?; writeln!(buffer, "pass {} for this message", styling.or(&HELP_ARG))?; @@ -206,7 +203,6 @@ as follows:", Ok(()) } -#[allow(clippy::print_stdout)] fn print_version(styling: &Styling) { println!( "{} {} (git hash {}) \n {}: {}", diff --git a/cli/src/samples.rs b/cli/src/samples.rs index 1b46b2c0556..061128548ac 100644 --- a/cli/src/samples.rs +++ b/cli/src/samples.rs @@ -1,4 +1,3 @@ -#![allow(clippy::restriction)] //! This module contains the sample configurations used for testing and benchmarking throghout Iroha. use std::{collections::HashSet, path::Path, str::FromStr}; diff --git a/client/Cargo.toml b/client/Cargo.toml index 64c6d60fb16..2b108118dcd 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -31,9 +31,9 @@ iroha_logger = { workspace = true } iroha_telemetry = { workspace = true } iroha_version = { workspace = true, features = ["http"] } -attohttpc = "0.18.0" +attohttpc = "0.26.1" eyre = { workspace = true } -http = "0.2.8" +http = "0.2.9" url = { workspace = true } rand = { workspace = true } serde = { workspace = true, features = ["derive"] } @@ -44,10 +44,8 @@ displaydoc = { workspace = true } derive_more = { workspace = true } parity-scale-codec = { workspace = true, default-features = false, features = ["derive"] } tokio = { workspace = true, features = ["rt"] } -# TODO: migrate to tokio-tungstenite 0.17 (or newer) and use the workspace dependency -tokio-tungstenite = { version = "0.16.1", features = ["native-tls"] } -tungstenite = { version = "0.16", features = ["native-tls"] } -futures-util = "0.3.25" +tokio-tungstenite = { workspace = true, features = ["native-tls"] } +futures-util = "0.3.28" [dev-dependencies] iroha_wasm_builder = { workspace = true } diff --git a/client/benches/torii.rs b/client/benches/torii.rs index a59ee916570..c35d90618e4 100644 --- a/client/benches/torii.rs +++ b/client/benches/torii.rs @@ -1,4 +1,4 @@ -#![allow(missing_docs, clippy::pedantic, clippy::restriction)] +#![allow(missing_docs, clippy::pedantic)] use std::thread; @@ -22,7 +22,7 @@ fn query_requests(criterion: &mut Criterion) { let rt = Runtime::test(); let genesis = GenesisNetwork::from_configuration( - RawGenesisBlockBuilder::new() + RawGenesisBlockBuilder::default() .domain("wonderland".parse().expect("Valid")) .account( "alice".parse().expect("Valid"), @@ -86,10 +86,11 @@ fn query_requests(criterion: &mut Criterion) { let _dropable = group.throughput(Throughput::Bytes(request.encode().len() as u64)); let _dropable2 = group.bench_function("query", |b| { b.iter(|| { - match iroha_client + let iter: Result, _> = iroha_client .request(request.clone()) - .and_then(|iter| iter.collect::, _>>()) - { + .and_then(Iterator::collect); + + match iter { Ok(assets) => { assert!(!assets.is_empty()); success_count += 1; @@ -117,7 +118,7 @@ fn instruction_submits(criterion: &mut Criterion) { let mut peer = ::new().expect("Failed to create peer"); let configuration = get_config(unique_vec![peer.id.clone()], Some(get_key_pair())); let genesis = GenesisNetwork::from_configuration( - RawGenesisBlockBuilder::new() + RawGenesisBlockBuilder::default() .domain("wonderland".parse().expect("Valid")) .account( "alice".parse().expect("Valid"), diff --git a/client/benches/tps/dev.rs b/client/benches/tps/dev.rs index 4a67cac7546..716fdfe2eb3 100644 --- a/client/benches/tps/dev.rs +++ b/client/benches/tps/dev.rs @@ -2,11 +2,6 @@ //! using [criterion](https://github.com/bheisler/criterion.rs) //! for performance check during development #![allow(missing_docs)] -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] use criterion::{ black_box, criterion_group, criterion_main, @@ -18,9 +13,7 @@ use crate::utils::Config; mod utils; -#[allow(clippy::multiple_inherent_impl)] impl Config { - #[allow(clippy::expect_used)] fn bench(self, c: &mut Criterion) { let mut group = c.benchmark_group("tps"); @@ -34,7 +27,6 @@ impl Config { } } -#[allow(clippy::expect_used)] fn bench_tps_with_config(c: &mut Criterion) { let config = Config::from_path("benches/tps/config.json").expect("Failed to configure"); iroha_logger::info!(?config); diff --git a/client/benches/tps/oneshot.rs b/client/benches/tps/oneshot.rs index a7e606ba017..6fd57cf00ba 100644 --- a/client/benches/tps/oneshot.rs +++ b/client/benches/tps/oneshot.rs @@ -7,7 +7,6 @@ use std::{fs::File, io::BufWriter}; use tracing_flame::{FlameLayer, FlushGuard}; use tracing_subscriber::prelude::*; -#[allow(clippy::expect_used, clippy::print_stdout, clippy::use_debug)] fn main() { let args: Vec = std::env::args().collect(); let mut flush_guard: Option>> = None; diff --git a/client/benches/tps/utils.rs b/client/benches/tps/utils.rs index b14a9509015..34adf4fdf5e 100644 --- a/client/benches/tps/utils.rs +++ b/client/benches/tps/utils.rs @@ -1,8 +1,3 @@ -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] use std::{ fmt, fs::File, @@ -58,7 +53,6 @@ impl Config { serde_json::from_reader(reader).wrap_err("Failed to deserialize json from reader") } - #[allow(clippy::expect_used, clippy::unwrap_in_result)] pub fn measure(self) -> Result { // READY let (_rt, network, client) = ::start_test_with_runtime(self.peers, None); @@ -169,7 +163,6 @@ impl MeasurerUnit { const PREPARATION_BLOCKS_NUMBER: u32 = 3; /// Submit initial transactions for measurement - #[allow(clippy::expect_used, clippy::unwrap_in_result)] fn ready(self) -> Result { let keypair = iroha_crypto::KeyPair::generate().expect("Failed to generate KeyPair."); @@ -208,7 +201,6 @@ impl MeasurerUnit { } /// Spawn who checks if all the expected blocks are committed - #[allow(clippy::expect_used)] fn spawn_event_counter(&self) -> thread::JoinHandle> { let listener = self.client.clone(); let (init_sender, init_receiver) = mpsc::channel(); @@ -273,7 +265,6 @@ impl MeasurerUnit { }) } - #[allow(clippy::expect_used)] fn instructions(&self) -> impl Iterator { [self.mint_or_burn(), self.relay_a_rose()] .into_iter() @@ -313,7 +304,6 @@ impl MeasurerUnit { } } -#[allow(clippy::expect_used)] fn asset_id(account_name: UnitName) -> AssetId { AssetId::new( "rose#wonderland".parse().expect("Valid"), @@ -321,7 +311,6 @@ fn asset_id(account_name: UnitName) -> AssetId { ) } -#[allow(clippy::expect_used)] fn account_id(name: UnitName) -> AccountId { format!("{name}@wonderland").parse().expect("Valid") } diff --git a/client/examples/million_accounts_genesis.rs b/client/examples/million_accounts_genesis.rs index 5cba2ca88a9..d781b2dfb73 100644 --- a/client/examples/million_accounts_genesis.rs +++ b/client/examples/million_accounts_genesis.rs @@ -1,5 +1,4 @@ -#![allow(missing_docs, clippy::pedantic, clippy::restriction)] - +//! This file contains examples from the Rust tutorial. use std::{thread, time::Duration}; use iroha::samples::{construct_executor, get_config}; @@ -12,7 +11,7 @@ use test_network::{ use tokio::runtime::Runtime; fn generate_genesis(num_domains: u32) -> RawGenesisBlock { - let mut builder = RawGenesisBlockBuilder::new(); + let mut builder = RawGenesisBlockBuilder::default(); let key_pair = get_key_pair(); for i in 0_u32..num_domains { diff --git a/client/examples/tutorial.rs b/client/examples/tutorial.rs index 5d8ec417b6f..f95229602ed 100644 --- a/client/examples/tutorial.rs +++ b/client/examples/tutorial.rs @@ -1,7 +1,5 @@ //! This file contains examples from the Rust tutorial. //! -#![allow(clippy::restriction, clippy::needless_borrow)] - use std::fs::File; use eyre::{Error, WrapErr}; @@ -42,7 +40,7 @@ fn json_config_client_test(config: &Configuration) -> Result<(), Error> { use iroha_client::client::Client; // Initialise a client with a provided config - let _current_client: Client = Client::new(&config)?; + let _current_client: Client = Client::new(config)?; Ok(()) } @@ -68,7 +66,7 @@ fn domain_registration_test(config: &Configuration) -> Result<(), Error> { // #region rust_client_create // Create an Iroha client - let iroha_client: Client = Client::new(&config)?; + let iroha_client: Client = Client::new(config)?; // #endregion rust_client_create // #region domain_register_example_prepare_tx @@ -122,7 +120,7 @@ fn account_registration_test(config: &Configuration) -> Result<(), Error> { // #endregion register_account_crates // Create an Iroha client - let iroha_client: Client = Client::new(&config)?; + let iroha_client: Client = Client::new(config)?; // #region register_account_create // Create an AccountId instance by providing the account and domain name @@ -170,7 +168,7 @@ fn asset_registration_test(config: &Configuration) -> Result<(), Error> { // #endregion register_asset_crates // Create an Iroha client - let iroha_client: Client = Client::new(&config)?; + let iroha_client: Client = Client::new(config)?; // #region register_asset_create_asset // Create an asset @@ -219,7 +217,7 @@ fn asset_minting_test(config: &Configuration) -> Result<(), Error> { // #endregion mint_asset_crates // Create an Iroha client - let iroha_client: Client = Client::new(&config)?; + let iroha_client: Client = Client::new(config)?; // Define the instances of an Asset and Account // #region mint_asset_define_asset_account @@ -277,7 +275,7 @@ fn asset_burning_test(config: &Configuration) -> Result<(), Error> { // #endregion burn_asset_crates // Create an Iroha client - let iroha_client: Client = Client::new(&config)?; + let iroha_client: Client = Client::new(config)?; // #region burn_asset_define_asset_account // Define the instances of an Asset and Account diff --git a/client/src/client.rs b/client/src/client.rs index 6703547e811..ce4cbad91b9 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -1,10 +1,5 @@ //! Contains the end-point querying logic. This is where you need to //! add any custom end-point related logic. -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] use std::{ collections::HashMap, fmt::Debug, @@ -424,7 +419,8 @@ impl Client { ) -> Result { if let Some(basic_auth) = &configuration.basic_auth { let credentials = format!("{}:{}", basic_auth.web_login, basic_auth.password); - let encoded = base64::encode(credentials); + let engine = base64::engine::general_purpose::STANDARD; + let encoded = base64::engine::Engine::encode(&engine, credentials); headers.insert(String::from("Authorization"), format!("Basic {encoded}")); } @@ -1264,7 +1260,7 @@ pub mod stream_api { } = Init::::init(handler); let mut stream = req.build()?.connect()?; - stream.write_message(WebSocketMessage::Binary(first_message))?; + stream.send(WebSocketMessage::Binary(first_message))?; trace!("`SyncIterator` created successfully"); Ok(SyncIterator { @@ -1279,7 +1275,7 @@ pub mod stream_api { fn next(&mut self) -> Option { loop { - match self.stream.read_message() { + match self.stream.read() { Ok(WebSocketMessage::Binary(message)) => { return Some(self.handler.message(message)) } @@ -1297,7 +1293,7 @@ pub mod stream_api { fn drop(&mut self) { let mut close = || -> eyre::Result<()> { self.stream.close(None)?; - let msg = self.stream.read_message()?; + let msg = self.stream.read()?; if !msg.is_close() { return Err(eyre!( "Server hasn't sent `Close` message for websocket handshake" @@ -1729,7 +1725,6 @@ pub mod parameter { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] use std::str::FromStr; use iroha_config::{ diff --git a/client/src/http_default.rs b/client/src/http_default.rs index 2147c9b61ce..7229d35f768 100644 --- a/client/src/http_default.rs +++ b/client/src/http_default.rs @@ -1,9 +1,4 @@ //! Defaults for various items used in communication over http(s). -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] use std::{net::TcpStream, str::FromStr}; use attohttpc::{ @@ -11,8 +6,8 @@ use attohttpc::{ }; use eyre::{eyre, Error, Result, WrapErr}; use http::header::HeaderName; -use tungstenite::{stream::MaybeTlsStream, WebSocket}; -pub use tungstenite::{Error as WebSocketError, Message as WebSocketMessage}; +use tokio_tungstenite::tungstenite::{stream::MaybeTlsStream, WebSocket}; +pub use tokio_tungstenite::tungstenite::{Error as WebSocketError, Message as WebSocketMessage}; use url::Url; use crate::http::{Method, RequestBuilder, Response}; @@ -122,9 +117,21 @@ impl DefaultWebSocketRequestBuilder { /// Consumes itself to build request. pub fn build(self) -> Result { - self.0 - .and_then(|b| b.body(()).map_err(Into::into)) - .map(DefaultWebSocketStreamRequest) + let mut req = self.0.and_then(|b| b.body(()).map_err(Into::into))?; + + let uri = req.uri().to_string(); + let headers = req.headers_mut(); + + headers.insert("Host", uri.parse()?); + headers.insert("Connection", "Upgrade".parse()?); + headers.insert("Upgrade", "websocket".parse()?); + headers.insert("Sec-WebSocket-Version", "13".parse()?); + headers.insert( + "Sec-WebSocket-Key", + tokio_tungstenite::tungstenite::handshake::client::generate_key().parse()?, + ); + + Ok(DefaultWebSocketStreamRequest(req)) } } diff --git a/client/src/lib.rs b/client/src/lib.rs index 0011dd63202..27f2559d46f 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -15,7 +15,6 @@ pub mod samples { use iroha_crypto::KeyPair; /// Get sample client configuration. - #[allow(clippy::expect_used)] pub fn get_client_config(key_pair: &KeyPair) -> Configuration { let (public_key, private_key) = key_pair.clone().into(); ConfigurationProxy { diff --git a/client/tests/integration/add_account.rs b/client/tests/integration/add_account.rs index 5b14d2895be..32d5462c2fe 100644 --- a/client/tests/integration/add_account.rs +++ b/client/tests/integration/add_account.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::thread; use eyre::Result; diff --git a/client/tests/integration/add_domain.rs b/client/tests/integration/add_domain.rs index 98633857e57..b10eaf4265b 100644 --- a/client/tests/integration/add_domain.rs +++ b/client/tests/integration/add_domain.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::thread; use eyre::Result; diff --git a/client/tests/integration/asset.rs b/client/tests/integration/asset.rs index 775b9bcc137..8f2059447b1 100644 --- a/client/tests/integration/asset.rs +++ b/client/tests/integration/asset.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{str::FromStr as _, thread}; use eyre::Result; diff --git a/client/tests/integration/asset_propagation.rs b/client/tests/integration/asset_propagation.rs index c9efa82a0c8..50e7152a81e 100644 --- a/client/tests/integration/asset_propagation.rs +++ b/client/tests/integration/asset_propagation.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{str::FromStr as _, thread}; use eyre::Result; diff --git a/client/tests/integration/burn_public_keys.rs b/client/tests/integration/burn_public_keys.rs index 970133a088a..c69618ffa30 100644 --- a/client/tests/integration/burn_public_keys.rs +++ b/client/tests/integration/burn_public_keys.rs @@ -1,5 +1,3 @@ -#![allow(clippy::pedantic, clippy::restriction)] - use iroha_client::client::{account, transaction, Client}; use iroha_crypto::{HashOf, KeyPair, PublicKey}; use iroha_data_model::{isi::Instruction, prelude::*, transaction::TransactionPayload}; diff --git a/client/tests/integration/config.rs b/client/tests/integration/config.rs index 381f8173c3c..5424beaccfe 100644 --- a/client/tests/integration/config.rs +++ b/client/tests/integration/config.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use test_network::*; use super::{Builder, Configuration, ConfigurationProxy}; diff --git a/client/tests/integration/connected_peers.rs b/client/tests/integration/connected_peers.rs index dcde0f1c2aa..c649b2da531 100644 --- a/client/tests/integration/connected_peers.rs +++ b/client/tests/integration/connected_peers.rs @@ -1,5 +1,3 @@ -#![allow(clippy::pedantic, clippy::restriction)] - use std::thread; use eyre::{Context, Result}; @@ -28,7 +26,6 @@ fn connected_peers_with_f_1_0_1() -> Result<()> { fn connected_peers_with_f(faults: u64, start_port: Option) -> Result<()> { let n_peers = 3 * faults + 1; - #[allow(clippy::expect_used)] let (_rt, network, client) = ::start_test_with_runtime( (n_peers) .try_into() diff --git a/client/tests/integration/domain_owner.rs b/client/tests/integration/domain_owner.rs index b82b9847080..5ebdda473d6 100644 --- a/client/tests/integration/domain_owner.rs +++ b/client/tests/integration/domain_owner.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use eyre::Result; use iroha_crypto::KeyPair; use iroha_data_model::{account::SignatureCheckCondition, prelude::*}; diff --git a/client/tests/integration/events/data.rs b/client/tests/integration/events/data.rs index f5cd354731b..e4c71bb6fad 100644 --- a/client/tests/integration/events/data.rs +++ b/client/tests/integration/events/data.rs @@ -1,4 +1,3 @@ -#![allow(clippy::restriction)] use std::{fmt::Write as _, str::FromStr, sync::mpsc, thread}; use eyre::Result; diff --git a/client/tests/integration/events/notification.rs b/client/tests/integration/events/notification.rs index 29d3ef58180..89b9a53a7ea 100644 --- a/client/tests/integration/events/notification.rs +++ b/client/tests/integration/events/notification.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{str::FromStr as _, sync::mpsc, thread, time::Duration}; use eyre::{eyre, Result, WrapErr}; diff --git a/client/tests/integration/events/pipeline.rs b/client/tests/integration/events/pipeline.rs index d0759371ea4..0d41bbb9f4a 100644 --- a/client/tests/integration/events/pipeline.rs +++ b/client/tests/integration/events/pipeline.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::thread::{self, JoinHandle}; use eyre::Result; diff --git a/client/tests/integration/multiple_blocks_created.rs b/client/tests/integration/multiple_blocks_created.rs index 762a30ccaf2..7f7c4066369 100644 --- a/client/tests/integration/multiple_blocks_created.rs +++ b/client/tests/integration/multiple_blocks_created.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::thread; use eyre::Result; diff --git a/client/tests/integration/multisignature_account.rs b/client/tests/integration/multisignature_account.rs index cf0dc9608ca..dfba65c7379 100644 --- a/client/tests/integration/multisignature_account.rs +++ b/client/tests/integration/multisignature_account.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::thread; use eyre::Result; diff --git a/client/tests/integration/multisignature_transaction.rs b/client/tests/integration/multisignature_transaction.rs index b05bce7f898..abbe63bab8a 100644 --- a/client/tests/integration/multisignature_transaction.rs +++ b/client/tests/integration/multisignature_transaction.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{str::FromStr as _, thread, time::Duration}; use eyre::Result; diff --git a/client/tests/integration/non_mintable.rs b/client/tests/integration/non_mintable.rs index adec2a9dbc0..cee51a0bf86 100644 --- a/client/tests/integration/non_mintable.rs +++ b/client/tests/integration/non_mintable.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::str::FromStr as _; use eyre::Result; diff --git a/client/tests/integration/offline_peers.rs b/client/tests/integration/offline_peers.rs index ee20b58ca4e..5896aed3b20 100644 --- a/client/tests/integration/offline_peers.rs +++ b/client/tests/integration/offline_peers.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use eyre::Result; use iroha_client::client::{self, QueryResult}; use iroha_data_model::{ diff --git a/client/tests/integration/pagination.rs b/client/tests/integration/pagination.rs index 1ec4992a035..e36fadb0ef4 100644 --- a/client/tests/integration/pagination.rs +++ b/client/tests/integration/pagination.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::num::{NonZeroU32, NonZeroU64}; use eyre::Result; diff --git a/client/tests/integration/permissions.rs b/client/tests/integration/permissions.rs index d19a4b709c1..8870d6694e1 100644 --- a/client/tests/integration/permissions.rs +++ b/client/tests/integration/permissions.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{str::FromStr as _, thread, time::Duration}; use eyre::Result; diff --git a/client/tests/integration/queries/account.rs b/client/tests/integration/queries/account.rs index de3fdb023a6..8698eb77c3f 100644 --- a/client/tests/integration/queries/account.rs +++ b/client/tests/integration/queries/account.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{collections::HashSet, str::FromStr as _}; use eyre::Result; diff --git a/client/tests/integration/queries/asset.rs b/client/tests/integration/queries/asset.rs index d9875ecdc4b..e833c801972 100644 --- a/client/tests/integration/queries/asset.rs +++ b/client/tests/integration/queries/asset.rs @@ -1,4 +1,3 @@ -#![allow(clippy::restriction)] use eyre::Result; use iroha_client::client::ClientQueryError; use iroha_crypto::KeyPair; diff --git a/client/tests/integration/queries/role.rs b/client/tests/integration/queries/role.rs index 0bb221e484a..2151b809f34 100644 --- a/client/tests/integration/queries/role.rs +++ b/client/tests/integration/queries/role.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::collections::HashSet; use eyre::Result; diff --git a/client/tests/integration/query_errors.rs b/client/tests/integration/query_errors.rs index 636048cb75b..1d307b69e4a 100644 --- a/client/tests/integration/query_errors.rs +++ b/client/tests/integration/query_errors.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::str::FromStr; use iroha_client::client::{self, ClientQueryError}; diff --git a/client/tests/integration/restart_peer.rs b/client/tests/integration/restart_peer.rs index 7560dad0f72..d3de54b4aaf 100644 --- a/client/tests/integration/restart_peer.rs +++ b/client/tests/integration/restart_peer.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{str::FromStr, sync::Arc}; use eyre::Result; diff --git a/client/tests/integration/roles.rs b/client/tests/integration/roles.rs index 5466aa001c7..326487c3fb7 100644 --- a/client/tests/integration/roles.rs +++ b/client/tests/integration/roles.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::str::FromStr as _; use eyre::Result; diff --git a/client/tests/integration/set_parameter.rs b/client/tests/integration/set_parameter.rs index a395d16493f..c31563db662 100644 --- a/client/tests/integration/set_parameter.rs +++ b/client/tests/integration/set_parameter.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::str::FromStr; use eyre::Result; diff --git a/client/tests/integration/sorting.rs b/client/tests/integration/sorting.rs index ff4ae41093e..94f3fd149c5 100644 --- a/client/tests/integration/sorting.rs +++ b/client/tests/integration/sorting.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction, clippy::pedantic)] - use std::{ collections::HashSet, num::{NonZeroU32, NonZeroU64}, @@ -126,6 +124,7 @@ fn correct_pagination_assets_after_creating_new_one() { } #[test] +#[allow(clippy::too_many_lines)] fn correct_sorting_of_entities() { let (_rt, _peer, test_client) = ::new().with_port(10_640).start_with_runtime(); @@ -134,7 +133,7 @@ fn correct_sorting_of_entities() { // Test sorting asset definitions let mut asset_definitions = vec![]; - let mut assets_metadata = vec![]; + let mut metadata_of_assets = vec![]; let mut instructions = vec![]; let n = 10u128; for i in 0..n { @@ -151,7 +150,7 @@ fn correct_sorting_of_entities() { let asset_definition = AssetDefinition::quantity(asset_definition_id.clone()) .with_metadata(asset_metadata.clone()); - assets_metadata.push(asset_metadata); + metadata_of_assets.push(asset_metadata); asset_definitions.push(asset_definition_id); let create_asset_definition = RegisterExpr::new(asset_definition); @@ -180,13 +179,13 @@ fn correct_sorting_of_entities() { .eq(asset_definitions.iter().rev())); assert!(res .iter() - .map(|asset_definition| asset_definition.metadata()) - .eq(assets_metadata.iter().rev())); + .map(AssetDefinition::metadata) + .eq(metadata_of_assets.iter().rev())); // Test sorting accounts let mut accounts = vec![]; - let mut accounts_metadata = vec![]; + let mut metadata_of_accounts = vec![]; let mut instructions = vec![]; let n = 10u32; @@ -203,7 +202,7 @@ fn correct_sorting_of_entities() { let account = Account::new(account_id.clone(), []).with_metadata(account_metadata.clone()); accounts.push(account_id); - accounts_metadata.push(account_metadata); + metadata_of_accounts.push(account_metadata); let create_account = RegisterExpr::new(account); instructions.push(create_account); @@ -228,13 +227,13 @@ fn correct_sorting_of_entities() { assert!(res.iter().map(Identifiable::id).eq(accounts.iter().rev())); assert!(res .iter() - .map(|account| account.metadata()) - .eq(accounts_metadata.iter().rev())); + .map(Account::metadata) + .eq(metadata_of_accounts.iter().rev())); // Test sorting domains let mut domains = vec![]; - let mut domains_metadata = vec![]; + let mut metadata_of_domains = vec![]; let mut instructions = vec![]; let n = 10u32; for i in 0..n { @@ -250,7 +249,7 @@ fn correct_sorting_of_entities() { let domain = Domain::new(domain_id.clone()).with_metadata(domain_metadata.clone()); domains.push(domain_id); - domains_metadata.push(domain_metadata); + metadata_of_domains.push(domain_metadata); let create_account = RegisterExpr::new(domain); instructions.push(create_account); @@ -276,13 +275,13 @@ fn correct_sorting_of_entities() { assert!(res.iter().map(Identifiable::id).eq(domains.iter().rev())); assert!(res .iter() - .map(|domain| domain.metadata()) - .eq(domains_metadata.iter().rev())); + .map(Domain::metadata) + .eq(metadata_of_domains.iter().rev())); // Naive test sorting of domains let input = [(0i32, 1u128), (2, 0), (1, 2)]; let mut domains = vec![]; - let mut domains_metadata = vec![]; + let mut metadata_of_domains = vec![]; let mut instructions = vec![]; for (idx, val) in input { let domain_id = DomainId::from_str(&format!("neverland_{idx}")).expect("Valid"); @@ -297,7 +296,7 @@ fn correct_sorting_of_entities() { let domain = Domain::new(domain_id.clone()).with_metadata(domain_metadata.clone()); domains.push(domain_id); - domains_metadata.push(domain_metadata); + metadata_of_domains.push(domain_metadata); let create_account = RegisterExpr::new(domain); instructions.push(create_account); @@ -323,9 +322,9 @@ fn correct_sorting_of_entities() { assert_eq!(res[0].id(), &domains[1]); assert_eq!(res[1].id(), &domains[0]); assert_eq!(res[2].id(), &domains[2]); - assert_eq!(res[0].metadata(), &domains_metadata[1]); - assert_eq!(res[1].metadata(), &domains_metadata[0]); - assert_eq!(res[2].metadata(), &domains_metadata[2]); + assert_eq!(res[0].metadata(), &metadata_of_domains[1]); + assert_eq!(res[1].metadata(), &metadata_of_domains[0]); + assert_eq!(res[2].metadata(), &metadata_of_domains[2]); } #[test] @@ -345,7 +344,11 @@ fn sort_only_elements_which_have_sorting_key() -> Result<()> { let n = 10u32; for i in 0..n { let account_id = AccountId::from_str(&format!("charlie{i}@wonderland")).expect("Valid"); - let account = if !skip_set.contains(&i) { + let account = if skip_set.contains(&i) { + let account = Account::new(account_id.clone(), []); + accounts_b.push(account_id); + account + } else { let mut account_metadata = Metadata::new(); account_metadata .insert_with_limits( @@ -357,10 +360,6 @@ fn sort_only_elements_which_have_sorting_key() -> Result<()> { let account = Account::new(account_id.clone(), []).with_metadata(account_metadata); accounts_a.push(account_id); account - } else { - let account = Account::new(account_id.clone(), []); - accounts_b.push(account_id); - account }; let create_account = RegisterExpr::new(account); diff --git a/client/tests/integration/transfer_asset.rs b/client/tests/integration/transfer_asset.rs index 1b3be0e6449..3eb2ae5883e 100644 --- a/client/tests/integration/transfer_asset.rs +++ b/client/tests/integration/transfer_asset.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction, clippy::pedantic)] - use iroha_client::client::{self, QueryResult}; use iroha_crypto::KeyPair; use iroha_data_model::{prelude::*, Registered}; @@ -8,19 +6,19 @@ use test_network::*; #[test] fn simulate_transfer_quantity() { - simulate_transfer(200_u32, 20_u32, AssetDefinition::quantity, 10_710) + simulate_transfer(200_u32, &20_u32, AssetDefinition::quantity, 10_710) } #[test] fn simulate_transfer_big_quantity() { - simulate_transfer(200_u128, 20_u128, AssetDefinition::big_quantity, 10_785) + simulate_transfer(200_u128, &20_u128, AssetDefinition::big_quantity, 10_785) } #[test] fn simulate_transfer_fixed() { simulate_transfer( Fixed::try_from(200_f64).expect("Valid"), - Fixed::try_from(20_f64).expect("Valid"), + &Fixed::try_from(20_f64).expect("Valid"), AssetDefinition::fixed, 10_790, ) @@ -32,7 +30,7 @@ fn simulate_transfer_fixed() { fn simulate_insufficient_funds() { simulate_transfer( Fixed::try_from(20_f64).expect("Valid"), - Fixed::try_from(200_f64).expect("Valid"), + &Fixed::try_from(200_f64).expect("Valid"), AssetDefinition::fixed, 10_800, ) @@ -45,7 +43,7 @@ fn simulate_transfer< D: FnOnce(AssetDefinitionId) -> ::With, >( starting_amount: T, - amount_to_transfer: T, + amount_to_transfer: &T, value_type: D, port_number: u16, ) where diff --git a/client/tests/integration/triggers/by_call_trigger.rs b/client/tests/integration/triggers/by_call_trigger.rs index 3ecfa20495a..e5541bec506 100644 --- a/client/tests/integration/triggers/by_call_trigger.rs +++ b/client/tests/integration/triggers/by_call_trigger.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{str::FromStr as _, sync::mpsc, thread, time::Duration}; use eyre::{eyre, Result, WrapErr}; @@ -337,7 +335,8 @@ fn trigger_in_genesis_using_base64() -> Result<()> { info!("WASM size is {} bytes", wasm.len()); - let wasm_base64 = serde_json::json!(base64::encode(&wasm)).to_string(); + let engine = base64::engine::general_purpose::STANDARD; + let wasm_base64 = serde_json::json!(base64::engine::Engine::encode(&engine, wasm)).to_string(); let account_id = AccountId::from_str("alice@wonderland")?; let trigger_id = TriggerId::from_str("genesis_trigger")?; diff --git a/client/tests/integration/triggers/data_trigger.rs b/client/tests/integration/triggers/data_trigger.rs index 3225bc94509..a95c9ff4466 100644 --- a/client/tests/integration/triggers/data_trigger.rs +++ b/client/tests/integration/triggers/data_trigger.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use eyre::Result; use iroha_client::client; use iroha_data_model::prelude::*; diff --git a/client/tests/integration/triggers/event_trigger.rs b/client/tests/integration/triggers/event_trigger.rs index 215897a8fa0..53a8aa55cd4 100644 --- a/client/tests/integration/triggers/event_trigger.rs +++ b/client/tests/integration/triggers/event_trigger.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::str::FromStr; use eyre::Result; diff --git a/client/tests/integration/triggers/time_trigger.rs b/client/tests/integration/triggers/time_trigger.rs index c8ca3e97a37..020c95eca26 100644 --- a/client/tests/integration/triggers/time_trigger.rs +++ b/client/tests/integration/triggers/time_trigger.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{str::FromStr as _, time::Duration}; use eyre::Result; diff --git a/client/tests/integration/tx_history.rs b/client/tests/integration/tx_history.rs index a01662c56b7..b3c2ea32566 100644 --- a/client/tests/integration/tx_history.rs +++ b/client/tests/integration/tx_history.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{ num::{NonZeroU32, NonZeroU64}, str::FromStr as _, diff --git a/client/tests/integration/tx_rollback.rs b/client/tests/integration/tx_rollback.rs index f24d240fd24..b7c03e2e20b 100644 --- a/client/tests/integration/tx_rollback.rs +++ b/client/tests/integration/tx_rollback.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::str::FromStr as _; use eyre::Result; diff --git a/client/tests/integration/unregister_peer.rs b/client/tests/integration/unregister_peer.rs index f0216d23d5a..70d91345ea9 100644 --- a/client/tests/integration/unregister_peer.rs +++ b/client/tests/integration/unregister_peer.rs @@ -1,4 +1,3 @@ -#![allow(clippy::restriction)] use std::thread; use eyre::Result; @@ -51,7 +50,6 @@ fn unstable_network_stable_after_add_and_after_remove_peer() -> Result<()> { Ok(()) } -#[allow(clippy::expect_used)] fn check_assets( iroha_client: &client::Client, account_id: &AccountId, @@ -95,7 +93,6 @@ fn mint( Ok(quantity) } -#[allow(clippy::expect_used)] fn init() -> Result<( tokio::runtime::Runtime, test_network::Network, diff --git a/client/tests/integration/unstable_network.rs b/client/tests/integration/unstable_network.rs index bcfa52ea249..f7f566b8aed 100644 --- a/client/tests/integration/unstable_network.rs +++ b/client/tests/integration/unstable_network.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use core::sync::atomic::Ordering; use std::thread; diff --git a/client/tests/integration/upgrade.rs b/client/tests/integration/upgrade.rs index ba33272b403..05c82710561 100644 --- a/client/tests/integration/upgrade.rs +++ b/client/tests/integration/upgrade.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{path::Path, str::FromStr as _}; use eyre::Result; diff --git a/client/tests/wasm/utils.rs b/client/tests/wasm/utils.rs index cf65d51eb20..53f3516ea68 100644 --- a/client/tests/wasm/utils.rs +++ b/client/tests/wasm/utils.rs @@ -1,9 +1,3 @@ -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] - /// Return string containing exported memory, dummy allocator, and /// host function imports which you can embed into your wasm module. /// diff --git a/client_cli/Cargo.toml b/client_cli/Cargo.toml index dd48bdddb81..29ee5b8827b 100644 --- a/client_cli/Cargo.toml +++ b/client_cli/Cargo.toml @@ -31,13 +31,13 @@ iroha_config = { workspace = true } color-eyre = { workspace = true } # TODO: migrate to clap v4 (and use the workspace dependency) -clap = { version = "3.2.23", features = ["derive"] } -dialoguer = { version = "0.10.2", default-features = false } +clap = { version = "3.2.25", features = ["derive"] } +dialoguer = { version = "0.11.0", default-features = false } json5 = { workspace = true } once_cell = { workspace = true } serde_json = { workspace = true } -erased-serde = "0.3.24" +erased-serde = "0.3.31" [build-dependencies] -vergen = { version = "8.1.1", default-features = false } +vergen = { version = "8.2.5", default-features = false } color-eyre = "0.6.2" diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index beeb3df8bea..b52cc851b3d 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -1,16 +1,4 @@ //! iroha client command line -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] -#![allow( - missing_docs, - clippy::print_stdout, - clippy::use_debug, - clippy::print_stderr -)] - use std::{ fmt, fs::{self, read as read_file}, @@ -196,7 +184,6 @@ fn main() -> Result<()> { config } else { let config_path = ConfigPath::default(&DEFAULT_CONFIG_PATH); - #[allow(clippy::expect_used)] Configuration::from_str( config_path .first_existing_path() diff --git a/config/Cargo.toml b/config/Cargo.toml index 4d0bf7dfc40..2db0d2cbf91 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -33,10 +33,7 @@ path-absolutize = { workspace = true } once_cell = { workspace = true } [dev-dependencies] -proptest = { workspace = true } +proptest = "1.3.1" [features] -default = [] tokio-console = [] -# Workaround to avoid activating `tokio-console` with `--all-features` flag, because `tokio-console` require `tokio_unstable` rustc flag -no-tokio-console = [] diff --git a/config/base/derive/src/lib.rs b/config/base/derive/src/lib.rs index 9ed2b75e900..f86d6af896b 100644 --- a/config/base/derive/src/lib.rs +++ b/config/base/derive/src/lib.rs @@ -1,7 +1,5 @@ //! Contains various configuration related macro definitions. -#![allow(clippy::arithmetic_side_effects, clippy::std_instead_of_core)] - use proc_macro::TokenStream; pub(crate) mod documented; diff --git a/config/base/derive/src/proxy.rs b/config/base/derive/src/proxy.rs index 8eb42326f1a..53128265ab1 100644 --- a/config/base/derive/src/proxy.rs +++ b/config/base/derive/src/proxy.rs @@ -68,7 +68,6 @@ pub fn impl_override(ast: &StructWithFields) -> TokenStream { .into() } -#[allow(clippy::str_to_string)] pub fn impl_load_from_env(ast: &StructWithFields) -> TokenStream { let env_fetcher_ident = quote! { env_fetcher }; let fetch_env_trait = quote! { ::iroha_config_base::proxy::FetchEnv }; @@ -195,7 +194,6 @@ fn gen_proxy_struct(mut ast: StructWithFields) -> StructWithFields { // For fields of `Configuration` that have an inner config, the corresponding // proxy field should have a `..Proxy` type there as well if field.has_inner { - #[allow(clippy::expect_used)] if let Type::Path(path) = &mut field.ty { let old_ident = &path.path.segments.last().expect("Can't be empty").ident; let new_ident = format_ident!("{}Proxy", old_ident); diff --git a/config/base/derive/src/utils.rs b/config/base/derive/src/utils.rs index 239fd0c7c5c..ba2fd8ceb5b 100644 --- a/config/base/derive/src/utils.rs +++ b/config/base/derive/src/utils.rs @@ -107,7 +107,6 @@ pub struct StructField { impl StructField { fn from_ast(field: syn::Field, env_prefix: &str) -> Self { - #[allow(clippy::expect_used)] let field_ident = field .ident .expect("Already checked for named fields at parsing"); @@ -270,14 +269,13 @@ pub fn is_option_type(ty: &Type) -> bool { pub fn remove_attr_from_struct(ast: &mut StructWithFields, attr_ident: &str) { let StructWithFields { attrs, fields, .. } = ast; for field in fields { - remove_attr(&mut field.attrs, attr_ident) + remove_attr(&mut field.attrs, attr_ident); } remove_attr(attrs, attr_ident); } /// Keep only derive attributes passed as a second argument in struct attributes and field attributes pub fn keep_derive_attr(ast: &mut StructWithFields, kept_attrs: &[&str]) { - #[allow(clippy::expect_used)] ast.attrs .iter_mut() .filter(|attr| attr.path.is_ident("derive")) @@ -299,7 +297,7 @@ pub fn keep_derive_attr(ast: &mut StructWithFields, kept_attrs: &[&str]) { .collect(); *attr = syn::parse_quote!( #[derive(#(#items),*)] - ) + ); } }); } @@ -343,7 +341,6 @@ pub fn gen_lvalue(field_ty: &Type, field_ident: &Ident) -> (TokenStream, TokenSt /// Check if [`StructWithFields`] has `#[builder(parent = ..)]` pub fn get_parent_ty(ast: &StructWithFields) -> Type { - #[allow(clippy::expect_used)] ast.attrs .iter() .find_map(|attr| Builder::::parse(attr).ok()) diff --git a/config/base/derive/src/view.rs b/config/base/derive/src/view.rs index dd80f80b2f9..fafffefa350 100644 --- a/config/base/derive/src/view.rs +++ b/config/base/derive/src/view.rs @@ -32,7 +32,6 @@ mod gen { ast } - #[allow(clippy::str_to_string, clippy::expect_used)] pub fn view_struct(mut ast: StructWithFields) -> StructWithFields { // Remove fields with #[view(ignore)] ast.fields.retain(is_view_field_ignored); diff --git a/config/base/src/runtime_upgrades.rs b/config/base/src/runtime_upgrades.rs index b2312f3f774..95b69e0e13d 100644 --- a/config/base/src/runtime_upgrades.rs +++ b/config/base/src/runtime_upgrades.rs @@ -1,6 +1,4 @@ //! Module handling runtime upgrade logic. -#![allow(clippy::std_instead_of_core, clippy::std_instead_of_alloc)] - pub use serde::{Deserialize, Serialize}; use thiserror::*; @@ -300,7 +298,7 @@ pub mod handle { /// # Errors /// If [`Singleton::set`] fails. pub fn set_handle(&self, other: impl ReloadMut + Send + Sync + 'static) { - self.1.set(other) + self.1.set(other); } } diff --git a/config/base/tests/simple.rs b/config/base/tests/simple.rs index 751add85639..9084f582e30 100644 --- a/config/base/tests/simple.rs +++ b/config/base/tests/simple.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{collections::HashMap, env::VarError, ffi::OsStr}; use iroha_config_base::{ @@ -174,17 +172,14 @@ fn test_can_load_inner_without_the_wrapping_config() { env.remove_var("CONF_OPTIONAL_INNER"); let config = ConfigurationProxy::new_with_placeholders(); let env_config = ConfigurationProxy::from_env(&env).expect("valid env"); - assert_eq!(&env_config.optional_inner, &config.optional_inner) + assert_eq!(&env_config.optional_inner, &config.optional_inner); } #[test] fn test_proxy_combine_does_not_overload_with_none() { let config = ConfigurationProxy::new_with_none(); - dbg!(&config); let env_config = ConfigurationProxy::from_env(&test_env_factory()).expect("valid env"); - dbg!(&env_config); let combine_config = env_config.clone().override_with(config); - dbg!(&combine_config); assert_eq!(&env_config.optional_data, &combine_config.optional_data); } @@ -210,5 +205,5 @@ fn configuration_proxy_from_env_returns_err_on_parsing_error() { let err = Target::from_env(&Env).expect_err("Must not be parsed"); let err = eyre::Report::new(err); - assert_eq!(format!("{err:?}"), "Failed to deserialize the field `FOO`\n\nCaused by:\n JSON5: --> 1:1\n |\n 1 | not u64 for sure\n | ^---\n |\n = expected array, boolean, null, number, object, or string\n\nLocation:\n config/base/tests/simple.rs:212:15"); + assert_eq!(format!("{err:?}"), "Failed to deserialize the field `FOO`\n\nCaused by:\n JSON5: --> 1:1\n |\n 1 | not u64 for sure\n | ^---\n |\n = expected array, boolean, null, number, object, or string\n\nLocation:\n config/base/tests/simple.rs:207:15"); } diff --git a/config/src/block_sync.rs b/config/src/block_sync.rs index 757ecb7948a..6802fcce9c9 100644 --- a/config/src/block_sync.rs +++ b/config/src/block_sync.rs @@ -1,5 +1,4 @@ //! Module for `BlockSynchronizer`-related configuration and structs. -#![allow(clippy::std_instead_of_core)] use iroha_config_base::derive::{Documented, Proxy}; use serde::{Deserialize, Serialize}; diff --git a/config/src/client.rs b/config/src/client.rs index 602bfbda465..312bb2a1737 100644 --- a/config/src/client.rs +++ b/config/src/client.rs @@ -1,5 +1,4 @@ //! Module for client-related configuration and structs -#![allow(clippy::std_instead_of_core, clippy::std_instead_of_alloc)] use core::str::FromStr; use std::num::NonZeroU64; @@ -186,7 +185,6 @@ mod tests { prop_compose! { // TODO: make tests to check generated key validity - #[allow(clippy::expect_used)] fn arb_keys_from_seed() (seed in prop::collection::vec(any::(), 33..64)) -> (PublicKey, PrivateKey) { let (public_key, private_key) = KeyPair::generate_with_configuration(KeyGenConfiguration::default().use_seed(seed)).expect("Seed was invalid").into(); @@ -195,7 +193,6 @@ mod tests { } prop_compose! { - #[allow(clippy::expect_used)] fn arb_keys_with_option() (keys in arb_keys_from_seed()) ((a, b) in (prop::option::of(Just(keys.0)), prop::option::of(Just(keys.1)))) @@ -204,7 +201,6 @@ mod tests { } } - #[allow(clippy::expect_used)] fn placeholder_account() -> AccountId { AccountId::from_str("alice@wonderland").expect("Invalid account Id ") } @@ -228,7 +224,6 @@ mod tests { proptest! { #[test] - #[allow(clippy::expect_used)] fn client_proxy_build_fails_on_none(proxy in arb_proxy()) { let cfg = proxy.build(); if cfg.is_ok() { diff --git a/config/src/genesis.rs b/config/src/genesis.rs index 087eabc7114..5831f73851b 100644 --- a/config/src/genesis.rs +++ b/config/src/genesis.rs @@ -1,6 +1,4 @@ //! Module with genesis configuration logic. -#![allow(clippy::std_instead_of_core)] - use iroha_config_base::derive::{view, Documented, Proxy}; use iroha_crypto::{PrivateKey, PublicKey}; use serde::{Deserialize, Serialize}; @@ -38,7 +36,6 @@ pub mod tests { use super::*; /// Key-pair used by default for test purposes - #[allow(clippy::expect_used)] fn placeholder_keypair() -> KeyPair { let public_key = "ed01204CFFD0EE429B1BDD36B3910EC570852B8BB63F18750341772FB46BC856C5CAAF" .parse() diff --git a/config/src/iroha.rs b/config/src/iroha.rs index 779295f6b4a..cdd07e355f5 100644 --- a/config/src/iroha.rs +++ b/config/src/iroha.rs @@ -1,6 +1,4 @@ //! This module contains [`struct@Configuration`] structure and related implementation. -#![allow(clippy::std_instead_of_core)] - use std::fmt::Debug; use iroha_config_base::derive::{view, Documented, Error as ConfigError, Proxy}; @@ -91,7 +89,6 @@ impl ConfigurationProxy { /// /// # Errors /// - If the relevant uppermost Iroha config fields were not provided. - #[allow(clippy::expect_used, clippy::unwrap_in_result)] pub fn finish(&mut self) -> Result<(), ConfigError> { if let Some(sumeragi_proxy) = &mut self.sumeragi { // First, iroha public/private key and sumeragi keypair are interchangeable, but @@ -171,8 +168,6 @@ impl ConfigurationProxy { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - use proptest::prelude::*; use super::*; @@ -181,7 +176,6 @@ mod tests { const CONFIGURATION_PATH: &str = "./iroha_test_config.json"; /// Key-pair used for proptests generation - #[allow(clippy::expect_used)] pub fn placeholder_keypair() -> KeyPair { let private_key = PrivateKey::from_hex( Algorithm::Ed25519, diff --git a/config/src/kura.rs b/config/src/kura.rs index 1ce797e8863..9eaed6f19d3 100644 --- a/config/src/kura.rs +++ b/config/src/kura.rs @@ -1,5 +1,4 @@ //! Module for kura-related configuration and structs -#![allow(clippy::std_instead_of_core)] use std::{num::NonZeroU64, path::Path}; use eyre::{eyre, Result}; @@ -28,7 +27,6 @@ pub struct Configuration { } impl Default for ConfigurationProxy { - #[allow(clippy::expect_used)] fn default() -> Self { Self { init_mode: Some(Mode::default()), @@ -75,7 +73,6 @@ pub mod tests { use super::*; prop_compose! { - #[allow(clippy::expect_used)] pub fn arb_proxy() ( init_mode in prop::option::of(Just(Mode::default())), diff --git a/config/src/logger.rs b/config/src/logger.rs index d603259468b..bee27fda3df 100644 --- a/config/src/logger.rs +++ b/config/src/logger.rs @@ -1,6 +1,5 @@ //! Module containing logic related to spawning a logger from the //! configuration, as well as run-time reloading of the log-level. -#![allow(clippy::std_instead_of_core)] use core::fmt::Debug; use derive_more::{Deref, DerefMut, From}; @@ -16,7 +15,7 @@ use tracing_subscriber::{filter::LevelFilter, reload::Handle}; const TELEMETRY_CAPACITY: u32 = 1000; const DEFAULT_COMPACT_MODE: bool = false; const DEFAULT_TERMINAL_COLORS: bool = true; -#[cfg(all(feature = "tokio-console", not(feature = "no-tokio-console")))] +#[cfg(feature = "tokio-console")] const DEFAULT_TOKIO_CONSOLE_ADDR: &str = "127.0.0.1:5555"; /// Convert [`Level`] into [`tracing::Level`] @@ -86,7 +85,7 @@ pub struct Configuration { pub log_file_path: Option, /// Enable ANSI terminal colors for formatted output. pub terminal_colors: bool, - #[cfg(all(feature = "tokio-console", not(feature = "no-tokio-console")))] + #[cfg(feature = "tokio-console")] /// Address of tokio console (only available under "tokio-console" feature) pub tokio_console_addr: String, } @@ -99,7 +98,7 @@ impl Default for ConfigurationProxy { compact_mode: Some(DEFAULT_COMPACT_MODE), log_file_path: Some(None), terminal_colors: Some(DEFAULT_TERMINAL_COLORS), - #[cfg(all(feature = "tokio-console", not(feature = "no-tokio-console")))] + #[cfg(feature = "tokio-console")] tokio_console_addr: Some(DEFAULT_TOKIO_CONSOLE_ADDR.into()), } } @@ -119,7 +118,7 @@ pub mod tests { (prop::option::of(Just(DEFAULT_COMPACT_MODE))), (prop::option::of(Just(None))), (prop::option::of(Just(DEFAULT_TERMINAL_COLORS))), - #[cfg(all(feature = "tokio-console", not(feature = "no-tokio-console")))] + #[cfg(feature = "tokio-console")] (prop::option::of(Just(DEFAULT_TOKIO_CONSOLE_ADDR.to_string()))), ); proptest::strategy::Strategy::prop_map(strat, move |strat| ConfigurationProxy { @@ -128,7 +127,7 @@ pub mod tests { compact_mode: strat.2, log_file_path: strat.3, terminal_colors: strat.4, - #[cfg(all(feature = "tokio-console", not(feature = "no-tokio-console")))] + #[cfg(feature = "tokio-console")] tokio_console_addr: strat.5, }) } diff --git a/config/src/network.rs b/config/src/network.rs index 9fe93337294..e5c5ec48e41 100644 --- a/config/src/network.rs +++ b/config/src/network.rs @@ -1,5 +1,4 @@ //! Module for network-related configuration and structs -#![allow(clippy::std_instead_of_core)] use iroha_config_base::derive::{Documented, Proxy}; use serde::{Deserialize, Serialize}; diff --git a/config/src/path.rs b/config/src/path.rs index 8128cd806d2..f6f14887c4e 100644 --- a/config/src/path.rs +++ b/config/src/path.rs @@ -66,7 +66,6 @@ impl Path { /// # Panics /// /// Panics if `path` contains an extension. - #[allow(clippy::panic)] pub fn default(path: &'static std::path::Path) -> Self { assert!( path.extension().is_none(), diff --git a/config/src/queue.rs b/config/src/queue.rs index 24cf5152631..3dde85d60d1 100644 --- a/config/src/queue.rs +++ b/config/src/queue.rs @@ -1,5 +1,4 @@ //! Module for `Queue`-related configuration and structs. -#![allow(clippy::std_instead_of_core, clippy::arithmetic_side_effects)] use iroha_config_base::derive::{Documented, Proxy}; use serde::{Deserialize, Serialize}; diff --git a/config/src/sumeragi.rs b/config/src/sumeragi.rs index 1ebcfa30972..c6929d441d6 100644 --- a/config/src/sumeragi.rs +++ b/config/src/sumeragi.rs @@ -1,5 +1,4 @@ //! `Sumeragi` configuration. Contains both block commit and Gossip-related configuration. -#![allow(clippy::std_instead_of_core, clippy::arithmetic_side_effects)] use std::{fmt::Debug, fs::File, io::BufReader, path::Path}; use eyre::{Result, WrapErr}; @@ -93,7 +92,6 @@ impl ConfigurationProxy { /// The [`peer_id`] field of [`Self`] /// has not been initialized prior to calling this method. pub fn insert_self_as_trusted_peers(&mut self) { - #[allow(clippy::expect_used)] let peer_id = self .peer_id .clone() @@ -171,10 +169,10 @@ pub mod tests { block_time_ms, trusted_peers, commit_time_limit_ms, + max_transactions_in_block, actor_channel_capacity, gossip_batch_size, gossip_period_ms, - max_transactions_in_block, #[cfg(debug_assertions)] debug_force_soft_fork } diff --git a/config/src/telemetry.rs b/config/src/telemetry.rs index 1d50a96c1b9..d347df8b050 100644 --- a/config/src/telemetry.rs +++ b/config/src/telemetry.rs @@ -1,5 +1,4 @@ //! Module for telemetry-related configuration and structs. -#![allow(clippy::std_instead_of_core)] use iroha_config_base::derive::{Documented, Proxy}; use serde::{Deserialize, Serialize}; use url::Url; diff --git a/config/src/torii.rs b/config/src/torii.rs index 764c369ddd4..28581417315 100644 --- a/config/src/torii.rs +++ b/config/src/torii.rs @@ -1,5 +1,4 @@ //! `Torii` configuration as well as the default values for the URLs used for the main endpoints: `p2p`, `telemetry`, but not `api`. -#![allow(clippy::std_instead_of_core, clippy::arithmetic_side_effects)] use std::num::NonZeroU64; use iroha_config_base::derive::{Documented, Proxy}; diff --git a/config/src/wasm.rs b/config/src/wasm.rs index 570f97efebf..0528da996ed 100644 --- a/config/src/wasm.rs +++ b/config/src/wasm.rs @@ -1,5 +1,4 @@ //! Module for wasm-related configuration and structs. -#![allow(clippy::std_instead_of_core, clippy::arithmetic_side_effects)] use iroha_config_base::derive::{Documented, Proxy}; use serde::{Deserialize, Serialize}; diff --git a/config/src/wsv.rs b/config/src/wsv.rs index b3b6fad84c0..aacc58734be 100644 --- a/config/src/wsv.rs +++ b/config/src/wsv.rs @@ -1,6 +1,4 @@ //! Module for `WorldStateView`-related configuration and structs. -#![allow(clippy::std_instead_of_core)] - use default::*; use iroha_config_base::derive::{Documented, Proxy}; use iroha_data_model::{prelude::*, transaction::TransactionLimits}; diff --git a/configs/peer/executor.wasm b/configs/peer/executor.wasm index 9d5028a64b721cf2fca2409455b8a6ce87d5f4a8..43b39134d2555d51ebc79f675f0a16db01483248 100644 GIT binary patch delta 98437 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 Bvef_p delta 98049 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 M!yC}|jz+%iKRKAm0{{R3 diff --git a/core/Cargo.toml b/core/Cargo.toml index b97c91d7d3e..1e19e019008 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -76,7 +76,7 @@ hex = { workspace = true } once_cell = { workspace = true } tempfile = { workspace = true } -byte-unit = "4.0.18" +byte-unit = "4.0.19" [[bench]] name = "validation" diff --git a/core/benches/blocks/apply_blocks.rs b/core/benches/blocks/apply_blocks.rs index 50c6ba37b5e..f57ebbcda8b 100644 --- a/core/benches/blocks/apply_blocks.rs +++ b/core/benches/blocks/apply_blocks.rs @@ -1,5 +1,3 @@ -#![allow(missing_docs, clippy::restriction)] - use eyre::Result; use iroha_core::{block::CommittedBlock, prelude::*}; use iroha_data_model::prelude::*; diff --git a/core/benches/blocks/apply_blocks_benchmark.rs b/core/benches/blocks/apply_blocks_benchmark.rs index 20079ab1527..a9f1b7e83b4 100644 --- a/core/benches/blocks/apply_blocks_benchmark.rs +++ b/core/benches/blocks/apply_blocks_benchmark.rs @@ -1,4 +1,4 @@ -#![allow(missing_docs, clippy::restriction)] +#![allow(missing_docs)] mod apply_blocks; diff --git a/core/benches/blocks/apply_blocks_oneshot.rs b/core/benches/blocks/apply_blocks_oneshot.rs index e6469db88d8..01a49614ae4 100644 --- a/core/benches/blocks/apply_blocks_oneshot.rs +++ b/core/benches/blocks/apply_blocks_oneshot.rs @@ -21,7 +21,6 @@ fn main() { .expect("Default logger config should always build") }; // Can't use logger because it's failed to initialize. - #[allow(clippy::print_stderr)] if let Err(err) = iroha_logger::init(&log_config) { eprintln!("Failed to initialize logger: {err}"); } diff --git a/core/benches/blocks/common.rs b/core/benches/blocks/common.rs index 56f769b1778..caa3f97502f 100644 --- a/core/benches/blocks/common.rs +++ b/core/benches/blocks/common.rs @@ -1,5 +1,3 @@ -#![allow(missing_docs, clippy::restriction)] - use std::str::FromStr as _; use eyre::Result; diff --git a/core/benches/blocks/validate_blocks.rs b/core/benches/blocks/validate_blocks.rs index 129d14298a1..d83f9ecfc7d 100644 --- a/core/benches/blocks/validate_blocks.rs +++ b/core/benches/blocks/validate_blocks.rs @@ -1,5 +1,3 @@ -#![allow(missing_docs, clippy::restriction)] - use eyre::Result; use iroha_core::prelude::*; use iroha_data_model::{isi::InstructionExpr, prelude::*}; diff --git a/core/benches/blocks/validate_blocks_benchmark.rs b/core/benches/blocks/validate_blocks_benchmark.rs index 96382bccb11..1417a1a426f 100644 --- a/core/benches/blocks/validate_blocks_benchmark.rs +++ b/core/benches/blocks/validate_blocks_benchmark.rs @@ -1,4 +1,4 @@ -#![allow(missing_docs, clippy::restriction)] +#![allow(missing_docs)] mod validate_blocks; diff --git a/core/benches/blocks/validate_blocks_oneshot.rs b/core/benches/blocks/validate_blocks_oneshot.rs index 631eff07f25..bcdeb20a519 100644 --- a/core/benches/blocks/validate_blocks_oneshot.rs +++ b/core/benches/blocks/validate_blocks_oneshot.rs @@ -21,7 +21,6 @@ fn main() { .expect("Default logger config should always build") }; // Can't use logger because it's failed to initialize. - #[allow(clippy::print_stderr)] if let Err(err) = iroha_logger::init(&log_config) { eprintln!("Failed to initialize logger: {err}"); } diff --git a/core/benches/kura.rs b/core/benches/kura.rs index 2f74c5ce1e4..7b60d69411f 100644 --- a/core/benches/kura.rs +++ b/core/benches/kura.rs @@ -1,4 +1,4 @@ -#![allow(missing_docs, clippy::restriction)] +#![allow(missing_docs)] use std::str::FromStr as _; diff --git a/core/benches/validation.rs b/core/benches/validation.rs index d2617396271..32c052341e3 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -1,4 +1,4 @@ -#![allow(missing_docs, clippy::restriction)] +#![allow(missing_docs)] use std::str::FromStr as _; diff --git a/core/src/block.rs b/core/src/block.rs index 177d8e90118..facbbd09093 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -4,13 +4,6 @@ //! 2. If a block is received, i.e. deserialized: //! `SignedBlock` -> `ValidBlock` -> `CommittedBlock` //! [`Block`]s are organised into a linear sequence over time (also known as the block chain). -#![allow( - clippy::module_name_repetitions, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - clippy::arithmetic_side_effects -)] - use std::error::Error as _; use iroha_config::sumeragi::default::DEFAULT_CONSENSUS_ESTIMATION_MS; @@ -134,8 +127,8 @@ mod pending { assert!(!transactions.is_empty(), "Empty block created"); Self(Pending { - transactions, commit_topology, + transactions, event_recommendations, }) } @@ -704,8 +697,6 @@ mod commit { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - use std::str::FromStr as _; use iroha_data_model::prelude::*; diff --git a/core/src/block_sync.rs b/core/src/block_sync.rs index a56e83be7e6..1f8d8fe1fcb 100644 --- a/core/src/block_sync.rs +++ b/core/src/block_sync.rs @@ -1,9 +1,4 @@ //! This module contains structures and messages for synchronization of blocks between peers. -#![allow( - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - clippy::arithmetic_side_effects -)] use std::{fmt::Debug, sync::Arc, time::Duration}; use iroha_config::block_sync::Configuration; diff --git a/core/src/gossiper.rs b/core/src/gossiper.rs index 1ee8312e8b3..7f1ea21b690 100644 --- a/core/src/gossiper.rs +++ b/core/src/gossiper.rs @@ -76,7 +76,6 @@ impl TransactionGossiper { async fn run(mut self, mut message_receiver: mpsc::Receiver) { let mut gossip_period = tokio::time::interval(self.gossip_period); - #[allow(clippy::arithmetic_side_effects)] loop { tokio::select! { _ = gossip_period.tick() => self.gossip_transactions(), diff --git a/core/src/kura.rs b/core/src/kura.rs index 309ad9cad16..671b0c958c8 100644 --- a/core/src/kura.rs +++ b/core/src/kura.rs @@ -2,7 +2,6 @@ //! logic. [`Kura`] is the main entity which should be used to store //! new [`Block`](`crate::block::SignedBlock`)s on the //! blockchain. -#![allow(clippy::std_instead_of_alloc, clippy::arithmetic_side_effects)] use std::{ fmt::Debug, fs, @@ -194,7 +193,6 @@ impl Kura { Ok(block_hashes) } - #[allow(clippy::expect_used, clippy::cognitive_complexity, clippy::panic)] #[iroha_logger::log(skip_all)] fn kura_receive_blocks_loop( kura: &Kura, @@ -278,7 +276,6 @@ impl Kura { } /// Get the hash of the block at the provided height. - #[allow(clippy::expect_used)] pub fn get_block_hash(&self, block_height: u64) -> Option> { let hash_data_guard = self.block_data.lock(); if block_height == 0 || block_height > hash_data_guard.len() as u64 { @@ -300,7 +297,6 @@ impl Kura { } /// Get a reference to block by height, loading it from disk if needed. - #[allow(clippy::expect_used)] // The below lint suggests changing the code into something that does not compile due // to the borrow checker. pub fn get_block_by_height(&self, block_height: u64) -> Option> { @@ -850,7 +846,6 @@ impl AddErrContextExt for Result { } } -#[allow(clippy::unwrap_used)] #[cfg(test)] mod tests { diff --git a/core/src/queue.rs b/core/src/queue.rs index 3d14dc0c628..6a7bce3b62e 100644 --- a/core/src/queue.rs +++ b/core/src/queue.rs @@ -1,11 +1,4 @@ //! Module with queue actor -#![allow( - clippy::module_name_repetitions, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - clippy::arithmetic_side_effects -)] - use core::time::Duration; use std::collections::HashSet; @@ -382,8 +375,6 @@ impl Queue { #[cfg(test)] mod tests { - #![allow(clippy::restriction, clippy::all, clippy::pedantic)] - use std::{str::FromStr, sync::Arc, thread, time::Duration}; use iroha_config::{base::proxy::Builder, queue::ConfigurationProxy}; @@ -427,7 +418,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let wsv = Arc::new(WorldStateView::new( world_with_test_domains([key_pair.public_key().clone()]), - kura.clone(), + kura, )); let queue = Queue::from_configuration(&Configuration { @@ -451,7 +442,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let wsv = Arc::new(WorldStateView::new( world_with_test_domains([key_pair.public_key().clone()]), - kura.clone(), + kura, )); let queue = Queue::from_configuration(&Configuration { @@ -486,7 +477,7 @@ mod tests { let wsv = { let domain_id = DomainId::from_str("wonderland").expect("Valid"); let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); - let mut domain = Domain::new(domain_id.clone()).build(&account_id); + let mut domain = Domain::new(domain_id).build(&account_id); let mut account = Account::new( account_id.clone(), key_pairs.iter().map(KeyPair::public_key).cloned(), @@ -496,7 +487,7 @@ mod tests { assert!(domain.add_account(account).is_none()); Arc::new(WorldStateView::new( World::with([domain], PeersIds::new()), - kura.clone(), + kura, )) }; @@ -517,7 +508,7 @@ mod tests { let fully_signed_tx: AcceptedTransaction = { let mut signed_tx = tx .clone() - .sign((&key_pairs[0]).clone()) + .sign(key_pairs[0].clone()) .expect("Failed to sign."); for key_pair in &key_pairs[1..] { signed_tx = signed_tx.sign(key_pair.clone()).expect("Failed to sign"); @@ -570,7 +561,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let wsv = Arc::new(WorldStateView::new( world_with_test_domains([alice_key.public_key().clone()]), - kura.clone(), + kura, )); let queue = Queue::from_configuration(&Configuration { transaction_time_to_live_ms: 100_000, @@ -596,7 +587,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new( world_with_test_domains([alice_key.public_key().clone()]), - kura.clone(), + kura, ); let tx = accepted_tx("alice@wonderland", alice_key); wsv.transactions.insert(tx.hash(), 1); @@ -624,7 +615,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new( world_with_test_domains([alice_key.public_key().clone()]), - kura.clone(), + kura, ); let tx = accepted_tx("alice@wonderland", alice_key); let queue = Queue::from_configuration(&Configuration { @@ -652,7 +643,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let wsv = Arc::new(WorldStateView::new( world_with_test_domains([alice_key.public_key().clone()]), - kura.clone(), + kura, )); let queue = Queue::from_configuration(&Configuration { transaction_time_to_live_ms: 200, @@ -700,7 +691,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let wsv = Arc::new(WorldStateView::new( world_with_test_domains([alice_key.public_key().clone()]), - kura.clone(), + kura, )); let queue = Queue::from_configuration(&Configuration { transaction_time_to_live_ms: 100_000, @@ -734,7 +725,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let wsv = Arc::new(WorldStateView::new( world_with_test_domains([alice_key.public_key().clone()]), - kura.clone(), + kura, )); let queue = Queue::from_configuration(&Configuration { transaction_time_to_live_ms: 100_000, @@ -775,7 +766,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let wsv = WorldStateView::new( world_with_test_domains([alice_key.public_key().clone()]), - kura.clone(), + kura, ); let queue = Arc::new(Queue::from_configuration(&Configuration { @@ -798,12 +789,9 @@ mod tests { while start_time.elapsed() < run_for { let tx = accepted_tx("alice@wonderland", alice_key.clone()); match queue_arc_clone.push(tx, &wsv_clone) { - Ok(()) => (), - Err(Failure { - err: Error::Full, .. - }) => (), - Err(Failure { - err: Error::MaximumTransactionsPerUser, + Ok(()) + | Err(Failure { + err: Error::Full | Error::MaximumTransactionsPerUser, .. }) => (), Err(Failure { err, .. }) => panic!("{err}"), @@ -815,7 +803,7 @@ mod tests { // Spawn a thread where we get_transactions_for_block and add them to WSV let get_txs_handle = { let queue_arc_clone = Arc::clone(&queue); - let mut wsv_clone = wsv.clone(); + let mut wsv_clone = wsv; thread::spawn(move || { while start_time.elapsed() < run_for { @@ -850,7 +838,7 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let wsv = Arc::new(WorldStateView::new( world_with_test_domains([alice_key.public_key().clone()]), - kura.clone(), + kura, )); let queue = Queue::from_configuration(&Configuration { @@ -897,7 +885,7 @@ mod tests { assert!(domain.add_account(bob_account).is_none()); World::with([domain], PeersIds::new()) }; - let mut wsv = WorldStateView::new(world, kura.clone()); + let mut wsv = WorldStateView::new(world, kura); let queue = Queue::from_configuration(&Configuration { transaction_time_to_live_ms: 100_000, @@ -929,8 +917,7 @@ mod tests { err: Error::MaximumTransactionsPerUser }), ), - "Failed to match: {:?}", - result, + "Failed to match: {result:?}", ); // First push by Bob should be fine despite previous Alice error @@ -950,14 +937,11 @@ mod tests { // After cleanup Alice and Bob pushes should work fine queue - .push( - accepted_tx("alice@wonderland", alice_key_pair.clone()), - &wsv, - ) + .push(accepted_tx("alice@wonderland", alice_key_pair), &wsv) .expect("Failed to push tx into queue"); queue - .push(accepted_tx("bob@wonderland", bob_key_pair.clone()), &wsv) + .push(accepted_tx("bob@wonderland", bob_key_pair), &wsv) .expect("Failed to push tx into queue"); } } diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index bdf3f476e10..d89433002a3 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -41,7 +41,6 @@ pub mod isi { use super::*; use crate::role::{AsRoleIdWithOwnerRef, RoleIdWithOwner, RoleIdWithOwnerRef}; - #[allow(clippy::expect_used, clippy::unwrap_in_result)] impl Execute for Register { #[metrics(+"register_asset")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index c633adad28c..46e4b334ab5 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -1,11 +1,6 @@ //! This module contains enumeration of all possible Iroha Special //! Instructions [`InstructionExpr`], generic instruction types and related //! implementations. -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] pub mod account; pub mod asset; pub mod block; @@ -473,8 +468,6 @@ pub mod prelude { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - use core::str::FromStr as _; use std::sync::Arc; diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 5b7795495f5..0efbb5d2d57 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -1,10 +1,5 @@ //! Query functionality. The common error type is also defined here, //! alongside functions for converting them into HTTP responses. -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] use eyre::Result; use iroha_data_model::{prelude::*, query::error::QueryExecutionFail as Error}; use parity_scale_codec::{Decode, Encode}; @@ -170,8 +165,6 @@ impl ValidQuery for QueryBox { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - use std::str::FromStr as _; use iroha_crypto::{Hash, HashOf, KeyPair}; diff --git a/core/src/smartcontracts/isi/triggers/mod.rs b/core/src/smartcontracts/isi/triggers/mod.rs index c0bf5e49721..f8f071d4d44 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -24,7 +24,6 @@ pub mod isi { impl Execute for Register> { #[metrics(+"register_trigger")] - #[allow(clippy::expect_used)] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let new_trigger = self.object; diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index c307455a06f..6378291240c 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -1,8 +1,6 @@ //! This module contains logic related to executing smartcontracts via //! `WebAssembly` VM Smartcontracts can be written in Rust, compiled //! to wasm format and submitted in a transaction -#![allow(clippy::doc_link_with_quotes, clippy::arithmetic_side_effects)] - use error::*; use import_traits::{ ExecuteOperations as _, GetExecutorPayloads as _, SetPermissionTokenSchema as _, @@ -678,7 +676,7 @@ impl Runtime { /// # Errors /// /// If string decoding fails - #[allow(clippy::print_stdout, clippy::needless_pass_by_value)] + #[allow(clippy::needless_pass_by_value)] #[codec::wrap(state = "S")] fn dbg(msg: String) { println!("{msg}"); @@ -836,7 +834,7 @@ impl<'wrld> Runtime> { /// /// - if instructions failed to validate, but queries are permitted /// - if instruction limits are not obeyed - /// - if execution of the smartcontract fails (check ['execute']) + /// - if execution of the smartcontract fails (check [`Self::execute`]) pub fn validate( &mut self, wsv: &'wrld mut WorldStateView, @@ -1614,8 +1612,6 @@ impl GetExport for (&wasmtime::Instance, C) { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - use std::str::FromStr as _; use iroha_crypto::KeyPair; diff --git a/core/src/snapshot.rs b/core/src/snapshot.rs index bc8b9f8b376..639408deb65 100644 --- a/core/src/snapshot.rs +++ b/core/src/snapshot.rs @@ -1,11 +1,4 @@ //! This module contains [`WorldStateView`] snapshot actor service. - -#![allow( - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - clippy::arithmetic_side_effects -)] - use std::{ io::Read, path::{Path, PathBuf}, diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index 3a0aef20b68..1de96d43c8f 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -135,7 +135,6 @@ impl Sumeragi { } } - #[allow(clippy::panic)] fn receive_network_packet( &self, view_change_proof_chain: &mut ProofChain, @@ -183,7 +182,6 @@ impl Sumeragi { }) } - #[allow(clippy::panic, clippy::panic_in_result_fn)] fn init_listen_for_genesis( &mut self, shutdown_receiver: &mut tokio::sync::oneshot::Receiver<()>, diff --git a/core/src/sumeragi/message.rs b/core/src/sumeragi/message.rs index e54e07c752b..5aa47890cdd 100644 --- a/core/src/sumeragi/message.rs +++ b/core/src/sumeragi/message.rs @@ -1,11 +1,4 @@ //! Contains message structures for p2p communication during consensus. -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - clippy::module_name_repetitions -)] - use iroha_crypto::{HashOf, SignaturesOf}; use iroha_data_model::block::{BlockPayload, SignedBlock}; use iroha_macro::*; diff --git a/core/src/sumeragi/mod.rs b/core/src/sumeragi/mod.rs index 3123025f805..6f445e59623 100644 --- a/core/src/sumeragi/mod.rs +++ b/core/src/sumeragi/mod.rs @@ -1,11 +1,6 @@ //! Translates to Emperor. Consensus-related logic of Iroha. //! //! `Consensus` trait is now implemented only by `Sumeragi` for now. -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] use std::{ fmt::{self, Debug, Formatter}, sync::{mpsc, Arc}, @@ -402,8 +397,8 @@ impl VotingBlock { voted_at: Instant, ) -> VotingBlock { VotingBlock { - block, voted_at, + block, new_wsv, } } diff --git a/core/src/sumeragi/network_topology.rs b/core/src/sumeragi/network_topology.rs index 495c72c6a47..fc06e7e95a7 100644 --- a/core/src/sumeragi/network_topology.rs +++ b/core/src/sumeragi/network_topology.rs @@ -1,11 +1,4 @@ //! Structures formalising the peer topology (e.g. which peers have which predefined roles). -#![allow( - clippy::new_without_default, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - clippy::arithmetic_side_effects -)] - use std::collections::HashSet; use derive_more::Display; diff --git a/core/src/sumeragi/view_change.rs b/core/src/sumeragi/view_change.rs index f4de4d07f18..11f24b90cfd 100644 --- a/core/src/sumeragi/view_change.rs +++ b/core/src/sumeragi/view_change.rs @@ -1,11 +1,5 @@ //! Structures related to proofs and reasons of view changes. //! Where view change is a process of changing topology due to some faulty network behavior. -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - single_use_lifetimes -)] use std::collections::HashSet; use derive_more::{Deref, DerefMut}; @@ -142,7 +136,6 @@ impl ProofChain { /// # Errors /// - If proof latest block hash doesn't match peer latest block hash /// - If proof view change number differs from view change number - #[allow(clippy::expect_used, clippy::unwrap_in_result)] pub fn insert_proof( &mut self, peers: &[PeerId], diff --git a/core/src/tx.rs b/core/src/tx.rs index 18404d6bd4e..790d8942326 100644 --- a/core/src/tx.rs +++ b/core/src/tx.rs @@ -7,14 +7,6 @@ //! //! This is also where the actual execution of instructions, as well //! as various forms of validation are performed. -// TODO: Add full lifecycle docs. -#![allow( - clippy::new_without_default, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - clippy::arithmetic_side_effects -)] - use eyre::Result; use iroha_crypto::{HashOf, SignatureVerificationFail, SignaturesOf}; pub use iroha_data_model::prelude::*; diff --git a/core/src/wsv.rs b/core/src/wsv.rs index 049947db282..02eb4057147 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -1,12 +1,5 @@ //! This module provides the [`WorldStateView`] — an in-memory representation of the current blockchain //! state. -#![allow( - clippy::new_without_default, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - clippy::arithmetic_side_effects -)] - use std::{ borrow::Borrow, collections::{BTreeSet, HashMap}, @@ -267,8 +260,8 @@ impl World { .map(|domain| (domain.id().clone(), domain)) .collect(); World { - domains, trusted_peers_ids, + domains, ..World::new() } } @@ -889,7 +882,6 @@ impl WorldStateView { /// /// # Errors /// Fails if there is no domain - #[allow(clippy::panic_in_result_fn)] pub fn map_domain<'wsv, T>( &'wsv self, id: &DomainId, @@ -1330,8 +1322,6 @@ mod range_bounds { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - use iroha_primitives::unique_vec::UniqueVec; use super::*; diff --git a/core/test_network/Cargo.toml b/core/test_network/Cargo.toml index 295e225700a..22cbae6888a 100644 --- a/core/test_network/Cargo.toml +++ b/core/test_network/Cargo.toml @@ -25,5 +25,5 @@ rand = { workspace = true } tempfile = { workspace = true } tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros"] } unique_port = "0.2.1" -parity-scale-codec = { version = "3.1.5", default-features = false } +parity-scale-codec = { version = "3.6.5", default-features = false } serde_json = { workspace = true } diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index b0e58df14d3..921716dda35 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -1,6 +1,4 @@ //! Module for starting peers and networks. Used only for tests -#![allow(clippy::restriction, clippy::future_not_send)] - use core::{fmt::Debug, str::FromStr as _, time::Duration}; #[cfg(debug_assertions)] use std::sync::atomic::AtomicBool; @@ -239,7 +237,6 @@ impl Network { offline_peers: u32, start_port: Option, ) -> Result { - #[allow(clippy::expect_used)] let mut builders = core::iter::repeat_with(PeerBuilder::new) .enumerate() .map(|(n, builder)| { diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index ab3f3a44028..3d0aba7b827 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -34,7 +34,7 @@ parity-scale-codec = { workspace = true, features = ["derive", "full"] } serde = { workspace = true, features = ["derive"] } serde_with = { workspace = true, features = ["macros"] } hex = { workspace = true, features = ["alloc", "serde"] } -openssl-sys = { version = "0.9.80", features = ["vendored"], optional = true } +openssl-sys = { version = "0.9.93", features = ["vendored"], optional = true } ursa = { workspace = true, optional = true } getset = { workspace = true } diff --git a/crypto/build.rs b/crypto/build.rs index c6b3b4910d9..364331891b5 100644 --- a/crypto/build.rs +++ b/crypto/build.rs @@ -6,7 +6,6 @@ fn main() { let ffi_import = std::env::var_os("CARGO_FEATURE_FFI_IMPORT").is_some(); let ffi_export = std::env::var_os("CARGO_FEATURE_FFI_EXPORT").is_some(); - #[allow(clippy::print_stderr)] if ffi_import && ffi_export { eprintln!("cargo:warning=Features `ffi_export` and `ffi_import` are mutually exclusive"); eprintln!("cargo:warning=When both active, `ffi_import` feature takes precedence"); diff --git a/crypto/src/hash.rs b/crypto/src/hash.rs index 12919a0faeb..f1ca35b89e8 100644 --- a/crypto/src/hash.rs +++ b/crypto/src/hash.rs @@ -124,7 +124,7 @@ impl Encode for Hash { #[inline] fn encode_to(&self, dest: &mut T) { - self.as_ref().encode_to(dest) + self.as_ref().encode_to(dest); } #[inline] @@ -243,7 +243,7 @@ impl Ord for HashOf { impl hash::Hash for HashOf { fn hash(&self, state: &mut H) { - self.0.hash(state) + self.0.hash(state); } } @@ -320,8 +320,6 @@ mod ffi { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - #[cfg(feature = "std")] #[cfg(not(feature = "ffi_import"))] use super::*; @@ -339,6 +337,6 @@ mod tests { "BA67336EFD6A3DF3A70EEB757860763036785C182FF4CF587541A0068D09F5B2" )[..] ); - }) + }); } } diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index d9a059aef24..f9e42a07b6c 100755 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -1,7 +1,5 @@ //! This module contains structures and implementations related to the cryptographic parts of the Iroha. #![cfg_attr(not(feature = "std"), no_std)] -// in no_std some code gets cfg-ed out, so we silence the warnings -#![allow(clippy::arithmetic_side_effects)] #[cfg(not(feature = "std"))] extern crate alloc; @@ -616,8 +614,6 @@ pub mod prelude { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - use parity_scale_codec::{Decode, Encode}; #[cfg(all(feature = "std", not(feature = "ffi_import")))] use serde::Deserialize; @@ -641,7 +637,7 @@ mod tests { serde_json::to_string(&algorithm) .and_then(|algorithm| serde_json::from_str(&algorithm)) .unwrap_or_else(|_| panic!("Failed to de/serialize key {:?}", &algorithm)) - ) + ); } } #[test] @@ -663,7 +659,7 @@ mod tests { serde_json::to_string(&key_pair) .and_then(|key_pair| serde_json::from_str(&key_pair)) .unwrap_or_else(|_| panic!("Failed to de/serialize key {:?}", &key_pair)) - ) + ); } } @@ -683,7 +679,7 @@ mod tests { algorithm, decoded_algorithm, "Failed to decode encoded {:?}", &algorithm - ) + ); } } @@ -730,7 +726,7 @@ mod tests { public_key, decoded_public_key, "Failed to decode encoded Public Key{:?}", &public_key - ) + ); } } @@ -819,7 +815,7 @@ mod tests { } ), "eb01c1040CB3231F601E7245A6EC9A647B450936F707CA7DC347ED258586C1924941D8BC38576473A8BA3BB2C37E3E121130AB67103498A96D0D27003E3AD960493DA79209CF024E2AA2AE961300976AEEE599A31A5E1B683EAA1BCFFC47B09757D20F21123C594CF0EE0BAF5E1BDD272346B7DC98A8F12C481A6B28174076A352DA8EAE881B90911013369D7FA960716A5ABC5314307463FA2285A5BF2A5B5C6220D68C2D34101A91DBFC531C5B9BBFB2245CCC0C50051F79FC6714D16907B1FC40E0C0" - ) + ); } #[cfg(all(feature = "std", not(feature = "ffi_import")))] #[derive(Debug, PartialEq, Deserialize, Serialize)] @@ -925,7 +921,7 @@ mod tests { "0000000000000000000000000000000060F3C1AC9ADDBBED8DB83BC1B2EF22139FB049EECB723A557A41CA1A4B1FED63"), } } - ) + ); } #[test] @@ -944,6 +940,6 @@ mod tests { Err(Error::KeyGen( "secp256k1 seed for must be at least 32 bytes long".to_owned() )) - ) + ); } } diff --git a/crypto/src/merkle.rs b/crypto/src/merkle.rs index 8cd0db82fe8..84d63cb1d8c 100644 --- a/crypto/src/merkle.rs +++ b/crypto/src/merkle.rs @@ -1,10 +1,4 @@ //! Merkle tree implementation. -#![allow( - clippy::std_instead_of_alloc, - clippy::std_instead_of_core, - clippy::arithmetic_side_effects -)] - #[cfg(not(feature = "std"))] use alloc::{format, string::String, vec::Vec}; #[cfg(feature = "std")] @@ -186,7 +180,7 @@ impl MerkleTree { } self.0.push(Some(hash)); - self.update(self.len().saturating_sub(1)) + self.update(self.len().saturating_sub(1)); } #[cfg(feature = "std")] @@ -299,7 +293,7 @@ mod tests { let tree = hashes.clone().into_iter().collect::>(); for i in 0..N_LEAVES as usize * 2 { - assert_eq!(tree.get_leaf_hash(i).as_ref(), hashes.get(i)) + assert_eq!(tree.get_leaf_hash(i).as_ref(), hashes.get(i)); } for (testee_hash, tester_hash) in tree.into_iter().zip(hashes) { assert_eq!(testee_hash, tester_hash); diff --git a/crypto/src/multihash.rs b/crypto/src/multihash.rs index fa382a71f44..579f9708d02 100644 --- a/crypto/src/multihash.rs +++ b/crypto/src/multihash.rs @@ -1,6 +1,4 @@ //! Module with multihash implementation -#![allow(clippy::std_instead_of_core)] - #[cfg(not(feature = "std"))] use alloc::{ string::{String, ToString as _}, @@ -215,8 +213,6 @@ impl From for MultihashConvertError { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - use super::*; use crate::hex_decode; @@ -237,7 +233,7 @@ mod tests { hex_decode("ed01201509A611AD6D97B01D871E58ED00C8FD7C3917B6CA61A8C2833A19E000AAC2E4") .expect("Failed to decode"), bytes - ) + ); } #[test] @@ -252,7 +248,7 @@ mod tests { hex_decode("ed01201509A611AD6D97B01D871E58ED00C8FD7C3917B6CA61A8C2833A19E000AAC2E4") .expect("Failed to decode"); let multihash_decoded: Multihash = bytes.try_into().expect("Failed to decode."); - assert_eq!(multihash, multihash_decoded) + assert_eq!(multihash, multihash_decoded); } #[test] diff --git a/crypto/src/signature.rs b/crypto/src/signature.rs index 4a5c65d7efb..2d8637c89d3 100644 --- a/crypto/src/signature.rs +++ b/crypto/src/signature.rs @@ -1,4 +1,3 @@ -#![allow(clippy::std_instead_of_core)] #[cfg(not(feature = "std"))] use alloc::{boxed::Box, collections::btree_set, format, string::String, vec, vec::Vec}; use core::marker::PhantomData; @@ -184,7 +183,7 @@ impl Ord for SignatureOf { #[cfg(not(feature = "ffi_import"))] impl core::hash::Hash for SignatureOf { fn hash(&self, state: &mut H) { - self.0.hash(state) + self.0.hash(state); } } @@ -537,8 +536,6 @@ impl std::error::Error for SignatureVerificationFail {} #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - #[cfg(feature = "std")] use super::*; #[cfg(any(feature = "std", feature = "ffi_import"))] @@ -555,7 +552,7 @@ mod tests { let signature = Signature::new(key_pair.clone(), message).expect("Failed to create signature."); assert!(*signature.public_key() == *key_pair.public_key()); - assert!(signature.verify(message).is_ok()) + assert!(signature.verify(message).is_ok()); } #[test] @@ -569,7 +566,7 @@ mod tests { let signature = Signature::new(key_pair.clone(), message).expect("Failed to create signature."); assert!(*signature.public_key() == *key_pair.public_key()); - assert!(signature.verify(message).is_ok()) + assert!(signature.verify(message).is_ok()); } #[test] @@ -583,7 +580,7 @@ mod tests { let signature = Signature::new(key_pair.clone(), message).expect("Failed to create signature."); assert!(*signature.public_key() == *key_pair.public_key()); - assert!(signature.verify(message).is_ok()) + assert!(signature.verify(message).is_ok()); } #[test] @@ -597,7 +594,7 @@ mod tests { let signature = Signature::new(key_pair.clone(), message).expect("Failed to create signature."); assert!(*signature.public_key() == *key_pair.public_key()); - assert!(signature.verify(message).is_ok()) + assert!(signature.verify(message).is_ok()); } #[test] diff --git a/crypto/src/varint.rs b/crypto/src/varint.rs index 66e426b0f6f..364fa5275ce 100644 --- a/crypto/src/varint.rs +++ b/crypto/src/varint.rs @@ -119,8 +119,6 @@ impl VarUint { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - #[cfg(not(feature = "std"))] use alloc::vec; diff --git a/data_model/benches/time_event_filter.rs b/data_model/benches/time_event_filter.rs index fca4349c97e..27e20605f1e 100644 --- a/data_model/benches/time_event_filter.rs +++ b/data_model/benches/time_event_filter.rs @@ -1,4 +1,4 @@ -#![allow(missing_docs, clippy::restriction)] +#![allow(missing_docs)] use std::time::Duration; diff --git a/data_model/build.rs b/data_model/build.rs index 2d55ca605eb..92b3b826f12 100644 --- a/data_model/build.rs +++ b/data_model/build.rs @@ -6,7 +6,6 @@ fn main() { let ffi_import = std::env::var_os("CARGO_FEATURE_FFI_IMPORT").is_some(); let ffi_export = std::env::var_os("CARGO_FEATURE_FFI_EXPORT").is_some(); - #[allow(clippy::print_stderr)] if ffi_import && ffi_export { println!("cargo:warning=Features `ffi_export` and `ffi_import` are mutually exclusive"); println!("cargo:warning=When both active, `ffi_import` feature takes precedence"); diff --git a/data_model/derive/src/filter.rs b/data_model/derive/src/filter.rs index 1cfbb9ce2bb..8479c88bfdb 100644 --- a/data_model/derive/src/filter.rs +++ b/data_model/derive/src/filter.rs @@ -1,8 +1,3 @@ -#![allow( - clippy::mixed_read_write_in_expression, - clippy::arithmetic_side_effects -)] - use darling::{FromDeriveInput, FromVariant}; use iroha_macro_utils::Emitter; use manyhow::emit; diff --git a/data_model/derive/src/has_origin.rs b/data_model/derive/src/has_origin.rs index fdac1780f4d..ac2e88833f1 100644 --- a/data_model/derive/src/has_origin.rs +++ b/data_model/derive/src/has_origin.rs @@ -1,9 +1,3 @@ -#![allow( - clippy::str_to_string, - clippy::mixed_read_write_in_expression, - clippy::unwrap_in_result -)] - use darling::{FromDeriveInput, FromVariant}; use iroha_macro_utils::{ attr_struct2, parse_single_list_attr, parse_single_list_attr_opt, Emitter, diff --git a/data_model/derive/src/id.rs b/data_model/derive/src/id.rs index 39983e1ad8e..3b40a0da006 100644 --- a/data_model/derive/src/id.rs +++ b/data_model/derive/src/id.rs @@ -1,5 +1,3 @@ -#![allow(clippy::str_to_string, clippy::mixed_read_write_in_expression)] - use darling::{FromAttributes, FromDeriveInput, FromField}; use iroha_macro_utils::{find_single_attr_opt, Emitter}; use manyhow::emit; diff --git a/data_model/derive/src/lib.rs b/data_model/derive/src/lib.rs index 7811b70bbf0..daf1b3a9a4f 100644 --- a/data_model/derive/src/lib.rs +++ b/data_model/derive/src/lib.rs @@ -1,6 +1,4 @@ //! A crate containing various derive macros for `data_model` -#![allow(clippy::std_instead_of_core)] - mod filter; mod has_origin; mod id; diff --git a/data_model/derive/src/model.rs b/data_model/derive/src/model.rs index 73aa757c87c..32d163d27cb 100644 --- a/data_model/derive/src/model.rs +++ b/data_model/derive/src/model.rs @@ -157,7 +157,6 @@ fn process_pub_item(input: syn2::DeriveInput) -> TokenStream { expose_ffi(attrs, &item) } // Triggers in `quote!` side, see https://github.com/rust-lang/rust-clippy/issues/10417 - #[allow(clippy::arithmetic_side_effects)] syn2::Data::Union(item) => { let fields = item.fields.named.iter().map(|field| { let field_attrs = &field.attrs; @@ -180,7 +179,6 @@ fn process_pub_item(input: syn2::DeriveInput) -> TokenStream { }); // See https://github.com/rust-lang/rust-clippy/issues/10417 - #[allow(clippy::arithmetic_side_effects)] let item = quote! { pub union #ident #impl_generics #where_clause { #(#fields),* diff --git a/data_model/derive/src/partially_tagged/mod.rs b/data_model/derive/src/partially_tagged/mod.rs index a17fd95aeb0..3e40d4518f0 100644 --- a/data_model/derive/src/partially_tagged/mod.rs +++ b/data_model/derive/src/partially_tagged/mod.rs @@ -160,7 +160,7 @@ pub fn impl_partially_tagged_deserialize(input: &syn2::DeriveInput) -> Result = serde_json::from_str(serialized_value) - .unwrap_or_else(|e| panic!("Failed to deserialize `{:?}`: {:?}", serialized_value, e)); + .unwrap_or_else(|e| panic!("Failed to deserialize `{serialized_value:?}`: {e:?}")); assert_eq!( *value, deserialized, - "Deserialized form of `{:?}` does not match the expected value", - value + "Deserialized form of `{value:?}` does not match the expected value" ); } } diff --git a/data_model/src/account.rs b/data_model/src/account.rs index b1c61a55fed..c66163920c0 100644 --- a/data_model/src/account.rs +++ b/data_model/src/account.rs @@ -1,6 +1,4 @@ //! Structures, traits and impls related to `Account`s. -#![allow(clippy::std_instead_of_alloc)] - #[cfg(not(feature = "std"))] use alloc::{ collections::{btree_map, btree_set}, diff --git a/data_model/src/asset.rs b/data_model/src/asset.rs index 9f658d98f00..25c19006e56 100644 --- a/data_model/src/asset.rs +++ b/data_model/src/asset.rs @@ -1,7 +1,5 @@ //! This module contains [`Asset`] structure, it's implementation and related traits and //! instructions implementations. -#![allow(clippy::std_instead_of_alloc)] - #[cfg(not(feature = "std"))] use alloc::{collections::btree_map, format, string::String, vec::Vec}; use core::{fmt, str::FromStr}; diff --git a/data_model/src/domain.rs b/data_model/src/domain.rs index 72214b21f4f..850eb3304a6 100644 --- a/data_model/src/domain.rs +++ b/data_model/src/domain.rs @@ -1,7 +1,5 @@ //! This module contains [`Domain`](`crate::domain::Domain`) structure //! and related implementations and trait implementations. -#![allow(clippy::std_instead_of_alloc)] - #[cfg(not(feature = "std"))] use alloc::{format, string::String, vec::Vec}; diff --git a/data_model/src/evaluate.rs b/data_model/src/evaluate.rs index c7a566277af..b566bf4e0b9 100644 --- a/data_model/src/evaluate.rs +++ b/data_model/src/evaluate.rs @@ -531,8 +531,6 @@ pub mod prelude { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - use core::{fmt::Debug, str::FromStr as _}; use iroha_crypto::KeyPair; diff --git a/data_model/src/events/pipeline.rs b/data_model/src/events/pipeline.rs index 4fbe2cfc8b6..27dbb58ac59 100644 --- a/data_model/src/events/pipeline.rs +++ b/data_model/src/events/pipeline.rs @@ -227,8 +227,6 @@ pub mod prelude { #[cfg(test)] #[cfg(feature = "transparent_api")] mod tests { - #![allow(clippy::restriction)] - #[cfg(not(feature = "std"))] use alloc::{string::ToString as _, vec, vec::Vec}; diff --git a/data_model/src/events/time.rs b/data_model/src/events/time.rs index 82e76481191..dc676145f78 100644 --- a/data_model/src/events/time.rs +++ b/data_model/src/events/time.rs @@ -1,6 +1,4 @@ //! Time event and filter -#![allow(clippy::arithmetic_side_effects)] - use core::{ops::Range, time::Duration}; use derive_more::Constructor; diff --git a/data_model/src/ipfs.rs b/data_model/src/ipfs.rs index 2af84ac2b23..13ff6cf0610 100644 --- a/data_model/src/ipfs.rs +++ b/data_model/src/ipfs.rs @@ -107,9 +107,7 @@ impl Decode for IpfsPath { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - - use parity_scale_codec::DecodeAll; + use parity_scale_codec::DecodeAll as _; use super::*; diff --git a/data_model/src/isi.rs b/data_model/src/isi.rs index e9541a3b0a3..c0b2fd41da1 100644 --- a/data_model/src/isi.rs +++ b/data_model/src/isi.rs @@ -261,10 +261,10 @@ mod transparent { /// Generic instruction for logging messages #[derive(Debug, Clone)] pub struct Log { - /// Message to be logged - pub msg: String, /// Log level of the message pub level: Level, + /// Message to be logged + pub msg: String, } impl From> for SetKeyValueExpr { diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 614e2d8d625..4459330b2e9 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -1,15 +1,8 @@ //! Iroha Data Model contains structures for Domains, Peers, Accounts and Assets with simple, //! non-specific functions like serialization. -#![allow( - clippy::module_name_repetitions, - clippy::unwrap_in_result, - clippy::std_instead_of_alloc, - clippy::arithmetic_side_effects, - clippy::trait_duplication_in_bounds, - clippy::extra_unused_lifetimes, // Thanks to `EnumKind` not knowing how to write a derive macro. - clippy::items_after_test_module, // Clippy bug -)] +// Clippy bug +#![allow(clippy::items_after_test_module)] // in no_std some code gets cfg-ed out, so we silence the warnings #![cfg_attr(not(feature = "std"), allow(unused, unused_tuple_struct_fields))] #![cfg_attr(not(feature = "std"), no_std)] @@ -203,7 +196,6 @@ pub struct EnumTryAsError { } // Manual implementation because this allow annotation does not affect `Display` derive -#[allow(clippy::use_debug)] impl fmt::Display for EnumTryAsError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> fmt::Result { write!( @@ -1068,7 +1060,6 @@ impl fmt::Display for Value { Value::Bool(v) => fmt::Display::fmt(&v, f), Value::String(v) => fmt::Display::fmt(&v, f), Value::Name(v) => fmt::Display::fmt(&v, f), - #[allow(clippy::use_debug)] Value::Vec(v) => { // TODO: Remove so we can derive. let list_of_display: Vec<_> = v.iter().map(ToString::to_string).collect(); @@ -1730,7 +1721,7 @@ where assert!( eq(&a().not().not(), &a()), "Double negation elimination doesn't hold for {typ}", - ) + ); } for a in &values { @@ -1837,7 +1828,6 @@ pub trait PredicateTrait { pub fn current_time() -> core::time::Duration { use std::time::SystemTime; - #[allow(clippy::expect_used)] SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .expect("Failed to get the current system time") diff --git a/data_model/src/metadata.rs b/data_model/src/metadata.rs index 8b3bd78d4a8..563c8a143ff 100644 --- a/data_model/src/metadata.rs +++ b/data_model/src/metadata.rs @@ -306,8 +306,6 @@ pub mod prelude { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - #[cfg(not(feature = "std"))] use alloc::{borrow::ToOwned as _, vec}; use core::str::FromStr as _; diff --git a/data_model/src/name.rs b/data_model/src/name.rs index 991708eed89..9de18a5a7c3 100644 --- a/data_model/src/name.rs +++ b/data_model/src/name.rs @@ -149,8 +149,6 @@ pub mod prelude { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - use parity_scale_codec::DecodeAll; use super::*; diff --git a/data_model/src/numeric.rs b/data_model/src/numeric.rs index e48323d3b0c..0bf04ac6e93 100644 --- a/data_model/src/numeric.rs +++ b/data_model/src/numeric.rs @@ -136,7 +136,7 @@ impl serde::Serialize for NumericValue { where S: Serializer, { - serializer.serialize_str(&format!("{:?}", self)) + serializer.serialize_str(&format!("{self:?}")) } } diff --git a/data_model/src/predicate.rs b/data_model/src/predicate.rs index d58163f5ee8..119625f6293 100644 --- a/data_model/src/predicate.rs +++ b/data_model/src/predicate.rs @@ -23,13 +23,13 @@ mod nontrivial { /// Extend the sequence with elements of another non-empty sequence #[inline] pub fn extend(&mut self, other: Self) { - self.0.extend(other.0) + self.0.extend(other.0); } /// Append `value` to the end of the sequence #[inline] pub fn push(&mut self, value: T) { - self.0.push(value) + self.0.push(value); } /// Apply the provided function to every element of the sequence @@ -230,8 +230,6 @@ impl Default for PredicateBox { #[cfg(test)] pub mod test { - #![allow(clippy::print_stdout, clippy::use_debug)] - use super::{value, PredicateBox}; use crate::{PredicateSymbol, PredicateTrait as _, ToValue}; @@ -841,7 +839,6 @@ pub mod numerical { } #[test] - #[allow(clippy::panic_in_result_fn)] // ? for syntax simplicity. fn semi_interval_semantics_fixed() -> Result<(), fixed::FixedPointOperationError> { let pred = SemiRange::Fixed((Fixed::try_from(1_f64)?, Fixed::try_from(100_f64)?).into()); @@ -903,7 +900,6 @@ pub mod numerical { } #[test] - #[allow(clippy::panic_in_result_fn)] // ? for syntax simplicity. fn interval_semantics_fixed() -> Result<(), fixed::FixedPointOperationError> { let pred = Range::Fixed((Fixed::try_from(1_f64)?, Fixed::try_from(100_f64)?).into()); @@ -1158,7 +1154,6 @@ pub mod value { } #[cfg(test)] - #[allow(clippy::print_stdout, clippy::use_debug)] mod test { use peer::Peer; use prelude::Metadata; @@ -1371,7 +1366,6 @@ pub mod ip_addr { #[cfg(test)] mod test { - #![allow(clippy::restriction)] use super::*; #[test] diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index ca6d7e67651..e14933992bf 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -142,10 +142,10 @@ pub mod model { #[getset(get = "pub")] #[ffi_type] pub struct TransactionQueryOutput { - /// Transaction - pub transaction: TransactionValue, /// The hash of the block to which `tx` belongs to pub block_hash: HashOf, + /// Transaction + pub transaction: TransactionValue, } /// Type returned from [`Metadata`] queries diff --git a/data_model/src/transaction.rs b/data_model/src/transaction.rs index 5a6684f4c65..d081dba6b8f 100644 --- a/data_model/src/transaction.rs +++ b/data_model/src/transaction.rs @@ -1,5 +1,4 @@ //! [`Transaction`] structures and related implementations. -#![allow(clippy::std_instead_of_core)] #[cfg(not(feature = "std"))] use alloc::{boxed::Box, format, string::String, vec::Vec}; use core::{ @@ -443,10 +442,8 @@ mod base64 { /// Serialize bytes using `base64` pub fn serialize(bytes: &[u8], serializer: S) -> Result { - serializer.collect_str(&base64::display::Base64Display::with_config( - bytes, - base64::STANDARD, - )) + let engine = base64::engine::general_purpose::STANDARD; + serializer.collect_str(&base64::display::Base64Display::new(bytes, &engine)) } /// Deserialize bytes using `base64` @@ -461,7 +458,8 @@ mod base64 { } fn visit_str(self, v: &str) -> Result { - base64::decode(v).map_err(serde::de::Error::custom) + let engine = base64::engine::general_purpose::STANDARD; + base64::engine::Engine::decode(&engine, v).map_err(serde::de::Error::custom) } } deserializer.deserialize_str(Visitor) @@ -767,8 +765,6 @@ pub mod prelude { #[cfg(test)] mod tests { - #![allow(clippy::pedantic, clippy::restriction)] - use super::*; #[test] diff --git a/data_model/src/trigger.rs b/data_model/src/trigger.rs index 48d6e5a7ed9..39271f8d0a2 100644 --- a/data_model/src/trigger.rs +++ b/data_model/src/trigger.rs @@ -306,7 +306,6 @@ pub mod action { } } - #[allow(clippy::expect_used)] impl Ord for Action { fn cmp(&self, other: &Self) -> cmp::Ordering { self.partial_cmp(other) @@ -438,7 +437,7 @@ mod tests { #[test] fn trigger_with_filterbox_can_be_unboxed() { /// Should fail to compile if a new variant will be added to `TriggeringFilterBox` - #[allow(dead_code, clippy::unwrap_used)] + #[allow(dead_code)] fn compile_time_check(boxed: Trigger) { match &boxed.action.filter { TriggeringFilterBox::Data(_) => { diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index b6b8d3a676c..64fcdb387e0 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -341,19 +341,19 @@ pub fn visit_expression( Expression::If(expr) => { visitor.visit_expression(authority, expr.condition()); visitor.visit_expression(authority, expr.then()); - visitor.visit_expression(authority, expr.otherwise()) + visitor.visit_expression(authority, expr.otherwise()); } Expression::Contains(expr) => { visitor.visit_expression(authority, expr.collection()); - visitor.visit_expression(authority, expr.element()) + visitor.visit_expression(authority, expr.element()); } Expression::ContainsAll(expr) => { visitor.visit_expression(authority, expr.collection()); - visitor.visit_expression(authority, expr.elements()) + visitor.visit_expression(authority, expr.elements()); } Expression::ContainsAny(expr) => { visitor.visit_expression(authority, expr.collection()); - visitor.visit_expression(authority, expr.elements()) + visitor.visit_expression(authority, expr.elements()); } Expression::Where(expr) => visitor.visit_expression(authority, expr.expression()), Expression::Query(query) => visitor.visit_query(authority, query), @@ -503,7 +503,7 @@ pub fn visit_transfer( object, destination_id, }, - ) + ); } ( IdBox::AccountId(source_id), @@ -589,15 +589,15 @@ pub fn visit_remove_key_value( match object_id { IdBox::AssetId(object_id) => { - visitor.visit_remove_asset_key_value(authority, RemoveKeyValue { object_id, key }) + visitor.visit_remove_asset_key_value(authority, RemoveKeyValue { object_id, key }); } IdBox::AssetDefinitionId(object_id) => visitor .visit_remove_asset_definition_key_value(authority, RemoveKeyValue { object_id, key }), IdBox::AccountId(object_id) => { - visitor.visit_remove_account_key_value(authority, RemoveKeyValue { object_id, key }) + visitor.visit_remove_account_key_value(authority, RemoveKeyValue { object_id, key }); } IdBox::DomainId(object_id) => { - visitor.visit_remove_domain_key_value(authority, RemoveKeyValue { object_id, key }) + visitor.visit_remove_domain_key_value(authority, RemoveKeyValue { object_id, key }); } _ => visitor.visit_unsupported(authority, isi), } @@ -654,7 +654,7 @@ pub fn visit_upgrade(visitor: &mut V, authority: &AccountId, match object { UpgradableBox::Executor(object) => { - visitor.visit_upgrade_executor(authority, Upgrade { object }) + visitor.visit_upgrade_executor(authority, Upgrade { object }); } } } diff --git a/data_model/tests/data_model.rs b/data_model/tests/data_model.rs index 6d420ea13b4..09cf1d602ff 100644 --- a/data_model/tests/data_model.rs +++ b/data_model/tests/data_model.rs @@ -1,5 +1,3 @@ -#![allow(clippy::too_many_lines, clippy::restriction)] - use std::str::FromStr as _; use iroha_data_model::{prelude::*, ParseError}; diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index f7f2fe68aaf..32a3fd329c9 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -4304,13 +4304,13 @@ }, "TransactionQueryOutput": { "Struct": [ - { - "name": "transaction", - "type": "TransactionValue" - }, { "name": "block_hash", "type": "HashOf" + }, + { + "name": "transaction", + "type": "TransactionValue" } ] }, diff --git a/ffi/derive/src/attr_parse/derive.rs b/ffi/derive/src/attr_parse/derive.rs index eb244cb5b19..d1d36bb5832 100644 --- a/ffi/derive/src/attr_parse/derive.rs +++ b/ffi/derive/src/attr_parse/derive.rs @@ -147,7 +147,7 @@ mod test { RustcDerive::Debug, ].into_iter().map(Derive::Rustc).collect(), } - ) + ); } #[test] @@ -162,7 +162,7 @@ mod test { GetSetDerive::CopyGetters, ].into_iter().map(Derive::GetSet).collect(), } - ) + ); } #[test] @@ -175,6 +175,6 @@ mod test { "Kek".to_string(), ].into_iter().map(Derive::Other).collect(), } - ) + ); } } diff --git a/ffi/derive/src/attr_parse/getset.rs b/ffi/derive/src/attr_parse/getset.rs index 0b63b0b5385..208c949956e 100644 --- a/ffi/derive/src/attr_parse/getset.rs +++ b/ffi/derive/src/attr_parse/getset.rs @@ -78,14 +78,11 @@ impl syn2::parse::Parse for SpannedGetSetOptions { } else { errors.push(syn2::Error::new( lit.span(), - format!( - "Failed to parse getset options at {}: duplicate visibility", - part - ), + format!("Failed to parse getset options at {part}: duplicate visibility",), )); } } else { - errors.push(syn2::Error::new(lit.span(), format!("Failed to parse getset options at `{}`: expected visibility or `with_prefix`", part))); + errors.push(syn2::Error::new(lit.span(), format!("Failed to parse getset options at `{part}`: expected visibility or `with_prefix`"))); } } @@ -183,7 +180,7 @@ fn insert_gen_request( match gen_map.entry(mode) { Entry::Occupied(_) => accumulator.push( - darling::Error::custom(format!("duplicate `getset({})` attribute", mode)) + darling::Error::custom(format!("duplicate `getset({mode})` attribute")) .with_span(&span), ), Entry::Vacant(v) => { @@ -255,7 +252,7 @@ impl GetSetRawFieldAttr { "getset attributes without `getset` prefix are not supported by iroha_ffi_derive", ) .with_span(attr), - ) + ); } } @@ -718,7 +715,7 @@ mod test { (GetSetGenMode::Get, GetSetOptions::default()), (GetSetGenMode::Set, GetSetOptions::default()), ]) - ) + ); } #[test] @@ -737,7 +734,7 @@ mod test { ..Default::default() }), ]) - ) + ); } #[test] @@ -756,7 +753,7 @@ mod test { with_prefix: true, }), ]) - ) + ); } } } diff --git a/ffi/derive/src/convert.rs b/ffi/derive/src/convert.rs index 374055ebd3a..4b2b0450e25 100644 --- a/ffi/derive/src/convert.rs +++ b/ffi/derive/src/convert.rs @@ -33,7 +33,7 @@ impl Display for FfiTypeToken { FfiTypeToken::UnsafeNonOwning => "#[ffi_type(unsafe {non_owning})]", FfiTypeToken::Local => "#[ffi_type(local)]", }; - write!(f, "{}", text) + write!(f, "{text}") } } @@ -286,7 +286,7 @@ pub fn derive_ffi_type(emitter: &mut Emitter, input: &syn2::DeriveInput) -> Toke emitter, &variant.span(), "Fieldless enums with explicit discriminants are prohibited", - ) + ); } derive_ffi_type_for_fieldless_enum( diff --git a/ffi/derive/src/ffi_fn.rs b/ffi/derive/src/ffi_fn.rs index 3b414cdb8e0..f90a4763191 100644 --- a/ffi/derive/src/ffi_fn.rs +++ b/ffi/derive/src/ffi_fn.rs @@ -189,7 +189,7 @@ fn gen_input_conversion_stmts(fn_descriptor: &FnDescriptor) -> TokenStream { let mut stmts = quote! {}; if let Some(arg) = &fn_descriptor.receiver { - stmts = gen_arg_ffi_to_src(arg) + stmts = gen_arg_ffi_to_src(arg); } for arg in &fn_descriptor.input_args { diff --git a/ffi/derive/src/impl_visitor.rs b/ffi/derive/src/impl_visitor.rs index c5bd408b01b..4d7f8dde79d 100644 --- a/ffi/derive/src/impl_visitor.rs +++ b/ffi/derive/src/impl_visitor.rs @@ -406,14 +406,14 @@ impl<'ast> Visit<'ast> for FnVisitor<'ast, '_> { self.emitter, node.abi, "Extern fn declarations not supported" - ) + ); } if node.variadic.is_some() { emit!( self.emitter, node.variadic, "Variadic arguments not supported" - ) + ); } visit_signature(self, node); diff --git a/ffi/derive/src/lib.rs b/ffi/derive/src/lib.rs index fdd0673192b..aa2fd27550d 100644 --- a/ffi/derive/src/lib.rs +++ b/ffi/derive/src/lib.rs @@ -1,6 +1,4 @@ //! Crate containing FFI related macro functionality -#![allow(clippy::arithmetic_side_effects)] - use darling::FromDeriveInput; use impl_visitor::{FnDescriptor, ImplDescriptor}; use iroha_macro_utils::Emitter; diff --git a/ffi/derive/src/wrapper.rs b/ffi/derive/src/wrapper.rs index 8ea1286eeb4..0096502cdc2 100644 --- a/ffi/derive/src/wrapper.rs +++ b/ffi/derive/src/wrapper.rs @@ -143,7 +143,7 @@ fn gen_shared_fns(emitter: &mut Emitter, input: &FfiTypeInput) -> Vec { shared_fn_impls.push(impl_clone_for_opaque(name, &input.generics)); @@ -169,7 +169,7 @@ fn gen_shared_fns(emitter: &mut Emitter, input: &FfiTypeInput) -> Vec { @@ -181,7 +181,7 @@ fn gen_shared_fns(emitter: &mut Emitter, input: &FfiTypeInput) -> Vec COutPtrWrite> for Option { // TODO: No need to zero the memory because it must never be read out_ptr.write(FfiTuple2(discriminant_out_ptr, unsafe { core::mem::zeroed() - })) + })); } Some(value) => { let mut discriminant_out_ptr = MaybeUninit::uninit(); diff --git a/ffi/src/primitives.rs b/ffi/src/primitives.rs index 1c53f998442..b6009b1f138 100644 --- a/ffi/src/primitives.rs +++ b/ffi/src/primitives.rs @@ -205,11 +205,8 @@ macro_rules! int128_derive { int128_derive! { u128 => FfiU128, i128 => FfiI128 } impl From for FfiU128 { - #[allow( - clippy::cast_possible_truncation, // Truncation is done on purpose - clippy::arithmetic_side_effects - )] - #[inline] + // Truncation is done on purpose + #[allow(clippy::cast_possible_truncation)] fn from(value: u128) -> Self { let lo = value as u64; let hi = (value >> 64) as u64; @@ -218,14 +215,10 @@ impl From for FfiU128 { } impl From for u128 { - #[allow( - clippy::cast_lossless, - clippy::cast_possible_truncation, // Truncation is done on purpose - clippy::arithmetic_side_effects - )] - #[inline] + // Truncation is done on purpose + #[allow(clippy::cast_possible_truncation)] fn from(FfiU128(FfiTuple2(hi, lo)): FfiU128) -> Self { - ((hi as u128) << 64) | (lo as u128) + (u128::from(hi) << 64) | u128::from(lo) } } @@ -259,7 +252,7 @@ mod tests { ]; for value in values { - assert_eq!(value, FfiU128::from(value).into()) + assert_eq!(value, FfiU128::from(value).into()); } } @@ -280,7 +273,7 @@ mod tests { ]; for value in values { - assert_eq!(value, FfiI128::from(value).into()) + assert_eq!(value, FfiI128::from(value).into()); } } } diff --git a/ffi/src/repr_c.rs b/ffi/src/repr_c.rs index ff0472c672e..f7efe9d08d8 100644 --- a/ffi/src/repr_c.rs +++ b/ffi/src/repr_c.rs @@ -285,7 +285,6 @@ impl<'itm, R: NonLocal + CTypeConvert<'itm, S, R::ReprC> + Clone + 'itm, S: C CTypeConvert::, _>::into_repr_c(self, store_borrow); // NOTE: None value indicates a bug in the implementation - #[allow(clippy::expect_used)] out_ptr.write(store.0.expect("Store must be initialized")); } } @@ -641,7 +640,7 @@ impl COutPtr for R { } impl COutPtrWrite for R { unsafe fn write_out(self, out_ptr: *mut Self::OutPtr) { - write_non_local::<_, Robust>(self, out_ptr) + write_non_local::<_, Robust>(self, out_ptr); } } impl COutPtrRead for R { @@ -713,7 +712,7 @@ impl COutPtr<&[Robust]> for &[R] { } impl COutPtrWrite<&[Robust]> for &[R] { unsafe fn write_out(self, out_ptr: *mut Self::OutPtr) { - write_non_local::<_, &[Robust]>(self, out_ptr) + write_non_local::<_, &[Robust]>(self, out_ptr); } } impl COutPtrRead<&[Robust]> for &[R] { @@ -747,7 +746,7 @@ impl COutPtr<&mut [Robust]> for &mut [R] { } impl COutPtrWrite<&mut [Robust]> for &mut [R] { unsafe fn write_out(self, out_ptr: *mut Self::OutPtr) { - write_non_local::<_, &mut [Robust]>(self, out_ptr) + write_non_local::<_, &mut [Robust]>(self, out_ptr); } } impl COutPtrRead<&mut [Robust]> for &mut [R] { @@ -836,7 +835,7 @@ impl COutPtr for R { } impl COutPtrWrite for R { unsafe fn write_out(self, out_ptr: *mut Self::OutPtr) { - write_non_local::<_, Opaque>(self, out_ptr) + write_non_local::<_, Opaque>(self, out_ptr); } } @@ -865,7 +864,7 @@ impl COutPtr> for Box { } impl COutPtrWrite> for Box { unsafe fn write_out(self, out_ptr: *mut Self::OutPtr) { - write_non_local::<_, Box>(self, out_ptr) + write_non_local::<_, Box>(self, out_ptr); } } @@ -1057,7 +1056,7 @@ impl COutPtr<[Opaque; N]> for [R; N] { } impl COutPtrWrite<[Opaque; N]> for [R; N] { unsafe fn write_out(self, out_ptr: *mut Self::OutPtr) { - write_non_local::<_, [Opaque; N]>(self, out_ptr) + write_non_local::<_, [Opaque; N]>(self, out_ptr); } } diff --git a/ffi/tests/export_getset.rs b/ffi/tests/export_getset.rs index 3a059d39c30..bb8bbf0cba5 100644 --- a/ffi/tests/export_getset.rs +++ b/ffi/tests/export_getset.rs @@ -1,4 +1,4 @@ -#![allow(unsafe_code, clippy::restriction, clippy::pedantic)] +#![allow(unsafe_code)] use std::mem::MaybeUninit; diff --git a/ffi/tests/export_shared_fns.rs b/ffi/tests/export_shared_fns.rs index 0103a171646..b254c657d42 100644 --- a/ffi/tests/export_shared_fns.rs +++ b/ffi/tests/export_shared_fns.rs @@ -1,4 +1,4 @@ -#![allow(unsafe_code, clippy::restriction)] +#![allow(unsafe_code)] use std::{cmp::Ordering, mem::MaybeUninit}; diff --git a/ffi/tests/ffi_export.rs b/ffi/tests/ffi_export.rs index fc3a661fcc6..4d0e8857a9d 100644 --- a/ffi/tests/ffi_export.rs +++ b/ffi/tests/ffi_export.rs @@ -1,4 +1,4 @@ -#![allow(unsafe_code, clippy::restriction, clippy::pedantic)] +#![allow(unsafe_code, clippy::pedantic)] use std::{alloc, collections::BTreeMap, mem::MaybeUninit}; @@ -55,7 +55,7 @@ pub enum DataCarryingEnum { D, } -/// ReprC struct +/// `ReprC` struct #[derive(Clone, Copy, PartialEq, Eq, FfiType)] #[repr(C)] pub struct RobustReprCStruct { @@ -344,7 +344,7 @@ fn into_iter_item_impl_into() { ]; let mut ffi_struct = get_new_struct(); - let mut tokens_store = Default::default(); + let mut tokens_store = Vec::default(); let tokens_ffi = tokens.clone().into_ffi(&mut tokens_store); let mut output = MaybeUninit::new(core::ptr::null_mut()); @@ -550,7 +550,7 @@ fn return_empty_tuple_result() { #[webassembly_test::webassembly_test] fn array_to_pointer() { let array = [1_u8]; - let mut store = Default::default(); + let mut store = Option::default(); let ptr: *mut [u8; 1] = array.into_ffi(&mut store); let mut output = MaybeUninit::new([0_u8]); @@ -767,7 +767,7 @@ fn return_vec_of_boxed_opaques() { fn array_of_opaques() { let input = [OpaqueStruct::default(), OpaqueStruct::default()]; let mut output = MaybeUninit::new([core::ptr::null_mut(), core::ptr::null_mut()]); - let mut store = Default::default(); + let mut store = Option::default(); unsafe { assert_eq!( diff --git a/ffi/tests/ffi_export_import_u128_i128.rs b/ffi/tests/ffi_export_import_u128_i128.rs index a4c7b5352fa..cbeb7892a47 100644 --- a/ffi/tests/ffi_export_import_u128_i128.rs +++ b/ffi/tests/ffi_export_import_u128_i128.rs @@ -130,7 +130,7 @@ fn i128_slice_conversion() { fn u128_vec_conversion() { let values = u128_values().to_vec(); - assert_eq!(values, freestanding_u128_vec(values.clone())) + assert_eq!(values, freestanding_u128_vec(values.clone())); } #[test] @@ -138,7 +138,7 @@ fn u128_vec_conversion() { fn i128_vec_conversion() { let values = i128_values().to_vec(); - assert_eq!(values, freestanding_i128_vec(values.clone())) + assert_eq!(values, freestanding_i128_vec(values.clone())); } #[test] @@ -147,7 +147,7 @@ fn u128_box_conversion() { let values = u128_values(); for value in values { let value = Box::new(value); - assert_eq!(value, freestanding_u128_box(value.clone())) + assert_eq!(value, freestanding_u128_box(value.clone())); } } @@ -158,7 +158,7 @@ fn i128_box_conversion() { for value in values { let value = Box::new(value); - assert_eq!(value, freestanding_i128_box(value.clone())) + assert_eq!(value, freestanding_i128_box(value.clone())); } } @@ -167,7 +167,7 @@ fn i128_box_conversion() { fn u128_array_conversion() { let values = u128_values(); - assert_eq!(values, freestanding_u128_array(values)) + assert_eq!(values, freestanding_u128_array(values)); } #[test] @@ -175,5 +175,5 @@ fn u128_array_conversion() { fn i128_array_conversion() { let values = i128_values(); - assert_eq!(values, freestanding_i128_array(values)) + assert_eq!(values, freestanding_i128_array(values)); } diff --git a/ffi/tests/ffi_import.rs b/ffi/tests/ffi_import.rs index 041c44e16fd..570a5ada0dd 100644 --- a/ffi/tests/ffi_import.rs +++ b/ffi/tests/ffi_import.rs @@ -1,4 +1,4 @@ -#![allow(unsafe_code, clippy::restriction, clippy::pedantic)] +#![allow(unsafe_code)] use iroha_ffi::{ffi, ffi_import, LocalRef, LocalSlice}; @@ -147,7 +147,7 @@ mod ffi { input: SliceRef>, output: *mut OutBoxedSlice>, ) -> FfiReturn { - let input = input.into_rust().map(|slice| slice.to_vec()); + let input = input.into_rust().map(<[_]>::to_vec); output.write(OutBoxedSlice::from_vec(input)); FfiReturn::Ok } diff --git a/ffi/tests/ffi_import_opaque.rs b/ffi/tests/ffi_import_opaque.rs index 8567258092b..c9ffe7c4fb4 100644 --- a/ffi/tests/ffi_import_opaque.rs +++ b/ffi/tests/ffi_import_opaque.rs @@ -1,4 +1,4 @@ -#![allow(unsafe_code, clippy::restriction, clippy::pedantic)] +#![allow(unsafe_code)] use std::collections::BTreeMap; @@ -130,10 +130,12 @@ fn fallible_output() { //assert!(OpaqueStruct::fallible_int_output(false).is_err()); } +#[allow(trivial_casts)] fn compare_opaque_eq(opaque1: &T, opaque2: &T) { unsafe { - let opaque1: &*const U = core::mem::transmute(opaque1); - let opaque2: &*const U = core::mem::transmute(opaque2); + let opaque1: &*const U = &*(opaque1 as *const T).cast::<*const U>(); + let opaque2: &*const U = &*(opaque2 as *const T).cast::<*const U>(); + assert_eq!(**opaque1, **opaque2) } } @@ -203,7 +205,7 @@ mod ffi { output: *mut *mut ExternOpaqueStruct, ) -> iroha_ffi::FfiReturn { let mut handle = *Box::from_raw(handle); - let mut store = Default::default(); + let mut store = Vec::default(); let params: Vec<(u8, ExternValue)> = FfiConvert::try_from_ffi(params, &mut store).expect("Valid"); handle.params = params.into_iter().collect(); diff --git a/ffi/tests/generics.rs b/ffi/tests/generics.rs index 2d92b2e8205..bd0b551f899 100644 --- a/ffi/tests/generics.rs +++ b/ffi/tests/generics.rs @@ -1,4 +1,4 @@ -#![allow(unsafe_code, clippy::restriction, clippy::pedantic)] +#![allow(unsafe_code)] use std::mem::MaybeUninit; diff --git a/ffi/tests/import_getset.rs b/ffi/tests/import_getset.rs index 0f0962e7988..56d5a733dae 100644 --- a/ffi/tests/import_getset.rs +++ b/ffi/tests/import_getset.rs @@ -1,4 +1,4 @@ -#![allow(unsafe_code, clippy::restriction, clippy::pedantic)] +#![allow(unsafe_code)] use iroha_ffi::{ffi, ffi_import}; diff --git a/ffi/tests/import_shared_fns.rs b/ffi/tests/import_shared_fns.rs index df0c232d631..cab3d5fd658 100644 --- a/ffi/tests/import_shared_fns.rs +++ b/ffi/tests/import_shared_fns.rs @@ -1,4 +1,4 @@ -#![allow(unsafe_code, clippy::restriction)] +#![allow(unsafe_code)] use iroha_ffi::{ffi, ffi_import}; diff --git a/ffi/tests/transparent.rs b/ffi/tests/transparent.rs index 1ef58685226..01f93912add 100644 --- a/ffi/tests/transparent.rs +++ b/ffi/tests/transparent.rs @@ -1,4 +1,4 @@ -#![allow(unsafe_code, clippy::restriction, clippy::pedantic)] +#![allow(unsafe_code)] use std::{alloc, marker::PhantomData, mem::MaybeUninit}; @@ -69,6 +69,7 @@ impl TransparentStruct { } } + #[must_use] pub fn with_payload(mut self, payload: GenericTransparentStruct<()>) -> Self { self.payload = payload; self @@ -167,7 +168,7 @@ fn transparent_vec_to_vec() { TransparentStruct::new(GenericTransparentStruct::new(3)), ]; - let mut store = Default::default(); + let mut store = Vec::default(); let mut output = MaybeUninit::new(OutBoxedSlice::from_raw_parts(core::ptr::null_mut(), 0)); unsafe { diff --git a/ffi/tests/unambiguous.rs b/ffi/tests/unambiguous.rs index 167d375a20b..4392fb48e2f 100644 --- a/ffi/tests/unambiguous.rs +++ b/ffi/tests/unambiguous.rs @@ -1,4 +1,4 @@ -#![allow(unsafe_code, clippy::restriction, clippy::pedantic)] +#![allow(unsafe_code)] use std::mem::MaybeUninit; @@ -13,7 +13,7 @@ pub enum Ambiguous { None, } -/// FfiStruct +/// `FfiStruct` #[derive(Clone, Copy, FfiType)] pub struct FfiStruct; diff --git a/futures/Cargo.toml b/futures/Cargo.toml index 592064ea911..9ac3a719bfa 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -26,4 +26,4 @@ serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros"] } [dev-dependencies] -tokio-stream = "0.1.11" +tokio-stream = "0.1.14" diff --git a/futures/derive/src/lib.rs b/futures/derive/src/lib.rs index 43ebc497e11..5212c38efe2 100644 --- a/futures/derive/src/lib.rs +++ b/futures/derive/src/lib.rs @@ -1,11 +1,4 @@ //! Crate with derive macros for futures - -#![allow( - clippy::expect_used, - clippy::str_to_string, - clippy::std_instead_of_core -)] - use iroha_macro_utils::Emitter; use manyhow::{emit, manyhow}; use proc_macro2::TokenStream; @@ -65,7 +58,7 @@ pub fn telemetry_future(args: TokenStream, input: TokenStream) -> TokenStream { let mut emitter = Emitter::new(); if !args.is_empty() { - emit!(emitter, args, "Unexpected arguments") + emit!(emitter, args, "Unexpected arguments"); } let Some(input) = emitter.handle(syn2::parse2(input)) else { diff --git a/futures/src/lib.rs b/futures/src/lib.rs index c8a01486346..f45fa002b71 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -1,5 +1,4 @@ //! Crate with various iroha futures -#![allow(clippy::std_instead_of_core, clippy::std_instead_of_alloc)] use std::{ future::Future, pin::Pin, @@ -50,7 +49,6 @@ pub struct TelemetryConversionError; impl TryFrom<&Telemetry> for FuturePollTelemetry { type Error = TelemetryConversionError; - #[allow(clippy::unwrap_in_result, clippy::unwrap_used)] fn try_from( Telemetry { target, fields }: &Telemetry, ) -> Result { @@ -85,7 +83,6 @@ impl TryFrom<&Telemetry> for FuturePollTelemetry { impl TryFrom for FuturePollTelemetry { type Error = TelemetryConversionError; - #[allow(clippy::unwrap_in_result, clippy::unwrap_used)] fn try_from(Telemetry { target, fields }: Telemetry) -> Result { if target != "iroha_futures" && fields.len() != 3 { return Err(TelemetryConversionError); diff --git a/futures/tests/basic.rs b/futures/tests/basic.rs index c3a17c6ba7a..a1514e01ab1 100644 --- a/futures/tests/basic.rs +++ b/futures/tests/basic.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{thread, time::Duration}; use iroha_config::base::proxy::Builder; diff --git a/genesis/src/lib.rs b/genesis/src/lib.rs index 3ea5510a364..5fd2f1fc56a 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -1,13 +1,5 @@ //! Genesis-related logic and constructs. Contains the `GenesisBlock`, //! `RawGenesisBlock` and the `RawGenesisBlockBuilder` structures. -#![allow( - clippy::module_name_repetitions, - clippy::new_without_default, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - clippy::arithmetic_side_effects -)] - use std::{ fmt::Debug, fs::{self, File}, @@ -251,9 +243,8 @@ mod executor_state { pub struct Unset; } -impl RawGenesisBlockBuilder { - /// Initiate the building process. - pub fn new() -> Self { +impl Default for RawGenesisBlockBuilder { + fn default() -> Self { // Do not add `impl Default`. While it can technically be // regarded as a default constructor, this builder should not // be used in contexts where `Default::default()` is likely to @@ -263,7 +254,9 @@ impl RawGenesisBlockBuilder { state: executor_state::Unset, } } +} +impl RawGenesisBlockBuilder { /// Set the executor. pub fn executor( self, @@ -379,12 +372,11 @@ mod tests { } #[test] - #[allow(clippy::expect_used)] fn load_new_genesis_block() -> Result<()> { let (genesis_public_key, genesis_private_key) = KeyPair::generate()?.into(); let (alice_public_key, _) = KeyPair::generate()?.into(); let _genesis_block = GenesisNetwork::from_configuration( - RawGenesisBlockBuilder::new() + RawGenesisBlockBuilder::default() .domain("wonderland".parse()?) .account("alice".parse()?, alice_public_key) .finish_domain() @@ -402,11 +394,10 @@ mod tests { Ok(()) } - #[allow(clippy::unwrap_used)] #[test] fn genesis_block_builder_example() { let public_key = "ed0120204E9593C3FFAF4464A6189233811C297DD4CE73ABA167867E4FBD4F8C450ACB"; - let mut genesis_builder = RawGenesisBlockBuilder::new(); + let mut genesis_builder = RawGenesisBlockBuilder::default(); genesis_builder = genesis_builder .domain("wonderland".parse().unwrap()) diff --git a/logger/Cargo.toml b/logger/Cargo.toml index 918e23bb3ba..68fd484a18e 100644 --- a/logger/Cargo.toml +++ b/logger/Cargo.toml @@ -22,7 +22,7 @@ tracing-futures = { workspace = true, features = ["std-future", "std"] } tracing-subscriber = { workspace = true, features = ["fmt", "ansi"] } tracing-bunyan-formatter = { workspace = true } tokio = { workspace = true, features = ["sync"] } -console-subscriber = { version = "0.1.8", optional = true } +console-subscriber = { version = "0.2.0", optional = true } once_cell = { workspace = true } derive_more = { workspace = true } tracing-error = "0.2.0" @@ -32,7 +32,6 @@ tokio = { workspace = true, features = ["macros", "time", "rt"] } [features] -default = [] tokio-console = ["dep:console-subscriber", "tokio/tracing", "iroha_config/tokio-console"] # Workaround to avoid activating `tokio-console` with `--all-features` flag, because `tokio-console` require `tokio_unstable` rustc flag no-tokio-console = [] diff --git a/logger/src/layer.rs b/logger/src/layer.rs index 1ae5b8303c3..5b17d93cfe4 100644 --- a/logger/src/layer.rs +++ b/logger/src/layer.rs @@ -1,5 +1,4 @@ //! Module for adding layers for events for subscribers -#![allow(clippy::std_instead_of_core, clippy::std_instead_of_alloc)] use std::{ any::TypeId, fmt::Debug, diff --git a/logger/src/lib.rs b/logger/src/lib.rs index aa4abc10751..fceecc1d26c 100644 --- a/logger/src/lib.rs +++ b/logger/src/lib.rs @@ -1,10 +1,4 @@ //! Iroha's logging utilities. -#![allow( - clippy::expect_used, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] - pub mod layer; pub mod telemetry; diff --git a/logger/src/telemetry.rs b/logger/src/telemetry.rs index 1af4bae5eb8..526209daa60 100644 --- a/logger/src/telemetry.rs +++ b/logger/src/telemetry.rs @@ -1,11 +1,5 @@ //! Module with telemetry layer for tracing -#![allow( - clippy::module_name_repetitions, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] - use std::{error::Error, fmt::Debug}; use derive_more::{Deref, DerefMut}; diff --git a/logger/tests/configuration.rs b/logger/tests/configuration.rs index 9d353fab8b0..661443ed256 100644 --- a/logger/tests/configuration.rs +++ b/logger/tests/configuration.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::time::Duration; use iroha_data_model::Level; @@ -14,7 +12,7 @@ async fn telemetry_separation_custom() { compact_mode: true, log_file_path: Some("/dev/stdout".into()), terminal_colors: true, - #[cfg(all(feature = "tokio-console", not(feature = "no-tokio-console")))] + #[cfg(feature = "tokio-console")] tokio_console_addr: "127.0.0.1:5555".into(), }; let (mut receiver, _) = init(&config).unwrap().unwrap(); diff --git a/logger/tests/log_level.rs b/logger/tests/log_level.rs index b97c9c7ce63..ac04284c1d4 100644 --- a/logger/tests/log_level.rs +++ b/logger/tests/log_level.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction, clippy::all)] - use std::time::Duration; use iroha_logger::{ @@ -16,6 +14,7 @@ struct SenderFilter { } impl SenderFilter { + #[allow(clippy::new_ret_no_self)] pub fn new(sub: S) -> (impl Subscriber, mpsc::UnboundedReceiver<()>) { let (sender, receiver) = mpsc::unbounded_channel(); (EventSubscriber(Self { sender, sub }), receiver) diff --git a/logger/tests/setting_logger.rs b/logger/tests/setting_logger.rs index da82ff950e3..6d204f7abca 100644 --- a/logger/tests/setting_logger.rs +++ b/logger/tests/setting_logger.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction, clippy::expect_used)] - use iroha_config::base::proxy::Builder; use iroha_logger::{init, ConfigurationProxy}; diff --git a/logger/tests/telemetry.rs b/logger/tests/telemetry.rs index 50507412673..bfab41332eb 100644 --- a/logger/tests/telemetry.rs +++ b/logger/tests/telemetry.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::time::Duration; use iroha_config::base::proxy::Builder; diff --git a/macro/derive/src/lib.rs b/macro/derive/src/lib.rs index 6d8df4912a4..c8121d9a317 100644 --- a/macro/derive/src/lib.rs +++ b/macro/derive/src/lib.rs @@ -1,7 +1,5 @@ //! Crate with various derive macros -#![allow(clippy::restriction)] - use darling::{util::SpannedValue, FromDeriveInput}; use manyhow::{manyhow, Result}; use proc_macro2::{Span, TokenStream}; diff --git a/macro/src/lib.rs b/macro/src/lib.rs index 35b71caacec..e7d398f16b5 100644 --- a/macro/src/lib.rs +++ b/macro/src/lib.rs @@ -1,6 +1,4 @@ //! Crate containing iroha macros - -#![allow(clippy::module_name_repetitions, clippy::std_instead_of_core)] #![cfg_attr(not(feature = "std"), no_std)] pub use iroha_derive::*; diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs index 963d6355f29..7d785eec1e9 100644 --- a/p2p/src/lib.rs +++ b/p2p/src/lib.rs @@ -1,7 +1,6 @@ //! This module provides a network layer for holding of persistent //! connections between blockchain nodes. Sane defaults for secure //! Cryptography are chosen in this module, and encapsulated. -#![allow(clippy::std_instead_of_core, clippy::std_instead_of_alloc)] use std::{io, net::AddrParseError}; use iroha_crypto::ursa::{ diff --git a/p2p/src/network.rs b/p2p/src/network.rs index a3b3da23294..aa8c9ce67a6 100644 --- a/p2p/src/network.rs +++ b/p2p/src/network.rs @@ -1,5 +1,4 @@ //! Network formed out of Iroha peers. -#![allow(clippy::std_instead_of_core)] use std::{ collections::{HashMap, HashSet}, fmt::Debug, @@ -204,7 +203,6 @@ impl NetworkBase { async fn run(mut self) { // TODO: probably should be configuration parameter let mut update_topology_interval = tokio::time::interval(Duration::from_millis(100)); - #[allow(clippy::arithmetic_side_effects)] loop { tokio::select! { // Select is biased because we want to service messages to take priority over data messages. diff --git a/p2p/src/peer.rs b/p2p/src/peer.rs index e7dbd5b95bf..22d78171984 100644 --- a/p2p/src/peer.rs +++ b/p2p/src/peer.rs @@ -1,5 +1,4 @@ //! Tokio actor Peer -#![allow(clippy::arithmetic_side_effects)] use bytes::{Buf, BufMut, BytesMut}; use iroha_data_model::prelude::PeerId; @@ -216,7 +215,7 @@ mod run { iroha_logger::debug!("Peer is terminated."); let _ = service_message_sender - .send(ServiceMessage::Terminated(Terminated { conn_id, peer_id })) + .send(ServiceMessage::Terminated(Terminated { peer_id, conn_id })) .await; } @@ -718,8 +717,8 @@ mod cryptographer { GenericArray::from_slice(shared_key.as_ref()), )); Self { - encryptor, shared_key, + encryptor, } } } diff --git a/p2p/tests/integration/p2p.rs b/p2p/tests/integration/p2p.rs index 5cd769aca68..fc9a958401e 100644 --- a/p2p/tests/integration/p2p.rs +++ b/p2p/tests/integration/p2p.rs @@ -1,5 +1,3 @@ -#![allow(clippy::restriction)] - use std::{ collections::HashSet, fmt::Debug, @@ -247,7 +245,6 @@ async fn multiple_networks() { .expect("Default logger config should always build") }; // Can't use logger because it's failed to initialize. - #[allow(clippy::print_stderr)] if let Err(err) = iroha_logger::init(&log_config) { eprintln!("Failed to initialize logger: {err}"); } diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index bbbd408827d..6d9328a51ef 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -37,7 +37,7 @@ fixnum = { workspace = true, features = ["serde", "parity", "i64"] } derive_more = { workspace = true, features = ["display", "from", "as_ref", "as_mut", "deref", "constructor", "into_iterator"] } serde = { workspace = true, features = ["derive"] } serde_with = { workspace = true, features = ["macros"] } -smallvec = { version = "1.10.0", default-features = false, features = ["serde", "union"] } +smallvec = { version = "1.11.1", default-features = false, features = ["serde", "union"] } smallstr = { version = "0.3.0", default-features = false, features = ["serde", "union"] } thiserror = { workspace = true, optional = true } displaydoc = { workspace = true } diff --git a/primitives/src/cmpext.rs b/primitives/src/cmpext.rs index f0905a836a0..0de287e3f3c 100644 --- a/primitives/src/cmpext.rs +++ b/primitives/src/cmpext.rs @@ -120,7 +120,7 @@ mod tests { let values = [u64::MIN, u64::MAX]; for value in values { - assert!(MinMaxExt::Min < value.into()) + assert!(MinMaxExt::Min < value.into()); } } @@ -129,7 +129,7 @@ mod tests { let values = [u64::MIN, u64::MAX]; for value in values { - assert!(MinMaxExt::Max > value.into()) + assert!(MinMaxExt::Max > value.into()); } } @@ -138,7 +138,7 @@ mod tests { let values = [u64::MIN, u64::MAX]; for value in values { - assert!(MinMaxExt::from(value) == MinMaxExt::from(value)) + assert!(MinMaxExt::from(value) == MinMaxExt::from(value)); } } } diff --git a/primitives/src/conststr.rs b/primitives/src/conststr.rs index a3e49c450b3..1749d62475b 100644 --- a/primitives/src/conststr.rs +++ b/primitives/src/conststr.rs @@ -1,10 +1,4 @@ //! Const-string related implementation and structs. -#![allow( - clippy::std_instead_of_core, - clippy::undocumented_unsafe_blocks, - clippy::arithmetic_side_effects -)] - #[cfg(not(feature = "std"))] use alloc::{ borrow::ToOwned as _, @@ -140,7 +134,7 @@ impl Borrow for ConstString { impl Hash for ConstString { #[inline] fn hash(&self, state: &mut H) { - (**self).hash(state) + (**self).hash(state); } } @@ -478,7 +472,6 @@ impl TryFrom for InlinedString { } } -#[allow(clippy::restriction)] #[cfg(test)] mod tests { use super::*; @@ -688,6 +681,6 @@ mod tests { ] .into_iter() .map(str::to_owned) - .for_each(f) + .for_each(f); } } diff --git a/primitives/src/fixed.rs b/primitives/src/fixed.rs index 49ce809b792..1b01678da78 100644 --- a/primitives/src/fixed.rs +++ b/primitives/src/fixed.rs @@ -1,6 +1,4 @@ //! Types used for Fixed-point operations. Uses [`fixnum::FixedPoint`]. -#![allow(clippy::std_instead_of_core)] - #[cfg(not(feature = "std"))] use alloc::{ format, @@ -59,7 +57,6 @@ impl Fixed { #[inline] #[cfg(test)] pub fn negative_one() -> Self { - #[allow(clippy::unwrap_used)] Self("-1".parse().unwrap()) } @@ -245,7 +242,6 @@ pub mod prelude { #[cfg(test)] mod tests { - #![allow(clippy::restriction, clippy::panic)] use parity_scale_codec::DecodeAll; use super::*; @@ -287,7 +283,7 @@ mod tests { assert_eq!( result.unwrap_err().to_string(), "`-1.0`: negative value not allowed" - ) + ); } #[test] diff --git a/primitives/src/small.rs b/primitives/src/small.rs index 2e39d05fee9..ddcd4e1635d 100644 --- a/primitives/src/small.rs +++ b/primitives/src/small.rs @@ -172,7 +172,7 @@ mod small_vector { /// Append an item to the vector. #[inline] pub fn push(&mut self, value: A::Item) { - self.0.push(value) + self.0.push(value); } /// Remove and return the element at position `index`, shifting all elements after it to the @@ -243,7 +243,7 @@ mod small_vector { impl Extend for SmallVec { fn extend>(&mut self, iter: T) { - self.0.extend(iter) + self.0.extend(iter); } } diff --git a/primitives/src/unique_vec.rs b/primitives/src/unique_vec.rs index 0e3a4bc3484..4448aef397f 100644 --- a/primitives/src/unique_vec.rs +++ b/primitives/src/unique_vec.rs @@ -64,7 +64,7 @@ impl UniqueVec { /// Clears the [`UniqueVec`], removing all values. pub fn clear(&mut self) { - self.0.clear() + self.0.clear(); } } diff --git a/schema/derive/src/lib.rs b/schema/derive/src/lib.rs index b3eb3795b53..233a901e5cb 100644 --- a/schema/derive/src/lib.rs +++ b/schema/derive/src/lib.rs @@ -1,6 +1,5 @@ //! Crate with derive `IntoSchema` macro -#![allow(clippy::arithmetic_side_effects)] // darling-generated code triggers this lint #![allow(clippy::option_if_let_else)] @@ -26,7 +25,7 @@ fn impl_type_id(input: &mut syn2::DeriveInput) -> TokenStream { input.generics.type_params_mut().for_each(|ty_param| { ty_param .bounds - .push(syn2::parse_quote! {iroha_schema::TypeId}) + .push(syn2::parse_quote! {iroha_schema::TypeId}); }); let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); @@ -177,7 +176,7 @@ pub fn schema_derive(input: TokenStream) -> Result { input.generics.type_params_mut().for_each(|ty_param| { ty_param .bounds - .push(parse_quote! {iroha_schema::IntoSchema}) + .push(parse_quote! {iroha_schema::IntoSchema}); }); let mut emitter = Emitter::new(); diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index b89d32ff949..b3c7007b4aa 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -1,8 +1,6 @@ //! Iroha schema generation support library. Contains the //! `build_schemas` `fn`, which is the function which decides which //! types are included in the schema. -#![allow(clippy::arithmetic_side_effects)] - use iroha_crypto::MerkleTree; use iroha_data_model::{ block::stream::{BlockMessage, BlockSubscriptionRequest}, diff --git a/schema/src/lib.rs b/schema/src/lib.rs index 3fed7592d9d..558dfca3796 100644 --- a/schema/src/lib.rs +++ b/schema/src/lib.rs @@ -40,6 +40,7 @@ impl MetaMap { } /// Create new [`Self`] + #[must_use] pub const fn new() -> MetaMap { Self(btree_map::BTreeMap::new()) } @@ -103,6 +104,7 @@ pub trait IntoSchema: TypeId { } /// Return schema map of types referenced by [`Self`] + #[must_use] fn schema() -> MetaMap { let mut map = MetaMap::new(); Self::update_schema_map(&mut map); diff --git a/schema/src/serialize.rs b/schema/src/serialize.rs index 2afe1abf1ff..de295b1fa81 100644 --- a/schema/src/serialize.rs +++ b/schema/src/serialize.rs @@ -72,7 +72,7 @@ impl Serialize for WithContext<'_, '_, NamedFieldsMeta> { let mut seq = serializer.serialize_seq(Some(self.data.declarations.len()))?; for declaration in &self.data.declarations { - seq.serialize_element(&declaration.add_ctx(self.context))? + seq.serialize_element(&declaration.add_ctx(self.context))?; } seq.end() @@ -116,7 +116,7 @@ impl Serialize for WithContext<'_, '_, EnumMeta> { let mut seq = serializer.serialize_seq(Some(self.data.variants.len()))?; for variant in &self.data.variants { - seq.serialize_element(&variant.add_ctx(self.context))? + seq.serialize_element(&variant.add_ctx(self.context))?; } seq.end() diff --git a/schema/tests/enum_with_various_discriminants.rs b/schema/tests/enum_with_various_discriminants.rs index 3cb6bb89529..b3c5ca2cdeb 100644 --- a/schema/tests/enum_with_various_discriminants.rs +++ b/schema/tests/enum_with_various_discriminants.rs @@ -1,10 +1,4 @@ // Lint triggers somewhere in Encode/Decode -#![allow( - trivial_numeric_casts, - clippy::unnecessary_cast, - clippy::std_instead_of_alloc -)] - use iroha_schema::prelude::*; use parity_scale_codec::{Decode, Encode}; diff --git a/schema/tests/fieldless_enum.rs b/schema/tests/fieldless_enum.rs index c1f506a95ff..d7cab1439c6 100644 --- a/schema/tests/fieldless_enum.rs +++ b/schema/tests/fieldless_enum.rs @@ -1,10 +1,4 @@ // Lint triggers somewhere in Encode/Decode -#![allow( - trivial_numeric_casts, - clippy::unnecessary_cast, - clippy::std_instead_of_alloc -)] - use iroha_schema::prelude::*; use parity_scale_codec::{Decode, Encode}; diff --git a/schema/tests/schema_json.rs b/schema/tests/schema_json.rs index bd1208141d6..4a98f3844ce 100644 --- a/schema/tests/schema_json.rs +++ b/schema/tests/schema_json.rs @@ -194,7 +194,7 @@ fn test_enum() { {"discriminant": 0, "tag": "Variant1", "type": "u32"}, {"discriminant": 1, "tag": "Variant3", "type": "String"} ]} - ) + ); } #[test] @@ -231,5 +231,5 @@ fn test_enum_codec_attr() { {"Enum": [ {"discriminant": 42, "tag": "Variant2", "type": "u32"} ]} - ) + ); } diff --git a/smart_contract/derive/src/entrypoint.rs b/smart_contract/derive/src/entrypoint.rs index 9ed630b7b1d..fd14ab43233 100644 --- a/smart_contract/derive/src/entrypoint.rs +++ b/smart_contract/derive/src/entrypoint.rs @@ -1,7 +1,5 @@ //! Macro for writing smart contract entrypoint -#![allow(clippy::str_to_string)] - use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, parse_quote}; @@ -29,7 +27,9 @@ pub fn impl_entrypoint(_attr: TokenStream, item: TokenStream) -> TokenStream { block.stmts.insert( 0, parse_quote!( - use ::iroha_wasm::{debug::DebugExpectExt as _, ExecuteOnHost as _, QueryHost as _}; + use ::iroha_smart_contract::{ + debug::DebugExpectExt as _, ExecuteOnHost as _, QueryHost as _, + }; ), ); @@ -40,7 +40,7 @@ pub fn impl_entrypoint(_attr: TokenStream, item: TokenStream) -> TokenStream { #[no_mangle] #[doc(hidden)] unsafe extern "C" fn #main_fn_name() { - let payload = ::iroha_wasm::get_smart_contract_payload(); + let payload = ::iroha_smart_contract::get_smart_contract_payload(); #fn_name(payload.owner) } diff --git a/smart_contract/derive/src/lib.rs b/smart_contract/derive/src/lib.rs index f1390145b3f..af82cd24fbe 100644 --- a/smart_contract/derive/src/lib.rs +++ b/smart_contract/derive/src/lib.rs @@ -18,7 +18,7 @@ mod entrypoint; // /// Using without parameters: /// ```ignore -/// #[iroha_wasm::main] +/// #[iroha_smart_contract::main] /// fn main(owner: AccountId) { /// todo!() /// } diff --git a/smart_contract/executor/derive/src/lib.rs b/smart_contract/executor/derive/src/lib.rs index 186f01e7be8..e2fb3bef25e 100644 --- a/smart_contract/executor/derive/src/lib.rs +++ b/smart_contract/executor/derive/src/lib.rs @@ -1,7 +1,5 @@ //! Crate with executor-related derive macros. -#![allow(clippy::panic)] - use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, parse_quote, DeriveInput}; diff --git a/smart_contract/executor/derive/src/token.rs b/smart_contract/executor/derive/src/token.rs index 97b1b3b4edb..52d198bfab5 100644 --- a/smart_contract/executor/derive/src/token.rs +++ b/smart_contract/executor/derive/src/token.rs @@ -1,7 +1,5 @@ //! Module with [`derive_token`](crate::derive_token) macro implementation -#![allow(clippy::arithmetic_side_effects)] // Triggers on quote! side - use super::*; /// [`derive_token`](crate::derive_token()) macro implementation diff --git a/smart_contract/executor/derive/src/validate.rs b/smart_contract/executor/derive/src/validate.rs index 7f5e59276b9..449a9dc943b 100644 --- a/smart_contract/executor/derive/src/validate.rs +++ b/smart_contract/executor/derive/src/validate.rs @@ -136,15 +136,14 @@ impl ValidateAttribute { fn gen_validate_impls( attributes: &[Attribute], ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { - use ValidateAttribute::*; - let validate_attribute = ValidateAttribute::from_attributes(attributes); + match validate_attribute { - General(pass_condition) => ( + ValidateAttribute::General(pass_condition) => ( gen_validate_impl(IsiName::Grant, &pass_condition), gen_validate_impl(IsiName::Revoke, &pass_condition), ), - Separate { + ValidateAttribute::Separate { grant_condition, revoke_condition, } => ( diff --git a/smart_contract/src/lib.rs b/smart_contract/src/lib.rs index 62e0a570e77..03c557b8b6b 100644 --- a/smart_contract/src/lib.rs +++ b/smart_contract/src/lib.rs @@ -193,9 +193,6 @@ pub mod prelude { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - #![allow(clippy::pedantic)] - use core::{mem::ManuallyDrop, slice}; use iroha_smart_contract_utils::encode_with_length_prefix; diff --git a/smart_contract/trigger/derive/src/lib.rs b/smart_contract/trigger/derive/src/lib.rs index 5c5a30e0397..71a0fb417c6 100644 --- a/smart_contract/trigger/derive/src/lib.rs +++ b/smart_contract/trigger/derive/src/lib.rs @@ -1,7 +1,5 @@ //! Crate with trigger procedural macros. -#![allow(clippy::panic)] - use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, parse_quote}; diff --git a/smart_contract/utils/src/debug.rs b/smart_contract/utils/src/debug.rs index 3164faf0645..be59f7c0a2e 100644 --- a/smart_contract/utils/src/debug.rs +++ b/smart_contract/utils/src/debug.rs @@ -42,7 +42,6 @@ pub fn dbg(_obj: &T) { /// /// # Panics /// Always -#[allow(clippy::panic)] pub fn dbg_panic(msg: &str) -> ! { dbg(msg); panic!() @@ -63,10 +62,8 @@ pub trait DebugUnwrapExt { impl DebugUnwrapExt for Result { type Output = T; - #[allow(clippy::panic)] fn dbg_unwrap(self) -> Self::Output { #[cfg(not(feature = "debug"))] - #[allow(clippy::unwrap_used)] return self.unwrap(); #[cfg(feature = "debug")] @@ -87,10 +84,8 @@ impl DebugUnwrapExt for Result { impl DebugUnwrapExt for Option { type Output = T; - #[allow(clippy::panic, clippy::single_match_else, clippy::option_if_let_else)] fn dbg_unwrap(self) -> Self::Output { #[cfg(not(feature = "debug"))] - #[allow(clippy::unwrap_used)] return self.unwrap(); #[cfg(feature = "debug")] diff --git a/telemetry/Cargo.toml b/telemetry/Cargo.toml index 6a3e7ae10de..01fd8aa03a4 100644 --- a/telemetry/Cargo.toml +++ b/telemetry/Cargo.toml @@ -24,7 +24,7 @@ iroha_futures = { workspace = true, features = ["telemetry"] } iroha_telemetry_derive = { workspace = true } async-trait = { workspace = true } -chrono = "0.4.23" +chrono = "0.4.31" eyre = { workspace = true } futures = { workspace = true, features = ["std", "async-await"] } serde_json = { workspace = true } diff --git a/telemetry/derive/src/lib.rs b/telemetry/derive/src/lib.rs index 44e50792061..779b3cdba0b 100644 --- a/telemetry/derive/src/lib.rs +++ b/telemetry/derive/src/lib.rs @@ -1,8 +1,6 @@ //! Attribute-like macro for instrumenting `isi` for `prometheus` //! metrics. See [`macro@metrics`] for more details. -#![allow(clippy::std_instead_of_core)] - use proc_macro::TokenStream; #[cfg(feature = "metric-instrumentation")] use proc_macro2::TokenStream as TokenStream2; @@ -30,7 +28,6 @@ fn type_has_metrics_field(ty: &Type) -> bool { // more than one way. Type::Path(pth) => { let Path { segments, .. } = pth.path.clone(); - #[allow(clippy::expect_used)] let type_name = &segments .last() .expect("Should have at least one segment") @@ -114,7 +111,7 @@ impl Parse for MetricSpec { impl ToTokens for MetricSpec { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - self.metric_name.to_tokens(tokens) + self.metric_name.to_tokens(tokens); } } @@ -150,7 +147,6 @@ impl ToTokens for MetricSpec { /// ``` #[proc_macro_error] #[proc_macro_attribute] -#[allow(clippy::str_to_string)] pub fn metrics(attr: TokenStream, item: TokenStream) -> TokenStream { let ItemFn { attrs, @@ -172,7 +168,6 @@ pub fn metrics(attr: TokenStream, item: TokenStream) -> TokenStream { syn::ReturnType::Type(_, typ) => match *typ { Type::Path(pth) => { let Path { segments, .. } = pth.path; - #[allow(clippy::expect_used)] let type_name = &segments.last().expect("non-empty path").ident; if *type_name != "Result" { abort!( diff --git a/telemetry/src/futures.rs b/telemetry/src/futures.rs index a18b9abec24..df723f38406 100644 --- a/telemetry/src/futures.rs +++ b/telemetry/src/futures.rs @@ -1,5 +1,4 @@ //! Module with telemetry future telemetry processing -#![allow(clippy::std_instead_of_core)] use std::{collections::HashMap, marker::Unpin, time::Duration}; use iroha_futures::FuturePollTelemetry; @@ -11,8 +10,6 @@ use tokio_stream::{Stream, StreamExt}; pub mod post_process { //! Module with telemetry post processing - #![allow(clippy::unwrap_used, clippy::fallible_impl_from)] - use super::*; /// Post processed info of function @@ -34,6 +31,7 @@ pub mod post_process { pub max: f64, } + #[allow(clippy::fallible_impl_from)] impl From<(String, HashMap>)> for PostProcessedInfo { fn from((name, entries): (String, HashMap>)) -> Self { let iter = entries diff --git a/telemetry/src/metrics.rs b/telemetry/src/metrics.rs index a1fa50b8a4e..a0b6c1d6831 100644 --- a/telemetry/src/metrics.rs +++ b/telemetry/src/metrics.rs @@ -1,5 +1,4 @@ //! [`Metrics`] and [`Status`]-related logic and functions. -#![allow(clippy::std_instead_of_core, clippy::arithmetic_side_effects)] use std::{ ops::Deref, @@ -165,7 +164,6 @@ impl Default for Metrics { block_height, connected_peers, uptime_since_genesis_ms, - registry, domains, accounts, tx_amounts, @@ -174,6 +172,7 @@ impl Default for Metrics { view_changes, queue_size, dropped_messages, + registry, } } } @@ -206,7 +205,6 @@ impl Metrics { #[cfg(test)] mod test { - #![allow(clippy::restriction)] use super::*; #[test] diff --git a/telemetry/src/retry_period.rs b/telemetry/src/retry_period.rs index 16b834c2bd1..b27d1b7d7fa 100644 --- a/telemetry/src/retry_period.rs +++ b/telemetry/src/retry_period.rs @@ -39,8 +39,6 @@ impl RetryPeriod { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] - #[test] fn increase_exponent_saturates() { let mut period = super::RetryPeriod { diff --git a/telemetry/src/ws.rs b/telemetry/src/ws.rs index d72179c4174..67579104b91 100644 --- a/telemetry/src/ws.rs +++ b/telemetry/src/ws.rs @@ -1,5 +1,4 @@ //! Telemetry sent to a server -#![allow(clippy::std_instead_of_core, clippy::std_instead_of_alloc)] use std::time::Duration; use chrono::Local; @@ -85,7 +84,6 @@ where ) { let mut stream = ReceiverStream::new(receiver).fuse(); let mut internal_stream = ReceiverStream::new(internal_receiver).fuse(); - #[allow(clippy::restriction)] loop { tokio::select! { msg = stream.next() => { @@ -260,7 +258,6 @@ impl SinkFactory for WebsocketSinkFactory { } } -#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] #[cfg(test)] mod tests { use std::{ diff --git a/tools/kagami/src/docs.rs b/tools/kagami/src/docs.rs index 0e5814a0743..737959c5aef 100644 --- a/tools/kagami/src/docs.rs +++ b/tools/kagami/src/docs.rs @@ -1,9 +1,3 @@ -#![allow(clippy::panic_in_result_fn, clippy::expect_used)] -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] use std::{fmt::Debug, io::Write}; use color_eyre::eyre::WrapErr as _; diff --git a/tools/kagami/src/genesis.rs b/tools/kagami/src/genesis.rs index 8f4424b1574..41ff4c71237 100644 --- a/tools/kagami/src/genesis.rs +++ b/tools/kagami/src/genesis.rs @@ -128,7 +128,7 @@ pub fn generate_default(executor: ExecutorMode) -> color_eyre::Result color_eyre::Result { // Add default `Domain` and `Account` to still be able to query - let mut builder = RawGenesisBlockBuilder::new() + let mut builder = RawGenesisBlockBuilder::default() .domain("wonderland".parse()?) .account("alice".parse()?, crate::DEFAULT_PUBLIC_KEY.parse()?) .finish_domain(); diff --git a/tools/kagami/src/main.rs b/tools/kagami/src/main.rs index f5f56789939..f34d3715774 100644 --- a/tools/kagami/src/main.rs +++ b/tools/kagami/src/main.rs @@ -1,12 +1,6 @@ //! CLI for generating iroha sample configuration, genesis and //! cryptographic key pairs. To be used with all compliant Iroha //! installations. -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc, - missing_docs -)] use std::{ io::{stdout, BufWriter, Write}, str::FromStr as _, diff --git a/tools/kura_inspector/src/main.rs b/tools/kura_inspector/src/main.rs index 9d705b401b4..c88e2ac7849 100644 --- a/tools/kura_inspector/src/main.rs +++ b/tools/kura_inspector/src/main.rs @@ -1,9 +1,4 @@ //! Kura inspector binary. For usage run with `--help`. -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] use std::path::{Path, PathBuf}; use clap::{Parser, Subcommand}; @@ -36,7 +31,6 @@ enum Command { }, } -#[allow(clippy::use_debug, clippy::print_stderr, clippy::panic)] fn main() { let args = Args::parse(); @@ -55,12 +49,6 @@ fn main() { } } -#[allow( - clippy::print_stdout, - clippy::use_debug, - clippy::expect_used, - clippy::expect_fun_call -)] fn print_blockchain(block_store_path: &Path, from_height: u64, block_count: u64) { let mut block_store_path: std::borrow::Cow<'_, Path> = block_store_path.into(); @@ -135,9 +123,9 @@ fn print_blockchain(block_store_path: &Path, from_height: u64, block_count: u64) vec![0_u8; usize::try_from(idx.length).expect("index_len didn't fit in 32-bits")]; block_store .read_block_data(idx.start, &mut block_buf) - .expect(&format!("Failed to read block № {} data.", meta_index + 1)); + .unwrap_or_else(|_| panic!("Failed to read block № {} data.", meta_index + 1)); let block = SignedBlock::decode_all_versioned(&block_buf) - .expect(&format!("Failed to decode block № {}", meta_index + 1)); + .unwrap_or_else(|_| panic!("Failed to decode block № {}", meta_index + 1)); println!("Block#{} :", meta_index + 1); println!("{block:#?}"); } diff --git a/tools/parity_scale_decoder/Cargo.toml b/tools/parity_scale_decoder/Cargo.toml index 34458b12eb4..e2cb948ff7a 100644 --- a/tools/parity_scale_decoder/Cargo.toml +++ b/tools/parity_scale_decoder/Cargo.toml @@ -27,7 +27,7 @@ iroha_genesis = { workspace = true } clap = { workspace = true, features = ["derive", "cargo"] } eyre = { workspace = true } parity-scale-codec = { workspace = true } -colored = "2.0.0" +colored = "2.0.4" [build-dependencies] iroha_data_model = { workspace = true } diff --git a/tools/parity_scale_decoder/build.rs b/tools/parity_scale_decoder/build.rs index 5d63316f7a7..f3bd391649d 100644 --- a/tools/parity_scale_decoder/build.rs +++ b/tools/parity_scale_decoder/build.rs @@ -1,7 +1,5 @@ //! Build script that auto-updates sample binaries from sources. -#![allow(clippy::restriction)] - use std::{fs, io::Result, path::PathBuf}; use iroha_data_model::{account::NewAccount, domain::NewDomain, prelude::*}; diff --git a/tools/parity_scale_decoder/src/main.rs b/tools/parity_scale_decoder/src/main.rs index 2f3d3a6f220..476da807870 100644 --- a/tools/parity_scale_decoder/src/main.rs +++ b/tools/parity_scale_decoder/src/main.rs @@ -1,11 +1,4 @@ //! Parity Scale decoder tool for Iroha data types. For usage run with `--help` -#![allow( - clippy::arithmetic_side_effects, - clippy::std_instead_of_core, - clippy::std_instead_of_alloc -)] -#![allow(clippy::print_stdout, clippy::use_debug, clippy::unnecessary_wraps)] - use core::num::NonZeroU64; use std::{ collections::{BTreeMap, BTreeSet}, @@ -115,7 +108,6 @@ pub trait DumpDecoded: Debug + DecodeAll { /// - If writing into `w` fails fn dump_decoded(mut input: &[u8], w: &mut dyn io::Write) -> Result<()> { let obj = ::decode_all(&mut input)?; - #[allow(clippy::use_debug)] writeln!(w, "{obj:#?}")?; Ok(()) } diff --git a/tools/wasm_builder_cli/src/main.rs b/tools/wasm_builder_cli/src/main.rs index 4ecd5a589ce..fdef78d3cb8 100644 --- a/tools/wasm_builder_cli/src/main.rs +++ b/tools/wasm_builder_cli/src/main.rs @@ -56,7 +56,7 @@ fn main() -> color_eyre::Result<()> { let builder = if format { builder.format() } else { builder }; let output = { - let sp = spinoff::Spinner::new_with_stream( + let mut sp = spinoff::Spinner::new_with_stream( spinoff::spinners::Dots12, "Building the smartcontract", None, @@ -76,7 +76,7 @@ fn main() -> color_eyre::Result<()> { }; let output = if optimize { - let sp = spinoff::Spinner::new_with_stream( + let mut sp = spinoff::Spinner::new_with_stream( spinoff::spinners::Binary, "Optimizing the output", None, diff --git a/tools/wasm_test_runner/src/main.rs b/tools/wasm_test_runner/src/main.rs index fe6bd7478d6..a2d3b5ca91f 100644 --- a/tools/wasm_test_runner/src/main.rs +++ b/tools/wasm_test_runner/src/main.rs @@ -37,7 +37,7 @@ fn main() -> Result { } let total = tests.len(); - eprintln!("\nrunning {} tests", total); + eprintln!("\nrunning {total} tests"); let mut store = Store::new(&engine, ()); let mut instance = Instance::new(&mut store, &module, &[])?; let mut passed = 0; @@ -47,14 +47,14 @@ fn main() -> Result { eprint!("test {} ...", meta.name); if meta.ignore { ignored += 1; - eprintln!(" ignored") + eprintln!(" ignored"); } else { let f = instance.get_typed_func::<(), ()>(&mut store, export.name())?; let pass = f.call(&mut store, ()).is_ok(); if pass { passed += 1; - eprintln!(" ok") + eprintln!(" ok"); } else { // Reset instance on test failure. WASM uses `panic=abort`, so // `Drop`s are not called after test failures, and a failed test @@ -63,7 +63,7 @@ fn main() -> Result { instance = Instance::new(&mut store, &module, &[])?; failed += 1; - eprintln!(" FAILED") + eprintln!(" FAILED"); } } } diff --git a/version/derive/src/lib.rs b/version/derive/src/lib.rs index f367086eef6..8d7fdc71e16 100644 --- a/version/derive/src/lib.rs +++ b/version/derive/src/lib.rs @@ -1,5 +1,4 @@ //! Crate containing schema related macro functionality -#![allow(clippy::arithmetic_side_effects)] use std::ops::Range; diff --git a/version/derive/tests/json.rs b/version/derive/tests/json.rs index 76bc312f365..4513cb72cfe 100644 --- a/version/derive/tests/json.rs +++ b/version/derive/tests/json.rs @@ -1,11 +1,5 @@ #[cfg(test)] mod tests { - #![allow( - clippy::items_after_statements, - clippy::wildcard_imports, - clippy::restriction - )] - use iroha_version::{ error::{Error, Result}, json::*, @@ -74,6 +68,8 @@ mod tests { #[test] fn unsupported_version() -> Result<(), String> { + use model_1::*; + let json = { use model_2::*; @@ -83,8 +79,6 @@ mod tests { .map_err(|e| e.to_string())? }; - use model_1::*; - let raw_string = "{\"version\":\"3\",\"content\":\"test string\"}"; let decoded_message = VersionedMessage::from_versioned_json_str(&json); match decoded_message { diff --git a/version/derive/tests/scale.rs b/version/derive/tests/scale.rs index 39c060da30b..925077b8fcf 100644 --- a/version/derive/tests/scale.rs +++ b/version/derive/tests/scale.rs @@ -1,11 +1,5 @@ #[cfg(test)] mod tests { - #![allow( - clippy::items_after_statements, - clippy::wildcard_imports, - clippy::restriction - )] - use iroha_version::{ error::{Error, Result}, scale::*, @@ -73,6 +67,8 @@ mod tests { #[test] fn unsupported_version() -> Result<(), String> { + use model_1::*; + let bytes = { use model_2::*; @@ -80,7 +76,6 @@ mod tests { versioned_message.encode_versioned() }; - use model_1::*; let raw_string = "test string".encode(); let decoded_message = VersionedMessage::decode_all_versioned(&bytes); match decoded_message { diff --git a/version/src/lib.rs b/version/src/lib.rs index 841197968f8..862d71fe8e1 100644 --- a/version/src/lib.rs +++ b/version/src/lib.rs @@ -1,10 +1,7 @@ //! Structures, traits and impls related to versioning. //! //! For usage examples see [`iroha_version_derive::declare_versioned`]. - -#![allow(clippy::module_name_repetitions)] #![cfg_attr(not(feature = "std"), no_std)] -#![allow(clippy::std_instead_of_core)] #[cfg(not(feature = "std"))] extern crate alloc; @@ -120,7 +117,7 @@ pub mod error { impl warp::Reply for &Error { fn into_response(self) -> warp::reply::Response { warp::reply::with_status( - format!("Transaction Rejected (Malformed), Reason : '{}'", self), + format!("Transaction Rejected (Malformed), Reason : '{self}'"), self.status_code(), ) .into_response() @@ -262,7 +259,6 @@ pub mod prelude { #[cfg(test)] mod tests { - #![allow(clippy::restriction)] use super::*; pub struct VersionedContainer(pub u8); diff --git a/wasm_builder/Cargo.toml b/wasm_builder/Cargo.toml index 9d1a340e47b..67876cf6b47 100644 --- a/wasm_builder/Cargo.toml +++ b/wasm_builder/Cargo.toml @@ -14,6 +14,6 @@ workspace = true [dependencies] eyre = { workspace = true } serde_json = { workspace = true, features = ["std"] } -sha256 = "1.2.2" +sha256 = "1.4.0" path-absolutize = { workspace = true } wasm-opt = "0.114.1" diff --git a/wasm_builder/src/lib.rs b/wasm_builder/src/lib.rs index 01491f00c7c..d59d7f38ad5 100644 --- a/wasm_builder/src/lib.rs +++ b/wasm_builder/src/lib.rs @@ -386,6 +386,7 @@ impl Output { } /// Get the file path of the underlying WASM + #[must_use] pub fn wasm_file_path(&self) -> &PathBuf { &self.wasm_file } diff --git a/wasm_codec/derive/src/lib.rs b/wasm_codec/derive/src/lib.rs index 8560067d80d..2562c243ea4 100644 --- a/wasm_codec/derive/src/lib.rs +++ b/wasm_codec/derive/src/lib.rs @@ -203,7 +203,7 @@ impl TokenStream2> LazyTokenStream { impl TokenStream2> quote::ToTokens for LazyTokenStream { fn to_tokens(&self, tokens: &mut TokenStream2) { let inner = &*self.0; - inner.to_tokens(tokens) + inner.to_tokens(tokens); } } diff --git a/wasm_codec/src/lib.rs b/wasm_codec/src/lib.rs index 26b80774efd..ecca6e08d47 100644 --- a/wasm_codec/src/lib.rs +++ b/wasm_codec/src/lib.rs @@ -1,7 +1,5 @@ //! This crate provides utils for encoding/decoding objects between Iroha host and Wasm smart contracts. -#![allow(clippy::arithmetic_side_effects)] - pub use iroha_core_wasm_codec_derive::{wrap, wrap_trait_fn}; use parity_scale_codec::{DecodeAll, Encode, Error as ParityError}; use wasmtime::Result; @@ -29,7 +27,6 @@ pub enum Error { /// # Errors /// /// Fails with [`Error`] which will be converted into [`wasmtime::Error`] if decoding fails. -#[allow(clippy::arithmetic_side_effects)] pub fn decode_from_memory( memory: &wasmtime::Memory, context: &C, From 2932a33889165f910d31ba94deb8cf4cbece99b6 Mon Sep 17 00:00:00 2001 From: Artemii Gerasimovich Date: Fri, 6 Oct 2023 20:26:55 +0300 Subject: [PATCH 53/55] [feature] #3516: make FindTrigger queries return original WASM Signed-off-by: Artemii Gerasimovich --- client/src/client.rs | 2 +- .../integration/triggers/by_call_trigger.rs | 4 +- core/src/smartcontracts/isi/query.rs | 2 +- core/src/smartcontracts/isi/triggers/mod.rs | 38 +++++++++++++++---- data_model/src/query/mod.rs | 6 +-- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/client/src/client.rs b/client/src/client.rs index ce4cbad91b9..706beba129e 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -329,7 +329,7 @@ impl_query_result! { iroha_data_model::query::MetadataValue, iroha_data_model::query::TransactionQueryOutput, iroha_data_model::permission::PermissionTokenSchema, - iroha_data_model::trigger::Trigger, + iroha_data_model::trigger::Trigger, } /// Iroha client diff --git a/client/tests/integration/triggers/by_call_trigger.rs b/client/tests/integration/triggers/by_call_trigger.rs index e5541bec506..90c62dc2e22 100644 --- a/client/tests/integration/triggers/by_call_trigger.rs +++ b/client/tests/integration/triggers/by_call_trigger.rs @@ -5,7 +5,7 @@ use iroha_client::client::{self, Client}; use iroha_data_model::{ prelude::*, query::error::{FindError, QueryExecutionFail}, - trigger::OptimizedExecutable, + transaction::Executable, }; use iroha_genesis::GenesisNetwork; use iroha_logger::info; @@ -286,7 +286,7 @@ fn unregister_trigger() -> Result<()> { }; let found_trigger = test_client.request(find_trigger.clone())?; let found_action = found_trigger.action; - let OptimizedExecutable::Instructions(found_instructions) = found_action.executable else { + let Executable::Instructions(found_instructions) = found_action.executable else { panic!("Expected instructions"); }; let found_trigger = Trigger::new( diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 0efbb5d2d57..39271242116 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -47,7 +47,7 @@ impl_lazy! { iroha_data_model::query::MetadataValue, iroha_data_model::query::TransactionQueryOutput, iroha_data_model::permission::PermissionTokenSchema, - iroha_data_model::trigger::Trigger, + iroha_data_model::trigger::Trigger, } /// Query Request statefully validated on the Iroha node side. diff --git a/core/src/smartcontracts/isi/triggers/mod.rs b/core/src/smartcontracts/isi/triggers/mod.rs index f8f071d4d44..f554bec10fe 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -198,11 +198,11 @@ pub mod query { use iroha_data_model::{ events::TriggeringFilterBox, query::{error::QueryExecutionFail as Error, MetadataValue}, - trigger::{OptimizedExecutable, Trigger, TriggerId}, + trigger::{Trigger, TriggerId}, }; use super::*; - use crate::prelude::*; + use crate::{prelude::*, smartcontracts::triggers::set::LoadedExecutable}; impl ValidQuery for FindAllActiveTriggerIds { #[metrics(+"find_all_active_triggers")] @@ -219,7 +219,7 @@ pub mod query { fn execute( &self, wsv: &WorldStateView, - ) -> Result, Error> { + ) -> Result, Error> { let id = wsv .evaluate(&self.id) .map_err(|e| Error::Evaluate(format!("Failed to evaluate trigger id. {e}")))?; @@ -237,8 +237,20 @@ pub mod query { .inspect_by_id(&id, |action| action.clone_and_box()) .ok_or_else(|| Error::Find(FindError::Trigger(id.clone())))?; - let action = - Action::new(loaded_executable, repeats, authority, filter).with_metadata(metadata); + let original_executable = match loaded_executable { + LoadedExecutable::Wasm(_) => { + let original_wasm = wsv + .triggers() + .get_original_contract(&id) + .cloned() + .expect("No original smartcontract saved for trigger. This is a bug."); + Executable::Wasm(original_wasm) + } + LoadedExecutable::Instructions(isi) => Executable::Instructions(isi), + }; + + let action = Action::new(original_executable, repeats, authority, filter) + .with_metadata(metadata); // TODO: Should we redact the metadata if the account is not the authority/owner? Ok(Trigger::new(id, action)) @@ -274,7 +286,7 @@ pub mod query { &self, wsv: &'wsv WorldStateView, ) -> eyre::Result< - Box> + 'wsv>, + Box> + 'wsv>, Error, > { let domain_id = wsv @@ -292,9 +304,21 @@ pub mod query { metadata, } = action.clone_and_box(); + let original_executable = + match loaded_executable { + LoadedExecutable::Wasm(_) => { + let original_wasm = + wsv.triggers().get_original_contract(&trigger_id).cloned().expect( + "No original smartcontract saved for trigger. This is a bug.", + ); + Executable::Wasm(original_wasm) + } + LoadedExecutable::Instructions(isi) => Executable::Instructions(isi), + }; + Trigger::new( trigger_id.clone(), - Action::new(loaded_executable, repeats, authority, filter) + Action::new(original_executable, repeats, authority, filter) .with_metadata(metadata), ) }, diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index e14933992bf..3edbc4ed64c 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -971,7 +971,7 @@ pub mod trigger { events::TriggeringFilterBox, expression::EvaluatesTo, prelude::InstructionExpr, - trigger::{OptimizedExecutable, Trigger, TriggerId}, + trigger::{Trigger, TriggerId}, Executable, Identifiable, Name, Value, }; @@ -1025,7 +1025,7 @@ pub mod trigger { } impl Query for FindTriggerById { - type Output = Trigger; + type Output = Trigger; } impl Query for FindTriggerKeyValueByIdAndKey { @@ -1033,7 +1033,7 @@ pub mod trigger { } impl Query for FindTriggersByDomainId { - type Output = Vec>; + type Output = Vec>; } impl FindTriggerById { From 445c1df9f1043e45a9b2325285afecdad1138293 Mon Sep 17 00:00:00 2001 From: Artemii Gerasimovich Date: Fri, 6 Oct 2023 20:25:36 +0300 Subject: [PATCH 54/55] [refactor] remove optimized WASM from data_model Signed-off-by: Artemii Gerasimovich --- client/src/client.rs | 2 +- .../executor_with_admin/src/lib.rs | 6 +- .../executor_with_custom_token/src/lib.rs | 6 +- .../executor_with_migration_fail/src/lib.rs | 6 +- configs/peer/executor.wasm | Bin 504337 -> 501672 bytes core/src/smartcontracts/isi/mod.rs | 10 +- core/src/smartcontracts/isi/query.rs | 2 +- core/src/smartcontracts/isi/triggers/mod.rs | 86 ++---- core/src/smartcontracts/isi/triggers/set.rs | 283 +++++++++++++----- core/src/wsv.rs | 7 +- data_model/src/events/data/events.rs | 2 +- data_model/src/lib.rs | 99 +----- data_model/src/query/mod.rs | 4 +- data_model/src/trigger.rs | 176 ++--------- data_model/src/visit.rs | 16 +- default_executor/src/lib.rs | 6 +- docs/source/references/schema.json | 95 +----- schema/gen/src/lib.rs | 4 +- smart_contract/executor/src/default.rs | 6 +- tools/parity_scale_decoder/build.rs | 2 +- .../parity_scale_decoder/samples/trigger.bin | Bin 80 -> 80 bytes tools/parity_scale_decoder/src/main.rs | 4 +- 22 files changed, 318 insertions(+), 504 deletions(-) diff --git a/client/src/client.rs b/client/src/client.rs index 706beba129e..9eebdccc786 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -329,7 +329,7 @@ impl_query_result! { iroha_data_model::query::MetadataValue, iroha_data_model::query::TransactionQueryOutput, iroha_data_model::permission::PermissionTokenSchema, - iroha_data_model::trigger::Trigger, + iroha_data_model::trigger::Trigger, } /// Iroha client diff --git a/client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs index 572742d85ec..9b2d676835e 100644 --- a/client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_admin/src/lib.rs @@ -104,9 +104,9 @@ impl Visit for Executor { visit_revoke_account_role(Revoke), // Trigger validation - visit_unregister_trigger(Unregister>), - visit_mint_trigger_repetitions(Mint>), - visit_burn_trigger_repetitions(Burn>), + visit_unregister_trigger(Unregister>), + visit_mint_trigger_repetitions(Mint>), + visit_burn_trigger_repetitions(Burn>), visit_execute_trigger(ExecuteTrigger), // Parameter validation diff --git a/client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs index bf54a6c8503..667fdedc5e3 100644 --- a/client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_custom_token/src/lib.rs @@ -255,9 +255,9 @@ impl Visit for Executor { visit_revoke_account_role(Revoke), // Trigger validation - visit_unregister_trigger(Unregister>), - visit_mint_trigger_repetitions(Mint>), - visit_burn_trigger_repetitions(Burn>), + visit_unregister_trigger(Unregister>), + visit_mint_trigger_repetitions(Mint>), + visit_burn_trigger_repetitions(Burn>), visit_execute_trigger(ExecuteTrigger), // Parameter validation diff --git a/client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs b/client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs index 23c5c957db8..e19a32a1f86 100644 --- a/client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs +++ b/client/tests/integration/smartcontracts/executor_with_migration_fail/src/lib.rs @@ -109,9 +109,9 @@ impl Visit for Executor { visit_revoke_account_role(Revoke), // Trigger validation - visit_unregister_trigger(Unregister>), - visit_mint_trigger_repetitions(Mint>), - visit_burn_trigger_repetitions(Burn>), + visit_unregister_trigger(Unregister>), + visit_mint_trigger_repetitions(Mint>), + visit_burn_trigger_repetitions(Burn>), visit_execute_trigger(ExecuteTrigger), // Parameter validation diff --git a/configs/peer/executor.wasm b/configs/peer/executor.wasm index 43b39134d2555d51ebc79f675f0a16db01483248..5b6263253cf65769833fa2b18c38e209bf8c849e 100644 GIT binary patch literal 501672 zcmeFa3%DIsdH+ARy=V3(yK3e_OpIx>m@wD;*vkO{JEF>wpVx0 zmR-fOD=yvo>}Oqd6|Y=$^>ZgLea=N!J@c|lpM6Q$cBc1#?~==(_1kLT>aCYN=c-Gr zgXxV8SFDU=dc~zfEnfM%mu~%o=~X)AgzTy3g@>D8X@Yg07e&FTZ9npY$glZ96b8N@ z)Ptbr`<_ZX-=j!{LC3Eztw#&}MFF?m3v2n8xF3~7fgeR`av5)OuX^@xaK){?T|CgO zt5w#GcwHmmpGU`@)zDo)!`yfpY82IKdcm^?!++EP|M8Ejka6%orV;V~#7h`no%?D3 z)NsUqnyzNVU*E6S>waB@YA&qtCjaXGJU>`WMmfaLD zsCE8F5p8t*MK%;hShH?HE2dKOPGQ;%K4z9-7=@9r(2tf_v`|#x=Qt`qh|Zf1 z4+jvoD_|@Nh3~*M_yc(7l@-O0gp9}0iFg<21M$UmPrvm@s~52{tLCvj-jc_9^~Lq* zakbN9*F1mS3e!4o$8}zb9e1^^$!B?l#5I_UF7)pbGMd~$GbgPIsMUW zLdE-&aPE2)nc}@7eB_+%Iic~Ya9L5~s%Kxa_3DeB`P}Cqy`FjXMVDND`E#G?9cVsc z_Q$_{sjKjzX7i$p5PFwfbm?<`JM>!@U3A%{mt1kt|Gng@OT(b?S9RaZ{nl&3pV{Nz z;{TPu&;PLhxBmP5zY6vRe;xcy@Sb3MbYu9f@I&Dp(cR&PqL)M;jXoZIBKn8uBhja# zFN6oePc#okH^iTecE^7f-xA*ze=NE?{%riZ`1A4K#`nedh98K&AKw}NVe;Z+NAi;7 zrOC^Z>ykf8{v>&M^0&#|$$up8j~l-$y|wQ+m$-SDpPJKE#$QEmXuPiRvG}9$ zhvPf_2a@k5pNhW}|9AXf@hclIZ)|Ve8~+zp8UfuYU#!DLqyvjy*Cy{x{yuqA{DSDRL&*n{_b2aY{7<+y{#f#_@rRNF@!K13YrM7b zmd2jOSCW5<{~^9J{)qnA%r@5yJA&n2&q z_tbA|ysNRd@rL*#@yEG)NBlR*Unl#Lze@fx`HSSX*HzqeGyOTF0uTNf=yf(QZc}?$ScF`7#Lyz!>S8ykNW z|7Cnb<5i9CCr6T*P-iC+=DIo|p&@u%bO#b1j*5q~KDV0=gXckw?b_r%|czZ-u$J`#U3{#N`S z@f+j+O5PRU9RFwXg=Ba1ndIH^t?^sq2g1+9Ux+^#eKkHDe>wh2yfgaq_z#;eYCh0- zN%MaiJDT5V9BzEAaisCh#`fk*n}5>$qvp37FKd3I@x8_in}6KAw)yhr{f)0Tb~b;| zctP{Kjq947}{$czP%Dny&w5qGP?B=h-mtxaoHsF|h{ z{9e0#OFOJocv3qMAWP7l+vPTBwI0dZWW1EVE-=uPV1Hdu)8pmk<1Ir^x7fqS+qza7 zZP^_1#hTaRiFAwI()N>GXFvFZVEMNAniXEYKb`D_EBg~HC+a4v#VG&F!nyCtI`*q~ zD(?+F>$mpfD$P5#WcjI+y(o+F#TP8of-PdfqFOyp#v0Amns#U2{Pbs8z%bu!KxQR^ zbY2#Y1-p}8EuX)+b1KjFff;p{uX`Fdd%1~qvx1vjxM@H+-AM23NxDhDDcYl{a(06z zH$~%_HP*|lnJlvg>O}*7mduNSi$eb*jp{%mwCVQT8{PILEmkqy)Ct=E4_BRM3ncI;{UN#&x6gKr}t}z`H}iWmSroR*Xw30p4#&>|JLlZ ztoOX<^|I`=r*fG+36NcNYu2Tf0Vqv1$Rl+i)7CV?RpC_JJ8eU@<7NRM-x1qryV+?s zcWZgzy5&t*+@r?MvIej2ifNeN9kJj#7Hp5Z285}&8|(godN*nt6g1Ek=>msK{UOw$ zMmGdo7n@DGV3xK5HCvH&pReoZgQqKg z{nqCfEgc`Kg6Soy(jjA*fvSe0pehS>3{?G1HBh1|>}?iI>?3M-PDFhga{*DGFGStg z@o6$x8yt?>Pos6C35p!nuM3YrbV9!S^$Sp`_EZhxFnDpA>)~*eLnlvh?;MHNf#P7h z)tZarokR;iRur0*<2@zxpQ5o(=XeaY;CN3G3T+wYc(-QtTd#3c#UxqFnTVvVdYbSWIjF#7er`1kF_Y9nWCK@?V#H{AqzKb zW1!xXkz26+W!!1y5N)~>uIR1gMO%2^|HEE)!w+7`XrFfFMygxKPrEX@CKGRWLPH`W z%bs#o=hw2+S_S$18UP&@7VTfPMFPKOW6Fyd_Y8_^h?|!>MC&2z5Y|kVSp%g6aXQ4W zhQ5tzIz^q|r>OrUiaIx|Z|tmQg!PguKWB)FYHd{$1)am{^tNw_uG!$#&=<4Gp1%?; z6%Gu9vR?YNrnFwCCEe>yXj1{jQL+w_2%NB#md;D?D8mV-0bJJYZtz>i9Ni!aiaS2d zLl{=oJR;LP81xTEHRt^hRO9Gn3yMaFqOn;m?egJ0Mml}^Fc!3fa*%14Z#1;qcQnMz zMQpv510ve#9z9C6cldKq(I$F20#Rn!qiABKNJuC)W$!{HdinQzE1rs&>}4yS-%`^A=06HkX}-bwL^0eG@a63(M4BNHdIo4zK*aQkvtjSN)PRpI^wP_b}(6AgAOxFykCZR=x7`%MW-`>)KgkdZc2^J#JR zg+!v|{e^_8$AV)mBn|c#vga0ZgPcQr)0PtJt4()*j z8G3olUT*(Fi_W6)4Sp9P)Lqd&tHlrEF+b=}bbagJKVKWHd`B>mJqncss&XQC7X=U( zVzMaMLjgBs4Jtob6`Y!~GvLbfl- z^Sj_wLqoY&EUh|}BNWUzltX?wl*7eUKIMjDdcj@jwX4E=eTMQVME%yzFX;XVU}+Wo z?<>0NgW>=M+>|r78SVGC3jmTsY-?#@pRZ-2RY-zX&r;a|sHR*h++s(=);1FtwkF~L z^pMYBJF!G}iLFvUXR;j`0fdjRo&sa7xq|g{Gi!pSFpTxH`aFCSm? zk*2kCku0kU$s9oLD{RaD>ypJ!TE??66Z4zdLh$S<6g&njXW!m=l-iXQ1Cy28+p@#B zE#cvO9%hkahbwMo7tS^~TcPcJd)?81BvtxE0@8ZvH3p>fnD?WrKr;9g#tohU3w9R; zke)`t$^uBeqXDTm2awK~1|;;pV$o0C)X}aWxU(T7TJ7B}5o4^nCyUW%CD`)ErQc{S z)!JZnfbyHjH`F9onAOhmw!>l3qA-l`_*yC@{219raJ z8;}QF*}4VC%a-z8^Cj@hxwB2--8Ityd2#_rv&bzM00E>LtIW4jXH(}9?d3;n0;AqB zn^@XDRZVCwUFh`I!{JCYyt%_osjK7wVzqaFv~0o|WGax~)R933iHtIA_48U*78fy~ttK1dP=2qZdyd#ReD`?x6Q0pfZ8=Jd25h#LmNh*USOsdPOj0NCX z$ycI252_UyF(!1>B05XJnqpW7S!gVE&58V8Lq4S0aGe4y=~C1n5PLCCHSPip&~%H2 z?nN^B`Pk5GF|hP!o56SPVR*vcL;6kD26yWhQwEdVQmml(lmqNC08!ftj+JD^I-nP3 zwN)N_4B;aqiYLZAZ>@K;CU&sRRK~bo>v=r1ML)|s08^J3*qyBNJ|qTT!J^9A%}zCL zg^XnTNGr-Qf~`#Lc&KMA&`@9z8ibI7)<@K?S;n$OAOxyEDu9m2FqUEp!sbP+ioZoXns2yg61w1IzjVrw9fl8DR&iU zE*q?r*^A58JG@df%w>KAOcuI&-|iGm(_Ckr_ce{8STsf?7gfH;zg(1$b#=Z&?OpSo z26`A%xHPAp54ZEFH%Yy^BxSmssi0POYaOSU0jTs5^b70JZ{}}2%M;?s)CS^RAYi@Q z))c9RI9w;}$=_oohbtw2XC-cXV0C7npP+N7vCey&5LA%r6v$f4Sg303NFu?;Bp;dq z^60ovrLxC|=X#->nY82RJvdH zJU^^oW6NuUUGpFV1X*VyMfZ@73D>sGg^IFvua%gi7CQH`^ALWU9 z5T`O(Z7t=ei>qU3na>+WcgDb6mGm?xYW5_BpfQ$U6Xl8M6|}E+d-L*>*rw(C2!lb*Senga`$ZR*_m-zCdy6-A9@Bq> z3522r6lHB{Om>&@dnlObF3T2l8+qF80>%DD7^-buz8$d^JqJgqrDvs-rh)4?zOTN_d5I6iEiA=;w+iyrt)r8OL}P* zpPS9g(sQ?VR%NmFthH=umTHQOAZytkxF+|5&F!%)1IW=^h}vcdBFPU7YamwSN^A<6 z>caj#{MQXe9Rb($yse!v^?E+7HZRyJASF3kZbTvfKX)19O3v-9%IQ|4I)9nQl2JI> zi?b+YN7KwYpl*LvvrZme?bdY_OV;2%yc*2Z70cJj{j0m3ZllG0lPBs5;=mo8#oGBa z1@MKTc4rHF7^`g+i^ZL9?|@?q-HXVc9!rFee_~QNsJFwbGi?p?bW%_2S?zpRd~PRl zJx=yodRtGmX!VKn0ckVGL(4!gpz=TnF>zi;HUqVIE){IBgIDE>=Z=ie`Q?#l2I`6`)y%$7UxJAyX>?VfjOL*&)Y{>+k^z*c6+0qI0#>LD?tIrF7oUVAU4u;pV_4khx)9toUvmUPV_7sw`%AM^gcK)bir2$4EflcGUz> zOz&?lHQP>F4iScyR;p;ZS7?lnEe6fgu-eiGnmso ziw0oM+TyE$ti5{n2D)zF*7r9IEQjqg^~P)u&YJx});5FPY;Txx@rTmRN?ob1+0IbV z@RRN~WzA{30|m_{UfJt7W!uYHOg89V205<{5~6Q9gH5fMgA1NBivARiJJ+0FR1>yV zwc(dpNmUzurIpOoh7FQK`?3<=-_uICjTqYpUAw)Sb{kG1R^Q;X?VeEr2V0$vb__vr ze_ZhYsh>)~wc0cEk+N1I_tDp{ou?fT%U z)oELop0>;d+6{nW&0=aU_BDd9pqfQnr8}ER&!GIH?eOQT9Y*M@u2(Luv~GxA5AGiNAperk3_$VC#cvN~Fdz6>~1_QUxfn|4o}Syx%&KZ-9=-KJW?aU!i2%$aqZJ(2}Qj{;%9+$fu;fl zxr(|ignAPv{vrW-MwC(;!O zP)ko|&mKW@dI|DnCFTWWV%R26I1#6hld6xQ9J3{1ZVV8sgOUF|4e3!LTJa1lTkArZ z9!j%jAz)!q`OeY+bp$SfHLZLtKf+wYd{5z%rlEW)REcweSu9t+!%CdX%SCqq%3br< zv1_-EWi<*9YhccNw?7#ewDSAt02Q%6N?z*W@HB%Hc2qNNnFWugvUM20+CS6E2+;JU z$D!DvYt-}L>Iv~Yn&~!6@lT5i_SxXmx6uS0CFyELL5Lcqf=W)yx9cIlW+J}j>+jcl zprO#=V1Q6##i_8ng?_V-s$B1jxSj$jgh(#Lbq6ZtYnu3ZMl-YR^r0A`pdT?23M>xVhpYEsUp^pK)=EcpPIdT zAFl`L&w-^@q0k^VRRUIyF{$z$OmmmTp@oCun=bmMEGxgQCKKpaaTiO#;|Qcs~1SW zmtuBWwvfU=Cb9{|?Lb3&3Q|z;g`C61?w?(wEiz-P);L^8-QT8K`|7<|-MQFK?Ohd> zXv;7b++OcC8Dm_q0$Jn&YB+un7yN*2t&9xA9HB77(fMHjEp`A?DA_?W%nqoLo=Huh zgSH$`hye{|B$)-4_J^Oda@|GRsyFGCjooCoseMD0nqukh4AgAA_iN?rGT4j-hwCkQ zcsFE!xV@WYL^o$Pd59yJNY@%X0u%=x8D*^Fm$koLYY0i~gWVZqr0eexg)PEbqhB_e zQ$lfrRNj(Z!REu(r=6}>yC8S5j55TJ;c4kc>Cg8X1#o3XV(ZZhegUq_bi{WjR>2rf zgSl#jgBK&J;>V^bhOR#wM(o`W(4un*b#~)(-5d)yJcKYit>`| zQ(F#$Y(qqk)^ln3kx2H-)(xQ@RkLN1=}LYgdSkE7jnqCFoj}PFaA&bFaCNO6)@lC2 z=8D!>7WmOvu&dRD&yEGxV}r;RN%Vk{KyWPBiP!;v!1DU}s*^RX4^a(`m4m`yu({L7 ze8bH+Z=GvgOe!RxaWKbV4EqN5^SfBl#)8+*?AHtE{TI+(MEb}*0hV=$-30_Fl<6-HUz z1{k>>;w+d%Fv|L4J(zJ$y%h3;0R-wv9>oKQi@IbCTkZ60P5MCKfbh{kaF;~jFCCWC zu#N0)nfA3mPFT;^>IQ$4-AM9UhjNLFLL2EXYH`h)m%;vb3I8FEo%&VBSUFp5sa*Z1 zu+8gr4_j0%F`bR_lIHsvEwl&y|B{OD2po;FN-;r7{TN z-;;EyBWZ(fL+qe3p6R2djh%p{-*ozmM&*T~F~y@kUfb~ZOYLc`4fczt!=-m88V0~g z$4!h|oWTxll29n>PF!v0)=W{TB3uFzk9QuxG=q@QAhTC#a zt)lmAH&^m8-IjRbi#^c}dJps4?Jvs3U^~>`hS}!DEGnj&Q`?7zRq*ASV|8W2HCr)<$pWzs^oSNt#c4?z@`AAUv8D>CBJxE9)2C_M@YjK};2vj>n> zLg|sh(4R|i=y6#DkkOv)PFCpmC;?KUr=@=oU` zn{#k!xl%TZ5>sZ|?SbrSQ(M#lrW9BKrmW~=N`XB?m}2v^6uW7dvP`3Quy8EG#@WbL zRAE8H&#bTzWRD69(Dy;WLR(p*nqHM^W`P9^xo@Hvz+yl(1yrD#f_{z(3jpi2PZ2B# z{dE*JGhK%?9k>4}cs2^-F*0+s87Qz7PB3d`PUI4YW}LEY4rYyWYW2WDNa0qPbD_h6T6!H;~o zOvW86kqU#vY~1KaxLlD1e;)sG9UrG@{x2_=8D&IWaLZ_*TZrOa9?^rQuF7&rw#=UQ zHpg;h$46b{Gd>8;cXaA{aDqYPYU0gQh@*(N*_q*hx&|u5@d^fGh9=e?I`gT`A{dSi zo|5?-7dDHdn6Z(4jy5H>n#X6W{IM`25$pbxRFu{OVZc#YmH-`E0yIy?CoR|rQ&7jY zpXh$$(u>VNjlIIu;_=C9FyC(5v>fpUj9N0_Ua6(SJD{Aj#7lMH*h`vum zf8a?Uu#_|eSx~Wc=Jywm%|dY4?;3^BXnG-SMj8`_TBm5>I+P-+%{6&w&KO7Lcj(g3 z-TiXiFDW{3RE0HT7bYQ@7kA1u^igkOL*R^xw}cZiC~9brM40L6J@44h3ww1*w@>8f z_Pr_@=ZdN~>A}xnAJOk?Z_$%|TynEJWE*&nUGCH69#_0q*Sl2#gv$#PnZbXVE&`IyQ9;S30A{Y-R?U80;{lz~%cxmVSPVEg7$}jn7+J z4rStV!>?uJrmtaxxW>!;o25|FgWH_w6oD*IP7}R3cxx54d{H{T^%!0t`NiG*|R{WU=A@}$E9PhGJca8nnu0b7-6dGZEV?8Gf4OpEa{pTi5tEIUNFKxkQF z>uFjmVuYwI*!lq(7Q55+BCg!U$9hU3WM4R-LM2qUPof0o(HP_;!v(7gXpnUC~w+$y(=O*XXha*a#N$lAJn182ttv!z`?= zUi&0==KL(K_IWOSsz5O*>SGg)8Ew&y{cgIF8jGk=o|*9^YS>vB)Ue+tsRr?@$7loP zaxm2kcqMJ+4ZW0<3)Z#;!!}ryX~8HXBWbP$a?8@HEQ`(7=#bMvUWW~>4LflZ09ex| z1-RylQ$(nu0$VH5h-%n7wk&ARN`_3o3qyD7GSn{69B#(oT2@iJf|^VYgjnm~6G{Z7 zdYQDG?JEUdHymS4kcnZ54QC#8$|c*}>F~k~oZ)m0w}L{O;>uyp zHZTWHY`7!ub{~1Z>+=pFJwhIS`nUt$Xu&$eqyN6Yu>-|{bZ^ky+SOr`=&ReK6Toi0 zhE_8`iyKvfS}k%C{_`W#sZz11g%!=`Px^f=h-wX&m_wf|PSK7m>h5wg7R!3>QF*6( z6fVP-;^o)dT{ni7L})jGYx+iLmQ3eKwKcT)}VtTzzn?hWFg)&^%&Li3kpHCaF|#(oXIUN0ZZ z+TaX+!nMH~SLJlw!Ew~{n5(eTRmfZg0;|>H65|#%35}YL&3PlvpRoY>AkQY=U->Fs z8Qv#$SU>g0d4+jBALAzl;M0&l6Dw3LTalu+r%3TW99!Uu*#_eco)ZmU)C|pmN za>TZZxX6Ge!Mp%kP4SM-x)D?Mc-cjz@SfesXqPuek*1rz4B5vUJyG3*SSDk zv9iRGfvYqM@lm&Kzjg8pn}&symbl|CUEAd5Qrv}C<;A4{;b}HBPBYR>NW^MmPWG}E zx~H&WwTC+v&L*E(PeaKixgugHV`^b4L)mt<#Q&@oPBGOY$nboaUR-5*ing32>x`r` zIGmp)n>+0sn7Lj~QTS!7Hu8{DbkrmD6{+F%lANba8m&C#}mYk}VZ0sx&_b^~AtOAR<;ZK{KS9hIQ51_M@ ziZt2SS%T!Dp|a%vZ0ww(aDG#%q=&$7&)Db~=s3w);>mhTB{#YoE{08lhlDd{j3>Ei-5 z6*|&*2T;6`R@&T`D{uGGRcD!hfnIL4rw?b)bfs@0FfCO|T4=u@OkaD>?Qo1u49}_4 zaZzB=(4vc*G(c&poc5@5G&Y0L?qX{PbQBxoW%LGBY)YfnTL8Ynvl25v1$np1N1VRE zBS%$=$0}|RPMfb1f7^(^dnZt(;ld5wRr+f%W4T<6rJRsMe51v#*pJvh9MbRgDpm?Lvumi%Htwx*c2Ew5-wQ^%v z=uGLE<;5e)izk#9Z{djDYM<5XifXFfQaT+xl0p z>R-LnT_J?eKB~@x1T39B)!bK;>F7-K%@L8RXAfJ z{paF^x9OK%xtm{6uWX3=YKQ8s8EEe>+(=mGzwD2$7-y-sIbgokJ%$aw&92gap{Lc} z7DRxg#Q?RyiCx}Vh)SWPzSJSdZhDoSa>0PcpE``aSZkiP(tp*g z?kTG}ZKA9?vxV~P!t^t)1;%{0yF$TBKdZKAqGwyyQh`bTjq$pX+~-E}@2ZDNf#3B| z|Jf1u>~ngC9>BBD_n&Py6(RkPvQyVuiHfaPhNUH8?~l)d#a?${!;t;ZGaNbNl39ahGcG9$361j>S&KgZcG;HpI3rTh zH!bavISHR7HO%0okb(ziSgH*fmTC{iu!Jqk8J1p$;pHKpeP{?HwQh3WqYb&2Ez_BW zg0UCj`dq@WdM^%Ey+;flvrmb}vX=Ug zg{^vT;&CtrJ!OCAwSLPFW!x&yaFWX6rLRUKNZ&8^3SBM9xR4PUd!U*WOK0CZ7A)>^ ztL+`^cq~|w5{SgRuhDBd+o|>K(66cOol#-eq?(7liG7FZ{xFiswEJBLhx-Ed!-38^;qTW- zqF-l`P(gkG>j8_;S zDz!_0{hrX2D51ZiC#nMZOru*YgG1SCX7)=Lv8Ux@GBW8065j7?nieN517L2B4eqYYdXSux%BW=FZp6un48)Y?V#5PW|_7>ovr*E;J%a>|% z<`4v)VTMypyoe@bN3B(6{0HpsM}50xoeP$CgcIW*@`0~TAL}!`<;yD!Z+W_4`SRrp zm&5RuFNfhRUw-OR&Uerdo&62A_ra#IIcI*Oys(g#CQxT#qulIj{F*t9U$dg|Yqm3f z3p=7VacaNct|<>Z7sFA%g#oJn-0V}8`nKh#o*9xV<%KqB%t7rGinG&^wt6!vE3OE#-)&MgF*`P5QIwE^~&E;!;! zx7e{1m-|Fd&Mn47k>qOwsV$N@qkM5(=;!Fs`-SyDTW$~XHK!^6-|+o059dSEfS9_Bn&23T!woec9x zzsPf^pPH7RKCQLZok$HXCh#?(q%#82jP9cJ)9yHNpgnMwd9AznN`k}booKZ<$W(a@ zr&S;aP3EUhgxQRX9Uby}5iL7u;KRC$fL$H_KxU`~#9|GlV*>U;L3=;Q?{);TlHfXV3L(YMeVEWH5fQm)A)NzatPqN8*pzs67jTAzem zxGdu;QlHXIK$42&16VeiNE}K@To23|W2lX(Xd%e2HvxwWte{rIagxm(838hbsb*)E z8`NL~^kygfwUb)u8C81e6N`nBbZ+ zfDNxsAI;fz{(}UX-lgk)gRM>QBUDOIR*XOt0;^dq;%|4kXR(-pPl?^wpD6tf>tdK{ z)`B1Sn_B?S(?*DUSmP#+&D%995TeJ z(IY=fK?xMa93e*k+qmc%U6lH~h zi?k)uefs6dtm4E(MNEqMABYTEC>>0()WP9NItRjm2dJ>s@gYXW{+#qHHZ3j27)z7> zEDaY!8VgSE>A)1XtYf{@q&iDYIxR(w4vgiMdf8DTQHHGq*q$mLY>D~ zREd>4+fiOZ&t>HF6P+COHKS)+mc%hcoRbrr6Qrt3yuoQO9!J4= zOx7a1UjOJI-WG}{9&-9)F#h2F!$%+{DIb9tf8isT5u~$VA=}cEHD+zcJqD||0vSIo z*ajHL{6a(gS`Sj0xv4}sjkK!s)oY;%WbPG z{y9pum2sO`moR|sCQwM6+t4cJN+UCSje&yYTdP_U$V~Vxa`ICnuqja9@aZ-j5tAlg$B=&5du---o37JczfXh8VE}>9G2avGkUwB`<(9D(Glm4P9A@$y zf2Wzs`UPWfl@fTljvNkh()jz2r)bYMUu7MD65d6;CU!<194VS+!#xXj<@Y;8GsR<8 zM2i82d9V8@V8iaO^&hDdEw&UA{9%T8eF*%qp6ZkUU#>JwpZQAPP$cE-a}9DJHkeBl zYb(eyH1HCaXTxFV4(|_M_=^|tI1#v*lg(J`SVicg&*Fzh_Xcn`=emO>MEoN3mGVDk zVKJ@ZHT^gR=*#pl=k6xBNm_UyQ_LFbXF?h1Oc<>z=Svq4*VD30x)!Q~d|&qYEG?M@ zNP#@#qEbFk(KVJ}hznecNbX`W9XY$z1#wGGR#3j!OTm9YwgMv?d6T)?P<7T$Hz*IEx%(?gQ(vy}5EC z?@1NOTQ&rZ1SZ}@JI_Jso2rueSl!|UN1;}09g73VT?~w@Zn0qKbUp>peqqiWhMN-0hnuY!3LDp z);z*2C9P}IGBnqgZPD|8F#fRK7=|(9k6VF#S7e2Iua67;WEJZ%20}56PP#9E0#jI8TL&pX*F7&B{ zspmoiP>0z`)>?c;NlA^lg2LG6bK-)mmag+!x|5!r=&*g1;OnrLy}*XNp|mm+zgAyn zt@T=P6$%9m*~=2e_T8a*H`aluJUd{Jp`Lrm@sfTAOnYa*;0A>1I;MOBgDr8o91q1W zS0o3(6kxy+v2_3=!~nD$(&s?yW)`NR0XH*^)^MakZ@}BANz}XEojPr*3RU-O*r*bY z3_%)qSXVh8hYMoBn(*z4DbdOX<2EXdNhpLyUtMDu&@5~0rn1J6k3A1BCY9fqPGT!6FJtF-^pGJi$QNGex#XL7g zOxLu8|G>nWs+-bjlR{9SZrOJ$+#2ARrvz(hDf(oJKOj_N-Us!|dL6`+zpuDH#5KDg zr^8wQ(70`yV0y+2_756U5C&BbSlEQIT8UXxONP1geHC_X+}Vl$k~{P9fOR2BHoOWS zvsY8;(2CYH^-*k>sToo-IF3efx@pMq3Qd~=x+ztiPI8@D>)m*q-m)FN#U=iz4>TdW zlWHP8MXjTVXy+>4t{4V)n6@K`dcNPeFu|y{FHFAUNj zfQ&S*<(5|Fb|{a-!Y6CL1F)3vhA>0>GS)}?2cU%<^|(Sm({u#qPq;*v!$; zl%Af>3Xn7+r1UI?+0vIi3r^<2VLQY~Aw-PEq_3-aw(d<P zjbo{%3NQzNu5X7S%&`C&BOvD4lM_!21EPkE2bio{WoAG zVZln$itJ#RMF5sB-veu@jdPHH&!iNbQmZSjDYRm*?0v(}7gU6d1?g*B@hWPp_M}?y zwip-2*20xPkehBmUr`6}V|y1+(FMaO!nUmUmjQefv9kAkk+u3FO7(Fd9Rgk%VOcU5 zVV}1?l-VtIjFts*6LFyiB1)6mwo2IeKWXSMWOqRiUJknTHyNINiAttZN2(y1eOtut z9EE~uvHkwE;1(nT5Y9YlM#(-KJ-}qB4sM}kZI!*=CO`XZZj5u}tD8Pm7LJ>6dZ2jb2<3?V-KtyKyQL^}W#0*3VhV@b;(2rlOTg}XuC~&KI z*x}GFJ$kJ@A_On}Gu`5oqvjOtyhgX80BN>69RDk#r;5)Sc=Y-Bni@|}D$1O3g#zgIiR$g3%mM; z^*e6Pr?y=sme9i!kLghu3+s_xPcmdaR=fpV%IC)Xfm-^;u;m;`c%c3)Y&9sxH}RFI zwUBx;@G)sz62zahT2sE8$QpBJ;ZxEEniUN^`M3XrwpV|;l-meUh=2y)$FemaBYj@2f5$s(vd2UsaD}?l>9R!%lTO&Kj<+X+;`6E;QnOj$AwcXTImJjLYT}3 zt}DjwMyMw^OBsoc%GHZ{?z~0Gq!6|(6K@Eo738tPa>7+x+YV!gvXW-vezk7UqAubd z57c|H&N)EgT;YoCnlm&5=>m6{I!yw&fT*6_2H;6apmHx*rWhtU4Gb6>ucVk^pzux* zvKd&3^M<)eRfj6ux5aSt0?9~%taHu!+NCoR_DzhKogv4ch4RxeNxVq_!RD_|4AYqe zPhm+n-0wyAAo5wH+lPa&98dp7*|RGYokRtq(kq@XZG3T#$*EI!P9lB- z4JhO2zDX|RLgJj&qL2jxY?*VqNe^`b0nJXXr2p$6Q~1tBy`V2YY)m=!4#Nmu9UWJP z_N#P1q~O_3=cSe|+VUGCScMm!TOUo`?wo(U^;|E2A_1&FX%25gVjm=i*_$_qC!j%r z$-ZH-oiD&j4KTUC;~-|Cq-Tc>h9j&2{b~&)F2v=_01YBDHqR2%a)v`hqB5Xj!$6~< zBBrGzp!7mpQVCXg`CBoyI8QqA1V=ja5~z?|7P;n`k4HQwG<(mI!nT5T^ed&I$AL0% zo0cB2Wl4SP=YW|&`(vVA{I>UL!0Q2Px@R3&pDR#`HK@m`dla4bE|)J>GM*M z|CrK8tts-OB7I!Z4=H`7!)i|H^M(+F5Vt?R|MHFzQO{A5ORHH-BGMvfZS1ETqZ zy$O<^SvnpGXcKy-8_U4iK|v8gJ18haY5T7fuEjx(BB*vyP)67GUn#?D`vu~{+LZJQ z%0SzV@`?>VDz*`Wx<$}!zkvE!O*WcV&*$fg7~J$fU98klH!^|@6%=ZCzb!F`YK{N4 zdt~&ZTbEVV$HCsm9G{B`wkP@a$FkCQq4(iBv{NSe2xRGe{gw9Rk;25o_35JvP!3ma zea@E{=IzXN1>=l^cdq z5q!puEpSf!jNqAw;UGrQnjowI`C2rrSNrW`9vw)vf|rZ6Nz*GD=5@bpiVALb(C;+g zrkd`()^cE}m(v!ExbM$STgcT`>)!&WTI=i%$HYq!j3ic8GPMLB8tT#s>0g_W*C<|>c^pca>~ zxP|1wQ~maUk=XVil{(5;NJQYd#03vcf{ZDrgSup;4~F)~mGV z3dZ%H1EW(Y`e&a=jUYif@}pW!S-gYwX%+|zT0*>b^tn436DM8j((5wqax;6#BK5@? z*`f?#`1PT?cIyg8RUOZ!sLu}Fhzf6)*4waplN#usJW{>6*2awRWGogYaqadk)#pz# zJo|P7-O9nC{EHQgjh|Qq&AvEO%N>1AnExt zvr5D9T=oh)du4|;ml{cj(DN)0EWh7Kls@KpWQoII(UM*2zO7z!!94O{=g0GsdG3S; zK~`bG^Te^je7F-NmnvE}AFmq!?+3O?2->^;Zn*hgx>ln^5_cm;g2&O^^% zVCi7Cee4Nl!bi8i>}Q1)wU>Mje5Hnllwp@6A1ANYoqt38e+;Lqkx zQ;RlFH}l;4X1?mV)i)-V@;R{vBXG7N{-%o!`({=IsbwKAj5Q9aON7(v<=WcIg3h=Y zwEb@G5Qy7f;tSOBYR}hre8%J6Fz5?y;b7!rI|e(CbKBU3)>_z?T{Y}Hnm0cL&Z$}! z5G4X;QImmA!*V5#DIlV_#8vh||X zVUrZ8-$uK+gvBu{gW#AOG{0O>AyEa)<1Od7PB;&OovY2DCw8p|sFRqMboi13jNwte z^taip;Bx1=`4ncg^gNk=k2x9}y5mf4awR|tYX<`{fCvy`iedmv-;gx#3`kNAciF%K z@c>m|iEs_LNr_1m6$+*W=Ll^4=5_JY^JR`W=3wP&E)@{BXmc!xn^5XN%XqjFEH{bB z3*LBTg*9Gj>sHt-(=Dyn`4s`cJRHV(GZ=2WR;$in z>>gfJpozQtt}kXgR5W~NoS7Xa)uGGp`z<6qD2@~i)9?AM7ng%Qs%%K=bmiw3zsEe>mhGE}uW8c8F*Q@;L?d#@APj`>r9^I)Rg5H%$_rAa z8Af$w6Q}%ZcMAR7P51_Ejq}Rvw?R=yXP69DPqo_ImwQdSw<@4d&qI7Wt0 z0AVO-cm$F%K*pOw$O|{Ye1(5qu^N6nrn^vS3U+FaHCMEy*NHBy*0s&sU|8QCMk96X zI0$dCS+VfpC zx)O7P(`g2fG(eZ6c0k}M_}VnXPm+J_Amfl*(X_F3ZX66i zc3XBe?9FT(ylh6M^=|Hk=`nC~w-j^jF@#CB?db0V**Llv-#i=C0NH!z2HEM;K=$_< zsyJil=07ub&MJ)H~sR%&`mXEwAqT`6YgD{Clk%S0691nt0=U0fl7Yw4>B3*2Iv&#$jU^dP;+ z4RrxiV&B|RU*S`>@+AvYIe}sQ7)MNcln{Mpd384G^g>(|du1>Z5oGq6Ew@i$#HIVw zIY1?xfDk`?C1v0MEhN7M2N~aY8aNJ676Ve@t!^L*stfwJnIcHF54Z=Tu@cY_HO>SL z@;l_^$CCq8Z=#Vu-v2zwp2mh5gV}FTcGbq?{X>f33Ta2KUbJj>hvWuA)$)R8Sba1g zmxwfBJ<8TalB08ya-g$Wu1RR*yKDzn<5#r(~88~0OF1*43lkfj0262N1p$PS{;28!U#l^@w-hbf=a^HP0g5~GC z#tQD4b-av~oi3O*ZOAlqg&R$`$uBlS7y;{Hftdsj`i5$xWYBK`Yk|-Kaff}?4)DCh zT`0JII?$EpQr3SdM-k+wJD~p$Kv!BQ&~(6`?Nw0O)c_xcK`k$IF&@qLLXoAx$U^m2 zd%wAn+-e^Dmcp)V&FH#UcJ25Tu}CvVYo<~Her7(gL;>I>11)`}{beu5g2DBjw#>Fv zthUx#pOL2a#rfeo5hYEwv>I8=+)MNTfxlY3hJ%mSL>3kS1-oiEI&{n3un5x~LLU|? z<$IB=nZ*_cIvNyQmo#>Du|Hq!a8%J4SBPiGLjsWjAuO$N*@?Z_f2~<|QJh=A+|qpn z%rdM2h%q<12(4-8t6*NaEER*s8_ysBgo;QJSH0hf8*_M$Lt9(1u>jAbGL=d=y-t{K zfnu{zvbJ-Y5$yuK|E!CrVmo1})ouAA@Tj}IJaGZzVF(*Le#cJd91A#@KqN!PCp@;E zUS?D+zKz#Uk(mW4O&B9mSMO9FfX&)XtUo0%{~6TBg8<^l+<&>=UKO5$H$dnQ!PsXB zIqO0+mEp3;l8&8@7@)vUYt6m5-liB@O?{fxUbI^xceDg74%Et-e=&m$ zo`dg=r-iKbnKRy7oiW_!m@`(S>%}F{FD9)>BR6ATi^Lpq zKjVPY&{7xr(_q9|>;`EdsdiW3Ocf@~rkp5~Y`K}r?eTgLy=Gj+0+Pok`-7&H_3MJu zSsNA%_lwr_)@H9}#4yGIh=xPLgi);=U9ijCaKkM(G9HL$5 zLL(Il;Cd#IjcLyTdTsXHNZy5vqS{c)^sNvl5La}Ja-i5}6aqH1yhLy)dp~ylSe!Ay zh_A`L*fJwpdG^Jbtz}eTBw{SGixlTPa`6ejHHS3+;KN3mA3ksbNb_6%c_ht8(tIS% zXVc3^(tIS%(S=6R+)48}1oDR-HUfF?M@|5Nyz5^^0(m5mM*?{ykhKvXZLeL5>S%jC z%l3K>f&7t&jX*wpBG|k4-Zc`)BY`{;$RmL~63EVXAWQm4ARoU#{@BAtAn*Us39v)n z`{|KD9tq@;KpqL?kw6{^WIV`oJD}&-A%EgwBaru=2s`9`|2h)LBY`{;$RmL~638Qg z{7?k)rye!}dFPK_Ab-n(a34&F_Vxch637oHfjspYLbMmn9-{s26FNluJwMS9?E+4t z5bYuJ?8t{a@*&R|qCLkB`Ob%pKtA-NH(5V;fqc`Ukw6{^Y)rox|e&eU5Lxg_Q(&MR?A%%r&XYU#g_lfH)W84ua-U|T1(V5a35?LMooZO*|8gFG`Ze1K?NGNxD)T-io-;a9r!D)_#8Di=G0U0tcxd~?mETI>7v1^!MOq%~ZQ$FNx4mIZv;gCj8*4@t2ki8}KC8{6p*t*E7A ziv)&A5Fk)eB|wqTH1ZQV8{r5H!Vs6UJ!Lhi-zT^umc>n*C7CG&o!02LEGd8&UM89& zznI(S^*ID<)xnsGWEHyvk+ocX=m6Dck5E=D?=-qS0+6t@>_F-8KSr? zGQ|OyGR3!&g`F5;f={)LTw4M)n99ij8!1tyc&(Z#K4XRIE>)ZrngKsj#Ru@K;6(wy zD(*P=Rq*R*@Pi-)z~bN#78H7_DW%-OuShB901UF-i zfGcA!ak>iOGE+@$*OYfIxN%&t<(=1!VY?4q(PN1pd`F$tCDUCf1gZw^TUqp17O1Cl zX30&j8}}eLeXGkM-(5&nmzy3}ISQDIfQ_qc5Ax=e*SN}6V&f`W*r7yot$@y5aw+Tu zL5c6#=Y~XGbmhJ_WH;Gt+3mBS%TRhdY;m|(b;l9NYJC>l2`37X-mVkxIOISF401%n z^j!9>#o2~O$z}ia!^X;T@c8t(2XivbL$I=Zepo>polH~Jy`XWZyRUmyj!kiz*NJyB z&B*Oha%u5k?Zsz5nP%knFm;9_ZK_e}Be%!M?JU9}g>4ZU6BZP)?}0ll#9gY;PH-P6A6BZ`)K8(RcI1mARn5Lq zJxatLC1Q^fu?Jt+9wlOr60!N9`6v;)@{#cWKO|z$5s~!8hfPG%?h_$I_+CySO>a=@ zkxo+?3q~QrqY&Xyh%hHlSvsDb52Is7W}XiNp|tII7@a9mJsl>Q;pw}&ThrMvv7HT5 z=Tr%fgo$&n)lGDE%`9h|yi-Sk1-T2DMf&%HtmX=sB}@9^;>?#=2bORM5KY%c5lKEL z%@n7!j3SbBuo;N_uKGiZNSZ?+|JTDtARj!wV5A@Kc_;VZJrc;H5aH3OvZL>=jJ~_# zoKiX?r+NlVc_Nx3izA(g7TJktk)4QEvlG$IP^QuNWM6M0IDP#rr=4*$9`(jJ=*yjU z#t~|jO?Dk&*>9n4O7Vr$4ip9W=K2*R1gJLtc5%d%{W3=~sfRUODHzhQ;Vid>USP%q+GWci?Ps z>@3e}vg7#ZA80xJBzD^EQBQj35a7y5@8gqhx9<++9(U)w=V~+%C9kok{8?kBuBhE< z(J5zjZ|Kc&!n^Dz`;TvjZ08+U?Wmma{zTyp8r52LL$CZ9pG?0~54K6CT0^hFCbL>$ z8PkEuW5F3ZhdRuCigmkQrZQLR>}QzIKKdz>%^V|5kwu=a_Ojfcuw;AdF5TPgapddS z^xjw-tmg+C+8O+ClJ**z%rMK*eqAU0Vi(C0Vt|l#A*ZgJ?Wna>*=%bpne9x@01i1G zyQ#ySBh`_0DKX1=aX#^6FI3-l!uiIIPL^Ig;Y@s0aB$$efG|F(W8O7iI_pMuyu0)D zVWs(Ey)fvpCR=RTR(nr!%f}3+EnnD9TER8$1-Fb(2B4>JW@cgjKNeOH>CpA^eD@iz zcR0G*DtLefC=X6|x0SN-Xo_pxTAYFLlUFGC*^M3SA*;P79Q|PT**dgi-DfpNB=niaCbFE%$L$>2)mb!IwH>9m5 zN0K{_%2TOTZa=TN*08;q{f-KXC`E^2*h=b%=?w~L2Lt+O zc50kx*FXE4r*`&togG^U6MTK$!FI_EjE>s8Xy=8C=IYw!=_Suz0$H_;qUh84fgZ-( zyl!pw-1+zH>CUvKhfbXq6nO_8ZX36}NY$OK_o0KNBW5|&kPcqwVD}bnwK6~b41kP`JG!D}?X2udlj6+98>%8bWrNiNeiF7!0eCI{~(Ns>zDr0i4BB?vq$ICO=o#avS7m$|I&4#7^?OpZa1U~d@(1` z7un3lWY&qoh|qOL1Z+TTnyAQD$zq+f&0OvE@~?O@8|cY;3_c%(f4+^Kv!X_{v(p2t zQP^1A2L<^t)3?`qp|)fxJ21N#lPwB6Li!p$xn}Q;1uM1tqp<&^+=tml%Dy^Q z+2r!&qH>el-(!tWvc+0hZm~2@+gY_{0QFlZGEjHAebNa9)EN*waw0=;>I8(~Gx=y3 zbe)>vH&3xzc$fy>){M4gp$j3*zwD(?Hv;HFDx#u8*i%*dji#z|B@-^MiM9$GMXPm| zCwfk0U6`>--#w96>Cg$tJZ3=fffE^mhkqI%`2738sRI!`QpoaAr8E?!BZ(f!TME|uMN)03fEnTgT?7nux_G*^m)N8rtVnu zwh!CxMYJrVvzdrlW;}xKtB4e3K5<38WL+Um)_c?)WP#{%>>aUD&JT;U*1D z-_GUh%a%V;lAgR~7q1H;7HGU?-kJRRFPm+MZOyS$pYUr%{SSN37%CpnyxsTn4mL*& z^$Is0eMDLwB7D}201sL{G#I&0oew#Ci!V*vSF?>H;NBX7u*O?L_@zhxj`y_p@U0Gg z!+S7Nn4a4%vTBu&NXi+z+B^P_NHR&WPuowLBbN_%PaA_6l0283d_KIqHiW)+*YeQD zf(ymnn$Ej>alZdP*iy6nTz4L9wl8+OvEOG{@C-R|d94@m)S#zt(uREcx)RIjzI1H| zR)W{*d!mfhvG3}^rS;QftOr!v@i|VzI764L( zm%b0F!Q=Vn`^bHVvaoPJmIqNg%VlnA+`K~osoSK7$60(;+Ksacb%^j83~Mk>MI{dg zI_prY?-#4K9v44x3BFSiri~Koihb7ELC^sfpcSz))mg7!7s`0UpjJ9qWxyEIOTADb zn7f-ZEQc>L%gEE4E1VfV>+Cd{+i~*4V2NdB3yO%yq!=mCU=A2MN4d;H?sLnP=7c)c z&n+8bc%r3&*W3k8E%D52&gh-X9FI8+l`w|l`^%1)z4VX$%J-LNip3ZIw2Q^5etgyc zo>;u@D^l;RBe95hovB*q|86AVMjOA;#xEdEpt3=&Zrny2zaQtuZ>EHM*-yKK+uc8W^M7v-cjs3}d$`da zZe-fjab_darZd5gBpl&nKY7#U3}^oz%_`u2Xb;_wCf;xF2^cQ%8@|5{7k1m6_5qgm z!uPJU*l1qh`BG3i0lp3Vf!}_=XD$~UfpT~DRHusvoNH>O-!uap^L; z9$%boJ&reS;gu11CqL`){g-zP$?{W)N5LYr_=06PwC61fqgp*q8cna&?krd^Z+_}8 zz|BL5pHc&FEwEA7H&m|Q?q}X=5AVz7&b+of9{TU#R}?PX=_c~E|<-}+h@1TOGse^>?{fnOV7_wbq;A_jgSDUNA`Dq2DrME+r5FD!F-GaH>xXAoY4`rbcDia zD`63?uAetuLzJf%7NOM-_;k=v_yZGC9JrUySIm)^n`GWpps;cC=g~_rA&0INEK#>R zD+Q7x`L41+%_B64nBot%qI?a5vp-9nXPa5?VLE)+F5InY-R(`7lbFku6UwI6+mBou z+@^>3ykkH0_v(_+2tumz+xMzu3s+PnFXS?_!o9l0 zx18?|C-UvL>{mwsHGMolD8obcgc2G(Hw?jHci4;8gwN6L1&@$W^28`2{M*ORD8w?l zetTgb(cuS-K|CUzQPvse8&uX~suiHu6=D1rben5vbL51f0p zHXv^#%}+GFHmJ4GD|_SQ6t15n$&jzvXziwGQho5qhYt2~$_&Y*QZ2YCe8)9QI+ zvtmOSXI<|;K$F%Z*SoA_Uu^=mVhoS>&VzI#_nyU+7!cCEJ~14ycMFIJd37JW(wgiy zc1Ry_Qj&3#)Jdc{TG?;EDis6A?lJ6wUSR0iIssYUD}3X@&VVNxCRq3RhQcch=IMpR zOlCrzJvJ#OVZ(QGpxAY&+IwT=1pIjz#7-pbEaL;gxEp;jNehGhePfqLV2v&emNB_7 zSf^1F2`C+z`iz8On;n$ey|4^}g-KoBi-=lX8$6M=h=I{@D)7toyu%45e9BWlwP4$T z6}tV5Q3}y|I&Ed#2@E+LEG!n3F)}JdCY|?OU>1zrg~c}3h38}q7Z!V13(|i>@j1hl zEf`0Ue+-GBm-OY#XDs-A0uU`qtdIi0sjAdbGd5_`OsqSi^pu@e$_tK{C@>Ltw0Hh(YWT88W~jipcL}#IPw4w!$EK z@kTA&-Vkon*knPYu|lXv~f%x?=P(pN`X3cF^hdBH-PL3u5Hj_h|t;HcXb z9xlj(V|pM6<^yGi`Pr&Zg@S0{ZAR)sT~U^4Q)ib?9jFQ#9utX{izG~#Nw6BGQ7Zr# zQ0t85G@yf#DD>=MA;PM@P+AR*o5-08Aa`^V7fYZk&UcZNF_E%{mmLoHCN41LMk0tu0pH&ueghk>OO}g6$vh)yY_}JpkF@4QF{bOTmNbGsDXv zOKFMfK`Nri?v~;nd=tcOmdYoc&`>Q92Bu%Iu*!RjD14RtMjlznU;6f%Cb%lRHxylm z602y_B9?-Yi1$)-n4-9Vf3RV@WmE=ts7r>hU)>!7vzei3lLo{5E-QiZ3c6!>t3pxb zL6Qc#ehxX28&D4PpbZo-GWmN$@Sf?9(S^ZBs%H8Qi(B0vGIHY|&{Aq~`g-*@Xq?*J zMC757>R2Dmi}Qw{XT+E0R?bSiE3;GRYgt1xCwvuuZx4ZWpiC5Kdrr!r=OW`wJi3rX zZ7L2m?0Pk;!%zvH)zL=jyOEJ3DWtnlM( zfB0bc(mF(^XD8{PC;Oludh)zQeo*eG(OcO}FIc!p!cq$8ne9cz70DYK5z@S;w%p@)mOCqj}r zN+s5k!9}ggt96Xj^x9%r(;6_PWVlVC-cYUowgM#3qsvH4r_>1E0uhRXPTif)%Clb5 zcQ^~F)p|6mt&)V5^z(oF&VJT0KXQa0 z@|g2|x<9Bt^T4h4M82Er^fN*<Ff>{vlx{l(08{-EEl-x=pSbS6z~M=5pMnYLUZYO1I~5rRYwigFdu zsHmw@y$F_Ak*10o6>F4KGnLYy6k|d8zCX{i*53R4y5|OnLK`FZ>>q2bz1H*ldDgSm z>cXo%8-!PT*@f3G!ZJFNaB|!ekNBq&#n6R?pCSquhw6p+x{Bswk6pSf&5kXZw;HRq z*vrzPoLyFq-2T&!R7EZxtB_P=)zLoBY(-0uRM`+l_##o+X zPpx?dVk27_pQNbJTL2o(bK7KtX1O*iT) zm20g~_2VP@pTbm$_KCT}eD$>T`P5BJ#>1tVmR#~yvjudeb!UiisaGH-Pk%*GbOx{Y zhT7&EQr`#1_scL?<0Jw+d|LL}%-?exQ+Xog6NO@o$mO^_!E2Q?ksAbvlcB4 zMwj_)tU+QNScoI7ht)(~b{B5{M)R()yF@gsPph|noKn!N$BD%HKreS?%_cW(UNK+X zyg2okZadER;OvCiXuM?Nmr3guwZgnk-2=ns3$mu0S)q1%dV-t#H2aFJ#CjUDBCStb zuZ(uJYVFn(u+VH=_)X_l)mrAd!GlB)W>eo>WOcO@l-YonsV9gc4o4hOUOwXh385w+V(0L|h%g!A`iQzIdC(;iX0E?vJw(Hop_ zttPB#vdlv>wS2{y*-QMz`MiKdfF%KF3WNaN%cexa+iAW|{0dU5#Ag^x2;S51UICPD zD9RN|@nD<9<_M6**c=k-oau(e=JsVYH|nvu2Br=-ip}wPV%sr3x1Z~`g!mlSaFD|N z+IpY{r}5_ipWI`ie4#Hq+))kBX*5?dVODk*0*KwEH4DqZwcZL%Y*&z_)nw##z72{L zT@bFHo4A0n&v^JkpA)8QA)12jx_HKA{MEU zo{BIf4@PMPNUfIeo3uV7CZ5WqS|l(D@nx5^*YDt4X()`}p&^>7^#Dl$D`P>jlQo<)f}I ztwSKdRi>FSbWgMqj2iCP#M?Vud1kYf%w&N8{o~EVMsTXnWJ$`-+cHmD#-2%Q^C)sS zK?H5&a^rLYO41jd>`he5ZSis-c1yLG3>5Vs{ANY0>Mf(tx<#o9xMt>XA&gs>>17PI zyqaBR`LKF*GLJ1rWl-Rz-U(k!*8oj6&kAsX-(EFp{k4JGP0<^(J1QNJ@qtc9I|K-z zocWA_v@C|oaIo5Q8L)i7+av`H`ck?WkP@3=i2WMdcVYbz!D2oP_LFU<0(xzlk3AjI z+B%-2<{=Ik!rDjk$Il>{+VzdtENmA()_i7{AVQWc<9kq5Fbpzd`{rF^6pRG8xZj$Q zM9%m{5y1fMVF}_j5F`B+%aTk$Ke@`*c`dPkXDlhgS`^f44Y`X4oC8+WE9HzT`!hjV zYy!pZ-!;6#<{lCA{?s~pW+fO967x0%_>5CT~}5@jVNq|ZKErq72YR-NP_+zFIM-4X2hR7RbOCg zu0HPX8+vcZQiIm=h}wg((tMPw66*$h0b3HS0>-jCgx$P5_Q)VeoCVWYEfQeC6V(+A zNS+W^f{Sl4X@o%6ERGomPA_luE){)SqWTu+vr$_ZOy98&>N8wufRfpgN+!Flm2w>M z%Hp|9_yRDhxU)0n8FQl=Arx4Ulmv^@ilj<_xsAg{Nvu1J()uQ#N~WgR{u(6%*(<=4 zL7^+x&;oAXzRD^0FK8@2hUjEEMB)hann=EhR+u@P|Zbu;5O@_QIGY| zDUE*JGvZy=fco~!g;+0aEr{ zx%1AeV(#EOowQ<5~$5<_;ffIQ+GjPRaZH839Q<1A4htm?d(5w(#gP4<~# z-w}PF!Pl~9rw?*ek%ct?2~+^FB01;zHSiT0U+E~EqN zl$~!V#-h8C3pci|sPh&BmI268;N$Y+YpokF-~=g|!nzux06&_`)e!kVpEH-grzr6B z2~8zL;H(~56x{I`Q9%7+DEQ08px};96xi(m6a?@;@1+~_n=l5i9Dsrw7mtGOqTML? zes(0eVBY4*A3YaPe;5iriI+Z<3z)gDa)I3rL_vSDfB)iP-d(gC=F1afM+AV2rsff5 zggv8=O%_pq7#8jvT?7{PjCNqbZu?=Of%Lh+gpe7FvU@KiWMr+s}x{Ux@qi2vtw{fn9h_|r6z0`2~1 z4$;yHEV%J{1B-Ngd`!kpVdBQ#2fMdbq!AQ}1;xb~Zm3}|3`sG#D&q>z*Kqf1g$wOoYtV{?FVYacz`$Cf$OXe@Ocq2~nl)1! zVT>ODCKRfmmA6~ZuyMv$ZtiR}vu95hUgFuG9n4J-Yn6rIw?=cXwcoD5AqLZ4Mwg!& zY66+}dMVmirZzADh_aBNtIm10Np$WF@bVg0Hpc%b!y zNI~UA_lt1P55RbVTb}}p4TGoV8pwn`Gg`LO`np5lfVr8W%>U8z=-C)HRqeqes;>8^ zk4;fff0&~9He(#BuJ?CJDZA~KQZiFlpdLWf+Xk3PZ(qE2=q}o=9iAqkS+Vew*5!(G zw~?k;+s!5_U2plDH!c*Sn#u~zk! za0b-j9BSoSG(p2lnDrc&aI-uki>~ZRHUXHh?`c`Jot4w0{&_ee z&F`Z02CaWdnM&BydRJZRUi|u69dsIsFq>h45fwkfqd2;Jx1FTut#Hkvx1t$~%&1A4 zv8aTu-&6Ovgs$h~bSr?g78ux4L^>eyM%2CC6tr1efAp3Rl~MgO1S$XYn^1!J^ES2K zWXZ;%w!#D@tZfq6WC!Y8B*Fws@PsNz-zLaaUdO!7aH|X@m5Pa+;jvao>T$^6w3xW=LpVIjjCHLz>Hrb~$bBk7yJ zrimmA76g9JI{BTGS$uj_B2wJ~W#VW)E3Ptj)}2d_XAhMg=TVq=Xb>K!^hg&}4)o9~ zo@)Mq*>a|uIj0!?&_ozUUY1(~Bvss~4eb#uTG_Tc%`0)ow5$eDpQga6{$_;_K2xLw z8dudBmGW6Beu#2OiK;!DsaCW`<(Op0oPBUfTpcq{Y77CH)+2;IvUQ97N4}IGI;}ri zvL}{_OZK9O8edY$M$S)?Ljm+#_ojvi`o>iT9p+CN@amXme)51<%bWSi0k2xk{HX(8 zEo~=uvE1&6uh$I0d)J+jt9_fyW;`WI#qp8`5x3dU3~>*LcZ1SL1WM8c+hC( zGyMr1b&#(b@T%6#e}2HLpe;l~5WBO5Na~cp3C0<4f^i0%kmb*k8D6lEWYjF|vZ}T% zowhX|kmA^N1cgsiNO(kx_FDW9>z`0)S)!J>q(c3y_|u&I2>Ex$UV*W=p3extwnv(u zsS$T(4br~2CJ|2v>n?5Gm$ox{iGTkO$Y)QTLW;9KEv8M);rvrZv(^WBI+NX?0rES? zX7~EtnYL1LiqzU$Q!K6eOp;)iT7mGItuzSxW~t`^5}yPvX@ChsfBISL)$%xBT{ zB*jWgWL()?U?xBB`+W2Cgm045poR6e!MPX6(+l!7k|e6YDQPKDCFShcLz^yPR+q(* z9C@a2yf@nLDrUlIdEkFHrcevFB^y~k4?Ht1i)U?RKKsBez(mU{0rzSA==K-+z5fO+ zi(f5Rkw3vYM!QON|E*)!n!sQpSw_SSB<9*+`qvqNx;XQC}btsc3t$*}6W16$p>jK|Z7a zhiQ$g%>mz+BCxQ{3-`Z<*+F}N4$`hEt3~S%F&ES%{tTzXE31WI-D<63u7Mx^oT!Ck z)1#ISX6!&k*%>xS)vC30EX-uMyZxR>W0@`B-ZNV~Vq@7VCMTMF$fGqAy0XlXNnHVPV&b|2;Dp6>WgOiq zu9kBJMfN6MglK_{u6j*j=_|(E|0(Y+730GrwklkJF?UyU^vLfN%LR$->Qg)*9ikL+ za{1XujJ}Xliau{%y#lwkF1@^OEarr-+r)?6$T2MU3Dd};S%>jsR>|osq-?l$Mig0Y zt)d>Ra~{}&uYI@4E%Ja{Wp<7crrx|a%My01PD9}gAtu^&_ zRWe^&qmBzMS$;bUrjuk%LV6mOs2>)lD4eVo>%DroR_0lwn^NPwO8lFp&7`y|AVpJN z8ol0f?99t2Th;O>Ev>7((#ah^UT{nWkBtShb*en>MTstDT9{3z9wz@~hIQbWm=kAD zp1|{u1E4Iwr>4vsZl3{*@3 zxAAyc*r%FFqk}kiHO0+hO;GD2^7ibb_HjO%;`r4jD#Nc9#>VI>yp+O3;Ocbm849(f ztsgfmPF#o4Cy&81tW6M^>;Cc!CYNjQbbiVDu`MiPkL@nGj^nX7JavLFUM2%1BDGaP zs^GYMX$_Rx7r$zWztf|6oi9=$+@qS+gM?(m5{k@Kok}v!WQ*3F&hM`a@uG6=5+P)6 zWosIHOHMi|J=pnzW9xo{niVsCpcwmaA%WT0N;|u#y;z?1wvGsq!WBlAHHt=Jvl(m8 zZS{J7hv#oAe}9s(uww*sX-L_!!)@>HGH;)5e5vTK`xfkaV;{H;ZC;)i2+7@yb-5L^ zhH-u=bYHWn)*aHS_#hKglIrZ31+lAsG&Nb{B*MLUblMgzIE~93oNl@;$`k{9F0)jq z+&VHnArhBq>)Q^P!MsE!qNTt$?W#S&Po60n8)@Pv@Ym^x2{|kbb5(Y?vqpATU=3J= zVXUgb8b&BksriBPut=`3kny!MMU`4vCVqzasi;KQrJ?9V!BeL?PqAJo@YF-0FYwgl zIg@zMnxV8QgGkq-qU*B40|hH-`!${~uKNUa8V+_-kuHwfB5~kydNMUV#!5HLrv}B) zs``s6>el^3xN<*K$o-n*hS1bg6Y}5K6a7;X(2ec}b~Go~Z}^ggl9ybik1Z7M;r$;NAZ0Q;=6JEBk3jW+KuZ^e04ju zoAqO_-n<#yEeA6uZ0|DyM+X<$*Nxxc899ps0Q1w-fRj- zuyNj@xuPNG9h$2)^wP6ZXC0j&3FoNs|8!RRVp_D$j;n`Ln)+#vxsBFf+}w>mH<{rF z@!94Fsd*wl9Eir0h9o2)Qy6WGAG~-Vr-omAR!Y!ASLdCTtkRW^#LG?tg3l7%=yT|; zl2>>@m%XzZ(Y`VHk=ru-NK8XtTA8g=E0~?`S%Tl$REub{FyWHVwq7)u>hWy-H*}yP zm%sFK3SIDAGUs(S@d^S$+`+)yjl80GJ(=6ldYJWLNmAVw%Mx080Ekp*w6Uz&_<&)b*K5W;n(D`(ZU0sH~UdZp$$1uThvxhBh4c}X~D0(#|#`6niuSb52i zJxE&M(}Owo@#ZH|-{7mVj5NC_5B5K&7bZ_}tA7Oku)Twrz7Vufb#?m5w-ipBZjfE8 z$frjUtXeH!rVaNXEnEq-yKRM)UdV%5p8WdBO|26Zu1^GlP?IlAb<=7a>oCQgdT#4Y zgPC5e%F1xzps4>8@&$xu9G0=O<*(2`LOY;2nF6-NQrZ4ZU2E$YRz?HX9VV@RZ@^Sx zK0B3Y2)y0IKz;-L&}^Pvz?ki-GU%0o82wDw@M(U-j50$Nt+zT*g~3K+0aZV5>x@Jv z-i;TX-1^5Q(}1{5Gs(%*^zt0Kki78Z=4mz$dU^u#_@m)y9R6VqOrxuF(5Q9qBo)@M zR7}m&>Ex!`2bqhQzQ&)PH3v(c0+=`rF6DYRQ>wC7UDG&G`c1K)^%u zEAr2MavqxqJXh8_Q$XIRlETY^Ur|8?`zr-uSvAe^i&hS1dv0<9s9(J?zk%W&g{-g2 zR%ivP@+(e&8CzWO3|eUGH^C>VNi_YUp5vt}p3K$hNn3&J8bL>dmnv)V>}djq%)D%Q zk{~)@g46OZ_!zie9Tscb*{5{YicMLlgRY^8+Q>&(hlD&x>t6v}IxglW6#)omlu$nZ zdvCi%V^zK$2=O+X%~K3<6n+{=2&GSFeKlx&+S$$KacV7YvZ=XmTZ}Nn(=N78TkkeG zYn!csRA4<%vRXyf<5)rq-LpvG*l32h7HP%s};JLn_Rg0mi0<_wg0nX7t<<;@0bxqoQUB>)^ zZB`eQ)t@-P+qRhjU`CYzVD2&`pdfe#xn&QfQ>BgB9*u&FEN1nr8 zUJ?3|$YeuRDt8PGA}9*u9iRmOKof3AiKU}x<#=%I+f0Pjs;xJf9MvXlkn&mS1V04j zrNHa1z47}Em`KVq)1{2~7-?$jlf6-#e#C7AC`5sKTek3@;@;8@3nMj=coh-qpS&J& z-~E7KLlTo226Nxd*eB;A2GH8x{8g!^<~uWGa=D3_v90&3w>?oxC62*xI9Q=x~~i@nk#J;1C13GD);BSULuZHHf*b zV-%Tb%SMF2zpb(zMb)*Akyn^C3|{0I2Bw_HY@H2*j;XFMA~C9v9RJd|MdOS%oISNf zX;a4r6b@x)VAO3*bO`1dq`(u~m420A)K}`Qzp{<;0FFjxKO!&aHNt-JUHp3AE)E^p z-H)!?Hy&NJul23=(oWHC-mxV;bQKqC=CIigGGlXm$V1m%vHvrb4=?k{YEomM9Dv_fNBZDw%E23Drz0Xju_+ z2U=8tF2{C8>f;w`J3sO_WNDMNp&hR+oM&Q8K~scN>oO$LOtx0$Hb)Og*f1+iw8=a< zJ!4kSoIOkUb#U6`pP;W9y%@#eYAy0gx}A0kPf!vYc&egVh;dfX=zOgLI~be3T}Qsp z=CXdrO*+jQF9yytwq1pR`jRYydPZ9PR0NM0IU@pL{joptAx_o6aDU7`HHQb=x-`-~ zxuCC|j+mD@3?IuG1DkFTDPW~-2N+9$NzKjQ^E>U+tW(zD$kRPFBbo5!an~>=6Ed>} zf;{m3T_wx~^#D#6VG>7k^-l5MO-5YEd6W# zmqc<=_!b_R6DXvT-`?IludSCk@X`%R?0D7MB;_S12~Dk)C9+L zlXl8b`5NUZSj{L95M70h(2{ zwkA~M31QQ)<;Ya3pA~{N4h_Ae8B}^(-Fk zBJ!UqnTWd)P{^c(z$ZgbnI>MVQs?>9X#ZfhY=+muwyZ z5B%|9Eg}gH8|ccW2QW{nQvoIcu-dd)#i*Fx2m!av1OIZOz%0NHyfrln;e|C6ExC7t z%aK4NPdJRiogNW~MfPoPs(!EP)H3OP7>HA3Ujkk5t83FC$B4G53Z|@$3K}rcP@n?D z;Fvu(VS3T2MsfX8L_}jaTBVBY_fieveVGh++%x1{(fI%yP&uGa9&=uV+3Um><2ls^mR?lL0y(aabCJw6^ zUIaofWt(tFd|E;vc#+t@?Ge04t=G1YDd8r($OcZ8%?uJF@=R2GNr?fhentTWDL#h$ zH~A%qV71AE#C6ngEo32^jgGuMW2*y;BeZR0E72gu3y7U72(YTQPC5Ue?3cu1%>OE0 ziY;xJIYGi~O*BOU1+BLGm~$uITt(i3naLO=ZLZXzh9(5)&>Dt=gR71HOy85?Ae`}G zt7A5^=%%J=`OdkF(>{3Kn%a3>(X(@@ z_e*X_DEd625ZLOfh1}Y1xSE(o;t5y3^m4f>?a?Z##-_#!RH@TK6~n#jH$lQcL1Io1T)YkD z6v-Wa;NlBK;9`r<%hyD8Qg=*lFC4hoYJrO@kI$ZQQBwinj;P90W9Lq4y}i*s37_bt zQ>Osrb(^Nhd&rqupVFaU%vhPSe3)P5b+8x@2_to+`LU^|@p~`7Z4ED(I@w1#HFbP# zU7^d5e*vovPC5Gmx!cFIPu@6XQ;)$IJEr|qw62;J)i2F6U&4nkt0jDB7q`vArb77% zQ+2PH6XQ^gG(TYzF`hA7BvvbTwaM^eoB8qLu>5$RP2?L)`~0~kb|I6eh;}(n#rWkZ zc7>%jlbwgpJobvIXb)Azd_4Dzv9tuQXSHXnmn+&c z*G;v2a^5IK>0v0tETiQ0Ub z@FaAdM(-j0h_0E4uG0*NP)Z;wqnL3hrt?dNGWgq2=DN*X8N*t`?eoVGzKXI z+9;3)Ea_X7k_QgLI<$lip(`TDprKnBvzYs5)FFI1JcYre1ySjdJA0wgKaCwS z=61)|$P%cEVl_z>(jK75HSAYwr0yn@NzYi&YT?(-s+PKrm=YbY$L{%Z9 zg2Ym{C+Rk!qljDB;nwl?(_j;}ljh2>d>pikNVNE6`#6&YsFf~Z806j{__#1!%GX8< z#PJoAwL+T%$#~pkp~1osCx1Y!Up_Y6nGMPDB$b} zIa5VZ;+c7+oAdbYsiqJ#x!bm@W4T%xl!W97&A{j~iKRF+C1F!uaJ|$Gu1RfbDG$y2 z@D7*^;dsJ!o9755i6E(FPBoNjmOw(VAUvd+4c0G~3_+9ATAkLoJl}n?*i;{46Q1pp+zps=OYvk6 zXWK;5vZhb-Hb~XLwq^L!rCep@#Meeucz6*016MpiwZ; zUL~V@RN~RB=}`+SdO4!Rr}^6%^?-ha5sX@&!N$G4A>i8ghN?Yy&PA{~>%agYfBT*I3DEwhBW7gRR@Gz+R(EH){7 zo~b+jR90G_Gntg~b>S=X85cSviatXOSF=CGvC0`WFE>2mi4IofeJnJ2j8YLho-CII z)A6LGbi$4&%i<0KMLT}tNwsA^@}&9%Ju7<92F2DK%N=6aK6cO#J*igmQ%@>SUO>ib z$lyUZYn<}zbZ{za@-Qu6DYo)>FHiG5>%D zHBM{yR=1~avQbUj9G!z2S%;c2duQ}{ZJq3 z>m0c${Ax2XDJBwqqeyXyPb`+#!Et^Fa0eTR4m@Cu)8bbgwMP$`$g{CZ(2Q9WNQz0! zAqAPh0;BDQMd%e;7`F)3T?jkV66Oxtj2^0mMZ59ox=rz+%X4citmHHw20HM-m z;%izSiXm^?)hm`oj5@!A)~pn<2Q2}vsl^R#!re+;wTa5L{P0j2T8MKwr`)006$ewY z7I&xmJLz)nR{FaWYf{K40Yze3+cUAb>;X=D(8MKIOo2*|HF&Apv1v9TwW|roX?vt~ zE>93BWbQeZ_|4oJpM zr~0D8*(0<&DjKW%BjJS>r^nD{unx&Ge)a%ZQm;_xOf#UqY8Tp9xl(Ir*(rr(z1NAQ z^)&xobuQY#-A-EOw@yr%wSpbhPI+QC_NU%@1IAAlXg05_ zmr6TiVv2rkAVAG883GZPq>b`eH{CcH!zK|k2>zr^>7lY^GIn7Kc84Dd%24Tyv5i?H z8POMK8#jZrdz5`i`EC@H@2^Y9b)-#JzDNtc(LiKRr!5xA3crfFw}HxxM43$(oeI!NC*FJ1v~!0KJPRlX%Ru56bZvM z_3&(r!!&s2oWzUPKc(OrT2Pc(KiZL*ZEpDUACwzPYk-s{nsK8C&gZq}M^exEQF;e^>SzLWqfymI8reFfjjqi{ zw3ffp%tb9pq2P=r}RwRkgK#p0NUV#1TJ2D7VrGZbMlegSES6n-3{b zi=Q@Yi(4Osnp+=3Wav-bb3~M4F{|kc%en^MAWU!(OM2?HP$VkGOcl=C4d3-aLIjZ1 zTIU*a1s{nY5_~}`G>~p;H%OqjU8)>U#g5?x-h2}I*PG2xNf_$0h(Z`pG<3wpptiYN zq!|2m6oU|Brx@IKIATy=>=J|aXt83@_umUCj=grLOl4V4dArD+!m*!j ztWSQ^1gliFd`l+d$?VrU1QeCN(YTI5vJgSK1P!Nre_%#>sT2$@EW{QQoCv{aa$UMh zb4ALr%@`~S;*!i23^PStnI+je{ma<`hCXZ8e#-~vie z&tgW@hQwv*0iTYPdF3G}ad((e0)*<5VIc?)lem?MG!2ONl{o=`exhbdfk3FER#q!y zZ-bSY*eyp%?jY-hE(i!V`;AbMUgul58o>J=iGgG)6m|Idu5cjtNUvvy=8&i7GYm z2|%@?C(4qN<$?|{8xgx-f=rgW85?HBxA`PssY%YfUfU$t>^FoTWyuqt!yYYGYm~@Wv0#!SQGtf4=R;Xe(f*XRA83x%tYJF858gFM-sq? z)D8!#D{G_{%EH0EMvn02!*Ri6A^mjvI^lEmWsc9VqO!I_pTpu^pNZZwqJHMRaCOR= z*-d)6{{!=s->FLo>_75z^G-cEmn(XqXv)*i%x>2E58bF2ySU`$M3(YctX>D($9=Lm z(cUyizJqN9Hs3I>Ps#v%w%nr-ubi{xy6)iebQOJ^u6w@0QijsT?z80(kiI#!u4Qa@ zA`dl69J@@G#0ApN;fIB*Tc|kc3!P(!jWUkTkeWEbh`^ zUYCQU!L!a}w-Mf7WhAkiOKwVOu)CB7@T5xv#KItHfbcMC7g3uu*jdvsm3tZ_{0TlrwoJtSUsvd51CcZKzTP$!lWbAa_V#{!vWVXX&uxKfN68~^R;ZrMGa*E zZEcuCOm}7e#s9qfg+a)h1^ZmnXj8_EDY54$|&S_JAE2D?r&I8JumRiP{!JDNZf6E&gc6zNLa(=qeB7lo4(^ zXL6-Kr<{se;NFZ~cI@&D6U+syGlD6Uv^uUYX^RSC2h2nTZ(5`W`XLViBDK~w0mFvh zx=NP}db-v%?CtLxFl+&=W8}xuf@HK>#PW;FX#{~zI7o$w1xD0?2GP$*C19m5hXR-qg zPcYN((l1Wzo?2~P7`)AC8?Omi3dQdYo2u@k`r16FvCx4^5uaG zwI{FB0P|T2#VWOSXGzAak?l12F!I){jbx`5tf6=8P3zsZgBeXT>8tK&XAq6+J(Sfp zD+CIz(`6qLIkY{JNWS}rx6o@SL`C%}NrC+9bdGTt6gAb$n6+osn&gX!^wxhztcO)D z^;OB9da=`2J^u=+2bNE#iAL4JSPi2&Xl?R|=~04eqpdS0iJhqPpa&#u!V63kYPa^i zGrmAW1A|D|CLcjij+dv5k}>K%jkh@6yq<66(HZ>0y{+SN!dG~K=>!vl_KLqNAcF!e zB4Q^}6Cgcgyv@)+$GfYrY%7vRH$Bf$oHKp_V;_3X=M4%w0aFN!3bJ!pgu8&&VNf}n zQw^YU(YU%TTIiy2X!~J4qxcXz7#WR6=28Y~Uvd{OQ16hs#Oc)1h^_Q#c7lQX^0{ zGTSL!NX8l0PLDBJJJ#B8IJ6HzappsX_754PY|H|Lcms=(y`Vd2KY{jBXdh$cr%d}h z7NmXhUO36T52Oy015RRC{pI{W6At*J$B6@Od*#1a4ycI(ObY})Aie?FoLbQV;u;>U z#Mp~!K}v*2Xo|SA9t<}`Q_P9Y@u5mhVS50w-m7R;0;0RYowWgaM7GW#9df|B$H$@$ zF{#Wh?3E{btqh-xWu#|zqKo&aqte2Qv!+g@^rPXjo1|aRGdkZ>w$z--Ed0p;Kl&hlH1*z?|2R*vTR4hglox(am z7rhW&biv{1qMfLi3#z(kr|{~K2}-$jfiC7cbWy>DQ#JN$&{;n2BQDN)yUjeBE}zwW zv@YN67>720d!4s2;dvrDQ^Q@ihY#bUnub&BkT7z>{kFM!#d#8wJDs`zB*I!H&jbfb z?$TaSKdz1t*2hs2zF_E<;=q;+;QY*XWx-8a#}vBQc`TA` z;U%q&+Vc-~l57wy95F;Pql-K5HV9TgZsl~m=|_a{{mYN*gf zs8A>~Af||zG%-?*>@i3Y84FTx*CPD;PJ-<8@0p&A?!6_ybe8qJ7Y82W{9RG*KBf*7 zRPJ=_cSXk@YBjnQK1~hvA=_Q=7(%wk3KI}Qm2Bm}2e-T8)WmUShEra`* z?`~Kas^L7G{3cHRFh{3@j-jGXM~C>g$2v+U-y9t>i=bo!%#oqw9q>Avc6W={K*8zSjcx*@&HAT!iH5XE{fJJdo%#S=sgPxx4T zA~%FUqFFj-rFB^;eMP@q{YSwmx5=8q2f10l_#hTwki;3_gNS=&)XWDTWENkdE3_+B zHo$11cJM*)!z!{LAFRi6iAsoZNu2+$!Q3)$K8Q5D34e*mLBfB|qPk{I6gG>sFPucX z#S{Qtswx27!oyMkWM_4_AE>$x?}K!jKKcO@SzZT!vAjlcJw}JR9v#{NrPAqo%!4iq zez|s_ZFfCL0YN*+>SWeLXMve!lD4$tw(6Q8H6w5L=0doTil+Gw@8X#m)}CE!B2)%} ztHA<@kIDF>HTg>lQlm&X02|$Vy3dk{&iM#)UVmRIpvjYpkaz));6l+Y@W`}KWeV&= znjg><7@32bTrOt*4!v8W?ee1N0VTTJsO3Bo)f&?kHn({;HW!VpauCg2P6-OkJ(E-2 z-=BNWqQ1|h6yGnuVBO=7#y)4;HOQ~JD971i;UJqEkek-XPhc$>tAUlFF`_;EnZIOi zn?IzA8;E>n2Ff(x$nM4M5_C@0BStF$C2+|xd!7U@^eSNmbC679Qcbc%RrUfKuWde? zj1+o@Y&CDB^;`T3uC>;G<7(x`==yo)fJ;QTy(?l{5|M)CWP<3x876JLBw8aHUz{H) ziNPE!ZaG}etJo32-izr*>$ka5|K!VwiGIswE9qA0mD-FHeI8gEe?cgj)EE~SLFm6o zuy6mBTix4#(|ZfF`gp>{jK;%-)k_ZxR$=DiUns18_po5~KOPfZ{g=oWPg1&i*?^HE%-zdVtH+ zjqws@i@|glS*Mk?=;6NR@Q1r)@NmnX4-y4G%d!6H;g9vTkLOq+hSwFuaO6>Y>7e1l z2!Zr9LA=M}2p*qkv|eum-a};VY_n))EzE~Uq9~(Pq@C8 z6d+27WbY*UX6r3E>!tR0F6k3%o-Ze|mW1qE%mqcKtFdOAKlC8E6tHC)JQP`{8nV}% z?GIp`u3YSc<*Cc{{D%ZJJr~0+oObZGCUr$>bWXdS`YB{FL>CxMn z?0NafIh<9j*(n&E9ndV5gufxc8Zr$ORJFVZg;5Wtte~0abRsqkvw45IrxdSN>;Kd0 zl$sV;@^{^))_;|Wp*?E1go#Z<=ZWVMWRL%57S!jdwCkup;)lKD!Y_rRC>z} z6yvQIaAC_&SPZ}cXaJUlJ<3j=9${ZOCCZSvqAhor461Co!;0c_v`(P1nwJ7?8biuy z-yPna$ej6FRUjZ1u?JuX7 zSg*$0OIk5Btd3c~3~0UOHd)t^_``Z0NA6#*cD&U1{W{JXf?-WRYM`*^R1Z)vhkBkZ z1gIDn9tNo2`Iio;7!)1`sQ>Y(0rg)ZD?GU=Dn^8d0qW%?pk@(|mF<#i+FzUpMKVbG@L9 zao}N~{GTN#7gl9GG*{5Y5n$hg!TTpm@k8{> z`cyG6ilA@L==&5V+&f_SxI;vH7Yl(-Pp|~tAY}VEI>oI&>vVP&G2SBTyO{BA893gu z&x3Tm_XTwS3X_9#YO71o`@UVwe+Rc8PPtPkxeLEk4yPYL-x;d)x)K2kl{8gCKrrK=Ua z@7zJ8(Nk?%ZG0wyMsdP6<+@4+h7C4EIpLTO0(c7S*7DE6N#;R|X_Ca08!VDMzcZ{` zTa~OU*5cIi+v9OoN||_c0+N(+qil}{x)4dqtvBplRrkKYoWs^z(1uMyzcr$@Y}1sp z=qgW}>~Ee-9M^1Xi<-kpN8bOQMWq9?7m-%85kKZHarMV79eLYzi~2t4$bA2?rXy=p zp`+=@%$f{LFpe>212xh$=2G-eJvo|=teKF-!Rlx_^5S82G#z>IusWKKT&4x}Px6cr z=*98r(RAct@Qh*T#liDvI&wc=?oX*l(~iqxO61eimyC?8i-EE!iP`U-D8E0uPlh+$Pc#&OUDt!;VSgzq<=IWxpg!h zxyTk@EJ=C<-9+=?H1DJ7$U%9zJ@VvCN7kl*N7IpyrX#ag=Ai70B9D5|jI`%bKdOw! zqU};LbxyE&+nqD?{tOeLGEd{r%8Z2G?3|Bx%&)X{WgTR^cm=3F?3 zHU@(=gKXIY0~S>rO-Bag3xhJofro+eXgYFOlidlZqv^s4XQ$5)j;14<1=$BOM6|I&wJd!l`X|I`T10(GCBXPliKi$iL1{@_mF?{Km;Tg7w&1 z-OpZ4niG@DmvbI#x}05Vv66Lq?2YLJhZ}^OtJ8^P#m)QEVlU^VR)Dh|-k(k^?N?y3 zQed)Qfr&~1I|0@{UipMq@=rATwXmep!jgUk#w!KJ`xO|g6d3DQV6;*IwO#3T1~>8QGz*vL7lvZX`O50qHR%Az{O zsJDQ(z{fsd6YaePlGwrrY#yF8e>}jpd(A6-z$FLg<*X(MtFEv|oBkT0Yte;LEl%-mb;42Dwv!GU zy+4mPH}4Fo{wiu`3a9e4X@AJ7}^@J=!2;Lpq$7MCP!__4WqtZVIeuHAq9IBeT7 z{n^^5Ts!dT5Fa(6vxnFZXQ|Kk`wpmks#w&bC>yOxYmasWkK=BghAEoSq0QPosNA|; z$jP@{qJHi(Jo%Zv!W|pU@JERSm)oJu%ecEc?iQpE2`)k`y9L>ywh*JyjZVQb3K)3q zgAJCs{U9HzUNVKtdzzt!0_c6NHd;CrAI;n z=Ub08Z0$cTbZP|vA?3qPxXUI|l4 zAPDUfbynvxBTn)ibW{~PENR&dXx8RLu)pt6WYon*Ng~T|vIAcQJO7!Z9p=*^$I4OE z(_=*Xdl)4%^4bUHzz?-a+*ZNZN_MeIV3?xUpvh^y&4xt9PF2vGI1cZheHyOD;-H;2*-}Itot&9 z__;qb3^|N%OSd4xSD9eXP4-t6JvIZ2`-#N;JKaWX@@d2u_JEi+d_(!!~=q{izMQp*s6x{_zD+Me}VFeT~2%1}A3Tq*TDXhSaWdVgLtUwG?bQh>s z3Rsw;yMV$J;S+XM2~$|nE@q3pu`oq<0s7@_#V|#80fi~7g(6JR&1|xeD$G`UJekdS zZk>3p!fZ;^?hQ}KKJ8#On9P_BU)`7u=7ZU4d9BK9PywfngAa;udjNQ5mh~2^`?5e_URfb2M&mq+!6jbE*?eC zuV$v=SWva3Q}V7^-04K_@pvZ%c^kZ`kL+ly$?gc(2QrQ{*EPI7pJwX-P4jFbh6V_F zitE44j`9N%7j^Sv&R`reob4y>o3OL}h{`vUG^;fljrvHVVN=M!j5aF}Qz)iJh$wb2 z-(nBeZGxF?cWB<8>U)SdaPrk&7PqdJw@pir;c|Labq*HZk zXV{#myMGl54DHQ8eeAYfHalw+0BMX91?%6jM>on^6Qc_f;(HqHRv1egg44wkSVph4 zEgHoEj7#fQUiL`g=~}MyU$rZEpqy2d$DSl)9tJ_pP{+GJPb8LrwXy#kO)Fq6GK1ti zUR~1}z8SA3O56vIv|;g7ya>@~XQA;an-`Vbd=3TgNH==C z&LAVnlh4ixBJ(DA^4$%FzFUtGxHWB4q@9+au(KzTiU<`W3*In0A(8;WRrDU>JPJK7 zDZ)sfC)V5!aJM%RGw1|Tm*U}Xt}{pxS8R}!kNOni2(pSvL=M(P)*>_uLdx&v&Y)a; z8SYN1La5en zNTKL=G87qB_P}XR@6TXG<#rp7I z>s>tc`sYkavO>myaEhlh07}A2Dp8LlAXVd9YX<{<#Y?A0pw%<8&6JW~Dls6nYGMe2 z(8NYs3uK4`YFZYKkZ9A)#%x2=QMG(q_gU5^7@=B@ONi4IGz`?mnAEnjtZVsB>czZ2J{H(DzA&rD5gK_Ne;;4RFfMfwlulXm$7etYh>&&xdAP! zXkhAEe!VGBq`Sy5ajQoXI(b*4b7q4L)G$txw4E?mTDYze&&9C*%+roMB@vwE!KQX) zcAGG4W*f5_?6%h0Fv)O2@EW&Z)6~dBQr$RB2#KqNE5oJ@B(#N$kuC&}HwY!j@76~g zKxTjy5+YEntf_pj0k%T1xq=~*NI@3y8EDuT9r7@~Gpma-0@X)tR>kpeCtUDSu%gbT zfuxL7#AU+#)<$lW8BN&r$V7pHQ76#Ebb|vjwwa=t$u4h9)6C_8BDeCZT9?|rj>@1v zTXaLA&7qKVlnP0!`TT?TQ)E0^lZ7a#oIl+VA*V*n68d&FyHp7f;Q@bB@Ds= z4u-M7B5;#`!S~#|#FSJp1tQUiIv&DZs2-*Q(HtrdQ>o>T#KTm;+)Q?JW7;}5lL4DF z&n`qG2&G%#-M2)V$B$){QtH;}n~F|rIEGwsVf@_Lc~{^96rD$`7$T=fYydOawGHO^ zc{qcFkt;Bh%{5wombMWcZiFYyb{d^m44yoFF7k_NBdw1EK#3jw-JNPC*qbt|o2HVs zU0vJIt0rfHyfw{lqwD#yXb}*!h|7sm@x5bfCzd&)BM^@-y#x-6B5oiq6k`M|Fll&6f0(P`mL`>O61ZuKj^N zQ+DnDsLCw?0)vKQ`}3D|-uHUy+%}}n|LXkCeX8?ULm+Ki)0e~f^EXiE3q$JsQ772m z_(tk{X-FO0x4rz%e$@$JLrF-+6c`mq#G-#veC8s}*(UjptyCJq*Rw&IKyIPdH&yG? zL%R3Mo@&=zMzuXds$E=Gy96PuPTsG2e?6q$=H7are$(*5y{fm`E8k4DVN&Qdz4h)? zy*r0=b4zc%?Uz$;2;%;XP(v9aQMPw3ryWrX1`b4^(P z%&f)5PBT}DZ(p894_SlSXZdN^oo<=zGruK2Rlc-d?=%qHBx@wriobe2wscgHztNF~ z!dKWi*@R5h*-*IRyU{S;nB{NU`Xr5(scT$*D^*lSVTd?31fON$VBMO}Mn6E21`&KV z`rSH*Fnp~{c%VP~-De{(IxW`-d(7)xtLAAkcx@mI14K^P`Feh4_L4q+nugw{WLOY~ zG{(|ac!GwF0P00rq)@CfTI8ScRr6)`@e!gf`~g5N*;h+m>Oi{HmU>h1 z(#$sz2+TzzG1W6~3y@ zd^qhfw|Ax$AMIo0jr!Sz+H^rE|3y175K^-i`M~s8>s-v!Gb(vz{ai9i#ym5ljMf>N zodq)Hl5U`P3^BN7w9RYgM55odqVx(ybtHBTqPabED{Z}lG54Xle2aA&U#^T4la)z$ zPzqB>StKPcp>&aY(?N-%Lq!jSxGp+`0PP9x*mgcAN{kFJD0=V`icxKc@fezsnG~ixU$#*@aQJXyWaLw zAxq`o_K6(m#K>7g_-bWCdfWiXwLsjUgGeDI4sB%WE)wYuLCMD}(xh$PGcosQsZ{L^ zrqVIRl$e*QL_}PQ944)5PU@dAt(xinIMC|B*(X1(N@50q+LuvioIc4ZJ2;VK;!nawN1cmS&FF+L| zw;jT_tRdmsS$IvYOZZxF!3lb_D{#9d3SYMgB!Eox>ZD0SY*cG@f^Em_w7OcIkyVt6 z`Dn%{TrCpzk5-i29bm876TyBDzxu4Hy=+}H$1+8(V&Gi(k?z|Yz`s=#CyT7qWYXpX zbRV^YMK(vFvdRwbx|Ls4!t_bP-6A#p1f3R3uQ;g~O;xLmK8d2D zRkjWLYw>28O(gGTR4Jk8NQL>lJ*XT#D!S{VBAxV%G%#3Dk}o8{OD<2#=Cw zuaM_MmpGBtc7dMQ4m~pIasgSf&)6MSJt?MdaCWW-&eKgaGRK%K{4x37rf3b${tYFv zC`7D}N2AgYC5sl7Op!8F?H2Op0v`~S&XksTGDF!Mr<7|M3=GHHtzzgg*v&MC7xv!r z)HICOZ5Xee&e9_JPd)9g$`8{4lC&erUvirW!QCJ7ZY*l)%ocqaLir$d0JBl~QMf-I zu`vI~Nej2!9S1t#-cXh74#yq37SH?$yF-!$#w56m^tao0u^BCiEa}xkU%30xqgaPH z(5(IHYbHvviMrfOY?Yr8|MjsOqnukLu~if;9jJQS6-A5l*X89j&&(DQ_oMAGlloES zS7;FSYg0Q4{B@hUNf5KdD6mt3Dg?2*AVAo+q**Dw&cd$okaYoPTWx4N(`gpOXc1WV zRH;jRsPR1%3{sB^2^d?jWC;)^VD8<~OLLFEII)x0+BP%F^r1~KMX_$viO9Bn>L~(N zBSg%Ou?%dia~as8+;f(Jnal6~d6&?qd94#Gluw5}Id9*tn3ED6eeB7dL&e}rEDR*x z@~QiM76#JzhDkxy=^{*mJI{l{g7imKtnQJ5viK;rR%@{;-gYNJ4G@Bb!FQ0+#u@`c zKm~SM9_`&`QS)9YC@_chSW(!lRnIg!BS;+Ebf5`xuvB^dgF@dkUAMNw`dGat`L8`8 zAp%8dJIvaDm+XI!2vtNN%jP7quQU4y?oxV8tvVrJC~9?|k{9TAM^=rN>Uc4VbuA@q z^@*0Y6fK>vcSlR>F_ zy~y(+CHGe6oP8!^!zObTNF;f;uQt0NIrfJDNWyL#Fz>O9Wo}LfS5C5=#ki*XS zATj9BHXo;7mMX>foB5oj?D@p7X@C&HB^3eM^Vd_O(WUAA^{=F)buMirjd~+(G;>19 zGue4co*JWx6G)y~vT13SX5w+ZIQ|^VwSn{y|8_|p79I0EZx4}fvnS6h4L^?;l9Awx zF6B9T+JutSY*jOwZ8lSI7j<)b^2*E-b9NglXur^$^Y(=HqlY8^Wvg-`42ir=TW_~j zm9-qCccc8_Ya+@+5{qGc&bsRur)Qp%u+zVqfB=1Cu6}qq2_hqjMl*yRSQeMQ+u+7m zSgXz79vJPdMKo0`Lx4Ce9)qb#5@l&rvYOmU=1PIf%xp z6h8;W?;Sw#kenzU{B}_MQl2eL@v6~9@t6;+<~E8~*03l(GTI=D7s6zA9IQFTEBVnV zz6=Wq)kg89wHhg&+JWN5DPxRHnh8E18*ll)}?1`K;QkGF?pmn>#I~_8? zAt>%2M@i8}gV$?~+KAzEkHP4Uz;m)$cH0wlbQB`Fvuuz4*#$TDXda*eAC{@NoxCUz zI#vX==lj6AwaozDTSDo7*1Ts)RgVMj9lYwu^PUAO4v+UBx5a3is*+iV~ zRT9CNQ`SZN1_EiOt62`ihDTweR=>Hxy*9t0N{ar|xyU4KG^f&NT~+K{t!XOlT=F+Y zTgRyl<~^m)ON-6a8_H1PyFvDzzeG+*V$9d8PK>q+>2+e3^>JdB$%)zbsGXR(Ya?CI zhrOi}QxPy4vV_<$2L`2q15;mw1G9JdNBx6^0~6Y&k6`sM9hk9*v)*6-iaRjrXf~Q? zg;DTQWU2-)MVBZx{#Lydw;y^WAl8F>DUxgSmcNp2on8t;-YjpG*=?|<{lajC7I;qk zRm()S_%12tUA$e;OS!49mm;-a(HS4M@t_B**5wYA>h<)$OV?r)mAdu=(Yh4X(igE+ z1lz>fljFu?0fy?XD~hTzLChoG4VZ;Gkxkdfotf(fW;t2dsYLW82R1s|l#L+lE(t(3 zV5^KPGRh26G=SLLnl2+xgAIxXYM9AzYg8<_HJXPMC_<?jEr25nj1wd0^Wggk3F5a=yrcL-z*GPLLVD0{+We7+(8ZnfJ!0^k$9#`dnN zvHhvS*tQ<+p`DIN!`=3vGHEEXa5F6?y)ayYsxT_DAw+9kdclUIX!jM`#JUA zd^x!V*29I}0+ycKAn9OL3%7vr;8f_T1CuU<00N*eHBuGvsF7sR7%s)r(neNGYN@#g z(N3z|FiMMc2Ybqu=!6ymheB9f3|VRc9l_<8+em}Vqo{hPBv}g!YSsqSqj9z1&;Rv! z9*_#kU{K6UJPb#4Mg#FTYvO;iG`eG6{gs34gPe{UydcMcg6X!QF|Wr=vL5r2 zInhVt7?;4&U^*xl+rz-*#X#{S&k9S5U}9`qp8jl+#zvrldYxR?GodV)>7}$ zWBSBji8Gs^C~S~&>jq(aZ<@RH?ei6UiwO&#FwpCLkSue#(b`ACFhj`9F!Qp?FYoEg zy~FzwzUs3i-m(~(yMxYY|_mXquFV1Aw z@-kfBoi447rkRUQFv8>sUZWQw-J6;c8>Xi;=nzoyK#~TVWB1%9;bQ)!7idCo;wLCchk{i)>gPyu6A`_$Mp`;U|XesN2F}F6fHstKM zl!q9J6lX2pE>A7`7-5R&a*3Ma*#RpDZl^stOSs)*&%k8FV=zpZ(Jr325U$`~Uco*x z=mU>}_ppwAA84l0xrle6c@89%{n~*@BXXV%)O+KS0>>(I&Lnk7JM}U$?R_rb`Cg+tVhN3j$^>JdAM-XOt?xCjTT(+J)Er58 zWG1Bit46OQd6VcJcD_NsF#Vhwr=x=%Nm0L?n4MwE02%7$#FSp4*kyntN$udo9Dqp6 zDq^Q@Yr)vbfu_#eqRxGF&5(6Fk~@8gKJ;cz3`?5bR@iIM1g!;usJG^`6i?JyGE&Mi zaqiaH+=!rKhH?M~1h{|!leY_EAX;m((gFsy2MlbhU|^6VDJ%&GI|2@N0lh9qQadsX za3rZ6aIl9$r6Y-i=y4?HLvI)yQl(|9WE}_Hj^qx*fk1CK*cNdBOe$(~zxeFlw@Pa5 zGs)`ffpqCo3w*nqaSy#g^7cxtuQy!m7g|gk5`_B=)GtgS+6~cm z#tXbCI_4fH_H#9^uI-e2jqk~T3VRn&q0RbEPZEj!iN2L4`cxuYqu$o4OQfzgmM#*A z>$0@=Yl}uV&i3gNxp0?u^tS!dErnRu=tMKrDtoYt&+7R@s8!nx8bzUe01Det0Lc%! zBDQS(t_|S>pVjjpqB?DMl zX1Ga%+y4Ox2OB4Y>whrAaX!R+^ZQj6n@1x&SUH#>Y;IKy{GeJU7j^Ru^Ndj4)jn7C znQQ`e$ z5}$}$Np=^&)GG=oUgw{%P0Njy*TIR}6r~DB_pJDDk7?VfKj`BvQ{~=qH|CUzevC zAdjRk=NOpD>?ub=46rwzBwc>-&P9uXTYGD*k#$o=sqz7v>w+~wyp0^r_kvi4ERPw*}IX<~G2ifrr!rRN>j z4TGCcURNQPtt%q0Mq1Gqg6?b~{#sli6XtkA(DA;Ie?9Qr0hzi+>&X9WMYecrN)^P} zM`<#XW2d~3KxKqI;5ZCQ_8f;16ROMOFkhE&_ELX|YEH z068MZVQhbAL`Zoo3|})AHpAet9tnfB#GovLk;$?0I1K#LDmx&8`q)m$b2DS@U9g=- zWyYGU5ycL%f+iqw6gB1c$Zj%e#kE;MdRl(&s_Gdl; zak2F~o6_QiX;11#KIvOi%T|)S8JRS@7yLdiAF)V}Ne&$vd4{Z1QMPQ>uUlqEyu)s$ zF+cH#h;S4t8d9$X8p3M+Ee|m! zWGYL-(}8dyM6R|H3d}Ndh5w;%`4bQO%OfeDz&fMyN#YY+ponNa?CoUI+e!6-Z4XaP zn!lc=7ZLJrZJN&5zlHH22B#BqCngYpw;h^K@?-L=^@A45uhqrwTW?A78cxRqI|%Zi z^>y8})ZB}@n>#a8Gh1Izjb-`HckqMfql)vop8Yb-je1Lacu;BSKXPzxNY6bH!-}NIkr$0-*xqTFb<(r+Mwyz<&Z1>YE6*gEXuvi?4H; z6Y}KmJTtO?&h4t&p>*o$LhC`S40i2P5#p&HxKHFGUW#p+&px2NSGMSqyx_}K>R%K2 z)9;5qqgQiWa>L1jME@zq^_*R+$R2Wzl6(t}@a5?R@|THXzR$k5hu1UNU71OBs2Y3o z>E|M(ASI@)X_tlw0oArqP8&sTRdd_3jc|}YvBPrs*B`w9zAxN+<>l{x+4`?-zIyh? zk01KL=aSYZGp)Ez^1WIp5S!BRe`*3Y$d|PKAANj(I%S>Mmjb$jcijR^k~N9I2a_G* z{@H1A7WaHjapru9bxMKgHqcT3?!WhA2i~;v_Ba1N{bT6sU-QYY+;ho2cYOLzIxdhY zm3o^%2OOpuwjeQ`wLYbe?Bo%vYDB#l#QMtT09HfZH2?6Xvo*=B83y0HN?*lClU2z) z4-EH27)q z!dkZ~hHv;Y`T)u5+Ll`DGX}Zs_IF3N{`+72&=2l>=+^t^ll5=@+S@<5>mT3p#o3D% zMudVZ0TFixMC?tU(1`epBZr8-@Ed@M+trPMnAmactFC|e-j81XV6y(cD<8P;vM=5| z`>z*9#GVoncLhZ3d151C_mM+HKkyB}!)F)9!?%BM_l?&bxc0>LU%cWQyXSv$`&D-j zkxaWwJlqlRu=|OPhrc|6c<2MZ0eJY_f_QkxKYVuAXYcvIM?QYh`rF_Cv8%U#>-vYj zF$59wB_eJMh?sw3BjS!DhlsxL8-R(=FNlfPU-hl~zVV4G-u1eR*8kbX*M0wz`Je1P zYhlT>t3<@j0TH{N*oe6E$RVO1_y*wNuNK6^bq~Jn8<*U)|1&RJfBk)b@rkQ%`Sa^f zTNn*WEjiXrrkes9*j*saXTM%CnU-zL-^e|7s4N&Wp|+IoqX~6vj|uhAM<3q%$UEL~ z#lHzA)SEB;%pF^{Uv|Z7E_xhID6{;Ij0x2TnjKjA>%xNi!h%@&+k3WLG57f&Jn)@l z{jGoht=k{oxBrLt4v|xAmJ#uCL%_@2lM63jJaX*P7oGz!bJv2H`M@VX`-blx`qEq8 ze$o0@fA^y|+_vYRcHc7uGdsY{m~+gv>6H09JJRWF{kOjJ`Ro7UzOUT0-~5co6s)6^ z*)G2Ve}T*O-`u|c%b)t2FFyFYfhq2LT!1^tv~_U z2e1yvm;CVc1tI^ny?=Ylt3S5)tFKu9#gE?fz*Qfd|G^(G4EQZ2KU^C4VatFU%BU+i`GAM(^u}A+rRymtwW+8vn5_O2fWNax$yEg zM-DH2;W+>^-&_zg-~HI0f874INA`avS^u3+-Sx>gTzC8Ymxt(XHlB>S`;T08|G^VX zbMHHHknanx4#=01>RSs!{-OKd^|jAk^6j7eU+cer_rbrp<|7}yoD)bEjLaS^0e_(b z{$)=vz<>M50lpu&2EhHE1>ydt?R)R|hh2a6+K*hc{(YD2`Sv6CeC4)mVYsuSTqO9H zI@~ur!Qj6C$iclIxCX%eZx@97ckh19r{DRiE5ALp{<=Hw{QC#r_4Qplho}G+bVv8? ze4mJT$&<>d{?3uZNlA3gl(Wc@?$`R1Pe-~RE%-yb4| z*l#SN<;9Mc^PW^_IdJ6A(ifTo@bZ5a#LMfx{*~{&|BGM!=keL8el-a8DYWCEkarR2GgB=crDlzW1wlzUrTDf7`cO zA>{Gnhu-_(JKwnb&42hfh5_$Aa!BY4ybd({eG&4wZ$UJ?@B3SC`0)O#Z<$zs%U?Wv z*WVocn>&^+%o^)9MI8LH<6zwr83+Gxm>W$XX$yZ2ss|M%{>W=%m9-l2b7e24lp*4v*47wpfCcYW*P2d}*M zwf86MFZs)xzH;%W?w|d`t`7Zh@g3^dT5pdIE!d+UedRshdFyB2vF%W@e&1z(f9UUS zy6HeA8^>Yvqs4crZ*#qU`lki^blr_teC-P#yw~2M=zV%< z@qOysTyLKqUa(JJdH;`Jebu$sUv~cb*WUN0M;`g~YhU#@-Cg?e;=9zZwcZ~6WWgT2 z^}+An{GHc-_4U87{^sj1`~E-dz4x{aU8MBL;ycu*vEKg7Dl2MW63g9p-+lE*K5@sp ze{22a@4NV_ov(by?&G`q^UD99x%Yv#tE%q(_n-6co^$TKJIPIQ$-ThdyHReGyri!{ zDA;=U{UHzok~*k^`eQiwy`O!LcQ4P8#EjH8Mj#i65T8)7phk-t6&q@eMn%PcH9=Zq zMU54O`cR|Aii#Sa)TVvZ{662g);{Ol+>=0j&2QAmJ^RnvYt1$1TyxGf*IaYy`)4=! z`&2d`o|{ex&s+ZdV?TM|#>a20PTl{(Z)`vMA(8BKm0eejBZx7>)-gk?>_?-COT9&+fiZS-!&C( zIdxR%i@f8I;now9;fF^*w|mdmZ++VrgQ?g3<7037*dzPj{-I}>CZruQEO%r`|6P;8 zf?ZF|VCajywfjfyMA%|MN>z9_@j6K`HlZ_&wuUEz}XfSL;dXZ zRG-S`>ZyZ7438$a_ds+ovOwJ84h-Tm5u%)x+KKYrX>q^ANtaI)xqAm8!aHK6@*ydH zMF+E5Nb*9Wkh7s^QvXtJ8hNu=d|GZv&BV{4abul`rf22qLzn~=cI$_Nb+3mXBbKcig7jB}}}*=j@t3%TCTp7f)wV5oIw|k#0gqi$=W9Lr8WO^~PDX9cx#6NN{+{ zVj5en1KYgb^CkV_TkWOke#`C&zGY`cI$)vLYsnbYT(@bEsO%!#f-8Ixo9^SysRlBSK-KgI4l6tg>e4uDf=W*JkAI-I6gpLoa1)7GH$mzUo9SScWOWxaTQB5ly zR&Q%r!p9v-kvXWc8CoUk3HwntXTxa%Wm@#pHgIy8Jg3DoJrR!a)KpUXBZmziOlK`6 z1LIPJ65;gEN~a{eC+>?4BZ_IK?-LPu5SlvofjxFJ7U-VZ4h8BK?A8cpGpHrK1(#`c z`f|tulqwJwsXhbA)#-JEmT1gA4UhdaV-CmHYn9Cn$YwIO`;sMTZGPH|ID~;~9db<5 zRX!x6H60^~NX0UV{?$(ODZ+S5hQ9cGWyrB)o|<{W)KomJr@62x4dg3~KDiI>%Dp-n8@m`Tpc z?Tgb%wMD_xl}={qnCCIrX{KbSS~@hHEu{%4uiAwqtDTE0)UMS|E7k%-C9jp$C^}C( zO0rJ z$;+_HOxA++;3am;*RugP2%1HxJt{*86mo&sK7WojSx60_R&`d=h3afP!A>OXhS{(P zlKtA|#9OwoDbGN3kIn~*i`=XA?&nhXbB+7CicKX*vv#fxAw`faA&&$cvXJeC zw3aR5%69K%1KO39aNC~F+7yIHG`2(^!5Y;ujYJI@?XV-+DkL1>317`*1KPr|tA-2; zmAxS0>xlmb5OFrj*{Qc4D)R$S6VXM*?g#e=^!)*yL(ovgdYU{jz();j-DTSsWoein zRvyMOrKJuo0X!bCBH@Og2Q4l^s|hr=mjPNtosmF;v#3eZqlAo#V4p5z7a?SSpsmF$ zdL(x>xxk~FyqOEOBImJ$1XuED@iPfaj0*n~l5?XH3GH+gT)L>WQE=(@#f*v{l-I$L zlr}khCbh8>J3`b;LOAqC9g@^V2u753vM%hPRS@c2#6TV)e2(cKsJ9N%F^ae&dIAI> z2&|={p@%94p!;z?Z3*e%3ohk*uF*|^F{6~YX}BtUM=gysq$$Gqf-TesP^~I8_E3z| z#jctk*%A-~?lz67C65OK+mLM|sW|_-X*)*w&ZZhl2S91nC<4B8vKNCgd7q*G+8k}e z7W;{4gG2vy^iv$Aew2ly-om!)_qtL%RFpH4e1GUSHx~IUUKPF~jV>251t&WStMC@x zqS;j;yah1QH88oJLI+fyp}wxpN?xe5ELxLg9l%lnJ?WtdV^1(efe(YbK{>Zkeo!j5=u5a#r{kt|F?}K5sP}0S6nExx?kUR1z zsKXUGyE!yN;*8yR#n(TFD5xbrF(e!g?O=8~%vg8;q|9vSYn({?!j;OQ;1H|_$AWVm&=5p=t!s*k_dW63#Bl#HO zt=Qq-Ns^WlQ|YcC6a$^#XG1lbPf?+Id@6`1 z=aRsN<+Tp+Z44?$3`YV4 z3_j~#9#StW$M2;^$-IuT&Ax}%CKMiWLSB<}r045RXwV0)v#ey3EH`>TBP-q~qAMqq zv7oVx023>6vwWISo;=yZm+dr9Glt`_JSdU%ta$&~HR#5jh}Pxl3CGhDy~H{mPs`Ss zh~^0fjYKaO{Aes57pY=Ts%wqGB^AVnXj1Hsm4S)nu=t!%)kIdRuVL{e-PXB9R`&p^ z>^S|Jwj?aR?L%SFgpFP1gdYfirU&3qn2Y}efqsuAp9wa?)=Qy=sDFdNsA#;dAa&D# zmBHv7{8! zs{-4$TV)qCtv?>T>ex4A#d4$U=>A7mt#g&UDo6LBvvhvIGb76*>gT^M1+g-v=+2Tw#1L(Kd^V=}SL3qKB`_ zA~{u}qWO|OAI%j!W-6QM->r7_G|?}3nxKk%n6hp?lEyRGHvXx%eVn0yih0~DA>?`$ zP~8LsP$i-<4wa^}ugDXqRe_2dNlrJ7|8D=72hNd^rXuHnTE$Q|P?c<`3o2eG1Jyn4 z3o3q>R@PujV2*>d?x!pGPMAwA@lzemPnl{krwaWvWM@tD5P8a&aWI8j72aK=igF@i z(~|+A-c3YY?ov3VoORV{ae)77)T~rZ*s_|8kvoLh3KJ2Ml*{Hb$vc}e#D}6FjBGYkn=a0FlaWl0JaXj($D7Vj&tN&Bi7TxjYz{Q)wJKR; zn69Qxy{cS1xPVjLx({%UCQ6>Dw`30&Vc8|t4^oUbI>6$CErA8@;{c0C>Egj*qp;@ffI;mtHT9DtN(>r-#{*5(8a#7m zqJfQhjlMA}+f6;>aTdqxC<3VG%5`Hj zWl%40C|)G$2*vy-`vtdT&Ma;S@5BQ9r3SWGz+8qTuJ+b*CZ~}oVFe7)x>DEdL=g~L z?-*8esnfgRIbBGH)t}+AKX~Xhs9LX^oR|}VtnL@NYP|d(q)B?~rr6Zv zA2+*?Lt*tq6%Mv__=3SmF8k`Uh4C4yHPgqc#ls;R_uruFR?WX**PGIU24h1996w7K zpRwz5X}W6b%2@g=t345sw1y-)4t5A^hV1VRHY8lF2bSYZ@5MV}1b&tF>{+({jGZ#a zmbDb4C>%6Quhe*W@n8*2%FskBT$;;Q%ln1~5DzYMqgf(9N*k-fkA-9iYF~%CxH^-% z2%|}-E~bmCr7=)y=AzY@ljv#7w3aQDji5hN3k?miI5t;hkmg+l%`uyep?5|^1!Z${ zUOnWAwA6G#t^`#k@T3q%C_07~N}h-Ix5P!2sT*f!XOlJ2U2;WX@ZP~Mep&S^c?agI z^&u)+SD++9U<#)%q*r#?MswD%3}i{Lh-ha!sE8WY0*M^=HJ8+u4Y?FPBLkHaIi~Xk4k1E@vIMfLC?Ce*2=I$|qn<2wQpc?}EVk8#Yw1k;3Y<);5UZgz zlOp9MBI(`&a7|CGzqSk_ZzhX_958;Jp0=;Er%=M6z?)7Di%j&oHo)1nq@PlMA;kvc zvPu!8BWVqM*!)B4mupQz@CpbB`CT zwFnbOn#M7tS?Wl$EZM1bDEC2=21J^MA*CkLoX#T%q;oRRieBsm>f5N*!S(4i)gTe*xxl$7Tp3ZFWnU}$=x906aAc|c zr^d!peD(}~n7}p0xI#6bVFS#-H(FPaL|B-u5{pV|^Y*k`6LPTnV?3Al%x*GIsQZuqGBUpahbWj?XFunG}$Uy~ALG zxL;mLz&<3*`Dw4?v;N;V0mozfkH2cK* zVum@dRi2N}<1czjUXKQ!@rV^>$maTe$j(yD5No`7nUpoiQlWHKA_~VQJHmV4N50Lb2H7%K4j=FO5LrFECFJqo5tU;6N;p?`vq&h zCKh2M9@@Q)y;sm9*g`_jcf`rNTH5R*?*^0iXk{!ye$`->ybikUd&X%+y|`M8dqg)* zC~$On=mb?gtqbRidgWB@7^Il|ye?ai?2??a@ouZS(Emqa(W^)n#sFN6*M$+RUT!@6!O|TnS!|RGG&M=bY036#0B!?-OaR) zq2EMuG@$EHS9Y+@thGR@yc*d7a)9)_=o+EkK(l7`x+3(8Nx2RrH?Goq&pe2TS1{_4 z5G*Uw6(=EHVb|h%Lk9y<(f}T^v?uDigonD_6$Mvoq#Pp&4w)nngSc@oHCgt{#NIV- zm|tTG>U*rh?v zQiio@JOvUVc9D-O0#H5`v@*-2ud^V6lysm$D^c@+3}b%>2hb(0w?tuen}C;y=SL!* zNVgRKm$IZfhGcn;r3t;wS(hb_hYDEsCZLMnqH;OET2tk5fwi2jC7#9B!7J)b0n6gF zLmpQ*pBE7Up^BihLacbp)d;^R1}#)2)5$wbg9LVP2rVuXN1{?H))#nBU8<;;F*92Q z;{m%Akp_rq9jl+4Dx*iZC^L8>47_i{W&A|JdtZUO$2hUmYpi^0(q+sA5h0CWa7~j~ zRk&3~R|(PsU*8Yx!lu4L+X=He=p!_^T2Bu}3w_R6yops|lZk^Y6N3JPn5p!ZG@43x zY$qUzn;pAZ@Qim`C=FV2x6l)wOTR}Y*X91pG1WI`67}uk2#ygZO!a7zx6QOI&D_Z9 zvI6ieOjDKlk?Ppn=gVKw2DMo`nq&yFz!V^vqu1gPG*?ef`>)+T6}%Lpo^~a)SZaTM zZ)~jB565IBZGlmj+*(BNX|9=CjoRYn=u~)pHcGL&Nhdstbk?i*IlZm#q3@LJ?KM3n z$8)-Lig3xJ!#AgGmD#Qdp8IE~XeJ*gAk0wF)RYT3Xh!FS@{Q`U0?7&P+atW*vR!0l zDNPkQL~9_Zm=7o^dys}xu&ri!8cE3NK)!&U?=YUqIx_`!jjoBt`Jp7e6*y9#ifTb1 z=U_v`M2X_Kz6P&pRla9of<)yL(JQmMdVv9J{gA&==Ebn@!=USf+*VB29DU%Asyi!E zb{icWG_S1UzdUnSiT@JYGXGe(GDwIeRlwGQ>EbL?gu~L%tef*8-w(_X<;bmUXhQXv zqYd+yf_Y+gp;jNk5Kqr9rvrlqo!s2CZm@J3=48Hu7}yg$mez1M81xO}LPDRyuv&R0 z{AoAXsiR_F3HB60sq1TaCDWZrN{W%1+}}(W>5N$rZF7XhX`{EX37aBRi?{NLHCZ-Q z{G13IB4@=evV-uEOa6dneB;EUS$N3e-l{Y)p!Iao1;GX^d8^acHjv_^Ltz_@7K*$A zhYsdT(!`N=N0coPLGOqhVQ-7F!Q>OooG=di3Rk63cEoU3;m)|zlk_y}mAFY+hA|z? zCI`C!!h-izI$A{1s>uW@S0|bRc+YwLO0Z-c@qwPpZ zTj27vCGv@2OZieYZb+%WBHoJ{$82=;=|%Q{^|0=mUYIT*9@XTHHLaxtYhEUbt~;|$ z9h?SeIAItj$tRoCObi{JcZWLqR*yiI^}=kze1V@4tVgZ@YXzDf|}IuXk#g#hDd8h z^)56O)S)5Ga;z89K-ld9ww&|Y+dC(sPq z>6*j5o59Z^82SwL?+93R?gJ+yG@XVpexfO3seM5}+*!5QrwG2*LJR{&OVPdr84x6Q zHe0P<#bHC)`S)t_;0y-}VT3~Io+RYm{N#RDLdZE0*ga0!vssonTGnXwf20yUd-%hGq+)r!us!@?v0dcUnLgMIQ$4%*U&C$BCjJfd5|d|EM#cGZB!=di zt0@^elVFToV@__wt<~bE4}A15YO*?E5!Fq^y=&sDAN|ZHKXT(!Z~m`qVm0yMJKy)y zzx(SS?%TR1RujNM6Y!aMECf{bYER^JfC01Y5_HslM4R71M0OQaM&#uu-@hG{ydVF(~pz%~b;Agfh@B7AyEz3R~Azm=ftp_ zPzZO^7*BOF96y5)_A*dT9R_ZrR|b|M*9$Qxa!*1Y_7k~ESV22F@>g==#4_JY`;(IM z|EEIuj{U;_|6fA5AHn7b;cpL^BtD@K##3@?c=7#*PRxsafj4i^xt3k{U(l;u@JQKFR?>9UVN2 zIZ`XUZ~bXZa_neVWoI0kr7+bc_?q}yP{nYl1a@pj%)`DaXWER_X96vhBHX9r6dAFshm;*5|ovvijpK+`onzADp0r@)v6 z)8F(Ulk_R#wC|mm)B12dF4t27%WZ#u(y)+F_!PnN_({V;7Tr?=%g*ngG%RF}JvFdw z|A&)?<`}$<$I?Jmf0sx8ZV^WJT){r%%Kn_k4+%W_ciw!(QRqS3dau%`KEUk%@x^LL#Ay&66)=4$xP%)g^uJ2QVW z37RtZRxirDROLNB0BO}8AHZBq4uX0$d19_68N0UB7!r%iq9fW7G_Huzu*=bXH)~Sw zRcBVJ&WWz-#QCAp7$}-~YsycIgE<=Al)t<1!fVsBsL-w_q>B}&XCpVoceDFl$D7@g zx$xAG`r)sgnAClSBN_Zo4J;2meA2Lx%I?&_^4Q6XO!Cp48dyI4!;{7fspw7(EJscr zmVY``upIo+N#lj|bEgI`_x|{#VIl3@se$FOlZSPW$~cQ@$q-& z(a-4Pul4%)S%-7;=r8~8M?d*U9?WKRBi ze*OaqRF$&<+O^T6;F*;7DtI+P*;!lO>T&Wbc&}9JztyYOaq>SOIB@dk#F2F3 z9^~fVd8ddl$HPSKpE+*+iP8dC)wKZ7`7Bvs1DuSbA9s3Rs-<!&9kT78B&iT6$o zEJscrmK~=GmdAc}(s&^U+o{3JU58H^7BZ>*TCluS$!8R&#qw?FSGtlrStb`;IG9kIM)LSxp6_Lwej`67Qu zb=o*$E>h|--CDQReGm0AmO-oj9P(M?iS3G0q^u*ulffJ^ywXzvxDF|XneG#U>G7f7 zvz-F6Ngp$I4&_QS8KJ6>PN#lFt&={33#{ zd9xxu0^`HdLPcb`5tXM!MoEossveRmSY#28qGA_u%oMAX%lblRJWG7)&I+j+meAaA z5!z0%5{{h)hbZ8nP*8_*_0eC7vgq)lL4yBuO>RW_^3&?NF|GiZ;MBMnxsHX9xcI?C zZ~d*c#3m|IH65;O<1b+?d)4=0%CPYRJ|$3%NTBY z7_7wEutF~Fc9}L2w@Cj5oULOrK@#M$g%IJ{6(cj*>HM$- zBOwc98!=0)w)S=r;7Jz9(R6{!0;w<^DvJs8EExiHC>vhk5)2Z-$2y3@JCi?gS&fc{ z4rh%S_O=t76Q>Lr4Bo6lE5tQjY+EkC)J*pa#o+P8HiUrXtm1~2S~^}OU|FB^RH9&} zK9y98huxC;1T3#dK+C?IyMtu>pSz41Bs3rsF`84p^o!lC5FVs?!SI zC&D*x>+*sU0`~iKLNtku-oDZRwzJ+sqcGZ3c9Qw8Y$6+Q@}3;_HQ?q4NAmA2@Qh z;no(hZ3_v@RCYyBq0lipppm0c&1_JbR_Wzbh>cS}gcr3{X{mlLWx&(!!i*%KSvwtK z8zZbZm@d7X_W04jK(DIp*cv#Eh3k|*LB2?>Eu@IrUB=^lY%LA9K+GWffEb^(bWE7e zD=Du7HnPEQO>sh%D}^0{KgGa~rQ@V;tSZ$)oxF>1mLj}Wh?T%!D9+UnYjk2a)88>zYPz+l(Go{R-N#YG%nnbqz zkSns(t#lm;o(V3Fia+OG zTX5Oiz^KgfWkaC2WhT+f#-BLU#e> z2rJPBL`?V|0u7DBi{gHGQq=L5-U4nGO|Nw47NR&kn`8A^>^* zc$_ya4TiS6RkfMzdtqLA5u%AGMeTiyi^my~%54|9+^tnBLSXQ^LAI|bjCK)iDhM-o#wm*brL|#&E)wKBbBSe7AR1Vu zrR{LR^EaC@K;jlUL-#=o zdJjY_;0lO*Uq|Q?NL48&)!O01%mt2%i<-2UZM;HTUl<VP!We;{2>V{p;VI0Sy=Kl(0UUp? zc8t3mDA+a(dYOImc^!Zl3s%BXlQj)3#@XW9XJ+^ogWuRv+^$p-CMy|^1`cRuM*oU-tiSI+XkicDKkS+w1L&i8A|OaRg(oZRtt!GepLy_$g0NLi9f$P++kc zcQAuqs`Z@}l{_qbjxfe@=}V`5{|K zqlIGXh0f?P`A)ggO4lYUB_uTUjV}%|gW9KxCNyLDOk|1y z1WbtWSX+d&PI-k){)L$%k+CFG2VQKCOKqUa5X+8vOxuOY(|*EsBw}uF;J9fA(#H>5 z1A&`85DImJ>3Ql?dd!4y2^Kw7Cp?_uDlng*-DNsvsyIhvoT3_VoBu+uzERUq@J zqWpXykIM=ual4T@(AToPWX0-hsp&BJuDv`Gk>^7XHT=G4ui=s8S`!_@BX*3Tz!TC* zBsjQtUS&g-Mv8kZ$lb(mi7E(Z2++LCv>zzEn`@0yHqTU$_xMDt;e9=H+=ZyajoWFJ z{SBCA<^ByAnR{{=b>1H~jc4>Pp9y7$q5MwT*R@0?yCLja9KntgyWYn&`?w?dTC_o? z_xqjB(-KKy+)ruqL9pw=+(7oV_CM_7N@MO({i1SkhLD#`SnjQh{U&T*<;`J(z1I8g z33h4_y+GbrQgHCsdbUY~E1tlG@GV{3%f-hS7k-2YWh-z4mCTEds~6`;CsFo3hQXZ1 zpHN3M1nvP*+EDtSbCDoWmCTxzowfAQ1zc-jtF&P@Cz_U_@Z9C3j>Z4ZGQ z^Wwnv?nCEovjpAR!J9SbRC{MEPuGDkkBWuf-Nx>e1b5p)@&tglfKdoH1qBUxDg+8Q zu=c%>Qp>cuCR)zpU52!h?t!))VBG}B6X$L~0cpR7;u!-4DVAcd1O85R9M4rJ4+XoP zxifx7c?3A@AXsnHJ8Ak#5ZBbg4PuHE3F_5dAu=Wq(aeE|4<=#bv+ox{u=2`i*Ruj0 zeAg5*L8>a}x~y{3v2Jk-+T&571PI)kh4B|n7tZNNvvT^8iXkA^-Fea7y7>NI?dMXx z;s)euuemPSR$*x^N-7(CV%~+$-3N{+wYmh&Fv)|7QdX9z7KQvMqgq5C!&o~ zE^$|?H|N_ht0dn9Cg>2#zZaT+56_<)A72}EVK}pl4(H$VLOYuL_5YOu-<*RhgMp!i zq0(m8>dK})oGe(lXk_sc5fk$=XrE4CXfj*Njb-G0>-YzG;WB)#@G8)NFDlxzD7MwYlsh%AQ6Gmf_E8>(rjQ+O???i@K*Z$xh!|1b?X6Vxf&^ zb*>E|Da{BJh=?A%Ye9Ro>nACe;{lTnEa7L)1V8AbajThj5gllyN#us9a_j|ji}VWo z$u)7xSI$o=f-pSLz>LAF2&*Syse@&*bt+|&$tVb^@d$%G!bx2Y13I=Mx`=@;3F}#m zGNppBC@HDjvpbKZ&o-=yHLvE=>R6sUw`7u~J%~;nqCu`!m^&EQ;DAG= zS^w!_UPfoB8|o0T6M@%UmZzwBD48Q`bjp6 z0F3a?Bi387gtS4ltV$?-rBRuU)uP%ZgNty|6=}D(+((YMH=+lOXBcKIW$D|C))*IR zz!h~qH%44|N}0W3Z7ewM;A;7@@5_)RetsF{GE@3^Uxr!H{4%(d0`hK_W$=|-nT~kr^izJOxx$N0 ze4eU*FAGSLpg&a?lvHKH?qR{rX5B6256^8%!`9zppCg{!R7dFPDKCpl83B$hkB=Zw zV!30V8_hA^kA2Rb<3M8320eZcIUg9{rD1Ec*V5K7IiNwJ@gPgYgeSn8KgFbnjksA0 zeta|xB;$JjNe>4@3#!#xt&TFP*J`yY|Et)f&ZYxY<`PN1ErgLMULm;y;`^SE-3xcc zdXhMSYs;^9si%@Gox)ZK6UO~A3iU=lnSZbfb)~v!h2QdB@74TwdnGUB0HWY_SA&{%JL@n}V~S&~IB z^@--9hQT=t$K5L5Z0Om5B|Bl0Btx7{&H{KhSFd|)CmE4ugPB_lE>JrwV*Fd@bH!Td zrSetPXgY8JGey4#MyS!UEZANnyMMwN}q} zhO4tM?=Y)ddwH?BcgyIy(9E^*D0QFc@M;TTn-FPcw@5RPG>3Y$)%&GEgKs@{fslyEdPz=&w1`y6Du_S zCM0E6=?X#x?f=kE7DH5f<4dpfWg@jGl(oJ59z2U~GZ392X*HkSuRfEUyz%utzh4>5 zxuDG(U*>uJ%E+{7^TwC4{z%}pC-lrLp0oOW$HH0A=8gaEx&6wR6z7dE^PGNVOrrC~ zms#Ggj7fLi_%grIuZ-zc-uNkpOKTNQZ+vO&$@yi*Rfadd3>M`4GN-GI zY)dyDu>gbO3_ZiX3yL#!g+`qJUFzTX?@Fs}K5mqaeJ+LiT5q}PGwaPpui0q7p=V}^ zE!S0PiOr$WbNm|*htep_vkafBGQ9C+%;q{v&t!ACe)n2g$Q7)&u0y%Bvix(iA$zSX z|9pXJ?6tD|bDP%oT3P-%nf=Vl>R4a?dB$_i77|6-9Ek$NFInt=oquK+ut+!b+(43f ze4L4XDVxWW1>@u63&)x8kB=`|Iyydn+A;xjQVrGfr8C}KF?s36rnc#;y&XK*NkY2k>-Os3_uqF)TYc=N#4Pjwm z=*Fa|13YCL3pZvs(|N2VZsqa`Svh0@*;Woy4oy`r^i@^*ae_v$J(R47>(wNHSr7+< z;6R}OtnO*Pu0NI|K#%0r#k#332uNzjF)*MdVx>hDDkokhs}(3-=%G-IqJYU87Mo*< z@MPBNQ3n9c8Ri1O2*D7dqlS_+Tp5fTj`R%S2!22+i!^dGCi{uWQQCiEu_a?MY>fAm84KLhs5SR5E72{_NZft!8FmNz0NW2pr$9Ww!OKdJB*>YO_Y+2 z-`UC)cwQ78_`;18+H^rczyf#eErbJd2lsJT+tPVWG>);b(n-KnfNN2Qcod%sb=%Nk zhw8U{s!S6N32-Lsj{2^*CFL};y7yU2g?YJq3$Tu*AbE5a8m;A&d|no^dF7*(7-OH7IJCKDIS<0w8*9!JG!H7rza z+pCK+x7d-5(m8lw6rjqQrKSOnxqa%!iiRDc$s(30;Ziq>F*VTmttceZOew zEPJn!IM7g`Aj_93rxi=^Y3iX|o3~iVulv3rEa*#WPD!XQMHLmnrFaZkMx_Go#l+M| zB%m4>N7E(?lkc=9AemZfYwYoXhE9~+r`%LV5&FgbE-TXulzbB$eZeUGYvwi_=NCCf9nT$+58*k3W3(_JR@S{HOA zr;~=geWX+EEEKTtrSDPO-UClfMB@y=2X*)W7;@UT_w9(i z)ilwB5arog0V(dWZ#6R2pS&^#D~U*4fEJ@MkdoSg5}G;!ypzMkC~9!R6S>L@%H+Lq zUe)=?jAb$F3|#SN3|_^4Sf@P<)|Mh&ebjo+`b@Wa$u1N01ScT>>bOXD$FwFLcRWZ$ z!Q;FWDptb_X{GfN`6rRDfrg7l4aiOIjnNH;IarW>@LGS!Z^KvyDixfbk^B*tFtvj3 zj6GW~giE4H$YKWntBp=gb=$8Ds@QQ$uYT3GxaaY6}d1$Jzh_+aqCb3v)T~WGGvCoB1?hCIN zlNR0xIs+Gw8YqGX{8L}?bhuFq(A+nRAOrj?iZx~cqFi#@MtX(n8`Co4}c#a-HAYefv!q}F##vSE9r@AK0>{8nwP-mh`25k$f7O) z(R={3stW-03ABn}mDb%7jH0rm^vWQGT`)-FFbZS{5Q3)5Mm0O)e zid^xM?;NRY6iLT32*rca_+d0jw^X$P+2BLaK$646t9s*5rwzTJk|Ut?AH{;(gb)5H zes5XX3V6|=E5Emz!T;LUhePwy3u&QnXOU3if7!AiOsbaOmAL)leTaT@>9bj(d@SY8 z_=$@%H)>oL-?5XjDn)H`8g24*D7M||h$svSYMVFNCx=5t7a?GZ_U5vzyoijeV&P`` zcsPJDRt9nBvrUY`R_koKDP2TI>6Zr8XScn0nksRc!Cr!zfno<~MXk+Yd;>k9m1&He z3qx}+`&_pS>X4MNdF_V0&Tks)hPav=wu0`kEEL|5>&4czUZ%)}4{xw1v467F^4K=E z>LFgW)@MS2NUKFUL(`$XPOi)&#l$BwRy(_J`hEfZ8dUbf5sifoQD4i9UD3JuNk5+w(B?NO~VEjNn<`U(V`;1B+3z77 zD8|#~`mrKnY-+N|;W9wNu#1b25N=Km(e+t0723Jj<;N)$4sYQPu<3t|--BRTeTs4r zNKEYf}S~dA#EcZ;&*r<2K>;sRiDjy~8(fuFZ7Zg#l7qJr-se86h z&no`ezQ8>^sE2j`a5i)gpVY&l@?qp2-t!S2j_G0R)-bA)`8=X=4vbgi$O>gLc2MRB zXNJz6OsCC-3`0p9>qCruh>Ek6JC&iTp&T(L5ww_LyTUXWmcePUBJrNIb}sMhH*C!t zzbpA5-4Lb?#?Wrt4j|zhFn-M!yo(|2tgoQh6()z9I=T)kltFLsRW7IfihzV`frsbB zMtn%Igzm8c6g4D}s2_r&U)95Wh?d#E!w9PFVY`iDbsLlvKm6SnUG z83jjkA|vIy!I^+y0#jp}E(<4AOTaD-r35l*!zUey(}wun;~)=>!_qow{%s~qY3imS z&xx{|(Z^EqaN(9s9e9N=9WHFtHHt9P0yjbHtsyQTkm!-C26l0lgHXr@FE0(4#|apN zq$)!c>8wUH%Bn&f(O^7Qb3m|`*Y$OqketFa$Y+m%P^Rp}^u#O+!#F^R*ERJO4(G@Z z_~xdNNt6wf;{qqU0zo)qtPWoYXHkwv2gA@_5YB`Y(wvz-VZb{oUjkxl+P~)AMTQaZ zkLec|n$Sa!OUAG?{c#S-N6p}48&vD&(0KMZ_<|OqSDeuso3=TL--|Qc0}c$!T|NhG zoIkl%XyapO)r+=DM;D81t&f>8hx7qtAxOQp8G=kmV{c~K1p2KEg5tNC{Am}M-Gn+t zRV5e`q9}+06LPirKq<{8+qJW(C*0aSt#km^~M@ zLLzQ<&-W_61eMsW-eYQn#p9~IU@th=Pt<*>$JxG&$X1bplfZa2ur3eB7*}ivGcR`eGPh(fuZy>8+yap7P* zNq@-!zm-v6e>p+glN#bzGQ?Xi-^5TJ()P`|-nOn(ruePgwzs~V2;L%Wy@;FU%Qxw# zzBO%LNdwL6(+Zcge$}RpaI2hK4b0T*ui~UmJLj>+PuP>pFNHm9<%>W%pJ~% zF$o&BzAzax8RNeVT0a-f+ye8!@<4nC_;m7Rj8T5BPa9V$D9-hXjtf9ps=Vkx0%}}w zp(?LkpVqE&8`&lK<*8=`!2$AF*%jb8=UANFA5$}%Hn0vh${8gYzaODl-G757$}~Kq8UO|Nc#JKsA;Rw53qualkha6r(SSi4%t%C6BoiXky4fOBHp=@H zKGDl6kv7H8zoRT4rkkua6`-7|L-ngVY-ZX+|CZkv2Hed^rz%b|@>MY{2>AjRGh-b% z+=RPRxr0?pUaEZ8U#fW!Y|V6Aa931{AVOhs+pSi9FFV1Sot*Mwb9A!UNHSBHSkBJ` zcD}x;$TtSb9NOipZ2dn$G|4DMcFo8ofVyGOUNI&_;pZ$4{L_9c5)n<7Uh!_=vuA0H z!;Q!8$$NNgPYO1!s0AR@pcRf<|8Iw$(PSDRuVDJ2C<>*sn8s^}z;7rx^S7u(gm8PJ zE&<}i0>WVJ*f1{A4A|L`i{HXYmdEWmM!@eoXNOa^G9RpskQpM~aqCMEf!1u10TZE8 z*w%2_yE>W}_lJkvJIaLO)@z&M zW!O$_EonPn0>ZSv&OpGAJGW+bu=$#q6ViXwP6;2?%tu{7Lu%Ng4mrkQ;XE_{S90bI#n#jU#|++EHAUu6mBEX^X}z+mbPUksJ75itv}c9KM)S0`wFV4ZS)!Pk`g+!eqwGmL>0Z?{1Hk7Y zL0joxFI8fKMw2LtCQLE+TZY)2*2J|j;}l!SRbIj0EiDgOI6Di$!?^IhDu^<&5uyWz z7$ARif|0ofBAlv$`P%`SNsa@t7IR0a#n{!HLk>&am~;ulA!s?p58Zhsc57*U1@o^Y zuWo-c=-iU?z9njR*0B-XTCYZct_Dfy1eUGspy6G%uf^V^?hU~|DyL2L2=);kHfim|tjuX}&zK^aJ{=49;cv%i(ICTwUNN*3W3()_j($<;a1iv!!&)fvetL zXHPO+mknPtV}>QcZS)v+;h=X%eyxaMZncsx+H#Hj2UMXP2te!JJY;VI_lAW&tsGmL z5_*L$LzYR^DmhKGjwfvr5P-X)sw0gwf`b{@k^#j@>dp(#>U##@!pYh89^t2Xk?j^R zmb)N0S75AmJv}>TbpbKAGB}5dDwmLbKj$B$wH(YWRsKDzy`Ii@>JXvdI|4FF|QL*enS^Xpmt}%JUJsWlpPi8WQk~K2|hIknX~s zw7IyqWNcaLVCWG?|B(H**3a+p7x|@tyNmq7#+*fdR;jd7$WzEy*wUCvl&kLQaChMz zbuOmvEg=4#Q(>pQxmENm+{0iVPcSd5z#Ze?JFzSfMyOU?*O%lEkga2eP4YLi=kWTx zxt}TMg>_QJ&pakOtv7zgullM=D(DFl_;T;fS7Mx-S|(T-U_t7~)>n~pmq^YLK@g@P zkpm`da$b)+yF>RQ#XAo%aAXzrEW!#`_VQg1BIc>G_hl<54H3-J+8%bryf7f+F^h{J z3*t%jy~h@dj}`gUs;HD0RfQo2TNVj!VOo`m)z28S`t*)=Ow~jx37ft)a*kcaBf;^? zkwjUU)(phrU%7Q58p9ildv1Rq5Vw{AB$X|I)$`OvYOs_z=PAU2Q3y7f^VBg@a?I1F zl^r?esV3~{z02CZOQJ!0W7C7 zzJirO$Z4*KA|R#R+^53{@hI1MHi-XEQ$)nlT8cN2@se(2WeKUx+@sCR3aeBk(tnc15>Vz?#y2G}>ib|1mI`SDu|u0Y#aP3{r(>-B zk$Xj5(BzdIEO}rNC2I54v>D+M3^dK+exn>Lx5cbPSYj~LxQsSV5|1Wr)F3T2YJ@5V zY>w}7Jm;uR^AvD1QhZU`<$#9g082qk$OgtR(RxMEitqMHWd}lh8~HNHR5-viQk? ziF#(CVEhJ98c&Gg$as!Hq+k%PRtBk}%*gAbNHTrQ8Ue-5MkCT0#16>OL*EJa08#*4 z3BO99){DP&-Q?N_)nyiN2()r$*CjQo79fW3;6Ye?;j?t~LH-E+K^~0Rj4~KY-W|8T z7NM|9a>Y*Ts#pUonbiauyquDC!XqL^M7VNR1*ddK_b`yLk_YMFFy@1EF}sYOVi<{L zM1VmG7lWj)zwWv;=L2*dEjpE>7BglEv7?D%LOL`-s(G3)T0BkcnG4SoP3jCIbgpbk zYVwhP6;BgJm__&Tu}%d(8`x35!n+4mG95#ygLoNDj`1*QWYB0Zi96yF>u(CB)P=hMDogD%$i*zW=1qi}@~yb_`ewQ39@$Xwt~}|@sK|xlBp=iS0(@6w?JE@(Kiba% z8-wBzEPQ7!f`>d=KvF~4G^jak zV>5Z=}2*Q@gSa0l9EAu$}*48w7%BK%SC(>j>6}qm8oD& znA88q9z^S=@>$M*bw6jor*iDgfAyHXQdrEq3Lm#un0fPGJz=k;mF9hQ$iNWP$k@hO zQri@%R+6>SN^d(|UA%<|139I(@hX)K`$(0g=rdi1ca|8T7=C3fL^M%tq!#VL7U2fL zM#?jbKz)Lx87F6F!2cs~Btra=Dq%*CRI&6C8}+z{ro3)m!mNY@Nm9eLV&|730+JA# zr0vU@LDi7UOhil(;dETfiXv&Zg0<3xFc%?QTE-#5Kx+imV(;hMGsVGAKA%)@#TWmK z>+0G~T)yL})=cremY#n15iZ|3x^|PE->|WG$KmG1T)q44JSJBkm)C484t>cUe)6Zy znW9F~P1fw;o6nyq?s%G$bXlDg+Htj3lds2i25WKG1B~ypizoH-AO|)+$nOJj@(t$O zDqSu9*XMaMQ9N*fpLa&ZcmIap4@MMV1%}!b`?g%PWNfGUg1M3`5?pCoQ`Rh|(;}CM zNQx@%kjv-m&-2Vdipb&_>jcmnCTH230h$hoq4{BySj>AmP=?T%JA{;vD%EnOI5*fG zM9*Q_E+*(Q1&1S!_zbBtFjJ0NDQwQr7PTrkaTz@lwiRubPV*rh|v<`sjgYc=8A;sZJ!k)RNn0g*$C{xy0lqHkG&J4nyr z0ygQiNF~WU8Ws~9IzT3(bC}_2c*d*M0sH{S7dp%AOtagHsRh|a5@W(z@*R93mjz%> zOPBm$cnK@~xCl^+#U3j!mQo1y3Nu09Q3*GA@}0D^Xsy=ULnqr^G&4=&@29b1HcAd@ zhD5p?93yG8RyD(b)UZzBfs%Y_1Q2@Z2*Whn%ut#s$p-|n>_3yeDr&{48A&Tb$kABJ zYm>>y>TybwEB9XFVuIGSKu1Hgv5tX=#?wL|2A-C^tvducYWYPK3-EY)Cew|~PGo)v zZm=))EP_{50k*G;%@lHCLRLb&O>Q>rJO~w3oWaXCcyEc6H89QQ-~r8s4xK!9A;DS+ z5CFogk3gR3Xw2agY0P1#F^8ST9CjLW__!Jq?j{!|sl%M|9Cpg{rJc6q{4i6ikA9ZL z!8^go+78RH3KB6s#HmCG&ELhzHzl=9AOC)*%KC}Ghmoc5nW0GG<1LfIH+QnA>lD7U zyz|kv?(n?k{PG%DX1^TIoak3OG*u9^YeQO^L8gHX;P+vtf*1>hRN$A4V!6fiqwpXp zNp@y*z!B9)pqsviWzhDriGrXtYQ$9Rw)c-{(F78k6Y{r0Gn3?F{tqCj2sM?G@DO`C z+!uXk<*iRtqPSx)A3MK^Cd+@a=W3E%{G#m)zMN@5=@h6BS}YI;XA_D`7k~iOBoodi zK}eBa6HcWR9bcAtMD{Xsq24mAG+F^(To7o^)?*{nqoU5B^s^N|gPAjL5nItdd-jeu zb-|u4r!JbfNLtEBmc@p+l!5FgVBMJsVA}!$tc6&#qHYFP7M1N=7OGn~kzlouBJha>pZdw4k^XEaF8_%icZU>O z&UlUsHW6OU4^#+{WDjB5i}*09x8j0br&J1(IT~6ul5L3^ttwx!(g^m{*i+wmo$5kgofb>9pnC2&nI!bg}F!hTMKf3=N z@A%9^Z`w8$BtL8NLZKnN_}lNk@0&l_{e@e98I&(3XZXI~7uW%MG5?G6)pe@mY)kvK zR0TQH33h~S1@Ow1d$#7tCQ|Ti<#Cl;sYAYS$p)l(R>YHA(}*{ec$tb%{q7EgO;s_y z6|T3N^B4eD-U8fu$R{rEdSe)m86{-E7lfGYXh zGzq04=t?-Vs6&1jF!-ga&F!N}3k;Q$l)2J~rY8aMy*K~r&%XWL1+1d!ZvP{zUZznD zFlL0IK=7_hAu`xtFPh(OU+cXsxNH-G5cOJ;W;vzA3!LZq~OMo{kK!7TsXG_Oot z)bv_wYsY!t(0gKOj`zN)_lm{=fIbU*F=>)j;J^oWJ?D5OhOES{yWV^I>HUic{+ozv z?dka}Mk3aiEJM;;&%q6_*fJwP&s$CG;>0aB_JtUf)D(>Ls(u~PcN-ii>U4|Itx9on zLg{eMY9fMXHw0jHRC@|VI#-ISH$eM7ZBqt%5g|;s`mTivDupxn;F78qTV37qvik2f z90P}|jL#Ue?nAc}s@B|B{^?xsk)i?`>rNHR%i~u9-0GpqivV^*0zo^h4o z{+B+1GT6dw3&TXES^2bOt-5uJuxFj(-7;m&WkZ3Ew?@mS5|C!ReL^9M1%^pH$zK-w z73)_Z5g5;tF)d*B;<&ZQQkas!&0;{|)Rp3a+nfWQ2~(|mQ(K1$uCGhOF{ZU#X^sT{ zD6m)&wKdF08P?Q^ylGsV*KIQy59?#JgzY8v*X#qgrKTP-m!+0OFKwID)Z1LaLF@A# zbR1*lIw`OKE>U%wi`iOQJi}r-TAejG{y>`=3DPUp2lWtGI{lc_smeOKUST4m@El#r zDT7OZj({C{gtb_=DVk z`($XwUZKz)7x5!gL}4dH{(uDekD!OLrXX9_8{I#<{dW}k9Th*Q`w7*aA}C;MTK>|0 z>WPx4Vpfb)Vq_Km#7)(Ws$5fh3~bl<$2R_)nhYfc>?Z6!4m^?tVaw5VRE*yaJkBBsKut*|^z z+i`u9*~fVy&J_8GK2o9B7;~eM#gSNA1v_OW-fNMM8qZ$`3A6?!X(1J=DS~-$=C`0a z<&dDgsc>tqM(sLy>7KkTK=i%>xnbs*D92*JZJle#$UqR$gI76OWV{aHd9p#{rf4D? z>9W35#Aq`GO;_OgPFrI+y}yWd8ki3h6+t_u>U^XKA`E7zi_C6+k1%d037pngV?(iVONuwGt+FvN&a_foqO(NdV0aj01a zZl7colLG+fMr~T|s7^~y|5_~_Q@^}JKnNO%;|Jp|=15vZkshXiz_2u+Ew4fiW<92* z#`r|yAX2b~lHyp+5jDr@}c%G5M3ZKpbg425w?r z@`x>L8db=bOB}jFszK5NR!xej+ z5C!ViJE*A%qfAq7neV(iDqS;7UNl2Cz#|B2po&ekmKmY4c*vwbD4y^30^0~xyp@!Z z$eiO7)qugOa3Ang5uWsoH*Q*NH6%aahVf?`zxGTuZ^&!fyT!+~-I^LQ_+(L4HS2QK zS^XA@N_Puwte{a>uLPgK@|EI4M%6f`^WRdRoRdwR?c?`mxGD^HjQ9#cTcw}`&(vOo z7I~$KF*tf!IEr<;oDb+NNzC$$ka8@MQQP7dAT>V#Yt@CF@o`rcUL?su+~5$@#e1$718W8dSa+L>?wQl|6=Cg5k42y(p4El zqGwn=C=*cQ;jit20$e{pOso%!PCJ?|0_D8caCC-2WchHt;ihbGAQQ?qw6{xwlIu!t zwxC@H@{lI-M5W9#q#zWcAzx*~Es4QvGL4;w7t|tWX-|Gut*MICE|;y?S|-KHQEMjBtPdt39uLczm}s0Jy)n_;wyCv@T<&y@>5Q)hPL}D;NX7(d z0ShLJ3z5dWOGNz;2|;NkV!?3Q(G6O!$PQ79;MxNBa1XjEp!ptM{578nB(-ODHoez+ z9DD2u8j2?Yy>SVCMSe8R!MA}k+zBx1=I9&^v!N&m!5nuHgv01_b}`6jS_SIz8bhqc z8si||Z|cC4PWA|~3L_7DM(ly>7w{cPoln}A00yQSw(ZIeO_KDJRC-ENqJ4qZl`z8f zHGeAIDq=a3g0fio+~J{JG4lwM9|X$mRwGbSvJTTx%Qoz$@w-`y=7wT5`FtRw%JRp6G%qhiMp2emj0jkWmgY75KC z+H`wptWC8Oq4kQ*h0sp&YS<rpDr!;{~tZ` zWr{R58%lEiG%m?Bohy@QwhSx&hJvu;8JKQ%Ho9VLzvKs@hWQZ3#=whq=*m(K<@*Z| zxgtJ4Gr54pxQk_$RpBH-$H^yowJN+6>O|V2gTKbWNJF4Z-p7=|{hN{mp&;uy0pX{6 z@{wEe(W&tId`!hB^2ImjOXSqnNK6-}BRh7Jtn^dVP3*QCGEA%>W||KZ#fD;M|CD0h zTznieDV%!2epY8$ePR;+u6s)5>O(d@6=sX$N#GsdF%`TNbx-wI^j5z_CdCqU$In0) z^B`NCE=k93))_QbVNT*86Mmg)~GyaILp7&r=@2PG!t?o%jZb?T~ z%w$Lrh7F3ll@UOpIOv_(ru*H+ZooaCgY&}c|NHe*54>&v6O|jLX5aOtUH3&>Wl=#K zOH={VlHbBtJeYhWUgls{<%BfM?AIf>9f9X!8U=wm%bO4Q{!!M`ok#RTOtOoZT*~c?F{-x2 ztBiDKry~cL_!alIbV!JG1@-GYgG&ws;e+XvJuJC&5Gxg})GZaMR8Ng1YUY-TRccTO z;bcsc?Y3zUbRHSN-^_+!DOa2VM38RIhJdr9y!fb^4oRsw9;vF3HkgAdNph9-uLePq zGtCK;T{q~C1vADPOg@e}vrXv^2o1b)Xu9ppZoqkJFlM2QO$x=AEh_HtQj59-0*(+7 zPVd{j@7wM@Aqk!LhTGmU?t#_A;HR8P3#m&lEwn1@Cd=YVqc;GV=Ly+%(C0LKh=5=q zhFu&SjvcFThu^{uJuSv16n0;&b9Qim%G^eHh_PI2D+AtQL&H#pI7p7==3m#@*D859 zYDE|yP9&y{%T$=02jW!KQ|F77!D)ipysQM9T5Ten;Zu&a+J1{4M)!&p;8Klhct80| z8o_SNs13W4na(kK%rOmxB?_d#-q%%vQd~A4I~hF(=Y(qQI2Fo-Gpmr3@lv+9U6OoO z2z#sz;NDQ?93&ea<}Nze#`d!Dk^D**yN0nYhIO22C?nYn2@HqBt#VEF0J6ml2fURB znwi4E75irY3QZh;)KpjvqvN=iLoCbTpw=>-+`i>t5*%a)o2Y--iS>`B7CrM(cX!C$jq7e{Iw~PQzBNBhVm>`>j`ZP+V9tS^wf%WRb^xus20MUKJf<#oY0Gq-4f7!3geNXHKqE?Bi+%$RD}`C% zUtWXJ#>=bFfrbp363&XSRadhgTu0Ofy^ygZLxQ{Wr_qO@in#j;Sqc?@kHE2-CpcR; zmJvZMm*z|4G3Jy+!L{C$b}rK*z_gg6rd#qMRG(8=626&czBHMqK+IIA58x`_ER*b4G2dWpN*2>6@USZ+T^ikqb@r6A5+GSL zjVXe`5ErvxV%%Nci?_Mgb}*j4muZ=J`#>!{6E-}aM%fU5PlbOKRYOTCh zb9ODT<3dd`+v{2sfwL&A0^S5OXk`otUyHv~CA#d?fmYRSQL{8CJHb)&=S5Gb0fsVa z-Bst*Gf=8av<#bC|1lJh`TH&_vE+0H?*P1WO`GmojXH%#{c7s~GycO&AB%%TAd6~L z-8BXvjTE?23Hq`-l{M=KE`4T3r7^>x9Q$&X?LJL9~n2yKX5)k0x$r5QMQT6166> zhE742H>R-B!0x`$`?4Vo%W^cyQ_A00S|C# z-Yd|!3~hi{)7Fb^TvuOW(ig-TZKwu{(Lv`9Um!o2nIC=-qRw5SwSic_V@d7VIJenwg zX2vErJsKD9CwABLD7uo90Clh}a*<`1T>}`c#x&BSF$xnsO4C8hGI7ee6i}t6>iFa4 zJDGoJPB1hQ{B)$}`k&&~8ry84Pgz*fPdkql?;RR~ZRulW5L9u_xFj}o;1aBv)}GL< z8R1Ba@fcWd^tIK*QnXBDx3`qFtNj{}^h_I!U5^xJBP1n9tRclJf|yZv?@W1O*D5yms;=N}dG_vq0xkZJ{8T645u+2h_7GYK4C7aZDp-jEy1NpGJ)((JMDNH>5+5{MgNEgnWIjw*a>KWc>5!iYX z<2bMz2>~~FsX?w^Dh4tvG26&W=curv^+jEl`$&}$8edLNwrWC+=4PvwIOzF8I~F;6 zaEs3uZFfCibSf-c7%W`YTsa)vVMB&%hb8BR5n6HEQg3oA$hWA8Ic+l8qD@*UGhMgH zQEdeS#=>uV|F9StD*G&b1PmDEi8T<1L?B0W(vU%-Da<8kJx3g)otKV4_R~mSD~E#e z*in=tV92Pf*VsSYizV5p5ft~`Nw|pWVoO1J*$GLpZTkmn(E$1NTYi4T&$T~^eNTpDI zb+OGvbeqg~eWrO6Lt5BikBJ+SI=`syLD(SQ>_qgM9J`*4@9un3xRqOx;WbR0X2}?? zZjMeDrziinN{@opqhH$>tOx?Pi*)gHao58=_aw1-L+?G4!CSlc1W>pGd#Gx&=!SI` z=@=f&g_<#zrd(ni708$;10Wtze$1G3pEH0>47>pRA_mUq2cN&zakPMrD=BTz-4SN?yMtwM z$p|-MR!>VRGOcVN6^(vaP25`gBpUWKQ#%k!et<)CJ}!O+P9@aD*yv*+Dbo2=Q?W!Q zu?p~x&d1>LuI?qXsm(lj3$?x-y`NE zrQLcD&38_72Af(FVRH)qQvnGzpp&eE47_#aMU@-v1ITN1;LX` zNQ#H)v$mJoGoa8Ym0iP=qAH!jxGwzb@)Hew4P3s1;pTj5dN@_KER&xIS->hVRW24p zNW2O*3JQquJj@E<)iJ@ar3phi=CUG(69GmspMeWHT}iG2 z+IvITdZpi8Hd zzt!*A?8)Fad001`Z1x}dA+(88i%m80)wMj~0}=T5XJ5YaQ1w#Q_X!@{-p-8 zTDXtvd|YF_hBIjOJ(NYGu-DUSde{!*TNN^a1|AHd z%GHKd&Uu2hT4=zrEP21n^aVCP;jRFZ~_-cqUWNSs=6-c57JgCuel_cA#^&|A&TCi30-_8$)Uj>rdZn=Uj~yEPjWof#Jks zbZ-f&Yt#4<{?qbw@}cq_r<>B=T$XWVocY1a^21i^H#~zw#?JF60D>E5tNbu@Y-6AB z)YeA*nRdPXZe4~Pl`~E(q4+0OjSeA0Q^cNS1S4t|!ygqA7I$%`c}UosL^4`Lk_ONG zo;2R0WRx5;*%z#D_k#7Eu(g!0l0($cOMvhC=ifW#`QL|RKL8 z^5`#dv4(*S+W!>v63E&ZYKBpzQqh@|w)sz-u-hS>WrRQLp#ROCEB}^q*NQ}ZfV)bA z5B@v1^`GZ75ly;Add7f8bopWOmQJmmN2+P0r%2~Tx82>9)?!B`6BSNkByXs+ey7v8 zYqlDPaoicX_jVey^z!Pde?(6|8g}aR5FmwAXW7yw;9737Nl$;NL>(BcFn47+aX{7{ znPQoYXn5$hk{PvFJ}BUjnlR7cvJHY{e1?T!rx@eWqH{Fn{1{`F_qZ(kP(j70IcD=N zc+>_Jo^*IjMrnOe=dqy~Aw0+P(6RUxbtTA;nG zA<$-OFO6Ih3q~%s`!xK_JIae0^SZl5@5-cgODM=4RBthI9p1C)2(f#SLkWF`j%DSK(=44bSE1uGc8+~NOz4hXV=y-ft(XDMSlN49m zf#cNnbgg*k+17S{T-NsKxIb)%<6<8`p8z)Phs5n&L|UXY-EnTK^}4V#_~r^3WYbU^ zc|U-VsnrJt8eWq+0q2DF`#R^+c7|qW+;=X{wS;eCw7WVZd0*$lbG5Y`r#SmEVe<| zM8fE6P|=n#I25%?g)FY`2uI14@^oG^mU!iCvT6H080qL<2M6`DmtW1W|KFMcOglgh zSvBmAi1SCNp(CmIe0|GvcMu>r`iS9(QAR6!Rl*+`Ec|^WGGwVLUC=Gsut+P(Qa!>d zW~}~y)V+JO9oJpwd8*Di_x-3VUCEN=M0E}dxoWJof*(>MH&K}+wmX=ZUirh!${%43 zGs{R`87FvU+-q1^A!ZP?lPHM+C2h!s@nFM*LC_vB;1B_(5y8+7B*BmX3WUUTLZd)P z41{Jr-|uhlI(4rkKk{I$ww7$hk8#q`sV^8<){CD{YS0Kf4 ztlyY~o+b%9ixXi7!O*%|GvB4=*3 zOf@+Iv0B-(H7&L3>U?M+ea>UZ=NEP#rK1eHkMgO8oew9lYU}dh<$$(RDj#>)d6Z8) z>^zcDQYhJZl+QnWXwV{a=WRL#vHOAZ6K$v?&yUYYtZu=keLftY%@aWyV_`mGa`*1e z5tF;CmEF5{Z`sWele>3w#N_VXJ1_N_uEwVY4s}ha)pmxnThpTjpG6r3N&AqW`ee#@ z>O(2x*5^{jt&gURTc1uDw?3dUZhc0jZ`)RVTxGoViIs8dnci5?GrjSVXF5Lc3~zj! z=@Ap*;(YWwPogf>v>P!Fh4($FHS7y(cim# zVTs_(a-;a1r;!NIT97~|N9YyR9u(U7`TqsVhLlWDon0UdZ6EUEYTBxTB&l>UzR3C> zdoSz=lm)!MhM}*Ih8{=V_0b$;V=5$53N5bSvR~G&{~dN8t%RGQmfcYhsD3~;$Axxh z42C%wr)&($TRp^ML#<3kX;t6d@PQ$krjV*@{n;att&DcxUBvJXvqcG`wRgJcm|X6z zI?|*&_PeAzhCK*7Vr-phKKG}x7|PI1i9NK-FB)OGa>5EFg#6OaBXRZ?9i)_NppVaviGDx;hwa#^N0qqXQC zwq3xmarg>gZMIZjR2Aeul{v1>paGbG0U|{8PlAuK+)?TUSuTN6h2_QC8_X9DHwj^OAyk#!VJJ?vD zisTJ?AgeM*jbFZb@<7tk#9@c;7Q8$(KU%G^Kre=LO#7!2L?BJ{BP;M?H!QUZFjYU| zZ9U$wrt{6IlLef%^K1!o`)Nd{;jz^8!^ zF~+Y*Ct4^A4W6MBZr%MbDP@ckY>>s0Wn(H-J=&k&8NbKpZ9tm8y)3>v?WA!?KrjgC zXWp7wz;5uZ^q~4O2FI2N;f=C%>Df%aOAo4t=2#*~BAAif0nEDWZsCcY@5xB70@;fG zf5eIn`i*>m1vL(*krHZ3o)1}T-M991z)e{RGtmrgOSx|Y)tE_<6_I3=m*1g|L`I-k z8&5L6i_|Di+S&S#@aGiOM=(L_lS<|%rkWHuVG|0`%KZ zcS!~(^|!x6{jF=QcOR+-xu$1fvQyjD)!6FPNlS_9WV?>8-NYvZ4p$^nto{Jay(J7j zs*8HuHMsFF_ahcWo8m%LP;_EZeV74t|EbfrdTlO=+Y=A)>KkMbvAhi!NF6JMRX%5tI5;iD;xA*Mtf$W>uTjW+TFfsVSpaEWs~U__;V zH$eWM_xTO&N-S9KidunRezs7M0^$0ORUj&-U=5It7-tUM;>tGt z67Taa(lS{(Wg$O{&tbIwoV`Bj^A9NDv4bN{w8#Un<;~5QBUx*|;(xR(_w`=H!7u%G zJfSBU7G8N?gJwN3i+N4mik>k+GI3Tq03fua4$I2GT(2Q2aJii5;w!2@5vqAv{;3_O z(Hp(52Oza>_ONwq098tH;dqPw)D`R)7Y?`=u!+dB)&T`kL#ae1Q!(#Wy(vS|_2Vre z3Cd~`hB(CP(ALQ`FQ&C>2g>TF9pcqe8+_wXU$ulWVeLp)#*#2#4R5m3dh`CTd6$6QKaS9n|gtqh=kGYGEq=6DDjy5$gV8P3M4alF5Vm9LupTZXC?@S_90mgP9I=G-YiYk8-bioaFc5OElD3DR zY_=sRY)CGnVLA+i5nYDr$hwP+7CL2**3+j`oxLa@zg#pamqt?9$c)J_f?Q*Wct!ea=UQ)L-J2kU2 zhG;b+%GgB+fL6Dex9jdE*oDB(PWTnfj#ADk*K$#U;107xW{D3+g~?zv1l|2)lC5Y; zmMQvuRlNi%Ya@VEiE6B8`{{wn9^X};a^J2Rt*9WP2s5BB*xa}c&roX(;xP#JM%uh> zyrbGP-U6j)U&3Q~v>@U!M~S0sYS8t_=#r+=IVvF1yxdF+1US8*-a_d9*UA_;$4XUw z6s$@Xk^b?BGgOukSsDUwdOWC9Q(aY;OJ3rC4Qxr9wfjD?rM^T#e?3E@&<Dr@oZ|C#+F8+qJD7OL3JHBQyI7gr=a^{N`5p66QI4(fX>wkWrtl&MY;lfr zm(9j0!&bY$G%_wgZ$VRdv*vo1Utm!^Ll`=e0aUr+5uz@pY`Zj*~%k(79-i8G+2xR&RWKa+v=T=HnuR6@(xaBwj)@EsX}{s=8f$p<&YP7G%5E$`ich>Iuhmq@$8>HGw zmtgX#B1?+U(60|UOjRB$Wtl!xwpLhiD_2Nu&0jxx8nV-DH-8fK7iXoL;1s;FJlsDF z0@=v@V1Hb);THkmlA9X(To3MO-a}mD>vsVknj!LC6pFhP$v*Q&ne+LaeJEN32rr6= z9}vK&Qu{c1%VFl+pJiWn+PN+I_}+8B>Z}7z$)-*T4wT>UJT`mIH@_aecQQ5vf{+z7 z2%UKb*5-~Ese8qx4QKX3tQ-J>+3YV*n>Vo?m$i!c6bH+k`P69zGdBOop-h6a;G)WG zafQFngiQiP3h|4zQdEB-o~6_hV+GTYZ+I}C^JZ?uB~c@)s0ZW(k%gjvgk!$y^5|$b zD1Hfy@;?(o2$|i78)DkV8wM&$N0u4fJl%kEqcrLHDd#3ZZr&ol(dkyu;?K zN!+mcD_E~+!ERC_F^da2USL|M0=({ePJZYsjro)useK&^uznZT04dD<<~?`)TlP9@ z*|bd%L^5e2fCDu@hyQa}^m;uh$I}f0uG%SInQJej_H*Q2(2M;9y+#XfQwyqJc&#C* z{-MYDeqJ$y%nEeOZ!!elf7dtBLwNx?%my`zzPf{&BCwMFGNf-N8+Fv{ui?-Me)>9T zfdNo81STht;vAz3b5cw!NGCZn3z+l&TWjQLm#YQux__ObiT&SQvUpjVq*0SN$M@qP zW9v1^*<=4s5A4$t0u_wRB6?B=p%574_}*CkHf6FzdIYCKc%)PakLF@RByk|%hOnv> z_N;lnEgTmwMFOPo3ep;&S9Av=tZn>}!CypOW?ljjC1Jr(I`N1#>3G#ahborQp?k}G zUe5{mIejV*mmsM+frQT>Xvp}@6>i20Hs{cwcGPH`7+}y2I5EQVuR8Zcn9-#`eyki% z9q2zUYW1W`ebzkt$&#hIGvv(2*(!InBh`RXvomB4JOODd0iQt$*{FGc2sje9;#S0p zGmj($MWORb(EXiuuLiwk&cjq|YR)&QB2QX_sU5^Cn-c?(@i5QMgk((KYTT}$DB>_d zIIWJ41q3BLOpLx1Q>j<;cX1p{GsYH$9!o&e{G z0R|!!1o8gRvI87XE~_)bvLSpOZr-vTW>lqw2H9sn(_AWsO8PYBKVs~05|JQbUQ5fN zsMxb_p?%SHN@u9!iI?ViK+3G2l@|B)BMELb|t*1(XQ)e zryT@3gf`Wi`~a>uTOZ1Mr}TlWfawDQdYnpMTd>3Pi6{X=Q>xtMW$x!g>S1d4%(A?&mgt8*)}CfkRtie|I|rHtvfhg3@X-d z9%l5jnUM018tqX6B4F55c(@>KKwH#ZQf0&TO0j}vw6ih$KKZwR63Ded%wiTEMEl`+ z^Rp-KnYxjsKHA3D%K)20HRRJpMNt`rSNJ#z#-t=?yylMBrD^m89chIV_eaqoKxK`A z>p;i6_y%2u({Qv>r)s4YrL>Hm8r{i(vNo{qe;~$2>IJnWy=XDYi9%`E?V!`Z4A=;c zrZbu+AW%I|9doU+Rx^$IO*?ymROG}LXK#i^2aq*G8aGOdWSVU_z&_U*STk!HD?Qt<30oBll+`H>ka)I!a~1_c)JV(!wIT$q73f0r zNTt3Fy{|)Q2+zyS$w6V>*g$baah+ckh(Ops|4iX$-pFHyB;r^f5Vkl?7S;a0Wkl;3wlbe>9p{ zCL=jNp*RxeTIc65b~0rk;ruj^1X!l0(TLqepTwNU?J4U_^!ekCDT{H74T;Fabdk}0 z({T5~GX#mf{nOJibqx2)1|ePX+PP<+&%+hnU!U?`;|};(p9WviaI8-#Rsp6j@ZA*! zD2R|{)&ZM})F17W_ZsSZ%loHN^Hc7QX5-2xjtp$O@l@(Y48~~(t|)$K>QM1Xuc=?0 z63^M!dw2@*o)Mjziiv%?CaC*igall5a3VX}nrX&>2AIeG_Zu3$1R5jCaoQg}3Mdi= zH)s6hF%!%*SCh^epS0AzQ}J*+_Wv(U(nB#xC6nXT_h8^be?9P^e=_g@YzGhKXx>V6 zpw&O-=2Sfcl@8j{RZLrJ#1~smsIoVoPH3k~>MRj`O}aA&Z1^E@l6< zkn9#qa$ev3`qrhg=wX)gF*B44ok6SW+o4D1N74V58fuk4NRuX_8Iv?!qHXK5 zh%={j5DAjPpm~xZp7x{aA zQ+q%V_@Qg(37$L;s;J(>(T@agV6w+-qp$Hwnv+pV*;Vk3kTNHKw=;bwKV@62QZaPy zeZ3V<<-ic*dTcs?Bl0*z<6Ot=c($$OTwm3^72$GU?`;E_-=(|%DNhH@_YIEhjf4V& z<_SMJ#uEkN3TBV{$y5FIi6-|P;WTH^(FV;gV97yAQB`dvr+B6mH&oVE^PsDtGM-5M zp=wohra!)#X_DP|N&%>7lnOwduCG2&Od;ZtiS)_?g@nEB7>`w(e?0FTPB0(N`;=l?Ubf+k@FcHQ~(5iwpc1>dk`o|ij#5=M!AFw9h?xi$76dpc>at(mK_#5W% zN!Ht-`904K6(sl$nm>w3?>sr{Csfi_F(h*wI;Ljv$?`z)0U0hVe+Ez#n6k*>w4s;? zB*do_Jq(gMZLY<`V!K418pK6fJl9|3 z;NZRG=lY{-=q4Nmg#-m%khtbRd9R>=W1=13%^Dy3xJPZx-=ccGcI2tesBweJVe*J_ z2?Ztj(6bwtrl&%N1vG=vGHe7XVHt7`cVEU<0>53BM)!WsZ187d;>&x`h=c_DddCO2`k1L>NP4wUUSzVLb+>d+|Ys9zZA>G;j6y zv`wpHvUUravHED8I>*;c)}Pm^p1nAp9rL&JK+j$h&pye@jB3=8NBiTML&ZI*E9?F7 zAuUs|i>II9YC~)K602#QDn7$)v|IDRX(Pk0@NCdfeG8s-KcQ?Mdh?*4P*MBjl%HVE z%}>;;PhgCCM7>~YPjfWf$ugGOiM}K2*b$T`xWzqFFc}4+8}FPA=3;iG*ojoG}fIGi?AtOdG&F(*_V_p&53UMT>jx8eKNJUi@RkDJfui zWG6D}`t!L9jZCOJ=`{j9YV?=T>uL6lOLri_R);;=ezrJ+^o%l)`3#1%axSPUi8fkt za;M2^R}%U6B0H`#I1K_|&4AFArdc13-*b zNv9LHs}n7{RI}g5>vSP zc_vmFeZJBpX}P`3Gn^c2^VT3;gLQTsMB@3a>K(GwhpJ^5aV#Gp8-5&5dcvw_{zUzI7)1rzJc1&!O z{*uu-NU{m7+Fmz0Q!;81+s1CFY|Ur~_@GYP^^kZW8a2fy%<^;KerA@i51DG4_ikJ+ zpMf@NO{|r8w?H~|&ZCn|OZ%`EeEu?Y^6leh16oVd(gs>CLOiFot~C3$-EYs-b_o9h9X7>4Wq+Hc|gAdPFew{Fr+p$mm=2%uR6Lyhk61B^UXM$gAetSwTJk<5| zSqLZhFo9Vc!}=#@Sxi#oZ6#VOPjj506xBzkrM~a$kIZghl(HK>*h)8D(-sjv`nFjwQJ6j zpDqogIb%y5Mu!a0=5ap(0W#19yeCN_d0O?JB2Vlhj*QbWrEc_x5Ex{~vOQ|Kt$Llr zn2Wg}I^`=CSL&3}5(&6vAwPIg4jtZ}VX1*~2^o!yAmUxt!WQiD-99=m1(! z`x@1a^o>o-!UGrCqoiPZu^*N&CigMNZ^8`5Rk)k zP3(`&8J-DXK`+DznO2@@3UQvQV|td*$Bxt3KFmW=xdYg9dJV^3c#e94@wPNY{(%uk z=e>~0vRRpc#~zO?MMmc>M^fp&9!Uy`8KZqBar8CV_D&Fr5D_$%I>z&D1U8=%h4Qdz z6gQ6)qXOqS$}g5*JmO@oS3C-?kjLbY$8dB;SK?T-kMTpgI|kVx-VdqZ?L>4*bW@!u zApF9+z?PrKd)4~~<3%0PMgmr}3HCN9N)_%-2nkt12MHe*9R}1K*KxXOLMecEnyAH= z;nF4o0!;R}rPXG2v=aeymZoFpO7!RWl=?I2iI(teeW}7|X63FWFnFdxB&`en;Yem$ z$sCB6_EOR{0fS4MPd)aoD{mz70L_*dToOo?HK_gs;E}`haY~bc3V@JuuWU{uZLyU> z9fhmloCTJr<7|<&@=+=GunV3&$_XQgXNv2kZ?hXC!PT=j()@TAp})_6`QmIF4~&At zqZJ+jw$-Dfn#=wpqiqC%@5cWb=(xT89`pk7=`+o+dZ$CNi9zBQAe|xnl>wyiS5*i|FCpA}j)}rDG_LrZH;~;1cf5u{4ZD#}@J8M(Ow*tN@5{nbQxtM7a08O0iPU)w>1T72=a%7!UvO zul4rz2ymE-U~kw2k^96BjCNDS3b!fdo7?IIs#Z@#fZ(3UW)}AKL7Y{lz$#{vMrKpA z_d|tncde9RSM3hiif{=kGa#I+7j9B(ZLGJdk67;&!U<~r^v0`>KJ3PN@3@g>X93E5 zy`n%HVh8FSf-})|4)(5uZOjwvio4O0P>%5Tg8z3A>Rl)TY^kn+GdLQB#^O`hZW%_Q ziK=IAqWsiN+U&CgLfqECd&u*|?LtPm@fOhZ731xMb*mB;(G!Jv7xngC<1JD^pfO9L zF&tv+Tx^%m5Tu+M!3e=k^&%q1r)##+ z_jGqZ6-;u5HeOjI1EC6O?kf}XCd_KTusc2 zrdR#YP>6H)a5SguvEgW|$R0uJV>Fg~cqtlqTvv9)-<^IRLFkaSXvo&i=d}h`3ao2D~Z{<*N0vslwPvqI3<~j1G z956Te)KiPDPva|B^vLAPr|=M1is&r6Cyq9&ud99-AP8aszv?7G|JA$vYkhjWML;LZ z|MVDJ3&T{P6&4ib8yvI6Qu{oZHNqK{Ob`r&(nUOA;UWvo0B=?U433W3Rm5vzBv*5p zrKskWRKu%!<>+|s5EZjN&?|jKpV-R6Wxdv0!IstAyt`n=G-OPWtvKQWTbdSly~O&a zv=%gWSN^g&>2K$FF{dXKHEM$&!fb$wm2t?<550r&9~rOe*;O?Mo~IST^5ruaNt&|{8ACUCK#=#l11U~UPIuLiPFxfkp4-^O>j*zC&3Umw~ zu)z1IcY!;4l*YQmkN~Pm)kCSd;GHmT*pM2Z4R#`YFug;?*+Lv$^#c|$66iUE%_|CI zQRvTEEgh^dAJcUU!ojo*4`4fy2-AmpJ(j4E3Sfj3$YEwj#yjd+$i58X7G)ksRXeWG zZ-Ng`P7#486dw>wMw3!bc(WPT=}<0VufZxMg0ehIgr5iCMoaH|bnh4^osca{z-8s; zF=!2RdW;EP>ry~b>_}B_ul@mHiorCJxqbu-d_?c_00Yc;wXPVvLWWf2Z@>%)7~>za z!1V;dPSclwaooX0rxpFV#2Oo4cBnWvV0X@Cg60myMje0@drAE`^g*Xu;N@0p5Nc5ABRUWN*oBOk5jzL^i?qm&fFeQ8iIv#bD(igNg zbbSK)3PXV`F4mVq4gteHlnX6Y)&`LHV^I8SRPs(EyRE2Yb9OrOY%h{0Fy5Tj7n1Jh ztGg}PtB*RjQD`Iq+yn!|fL1j>PBK&}I)c*4!lh2=5%Ntld?U&&&+jV`7=XYlcUAXE z#ubQC=k@wt*1s1w_a}<+oQLC1H02xQD`nEX#V~j53)ISKTEp>5BsD9WA0=`EQ3A(& zatYHh9#uSIZ*@4K%@xO6c*H7BkHQOW%CM$BnEM%GqXjg&*wtN%Zb9ybq8If7BZDv# zd^!ihfHH`rntG`=V>| zlNY`*#CD}vxeM7`LsvFV_8=y^*wfoM*@8Hxb0%BjBSPth$v#e`v4rQ(e*D*`9ce5r z#?nSa8Y5r>07n{w{a)Ul?jlWh!6YGbrs-DDym@P$ZiUYyrVL`b?b`2Ax-;G0lM~Y| zafY@enmg4SlA71*)RA`3-T9PIg952Y;~)_07oAV?UV1)B;L3T27zD$vq4~Vi>s*P(bsVc(b4VY+^!?WO1!kGNw!*z`-qRL1~xjuxbu&;l(jDHG_`R;U&;=^iV|Bd_UodQt8TjkGVYV$u)$M2YA zfS=C+QE*{}D3l_{^NQ@HT%~W>`6w?|{-@_F?8566xa7S5H^wB; zTL%{GJQzYIw#WIpETsDK=72~kvN1u;AtJl&X1nO*zMebLquMttBK80qzVVdBcRUie zMz;C7co~n|MhUZ`lJ^X?@6EEqj}H`j2Y*Wt((4=4Yqrjx|4(mkT$+oBk16&?pp-h3 zN*=Jo#aMw_;GDswbGp%`@{lv7R(yr6QYVL_gQodJmg;)K8WNOgDEYz45JxIo8JZ%J zWKR0Z0^#Hrst~yVgY9#zu%JR>_e$1LJIA%gk95)fr{RoJnALEKtfjdNKL$kALFmG~ ztoPr$6jL$o(O@*KpFB zVq>CBj4zx>&}IEX=`0CKfHU055|7LK(xfuEV98zyfyNH7#Ml9>3^QOQn3azN%*sav zGk!ld99<{3w6@{QsTcPS7udv*d-eyZXNxEidr_?0ru|8uPyRLSEYtSC0b9S3w)b{% z@c&AHetDqu#;$MZs_PqIAb_{$#wTAJf1l}Vj04J>oWE|n&ZFG<1ATPlTmUb!p>8U8 z!rm~f*pwBzg#E!ozS_=vpe>iFtP>WsfiB)cMUY=D=t;iKVDR*GyRvZ|0A`7k7g`4h zr_W)bvK~h24Rh>c&za+^37VjOt%(J^A$h195uUDp6+1A;G<4|N{gbtZLaVLaU%j!< z)3mAX+Js=OiC|4SA<7 zcSXFprA*vN1L7~19&@9f?s<}}Bo@bT5_S8PzaQ(wb;_%2?{GX1TD84xYY_0Hrd;FEu>TS;}y* z@}N7BFZM*@<;gH@Cx(4|8IWOc+%zeO^X+>Xe$t$@-=lKp_w$J}%!-*z5y`Z11{%im zJhURO9O6IJTbxCcLi+*0HY(F}rNTnOMt=^2oo^uZh1ZUvbn{qm7TVG)$21jM<0|e* zT?=k8oS*PipB!S6P4P@7{BTaoS**2}3-+)hv~-(OcIpaZ*Sa1Xj@W&c$KF=9HCG09 zG-uHuR>iQhSR>Stjmd^IuJT^WJb=lEDrtHLQDrOjr3kKzSZ#JP`kK){ABensbXAv1 zWCA1EprEN1RWm+3BdTuTbHY=COv3vICeEdL*&7B1Ud^b}4l%k3L}0vz2rct_O0#V& zHMWAKfc9#r70XY_7H)s@-4FxZIzgip5|O9s+cYz;^+alU#mscarl-$kY>EL_+X*Qp~me>E(Q#4BBT~^uhbQ!yGB>Uw5wA$cIXO*;Mr(SLP2Km!L&xy zvcAj|MB@))ZjIA>*s;W0wvz~D74rtG#3e2@p zPX-4WvL+_1Q+?4%fx70pD4Qwwr^vDT5chIKV`?qXi)|148X}*3 z%d(Uij27FFA=*WPksZ3I3rSty#RaR-odR?w?Eea(6KbK&SudFfnu&Ud17$&MuQ)>p z9H!{qF=OC?gx24{m)9}}FF=IaGaA*iqkml!mS0~75Dt$14XooE>teK5JS#U$qnc!` zdDq>oRd&HABulT<*Nk3LUp+cRjYDc&ptb|`)M!6m&u#Ut(T;k=OkX*AF)cK-z%ETp z23VtCq)OXJ8-wr(z=_qF`?cN&0mGBJ-?!H5UDNxt@%jvAHsQmg-Vtv68*L9eO|^$r zfhkQs2pi?L%T6v$xc(%UtfPMg~KdYQ9yPYu3?tb&1hV2mpyL4Wh}E?)!J#!V6y`b zS~K*4c4U`izylh?)+y`$%1e5;a3M77W`7t4@=8Gicmh=!b~$@V)QK>pS2C&FGs7tG zdPX^9M6m3fbNp9|T6~cv(p5;|CooL4!K>^Vs+wy#h(5lA+mhs7Z$CysCgszEYkKM& zJ%5thZ)JJ}ae`9@_^mJ>C6_M794N!OdDA*~@8K>?%}n}fY~ZpzgQ+t_LxOSmNeQVs z#UVx!?IW4QF*JD%Mf6m^d90N*BD#u49CIlPARaln>1uDDP36BCtBH zaG|?x;6@B3O2}4lZfLN2C)-taDn=wnAl;p!pA>y|GnnB3FGz)>i!!O8Jz6dDPoi#e z*FWLq-)v=kDMYQa+xB}?-9+n5Nv@*%YrVHCyr5Z~e1M@Scjo_0A84y>`e1MI4s5pr z!j_oze)DcZp1c98**2-c!yzt>xV7&~H7Is1qVtH1GsGeWE_S{36+%UA%oUQc9aa<-yN%^byuDwu*wQiZsJ^CZVO^w^O*E=DVWo7W7Qi&WK^YXQfcMN#Ji}ytqfMh;O%+BQwVbKyHmNq^dvFp z+ViXscQrJrY@Nc?-d2WRNR{WFh#Ph*S7i?eFLXGr8k$r_T(xR%D|;#`Z!0^uv2s;* zoXXe=obyMBOitwrjXB5kQbWM?dN=nRr3d{~mBv=iQVzKJ7l$l6^9N9Fws<3_%(J=? z(yh-y%I0q-gAORCpgy+2C=HH&HK#~BBBU$uL*6znl}$}QayAmubrGgl63#$XybvEi zN>t6?-sb5mi5s_B*|{!?I4_xulGFq>R>oK?@|zAD9%+1LE6V(DZh<0%+`y=XEHY}- z>-P@Y+_i2cRu5T4%fk|8WoTaPN#xx4Pw$GQ*@+!kBwfv$yl+}r6h_j5%z@{gp?K<4F^<$qIq9aj>zJzL}7uJYnt_LZs9c>3rNZClu*Q6AdU;?Zl*El)HexP zo!pY&2aq3L%~dWy`yi^{V&>SgiNA_yi}->Irxf)MhWcI;XkC4PQuw!^A%IBjkm4JR z=Tbvvn4Dvds1SM1=uVrjjiz721xe|ankm(W*hEJxhLYX?7=dr2J}6l9)d46Of9W7y zn=Ar#l0Dguba%V2xn9-|31)a>%!PiN-(*v2-h|S4Cwgu8S&+4meVwRNVO>4?LU(V` zDGFp9w&rsXp?{&-Mh>w_xFYFc-`FhNHeMzqbsI;uwr}VekBDt$pE|L6_{q4Ci5A0y zVn?Uy1x2XN)-yz?ZmX9gRWaLLR2k6&D;g5MV~0*EI+Yk6Fm|PS%%{Q@r0@n7rC~wv zqoQ^C6o7X3DMHPJN+`284q*cKko$#IJrT3+r!>LG3Ww}`3_9|$QnTWk$31;xO*9>0 zjt=^HBSdWrAsq|K?5|Iy~z?6Y#m*fd$;~L|3#7R>tCN=#Mgb6Gb zQ71@9zi?O_rE*0#QnUI)pQFcQEu20xtN(K#3b5F7Sx4-_pxHEi1wrZ=yLa ze6KXbYC1wwrAt{08Y_)8k2wR5ID$*0ViB53;1qKr3}(DhC}*+EbvvAPOOWtxeT1~sG5Sm9ypXTh_p05K*=VW6`POl8tk5g&T?z&~u+ zci6|xRJmcUlWN<2@g+40Xo$Z6 z#+|5Ari|?U#?c-Wd#$`hYmVH}5nn1|Q3$E@>e^9J{Vx0gA_J}cE~pD=aVNh-Vf#(5 z`Y)zRcNY;(b*umfv<+~<;6n+y2WqBmKv*SAr;&~P`xw{eCqXVbR^G)`@ueT^u|T*Y z&4I>c^GEz%#%MHXdZVoXlT=ImbzJGmqCCvv$;ZSvvIa0mTq%nY3D1odqzaLst{2P9 z^ZXNfFETD5mhy>q#6>v*UKd5Jj4@FnSe)Mk>dLZ&!7$;FLHI*Bq*xINVY@3 zL7=M`OrOEJv?(JEX@P-B&;!$d7Q=L)rAQp9s=XTZiRdKeA2QdqI1J1cWCF5)uptvF zKF4$f>cCqeqkocDTO_pP0)MPYm#_W@FqF0uR^qNtfHw1lH3rP!Q(=S$t7L~THiDhTM(irboX!{2yP~*75rVWN;< z4tWE@-@gG`D@1d2C+Wg1^@xCMz&KjYCA?Aa=}?a}Tl1`OV~^ub-34J`rvm`$gq9A6 z0txjsG=*;FK#K_9y!3(kQu%bMp8~*QXOO3e!TC{Uex)YJI>&6*a|+D_TK5(3ghGR! zRf{P!lkq;N<{0og5`8^mq+|IgG?Q2=AZldOt#Cr)ml_Or6yY|5|vr=bYC<}(iyTE#%{1hQ@5xf%o!pX%aFyOe_E@rseYeY9Jj*DMAyD4s=NWJW_Y%O z2~w8NVfwwH06fp?fIuG^ZOv4bT`&@A5XIIlIhuE11#Zo?bczpj_RVXV%Zbp?+nBRm zh^kSrNPJY$hh$k`J^<8#u-zo#G}&$}#j+B>{+zU3qUJ|vEYwTyFxk_af8dgG*IfhU zKYhFvy+h9Y1B8 zlU*#A=yC)4pG)$=|1jNaH~(EqGgKeY$UD%4)xr#<2Ngz>E|WA~|kX zxNG;xxFe)X5cdHfmmthc9Z`HYgqwB61UWd@BSX%iNpJh2sgSn;n>Zw3OOjDXyq4AB zxro;s#B#oP{j(OYiGa@HwKI{nlRMpt*ZO)ECfkbFnl^YY;$IOPM@A)5?>s8Bg5 zn~~7sHCs?x@!D|_9r1bzdYQy)b`ZV_-NieBpdmMLpT%n>udQXl8(*qf)vh6l*Q*k* zx7`T*BwlMzFjRV`-sV7h4)M?j+l5w$v9M3>A|MfegM{hrh}V_G>!A*mf!HwsZxge4 zJ-tc1p6-a(t07*q(eTu8Ts60eS5S+$q`+aTUE?YV5YGQ52SkuBIw8@OKka*_I?XX# zO%&kC7XR93j9C2ch})NK61Qo4deV}U5qDa0=H*UH!fHz~)5b%I6HMcG`bS6no<2|f zCQoq>`EYxEDRiz^uOfFd22E2({ASK42Z3avTRU8e3RLTC>cWsA(kVNKDKpY`Z0UMU zNSC*WVKRv;G$zR$vWH}@JuG*`uiN<&8Vq}rM6Jxp60(V1m5?r8@IlHZ79-f&2jrW(z~86RPAe23B?rI!50!1r5}+7!S#;kGT|45Am>mt`o@QMV%d#u z_2?E8=x!;^^0+UL&>YV?T|#=Mknb? z8q+Qi{XG?f(CxQZ>+wziuRdCY4e+>lKUw}VXsiiJ6m}KkzQ$f+U_Mekz%z>)bc>fa zk98UWH?JNq#`ZG-+sehC6&j*cR}gFpQmai=N;Xio$^}KjY0*e!1XOwr|97f*!D!Z7 zaQad%c!j1jUh)jV`q;0U^?n&DlUBEU=($Yt8fNUmcHNLP9*ym40aD zMT9n!q+5klJYN{Nf^7h-eV#t@nty)WL3*Poull!W3!1hM33^h3vNj?mjq#-6%8mkD zRSH=swxAVaR?wG|SdSZ)|m%0Cigo0;y@r6EYowx4akdEBiTm?69 zVT(%V{8{zI>0&*#sKFzc%cJtPK{>VgaMW5jr!bz#<|=KV?s!)8 zn+@~wrX(staoof_zFm}gt@nD^Tk;wF1J7|p==l}JoJ=h-d}t3};Vb6x?H((N#1%zs zuX@T>Zn2RoklLV@YizAhm0C(wR9WexD~c^dwxvTZqRKy3@$z<&OD2ugg$L1Ujx--o1W%DQ?u!5N|Ng5bb+vK=?v|nXd zGhm@c5~E@xN_j1{Gvham$&N&xoG|6LCkFdy&b-*|Qp5k#12M?m(i4M>K~pz@71hsx zV_sVz#P@y+npoDO>=K4{Y@(~c@$z>-7TTPy~gv0 z2KNL7L{T2re1eM#L=t^Gr7NE*M&l8^Q==$ZB5AGG#P_=CqxW3_} zm36|2y}mh?PK%Vr@OV#3p{}77&NgYIb3G?F%mT*dj%K(BVOO1f=vl@CAjEN|aIw$} zmsJ&Rn-6#Mgs4bEo)8(6lYS_@3+*BFLq1X1!Q>;!d>ADqG|Dq*V*PZLNNYQ<5~T{+ zTnRjugcMR3(L?41((aQn3EAY;nI})kqFA9wj}*q~BO144_GNpiyff8f)+Txc4chhj0v5!&Zt8`$h3^|1|mym z1YF{0al)V1h31k%>=^z_6V+GCnvRSZJ{bitF7t$q;({c-c@^y~(V7;^O>VpI2DIr^ zJ5Q}NV$*boCQ2it1u#0#kcF^_(kNgfJSMGCD2IO~KzrM0MyQ7l)K7Zj7U_*MK8O^B z4gZWjAJ0GsSf!|Oax0=>$uBdL)Haga-POp@!&EVE{7tyWDpt;rE#wGMw3|!ivms&5 zyC_P%`XHkvwmfb2+sf2fSCwJTO@aZhQg7VkGQNYUi>^h02q{x6b#GaBV=a zsc(}`sH4hol_+ZN6~M8}me+AWsy9hx4pj$U&IB6`G`NUwk1|F!NpQI5^j5N%fm+k<^u? zM62c)oN-e(VN{Cou%7kQGxzpf>a7?bT)=&%37DCP{gcXe#g&S>y*Wp3&L$25!urej zh zb`YQ#FNIkDnPR-s)l5nL_xULuf2n}8Z=M2z4RK* z)QLV+X2E5qUr9Aex{2EhLGJUgWx2h4JMT<1|w|qF%06-&pRV zfoQi97-rE{#U~aT)c~b%4ZOKyyb5>-J;o``Q&lp@-|?KDvepE1cKj>xGw+(yS+-$9 z$D)6gDjHwXXgYQzRUZoIr^)hx;&MqeD@FJDB9JNwncoq5YAMwfWI)ECKAM39x*^e9 zXldIh3js#4y^DTn;cTJFR7{8U!l+Ob2~~455}8?DY7y_fHrS=2)`Dj|Q*tIEr{m4R z=gi$i3l>1JyZ&FWM;=tUoJp$dy`D-QJ&O72s6$ zDnRyxvk7Mt#!d?xLMcYjZyq<@fR0svDqd%87n{$ysqwU!k3FOOdbkZX6>S6 zoHdSrQxMP_kU%;lS0bQR;xV*l+oRz;qIx6_>b9&!aLm=*J*+;?jj%(75_u*^x5@K4 zoee~UON^glhmZ0Hl0qk-Mm_$~9-`-QQ2;jE->oZFjbo(((mJ{?II)t501MTKy&@`$ z^A^T|Cq3)53jYhjfH<#eCDtDUr{Eo|?nRCd{}Z|U$?0KRJKcdceb7pXzcrCW9py{X zvS!uCn4=`X;zh)F=ddk7;-H;IiXVVMIad^##Z!rST|~1W4D&qA;?Eo-r5e{e+6A%{ zBEtFF#bbE|KAm>)*u}LAwU*m@uG+<8NxS&Wz)HgqU{e~! zue65oiGLXl1M5at!MG|EjQwA21w*i&C>X-Hq+oFSEEEiV@C*vZL!n?WQ&3|5URc3! zsSOH-NsK=DN+}q*!mfg$;Y-*>!SL-@Rlxw0s=s)81>=+EYZp{7EYPE1Sg}CCI4f?& z?~jSiJPQS55$(^^9eE~wa6tv*6G_2%^5O~xt1b28Uq-<=C$W#^&B$ zP{BATnTjT!lY-%o_(nqdrzD6x8wJB3U0A_*a@Z;ufB760jQJ)y(@`*hkQEFN2L=MGPfj-rz)#bMDQZVpZTESRp6^yN$6pRmSRxmhN4{K3Z!Jx=S1;YW4%9ogw z5EKl`pn^!ja9rK|A)bVSp=(ktq(@-Bv1%cYDckLqn`?1!RlK-1$J$9w8{=Y|C>T;A zEc?T*vuZKTM+>PElsx&=_!|nwHoy=HMupVJyH<0|`o)Yj2|2FEmn8K<&UAE&1-_8( zF`v9@&!?UFq*z=MUXW7GE))w~Z*VGAudzsNM!AtCa7)|X)2SBpOgM_5yBf{4ngwW^ zHH$gajWRno%Tz1^Q&AE=a6!f5GhM~vRIy31 z&^Hss!oDBr6@O*azC0xVHR%--O8ceg75`0ZBkL7Gl`pDS)DqXFSNv5+uYfXJuOJ4} zdIkCgdIiFNM52Vo(9tX4PD1n*7V2ib!dk>8ZGxq|h&J)*&?cVhXcND;Nt-x(F>ONb zha6xgPN22FBWV*vnIWDkClcDk7oJ|5_`(IWiNEe@6AsXv@sVB4OtW63{N@oE2>nSX zB4E_9spZ113hZLdT6ik(SVTA(-^MIeYA?83xRmDV6?rS9oyl9l8imlvQ8DN^Dps1c z+hG1H%|oAjZ0C*GXGQhuIr}MKuSUFs}ehQj`n`)WdB)cJSkt5_;`6(D-_EP}&i53CkB_)FO z^~_ERia&!2aZ7{EjHzL^)-IwysK^HOp`Fd3v|p}wBC6}E4uNXY9CY_pRUE*Y>Tg=b z;fskJ%g7_~jd5d*G51$!Cm;NX-obK*BoO~P*-e2m0Lt9ns~5hVz(11Nh7uyxDOvd8sA&4+R;Mb zOf_$H>`B{{H@G!)coA0iJTgqL{FZH&R=S44?E1)KI4$)~Jm+)jur!irnn)`ZIqj4Z z-e2h~D-3_AU=k)m;V=P<)-Qs>wJxrOIK9~$(ot4!oj5}XCC>Bhz2&pyq)nlB%`s2d zT(_a@EU6b<>KrqHahIGlX%o z6?rakljs_n0oRTea|%L>fvVZzpuSnImijpSPb8S2K6WJ8O~Mv@RV&>B_Ky~`P1*v9 zM(BkqS>c^3S>*3{yWU*_7?f53(TCc2M^@$7cx>F%YC+uWuE!P6lyF{XGS<26VnOu>1ENlI7 z_Pip|#u-Di4`wBfWv1hJ#M1|$b(|5cl@^N9j*M!0m3%OB_0IGZ4}AMRJai1TdOE+% zc6{er^0^&{F8Y9I^+c;AcgCt!)d+3Ccu- zTog*|42{dRO7h>Zn`VgDA$bn$#`Su28oW$B7@PH;=bR{E%-U76^ON zwjA@KKqe$U)|QGUUrs5{%_f}-!ov!J;J|hEp%q2woIE(cze(phcQKu-jV36nk0wv~ zi4HUob>C_W z*eXRx?T~@t=WInPYo4R>C^WbIR1v(F^Zcp_|Le(3m@}66V


QU<-84XokI_4C&r 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
Zc#inNqug1g< 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 diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index 46e4b334ab5..ea009e6d575 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -83,8 +83,7 @@ impl Execute for RegisterExpr { } RegistrableBox::Asset(object) => Register:: { object }.execute(authority, wsv), RegistrableBox::Trigger(object) => { - Register::> { object } - .execute(authority, wsv) + Register::> { object }.execute(authority, wsv) } RegistrableBox::Role(object) => Register:: { object }.execute(authority, wsv), } @@ -110,8 +109,7 @@ impl Execute for UnregisterExpr { IdBox::PeerId(object_id) => Unregister:: { object_id }.execute(authority, wsv), IdBox::RoleId(object_id) => Unregister:: { object_id }.execute(authority, wsv), IdBox::TriggerId(object_id) => { - Unregister::> { object_id } - .execute(authority, wsv) + Unregister::> { object_id }.execute(authority, wsv) } IdBox::PermissionTokenId(_) | IdBox::ParameterId(_) => { Err(Error::Evaluate(InstructionType::Unregister.into())) @@ -164,7 +162,7 @@ impl Execute for MintExpr { .execute(authority, wsv) } (IdBox::TriggerId(destination_id), Value::Numeric(NumericValue::U32(object))) => { - Mint::> { + Mint::> { object, destination_id, } @@ -206,7 +204,7 @@ impl Execute for BurnExpr { } .execute(authority, wsv), (IdBox::TriggerId(destination_id), Value::Numeric(NumericValue::U32(object))) => { - Burn::> { + Burn::> { object, destination_id, } diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 39271242116..62487790ca8 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -47,7 +47,7 @@ impl_lazy! { iroha_data_model::query::MetadataValue, iroha_data_model::query::TransactionQueryOutput, iroha_data_model::permission::PermissionTokenSchema, - iroha_data_model::trigger::Trigger, + iroha_data_model::trigger::Trigger, } /// Query Request statefully validated on the Iroha node side. diff --git a/core/src/smartcontracts/isi/triggers/mod.rs b/core/src/smartcontracts/isi/triggers/mod.rs index f554bec10fe..7c814b6fe47 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -22,7 +22,7 @@ pub mod isi { use super::{super::prelude::*, *}; - impl Execute for Register> { + impl Execute for Register> { #[metrics(+"register_trigger")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let new_trigger = self.object; @@ -81,7 +81,7 @@ pub mod isi { } } - impl Execute for Unregister> { + impl Execute for Unregister> { #[metrics(+"unregister_trigger")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let trigger_id = self.object_id.clone(); @@ -100,7 +100,7 @@ pub mod isi { } } - impl Execute for Mint> { + impl Execute for Mint> { #[metrics(+"mint_trigger_repetitions")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let id = self.destination_id; @@ -132,7 +132,7 @@ pub mod isi { } } - impl Execute for Burn> { + impl Execute for Burn> { #[metrics(+"burn_trigger_repetitions")] fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { let trigger = self.destination_id; @@ -202,7 +202,7 @@ pub mod query { }; use super::*; - use crate::{prelude::*, smartcontracts::triggers::set::LoadedExecutable}; + use crate::prelude::*; impl ValidQuery for FindAllActiveTriggerIds { #[metrics(+"find_all_active_triggers")] @@ -216,41 +216,19 @@ pub mod query { impl ValidQuery for FindTriggerById { #[metrics(+"find_trigger_by_id")] - fn execute( - &self, - wsv: &WorldStateView, - ) -> Result, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let id = wsv .evaluate(&self.id) .map_err(|e| Error::Evaluate(format!("Failed to evaluate trigger id. {e}")))?; iroha_logger::trace!(%id); - // Can't use just `ActionTrait::clone_and_box` cause this will trigger lifetime mismatch + // Can't use just `LoadedActionTrait::clone_and_box` cause this will trigger lifetime mismatch #[allow(clippy::redundant_closure_for_method_calls)] - let Action { - executable: loaded_executable, - repeats, - authority, - filter, - metadata, - } = wsv + let loaded_action = wsv .triggers() .inspect_by_id(&id, |action| action.clone_and_box()) .ok_or_else(|| Error::Find(FindError::Trigger(id.clone())))?; - let original_executable = match loaded_executable { - LoadedExecutable::Wasm(_) => { - let original_wasm = wsv - .triggers() - .get_original_contract(&id) - .cloned() - .expect("No original smartcontract saved for trigger. This is a bug."); - Executable::Wasm(original_wasm) - } - LoadedExecutable::Instructions(isi) => Executable::Instructions(isi), - }; - - let action = Action::new(original_executable, repeats, authority, filter) - .with_metadata(metadata); + let action = wsv.triggers().get_original_action(loaded_action); // TODO: Should we redact the metadata if the account is not the authority/owner? Ok(Trigger::new(id, action)) @@ -285,44 +263,22 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> eyre::Result< - Box> + 'wsv>, - Error, - > { + ) -> eyre::Result> + 'wsv>, Error> + { let domain_id = wsv .evaluate(&self.domain_id) .map_err(|e| Error::Evaluate(format!("Failed to evaluate domain id. {e}")))?; - Ok(Box::new(wsv.triggers().inspect_by_domain_id( - &domain_id, - |trigger_id, action| { - let Action { - executable: loaded_executable, - repeats, - authority, - filter, - metadata, - } = action.clone_and_box(); - - let original_executable = - match loaded_executable { - LoadedExecutable::Wasm(_) => { - let original_wasm = - wsv.triggers().get_original_contract(&trigger_id).cloned().expect( - "No original smartcontract saved for trigger. This is a bug.", - ); - Executable::Wasm(original_wasm) - } - LoadedExecutable::Instructions(isi) => Executable::Instructions(isi), - }; - - Trigger::new( - trigger_id.clone(), - Action::new(original_executable, repeats, authority, filter) - .with_metadata(metadata), - ) - }, - ))) + Ok(Box::new( + wsv.triggers() + .inspect_by_domain_id(&domain_id, |trigger_id, action| { + (trigger_id.clone(), action.clone_and_box()) + }) + .map(|(trigger_id, action)| { + let action = wsv.triggers().get_original_action(action); + Trigger::new(trigger_id, action) + }), + )) } } } diff --git a/core/src/smartcontracts/isi/triggers/set.rs b/core/src/smartcontracts/isi/triggers/set.rs index a87217bc188..3cd20738837 100644 --- a/core/src/smartcontracts/isi/triggers/set.rs +++ b/core/src/smartcontracts/isi/triggers/set.rs @@ -17,7 +17,8 @@ use iroha_data_model::{ isi::error::{InstructionExecutionError, MathError}, prelude::*, query::error::FindError, - trigger::{action::ActionTrait, OptimizedExecutable, Trigger, WasmInternalRepr}, + transaction::WasmSmartContract, + trigger::Trigger, }; use serde::{ de::{DeserializeSeed, MapAccess, Visitor}, @@ -38,8 +39,98 @@ pub enum Error { /// Result type for [`Set`] operations. pub type Result = core::result::Result; -/// Type of action with pre-loaded executable. -pub type LoadedAction = Action; +/// Same as [`Action`](`iroha_data_model::trigger::Action`) but with +/// executable in pre-loaded form +#[derive(Clone, Debug)] +pub struct LoadedAction { + /// The executable linked to this action in loaded form + executable: LoadedExecutable, + /// The repeating scheme of the action. It's kept as part of the + /// action and not inside the [`Trigger`] type, so that further + /// sanity checking can be done. + pub repeats: Repeats, + /// Account executing this action + pub authority: AccountId, + /// Defines events which trigger the `Action` + pub filter: F, + /// Metadata used as persistent storage for trigger data. + pub metadata: Metadata, +} + +/// Trait common for all `LoadedAction`s +pub trait LoadedActionTrait { + /// Get action executable + fn executable(&self) -> &LoadedExecutable; + + /// Get action repeats enum + fn repeats(&self) -> &Repeats; + + /// Set action repeats + fn set_repeats(&mut self, repeats: Repeats); + + /// Get action technical account + fn authority(&self) -> &AccountId; + + /// Get action metadata + fn metadata(&self) -> &Metadata; + + /// Check if action is mintable. + fn mintable(&self) -> bool; + + /// Convert action to a boxed representation + fn into_boxed(self) -> LoadedAction; + + /// Same as [`into_boxed()`](LoadedActionTrait::into_boxed) but clones `self` + fn clone_and_box(&self) -> LoadedAction; +} + +impl + Clone> LoadedActionTrait for LoadedAction { + fn executable(&self) -> &LoadedExecutable { + &self.executable + } + + fn repeats(&self) -> &iroha_data_model::trigger::action::Repeats { + &self.repeats + } + + fn set_repeats(&mut self, repeats: iroha_data_model::trigger::action::Repeats) { + self.repeats = repeats; + } + + fn authority(&self) -> &AccountId { + &self.authority + } + + fn metadata(&self) -> &Metadata { + &self.metadata + } + + fn mintable(&self) -> bool { + self.filter.mintable() + } + + fn into_boxed(self) -> LoadedAction { + let Self { + executable, + repeats, + authority, + filter, + metadata, + } = self; + + LoadedAction { + executable, + repeats, + authority, + filter: filter.into(), + metadata, + } + } + + fn clone_and_box(&self) -> LoadedAction { + self.clone().into_boxed() + } +} /// Specialized structure that maps event filters to Triggers. // NB: `Set` has custom `Serialize` and `DeserializeSeed` implementations @@ -57,7 +148,7 @@ pub struct Set { /// Trigger ids with type of events they process ids: HashMap, /// Original [`WasmSmartContract`]s by [`TriggerId`] for querying purposes. - original_contracts: HashMap, + original_contracts: HashMap, WasmSmartContract>, /// List of actions that should be triggered by events provided by `handle_*` methods. /// Vector is used to save the exact triggers order. matched_ids: Vec<(Event, TriggerId)>, @@ -85,7 +176,7 @@ impl Serialize for TriggersWithContext<'_, F> { { let mut map = serializer.serialize_map(Some(self.triggers.len()))?; for (id, action) in self.triggers.iter() { - let action = self.set.get_original_action(id, action.clone()); + let action = self.set.get_original_action(action.clone()); map.serialize_entry(&id, &action)?; } map.end() @@ -145,7 +236,7 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Set> { while let Some(key) = map.next_key::()? { match key.as_str() { "data_triggers" => { - let triggers: HashMap> = + let triggers: HashMap> = map.next_value()?; for (id, action) in triggers { set.add_data_trigger(self.loader.engine, Trigger::new(id, action)) @@ -153,10 +244,8 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Set> { } } "pipeline_triggers" => { - let triggers: HashMap< - TriggerId, - Action, - > = map.next_value()?; + let triggers: HashMap> = + map.next_value()?; for (id, action) in triggers { set.add_pipeline_trigger( self.loader.engine, @@ -166,7 +255,7 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Set> { } } "time_triggers" => { - let triggers: HashMap> = + let triggers: HashMap> = map.next_value()?; for (id, action) in triggers { set.add_time_trigger(self.loader.engine, Trigger::new(id, action)) @@ -174,10 +263,8 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, Set> { } } "by_call_triggers" => { - let triggers: HashMap< - TriggerId, - Action, - > = map.next_value()?; + let triggers: HashMap> = + map.next_value()?; for (id, action) in triggers { set.add_by_call_trigger( self.loader.engine, @@ -227,7 +314,7 @@ impl Set { pub fn add_data_trigger( &mut self, engine: &wasmtime::Engine, - trigger: Trigger, + trigger: Trigger, ) -> Result { self.add_to(engine, trigger, TriggeringEventType::Data, |me| { &mut me.data_triggers @@ -245,7 +332,7 @@ impl Set { pub fn add_pipeline_trigger( &mut self, engine: &wasmtime::Engine, - trigger: Trigger, + trigger: Trigger, ) -> Result { self.add_to(engine, trigger, TriggeringEventType::Pipeline, |me| { &mut me.pipeline_triggers @@ -263,7 +350,7 @@ impl Set { pub fn add_time_trigger( &mut self, engine: &wasmtime::Engine, - trigger: Trigger, + trigger: Trigger, ) -> Result { self.add_to(engine, trigger, TriggeringEventType::Time, |me| { &mut me.time_triggers @@ -281,7 +368,7 @@ impl Set { pub fn add_by_call_trigger( &mut self, engine: &wasmtime::Engine, - trigger: Trigger, + trigger: Trigger, ) -> Result { self.add_to(engine, trigger, TriggeringEventType::ExecuteTrigger, |me| { &mut me.by_call_triggers @@ -298,7 +385,7 @@ impl Set { fn add_to( &mut self, engine: &wasmtime::Engine, - trigger: Trigger, + trigger: Trigger, event_type: TriggeringEventType, map: impl FnOnce(&mut Self) -> &mut HashMap>, ) -> Result { @@ -317,12 +404,13 @@ impl Set { let loaded_executable = match executable { Executable::Wasm(bytes) => { + let hash = HashOf::new(&bytes); let loaded = LoadedExecutable::Wasm(LoadedWasm { module: wasm::load_module(engine, &bytes)?, - blob_hash: HashOf::new(&bytes), + blob_hash: hash, }); // Store original executable representation to respond to queries with. - self.original_contracts.insert(trigger_id.clone(), bytes); + self.original_contracts.insert(hash, bytes); loaded } Executable::Instructions(instructions) => LoadedExecutable::Instructions(instructions), @@ -345,16 +433,17 @@ impl Set { /// Returns `None` if there's no [`Trigger`] /// with specified `id` that has WASM executable #[inline] - pub fn get_original_contract(&self, id: &TriggerId) -> Option<&WasmSmartContract> { - self.original_contracts.get(id) + pub fn get_original_contract( + &self, + hash: &HashOf, + ) -> Option<&WasmSmartContract> { + self.original_contracts.get(hash) } - fn get_original_action( - &self, - id: &TriggerId, - action: LoadedAction, - ) -> Action { - let Action { + /// Convert [`LoadedAction`] to original [`Action`] by retrieving original + /// [`WasmSmartContract`] if applicable + pub fn get_original_action(&self, action: LoadedAction) -> Action { + let LoadedAction { executable, repeats, authority, @@ -363,9 +452,9 @@ impl Set { } = action; let original_executable = match executable { - LoadedExecutable::Wasm(_) => { + LoadedExecutable::Wasm(LoadedWasm { ref blob_hash, .. }) => { let original_wasm = self - .get_original_contract(id) + .get_original_contract(blob_hash) .cloned() .expect("No original smartcontract saved for trigger. This is a bug."); Executable::Wasm(original_wasm) @@ -388,6 +477,43 @@ impl Set { self.ids.keys() } + /// Get [`LoadedExecutable`] for given [`TriggerId`]. + /// Returns `None` if `id` is not in the set. + pub fn get_executable(&self, id: &TriggerId) -> Option<&LoadedExecutable> { + let event_type = self.ids.get(id)?; + + Some(match event_type { + TriggeringEventType::Data => { + &self + .data_triggers + .get(id) + .expect("`Set::data_triggers` doesn't contain required id. This is a bug") + .executable + } + TriggeringEventType::Pipeline => { + &self + .pipeline_triggers + .get(id) + .expect("`Set::pipeline_triggers` doesn't contain required id. This is a bug") + .executable + } + TriggeringEventType::Time => { + &self + .time_triggers + .get(id) + .expect("`Set::time_triggers` doesn't contain required id. This is a bug") + .executable + } + TriggeringEventType::ExecuteTrigger => { + &self + .by_call_triggers + .get(id) + .expect("`Set::by_call_triggers` doesn't contain required id. This is a bug") + .executable + } + }) + } + /// Apply `f` to triggers that belong to the given [`DomainId`] /// /// Return an empty list if [`Set`] doesn't contain any triggers belonging to [`DomainId`]. @@ -397,7 +523,7 @@ impl Set { f: F, ) -> impl Iterator + '_ where - F: Fn(&TriggerId, &dyn ActionTrait) -> R, + F: Fn(&TriggerId, &dyn LoadedActionTrait) -> R, { let domain_id = domain_id.clone(); @@ -440,7 +566,7 @@ impl Set { /// Return [`None`] if [`Set`] doesn't contain the trigger with the given `id`. pub fn inspect_by_id(&self, id: &TriggerId, f: F) -> Option where - F: Fn(&dyn ActionTrait) -> R, + F: Fn(&dyn LoadedActionTrait) -> R, { let event_type = self.ids.get(id).copied()?; @@ -474,7 +600,7 @@ impl Set { /// Return [`None`] if [`Set`] doesn't contain the trigger with the given `id`. pub fn inspect_by_id_mut(&mut self, id: &TriggerId, f: F) -> Option where - F: Fn(&mut dyn ActionTrait) -> R, + F: Fn(&mut dyn LoadedActionTrait) -> R, { let event_type = self.ids.get(id).copied()?; @@ -507,32 +633,49 @@ impl Set { /// /// Return `false` if [`Set`] doesn't contain the trigger with the given `id`. pub fn remove(&mut self, id: &TriggerId) -> bool { - self.original_contracts.remove(id); - self.ids - .remove(id) - .map(|event_type| match event_type { - TriggeringEventType::Data => self - .data_triggers - .remove(id) - .map(|_| ()) - .expect("`Set::data_triggers` doesn't contain required id. This is a bug"), - TriggeringEventType::Pipeline => { - self.pipeline_triggers.remove(id).map(|_| ()).expect( - "`Set::pipeline_triggers` doesn't contain required id. This is a bug", - ) - } - TriggeringEventType::Time => self - .time_triggers - .remove(id) - .map(|_| ()) - .expect("`Set::time_triggers` doesn't contain required id. This is a bug"), - TriggeringEventType::ExecuteTrigger => { - self.by_call_triggers.remove(id).map(|_| ()).expect( - "`Set::by_call_triggers` doesn't contain required id. This is a bug", - ) - } - }) - .is_some() + // Used in a map that requires this signature + #[allow(clippy::needless_pass_by_value)] + fn extract_blob_hash(action: LoadedAction) -> Option> { + match action.executable { + LoadedExecutable::Wasm(LoadedWasm { blob_hash, .. }) => Some(blob_hash), + LoadedExecutable::Instructions(_) => None, + } + } + + let Some(event_type) = self.ids.remove(id) else { + return false; + }; + + let blob_hash = match event_type { + TriggeringEventType::Data => self + .data_triggers + .remove(id) + .map(extract_blob_hash) + .expect("`Set::data_triggers` doesn't contain required id. This is a bug"), + TriggeringEventType::Pipeline => self + .pipeline_triggers + .remove(id) + .map(extract_blob_hash) + .expect("`Set::pipeline_triggers` doesn't contain required id. This is a bug"), + TriggeringEventType::Time => self + .time_triggers + .remove(id) + .map(extract_blob_hash) + .expect("`Set::time_triggers` doesn't contain required id. This is a bug"), + TriggeringEventType::ExecuteTrigger => self + .by_call_triggers + .remove(id) + .map(extract_blob_hash) + .expect("`Set::by_call_triggers` doesn't contain required id. This is a bug"), + }; + + if let Some(blob_hash) = blob_hash { + self.original_contracts + .remove(&blob_hash) + .expect("`Set::original_contracts` doesn't contain required hash. This is a bug"); + } + + true } /// Check if [`Set`] contains `id`. @@ -735,24 +878,6 @@ impl core::fmt::Debug for LoadedExecutable { } } -impl From for OptimizedExecutable { - fn from(executable: LoadedExecutable) -> Self { - match executable { - LoadedExecutable::Wasm(LoadedWasm { module, blob_hash }) => { - OptimizedExecutable::WasmInternalRepr(WasmInternalRepr { - serialized: module - .serialize() - .expect("Serialization of optimized wasm module should always succeed"), - blob_hash, - }) - } - LoadedExecutable::Instructions(instructions) => { - OptimizedExecutable::Instructions(instructions) - } - } - } -} - /// [`Set::mod_repeats()`] error #[derive(Debug, Clone, thiserror::Error, displaydoc::Display)] pub enum ModRepeatsError { diff --git a/core/src/wsv.rs b/core/src/wsv.rs index 02eb4057147..e095e7c2dd7 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -24,7 +24,6 @@ use iroha_data_model::{ permission::PermissionTokenSchema, prelude::*, query::error::{FindError, QueryExecutionFail}, - trigger::action::ActionTrait, }; use iroha_logger::prelude::*; use iroha_primitives::small::SmallVec; @@ -42,7 +41,7 @@ use crate::{ smartcontracts::{ triggers::{ self, - set::{LoadedExecutable, LoadedWasm, Set as TriggerSet}, + set::{LoadedActionTrait, LoadedWasm, Set as TriggerSet}, }, wasm, Execute, }, @@ -511,7 +510,7 @@ impl WorldStateView { fn process_trigger( &mut self, id: &TriggerId, - action: &dyn ActionTrait, + action: &dyn LoadedActionTrait, event: Event, ) -> Result<()> { use triggers::set::LoadedExecutable::*; @@ -540,6 +539,8 @@ impl WorldStateView { let mut succeed = Vec::::with_capacity(matched_ids.len()); let mut errors = Vec::new(); for (event, id) in matched_ids { + // Eliding the closure triggers a lifetime mismatch + #[allow(clippy::redundant_closure_for_method_calls)] let action = self .world .triggers diff --git a/data_model/src/events/data/events.rs b/data_model/src/events/data/events.rs index 54536767a41..8bf07a8e49b 100644 --- a/data_model/src/events/data/events.rs +++ b/data_model/src/events/data/events.rs @@ -502,7 +502,7 @@ mod trigger { use super::*; data_event! { - #[has_origin(origin = Trigger)] + #[has_origin(origin = Trigger)] pub enum TriggerEvent { Created(TriggerId), Deleted(TriggerId), diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 4459330b2e9..2f9a6c21089 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -630,7 +630,7 @@ pub mod model { Asset(::With), /// [`Trigger`](`trigger::Trigger`) variant. #[display(fmt = "Trigger {_0}")] - Trigger( as Registered>::With), + Trigger( as Registered>::With), /// [`Role`](`role::Role`) variant. #[display(fmt = "Role {_0}")] Role(::With), @@ -672,40 +672,14 @@ pub mod model { AssetDefinition(asset::AssetDefinition), /// [`Asset`](`asset::Asset`) variant. Asset(asset::Asset), - /// [`TriggerBox`] variant. - Trigger(TriggerBox), + /// [`Trigger`](`trigger::Trigger`) variant. + Trigger(trigger::Trigger), /// [`Role`](`role::Role`) variant. Role(role::Role), /// [`Parameter`](`parameter::Parameter`) variant. Parameter(parameter::Parameter), } - /// Sized container for triggers with different executables. - #[derive( - Debug, - Display, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - FromVariant, - Decode, - Encode, - Deserialize, - Serialize, - IntoSchema, - )] - #[ffi_type] - pub enum TriggerBox { - /// Un-optimized [`Trigger`](`trigger::Trigger`) submitted from client to Iroha. - #[display(fmt = "{_0}")] - Raw(trigger::Trigger), - /// Optimized [`Trigger`](`trigger::Trigger`) returned from Iroha to client. - #[display(fmt = "{_0} (optimised)")] - Optimized(trigger::Trigger), - } - /// Sized container for all possible upgradable entities. #[derive( Debug, @@ -984,17 +958,6 @@ pub mod model { } } -impl Identifiable for TriggerBox { - type Id = trigger::TriggerId; - - fn id(&self) -> &Self::Id { - match self { - TriggerBox::Raw(trigger) => trigger.id(), - TriggerBox::Optimized(trigger) => trigger.id(), - } - } -} - // TODO: think of a way to `impl Identifiable for IdentifiableBox`. // The main problem is lifetimes and conversion cost. @@ -1312,7 +1275,7 @@ from_and_try_from_value_identifiable!( Account(account::Account), AssetDefinition(asset::AssetDefinition), Asset(asset::Asset), - Trigger(TriggerBox), + Trigger(trigger::Trigger), Role(role::Role), Parameter(parameter::Parameter), ); @@ -1365,13 +1328,10 @@ impl TryFrom for RegistrableBox { } NewRole(role) => Ok(RegistrableBox::Role(role)), Asset(asset) => Ok(RegistrableBox::Asset(asset)), - Trigger(TriggerBox::Raw(trigger)) => Ok(RegistrableBox::Trigger(trigger)), - Domain(_) - | Account(_) - | AssetDefinition(_) - | Role(_) - | Parameter(_) - | Trigger(TriggerBox::Optimized(_)) => Err(Self::Error::default()), + Trigger(trigger) => Ok(RegistrableBox::Trigger(trigger)), + Domain(_) | Account(_) | AssetDefinition(_) | Role(_) | Parameter(_) => { + Err(Self::Error::default()) + } } } } @@ -1389,7 +1349,7 @@ impl From for IdentifiableBox { } Role(role) => IdentifiableBox::NewRole(role), Asset(asset) => IdentifiableBox::Asset(asset), - Trigger(trigger) => IdentifiableBox::Trigger(TriggerBox::Raw(trigger)), + Trigger(trigger) => IdentifiableBox::Trigger(trigger), } } } @@ -1459,43 +1419,6 @@ impl TryFrom for Value { } } -impl From> for Value { - fn from(trigger: trigger::Trigger) -> Self { - Value::Identifiable(IdentifiableBox::Trigger(TriggerBox::Raw(trigger))) - } -} - -impl From> for Value { - fn from(trigger: trigger::Trigger) -> Self { - Value::Identifiable(IdentifiableBox::Trigger(TriggerBox::Optimized(trigger))) - } -} - -impl TryFrom for trigger::Trigger { - type Error = ErrorTryFromEnum; - - fn try_from(value: Value) -> Result { - if let Value::Identifiable(IdentifiableBox::Trigger(TriggerBox::Raw(trigger))) = value { - return Ok(trigger); - } - - Err(Self::Error::default()) - } -} - -impl TryFrom for trigger::Trigger { - type Error = ErrorTryFromEnum; - - fn try_from(value: Value) -> Result { - if let Value::Identifiable(IdentifiableBox::Trigger(TriggerBox::Optimized(trigger))) = value - { - return Ok(trigger); - } - - Err(Self::Error::default()) - } -} - impl TryFrom for UpgradableBox { type Error = ErrorTryFromEnum; @@ -1938,7 +1861,7 @@ pub mod prelude { metadata::prelude::*, name::prelude::*, parameter::prelude::*, peer::prelude::*, permission::prelude::*, query::prelude::*, role::prelude::*, transaction::prelude::*, trigger::prelude::*, EnumTryAsError, HasMetadata, IdBox, Identifiable, IdentifiableBox, - LengthLimits, NumericValue, PredicateTrait, RegistrableBox, ToValue, TriggerBox, TryAsMut, - TryAsRef, TryToValue, UpgradableBox, ValidationFail, Value, + LengthLimits, NumericValue, PredicateTrait, RegistrableBox, ToValue, TryAsMut, TryAsRef, + TryToValue, UpgradableBox, ValidationFail, Value, }; } diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index 3edbc4ed64c..211d0233935 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -1025,7 +1025,7 @@ pub mod trigger { } impl Query for FindTriggerById { - type Output = Trigger; + type Output = Trigger; } impl Query for FindTriggerKeyValueByIdAndKey { @@ -1033,7 +1033,7 @@ pub mod trigger { } impl Query for FindTriggersByDomainId { - type Output = Vec>; + type Output = Vec>; } impl FindTriggerById { diff --git a/data_model/src/trigger.rs b/data_model/src/trigger.rs index 39271f8d0a2..0127ce3bf77 100644 --- a/data_model/src/trigger.rs +++ b/data_model/src/trigger.rs @@ -7,7 +7,7 @@ use core::{cmp, str::FromStr}; use derive_more::{Constructor, Display}; use getset::Getters; use iroha_data_model_derive::{model, IdEqOrdHash}; -use iroha_macro::{ffi_impl_opaque, FromVariant}; +use iroha_macro::ffi_impl_opaque; use iroha_schema::IntoSchema; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; @@ -15,8 +15,8 @@ use serde_with::{DeserializeFromStr, SerializeDisplay}; pub use self::model::*; use crate::{ - domain::DomainId, events::prelude::*, metadata::Metadata, prelude::InstructionExpr, - transaction::Executable, Identifiable, Name, ParseError, Registered, + domain::DomainId, events::prelude::*, metadata::Metadata, transaction::Executable, + Identifiable, Name, ParseError, Registered, }; #[model] @@ -43,10 +43,10 @@ pub mod model { #[getset(get = "pub")] #[ffi_type] pub struct TriggerId { - /// Name given to trigger by its creator. - pub name: Name, /// DomainId of domain of the trigger. pub domain_id: Option, + /// Name given to trigger by its creator. + pub name: Name, } /// Type which is used for registering a `Trigger`. @@ -64,62 +64,38 @@ pub mod model { )] #[display(fmt = "@@{id}")] #[ffi_type] - pub struct Trigger { + pub struct Trigger { /// [`Id`] of the [`Trigger`]. pub id: TriggerId, /// Action to be performed when the trigger matches. - pub action: action::Action, - } - - /// Internal representation of Wasm blob provided by preloading it with `wasmtime` crate. - #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] - pub struct WasmInternalRepr { - /// Serialized with `wasmtime::Module::serialize` - pub serialized: Vec, - /// Hash of original WASM blob on blockchain - pub blob_hash: iroha_crypto::HashOf, - } - - /// Same as [`Executable`] but instead of [`Wasm`](Executable::Wasm) contains - /// [`WasmInternalRepr`] with serialized optimized representation - /// from `wasmtime` library. - #[derive( - Debug, Clone, PartialEq, Eq, FromVariant, Decode, Encode, Deserialize, Serialize, IntoSchema, - )] - // TODO: Made opaque temporarily - #[ffi_type(opaque)] - pub enum OptimizedExecutable { - /// WASM serialized with `wasmtime`. - WasmInternalRepr(WasmInternalRepr), - /// Vector of [`instructions`](InstructionExpr). - Instructions(Vec), + pub action: action::Action, } } #[ffi_impl_opaque] -impl Trigger { +impl Trigger { /// [`Id`] of the [`Trigger`]. pub fn id(&self) -> &TriggerId { &self.id } /// Action to be performed when the trigger matches. - pub fn action(&self) -> &action::Action { + pub fn action(&self) -> &action::Action { &self.action } } -impl Registered for Trigger { +impl Registered for Trigger { type With = Self; } macro_rules! impl_try_from_box { ($($variant:ident => $filter_type:ty),+ $(,)?) => { $( - impl TryFrom> for Trigger<$filter_type, E> { + impl TryFrom> for Trigger<$filter_type> { type Error = &'static str; - fn try_from(boxed: Trigger) -> Result { + fn try_from(boxed: Trigger) -> Result { if let TriggeringFilterBox::$variant(concrete_filter) = boxed.action.filter { let action = action::Action::new( boxed.action.executable, @@ -210,9 +186,9 @@ pub mod action { Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema, )] #[ffi_type] - pub struct Action { + pub struct Action { /// The executable linked to this action - pub executable: E, + pub executable: Executable, /// The repeating scheme of the action. It's kept as part of the /// action and not inside the [`Trigger`] type, so that further /// sanity checking can be done. @@ -239,16 +215,16 @@ pub mod action { } #[cfg(feature = "transparent_api")] - impl crate::HasMetadata for Action { + impl crate::HasMetadata for Action { fn metadata(&self) -> &crate::metadata::Metadata { &self.metadata } } #[ffi_impl_opaque] - impl Action { + impl Action { /// The executable linked to this action - pub fn executable(&self) -> &OptimizedExecutable { + pub fn executable(&self) -> &Executable { &self.executable } /// The repeating scheme of the action. It's kept as part of the @@ -267,10 +243,10 @@ pub mod action { } } - impl Action { + impl Action { /// Construct an action given `executable`, `repeats`, `authority` and `filter`. pub fn new( - executable: impl Into, + executable: impl Into, repeats: impl Into, authority: AccountId, filter: F, @@ -293,7 +269,7 @@ pub mod action { } } - impl PartialOrd for Action { + impl PartialOrd for Action { fn partial_cmp(&self, other: &Self) -> Option { // Exclude the executable. When debugging and replacing // the trigger, its position in Hash and Tree maps should @@ -306,93 +282,13 @@ pub mod action { } } - impl Ord for Action { + impl Ord for Action { fn cmp(&self, other: &Self) -> cmp::Ordering { self.partial_cmp(other) .expect("`PartialCmp::partial_cmp()` for `Action` should never return `None`") } } - /// Trait for common methods for all [`Action`]'s - #[cfg(feature = "transparent_api")] - pub trait ActionTrait { - /// Type of action executable - type Executable; - - /// Get action executable - fn executable(&self) -> &Self::Executable; - - /// Get action repeats enum - fn repeats(&self) -> &Repeats; - - /// Set action repeats - fn set_repeats(&mut self, repeats: Repeats); - - /// Get action technical account - fn authority(&self) -> &AccountId; - - /// Get action metadata - fn metadata(&self) -> &Metadata; - - /// Check if action is mintable. - fn mintable(&self) -> bool; - - /// Convert action to a boxed representation - fn into_boxed(self) -> Action; - - /// Same as [`into_boxed()`](ActionTrait::into_boxed) but clones `self` - fn clone_and_box(&self) -> Action; - } - - #[cfg(feature = "transparent_api")] - impl + Clone, E: Clone> ActionTrait for Action { - type Executable = E; - - fn executable(&self) -> &Self::Executable { - &self.executable - } - - fn repeats(&self) -> &Repeats { - &self.repeats - } - - fn set_repeats(&mut self, repeats: Repeats) { - self.repeats = repeats; - } - - fn authority(&self) -> &AccountId { - &self.authority - } - - fn metadata(&self) -> &Metadata { - &self.metadata - } - - fn mintable(&self) -> bool { - self.filter.mintable() - } - - fn into_boxed(self) -> Action { - Action:: { - executable: self.executable, - repeats: self.repeats, - authority: self.authority, - filter: self.filter.into(), - metadata: self.metadata, - } - } - - fn clone_and_box(&self) -> Action { - Action:: { - executable: self.executable.clone(), - repeats: self.repeats.clone(), - authority: self.authority.clone(), - filter: self.filter.clone().into(), - metadata: self.metadata.clone(), - } - } - } - impl PartialOrd for Repeats { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) @@ -425,8 +321,6 @@ pub mod action { pub mod prelude { //! Re-exports of commonly used types. - #[cfg(feature = "transparent_api")] - pub use super::action::ActionTrait; pub use super::{action::prelude::*, Trigger, TriggerId}; } @@ -438,25 +332,19 @@ mod tests { fn trigger_with_filterbox_can_be_unboxed() { /// Should fail to compile if a new variant will be added to `TriggeringFilterBox` #[allow(dead_code)] - fn compile_time_check(boxed: Trigger) { + fn compile_time_check(boxed: Trigger) { match &boxed.action.filter { - TriggeringFilterBox::Data(_) => { - Trigger::::try_from(boxed) - .map(|_| ()) - .unwrap() - } - TriggeringFilterBox::Pipeline(_) => { - Trigger::::try_from(boxed) - .map(|_| ()) - .unwrap() - } - TriggeringFilterBox::Time(_) => { - Trigger::::try_from(boxed) - .map(|_| ()) - .unwrap() - } + TriggeringFilterBox::Data(_) => Trigger::::try_from(boxed) + .map(|_| ()) + .unwrap(), + TriggeringFilterBox::Pipeline(_) => Trigger::::try_from(boxed) + .map(|_| ()) + .unwrap(), + TriggeringFilterBox::Time(_) => Trigger::::try_from(boxed) + .map(|_| ()) + .unwrap(), TriggeringFilterBox::ExecuteTrigger(_) => { - Trigger::::try_from(boxed) + Trigger::::try_from(boxed) .map(|_| ()) .unwrap() } diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index 64fcdb387e0..62a33f328c8 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -114,7 +114,7 @@ pub trait Visit: ExpressionEvaluator { visit_register_asset_definition(Register), visit_register_asset(Register), visit_register_role(Register), - visit_register_trigger(Register>), + visit_register_trigger(Register>), // Visit UnregisterExpr visit_unregister_peer(Unregister), @@ -124,18 +124,18 @@ pub trait Visit: ExpressionEvaluator { visit_unregister_asset(Unregister), // TODO: Need to allow role creator to unregister it somehow visit_unregister_role(Unregister), - visit_unregister_trigger(Unregister>), + visit_unregister_trigger(Unregister>), // Visit MintExpr visit_mint_asset(Mint), visit_mint_account_public_key(Mint), visit_mint_account_signature_check_condition(Mint), - visit_mint_trigger_repetitions(Mint>), + visit_mint_trigger_repetitions(Mint>), // Visit BurnExpr visit_burn_account_public_key(Burn), visit_burn_asset(Burn), - visit_burn_trigger_repetitions(Burn>), + visit_burn_trigger_repetitions(Burn>), // Visit TransferExpr visit_transfer_asset_definition(Transfer), @@ -728,10 +728,10 @@ leaf_visitors! { visit_unregister_role(Unregister), visit_grant_account_role(Grant), visit_revoke_account_role(Revoke), - visit_register_trigger(Register>), - visit_unregister_trigger(Unregister>), - visit_mint_trigger_repetitions(Mint>), - visit_burn_trigger_repetitions(Burn>), + visit_register_trigger(Register>), + visit_unregister_trigger(Unregister>), + visit_mint_trigger_repetitions(Mint>), + visit_burn_trigger_repetitions(Burn>), visit_upgrade_executor(Upgrade), visit_new_parameter(NewParameter), visit_set_parameter(SetParameter), diff --git a/default_executor/src/lib.rs b/default_executor/src/lib.rs index 9bb8c2e77d4..5b6deb36a67 100644 --- a/default_executor/src/lib.rs +++ b/default_executor/src/lib.rs @@ -112,9 +112,9 @@ impl Visit for Executor { visit_revoke_account_role(Revoke), // Trigger validation - visit_unregister_trigger(Unregister>), - visit_mint_trigger_repetitions(Mint>), - visit_burn_trigger_repetitions(Burn>), + visit_unregister_trigger(Unregister>), + visit_mint_trigger_repetitions(Mint>), + visit_burn_trigger_repetitions(Burn>), visit_execute_trigger(ExecuteTrigger), // Parameter validation diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index 32a3fd329c9..17d8eb33db2 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -179,7 +179,7 @@ } ] }, - "Action": { + "Action": { "Struct": [ { "name": "executable", @@ -203,30 +203,6 @@ } ] }, - "Action": { - "Struct": [ - { - "name": "executable", - "type": "OptimizedExecutable" - }, - { - "name": "repeats", - "type": "Repeats" - }, - { - "name": "authority", - "type": "AccountId" - }, - { - "name": "filter", - "type": "TriggeringFilterBox" - }, - { - "name": "metadata", - "type": "Metadata" - } - ] - }, "Add": { "Struct": [ { @@ -2222,7 +2198,6 @@ "HashOf>": "Hash", "HashOf": "Hash", "HashOf": "Hash", - "HashOf": "Hash", "HashValue": { "Enum": [ { @@ -2336,7 +2311,7 @@ { "tag": "Trigger", "discriminant": 9, - "type": "TriggerBox" + "type": "Trigger" }, { "tag": "Role", @@ -3116,20 +3091,6 @@ } ] }, - "OptimizedExecutable": { - "Enum": [ - { - "tag": "WasmInternalRepr", - "discriminant": 0, - "type": "WasmInternalRepr" - }, - { - "tag": "Instructions", - "discriminant": 1, - "type": "Vec" - } - ] - }, "Option": { "Option": "DomainId" }, @@ -3744,7 +3705,7 @@ { "tag": "Trigger", "discriminant": 5, - "type": "Trigger" + "type": "Trigger" }, { "tag": "Role", @@ -4375,7 +4336,7 @@ } ] }, - "Trigger": { + "Trigger": { "Struct": [ { "name": "id", @@ -4383,33 +4344,7 @@ }, { "name": "action", - "type": "Action" - } - ] - }, - "Trigger": { - "Struct": [ - { - "name": "id", - "type": "TriggerId" - }, - { - "name": "action", - "type": "Action" - } - ] - }, - "TriggerBox": { - "Enum": [ - { - "tag": "Raw", - "discriminant": 0, - "type": "Trigger" - }, - { - "tag": "Optimized", - "discriminant": 1, - "type": "Trigger" + "type": "Action" } ] }, @@ -4520,13 +4455,13 @@ }, "TriggerId": { "Struct": [ - { - "name": "name", - "type": "Name" - }, { "name": "domain_id", "type": "Option" + }, + { + "name": "name", + "type": "Name" } ] }, @@ -4853,18 +4788,6 @@ } ] }, - "WasmInternalRepr": { - "Struct": [ - { - "name": "serialized", - "type": "Vec" - }, - { - "name": "blob_hash", - "type": "HashOf" - } - ] - }, "WasmSmartContract": "Vec", "Where": { "Struct": [ diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index b3c7007b4aa..ade793e5963 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -68,7 +68,7 @@ types!( AccountId, AccountPermissionChanged, AccountRoleChanged, - Action, + Action, Add, Algorithm, And, @@ -351,7 +351,7 @@ types!( TransactionRejectionReason, TransactionValue, TransferExpr, - Trigger, + Trigger, TriggerCompletedEventFilter, TriggerCompletedOutcomeType, TriggerEvent, diff --git a/smart_contract/executor/src/default.rs b/smart_contract/executor/src/default.rs index 816e9e58ab3..a39735e3480 100644 --- a/smart_contract/executor/src/default.rs +++ b/smart_contract/executor/src/default.rs @@ -1510,7 +1510,7 @@ pub mod trigger { pub fn visit_unregister_trigger( executor: &mut V, authority: &AccountId, - isi: Unregister>, + isi: Unregister>, ) { let trigger_id = isi.object_id; @@ -1536,7 +1536,7 @@ pub mod trigger { pub fn visit_mint_trigger_repetitions( executor: &mut V, authority: &AccountId, - isi: Mint>, + isi: Mint>, ) { let trigger_id = isi.destination_id; @@ -1562,7 +1562,7 @@ pub mod trigger { pub fn visit_burn_trigger_repetitions( executor: &mut V, authority: &AccountId, - isi: Burn>, + isi: Burn>, ) { let trigger_id = isi.destination_id; diff --git a/tools/parity_scale_decoder/build.rs b/tools/parity_scale_decoder/build.rs index f3bd391649d..58e3db5dbd8 100644 --- a/tools/parity_scale_decoder/build.rs +++ b/tools/parity_scale_decoder/build.rs @@ -11,7 +11,7 @@ fn main() { sample_into_binary_file::("domain").expect("Failed to encode into domain.bin."); - sample_into_binary_file::>("trigger") + sample_into_binary_file::>("trigger") .expect("Failed to encode into trigger.bin."); } diff --git a/tools/parity_scale_decoder/samples/trigger.bin b/tools/parity_scale_decoder/samples/trigger.bin index ed5af47caea213d4ef2283aeb46e194b0250c15a..aa17a69bcd0fbab87f0e18137d1853f50763d58e 100644 GIT binary patch delta 17 YcmWFt;AT+C&CDx_FUl`YoyhG904-_-fdBvi delta 17 YcmWFt;8w}a%qxj6$}di3n8@u405M(#fdBvi diff --git a/tools/parity_scale_decoder/src/main.rs b/tools/parity_scale_decoder/src/main.rs index 476da807870..0cff5a839e5 100644 --- a/tools/parity_scale_decoder/src/main.rs +++ b/tools/parity_scale_decoder/src/main.rs @@ -261,7 +261,7 @@ mod tests { ); let rose_id = AssetId::new(rose_definition_id, account_id.clone()); let trigger_id = "mint_rose".parse().expect("Valid"); - let action = Action::::new( + let action = Action::::new( vec![MintExpr::new(1_u32, rose_id)], Repeats::Indefinitely, account_id, @@ -273,7 +273,7 @@ mod tests { decode_sample( "trigger.bin", - String::from("Trigger"), + String::from("Trigger"), &trigger, ); } From 25aaede281071e55047794d3651f1c8b36c37497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Mon, 16 Oct 2023 09:34:30 +0200 Subject: [PATCH 55/55] [refactor]: remove unused dependencies (#3992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- Cargo.lock | 4 ---- Cargo.toml | 3 --- core/Cargo.toml | 1 - data_model/Cargo.toml | 4 +--- p2p/Cargo.toml | 1 - tools/swarm/Cargo.toml | 6 ++++-- 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e42401fc1c..4d65b134304 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2905,7 +2905,6 @@ dependencies = [ "iroha_telemetry", "iroha_version", "iroha_wasm_codec", - "itertools 0.11.0", "once_cell", "parity-scale-codec", "parking_lot", @@ -2955,7 +2954,6 @@ version = "2.0.0-pre-rc.19" dependencies = [ "base64 0.21.4", "criterion", - "dashmap", "derive_more", "displaydoc", "getset", @@ -2973,7 +2971,6 @@ dependencies = [ "serde_with", "strum 0.25.0", "thiserror", - "tokio", "trybuild", "warp", ] @@ -3162,7 +3159,6 @@ name = "iroha_p2p" version = "2.0.0-pre-rc.19" dependencies = [ "aead", - "async-stream", "async-trait", "bytes", "derive_more", diff --git a/Cargo.toml b/Cargo.toml index 577997a76fd..65dd3671b33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,6 @@ manyhow = { version = "0.8.1", features = ["darling"] } darling = "0.20.3" futures = { version = "0.3.28", default-features = false } -async-stream = "0.3.5" tokio = "1.33.0" tokio-stream = "0.1.14" tokio-tungstenite = "0.20.1" @@ -79,7 +78,6 @@ once_cell = "1.18.0" tempfile = "3.8.0" path-absolutize = "3.1.1" pathdiff = "0.2.1" -itertools = "0.11.0" bytes = "1.5.0" vergen = { version = "8.2.5", default-features = false } @@ -102,7 +100,6 @@ duct = "0.13.6" criterion = "0.5.1" proptest = "1.3.1" -expect-test = "1.4.1" eyre = "0.6.8" color-eyre = "0.6.2" diff --git a/core/Cargo.toml b/core/Cargo.toml index 1e19e019008..ee25db8e235 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -68,7 +68,6 @@ displaydoc = { workspace = true } wasmtime = { workspace = true } parking_lot = { workspace = true, features = ["deadlock_detection"] } derive_more = { workspace = true } -itertools = { workspace = true } [dev-dependencies] criterion = { workspace = true } diff --git a/data_model/Cargo.toml b/data_model/Cargo.toml index 6d7203ec735..83551e7125d 100644 --- a/data_model/Cargo.toml +++ b/data_model/Cargo.toml @@ -21,7 +21,7 @@ default = ["std"] # Enable static linkage of the rust standard library. # Disabled for WASM interoperability, to reduce the binary size. # Please refer to https://docs.rust-embedded.org/book/intro/no-std.html -std = ["iroha_macro/std", "iroha_version/std", "iroha_crypto/std", "iroha_primitives/std", "thiserror", "displaydoc/std", "strum/std", "dashmap", "tokio"] +std = ["iroha_macro/std", "iroha_version/std", "iroha_crypto/std", "iroha_primitives/std", "thiserror", "displaydoc/std", "strum/std"] # Enable API for HTTP requests. Should be activated for HTTP clients http = ["std", "warp", "iroha_version/http"] # Replace structures and methods with FFI equivalents to facilitate dynamic linkage (mainly used in smartcontracts) @@ -41,8 +41,6 @@ iroha_version = { workspace = true, features = ["derive", "json", "scale"] } iroha_schema = { workspace = true } iroha_ffi = { workspace = true, optional = true } -dashmap = { workspace = true, optional = true } -tokio = { workspace = true, optional = true, features = ["sync", "rt-multi-thread"] } parity-scale-codec = { workspace = true, features = ["derive"] } derive_more = { workspace = true, features = ["as_ref", "display", "constructor", "from_str", "from", "into"] } serde = { workspace = true, features = ["derive"] } diff --git a/p2p/Cargo.toml b/p2p/Cargo.toml index d28d34b35eb..ba85ca93604 100644 --- a/p2p/Cargo.toml +++ b/p2p/Cargo.toml @@ -21,7 +21,6 @@ iroha_data_model_derive = { workspace = true } rand = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread", "macros", "io-util", "net", "time"] } -async-stream = { workspace = true } futures = { workspace = true, features = ["alloc"] } async-trait = { workspace = true } parity-scale-codec = { workspace = true, features = ["derive"] } diff --git a/tools/swarm/Cargo.toml b/tools/swarm/Cargo.toml index 1500d1526b4..99b678aff4a 100644 --- a/tools/swarm/Cargo.toml +++ b/tools/swarm/Cargo.toml @@ -13,9 +13,7 @@ workspace = true iroha_crypto.workspace = true iroha_data_model.workspace = true iroha_primitives.workspace = true -iroha_config.workspace = true color-eyre.workspace = true -expect-test.workspace = true path-absolutize.workspace = true pathdiff.workspace = true owo-colors = { workspace = true, features = ["supports-colors"] } @@ -26,3 +24,7 @@ serde_json.workspace = true derive_more.workspace = true inquire.workspace = true +[dev-dependencies] +iroha_config.workspace = true + +expect-test = "1.4.1"

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 R%%j@BRF`)B^}_L({{vc1BAx&M diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 62028abdf0e..af233d52446 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -16,8 +16,9 @@ use iroha_data_model::{ isi::InstructionExpr, permission::PermissionTokenSchema, prelude::*, + query::QueryBox, + smart_contract::payloads::{self, Validate}, validator::{self, MigrationResult}, - wasm::{export, import, payloads}, Level as LogLevel, ValidationFail, }; use iroha_logger::debug; @@ -36,9 +37,43 @@ use crate::{ wsv::WorldStateView, }; +/// Name of the exported memory +const WASM_MEMORY: &str = "memory"; +const WASM_MODULE: &str = "iroha"; + +mod export { + pub const EXECUTE_ISI: &str = "execute_instruction"; + pub const EXECUTE_QUERY: &str = "execute_query"; + pub const GET_SMART_CONTRACT_PAYLOAD: &str = "get_smart_contract_payload"; + pub const GET_TRIGGER_PAYLOAD: &str = "get_trigger_payload"; + pub const GET_MIGRATE_PAYLOAD: &str = "get_migrate_payload"; + pub const GET_VALIDATE_TRANSACTION_PAYLOAD: &str = "get_validate_transaction_payload"; + pub const GET_VALIDATE_INSTRUCTION_PAYLOAD: &str = "get_validate_instruction_payload"; + pub const GET_VALIDATE_QUERY_PAYLOAD: &str = "get_validate_query_payload"; + pub const SET_PERMISSION_TOKEN_SCHEMA: &str = "set_permission_token_schema"; + + pub const DBG: &str = "dbg"; + pub const LOG: &str = "log"; +} + +mod import { + pub const SMART_CONTRACT_MAIN: &str = "_iroha_smart_contract_main"; + pub const SMART_CONTRACT_ALLOC: &str = "_iroha_smart_contract_alloc"; + pub const SMART_CONTRACT_DEALLOC: &str = "_iroha_smart_contract_dealloc"; + + pub const TRIGGER_MAIN: &str = "_iroha_trigger_main"; + + pub const VALIDATOR_VALIDATE_TRANSACTION: &str = "_iroha_validator_validate_transaction"; + pub const VALIDATOR_VALIDATE_INSTRUCTION: &str = "_iroha_validator_validate_instruction"; + pub const VALIDATOR_VALIDATE_QUERY: &str = "_iroha_validator_validate_query"; + pub const VALIDATOR_MIGRATE: &str = "_iroha_validator_migrate"; +} + mod import_traits { //! Traits which some [Runtime]s should implement to import functions from Iroha to WASM + use iroha_data_model::{query::QueryBox, smart_contract::payloads::Validate}; + use super::*; pub trait ExecuteOperations { @@ -59,13 +94,13 @@ mod import_traits { fn get_migrate_payload(state: &S) -> payloads::Migrate; #[codec::wrap_trait_fn] - fn get_validate_transaction_payload(state: &S) -> payloads::ValidateTransaction; + fn get_validate_transaction_payload(state: &S) -> Validate; #[codec::wrap_trait_fn] - fn get_validate_instruction_payload(state: &S) -> payloads::ValidateInstruction; + fn get_validate_instruction_payload(state: &S) -> Validate; #[codec::wrap_trait_fn] - fn get_validate_query_payload(state: &S) -> payloads::ValidateQuery; + fn get_validate_query_payload(state: &S) -> Validate; } pub trait SetPermissionTokenSchema { @@ -556,23 +591,23 @@ pub struct Runtime { impl Runtime { fn get_memory(caller: &mut impl GetExport) -> Result { caller - .get_export(export::WASM_MEMORY) - .ok_or_else(|| ExportError::not_found(export::WASM_MEMORY))? + .get_export(WASM_MEMORY) + .ok_or_else(|| ExportError::not_found(WASM_MEMORY))? .into_memory() - .ok_or_else(|| ExportError::not_a_memory(export::WASM_MEMORY)) + .ok_or_else(|| ExportError::not_a_memory(WASM_MEMORY)) } fn get_alloc_fn( caller: &mut Caller, ) -> Result, ExportError> { caller - .get_export(export::fn_names::WASM_ALLOC) - .ok_or_else(|| ExportError::not_found(export::fn_names::WASM_ALLOC))? + .get_export(import::SMART_CONTRACT_ALLOC) + .ok_or_else(|| ExportError::not_found(import::SMART_CONTRACT_ALLOC))? .into_func() - .ok_or_else(|| ExportError::not_a_function(export::fn_names::WASM_ALLOC))? + .ok_or_else(|| ExportError::not_a_function(import::SMART_CONTRACT_ALLOC))? .typed::(caller) .map_err(|_error| { - ExportError::wrong_signature::(export::fn_names::WASM_ALLOC) + ExportError::wrong_signature::(import::SMART_CONTRACT_ALLOC) }) } @@ -620,12 +655,12 @@ impl Runtime { let _ = Self::get_typed_func::( instance, store, - export::fn_names::WASM_ALLOC, + import::SMART_CONTRACT_ALLOC, )?; let _ = Self::get_typed_func::<(WasmUsize, WasmUsize), ()>( instance, store, - export::fn_names::WASM_DEALLOC, + import::SMART_CONTRACT_DEALLOC, )?; Ok(()) @@ -723,7 +758,7 @@ impl Runtime { let memory = Self::get_memory(&mut (&instance, &mut store)).expect("Checked at instantiation step"); let dealloc_fn = - Self::get_typed_func(&instance, &mut store, export::fn_names::WASM_DEALLOC) + Self::get_typed_func(&instance, &mut store, import::SMART_CONTRACT_DEALLOC) .expect("Checked at instantiation step"); codec::decode_with_length_prefix_from_memory(&memory, &dealloc_fn, &mut store, offset) .map_err(Error::Decode) @@ -826,11 +861,8 @@ impl<'wrld> Runtime> { let mut store = self.create_store(state); let smart_contract = self.create_smart_contract(&mut store, bytes)?; - let main_fn = Self::get_typed_func( - &smart_contract, - &mut store, - export::fn_names::SMART_CONTRACT_MAIN, - )?; + let main_fn = + Self::get_typed_func(&smart_contract, &mut store, import::SMART_CONTRACT_MAIN)?; // NOTE: This function takes ownership of the pointer main_fn @@ -895,7 +927,7 @@ impl<'wrld> Runtime> { let mut store = self.create_store(state); let instance = self.instantiate_module(module, &mut store)?; - let main_fn = Self::get_typed_func(&instance, &mut store, export::fn_names::TRIGGER_MAIN)?; + let main_fn = Self::get_typed_func(&instance, &mut store, import::TRIGGER_MAIN)?; // NOTE: This function takes ownership of the pointer main_fn @@ -1016,7 +1048,7 @@ impl<'wrld> Runtime> { common: state::Common::new(wsv, authority.clone(), self.config, span), to_validate: transaction, }, - export::fn_names::VALIDATOR_VALIDATE_TRANSACTION, + import::VALIDATOR_VALIDATE_TRANSACTION, ) } } @@ -1039,8 +1071,8 @@ impl<'wrld> import_traits::GetValidatorPayloads, - ) -> payloads::ValidateTransaction { - payloads::ValidateTransaction { + ) -> Validate { + Validate { authority: state.authority().clone(), block_height: state.wsv().height(), to_validate: state.to_validate.clone(), @@ -1050,14 +1082,14 @@ impl<'wrld> import_traits::GetValidatorPayloads, - ) -> payloads::ValidateInstruction { + ) -> Validate { panic!("Validator `validate_transaction()` entrypoint should not query payload for `validate_instruction()` entrypoint") } #[codec::wrap] fn get_validate_query_payload( _state: &state::validator::ValidateTransaction<'wrld>, - ) -> payloads::ValidateQuery { + ) -> Validate { panic!("Validator `validate_transaction()` entrypoint should not query payload for `validate_query()` entrypoint") } } @@ -1092,7 +1124,7 @@ impl<'wrld> Runtime> { common: state::Common::new(wsv, authority.clone(), self.config, span), to_validate: instruction, }, - export::fn_names::VALIDATOR_VALIDATE_INSTRUCTION, + import::VALIDATOR_VALIDATE_INSTRUCTION, ) } } @@ -1115,15 +1147,15 @@ impl<'wrld> import_traits::GetValidatorPayloads, - ) -> payloads::ValidateTransaction { + ) -> Validate { panic!("Validator `validate_instruction()` entrypoint should not query payload for `validate_transaction()` entrypoint") } #[codec::wrap] fn get_validate_instruction_payload( state: &state::validator::ValidateInstruction<'wrld>, - ) -> payloads::ValidateInstruction { - payloads::ValidateInstruction { + ) -> Validate { + Validate { authority: state.authority().clone(), block_height: state.wsv().height(), to_validate: state.to_validate.clone(), @@ -1133,7 +1165,7 @@ impl<'wrld> import_traits::GetValidatorPayloads, - ) -> payloads::ValidateQuery { + ) -> Validate { panic!("Validator `validate_instruction()` entrypoint should not query payload for `validate_query()` entrypoint") } } @@ -1171,7 +1203,7 @@ impl<'wrld> Runtime> { log_span: span, query, }, - export::fn_names::VALIDATOR_VALIDATE_QUERY, + import::VALIDATOR_VALIDATE_QUERY, ) } } @@ -1215,22 +1247,22 @@ impl<'wrld> import_traits::GetValidatorPayloads, - ) -> payloads::ValidateTransaction { + ) -> Validate { panic!("Validator `validate_query()` entrypoint should not query payload for `validate_transaction()` entrypoint") } #[codec::wrap] fn get_validate_instruction_payload( _state: &state::validator::ValidateQuery<'wrld>, - ) -> payloads::ValidateInstruction { + ) -> Validate { panic!("Validator `validate_query()` entrypoint should not query payload for `validate_instruction()` entrypoint") } #[codec::wrap] fn get_validate_query_payload( state: &state::validator::ValidateQuery<'wrld>, - ) -> payloads::ValidateQuery { - payloads::ValidateQuery { + ) -> Validate { + Validate { authority: state.authority().clone(), block_height: state.wsv().height(), to_validate: state.query.clone(), @@ -1270,8 +1302,7 @@ impl<'wrld> Runtime> { let mut store = self.create_store(state); let instance = self.instantiate_module(module, &mut store)?; - let migrate_fn = - Self::get_typed_func(&instance, &mut store, export::fn_names::VALIDATOR_MIGRATE)?; + let migrate_fn = Self::get_typed_func(&instance, &mut store, import::VALIDATOR_MIGRATE)?; let offset = migrate_fn .call(&mut store, ()) @@ -1280,7 +1311,7 @@ impl<'wrld> Runtime> { let memory = Self::get_memory(&mut (&instance, &mut store)).expect("Checked at instantiation step"); let dealloc_fn = - Self::get_typed_func(&instance, &mut store, export::fn_names::WASM_DEALLOC) + Self::get_typed_func(&instance, &mut store, import::SMART_CONTRACT_DEALLOC) .expect("Checked at instantiation step"); codec::decode_with_length_prefix_from_memory(&memory, &dealloc_fn, &mut store, offset) .map_err(Error::Decode) @@ -1314,21 +1345,19 @@ impl<'wrld> import_traits::GetValidatorPayloads #[codec::wrap] fn get_validate_transaction_payload( _state: &state::validator::Migrate<'wrld>, - ) -> payloads::ValidateTransaction { + ) -> Validate { panic!("Validator `migrate()` entrypoint should not query payload for `validate_transaction()` entrypoint") } #[codec::wrap] fn get_validate_instruction_payload( _state: &state::validator::Migrate<'wrld>, - ) -> payloads::ValidateInstruction { + ) -> Validate { panic!("Validator `migrate()` entrypoint should not query payload for `validate_instruction()` entrypoint") } #[codec::wrap] - fn get_validate_query_payload( - _state: &state::validator::Migrate<'wrld>, - ) -> payloads::ValidateQuery { + fn get_validate_query_payload(_state: &state::validator::Migrate<'wrld>) -> Validate { panic!("Validator `migrate()` entrypoint should not query payload for `validate_query()` entrypoint") } } @@ -1405,24 +1434,24 @@ impl RuntimeBuilder { macro_rules! create_imports { ( $linker:ident, - $(import::fn_names:: $name:ident => $fn_path:path),* $(,)? + $(export::$name:ident => $fn_path:path),* $(,)? ) => { $linker.func_wrap( - import::MODULE, - import::fn_names::LOG, + WASM_MODULE, + export::LOG, Runtime::log, ) .and_then(|l| { l.func_wrap( - import::MODULE, - import::fn_names::DBG, + WASM_MODULE, + export::DBG, Runtime::dbg, ) }) $(.and_then(|l| { l.func_wrap( - import::MODULE, - import::fn_names::$name, + WASM_MODULE, + export::$name, $fn_path, ) }))* @@ -1441,9 +1470,9 @@ impl<'wrld> RuntimeBuilder> { let mut linker = Linker::new(engine); create_imports!(linker, - import::fn_names::EXECUTE_ISI => Runtime::>::execute_instruction, - import::fn_names::EXECUTE_QUERY => Runtime::>::execute_query, - import::fn_names::GET_SMART_CONTRACT_PAYLOAD => Runtime::get_smart_contract_payload, + export::EXECUTE_ISI => Runtime::>::execute_instruction, + export::EXECUTE_QUERY => Runtime::>::execute_query, + export::GET_SMART_CONTRACT_PAYLOAD => Runtime::get_smart_contract_payload, )?; Ok(linker) }) @@ -1461,9 +1490,9 @@ impl<'wrld> RuntimeBuilder> { let mut linker = Linker::new(engine); create_imports!(linker, - import::fn_names::EXECUTE_ISI => Runtime::>::execute_instruction, - import::fn_names::EXECUTE_QUERY => Runtime::>::execute_query, - import::fn_names::GET_TRIGGER_PAYLOAD => Runtime::get_trigger_payload, + export::EXECUTE_ISI => Runtime::>::execute_instruction, + export::EXECUTE_QUERY => Runtime::>::execute_query, + export::GET_TRIGGER_PAYLOAD => Runtime::get_trigger_payload, )?; Ok(linker) }) @@ -1481,13 +1510,13 @@ impl<'wrld> RuntimeBuilder> { let mut linker = Linker::new(engine); create_imports!(linker, - import::fn_names::EXECUTE_ISI => Runtime::>::execute_instruction, - import::fn_names::EXECUTE_QUERY => Runtime::>::execute_query, - import::fn_names::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, - import::fn_names::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, - import::fn_names::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, - import::fn_names::GET_VALIDATE_QUERY_PAYLOAD => Runtime::get_validate_query_payload, - import::fn_names::SET_PERMISSION_TOKEN_SCHEMA => Runtime::set_permission_token_schema, + export::EXECUTE_ISI => Runtime::>::execute_instruction, + export::EXECUTE_QUERY => Runtime::>::execute_query, + export::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, + export::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, + export::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, + export::GET_VALIDATE_QUERY_PAYLOAD => Runtime::get_validate_query_payload, + export::SET_PERMISSION_TOKEN_SCHEMA => Runtime::set_permission_token_schema, )?; Ok(linker) }) @@ -1505,13 +1534,13 @@ impl<'wrld> RuntimeBuilder> { let mut linker = Linker::new(engine); create_imports!(linker, - import::fn_names::EXECUTE_ISI => Runtime::>::execute_instruction, - import::fn_names::EXECUTE_QUERY => Runtime::>::execute_query, - import::fn_names::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, - import::fn_names::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, - import::fn_names::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, - import::fn_names::GET_VALIDATE_QUERY_PAYLOAD => Runtime::get_validate_query_payload, - import::fn_names::SET_PERMISSION_TOKEN_SCHEMA => Runtime::set_permission_token_schema, + export::EXECUTE_ISI => Runtime::>::execute_instruction, + export::EXECUTE_QUERY => Runtime::>::execute_query, + export::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, + export::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, + export::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, + export::GET_VALIDATE_QUERY_PAYLOAD => Runtime::get_validate_query_payload, + export::SET_PERMISSION_TOKEN_SCHEMA => Runtime::set_permission_token_schema, )?; Ok(linker) }) @@ -1529,13 +1558,13 @@ impl<'wrld> RuntimeBuilder> { let mut linker = Linker::new(engine); create_imports!(linker, - import::fn_names::EXECUTE_ISI => Runtime::>::execute_instruction, - import::fn_names::EXECUTE_QUERY => Runtime::>::execute_query, - import::fn_names::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, - import::fn_names::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, - import::fn_names::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, - import::fn_names::GET_VALIDATE_QUERY_PAYLOAD => Runtime::get_validate_query_payload, - import::fn_names::SET_PERMISSION_TOKEN_SCHEMA => Runtime::set_permission_token_schema, + export::EXECUTE_ISI => Runtime::>::execute_instruction, + export::EXECUTE_QUERY => Runtime::>::execute_query, + export::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, + export::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, + export::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, + export::GET_VALIDATE_QUERY_PAYLOAD => Runtime::get_validate_query_payload, + export::SET_PERMISSION_TOKEN_SCHEMA => Runtime::set_permission_token_schema, )?; Ok(linker) }) @@ -1553,13 +1582,13 @@ impl<'wrld> RuntimeBuilder> { let mut linker = Linker::new(engine); create_imports!(linker, - import::fn_names::EXECUTE_ISI => Runtime::>::execute_instruction, - import::fn_names::EXECUTE_QUERY => Runtime::>::execute_query, - import::fn_names::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, - import::fn_names::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, - import::fn_names::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, - import::fn_names::GET_VALIDATE_QUERY_PAYLOAD => Runtime::get_validate_query_payload, - import::fn_names::SET_PERMISSION_TOKEN_SCHEMA => Runtime::set_permission_token_schema, + export::EXECUTE_ISI => Runtime::>::execute_instruction, + export::EXECUTE_QUERY => Runtime::>::execute_query, + export::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, + export::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, + export::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, + export::GET_VALIDATE_QUERY_PAYLOAD => Runtime::get_validate_query_payload, + export::SET_PERMISSION_TOKEN_SCHEMA => Runtime::set_permission_token_schema, )?; Ok(linker) }) @@ -1626,9 +1655,9 @@ mod tests { (func (export "{dealloc_fn_name}") (param $size i32) (param $len i32) nop) "#, - memory_name = export::WASM_MEMORY, - alloc_fn_name = export::fn_names::WASM_ALLOC, - dealloc_fn_name = export::fn_names::WASM_DEALLOC, + memory_name = WASM_MEMORY, + alloc_fn_name = import::SMART_CONTRACT_ALLOC, + dealloc_fn_name = import::SMART_CONTRACT_DEALLOC, isi_len = isi_hex.len() / 3, isi_hex = isi_hex, ) @@ -1677,8 +1706,8 @@ mod tests { ;; No use of return values drop)) "#, - main_fn_name = export::fn_names::SMART_CONTRACT_MAIN, - execute_fn_name = import::fn_names::EXECUTE_ISI, + main_fn_name = import::SMART_CONTRACT_MAIN, + execute_fn_name = export::EXECUTE_ISI, memory_and_alloc = memory_and_alloc(&isi_hex), isi_len = isi_hex.len() / 3, ); @@ -1713,8 +1742,8 @@ mod tests { ;; No use of return values drop)) "#, - main_fn_name = export::fn_names::SMART_CONTRACT_MAIN, - execute_fn_name = import::fn_names::EXECUTE_QUERY, + main_fn_name = import::SMART_CONTRACT_MAIN, + execute_fn_name = export::EXECUTE_QUERY, memory_and_alloc = memory_and_alloc(&query_hex), isi_len = query_hex.len() / 3, ); @@ -1754,8 +1783,8 @@ mod tests { (call $exec_fn (i32.const 0) (i32.const {isi1_end})) (call $exec_fn (i32.const {isi1_end}) (i32.const {isi2_end})))) "#, - main_fn_name = export::fn_names::SMART_CONTRACT_MAIN, - execute_fn_name = import::fn_names::EXECUTE_ISI, + main_fn_name = import::SMART_CONTRACT_MAIN, + execute_fn_name = export::EXECUTE_ISI, // Store two instructions into adjacent memory and execute them memory_and_alloc = memory_and_alloc(&isi_hex.repeat(2)), isi1_end = isi_hex.len() / 3, @@ -1804,8 +1833,8 @@ mod tests { ) ) "#, - main_fn_name = export::fn_names::SMART_CONTRACT_MAIN, - execute_fn_name = import::fn_names::EXECUTE_ISI, + main_fn_name = import::SMART_CONTRACT_MAIN, + execute_fn_name = export::EXECUTE_ISI, memory_and_alloc = memory_and_alloc(&isi_hex), isi_len = isi_hex.len() / 3, ); @@ -1847,8 +1876,8 @@ mod tests { ;; No use of return value drop)) "#, - main_fn_name = export::fn_names::SMART_CONTRACT_MAIN, - execute_fn_name = import::fn_names::EXECUTE_QUERY, + main_fn_name = import::SMART_CONTRACT_MAIN, + execute_fn_name = export::EXECUTE_QUERY, memory_and_alloc = memory_and_alloc(&query_hex), isi_len = query_hex.len() / 3, ); @@ -1888,8 +1917,8 @@ mod tests { ;; No use of return values drop)) "#, - main_fn_name = export::fn_names::SMART_CONTRACT_MAIN, - get_trigger_payload_fn_name = import::fn_names::GET_TRIGGER_PAYLOAD, + main_fn_name = import::SMART_CONTRACT_MAIN, + get_trigger_payload_fn_name = export::GET_TRIGGER_PAYLOAD, memory_and_alloc = memory_and_alloc(&query_hex), ); diff --git a/crypto/src/hash.rs b/crypto/src/hash.rs index be6a701015b..12919a0faeb 100644 --- a/crypto/src/hash.rs +++ b/crypto/src/hash.rs @@ -69,6 +69,8 @@ impl Hash { impl Hash { /// Hash the given bytes. #[must_use] + // NOTE: Panic is predicated by implementation not user input + #[allow(clippy::missing_panics_doc)] pub fn new(bytes: impl AsRef<[u8]>) -> Self { let vec_hash = VarBlake2b::new(Self::LENGTH) .expect("Failed to initialize variable size hash") diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 90bac808f97..88713128a6a 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -76,11 +76,11 @@ pub mod permission; pub mod predicate; pub mod query; pub mod role; +pub mod smart_contract; pub mod transaction; pub mod trigger; pub mod validator; pub mod visit; -pub mod wasm; mod seal { use crate::{isi::prelude::*, query::prelude::*}; diff --git a/data_model/src/name.rs b/data_model/src/name.rs index fd586bb26a5..991708eed89 100644 --- a/data_model/src/name.rs +++ b/data_model/src/name.rs @@ -106,7 +106,8 @@ impl FromStr for Name { type Err = ParseError; fn from_str(candidate: &str) -> Result { - Self::validate_str(candidate).map(|_| Self(ConstString::from(candidate))) + Self::validate_str(candidate)?; + Ok(Self(ConstString::from(candidate))) } } @@ -114,7 +115,8 @@ impl TryFrom for Name { type Error = ParseError; fn try_from(candidate: String) -> Result { - Self::validate_str(&candidate).map(|_| Self(ConstString::from(candidate))) + Self::validate_str(&candidate)?; + Ok(Self(ConstString::from(candidate))) } } @@ -125,17 +127,17 @@ impl<'de> Deserialize<'de> for Name { { use serde::de::Error as _; - let name = ConstString::deserialize(deserializer)?; - Self::validate_str(&name) - .map(|_| Self(name)) - .map_err(D::Error::custom) + let candidate = ConstString::deserialize(deserializer)?; + Self::validate_str(&candidate).map_err(D::Error::custom)?; + + Ok(Self(candidate)) } } impl Decode for Name { fn decode(input: &mut I) -> Result { let name = ConstString::decode(input)?; Self::validate_str(&name) - .map(|_| Self(name)) + .map(|()| Self(name)) .map_err(|error| error.reason.into()) } } diff --git a/data_model/src/predicate.rs b/data_model/src/predicate.rs index 3cd95902fb4..d58163f5ee8 100644 --- a/data_model/src/predicate.rs +++ b/data_model/src/predicate.rs @@ -1335,7 +1335,7 @@ pub mod ip_addr { self.0 .iter() .copied() - .zip(input.into_iter()) + .zip(input) .all(|(myself, other)| myself.applies(other)) } } diff --git a/data_model/src/smart_contract.rs b/data_model/src/smart_contract.rs new file mode 100644 index 00000000000..471d7bd777f --- /dev/null +++ b/data_model/src/smart_contract.rs @@ -0,0 +1,43 @@ +//! This module contains data and structures related only to smart contract execution + +pub mod payloads { + //! Payloads with function arguments for different entrypoints + + use parity_scale_codec::{Decode, Encode}; + + use crate::prelude::*; + + /// Payload for smart contract entrypoint + #[derive(Debug, Clone, Encode, Decode)] + pub struct SmartContract { + /// Smart contract owner who submitted transaction with it + pub owner: AccountId, + } + + /// Payload for trigger entrypoint + #[derive(Debug, Clone, Encode, Decode)] + pub struct Trigger { + /// Trigger owner who registered the trigger + pub owner: AccountId, + /// Event which triggered the execution + pub event: Event, + } + + /// Payload for migrate entrypoint + #[derive(Debug, Clone, Copy, Encode, Decode)] + pub struct Migrate { + /// Height of the latest block in the blockchain + pub block_height: u64, + } + + /// Generic payload for `validate_*()` entrypoints of validator. + #[derive(Debug, Clone, Encode, Decode)] + pub struct Validate { + /// Authority which executed the operation to be validated + pub authority: AccountId, + /// Height of the latest block in the blockchain + pub block_height: u64, + /// Operation to be validated + pub to_validate: T, + } +} diff --git a/data_model/src/wasm.rs b/data_model/src/wasm.rs deleted file mode 100644 index 9510a6d0f7d..00000000000 --- a/data_model/src/wasm.rs +++ /dev/null @@ -1,120 +0,0 @@ -//! This module contains data and structures related only to WASM execution - -pub mod export { - //! Data which is exported from WASM to Iroha - - /// Name of the exported memory - pub const WASM_MEMORY: &str = "memory"; - - pub mod fn_names { - //! Names of the functions which are exported from Iroha to WASM - - /// Exported function to allocate memory - pub const WASM_ALLOC: &str = "_iroha_wasm_alloc"; - /// Exported function to deallocate memory - pub const WASM_DEALLOC: &str = "_iroha_wasm_dealloc"; - /// Name of the exported entry for smart contract execution - pub const SMART_CONTRACT_MAIN: &str = "_iroha_smart_contract_main"; - /// Name of the exported entry for trigger execution - pub const TRIGGER_MAIN: &str = "_iroha_trigger_main"; - /// Name of the exported entry for validator to validate transaction - pub const VALIDATOR_VALIDATE_TRANSACTION: &str = "_iroha_validator_validate_transaction"; - /// Name of the exported entry for validator to validate instruction - pub const VALIDATOR_VALIDATE_INSTRUCTION: &str = "_iroha_validator_validate_instruction"; - /// Name of the exported entry for validator to validate query - pub const VALIDATOR_VALIDATE_QUERY: &str = "_iroha_validator_validate_query"; - /// Name of the exported entry for validator to perform migration - pub const VALIDATOR_MIGRATE: &str = "_iroha_validator_migrate"; - } -} - -pub mod import { - //! Data which is imported from Iroha to WASM - - /// Name of the linked wasm module - pub const MODULE: &str = "iroha"; - - pub mod fn_names { - //! Names of the functions which are imported from Iroha to WASM - - /// Name of the imported function to execute instructions - pub const EXECUTE_ISI: &str = "execute_instruction"; - /// Name of the imported function to execute queries - pub const EXECUTE_QUERY: &str = "execute_query"; - /// Name of the imported function to get payload for smart contract - /// [`main()`](super::super::export::fn_names::SMART_CONTRACT_MAIN) entrypoint - pub const GET_SMART_CONTRACT_PAYLOAD: &str = "get_smart_contract_payload"; - /// Name of the imported function to get payload for trigger - /// [`main()`](super::super::export::fn_names::TRIGGER_MAIN) entrypoint - pub const GET_TRIGGER_PAYLOAD: &str = "get_trigger_payload"; - /// Name of the imported function to get payload for - /// [`migrate()`](super::super::export::fn_names::VALIDATOR_MIGRATE) entrypoint - pub const GET_MIGRATE_PAYLOAD: &str = "get_migrate_payload"; - /// Name of the imported function to get payload for - /// [`validate_transaction()`](super::super::export::fn_names::VALIDATOR_VALIDATE_TRANSACTION) entrypoint - pub const GET_VALIDATE_TRANSACTION_PAYLOAD: &str = "get_validate_transaction_payload"; - /// Name of the imported function to get payload for - /// [`validate_instruction()`](super::super::export::fn_names::VALIDATOR_VALIDATE_INSTRUCTION) entrypoint - pub const GET_VALIDATE_INSTRUCTION_PAYLOAD: &str = "get_validate_instruction_payload"; - /// Name of the imported function to get payload for - /// [`validate_query()`](super::super::export::fn_names::VALIDATOR_VALIDATE_QUERY) entrypoint - pub const GET_VALIDATE_QUERY_PAYLOAD: &str = "get_validate_query_payload"; - /// Name of the imported function to debug print objects - pub const DBG: &str = "dbg"; - /// Name of the imported function to log objects - pub const LOG: &str = "log"; - /// Name of the imported function to set new [`PermissionTokenSchema`](crate::permission::PermissionTokenSchema) - pub const SET_PERMISSION_TOKEN_SCHEMA: &str = "set_permission_token_schema"; - } -} - -pub mod payloads { - //! Payloads with function arguments for different entrypoints - - use parity_scale_codec::{Decode, Encode}; - - use crate::prelude::*; - - /// Payload for smart contract [`main()`](super::export::fn_names::SMART_CONTRACT_MAIN) entrypoint - #[derive(Debug, Clone, Encode, Decode)] - pub struct SmartContract { - /// Smart contract owner who submitted transaction with it - pub owner: AccountId, - } - - /// Payload for trigger [`main()`](super::export::fn_names::TRIGGER_MAIN) entrypoint - #[derive(Debug, Clone, Encode, Decode)] - pub struct Trigger { - /// Trigger owner who registered the trigger - pub owner: AccountId, - /// Event which triggered the execution - pub event: Event, - } - - /// Payload for [`migrate()`](super::export::fn_names::VALIDATOR_MIGRATE) entrypoint - #[derive(Debug, Clone, Copy, Encode, Decode)] - pub struct Migrate { - /// Height of the latest block in the blockchain - pub block_height: u64, - } - - /// Payload for [`validate_transaction()`](super::export::fn_names::VALIDATOR_VALIDATE_TRANSACTION) entrypoint - pub type ValidateTransaction = Validate; - - /// Payload for [`validate_instruction()`](super::export::fn_names::VALIDATOR_VALIDATE_INSTRUCTION) entrypoint - pub type ValidateInstruction = Validate; - - /// Payload for [`validate_query()`](super::export::fn_names::VALIDATOR_VALIDATE_QUERY) entrypoint - pub type ValidateQuery = Validate; - - /// Generic payload for `validate_*()` entrypoints of validator. - #[derive(Debug, Clone, Encode, Decode)] - pub struct Validate { - /// Authority which executed the operation to be validated - pub authority: AccountId, - /// Height of the latest block in the blockchain - pub block_height: u64, - /// Operation to be validated - pub to_validate: T, - } -} diff --git a/default_validator/Cargo.toml b/default_validator/Cargo.toml index f45204042fd..31f69bf876f 100644 --- a/default_validator/Cargo.toml +++ b/default_validator/Cargo.toml @@ -24,6 +24,7 @@ opt-level = "z" # Optimize for size vs speed with "s"/"z"(removes vectorizat codegen-units = 1 # Further reduces binary size but increases compilation time [dependencies] -iroha_validator = { version = "2.0.0-pre-rc.19", path = "../wasm/validator", features = ["debug"]} +iroha_validator = { version = "2.0.0-pre-rc.19", path = "../smart_contract/validator", features = ["debug"]} +lol_alloc = "0.4.0" panic-halt = "0.2.0" diff --git a/default_validator/src/lib.rs b/default_validator/src/lib.rs index e602b8ccd89..6cd9116e9ba 100644 --- a/default_validator/src/lib.rs +++ b/default_validator/src/lib.rs @@ -11,8 +11,12 @@ use alloc::borrow::ToOwned as _; use iroha_validator::{ data_model::evaluate::ExpressionEvaluator, default::default_permission_token_schema, - iroha_wasm, prelude::*, + prelude::*, smart_contract, }; +use lol_alloc::{FreeListAllocator, LockedAllocator}; + +#[global_allocator] +static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); /// Validator that replaces some of [`Validate`]'s methods with sensible defaults /// @@ -23,7 +27,7 @@ use iroha_validator::{ pub struct Validator { verdict: Result, block_height: u64, - host: iroha_wasm::Host, + host: smart_contract::Host, } impl Validator { @@ -32,7 +36,7 @@ impl Validator { Self { verdict: Ok(()), block_height, - host: iroha_wasm::Host, + host: smart_contract::Host, } } @@ -139,7 +143,8 @@ impl ExpressionEvaluator for Validator { fn evaluate( &self, expression: &E, - ) -> core::result::Result { + ) -> core::result::Result + { self.host.evaluate(expression) } } @@ -159,7 +164,7 @@ pub fn migrate(block_height: u64) -> MigrationResult { let schema = default_permission_token_schema(); let (token_ids, schema_str) = schema.serialize(); - iroha_validator::iroha_wasm::set_permission_token_schema( + iroha_validator::set_permission_token_schema( &iroha_validator::data_model::permission::PermissionTokenSchema::new(token_ids, schema_str), ); diff --git a/ffi/derive/src/convert.rs b/ffi/derive/src/convert.rs index 5c835c9bd4a..3f0ea4b2cd3 100644 --- a/ffi/derive/src/convert.rs +++ b/ffi/derive/src/convert.rs @@ -465,7 +465,7 @@ fn derive_ffi_type_for_data_carrying_enum( local: bool, ) -> TokenStream { let (repr_c_enum_name, repr_c_enum) = - gen_data_carrying_repr_c_enum(emitter, enum_name, &mut generics, variants); + gen_data_carrying_repr_c_enum(emitter, enum_name, &generics, variants); generics.make_where_clause(); let lifetime = quote! {'__iroha_ffi_itm}; @@ -681,7 +681,7 @@ fn derive_ffi_type_for_repr_c(emitter: &mut Emitter, input: &FfiTypeInput) -> To fn gen_data_carrying_repr_c_enum( emitter: &mut Emitter, enum_name: &Ident, - generics: &mut syn2::Generics, + generics: &syn2::Generics, variants: &[SpannedValue], ) -> (Ident, TokenStream) { let (payload_name, payload) = @@ -712,7 +712,7 @@ fn gen_data_carrying_repr_c_enum( fn gen_data_carrying_enum_payload( emitter: &mut Emitter, enum_name: &Ident, - generics: &mut syn2::Generics, + generics: &syn2::Generics, variants: &[SpannedValue], ) -> (Ident, TokenStream) { let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); diff --git a/schema/Cargo.toml b/schema/Cargo.toml index d118ec66407..3deae73c8c5 100644 --- a/schema/Cargo.toml +++ b/schema/Cargo.toml @@ -18,5 +18,5 @@ fixnum = { workspace = true, features = ["i64"] } [dev-dependencies] parity-scale-codec = { workspace = true, default-features = false, features = ["derive", "full"] } +serde_json = { workspace = true, features = ["alloc"] } impls = { workspace = true } -serde_json = { workspace = true, features = ["std"] } diff --git a/wasm/.cargo/config.toml b/smart_contract/.cargo/config.toml similarity index 60% rename from wasm/.cargo/config.toml rename to smart_contract/.cargo/config.toml index 0134e4439a2..10c68cf82ce 100644 --- a/wasm/.cargo/config.toml +++ b/smart_contract/.cargo/config.toml @@ -1,5 +1,2 @@ -[build] -target = "wasm32-unknown-unknown" - [target.wasm32-unknown-unknown] runner = "iroha_wasm_test_runner" diff --git a/smart_contract/Cargo.toml b/smart_contract/Cargo.toml new file mode 100644 index 00000000000..64ba4666156 --- /dev/null +++ b/smart_contract/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "iroha_smart_contract" + +edition.workspace = true +version.workspace = true +authors.workspace = true + +license.workspace = true + +[lints] +workspace = true + +[features] +# Enables debugging tools such as `dbg()` and `DebugUnwrapExt` +debug = [] + +[dependencies] +iroha_data_model.workspace = true +iroha_smart_contract_utils.workspace = true +iroha_smart_contract_derive.workspace = true + +parity-scale-codec.workspace = true + +[dev-dependencies] +webassembly-test = "0.1.0" + diff --git a/wasm/LICENSE b/smart_contract/LICENSE similarity index 100% rename from wasm/LICENSE rename to smart_contract/LICENSE diff --git a/wasm/README.md b/smart_contract/README.md similarity index 96% rename from wasm/README.md rename to smart_contract/README.md index b221dcc903a..430c73f33ec 100644 --- a/wasm/README.md +++ b/smart_contract/README.md @@ -49,7 +49,7 @@ By following this list of optimization steps you can reduce the size of your bin [dependencies] iroha_data_model = { git = "https://github.com/hyperledger/iroha/", branch = "iroha2", default-features = false } - iroha_wasm = { git = "https://github.com/hyperledger/iroha/", branch = "iroha2" } + iroha_smart_contract = { git = "https://github.com/hyperledger/iroha/", branch = "iroha2" } panic-halt = "0.2.0" ``` diff --git a/wasm/derive/Cargo.toml b/smart_contract/derive/Cargo.toml similarity index 80% rename from wasm/derive/Cargo.toml rename to smart_contract/derive/Cargo.toml index 42aa8006f4a..72658aa9aa8 100644 --- a/wasm/derive/Cargo.toml +++ b/smart_contract/derive/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "iroha_wasm_derive" +name = "iroha_smart_contract_derive" version.workspace = true authors.workspace = true @@ -14,7 +14,6 @@ workspace = true proc-macro = true [dependencies] -iroha_data_model.workspace = true syn.workspace = true quote.workspace = true proc-macro2.workspace = true diff --git a/wasm/derive/src/entrypoint.rs b/smart_contract/derive/src/entrypoint.rs similarity index 86% rename from wasm/derive/src/entrypoint.rs rename to smart_contract/derive/src/entrypoint.rs index 1a01dfc83cf..9ed630b7b1d 100644 --- a/wasm/derive/src/entrypoint.rs +++ b/smart_contract/derive/src/entrypoint.rs @@ -6,6 +6,10 @@ use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, parse_quote}; +mod export { + pub const SMART_CONTRACT_MAIN: &str = "_iroha_smart_contract_main"; +} + #[allow(clippy::needless_pass_by_value)] pub fn impl_entrypoint(_attr: TokenStream, item: TokenStream) -> TokenStream { let syn::ItemFn { @@ -29,10 +33,7 @@ pub fn impl_entrypoint(_attr: TokenStream, item: TokenStream) -> TokenStream { ), ); - let main_fn_name = syn::Ident::new( - iroha_data_model::wasm::export::fn_names::SMART_CONTRACT_MAIN, - proc_macro2::Span::call_site(), - ); + let main_fn_name = syn::Ident::new(export::SMART_CONTRACT_MAIN, proc_macro2::Span::call_site()); quote! { /// Smart contract entrypoint diff --git a/wasm/derive/src/lib.rs b/smart_contract/derive/src/lib.rs similarity index 100% rename from wasm/derive/src/lib.rs rename to smart_contract/derive/src/lib.rs diff --git a/smart_contract/src/lib.rs b/smart_contract/src/lib.rs new file mode 100644 index 00000000000..62e0a570e77 --- /dev/null +++ b/smart_contract/src/lib.rs @@ -0,0 +1,268 @@ +//! API which simplifies writing of smartcontracts +#![no_std] +#![allow(unsafe_code)] + +extern crate alloc; + +use alloc::{boxed::Box, collections::BTreeMap}; + +#[cfg(not(test))] +use data_model::smart_contract::payloads; +use data_model::{ + isi::Instruction, + prelude::*, + query::{Query, QueryBox}, +}; +pub use iroha_data_model as data_model; +pub use iroha_smart_contract_derive::main; +pub use iroha_smart_contract_utils::{debug, log}; +use iroha_smart_contract_utils::{ + debug::DebugExpectExt as _, decode_with_length_prefix_from_raw, encode_and_execute, +}; +use parity_scale_codec::{DecodeAll, Encode}; + +#[no_mangle] +extern "C" fn _iroha_smart_contract_alloc(len: usize) -> *const u8 { + if len == 0 { + iroha_smart_contract_utils::debug::dbg_panic("Cannot allocate 0 bytes"); + } + let layout = core::alloc::Layout::array::(len).dbg_expect("Cannot allocate layout"); + // Safety: safe because `layout` is guaranteed to have non-zero size + unsafe { alloc::alloc::alloc_zeroed(layout) } +} + +/// # Safety +/// - `offset` is a pointer to a `[u8; len]` which is allocated in the WASM memory. +/// - This function can't call destructor of the encoded object. +#[no_mangle] +unsafe extern "C" fn _iroha_smart_contract_dealloc(offset: *mut u8, len: usize) { + let _box = Box::from_raw(core::slice::from_raw_parts_mut(offset, len)); +} + +/// Implementing instructions can be executed on the host +pub trait ExecuteOnHost: Instruction { + /// Execute instruction on the host + /// + /// # Errors + /// + /// - If instruction validation failed + /// - If instruction execution failed + fn execute(&self) -> Result<(), ValidationFail>; +} + +/// Implementing queries can be executed on the host +pub trait QueryHost: Query { + /// Execute query on the host + /// + /// # Errors + /// + /// - If query validation failed + /// - If query execution failed + fn execute(&self) -> Result; +} + +// TODO: Remove the Clone bound. It can be done by custom serialization to InstructionExpr +impl ExecuteOnHost for I { + fn execute(&self) -> Result<(), ValidationFail> { + #[cfg(not(test))] + use host::execute_instruction as host_execute_instruction; + #[cfg(test)] + use tests::_iroha_smart_contract_execute_instruction_mock as host_execute_instruction; + + // TODO: Redundant conversion into `InstructionExpr` + let isi_box: InstructionExpr = self.clone().into(); + // Safety: `host_execute_instruction` doesn't take ownership of it's pointer parameter + unsafe { + decode_with_length_prefix_from_raw(encode_and_execute( + &isi_box, + host_execute_instruction, + )) + } + } +} + +// TODO: Remove the Clone bound. It can be done by custom serialization/deserialization to QueryBox +impl + Encode + Clone> QueryHost for Q +where + Q::Output: DecodeAll, + >::Error: core::fmt::Debug, +{ + fn execute(&self) -> Result { + #[cfg(not(test))] + use host::execute_query as host_execute_query; + #[cfg(test)] + use tests::_iroha_smart_contract_execute_query_mock as host_execute_query; + + // TODO: Redundant conversion into `QueryBox` + let query_box: QueryBox = self.clone().into(); + // Safety: - `host_execute_query` doesn't take ownership of it's pointer parameter + // - ownership of the returned result is transferred into `_decode_from_raw` + let res: Result = unsafe { + decode_with_length_prefix_from_raw(encode_and_execute(&query_box, host_execute_query)) + }; + + res.map(|value| value.try_into().expect("Query returned invalid type")) + } +} + +/// World state view of the host +#[derive(Debug, Clone, Copy)] +pub struct Host; + +impl iroha_data_model::evaluate::ExpressionEvaluator for Host { + fn evaluate( + &self, + expression: &E, + ) -> Result { + expression.evaluate(&Context::new()) + } +} + +/// Context of expression evaluation +#[derive(Clone, Default)] +#[repr(transparent)] +pub struct Context { + values: BTreeMap, +} + +impl Context { + /// Create new [`Self`] + pub fn new() -> Self { + Self { + values: BTreeMap::new(), + } + } +} + +impl iroha_data_model::evaluate::Context for Context { + fn query(&self, query: &QueryBox) -> Result { + query.execute() + } + + fn get(&self, name: &Name) -> Option<&Value> { + self.values.get(name) + } + + fn update(&mut self, other: impl IntoIterator) { + self.values.extend(other) + } +} + +/// Get payload for smart contract `main()` entrypoint. +#[cfg(not(test))] +pub fn get_smart_contract_payload() -> payloads::SmartContract { + // Safety: ownership of the returned result is transferred into `_decode_from_raw` + unsafe { decode_with_length_prefix_from_raw(host::get_smart_contract_payload()) } +} + +#[cfg(not(test))] +mod host { + #[link(wasm_import_module = "iroha")] + extern "C" { + /// Execute encoded query by providing offset and length + /// into WebAssembly's linear memory where query is stored + /// + /// # Warning + /// + /// This function doesn't take ownership of the provided allocation + /// but it does transfer ownership of the result to the caller + pub(super) fn execute_query(ptr: *const u8, len: usize) -> *const u8; + + /// Execute encoded instruction by providing offset and length + /// into WebAssembly's linear memory where instruction is stored + /// + /// # Warning + /// + /// This function doesn't take ownership of the provided allocation + /// but it does transfer ownership of the result to the caller + pub(super) fn execute_instruction(ptr: *const u8, len: usize) -> *const u8; + + /// Get payload for smart contract `main()` entrypoint. + /// + /// # Warning + /// + /// This function does transfer ownership of the result to the caller + pub(super) fn get_smart_contract_payload() -> *const u8; + } +} + +/// Most used items +pub mod prelude { + pub use crate::{ExecuteOnHost, QueryHost}; +} + +#[cfg(test)] +mod tests { + #![allow(clippy::restriction)] + #![allow(clippy::pedantic)] + + use core::{mem::ManuallyDrop, slice}; + + use iroha_smart_contract_utils::encode_with_length_prefix; + use webassembly_test::webassembly_test; + + use super::*; + + const QUERY_RESULT: Result = + Ok(Value::Numeric(NumericValue::U32(1234_u32))); + const ISI_RESULT: Result<(), ValidationFail> = Ok(()); + const EXPRESSION_RESULT: NumericValue = NumericValue::U32(5_u32); + + fn get_test_instruction() -> InstructionExpr { + let new_account_id = "mad_hatter@wonderland".parse().expect("Valid"); + let register_isi = RegisterExpr::new(Account::new(new_account_id, [])); + + register_isi.into() + } + + fn get_test_query() -> QueryBox { + let account_id: AccountId = "alice@wonderland".parse().expect("Valid"); + FindAccountById::new(account_id).into() + } + + fn get_test_expression() -> EvaluatesTo { + Add::new(2_u32, 3_u32).into() + } + + #[no_mangle] + pub unsafe extern "C" fn _iroha_smart_contract_execute_instruction_mock( + ptr: *const u8, + len: usize, + ) -> *const u8 { + let bytes = slice::from_raw_parts(ptr, len); + let instruction = InstructionExpr::decode_all(&mut &*bytes); + assert_eq!(get_test_instruction(), instruction.unwrap()); + + ManuallyDrop::new(encode_with_length_prefix(&ISI_RESULT)).as_ptr() + } + + #[no_mangle] + pub unsafe extern "C" fn _iroha_smart_contract_execute_query_mock( + ptr: *const u8, + len: usize, + ) -> *const u8 { + let bytes = slice::from_raw_parts(ptr, len); + let query = QueryBox::decode_all(&mut &*bytes).unwrap(); + assert_eq!(query, get_test_query()); + + ManuallyDrop::new(encode_with_length_prefix(&QUERY_RESULT)).as_ptr() + } + + #[webassembly_test] + fn execute_instruction() { + get_test_instruction().execute().unwrap(); + } + + #[webassembly_test] + fn execute_query() { + assert_eq!(get_test_query().execute(), QUERY_RESULT); + } + + #[webassembly_test] + fn evaluate_expression() { + assert_eq!( + get_test_expression().evaluate(&Context::new()), + Ok(EXPRESSION_RESULT) + ); + } +} diff --git a/wasm/trigger/Cargo.toml b/smart_contract/trigger/Cargo.toml similarity index 54% rename from wasm/trigger/Cargo.toml rename to smart_contract/trigger/Cargo.toml index f14c79c46df..72da4d0677f 100644 --- a/wasm/trigger/Cargo.toml +++ b/smart_contract/trigger/Cargo.toml @@ -11,11 +11,10 @@ workspace = true [features] # Enables debugging tools such as `dbg()` and `DebugUnwrapExt` -debug = ["iroha_wasm/debug"] +debug = ["iroha_smart_contract/debug"] [dependencies] -iroha_wasm = { version = "2.0.0-pre-rc.18", path = ".." } -iroha_trigger_derive = { version = "2.0.0-pre-rc.18", path = "derive" } - -[dev-dependencies] -webassembly-test.workspace = true +iroha_smart_contract_utils.workspace = true +iroha_smart_contract.workspace = true +iroha_trigger_derive.workspace = true +iroha_data_model.workspace = true diff --git a/wasm/trigger/derive/Cargo.toml b/smart_contract/trigger/derive/Cargo.toml similarity index 89% rename from wasm/trigger/derive/Cargo.toml rename to smart_contract/trigger/derive/Cargo.toml index 05feb5bd61e..486eaa75ad7 100644 --- a/wasm/trigger/derive/Cargo.toml +++ b/smart_contract/trigger/derive/Cargo.toml @@ -15,7 +15,6 @@ workspace = true proc-macro = true [dependencies] -iroha_data_model.workspace = true syn.workspace = true quote.workspace = true proc-macro2.workspace = true diff --git a/wasm/trigger/derive/src/entrypoint.rs b/smart_contract/trigger/derive/src/entrypoint.rs similarity index 79% rename from wasm/trigger/derive/src/entrypoint.rs rename to smart_contract/trigger/derive/src/entrypoint.rs index 1cecaba0f58..71387f19be9 100644 --- a/wasm/trigger/derive/src/entrypoint.rs +++ b/smart_contract/trigger/derive/src/entrypoint.rs @@ -2,6 +2,10 @@ use super::*; +mod export { + pub const TRIGGER_MAIN: &str = "_iroha_trigger_main"; +} + /// [`main`](super::main()) macro implementation #[allow(clippy::needless_pass_by_value)] pub fn impl_entrypoint(_attr: TokenStream, item: TokenStream) -> TokenStream { @@ -22,23 +26,20 @@ pub fn impl_entrypoint(_attr: TokenStream, item: TokenStream) -> TokenStream { block.stmts.insert( 0, parse_quote!( - use ::iroha_trigger::iroha_wasm::{ + use ::iroha_trigger::smart_contract::{ debug::DebugExpectExt as _, ExecuteOnHost as _, QueryHost as _, }; ), ); - let main_fn_name = syn::Ident::new( - iroha_data_model::wasm::export::fn_names::TRIGGER_MAIN, - proc_macro2::Span::call_site(), - ); + let main_fn_name = syn::Ident::new(export::TRIGGER_MAIN, proc_macro2::Span::call_site()); quote! { /// Smart contract entrypoint #[no_mangle] #[doc(hidden)] unsafe extern "C" fn #main_fn_name() { - let payload = ::iroha_trigger::iroha_wasm::get_trigger_payload(); + let payload = ::iroha_trigger::get_trigger_payload(); #fn_name(payload.owner, payload.event) } diff --git a/wasm/trigger/derive/src/lib.rs b/smart_contract/trigger/derive/src/lib.rs similarity index 100% rename from wasm/trigger/derive/src/lib.rs rename to smart_contract/trigger/derive/src/lib.rs diff --git a/smart_contract/trigger/src/lib.rs b/smart_contract/trigger/src/lib.rs new file mode 100644 index 00000000000..84bb1d1f76a --- /dev/null +++ b/smart_contract/trigger/src/lib.rs @@ -0,0 +1,45 @@ +//! Iroha Trigger Rust SDK +#![no_std] +#![allow(unsafe_code)] + +#[cfg(not(test))] +use data_model::smart_contract::payloads; +pub use iroha_data_model as data_model; +pub use iroha_smart_contract as smart_contract; +pub use iroha_smart_contract_utils::debug; +#[cfg(not(test))] +use iroha_smart_contract_utils::decode_with_length_prefix_from_raw; +pub use iroha_trigger_derive::main; + +pub mod log { + //! WASM logging utilities + pub use iroha_smart_contract_utils::{debug, error, event, info, log::*, trace, warn}; +} + +#[cfg(not(test))] +mod host { + #[link(wasm_import_module = "iroha")] + extern "C" { + /// Get payload for trigger `main()` entrypoint. + /// + /// # Warning + /// + /// This function does transfer ownership of the result to the caller + pub(super) fn get_trigger_payload() -> *const u8; + } +} + +/// Get payload for trigger `main()` entrypoint. +#[cfg(not(test))] +pub fn get_trigger_payload() -> payloads::Trigger { + // Safety: ownership of the returned result is transferred into `_decode_from_raw` + unsafe { decode_with_length_prefix_from_raw(host::get_trigger_payload()) } +} + +pub mod prelude { + //! Common imports used by triggers + + pub use iroha_smart_contract::{data_model::prelude::*, prelude::*}; + pub use iroha_smart_contract_utils::debug::DebugUnwrapExt; + pub use iroha_trigger_derive::main; +} diff --git a/smart_contract/utils/Cargo.toml b/smart_contract/utils/Cargo.toml new file mode 100644 index 00000000000..97f8a59d60d --- /dev/null +++ b/smart_contract/utils/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "iroha_smart_contract_utils" + +edition.workspace = true +version.workspace = true +authors.workspace = true + +license.workspace = true + +[lints] +workspace = true + +[dependencies] +iroha_data_model.workspace = true + +parity-scale-codec.workspace = true + +[dev-dependencies] +webassembly-test = "0.1.0" diff --git a/wasm/src/debug.rs b/smart_contract/utils/src/debug.rs similarity index 98% rename from wasm/src/debug.rs rename to smart_contract/utils/src/debug.rs index ed88fa048f1..3164faf0645 100644 --- a/wasm/src/debug.rs +++ b/smart_contract/utils/src/debug.rs @@ -2,9 +2,6 @@ use core::fmt::Debug; -#[cfg(feature = "debug")] -use super::*; - #[cfg(not(test))] mod host { #[cfg(feature = "debug")] @@ -35,7 +32,7 @@ pub fn dbg(_obj: &T) { #[allow(clippy::used_underscore_binding)] let s = format!("{:?}", _obj); // Safety: `host_dbg` doesn't take ownership of it's pointer parameter - unsafe { encode_and_execute(&s, host_dbg) } + unsafe { iroha_smart_contract_utils::encode_and_execute(&s, host_dbg) } } } diff --git a/smart_contract/utils/src/lib.rs b/smart_contract/utils/src/lib.rs new file mode 100644 index 00000000000..ec9f70a242e --- /dev/null +++ b/smart_contract/utils/src/lib.rs @@ -0,0 +1,120 @@ +//! Crate with utilities for implementing smart contract FFI +#![no_std] +#![allow(unsafe_code)] + +extern crate alloc; + +use alloc::{boxed::Box, format, vec::Vec}; +use core::ops::RangeFrom; + +use parity_scale_codec::{DecodeAll, Encode}; + +pub mod debug; +pub mod log; + +/// Decode the object from given pointer and length +/// +/// # Warning +/// +/// This method takes ownership of the given pointer +/// +/// # Safety +/// +/// It's safe to call this function as long as it's safe to construct, from the given +/// pointer, `Box<[u8]>` containing the encoded object +unsafe fn _decode_from_raw(ptr: *const u8, len: usize) -> T { + _decode_from_raw_in_range(ptr, len, 0..) +} + +/// Decode the object from given pointer and length in the given range +/// +/// # Warning +/// +/// This method takes ownership of the given pointer +/// +/// # Safety +/// +/// It's safe to call this function as long as it's safe to construct, from the given +/// pointer, `Box<[u8]>` containing the encoded object +unsafe fn _decode_from_raw_in_range( + ptr: *const u8, + len: usize, + range: RangeFrom, +) -> T { + let bytes = Box::from_raw(core::slice::from_raw_parts_mut(ptr.cast_mut(), len)); + + #[allow(clippy::expect_fun_call)] + T::decode_all(&mut &bytes[range]).expect( + format!( + "Decoding of {} failed. This is a bug", + core::any::type_name::() + ) + .as_str(), + ) +} + +/// Decode the object from given pointer where first element is the size of the object +/// following it. This can be considered a custom encoding format. +/// +/// # Warning +/// +/// This method takes ownership of the given pointer +/// +/// # Safety +/// +/// It's safe to call this function as long as it's safe to construct, from the given +/// pointer, byte array of prefix length and `Box<[u8]>` containing the encoded object +pub unsafe fn decode_with_length_prefix_from_raw(ptr: *const u8) -> T { + let len_size_bytes = core::mem::size_of::(); + + let len = usize::from_le_bytes( + core::slice::from_raw_parts(ptr, len_size_bytes) + .try_into() + .expect("Prefix length size(bytes) incorrect. This is a bug."), + ); + + _decode_from_raw_in_range(ptr, len, len_size_bytes..) +} + +/// Encode the given object and call the given function with the pointer and length of the allocation +/// +/// # Warning +/// +/// Ownership of the returned allocation is transfered to the caller +/// +/// # Safety +/// +/// The given function must not take ownership of the pointer argument +pub unsafe fn encode_and_execute( + obj: &T, + fun: unsafe extern "C" fn(*const u8, usize) -> O, +) -> O { + // NOTE: It's imperative that encoded object is stored on the heap + // because heap corresponds to linear memory when compiled to wasm + let bytes = obj.encode(); + + fun(bytes.as_ptr(), bytes.len()) +} + +/// Encode the given `val` as a vector of bytes with the size of the object at the beginning +// +// TODO: Write a separate crate for codec/protocol between Iroha and smartcontract +pub fn encode_with_length_prefix(val: &T) -> Box<[u8]> { + let len_size_bytes = core::mem::size_of::(); + + let mut r = Vec::with_capacity( + len_size_bytes + .checked_add(val.size_hint()) + .expect("Overflow during length computation"), + ); + + // Reserve space for length + r.resize(len_size_bytes, 0); + val.encode_to(&mut r); + + // Store length of the whole vector as byte array at the beginning of the vec + let len = r.len(); + r[..len_size_bytes].copy_from_slice(&len.to_le_bytes()); + + r.into_boxed_slice() +} diff --git a/wasm/src/log.rs b/smart_contract/utils/src/log.rs similarity index 99% rename from wasm/src/log.rs rename to smart_contract/utils/src/log.rs index 2adcfede7f2..bc1372ed86c 100644 --- a/wasm/src/log.rs +++ b/smart_contract/utils/src/log.rs @@ -3,6 +3,7 @@ pub use iroha_data_model::Level; use super::*; + #[cfg(not(test))] mod host { #[link(wasm_import_module = "iroha")] diff --git a/smart_contract/validator/Cargo.toml b/smart_contract/validator/Cargo.toml new file mode 100644 index 00000000000..22cca4dd92a --- /dev/null +++ b/smart_contract/validator/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "iroha_validator" + +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true + +[lints] +workspace = true + +[features] +# Enables debugging tools such as `dbg()` and `DebugUnwrapExt` +debug = ["iroha_smart_contract/debug"] + +[dependencies] +iroha_smart_contract_utils.workspace = true +iroha_smart_contract.workspace = true +iroha_validator_derive.workspace = true +iroha_data_model.workspace = true +iroha_schema.workspace = true + +serde.workspace = true +serde_json.workspace = true diff --git a/wasm/validator/derive/Cargo.toml b/smart_contract/validator/derive/Cargo.toml similarity index 89% rename from wasm/validator/derive/Cargo.toml rename to smart_contract/validator/derive/Cargo.toml index 04f6438d9f1..a2c930c1eda 100644 --- a/wasm/validator/derive/Cargo.toml +++ b/smart_contract/validator/derive/Cargo.toml @@ -15,7 +15,6 @@ workspace = true proc-macro = true [dependencies] -iroha_data_model.workspace = true syn.workspace = true quote.workspace = true proc-macro2.workspace = true diff --git a/wasm/validator/derive/src/conversion.rs b/smart_contract/validator/derive/src/conversion.rs similarity index 100% rename from wasm/validator/derive/src/conversion.rs rename to smart_contract/validator/derive/src/conversion.rs diff --git a/wasm/validator/derive/src/entrypoint.rs b/smart_contract/validator/derive/src/entrypoint.rs similarity index 77% rename from wasm/validator/derive/src/entrypoint.rs rename to smart_contract/validator/derive/src/entrypoint.rs index 73ceb77538c..0baa04cb8f2 100644 --- a/wasm/validator/derive/src/entrypoint.rs +++ b/smart_contract/validator/derive/src/entrypoint.rs @@ -2,6 +2,19 @@ use super::*; +mod export { + pub const VALIDATOR_VALIDATE_TRANSACTION: &str = "_iroha_validator_validate_transaction"; + pub const VALIDATOR_VALIDATE_INSTRUCTION: &str = "_iroha_validator_validate_instruction"; + pub const VALIDATOR_VALIDATE_QUERY: &str = "_iroha_validator_validate_query"; + pub const VALIDATOR_MIGRATE: &str = "_iroha_validator_migrate"; +} + +mod import { + pub const GET_VALIDATE_TRANSACTION_PAYLOAD: &str = "get_validate_transaction_payload"; + pub const GET_VALIDATE_INSTRUCTION_PAYLOAD: &str = "get_validate_instruction_payload"; + pub const GET_VALIDATE_QUERY_PAYLOAD: &str = "get_validate_query_payload"; +} + /// [`validator_entrypoint`](crate::validator_entrypoint()) macro implementation #[allow(clippy::needless_pass_by_value)] pub fn impl_entrypoint(attr: TokenStream, item: TokenStream) -> TokenStream { @@ -25,8 +38,8 @@ pub fn impl_entrypoint(attr: TokenStream, item: TokenStream) -> TokenStream { impl_validate_entrypoint( fn_item, stringify!($user_entrypoint_name), - iroha_data_model::wasm::export::fn_names::$generated_entrypoint_name, - iroha_data_model::wasm::import::fn_names::$query_validating_object_fn_name, + export::$generated_entrypoint_name, + import::$query_validating_object_fn_name, ) })* $(fn_name if fn_name == stringify!($other_user_entrypoint_name) => $branch),* @@ -75,7 +88,7 @@ fn impl_validate_entrypoint( block.stmts.insert( 0, parse_quote!( - use ::iroha_validator::iroha_wasm::{ExecuteOnHost as _, QueryHost as _}; + use ::iroha_validator::smart_contract::{ExecuteOnHost as _, QueryHost as _}; ), ); @@ -93,14 +106,14 @@ fn impl_validate_entrypoint( /// # Memory safety /// /// This function transfers the ownership of allocated - /// [`Result`](::iroha_validator::iroha_wasm::data_model::validator::Result) + /// [`Result`](::iroha_validator::data_model::validator::Result) #[no_mangle] #[doc(hidden)] unsafe extern "C" fn #generated_entrypoint_ident() -> *const u8 { - let payload = ::iroha_validator::iroha_wasm::#get_validation_payload_fn_ident(); - let verdict: ::iroha_validator::iroha_wasm::data_model::validator::Result = + let payload = ::iroha_validator::#get_validation_payload_fn_ident(); + let verdict: ::iroha_validator::data_model::validator::Result = #fn_name(payload.authority, payload.to_validate, payload.block_height); - let bytes_box = ::core::mem::ManuallyDrop::new(::iroha_validator::iroha_wasm::encode_with_length_prefix(&verdict)); + let bytes_box = ::core::mem::ManuallyDrop::new(::iroha_validator::utils::encode_with_length_prefix(&verdict)); bytes_box.as_ptr() } @@ -128,10 +141,8 @@ fn impl_migrate_entrypoint(fn_item: syn::ItemFn) -> TokenStream { "Validator `migrate()` entrypoint must have `MigrationResult` return type" ); - let migrate_fn_name = syn::Ident::new( - iroha_data_model::wasm::export::fn_names::VALIDATOR_MIGRATE, - proc_macro2::Span::call_site(), - ); + let migrate_fn_name = + syn::Ident::new(export::VALIDATOR_MIGRATE, proc_macro2::Span::call_site()); quote! { /// Validator `permission_token_schema` entrypoint @@ -142,9 +153,9 @@ fn impl_migrate_entrypoint(fn_item: syn::ItemFn) -> TokenStream { #[no_mangle] #[doc(hidden)] unsafe extern "C" fn #migrate_fn_name() -> *const u8 { - let payload = ::iroha_validator::iroha_wasm::get_migrate_payload(); + let payload = ::iroha_validator::get_migrate_payload(); let res: ::iroha_validator::data_model::validator::MigrationResult = #fn_name(payload.block_height); - let bytes = ::core::mem::ManuallyDrop::new(::iroha_validator::iroha_wasm::encode_with_length_prefix(&res)); + let bytes = ::core::mem::ManuallyDrop::new(::iroha_validator::utils::encode_with_length_prefix(&res)); ::core::mem::ManuallyDrop::new(bytes).as_ptr() } diff --git a/wasm/validator/derive/src/lib.rs b/smart_contract/validator/derive/src/lib.rs similarity index 100% rename from wasm/validator/derive/src/lib.rs rename to smart_contract/validator/derive/src/lib.rs diff --git a/wasm/validator/derive/src/token.rs b/smart_contract/validator/derive/src/token.rs similarity index 84% rename from wasm/validator/derive/src/token.rs rename to smart_contract/validator/derive/src/token.rs index 38cc336641a..748797ee14f 100644 --- a/wasm/validator/derive/src/token.rs +++ b/smart_contract/validator/derive/src/token.rs @@ -25,10 +25,10 @@ fn impl_token(ident: &syn::Ident, generics: &syn::Generics) -> proc_macro2::Toke quote! { impl #impl_generics ::iroha_validator::permission::Token for #ident #ty_generics #where_clause { - fn is_owned_by(&self, account_id: &::iroha_validator::data_model::prelude::AccountId) -> bool { - let all_account_tokens: Vec = ::iroha_validator::iroha_wasm::debug::DebugExpectExt::dbg_expect( - ::iroha_validator::iroha_wasm::QueryHost::execute( - &::iroha_validator::iroha_wasm::data_model::prelude::FindPermissionTokensByAccountId::new( + fn is_owned_by(&self, account_id: &::iroha_validator::data_model::account::AccountId) -> bool { + let all_account_tokens: Vec = ::iroha_validator::smart_contract::debug::DebugExpectExt::dbg_expect( + ::iroha_validator::smart_contract::QueryHost::execute( + &::iroha_validator::data_model::query::permission::FindPermissionTokensByAccountId::new( account_id.clone(), ) ), @@ -58,7 +58,7 @@ fn impl_try_from_permission_token( fn try_from(token: ::iroha_validator::data_model::permission::PermissionToken) -> ::core::result::Result { if #token_id != *token.definition_id() { return Err(::iroha_validator::permission::PermissionTokenConversionError::Id( - ::alloc::borrow::ToOwned::to_owned(token.definition_id()) + ToOwned::to_owned(token.definition_id()) )); } ::serde_json::from_str::(token.payload()) diff --git a/wasm/validator/derive/src/validate.rs b/smart_contract/validator/derive/src/validate.rs similarity index 100% rename from wasm/validator/derive/src/validate.rs rename to smart_contract/validator/derive/src/validate.rs diff --git a/wasm/validator/src/default.rs b/smart_contract/validator/src/default.rs similarity index 99% rename from wasm/validator/src/default.rs rename to smart_contract/validator/src/default.rs index 2ad6a85a32b..cb74088286f 100644 --- a/wasm/validator/src/default.rs +++ b/smart_contract/validator/src/default.rs @@ -1,7 +1,7 @@ //! Definition of Iroha default validator and accompanying validation functions #![allow(missing_docs, clippy::missing_errors_doc)] -use alloc::{borrow::ToOwned as _, format, string::String}; +use alloc::{borrow::ToOwned, format, string::String}; pub use account::{ visit_burn_account_public_key, visit_mint_account_public_key, @@ -30,7 +30,6 @@ pub use trigger::{ }; pub use validator::visit_upgrade_validator; -use super::*; use crate::{permission, permission::Token as _, prelude::*}; macro_rules! evaluate_expr { @@ -1276,8 +1275,7 @@ pub mod role { deny!($validator, error); } }; - let role = Role::try_from(find_role_query_res) - .dbg_expect("Failed to convert `FindRoleByRoleId` query result to `Role`"); + let role = Role::try_from(find_role_query_res).unwrap(); for token in role.permissions() { macro_rules! visit_internal { @@ -1325,12 +1323,12 @@ pub mod role { let role = isi.object.inner(); for token in role.permissions() { - iroha_wasm::debug!(&format!("Checking `{token:?}`")); + iroha_smart_contract::debug!(&format!("Checking `{token:?}`")); macro_rules! try_from_token { ($token_ty:ty) => { - iroha_wasm::debug!(concat!("Trying `", stringify!($token_ty), "`")); + iroha_smart_contract::debug!(concat!("Trying `", stringify!($token_ty), "`")); if <$token_ty as TryFrom<_>>::try_from(token.clone()).is_ok() { - iroha_wasm::debug!("Success!"); + iroha_smart_contract::debug!("Success!"); // Continue because token can correspond to only one concrete token continue; } @@ -1592,7 +1590,7 @@ pub mod validator { pub fn visit_upgrade_validator( validator: &mut V, authority: &AccountId, - _isi: Upgrade, + _isi: Upgrade, ) { if is_genesis(validator) { pass!(validator); diff --git a/smart_contract/validator/src/lib.rs b/smart_contract/validator/src/lib.rs new file mode 100644 index 00000000000..e10a2d04465 --- /dev/null +++ b/smart_contract/validator/src/lib.rs @@ -0,0 +1,291 @@ +//! API for *Runtime Validators*. +#![no_std] +#![allow(unsafe_code)] + +extern crate alloc; +extern crate self as iroha_validator; + +use alloc::vec::Vec; + +pub use iroha_data_model as data_model; +use iroha_data_model::{ + permission::PermissionTokenId, validator::Result, visit::Visit, ValidationFail, +}; +#[cfg(not(test))] +use iroha_data_model::{prelude::*, smart_contract::payloads}; +pub use iroha_schema::MetaMap; +pub use iroha_smart_contract as smart_contract; +pub use iroha_smart_contract_utils::{debug, encode_with_length_prefix}; +#[cfg(not(test))] +use iroha_smart_contract_utils::{decode_with_length_prefix_from_raw, encode_and_execute}; + +pub mod default; +pub mod permission; + +pub mod utils { + //! Crate with utilities for implementing smart contract FFI + pub use iroha_smart_contract_utils::encode_with_length_prefix; +} + +pub mod log { + //! WASM logging utilities + pub use iroha_smart_contract_utils::{debug, error, event, info, log::*, trace, warn}; +} + +/// Get payload for `validate_transaction()` entrypoint. +/// +/// # Traps +/// +/// Host side will generate a trap if this function was called not from a +/// validator `validate_transaction()` entrypoint. +#[cfg(not(test))] +pub fn get_validate_transaction_payload() -> payloads::Validate { + // Safety: ownership of the returned result is transferred into `_decode_from_raw` + unsafe { decode_with_length_prefix_from_raw(host::get_validate_transaction_payload()) } +} + +/// Get payload for `validate_instruction()` entrypoint. +/// +/// # Traps +/// +/// Host side will generate a trap if this function was called not from a +/// validator `validate_instruction()` entrypoint. +#[cfg(not(test))] +pub fn get_validate_instruction_payload() -> payloads::Validate { + // Safety: ownership of the returned result is transferred into `_decode_from_raw` + unsafe { decode_with_length_prefix_from_raw(host::get_validate_instruction_payload()) } +} + +/// Get payload for `validate_query()` entrypoint. +/// +/// # Traps +/// +/// Host side will generate a trap if this function was called not from a +/// validator `validate_query()` entrypoint. +#[cfg(not(test))] +pub fn get_validate_query_payload() -> payloads::Validate { + // Safety: ownership of the returned result is transferred into `_decode_from_raw` + unsafe { decode_with_length_prefix_from_raw(host::get_validate_query_payload()) } +} + +/// Get payload for `migrate()` entrypoint. +/// +/// # Traps +/// +/// Host side will generate a trap if this function was called not from a +/// validator `migrate()` entrypoint. +#[cfg(not(test))] +pub fn get_migrate_payload() -> payloads::Migrate { + // Safety: ownership of the returned result is transferred into `_decode_from_raw` + unsafe { decode_with_length_prefix_from_raw(host::get_migrate_payload()) } +} + +/// Set new [`PermissionTokenSchema`]. +/// +/// # Errors +/// +/// - If execution on Iroha side failed +/// +/// # Traps +/// +/// Host side will generate a trap if this function was not called from a +/// validator's `migrate()` entrypoint. +#[cfg(not(test))] +pub fn set_permission_token_schema(schema: &data_model::permission::PermissionTokenSchema) { + // Safety: - ownership of the returned result is transferred into `_decode_from_raw` + unsafe { encode_and_execute(&schema, host::set_permission_token_schema) } +} + +#[cfg(not(test))] +mod host { + #[link(wasm_import_module = "iroha")] + extern "C" { + /// Get payload for `validate_transaction()` entrypoint. + /// + /// # Warning + /// + /// This function does transfer ownership of the result to the caller + pub(super) fn get_validate_transaction_payload() -> *const u8; + + /// Get payload for `validate_instruction()` entrypoint. + /// + /// # Warning + /// + /// This function does transfer ownership of the result to the caller + pub(super) fn get_validate_instruction_payload() -> *const u8; + + /// Get payload for `validate_query()` entrypoint. + /// + /// # Warning + /// + /// This function does transfer ownership of the result to the caller + pub(super) fn get_validate_query_payload() -> *const u8; + + /// Get payload for `migrate()` entrypoint. + /// + /// # Warning + /// + /// This function does transfer ownership of the result to the caller + pub(super) fn get_migrate_payload() -> *const u8; + + /// Set new [`PermissionTokenSchema`]. + pub(super) fn set_permission_token_schema(ptr: *const u8, len: usize); + } +} + +/// Shortcut for `return Ok(())`. +#[macro_export] +macro_rules! pass { + ($validator:ident) => {{ + #[cfg(debug_assertions)] + if let Err(_error) = $validator.verdict() { + unreachable!("Validator already denied"); + } + + return; + }}; +} + +/// Shortcut for `return Err(ValidationFail)`. +/// +/// Supports [`format!`](alloc::fmt::format) syntax as well as any expression returning [`String`](alloc::string::String). +#[macro_export] +macro_rules! deny { + ($validator:ident, $l:literal $(,)?) => {{ + #[cfg(debug_assertions)] + if let Err(_error) = $validator.verdict() { + unreachable!("Validator already denied"); + } + $validator.deny($crate::data_model::ValidationFail::NotPermitted( + ::alloc::fmt::format(::core::format_args!($l)), + )); + return; + }}; + ($validator:ident, $e:expr $(,)?) => {{ + #[cfg(debug_assertions)] + if let Err(_error) = $validator.verdict() { + unreachable!("Validator already denied"); + } + $validator.deny($e); + return; + }}; +} + +/// Macro to parse literal as a type. Panics if failed. +/// +/// # Example +/// +/// ```no_run +/// use iroha_validator::parse; +/// use iroha_data_model::prelude::*; +/// +/// let account_id = parse!("alice@wonderland" as AccountId); +/// ``` +#[macro_export] +macro_rules! parse { + ($l:literal as _) => { + compile_error!( + "Don't use `_` as a type in this macro, \ + otherwise panic message would be less informative" + ) + }; + ($l:literal as $t:ty) => { + $crate::debug::DebugExpectExt::dbg_expect( + $l.parse::<$t>(), + concat!("Failed to parse `", $l, "` as `", stringify!($t), "`"), + ) + }; +} + +/// Declare token types of current module. Use it with a full path to the token. +/// +/// Used to iterate over token types to validate `Grant` and `Revoke` instructions. +/// +/// +/// TODO: Replace with procedural macro. Example: +/// ``` +/// mod tokens { +/// use std::borrow::ToOwned; +/// +/// use iroha_schema::IntoSchema; +/// use iroha_validator_derive::{Token, ValidateGrantRevoke}; +/// use serde::{Deserialize, Serialize}; +/// +/// #[derive(Clone, PartialEq, Deserialize, Serialize, IntoSchema, Token, ValidateGrantRevoke)] +/// #[validate(iroha_validator::permission::OnlyGenesis)] +/// pub struct MyToken; +/// } +/// ``` +#[macro_export] +macro_rules! declare_tokens { + ($($token_ty:ty),+ $(,)?) => { + macro_rules! map_tokens { + ($callback:ident) => {$( + $callback!($token_ty) + );+} + } + + pub(crate) use map_tokens; + } +} + +/// Collection of all permission tokens defined by the validator +#[derive(Debug, Clone, Default)] +pub struct PermissionTokenSchema(Vec, MetaMap); + +impl PermissionTokenSchema { + /// Remove permission token from this collection + pub fn remove(&mut self) { + let to_remove = ::name(); + + if let Some(pos) = self.0.iter().position(|token_id| *token_id == to_remove) { + self.0.remove(pos); + ::remove_from_schema(&mut self.1); + } + } + + /// Insert new permission token into this collection + pub fn insert(&mut self) { + ::update_schema_map(&mut self.1); + self.0.push(::name()); + } + + /// Serializes schema into a JSON string representation + pub fn serialize(mut self) -> (Vec, alloc::string::String) { + self.0.sort(); + + ( + self.0, + serde_json::to_string(&self.1).expect("schema serialization must not fail"), + ) + } +} + +/// Validator of Iroha operations +pub trait Validate: Visit { + /// Validator verdict. + fn verdict(&self) -> &Result; + + /// Current block height. + fn block_height(&self) -> u64; + + /// Set validator verdict to deny + fn deny(&mut self, reason: ValidationFail); +} + +pub mod prelude { + //! Contains useful re-exports + + pub use alloc::vec::Vec; + + pub use iroha_data_model::{ + prelude::*, + validator::{MigrationError, MigrationResult, Result}, + visit::Visit, + ValidationFail, + }; + pub use iroha_smart_contract::{prelude::*, Context}; + pub use iroha_validator_derive::{entrypoint, Token, ValidateGrantRevoke}; + + pub use super::{declare_tokens, deny, pass, PermissionTokenSchema, Validate}; +} diff --git a/wasm/validator/src/permission.rs b/smart_contract/validator/src/permission.rs similarity index 99% rename from wasm/validator/src/permission.rs rename to smart_contract/validator/src/permission.rs index 6d6bb263f72..12cab95c2ce 100644 --- a/wasm/validator/src/permission.rs +++ b/smart_contract/validator/src/permission.rs @@ -3,6 +3,7 @@ use alloc::borrow::ToOwned as _; use iroha_schema::IntoSchema; +use iroha_smart_contract_utils::debug::DebugExpectExt as _; use serde::{de::DeserializeOwned, Serialize}; use crate::{data_model::prelude::*, prelude::*}; diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml deleted file mode 100644 index 71b4c307a13..00000000000 --- a/wasm/Cargo.toml +++ /dev/null @@ -1,207 +0,0 @@ -[workspace.package] -edition = "2021" -version = "2.0.0-pre-rc.19" -# TODO: teams are being deprecated update the authors URL -authors = ["Iroha 2 team "] - -license = "Apache-2.0" - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" - -[workspace] -resolver = "2" -members = [ - "derive", - "validator", - "validator/derive", - "trigger", - "trigger/derive", -] - -[workspace.dependencies] -iroha_data_model = { version = "=2.0.0-pre-rc.19", path = "../data_model", default-features = false } -syn = { version = "1", default-features = false, features = ["full", "extra-traits", "derive"] } -quote = "1.0" -proc-macro2 = "1.0.49" - -webassembly-test = "0.1.0" - -[workspace.lints] -rust.anonymous_parameters = "deny" - -# lower the priority to allow overriding later -clippy.pedantic = { level = "deny", priority = -1 } -clippy.all = { level = "deny", priority = -1 } -clippy.dbg_macro = "deny" - -# clippy.nursery = "deny" -clippy.debug_assert_with_mut_call = "deny" -clippy.derive_partial_eq_without_eq = "deny" -clippy.empty_line_after_outer_attr = "deny" -clippy.fallible_impl_from = "deny" -clippy.future_not_send = "deny" -clippy.iter_with_drain = "deny" -clippy.mutex_integer = "deny" -clippy.needless_collect = "deny" -clippy.path_buf_push_overwrite = "deny" -clippy.suboptimal_flops = "deny" -clippy.trailing_empty_array = "deny" -clippy.transmute_undefined_repr = "deny" -clippy.trivial_regex = "deny" -clippy.unused_peekable = "deny" -clippy.unused_rounding = "deny" - -rust.future_incompatible = "deny" -rust.missing_copy_implementations = "deny" -rust.missing_docs = "deny" -rust.nonstandard_style = "deny" -rust.private_doc_tests = "deny" -rust.rust_2018_idioms = "deny" -rust.trivial_casts = "deny" -rust.trivial_numeric_casts = "deny" -rust.unconditional_recursion = "deny" -rust.unsafe_code = "deny" -rust.unused = "deny" -rust.unused_import_braces = "deny" -rust.variant_size_differences = "deny" -rust.unused_tuple_struct_fields = "deny" -rust.explicit_outlives_requirements = "deny" -rust.non_ascii_idents = "deny" -# TODO: reenable -# rust.unreachable_pub = "deny" -# rust.unsafe_op_in_unsafe_fn = "deny" - -# These are up to personal taste. We don't want these to be enabled ever. -clippy.string_add = "allow" -clippy.as_conversions = "allow" -clippy.else_if_without_else = "allow" -clippy.enum_glob_use = "allow" -clippy.exhaustive_enums = "allow" -clippy.exhaustive_structs = "allow" -clippy.implicit_return = "allow" -clippy.inconsistent_struct_constructor = "allow" -clippy.indexing_slicing = "allow" -clippy.arithmetic_side_effects = "allow" -clippy.let_underscore_must_use = "allow" -clippy.match_wildcard_for_single_variants = "allow" -clippy.missing_docs_in_private_items = "allow" -clippy.module_name_repetitions = "allow" -clippy.shadow_reuse = "allow" -clippy.shadow_same = "allow" - -# These are normally decisions, which need to be audited by a human. -clippy.unwrap_in_result = "allow" -clippy.expect_used = "allow" -clippy.unreachable = "allow" -clippy.wildcard_enum_match_arm = "allow" -clippy.wildcard_imports = "allow" -# Our preferred style. -clippy.non-ascii-literal = "allow" -clippy.std_instead_of_core = "allow" - -# This lint could be useful in theory. The trade-off of making -# refactoring away from references difficult isn't worth it in all -# cases, so if it is enabled, it should be enabled locally. -clippy.pattern_type_mismatch = "allow" - -# Style guide. -clippy.mod-module-files = "allow" -clippy.separated-literal-suffix = "allow" -# Most trybuild code triggers a false-positive. - -# Not all public items should be inline. We only inline **trivial** functions. -clippy.missing_inline_in_public_items = "allow" - -# --- Re-enable candidates ----- - -# Lots of false-positives. -clippy.self-named-module-files = "allow" -clippy.manual_let_else = "allow" - -# We often need to shadow the name of the method to specialise. -# As soon as trait specialisation is stable we need to remove it. -clippy.same_name_method = "allow" -clippy.pub_use = "allow" - -# Style guide candidate. Explicitly converting the return value to -# () is good for refactoring, and if there is necessary -# processing of the data returned by a function, it should -# **really** be marked as #[must_use] -clippy.semicolon_if_nothing_returned = "allow" - -# This lint has way too many false-positives, so even enabling it -# as a warning is too much. Instead prefer adding explicit -# `#[deny]` directives -clippy.must_use_candidate = "allow" - -# Unstable and many false-positives -## https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn -clippy.missing_const_for_fn = "allow" - -# Too much affected code. Often impossible to apply suggestion on stable rust. -rust.elided_lifetimes_in_paths = "allow" - -# This lint produces a lot of false positives. Recommend local #[deny] directives -clippy.use_self = "allow" - -# We don't want to manually deny every `clippy.restriction.*` lint. -clippy.blanket-clippy-restriction-lints = "allow" - -# A lot of false-positive. -clippy.partial_pub_fields = "allow" - -# Should be enabled per trait impl rather than globally. -clippy.missing_trait_methods = "allow" - -# We allow this and deny `clippy.semicolon_inside_block`. -clippy.semicolon_outside_block = "allow" - -# It is debatable whether it's actually easier to read, -# additionally, not all patterns are covered by the inlined syntax -clippy.uninlined_format_args = "allow" - -rust.unknown_lints = "warn" -# these lints were duplicated, with `allow` taking precedence -# clippy.inconsistent_struct_constructor = "warn" -# clippy.match_wildcard_for_single_variants = "warn" -# clippy.arithmetic_side_effects = "warn" -clippy.option_if_let_else = "warn" -clippy.or_fun_call = "warn" -clippy.redundant_pub_crate = "warn" -clippy.string_lit_as_bytes = "warn" -clippy.suspicious_operation_groupings = "warn" -clippy.useless_let_if_seq = "warn" - -# unstable -# rust.non_exhaustive_omitted_patterns = "warn" - -rust.single_use_lifetimes = "warn" -rust.unused_lifetimes = "warn" - -[package] -name = "iroha_wasm" - -version.workspace = true -authors.workspace = true -edition.workspace = true - -license.workspace = true - -[features] -# Enables debugging tools such as `dbg()` and `DebugUnwrapExt` -debug = [] - -[dependencies] -iroha_data_model.workspace = true -iroha_wasm_derive = { version = "=2.0.0-pre-rc.19", path = "derive" } - -parity-scale-codec = { version = "3.1.5", default-features = false } -lol_alloc = "0.4.0" - -[dev-dependencies] -webassembly-test.workspace = true - diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs deleted file mode 100644 index fb97b6bac78..00000000000 --- a/wasm/src/lib.rs +++ /dev/null @@ -1,495 +0,0 @@ -//! API which simplifies writing of smartcontracts -#![no_std] -// Required because of `unsafe` code and `no_mangle` use -#![allow(unsafe_code)] - -#[cfg(all(not(test), not(target_pointer_width = "32")))] -compile_error!("Target architectures other then 32-bit are not supported"); - -#[cfg(all(not(test), not(all(target_arch = "wasm32", target_os = "unknown"))))] -compile_error!("Targets other then wasm32-unknown-unknown are not supported"); - -extern crate alloc; - -use alloc::{boxed::Box, collections::BTreeMap, format, vec::Vec}; -use core::ops::RangeFrom; - -#[cfg(not(test))] -use data_model::wasm::payloads; -use data_model::{ - isi::Instruction, - prelude::*, - query::{Query, QueryBox}, -}; -use debug::DebugExpectExt as _; -pub use iroha_data_model as data_model; -pub use iroha_wasm_derive::main; -use lol_alloc::{FreeListAllocator, LockedAllocator}; -use parity_scale_codec::{DecodeAll, Encode}; - -pub mod debug; -pub mod log; - -#[global_allocator] -static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); - -#[no_mangle] -extern "C" fn _iroha_wasm_alloc(len: usize) -> *const u8 { - if len == 0 { - debug::dbg_panic("Cannot allocate 0 bytes"); - } - let layout = core::alloc::Layout::array::(len).dbg_expect("Cannot allocate layout"); - // Safety: safe because `layout` is guaranteed to have non-zero size - unsafe { alloc::alloc::alloc_zeroed(layout) } -} - -/// # Safety -/// - `offset` is a pointer to a `[u8; len]` which is allocated in the WASM memory. -/// - This function can't call destructor of the encoded object. -#[no_mangle] -unsafe extern "C" fn _iroha_wasm_dealloc(offset: *mut u8, len: usize) { - let _box = Box::from_raw(core::slice::from_raw_parts_mut(offset, len)); -} - -/// Implementing instructions can be executed on the host -pub trait ExecuteOnHost: Instruction { - /// Execute instruction on the host - /// - /// # Errors - /// - /// - If instruction validation failed - /// - If instruction execution failed - fn execute(&self) -> Result<(), ValidationFail>; -} - -/// Implementing queries can be executed on the host -pub trait QueryHost: Query { - /// Execute query on the host - /// - /// # Errors - /// - /// - If query validation failed - /// - If query execution failed - fn execute(&self) -> Result; -} - -// TODO: Remove the Clone bound. It can be done by custom serialization to InstructionExpr -impl ExecuteOnHost for I { - fn execute(&self) -> Result<(), ValidationFail> { - #[cfg(not(test))] - use host::execute_instruction as host_execute_instruction; - #[cfg(test)] - use tests::_iroha_wasm_execute_instruction_mock as host_execute_instruction; - - // TODO: Redundant conversion into `InstructionExpr` - let isi_box: InstructionExpr = self.clone().into(); - // Safety: `host_execute_instruction` doesn't take ownership of it's pointer parameter - unsafe { - decode_with_length_prefix_from_raw(encode_and_execute( - &isi_box, - host_execute_instruction, - )) - } - } -} - -// TODO: Remove the Clone bound. It can be done by custom serialization/deserialization to QueryBox -impl + Encode + Clone> QueryHost for Q -where - Q::Output: DecodeAll, - >::Error: core::fmt::Debug, -{ - fn execute(&self) -> Result { - #[cfg(not(test))] - use host::execute_query as host_execute_query; - #[cfg(test)] - use tests::_iroha_wasm_execute_query_mock as host_execute_query; - - // TODO: Redundant conversion into `QueryBox` - let query_box: QueryBox = self.clone().into(); - // Safety: - `host_execute_query` doesn't take ownership of it's pointer parameter - // - ownership of the returned result is transferred into `_decode_from_raw` - let res: Result = unsafe { - decode_with_length_prefix_from_raw(encode_and_execute(&query_box, host_execute_query)) - }; - - res.map(|value| value.try_into().expect("Query returned invalid type")) - } -} - -/// World state view of the host -#[derive(Debug, Clone, Copy)] -pub struct Host; - -impl iroha_data_model::evaluate::ExpressionEvaluator for Host { - fn evaluate( - &self, - expression: &E, - ) -> Result { - expression.evaluate(&Context::new()) - } -} - -/// Context of expression evaluation -#[derive(Clone, Default)] -#[repr(transparent)] -pub struct Context { - values: BTreeMap, -} - -impl Context { - /// Create new [`Self`] - pub fn new() -> Self { - Self { - values: BTreeMap::new(), - } - } -} - -impl iroha_data_model::evaluate::Context for Context { - fn query(&self, query: &QueryBox) -> Result { - query.execute() - } - - fn get(&self, name: &Name) -> Option<&Value> { - self.values.get(name) - } - - fn update(&mut self, other: impl IntoIterator) { - self.values.extend(other) - } -} - -/// Get payload for smart contract `main()` entrypoint. -#[cfg(not(test))] -pub fn get_smart_contract_payload() -> payloads::SmartContract { - // Safety: ownership of the returned result is transferred into `_decode_from_raw` - unsafe { decode_with_length_prefix_from_raw(host::get_smart_contract_payload()) } -} - -/// Get payload for trigger `main()` entrypoint. -#[cfg(not(test))] -pub fn get_trigger_payload() -> payloads::Trigger { - // Safety: ownership of the returned result is transferred into `_decode_from_raw` - unsafe { decode_with_length_prefix_from_raw(host::get_trigger_payload()) } -} - -/// Get payload for `validate_transaction()` entrypoint. -/// -/// # Traps -/// -/// Host side will generate a trap if this function was called not from a -/// validator `validate_transaction()` entrypoint. -#[cfg(not(test))] -pub fn get_validate_transaction_payload() -> payloads::ValidateTransaction { - // Safety: ownership of the returned result is transferred into `_decode_from_raw` - unsafe { decode_with_length_prefix_from_raw(host::get_validate_transaction_payload()) } -} - -/// Get payload for `validate_instruction()` entrypoint. -/// -/// # Traps -/// -/// Host side will generate a trap if this function was called not from a -/// validator `validate_instruction()` entrypoint. -#[cfg(not(test))] -pub fn get_validate_instruction_payload() -> payloads::ValidateInstruction { - // Safety: ownership of the returned result is transferred into `_decode_from_raw` - unsafe { decode_with_length_prefix_from_raw(host::get_validate_instruction_payload()) } -} - -/// Get payload for `validate_query()` entrypoint. -/// -/// # Traps -/// -/// Host side will generate a trap if this function was called not from a -/// validator `validate_query()` entrypoint. -#[cfg(not(test))] -pub fn get_validate_query_payload() -> payloads::ValidateQuery { - // Safety: ownership of the returned result is transferred into `_decode_from_raw` - unsafe { decode_with_length_prefix_from_raw(host::get_validate_query_payload()) } -} - -/// Get payload for `migrate()` entrypoint. -/// -/// # Traps -/// -/// Host side will generate a trap if this function was called not from a -/// validator `migrate()` entrypoint. -#[cfg(not(test))] -pub fn get_migrate_payload() -> payloads::Migrate { - // Safety: ownership of the returned result is transferred into `_decode_from_raw` - unsafe { decode_with_length_prefix_from_raw(host::get_migrate_payload()) } -} - -/// Set new [`PermissionTokenSchema`]. -/// -/// # Errors -/// -/// - If execution on Iroha side failed -/// -/// # Traps -/// -/// Host side will generate a trap if this function was not called from a -/// validator's `migrate()` entrypoint. -#[cfg(not(test))] -pub fn set_permission_token_schema(schema: &data_model::permission::PermissionTokenSchema) { - // Safety: - ownership of the returned result is transferred into `_decode_from_raw` - unsafe { encode_and_execute(&schema, host::set_permission_token_schema) } -} - -#[cfg(not(test))] -mod host { - #[link(wasm_import_module = "iroha")] - extern "C" { - /// Execute encoded query by providing offset and length - /// into WebAssembly's linear memory where query is stored - /// - /// # Warning - /// - /// This function doesn't take ownership of the provided allocation - /// but it does transfer ownership of the result to the caller - pub(super) fn execute_query(ptr: *const u8, len: usize) -> *const u8; - - /// Execute encoded instruction by providing offset and length - /// into WebAssembly's linear memory where instruction is stored - /// - /// # Warning - /// - /// This function doesn't take ownership of the provided allocation - /// but it does transfer ownership of the result to the caller - pub(super) fn execute_instruction(ptr: *const u8, len: usize) -> *const u8; - - /// Get payload for smart contract `main()` entrypoint. - /// - /// # Warning - /// - /// This function does transfer ownership of the result to the caller - pub(super) fn get_smart_contract_payload() -> *const u8; - - /// Get payload for trigger `main()` entrypoint. - /// - /// # Warning - /// - /// This function does transfer ownership of the result to the caller - pub(super) fn get_trigger_payload() -> *const u8; - - /// Get payload for `validate_transaction()` entrypoint. - /// - /// # Warning - /// - /// This function does transfer ownership of the result to the caller - pub(super) fn get_validate_transaction_payload() -> *const u8; - - /// Get payload for `validate_instruction()` entrypoint. - /// - /// # Warning - /// - /// This function does transfer ownership of the result to the caller - pub(super) fn get_validate_instruction_payload() -> *const u8; - - /// Get payload for `validate_query()` entrypoint. - /// - /// # Warning - /// - /// This function does transfer ownership of the result to the caller - pub(super) fn get_validate_query_payload() -> *const u8; - - /// Get payload for `migrate()` entrypoint. - /// - /// # Warning - /// - /// This function does transfer ownership of the result to the caller - pub(super) fn get_migrate_payload() -> *const u8; - - /// Set new [`PermissionTokenSchema`]. - pub(super) fn set_permission_token_schema(ptr: *const u8, len: usize); - } -} - -/// Decode the object from given pointer where first element is the size of the object -/// following it. This can be considered a custom encoding format. -/// -/// # Warning -/// -/// This method takes ownership of the given pointer -/// -/// # Safety -/// -/// It's safe to call this function as long as it's safe to construct, from the given -/// pointer, byte array of prefix length and `Box<[u8]>` containing the encoded object -unsafe fn decode_with_length_prefix_from_raw(ptr: *const u8) -> T { - let len_size_bytes = core::mem::size_of::(); - - let len = usize::from_le_bytes( - core::slice::from_raw_parts(ptr, len_size_bytes) - .try_into() - .expect("Prefix length size(bytes) incorrect. This is a bug."), - ); - - _decode_from_raw_in_range(ptr, len, len_size_bytes..) -} - -/// Decode the object from given pointer and length -/// -/// # Warning -/// -/// This method takes ownership of the given pointer -/// -/// # Safety -/// -/// It's safe to call this function as long as it's safe to construct, from the given -/// pointer, `Box<[u8]>` containing the encoded object -unsafe fn _decode_from_raw(ptr: *const u8, len: usize) -> T { - _decode_from_raw_in_range(ptr, len, 0..) -} - -/// Decode the object from given pointer and length in the given range -/// -/// # Warning -/// -/// This method takes ownership of the given pointer -/// -/// # Safety -/// -/// It's safe to call this function as long as it's safe to construct, from the given -/// pointer, `Box<[u8]>` containing the encoded object -unsafe fn _decode_from_raw_in_range( - ptr: *const u8, - len: usize, - range: RangeFrom, -) -> T { - let bytes = Box::from_raw(core::slice::from_raw_parts_mut(ptr.cast_mut(), len)); - - #[allow(clippy::expect_fun_call)] - T::decode_all(&mut &bytes[range]).expect( - format!( - "Decoding of {} failed. This is a bug", - core::any::type_name::() - ) - .as_str(), - ) -} - -/// Encode the given object and call the given function with the pointer and length of the allocation -/// -/// # Warning -/// -/// Ownership of the returned allocation is transfered to the caller -/// -/// # Safety -/// -/// The given function must not take ownership of the pointer argument -unsafe fn encode_and_execute( - obj: &T, - fun: unsafe extern "C" fn(*const u8, usize) -> O, -) -> O { - // NOTE: It's imperative that encoded object is stored on the heap - // because heap corresponds to linear memory when compiled to wasm - let bytes = obj.encode(); - - fun(bytes.as_ptr(), bytes.len()) -} - -/// Encode the given `val` as a vector of bytes with the size of the object at the beginning -// -// TODO: Write a separate crate for codec/protocol between Iroha and smartcontract -pub fn encode_with_length_prefix(val: &T) -> Box<[u8]> { - let len_size_bytes = core::mem::size_of::(); - - let mut r = Vec::with_capacity( - len_size_bytes - .checked_add(val.size_hint()) - .dbg_expect("Overflow during length computation"), - ); - - // Reserve space for length - r.resize(len_size_bytes, 0); - val.encode_to(&mut r); - - // Store length of the whole vector as byte array at the beginning of the vec - let len = r.len(); - r[..len_size_bytes].copy_from_slice(&len.to_le_bytes()); - - r.into_boxed_slice() -} - -/// Most used items -pub mod prelude { - pub use crate::{debug::*, ExecuteOnHost, QueryHost}; -} - -#[cfg(test)] -mod tests { - #![allow(clippy::restriction)] - #![allow(clippy::pedantic)] - - use core::{mem::ManuallyDrop, slice}; - - use webassembly_test::webassembly_test; - - use super::*; - - const QUERY_RESULT: Result = - Ok(Value::Numeric(NumericValue::U32(1234_u32))); - const ISI_RESULT: Result<(), ValidationFail> = Ok(()); - const EXPRESSION_RESULT: NumericValue = NumericValue::U32(5_u32); - - fn get_test_instruction() -> InstructionExpr { - let new_account_id = "mad_hatter@wonderland".parse().expect("Valid"); - let register_isi = RegisterExpr::new(Account::new(new_account_id, [])); - - register_isi.into() - } - - fn get_test_query() -> QueryBox { - let account_id: AccountId = "alice@wonderland".parse().expect("Valid"); - FindAccountById::new(account_id).into() - } - - fn get_test_expression() -> EvaluatesTo { - Add::new(2_u32, 3_u32).into() - } - - #[no_mangle] - pub unsafe extern "C" fn _iroha_wasm_execute_instruction_mock( - ptr: *const u8, - len: usize, - ) -> *const u8 { - let bytes = slice::from_raw_parts(ptr, len); - let instruction = InstructionExpr::decode_all(&mut &*bytes); - assert_eq!(get_test_instruction(), instruction.unwrap()); - - ManuallyDrop::new(encode_with_length_prefix(&ISI_RESULT)).as_ptr() - } - - #[no_mangle] - pub unsafe extern "C" fn _iroha_wasm_execute_query_mock( - ptr: *const u8, - len: usize, - ) -> *const u8 { - let bytes = slice::from_raw_parts(ptr, len); - let query = QueryBox::decode_all(&mut &*bytes).unwrap(); - assert_eq!(query, get_test_query()); - - ManuallyDrop::new(encode_with_length_prefix(&QUERY_RESULT)).as_ptr() - } - - #[webassembly_test] - fn execute_instruction() { - get_test_instruction().execute().unwrap(); - } - - #[webassembly_test] - fn execute_query() { - assert_eq!(get_test_query().execute(), QUERY_RESULT); - } - - #[webassembly_test] - fn evaluate_expression() { - assert_eq!( - get_test_expression().evaluate(&Context::new()), - Ok(EXPRESSION_RESULT) - ); - } -} diff --git a/wasm/trigger/src/lib.rs b/wasm/trigger/src/lib.rs deleted file mode 100644 index 5915f89034f..00000000000 --- a/wasm/trigger/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Iroha Trigger Rust SDK - -#![no_std] - -pub use iroha_trigger_derive::main; -pub use iroha_wasm::{self, data_model, *}; - -pub mod prelude { - //! Common imports used by triggers - - pub use iroha_trigger_derive::main; - pub use iroha_wasm::{data_model::prelude::*, prelude::*}; -} diff --git a/wasm/validator/Cargo.toml b/wasm/validator/Cargo.toml deleted file mode 100644 index e9454e6c78a..00000000000 --- a/wasm/validator/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "iroha_validator" - -version.workspace = true -authors.workspace = true -edition.workspace = true -license.workspace = true - -[lints] -workspace = true - -[features] -# Enables debugging tools such as `dbg()` and `DebugUnwrapExt` -debug = ["iroha_wasm/debug"] - -[dependencies] -iroha_wasm = { version = "2.0.0-pre-rc.19", path = ".." } -iroha_schema = { path = "../../schema", version = "=2.0.0-pre-rc.19" } -iroha_validator_derive = { version = "2.0.0-pre-rc.19", path = "derive" } - -serde = { version = "1.0.151", default-features = false } -serde_json = { version = "1.0.91", default-features = false } - -[dev-dependencies] -webassembly-test.workspace = true diff --git a/wasm/validator/src/lib.rs b/wasm/validator/src/lib.rs deleted file mode 100644 index 348d8173f66..00000000000 --- a/wasm/validator/src/lib.rs +++ /dev/null @@ -1,170 +0,0 @@ -//! API for *Runtime Validators*. -#![no_std] - -extern crate alloc; -extern crate self as iroha_validator; - -use alloc::vec::Vec; - -pub use iroha_schema::MetaMap; -use iroha_wasm::data_model::{ - permission::PermissionTokenId, validator::Result, visit::Visit, ValidationFail, -}; -pub use iroha_wasm::{self, data_model}; - -pub mod default; -pub mod permission; - -/// Shortcut for `return Ok(())`. -#[macro_export] -macro_rules! pass { - ($validator:ident) => {{ - #[cfg(debug_assertions)] - if let Err(_error) = $validator.verdict() { - unreachable!("Validator already denied"); - } - - return; - }}; -} - -/// Shortcut for `return Err(ValidationFail)`. -/// -/// Supports [`format!`](alloc::fmt::format) syntax as well as any expression returning [`String`](alloc::string::String). -#[macro_export] -macro_rules! deny { - ($validator:ident, $l:literal $(,)?) => {{ - #[cfg(debug_assertions)] - if let Err(_error) = $validator.verdict() { - unreachable!("Validator already denied"); - } - $validator.deny(::iroha_validator::data_model::ValidationFail::NotPermitted( - ::alloc::fmt::format(::core::format_args!($l)), - )); - return; - }}; - ($validator:ident, $e:expr $(,)?) => {{ - #[cfg(debug_assertions)] - if let Err(_error) = $validator.verdict() { - unreachable!("Validator already denied"); - } - $validator.deny($e); - return; - }}; -} - -/// Macro to parse literal as a type. Panics if failed. -/// -/// # Example -/// -/// ```no_run -/// use iroha_wasm::parse; -/// use data_model::prelude::*; -/// -/// let account_id = parse!("alice@wonderland" as AccountId); -/// ``` -#[macro_export] -macro_rules! parse { - ($l:literal as _) => { - compile_error!( - "Don't use `_` as a type in this macro, \ - otherwise panic message would be less informative" - ) - }; - ($l:literal as $t:ty) => { - $crate::iroha_wasm::debug::DebugExpectExt::dbg_expect( - $l.parse::<$t>(), - concat!("Failed to parse `", $l, "` as `", stringify!($t), "`"), - ) - }; -} - -/// Declare token types of current module. Use it with a full path to the token. -/// -/// Used to iterate over token types to validate `Grant` and `Revoke` instructions. -/// -/// -/// TODO: Replace with procedural macro. Example: -/// ``` -/// #[tokens(path = "crate::current_module")] -/// mod tokens { -/// #[derive(Token, ...)] -/// pub struct MyToken; -/// } -/// ``` -#[macro_export] -macro_rules! declare_tokens { - ($($token_ty:ty),+ $(,)?) => { - macro_rules! map_tokens { - ($callback:ident) => {$( - $callback!($token_ty) - );+} - } - - pub(crate) use map_tokens; - } -} - -/// Collection of all permission tokens defined by the validator -#[derive(Debug, Clone, Default)] -pub struct PermissionTokenSchema(Vec, MetaMap); - -impl PermissionTokenSchema { - /// Remove permission token from this collection - pub fn remove(&mut self) { - let to_remove = ::name(); - - if let Some(pos) = self.0.iter().position(|token_id| *token_id == to_remove) { - self.0.remove(pos); - ::remove_from_schema(&mut self.1); - } - } - - /// Insert new permission token into this collection - pub fn insert(&mut self) { - ::update_schema_map(&mut self.1); - self.0.push(::name()); - } - - /// Serializes schema into a JSON string representation - pub fn serialize(mut self) -> (Vec, alloc::string::String) { - self.0.sort(); - - ( - self.0, - serde_json::to_string(&self.1).expect("schema serialization must not fail"), - ) - } -} - -/// Validator of Iroha operations -pub trait Validate: Visit { - /// Validator verdict. - fn verdict(&self) -> &Result; - - /// Current block height. - fn block_height(&self) -> u64; - - /// Set validator verdict to deny - fn deny(&mut self, reason: ValidationFail); -} - -pub mod prelude { - //! Contains useful re-exports - - pub use alloc::vec::Vec; - - pub use iroha_validator_derive::{entrypoint, Token, ValidateGrantRevoke}; - pub use iroha_wasm::{ - data_model::{ - prelude::*, - validator::{MigrationError, MigrationResult, Result}, - visit::Visit, - ValidationFail, - }, - prelude::*, - Context, - }; - - pub use super::{declare_tokens, deny, pass, PermissionTokenSchema, Validate}; -} diff --git a/wasm_codec/src/lib.rs b/wasm_codec/src/lib.rs index 9c77ab201c0..26b80774efd 100644 --- a/wasm_codec/src/lib.rs +++ b/wasm_codec/src/lib.rs @@ -53,7 +53,8 @@ pub fn decode_from_memory( /// /// - Failed to decode object /// - Failed to call `dealloc_fn` -#[allow(clippy::expect_used, clippy::unwrap_in_result)] +// NOTE: Panic is predicated by implementation not user input +#[allow(clippy::missing_panics_doc)] pub fn decode_with_length_prefix_from_memory< C: wasmtime::AsContextMut, T: DecodeAll + std::fmt::Debug, @@ -92,6 +93,8 @@ pub fn decode_with_length_prefix_from_memory< /// /// - If failed to call `alloc_fn` /// - If failed to write into the `memory` +// NOTE: Panic is predicated by implementation not user input +#[allow(clippy::missing_panics_doc)] pub fn encode_into_memory( obj: &T, memory: &wasmtime::Memory, @@ -123,10 +126,12 @@ pub fn encode_into_memory( /// `WebAssembly` it's not possible to return two values from a wasm function without some /// shenanignas. In those cases, only one value is sent which is pointer to the allocation /// with the first element being the length of the encoded object following it. +// NOTE: Panic is predicated by implementation not user input +#[allow(clippy::missing_panics_doc)] pub fn encode_with_length_prefix(obj: &T) -> Vec { // Compile-time size check #[allow(clippy::let_unit_value)] - let _ = SizeChecker::::RESULT; + let () = SizeChecker::::RESULT; let len_size_bytes = core::mem::size_of::(); From 2615b589aed7cf9ea7e16dbd5b0111bc735ba04d Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Thu, 5 Oct 2023 09:47:01 +0300 Subject: [PATCH 41/55] [fix] #3953: Fix `RemoveKeyValue` for `Domain` Signed-off-by: Shanin Roman --- core/src/smartcontracts/isi/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index ba59338c9fa..4c94e5e2e76 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -307,6 +307,9 @@ impl Execute for RemoveKeyValueExpr { IdBox::AccountId(object_id) => { RemoveKeyValue:: { object_id, key }.execute(authority, wsv) } + IdBox::DomainId(object_id) => { + RemoveKeyValue:: { object_id, key }.execute(authority, wsv) + } _ => Err(Error::Evaluate(InstructionType::RemoveKeyValue.into())), } } From de86914ad0d564fbacd592f309cf7ce8cd52e49f Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Thu, 5 Oct 2023 11:41:30 +0300 Subject: [PATCH 42/55] [fix] #3932: Fix transfer `AssetDefinition` Signed-off-by: Shanin Roman --- client/tests/integration/asset.rs | 34 +++++++++++ .../validator_with_admin/src/lib.rs | 2 +- .../validator_with_custom_token/src/lib.rs | 2 +- .../validator_with_migration_fail/src/lib.rs | 2 +- configs/peer/validator.wasm | Bin 487587 -> 489615 bytes core/src/smartcontracts/isi/account.rs | 6 +- core/src/smartcontracts/isi/mod.rs | 56 +++++++++++------- data_model/src/visit.rs | 31 ++++++---- default_validator/src/lib.rs | 2 +- smart_contract/validator/src/default.rs | 4 +- 10 files changed, 97 insertions(+), 42 deletions(-) diff --git a/client/tests/integration/asset.rs b/client/tests/integration/asset.rs index 81ebfb7c17f..775b9bcc137 100644 --- a/client/tests/integration/asset.rs +++ b/client/tests/integration/asset.rs @@ -393,6 +393,40 @@ fn find_rate_and_make_exchange_isi_should_succeed() { assert_eq!(expected_buyer_btc, buyer_btc_quantity); } +#[test] +fn transfer_asset_definition() { + let (_rt, _peer, test_client) = ::new().with_port(11_060).start_with_runtime(); + wait_for_genesis_committed(&[test_client.clone()], 0); + + let alice_id: AccountId = "alice@wonderland".parse().expect("Valid."); + let bob_id: AccountId = "bob@wonderland".parse().expect("Valid."); + let asset_definition_id: AssetDefinitionId = "asset#wonderland".parse().expect("Valid"); + + test_client + .submit_blocking(RegisterExpr::new(AssetDefinition::quantity( + asset_definition_id.clone(), + ))) + .expect("Failed to submit transaction"); + + let asset_definition = test_client + .request(FindAssetDefinitionById::new(asset_definition_id.clone())) + .expect("Failed to execute Iroha Query"); + assert_eq!(asset_definition.owned_by(), &alice_id); + + test_client + .submit_blocking(TransferExpr::new( + alice_id, + asset_definition_id.clone(), + bob_id.clone(), + )) + .expect("Failed to submit transaction"); + + let asset_definition = test_client + .request(FindAssetDefinitionById::new(asset_definition_id)) + .expect("Failed to execute Iroha Query"); + assert_eq!(asset_definition.owned_by(), &bob_id); +} + fn account_id_new(account_name: &str, account_domain: &str) -> AccountId { AccountId::new( account_name.parse().expect("Valid"), diff --git a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs index 8c68022219d..1c40e04d70f 100644 --- a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs @@ -88,7 +88,7 @@ impl Visit for Validator { // AssetDefinition validation visit_unregister_asset_definition(Unregister), - visit_transfer_asset_definition(Transfer), + visit_transfer_asset_definition(Transfer), visit_set_asset_definition_key_value(SetKeyValue), visit_remove_asset_definition_key_value(RemoveKeyValue), diff --git a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs index 30a6e6d7873..1954fc479dc 100644 --- a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs @@ -239,7 +239,7 @@ impl Visit for Validator { // AssetDefinition validation visit_unregister_asset_definition(Unregister), - visit_transfer_asset_definition(Transfer), + visit_transfer_asset_definition(Transfer), visit_set_asset_definition_key_value(SetKeyValue), visit_remove_asset_definition_key_value(RemoveKeyValue), diff --git a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs index 9bbf0ff22ff..b8ba577399f 100644 --- a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs @@ -93,7 +93,7 @@ impl Visit for Validator { // AssetDefinition validation visit_unregister_asset_definition(Unregister), - visit_transfer_asset_definition(Transfer), + visit_transfer_asset_definition(Transfer), visit_set_asset_definition_key_value(SetKeyValue), visit_remove_asset_definition_key_value(RemoveKeyValue), diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index 744cbc09a101a2f680e5e393795c4fddd802bdf2..72ed8b4e5d70e390f611b51959e63e4535942e92 100644 GIT binary patch delta 171700 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 DH?4vW delta 169231 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%0DRUoIE50T15a(^My7vQrFJciHu#jwgmdS7VH z^1@URD-(vjZz|40LoK^z&1syVoAR#&LC&{I!HX1Jt>DE9u2FEUg6ph`RdSIcutdR2 z6)}Tfz@) z_zPTGqC2R0yL33D!bua}jgs(44v3`z7DZA-)iL(-zY) zEqS6aSd-i-$;Gb`o0rp)zOTD1rlsI9!$--AdG206(v5nEA%&iSZqFo5) zz3vYox7Zi|o?B%D=;;$A|wR6)Ys?q}Rb2{KJ z3}S)P9YqdfBdC(Qjl)SC3LIHM4`;lCYH(v86?d$pS>o14Y7h%2QnnDebf)NRqyn*T zB_+grjc`1)K#(64&vFg^k?}?a|46~tD)>4DZ&L8}3ci77MLEM86@kqPzDdDb6nwLS zZ&C2A3ck&Xy^>sjt%|^p6)Y6IO~JP-c)NmsqToCF6vCYfzDvP(D|kS`_bB+M3cgpt z%{vsreG0xGxXHP)-l3;`C6165@L>>m9a_|Zt~_+B;6dCju%RC%JM*sGCVI#^J#{?+ zw-G|@zjX}x4sb&O+bxF{akv}ccysT1VHHiaHd`#4*4mBj(ooW5=DNeZ7#4})(#3&p zFwn>fA}0@J>b!2pI(FJ(d<-2@q`a8UfdgVhGc9*ib>pTCO39;}XH#Cf9zZRvppQaa z41R@MMq8V4II$a~0+4RNd#t#s4M*v=)pT*j96zqJfc~{`uck=m6M)kJqki%3YHH8O z3*aUR@F${n4SDQ0rr;X9*&r9r+F^}kjYsmu56=C_K$(tUfhBAWKO%l&1p5H z?R3-3%qzl4`O>hs%S{_Ivm7px-9#BV6O5GyeEinbX<~|pwmLz)Lzl5Q>$%5uXskMa_a};OP!jAJK}ar zp3rpY^mouaTRbiv>Yxj3`{UwJ2bJ4SNrs8V|2fDS|tfW~W5K<{NY1QZ)&%Q4W|V;PNw zx`(J3l(@o|4SMpd#tcb{)Eu4rkb&-zauRX>!KVjmgp-7avBc zBCG$V=PX&)HTe62TSRe;rrG;%W&-vXJ8nVbqv7I}7!~c>9;4CtztQ7Vnm-)baY%0u oIeuV~-7<)96yX@cC*rjp+@k9e)Jxxr1#uc@yKS4eBu*vY0c5=)mjD0& diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index db01e02b787..bdf3f476e10 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -199,13 +199,13 @@ pub mod isi { } } - impl Execute for Transfer { + impl Execute for Transfer { fn execute(self, _authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { - wsv.asset_definition_mut(&self.object.id)?.owned_by = self.destination_id.clone(); + wsv.asset_definition_mut(&self.object)?.owned_by = self.destination_id.clone(); wsv.emit_events(Some(AssetDefinitionEvent::OwnerChanged( AssetDefinitionOwnerChanged { - asset_definition_id: self.object.id, + asset_definition_id: self.object, new_owner: self.destination_id, }, ))); diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index 4c94e5e2e76..a143d5b7ae2 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -222,32 +222,44 @@ impl Execute for BurnExpr { impl Execute for TransferExpr { #[iroha_logger::log(name = "transfer", skip_all, fields(from, to))] fn execute(self, authority: &AccountId, wsv: &mut WorldStateView) -> Result<(), Error> { - let (IdBox::AssetId(source_id), IdBox::AccountId(destination_id)) = ( - wsv.evaluate(&self.source_id)?, - wsv.evaluate(&self.destination_id)?, - ) else { - return Err(Error::Evaluate(InstructionType::Transfer.into())); - }; - + let source_id = wsv.evaluate(&self.source_id)?; + let destination_id = wsv.evaluate(&self.destination_id)?; let object = wsv.evaluate(&self.object)?; + iroha_logger::trace!(%object, %authority); Span::current().record("from", source_id.to_string()); Span::current().record("to", destination_id.to_string()); - iroha_logger::trace!(%object, %authority); - match object { - Value::Numeric(NumericValue::U32(object)) => Transfer { - source_id, - object, - destination_id, - } - .execute(authority, wsv), - Value::Numeric(NumericValue::U128(object)) => Transfer { - source_id, - object, - destination_id, - } - .execute(authority, wsv), - Value::Numeric(NumericValue::Fixed(object)) => Transfer { + match (source_id, object, destination_id) { + ( + IdBox::AssetId(source_id), + Value::Numeric(value), + IdBox::AccountId(destination_id), + ) => match value { + NumericValue::U32(object) => Transfer { + source_id, + object, + destination_id, + } + .execute(authority, wsv), + NumericValue::U128(object) => Transfer { + source_id, + object, + destination_id, + } + .execute(authority, wsv), + NumericValue::Fixed(object) => Transfer { + source_id, + object, + destination_id, + } + .execute(authority, wsv), + _ => Err(Error::Evaluate(InstructionType::Transfer.into())), + }, + ( + IdBox::AccountId(source_id), + Value::Id(IdBox::AssetDefinitionId(object)), + IdBox::AccountId(destination_id), + ) => Transfer { source_id, object, destination_id, diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index 7ef7be8a2b0..73b53e6872b 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -138,7 +138,7 @@ pub trait Visit: ExpressionEvaluator { visit_burn_asset(Burn), // Visit TransferExpr - visit_transfer_asset_definition(Transfer), + visit_transfer_asset_definition(Transfer), visit_transfer_asset(Transfer), // Visit SetKeyValueExpr @@ -483,16 +483,25 @@ pub fn visit_transfer( isi: &TransferExpr, ) { let object = evaluate_expr!(visitor, authority, ::object()); + let source_id = evaluate_expr!(visitor, authority, ::source_id()); + let destination_id = evaluate_expr!(visitor, authority, ::destination_id()); - let (IdBox::AssetId(source_id), IdBox::AccountId(destination_id)) = ( - evaluate_expr!(visitor, authority, ::source_id()), - evaluate_expr!(visitor, authority, ::destination_id()), - ) else { - return visitor.visit_unsupported(authority, isi); - }; - - match object { - Value::Numeric(object) => visitor.visit_transfer_asset( + match (source_id, object, destination_id) { + (IdBox::AssetId(source_id), Value::Numeric(object), IdBox::AccountId(destination_id)) => { + visitor.visit_transfer_asset( + authority, + Transfer { + source_id, + object, + destination_id, + }, + ) + } + ( + IdBox::AccountId(source_id), + Value::Id(IdBox::AssetDefinitionId(object)), + IdBox::AccountId(destination_id), + ) => visitor.visit_transfer_asset_definition( authority, Transfer { source_id, @@ -683,7 +692,7 @@ leaf_visitors! { visit_remove_asset_key_value(RemoveKeyValue), visit_register_asset_definition(Register), visit_unregister_asset_definition(Unregister), - visit_transfer_asset_definition(Transfer), + visit_transfer_asset_definition(Transfer), visit_set_asset_definition_key_value(SetKeyValue), visit_remove_asset_definition_key_value(RemoveKeyValue), visit_register_domain(Register), diff --git a/default_validator/src/lib.rs b/default_validator/src/lib.rs index 6cd9116e9ba..3d984d6f5e6 100644 --- a/default_validator/src/lib.rs +++ b/default_validator/src/lib.rs @@ -97,7 +97,7 @@ impl Visit for Validator { // AssetDefinition validation visit_unregister_asset_definition(Unregister), - visit_transfer_asset_definition(Transfer), + visit_transfer_asset_definition(Transfer), visit_set_asset_definition_key_value(SetKeyValue), visit_remove_asset_definition_key_value(RemoveKeyValue), diff --git a/smart_contract/validator/src/default.rs b/smart_contract/validator/src/default.rs index cb74088286f..0227afccda2 100644 --- a/smart_contract/validator/src/default.rs +++ b/smart_contract/validator/src/default.rs @@ -720,7 +720,7 @@ pub mod asset_definition { pub fn visit_transfer_asset_definition( validator: &mut V, authority: &AccountId, - isi: Transfer, + isi: Transfer, ) { let source_id = isi.source_id; let destination_id = isi.object; @@ -731,7 +731,7 @@ pub mod asset_definition { if &source_id == authority { pass!(validator); } - match is_asset_definition_owner(destination_id.id(), authority) { + match is_asset_definition_owner(&destination_id, authority) { Err(err) => deny!(validator, err), Ok(true) => pass!(validator), Ok(false) => {} From 5052f2a5c312f09731cc6da8e7b5d6892df21bc3 Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Thu, 5 Oct 2023 12:48:51 +0300 Subject: [PATCH 43/55] [fix] #3931: Fix burn `Trigger` reprtitions Signed-off-by: Shanin Roman --- .../validator_with_admin/src/lib.rs | 1 + .../validator_with_custom_token/src/lib.rs | 1 + .../validator_with_migration_fail/src/lib.rs | 1 + .../integration/triggers/by_call_trigger.rs | 36 ++++++++++++++++ configs/peer/validator.wasm | Bin 489615 -> 493236 bytes core/src/smartcontracts/isi/mod.rs | 7 ++++ data_model/src/visit.rs | 10 +++++ default_validator/src/lib.rs | 1 + smart_contract/validator/src/default.rs | 39 +++++++++++++++++- 9 files changed, 95 insertions(+), 1 deletion(-) diff --git a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs index 1c40e04d70f..62bd93fe8fd 100644 --- a/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_admin/src/lib.rs @@ -105,6 +105,7 @@ impl Visit for Validator { // Trigger validation visit_unregister_trigger(Unregister>), visit_mint_trigger_repetitions(Mint>), + visit_burn_trigger_repetitions(Burn>), visit_execute_trigger(ExecuteTrigger), // Parameter validation diff --git a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs index 1954fc479dc..44f001d650a 100644 --- a/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_custom_token/src/lib.rs @@ -256,6 +256,7 @@ impl Visit for Validator { // Trigger validation visit_unregister_trigger(Unregister>), visit_mint_trigger_repetitions(Mint>), + visit_burn_trigger_repetitions(Burn>), visit_execute_trigger(ExecuteTrigger), // Parameter validation diff --git a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs index b8ba577399f..04b756e3ca6 100644 --- a/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs +++ b/client/tests/integration/smartcontracts/validator_with_migration_fail/src/lib.rs @@ -110,6 +110,7 @@ impl Visit for Validator { // Trigger validation visit_unregister_trigger(Unregister>), visit_mint_trigger_repetitions(Mint>), + visit_burn_trigger_repetitions(Burn>), visit_execute_trigger(ExecuteTrigger), // Parameter validation diff --git a/client/tests/integration/triggers/by_call_trigger.rs b/client/tests/integration/triggers/by_call_trigger.rs index 5d0d134f157..3ecfa20495a 100644 --- a/client/tests/integration/triggers/by_call_trigger.rs +++ b/client/tests/integration/triggers/by_call_trigger.rs @@ -449,6 +449,42 @@ fn trigger_should_be_able_to_modify_other_trigger() -> Result<()> { Ok(()) } +#[test] +fn trigger_burn_repetitions() -> Result<()> { + let (_rt, _peer, test_client) = ::new().with_port(11_070).start_with_runtime(); + wait_for_genesis_committed(&vec![test_client.clone()], 0); + + let asset_definition_id = "rose#wonderland".parse()?; + let account_id = AccountId::from_str("alice@wonderland")?; + let asset_id = AssetId::new(asset_definition_id, account_id.clone()); + let trigger_id = TriggerId::from_str("trigger")?; + + let trigger_instructions = vec![MintExpr::new(1_u32, asset_id)]; + let register_trigger = RegisterExpr::new(Trigger::new( + trigger_id.clone(), + Action::new( + trigger_instructions, + Repeats::from(1_u32), + account_id.clone(), + TriggeringFilterBox::ExecuteTrigger(ExecuteTriggerEventFilter::new( + trigger_id.clone(), + account_id, + )), + ), + )); + test_client.submit_blocking(register_trigger)?; + + test_client.submit_blocking(BurnExpr::new(1_u32, trigger_id.clone()))?; + + // Executing trigger + let execute_trigger = ExecuteTriggerExpr::new(trigger_id); + let _err = test_client + .submit_blocking(execute_trigger) + .expect_err("Should fail without repetitions"); + + Ok(()) +} + fn get_asset_value(client: &mut Client, asset_id: AssetId) -> Result { let asset = client.request(client::asset::by_id(asset_id))?; Ok(*TryAsRef::::try_as_ref(asset.value())?) diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index 72ed8b4e5d70e390f611b51959e63e4535942e92..68fc695d51fe9c4bf4612ab3b2fb4a21aca760eb 100644 GIT binary patch delta 124148 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%0Do#w%A-$Z@p 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 diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index a143d5b7ae2..212a6a55ff2 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -210,6 +210,13 @@ impl Execute for BurnExpr { destination_id, } .execute(authority, wsv), + (IdBox::TriggerId(destination_id), Value::Numeric(NumericValue::U32(object))) => { + Burn::> { + object, + destination_id, + } + .execute(authority, wsv) + } // TODO: Not implemented yet. // (IdBox::AccountId(account_id), Value::SignatureCheckCondition(condition)) => { // Burn::{condition, account_id}.execute(authority, wsv) diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index 73b53e6872b..56a823f23eb 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -136,6 +136,7 @@ pub trait Visit: ExpressionEvaluator { // Visit BurnExpr visit_burn_account_public_key(Burn), visit_burn_asset(Burn), + visit_burn_trigger_repetitions(Burn>), // Visit TransferExpr visit_transfer_asset_definition(Transfer), @@ -473,6 +474,14 @@ pub fn visit_burn(visitor: &mut V, authority: &AccountId, isi destination_id, }, ), + (IdBox::TriggerId(destination_id), Value::Numeric(NumericValue::U32(object))) => visitor + .visit_burn_trigger_repetitions( + authority, + Burn { + object, + destination_id, + }, + ), _ => visitor.visit_unsupported(authority, isi), } } @@ -710,6 +719,7 @@ leaf_visitors! { visit_register_trigger(Register>), visit_unregister_trigger(Unregister>), visit_mint_trigger_repetitions(Mint>), + visit_burn_trigger_repetitions(Burn>), visit_upgrade_validator(Upgrade), visit_new_parameter(NewParameter), visit_set_parameter(SetParameter), diff --git a/default_validator/src/lib.rs b/default_validator/src/lib.rs index 3d984d6f5e6..0925c89ed11 100644 --- a/default_validator/src/lib.rs +++ b/default_validator/src/lib.rs @@ -114,6 +114,7 @@ impl Visit for Validator { // Trigger validation visit_unregister_trigger(Unregister>), visit_mint_trigger_repetitions(Mint>), + visit_burn_trigger_repetitions(Burn>), visit_execute_trigger(ExecuteTrigger), // Parameter validation diff --git a/smart_contract/validator/src/default.rs b/smart_contract/validator/src/default.rs index 0227afccda2..f33eb3b29f2 100644 --- a/smart_contract/validator/src/default.rs +++ b/smart_contract/validator/src/default.rs @@ -26,7 +26,8 @@ pub use role::{ visit_grant_account_role, visit_register_role, visit_revoke_account_role, visit_unregister_role, }; pub use trigger::{ - visit_execute_trigger, visit_mint_trigger_repetitions, visit_unregister_trigger, + visit_burn_trigger_repetitions, visit_execute_trigger, visit_mint_trigger_repetitions, + visit_unregister_trigger, }; pub use validator::visit_upgrade_validator; @@ -1405,6 +1406,7 @@ pub mod trigger { crate::default::trigger::tokens::CanExecuteUserTrigger, crate::default::trigger::tokens::CanUnregisterUserTrigger, crate::default::trigger::tokens::CanMintUserTrigger, + crate::default::trigger::tokens::CanBurnUserTrigger, } pub mod tokens { @@ -1433,12 +1435,21 @@ pub mod trigger { pub trigger_id: TriggerId, } } + + token! { + #[derive(ValidateGrantRevoke)] + #[validate(permission::trigger::Owner)] + pub struct CanBurnUserTrigger { + pub trigger_id: TriggerId, + } + } } impl_froms!( tokens::CanExecuteUserTrigger, tokens::CanUnregisterUserTrigger, tokens::CanMintUserTrigger, + tokens::CanBurnUserTrigger, ); pub fn visit_unregister_trigger( @@ -1493,6 +1504,32 @@ pub mod trigger { ); } + pub fn visit_burn_trigger_repetitions( + validator: &mut V, + authority: &AccountId, + isi: Burn>, + ) { + let trigger_id = isi.destination_id; + + if is_genesis(validator) { + pass!(validator); + } + match is_trigger_owner(trigger_id.clone(), authority) { + Err(err) => deny!(validator, err), + Ok(true) => pass!(validator), + Ok(false) => {} + } + let can_mint_user_trigger_token = tokens::CanMintUserTrigger { trigger_id }; + if can_mint_user_trigger_token.is_owned_by(authority) { + pass!(validator); + } + + deny!( + validator, + "Can't burn execution count for trigger owned by another account" + ); + } + pub fn visit_execute_trigger( validator: &mut V, authority: &AccountId, From 00822f272d273fcd324ceca3152ac0860f7b08aa Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Wed, 4 Oct 2023 15:07:56 +0300 Subject: [PATCH 44/55] [feature] #3953: Add `owned_by` field to `Domain` Signed-off-by: Shanin Roman --- configs/peer/validator.wasm | Bin 493236 -> 494641 bytes core/src/smartcontracts/isi/domain.rs | 3 ++- data_model/src/domain.rs | 3 +++ data_model/src/events/data/filters.rs | 2 ++ docs/source/references/schema.json | 4 ++++ 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index 68fc695d51fe9c4bf4612ab3b2fb4a21aca760eb..3f5e655c055c17beefb92f06db4fe9db350e2a89 100644 GIT binary patch delta 50560 zcmeFadwdi{x;H-6UEMR8%p{$ANCN2@0wh4VlOPwNQBXw1yRKJcT`vI<5bw%F1w};- zj>ke}HSW5r>#B>3o?#U=t{!C-6%<`uQRAKC6%~}T>iYXWPjyd*5Y%%%=lA~ceqJNf z-PLt@>ZzxmTRm0%;I(}oSkb3#TBDuf|3Wh@zKYaLBef_r(@ZT&g=WfBYSAJjg>|OX z^4WC{-12u}ei8jVz0epVidWxf2q8++e=_Hf&X0xgpO8qX=^YJQGSnwj8_Exb%y3xZ zHx#l$qA)*XT5c#W95%y={KCTYk#ft_s1PzFZ7B>9F+@lhxHnL-6j6O2%6-u3LRkDi z@)~#@2Q24V>qLnqrI7TWQ4k814+w?qlJw!>%VUn?7^r`6ky%ufekc5)_#*vm#1&tr zKaQL%Hlz>AyFk3S`kA~^LtY+vES!Elzv|@m^7=?y`?NTlDtm-O=Ah?}^?V{dM%( z=)KXqqUq>wqRXRg(VL>TMmI*IuYXbf`RZe1KSUDSqOR#VEpBph$n85hVmr4k$?v`K?&(0eNNZ;Iz_j9+mO(e?=O8$DCYV)kc^_b`0D!F|1d^v zk5-`%Yr-w~ZI8Aj^SqrQhZ9|EY-m~7HQm}~V==DYwa66l207c)iR3;*biu8W7B{De zF*dX|qKiC;tM@2gOD=Lla$2D-(oxvr3Qqed`SEC-w$$|7&$jNhhFg--HM~(88gGNq z;>iW54GHOJ-K>7PWG7lMy}P3=-Zq9iCi3yT3aP>yhMddm>XLp=;7)k;es#LVyTdKq zV*2lO&y3L7s7H*7EGX`td$pn8k$$hXNxxUCNA=%ZitXvM2lmJBEd$4h?W^W8i*){^Ms zmbzirM&Gs#8HjAvLr3BFkfC*ANBW$hN8|qap_9AgdUc;+XHcD!M)bz-?}y)wNu34o1GiM>ga4nvuiu0S$1w>$M!NZCdT1P*!0(K)t9bwg z#t7|ttANGT#p6usTlx6Gqk5*P76Z-zz2z z=3%#85fqWSNEE{aWQ-G^6{0Di2EU+O?_M;Res4k(3Rmwv62CL{9)aJ>_TCSmKD+mH zu?t1tZE5=ANw!%22t^+-X}~V%y?7EKorhudOOu`iMXkPR%KgGb2h;z#&-m4s?>A3B zyfJxvdc?F&|HZiUAqT`!@Wcb2FV&-ZH^|-uE&GH%ae5`HI%fJs!uAL9wF4(2rPo0> zi^KG|jL9v)BL&*_Cn8O+kjGO5e9!dOq27QbqE&cDV;RB=aG<(S{(r2NGkzBy>;aSY zMkpyfdv-GHhP~*F>SP$HCZ$FwHR?twb-%d!qOVb6xZ(8rqh_Rp8`&>jY)tC? z3oK!n(!z`|G%S%8Co&~o5i871nKmU}9xI>}2GwbCZZ@XG%VKd#LYGYZI5VciOJlLz zl*6aQOJez)VsWO`&mH}=A-+!EaO_m$NjrVVNww)Aw}k(EoGFNCfdS_<^;+6KaP^Gi z!$!|oZ#l6FI9_t1mBo77N!O&l%4;%YtU4ck0wiDMB@B&QfllF(5E*g}%A+x>bJ24z z#&p+nWw+;wZqMc2p3CSt+ za`uc4j8~5Zb5Vv7+@-bX&nT1ERpta9n@CpzKZm1%jyi}P9fhhJWTDlR$YPGei1y7PD9C@3Qr{;GEDwmc?6nk69`tKb

J0jYuDl(?2OHH&*p&_dP-co4n8KF=F{1g79PZ1Vtpmq5*OD_o@&$++v!zD z4xoTAUrC|ZcCX#WUo^i15~*!f}UWGhG_lyki(wAr~s| zY%5I1fdrqy1_;8dS!{()5916_BU-}SHMY3h3uF*V&(wiN3HiuokUB#6wKhmf6b6q* zw%7z30XHVOKra4*F**E)uP7Otfno^vD^N`BzyU~v!TTLfL+`<1$im>YaIxwznHeU9 zZDEX;zKqY7YWNhnOrG#=B=Ps&*~Wu%DLzRG3I>+;l zWIM=_J1FS1L&QRsPOI`8f3-57LHDDL+m;+j@%hVIf(X}s2T_tWt^%y41+jx(=z!D~ ztISh>-Z6MujY-CVK`REM7>Q=BRi(qlnK@ z@ot#SGM<0PZ(+B$ovr(xF$8xXvL+7D?AzNb3MpmXOmqQsOiTzRlz}vJ|!JV7!eG)6u{I&CJ}g z51Ipg5c_#4%9qMNnvJA?hpw&RlA^`*U@ilcl*y;j+&UI-AwNgM7!^Mx1tCQL^C5X} znkEM^C{wK;NL2EK@HxgD)0x_*bp9?DHu1J+#O*VEGAq>!r0o~dQX~Etr)H*V zI-ePcD{@W`Zb1Zk{_Qs_Q5NW}T9m$xC3)8pOBVf=cMWhvhNhbcnbNpmA zf@E<5QIejOt0{FLV+}PNOhH)=qz#Hr9R_|;X|Ss9bQpoOE?$+Nt3V@E!erBuOjW?? zsiORRD38kuDDgv+5`n&!#wDdyUrRWL={GF%>4?}FO4OwLQ_I$R>ovwOgh$jMLqUm8 z$we63z|zSkD2)^!G+*Qr?}jP{&JdubmB~C%co*-Qo18;P;PMzhtl_!7aXbivYnXSB zW8wSx&DfVHEoS+RNUESZ0kamQjDMLXl$~JY5755e#US_jcTogR=axRlJI?%(j4Jd@ z4nJiN`1TT+R3h<-`*@nQ0f%z4_t@9_oV~|p+M_Copuy@96;BAu{dM7l9^oLsif#~g z!6w&!t_UIq(8bY*_?y-Fa)$=4coLJ)*Yv`1i1ee(3qM1IvULDg5-*a?x=>ssX{2|i z!TFXRkPp z0uii*4AUBd7>1jaHZ}AqY-+?~(A1YvZ9lJeT!#y~Fo^WbYDX;^QeZCmoTB8EK%ZId zVGv|C8%W=M=uB&h>>%5h4)yd``{r0?t)pQc6-&Ks4d;K^)|T4wbP8vpC~L@%QlPDH zYu~e{KsDdTu&pKepdqas`#}ETP)h($aaILHkG4(Z-WJGbt+YO6h2usZFvhLw)t#aGTrg;6t>eT(`j)ut7e3=MzF_gf ztZ3mxM9fSjn6O7^jUSa>iw)3{SBbEIz?t@q#%Q{57CxGlh3|g#;8AABU3&SsQR;$no*E`em?-&WiE53IpJ~Ej%+V$qW0mHu zfJbS00?e8faLy{dXOL( z(~t8DubE$XtE*Y(%Fw5DwA#0X?V$SDEQ9@Rj<+KWum+-Of6`dCxerKY8Y3lcWDc8X zl`Rtag{`-b1K+5FY8VjBMk(w-tB6D<1ZGnzCnYR}qTuLN3zvc>Z8TLc&NY4fI@*cD ztJqyR;8mukytE}|OJ8{$LSwCNVanHD5@&*YD}JvuAf7L7fuX1@uSr531MHc_$3b9` zIADWse^{*Lh|c{9)W-6ZX)2tuX(j|^JSaxk4cN4f+E!A_()W`t-&9O-Ws7`oCxHu{ zr|B@zZXoV4JqxDPKP0P_3%jcjb&#FDD~6Yn3fR6g3h`B`+lv1IUtjpu#^EKTiqGGZ zbe5`KHvn%m&6lgkjeR>(Jqw~0_I6&PBgrMaI?UgJISo?rNoh@2A(T|TfYw&ducjhV zX~gAce&(z=X<^@uev~agX<>yqomVr*w+DMufg#~Mukf;JD)*u9o2I)BqL1uF(6>bB zTcRw+UucDTv?IX5(?DUs-4vBPDG{#g5R~K5K;-X*WfUZ-Lyj*)VC#it-JRln2f^=5Pfr0|gFE5QnCU8sd@L?hmc%2nS^AT3cBrzk{-_{~4S(bX?nAFyaN0pjRs6}&$=f$~{IG#oc zT>%&OZ-hZKIrvYaKNwk3tJUibq+g?6uh;lrVk<~nh0rAzFZOB?s@6XN3PpMhJrQ+D zDX9}Hwo&^Q!&6eMP4lX_6+>-u&!os)o@_v04UPJFQ++hVvzO9)TbNg-@a*WT_CF`( z#*Vqt+BuJ>q45zW@-?|u)b}4V{ zw{Efo@pdV+r6zla+g*i{Dou7pyI5Ch=u9zcWpa5sBk+gBxBmrz#n&N4DYN~J+Cfx^ z&$_-JiVp0gCsSE{r|B2-aC$AkNv~zcpPDWXNB`i!X=vfYHkB z9h`G#?w3sMGF*uEcpVy97hV{h|H2J%vi`gmtebd#?RjgZ&1Smp;+&DQ*Nl&*tCy@= zx@_f&}!HN;;m?4Zo0nG0mKgYhRtOuf$$DFVvf<7aLCc zeRsk4>rYzt>;+}dJ84-09nOR61t%?g)`GI@1o@cyFmckah>tk0h3D(5mHO&u^|nfH z&(qskdRwbE?Fe;#MsMfpE!SJ7x9&;X(I&$nhBJM&R$rZ~x991NWr!a&R8J;|(#i#d zt!7K@l_AHML0w%a*M3H2$nj-NxAYni^dSu>SBX-w9H_tRbNsiZ z);Lh+9F-x*mnoISfih>S3^~3`sUr@QS)(%K_%fwxI8bJ_%Jk@78eyp=`M#`B2^7GE zcpy}r<@oyhH9`OFGL?|NH?K}x5lWKHOE-;jQH{@ZO4ImkrY)-RnRaO!pOxv?_&hwO zTcYtT?2BoX(gof8NBdh?#xzRlg{};m;KDMdQ%Xm4Wl#qfmNEU39AAd*n1yAAggJ72 z8C1H3WlZ5Twa@yCUbnD}Ey<+uIe1u-Ei7YNp{>-do<;RN(-2LMu`<%?=8YXF4rJL~ zSik9tCM)$V9ta3OG_NH{76g|5H2LbSar>qLsex`gR{T(r?nAUSGdB@YVhMXCI2Fj( zN4wnYkMK);IbefKq>bpd5M#zWie>3jA*)q(EG4zr3J{DI!;0m~h9F6Qz@pc|^Y5!5 zQ)W?7HM065Tl?%=5oP&ZnYgeGm@c60~r0y*=Asipbo7wR-~_>P^_kKdzZZ) zkZJqWq0r%OeI$*+QnV;jUM+4rs?>Uiel`*(q6-{mheaPi53*$b)*rb>B}x*~!9{&Z zKsYciw15O6lx>00P{1(^fdb}T-|fl zQegqn`wJ+5)Ij4EY$dR+ilw`X#`fZbt0ifJ77>xS0qEH>F#in6r!)H?iMLgA?uvz& zMlKsFX0lKbxgt>v-G^r0$!BC0w-9^m4XE9=Iy4sb<W_+G(=a_1J^L_$HeYMjxDZ8~?2!JhH38wMrH(iNA1DMG+3A6pbfXM<#_xAK z`1`=pj%o>-%~y4!XLpd|L{lb5BwvJ*{xrJk(lp7$KZPbbc6mTI*lMI|;4L0|--Ec+ z2E;A~h$q9Y+q`9%e=qK;3N=8r#)8}H6}N^VrJw~ZvkVbM7H=LmE4)TLOmooOzRVHm zz@nza3yA1+Lv;^I5^&alc&5R)T5KRtE5bL-fFHNFrCqjLyceOhF~TbdT^&!_e)Vs8 z!Eu3){}@eLHVn`xIoXj+l7wrhYH)7pv5p!J3sU2=l$WhIO5bbWiu0(~c`}ZxvId_QFm2QWq*#k7 zp+zcvDjAq0G)w(35%3d zX`nIH_fpr|ABe-2uOJK911gXcB2_ek>0;O_0xVdCv1 zO0MIMzsrO+PG(s{PG0Q8N%ZY63f*nyOG`yWRMFNZpL90Na4Y^ zQkzLAv>J0pnO7%U!U-3V6|^E5A3k0Zndhe=O82Frv0Lm4HrR zzj-`|P*Gv~_VQeK!padGZ;(}&8`pzuc;p>oxz7>ur3<~Nyci1N{nDiR{GOLjQzcv%@&Y_~VhHUp z0_~k)d@~@!#->r?E)UJT?<1i~@g%%xUcWhS@XTWUz;)>6-Jm-x3xzl5%GjMX$^fd& zq?;`z_9?rk6y>zJTZ!23+7E=1LbO_BGc@gkpkA9t^6XD%tac)&h8YPib9Qzv@cB)b zpU%sloeh0~#1&{RD3JOBkt>iaDB#)vo~X(SekG4QS^($p?E?RzFuXYua^smJ%%y+} zzornXhx24#7QPDpWwQb=IUy5DvyVO!MaiBzQIsFB;KY#Ne?WFej{NI}C>9fqTl1D7 zOZeK$>AmpwsejX2$0F0#r!LxesCagCJGVYFB;l>xrUeIb)2)E)3jAiv&!2uaxHWHY z&1>UXyD#mR#tU3WxUxEHZ5=Nn=4OD&AAffsVcNyT$8n&?mwjtDnhGsqW%+T&2#2@x zM}x`#n!m(=bsJNZW1!?MT72a|bv5Md zxv5+wV$y*BCHr2CMhYu|Mncr*T$V@?3m&8QvfLC0P5&sCE>SeME3cS+@R9S&q|_&U zbS@~O^uw^7u*h86KBXl-Z7y($2b9?GiL;?g{Dcxm%EZVeKBdHQCAQxbMm1t$M>Njm z-g1mtCmq{CnVV;7c(|*J!9u2?xQ+E8hCf8b^S5xCf~l&h95E+hw5WFn!z>t;D$BwZ zVRJaEzli+C&AapFFN!}%HiTJ|IdsSlIEeWM%wLOQc#tU_+gdv)4&r!+FDXR$qyWOhGp4o(e43h0bwd^pKWl2=0<4Ar%`70y;*fAlFi!3L)rtw0l$w+*Cxz3Y z!@C`FM?r2X3EPA|Q>0);IcE2Pn{j=<~FccAkc2 zNYM0%rj#hcolV$*4tNw4&EFP}vIEX3OoM#q;SPF?6il-) zj02QtU5jeraDab+$~T5s-)x$k6gcS>FhU)yQjKo#b1YaWhL(Z57FXN4Cp4lU3RIvmUC>K+{6UkdxX@@661`B_1{PCWUlT&e5vVDx z)#n;*m+xxfqsxL2#MfU&4eejE`xk6TZShpjXcIYZ0Nrph0*4*`1R=G^yN)RSz^?Gy*$B@A1hn%zt zXn~6e^xL*nP1`9R@8wHW90^U;)2e{NTs~~ezG80gFL*N_lAENWS#XC~F?;9tAB#6j zt>B#;mw-aSv@Pm|SlsO4#}i+IO6;fdQ8jc6tE%E$JMT|6e5ofmiVe$Fk)l^7i-U4|H$OYOUxkx$ z5w>5(kJhVp=+W4nwXUUs)=gQ$E3IF*V>{F;vsn{0^``51ZK9UF%C>(4W30BW@akuu z?T6&yY*@q{&WJFHz-@i;Cqv3_gZ4jY%n)SQeTLQsqC3E+ldois^0+B$UWf5aiS&t% z3qWbAWK@uV8dqGX%Ih~}_3PZBd~tp|)r`T3r9ZrbxuiAwkTbi*>BmuBbQ%TiV7p8` z;_*jdnzbWWsw^iEp*xuyC}Rgt+{Cns2vTos$?zbeaJ`b6Lq&dh(`OE&RWn!pAfn5@ zr)F8xlCHQw$MZPuC0dV<;D2Zr0z)&Z0Z=gi$LQjkBAhY4JnS$kAY2y^Fkz4eGh)$+ zctV6&H(i9vbbmnxohY-0Ut#g&{d0yEWRta~0+dsAh<;Uv&P;pA-|`#7fcr64Rh3p% zu`CGr0uwrO9XQ;AyQAB@L zF-cA>)V`L-1bV){Nn{&i$Q;_u81%mc(Im4J-ZdkW0OE#8d(F5Ig;}?_|D6w_k!aAQ z=@s7xK1<7D3~rjZmhu$ImQrvcM=b!MCarMP{$H!{j3%=Heg)BwL{TW2#WG$~1bRcj znY~3N6glF_h8T!r3owJt(F# zjsUtWpu1u?aC;15{7H6oZMTZ#S!^k{XmbU4U@OJl56sa8SDo_sbSC|r)HQx#R{l}! zB0Dqf8%%o^U*O_Av!w`UYoLFID%9n*lEvztlDqX{gS2~QDOx(%Mqd^)VkDhu$6CbN ziAn(_XgKJ*3WR+|%@Ekl(vx$fOkboA#zGZjhRW!TsCKT7l3+3)(n$SeH4wtU7IZQw zb!hhjb4S_`WL=Jk8BFX6Wn?&eYpVi{GxI&r?9j5fXgE`ZSZ?Jt%r$d{FRgL-$pS%}?;#j@aV0bJ=^+`cQq+y&>y0AE`h6wlWx5(*5a-u7p~b!L1I z4ncg}Ha;v(S_ac07#*r2Gnrz{nKvGSP8PX%Tt`|+$0{%L4t@p%u zm>0fR#q(jgnjtl_iMN0A6f^S@2H}6y#QgaH$t1&pH@q`i%w4e&87whl(j^p!pzQ=d z<4%^yt*!kP)W33gXOpn4;jK32;ndoIhhts|o_ zuJKD|^#8Q|85s>1iQZ82l5*|>9^1us%-7r3sj&)H9av26%0qNZfy4)mcyvnUYl>hvurY8H2hOQZOe z3cCP)8TDLmY zjtQRGo+yN6TPP@_7BI+SBB;;&X7h|5(I=LDN%{pkCCo9(1g`)=yg4ju<&9X7Ft_at zZsXP9Gfqv7uguFiAi;264JQa1Tp-27D&IB>2ri;KNamp(mOR zVq!KWqDlP|8(ovrSzBB2kyc*8g&HIimv*oKn(0PRRS-{RkZPZ%7D*s5YthtV)71D* zZaKQ85j71~P^1`*+ZxZ{B-LC3tk12MERY%}g%2S6)IEbqIrLA$Or%y8^=8pil$LRq zkC{X}p%HcQAtH3@_`ezAhvX5;$Qjc9C1ds7x%pF!9WwZbQ4N;fw;a@=a0jF z=0K{Exm=0{Qr-MY=cTr6o{h~*mDwWP@xK+(E~y>5`_~lisK9iIP>GALe`PMHG#%LW zU-H}FWIzgnF&cxvEI_ny@FT2WLJzexp?@Q0X9 z6Lcq}HZu~p7;*}$6c9*=sUr28Lb_jBCAtoXfMW~Mu0_G2vA z8@i2D*HA%@j9w8SqF14c`JH2dU6XSOq0MQ2j1}*Y#N97GG{lA&%hI876xBZG4Io!R z4S-%&m7>{Fi>LqTh^TuY13RgC456NZH_$R9{l{8+r&=R_VFPQrI8A_}%Yv1raTY(i z-^>ESDM9MAjV6VAC0oEmkWiZW{P7G}4PXzF*C6Srg>s4EZ9|aBr;u<(c4;CXvr|H` z^(YB+2IdNKl;}I*5*P}AE8$lORGs30;AZS92f(g5>jJGz`VGz3n&}u!TN1+Jw?D@R z`}iaD2YE1V>*`=UeNWu}nl?kr;fkFiqGC<3WLy|Dcn%?zjU@bLG;rnG5=yCt?)Nlw zH4PmU#;SM_vvP|Uy;W^SB(tXp%}13Mat@a{nsH${1@5HCg25guBe zbUaNagf}0#3x(V745jA?i`~%Cy3O7NOgfs3m~<#jLN+EeR7AtDo4|%^=C?RFCJ(?8 zqE9$3?GM416F^(A%DwlS3^gVDF>gE^INPtSl#8~Lv5UD!!L`KPhcjxFYbOxNHl=Gv zg+38;`k%oWgv&aX*YwX~a!tKEH?ZDXAArFY?IkSfBXRq;T4i7bcmr}?{Wpmf6}eEH z=EGV>f$v01Ap8~8xXuqj#-Ml%J}4EGKX@tLZKK&K-LphXD#yK$k3uJK2*w(j3&pB# z=bEL{;d!Q3JXtln===-+F{VQ^BeiqI!lP{PUMBClMTQ9n7|971q z6JgMRgd4*-kICqEP@}_Luwry-cFiCC%AD<*^J(6awUP*SR}5qSwY$Ytmc^Bf8}%ye z8e$)F=?k)CD!3%f>H1?2A$2oZZWm_V$4&5=w4sGrk69M$qJ>#cSQhHY!mKAPOH*(G z7{?6^NEVwjB8$jHMW+39?Kjigs;kR);b$S!+#a$rsr8T4*pNS0ETB<5R$_!=Sl6{3 z(?YcA+WTG=I9&wWDbKz%7uR@ULmtj$aiVS3%nzA8~3gUynKEcJ0@(`FWa7TPJ{Cd)5& zW{P8=8+nK&#`6!J9 zgQ9lUwXmyNGc6v7imur`mQKpZV1()$`T{En@I1Eu29nkTJz?1L{206sM zyjtSb){(rjM9>eYfU{X`LWE*lfW$lHA{M=xo)%aEaua`{vn*J(;7?2}NH?Ny zpa<*7UttltG5~Yhz~zDBC9Lppey|jaJyu>Wp%5wyH9_A|2|w7+aNN#(*4pn09dCEu z;xx&w2aOf8QTo?fG!hpHYf%<$R?QF~HEfZSq&Qy|0faK$z+ibWnM*U}@Bu+A{m*!> zidu1MhSO>wWNt0_wSINr)x@+!2;ruxi`#DiIvS#lElfltp0-0#@U;1F-NDsUn^3A) zfXCA_UHy>S3C|BjSDN&E1VyO=bYJJ8D&)jC?u6LfoPog^RS+)@UcSMGjlZygX*vf9 zG#ff}3SMhW`ym2AnDzeMGnK>~J(a{9brN&bNz73vF-K1-F`;h76&>-ybJPjXS5$4u z9%QQ4BJx=p2YG^#9WFMdHQqOZj%;r6__<(I1}8>a#vLYBa1PgerJ;lMYe zx<=Otd`Wp{sc!H0wB~jvG_g#7DfRM!^&^N~taip!uHdc>NogjTCN_XSjVcIY%pp|n zZ&He7E7U_yQj!_iC@OF?>SK(XzJ_Fw_LB91v$>?6m`4t88p#Pxlri?Ig+M@+h*hx^6X!|l%`QCum^^Vc`gWcg3}oNlYv6KQAg ziuO6Ud9tMo`m|!dYCyDb5x10*ERD@pBkRirSZ`$l*tU%#M|tc7D(Y5nWzoSNz-I!{ zBAiW~s7IiWAOOflIUDD@$(t<&bXpF!Z5zYtBenYFS-2ta%d>fX zEEixjr?Fgo`6bJ)=_VRxfsdp%_`!Pra;*J}j?zMP3-b-67E%N{5#v)o`EwF8jHvtv ze%>9IgFW*(E;v`7mg>S8*Tp*C_abz6#q~*_l(?qw-mS3w zxcHLxG9_oPSD&v4oaF>Z|8@g-a_!;WIlPG|A-hSg@l)cEk}kM|B+t5dl29w;P~w#;KJ|* zHYdFAHG4V$Y`7h`m+jj-^}zez_<^^6IGOFDQb_8G39IAB@BQ?9KYiCf`Tii?oSQCz z`m_k8A;uM_ZjH_{!{AqIwziKZ%{^9jW7bMzTAl=WIp6wkfAFnuFJUiHzm7a|{wp<$ z0mhUt1PB`r5{OJT$cyIpTKPBP?L0gCy<0!}trfF}=I!WF7Dq8y`3$bfPXx34_r?Wf z;-ao>?J%Aszo~pYicXf_QoekW0AP{r%~+wZDRA_U4?gc?B}S~o!8?Edx6fX@h~R%C z-o1T2pG8ST`;um;$ngER0T$bA1?UBPsy&>zE!RaM1|@a5WW8>&4(Yoa9VqH_o7t^O zF>*4};lQ3MjOP#oz#g##DXPAav0tQZ$}nE|Nz<)GcZ3C%oI1RVO-)ZaL>kAK)6{;gQmeE{ zBhKB$@Gg16$e;^zI1Uw+W@Xcsw(7QS!oIDW_ehm7lMMwbYmGLM#URa?@)k=W3#3A&faU#kzymRfp9UA9FH@GiwJ^+jGUD8 zDx(Z00XhP9=n>jt!I!p&*E$>f2{SQ}zluI61#3sUmW|!T$*)Xp^1s$OuydZ{2F+{`tMXApiHM_-?~5s16rF0a?@X z+vlh!N`Dx$SEC|NHePqw9yc=iti(H1A}&jytC;ttWgSo!(QnI-#clL8&l}BIQZ2lz zY@z*q$NiC?QW%<0D!PyS1?TQZisf^x$=l7pXNiz?E{N=1tLp zH_~N&DZklP2AZzH@}0HEb9(<$+G(ObNTt%-dfu+HH$`5$*50^DO#x7qt-wrI+S>)Z zZITTco+2`D+T9gF`uD~+NYx=wT@cgI=~ZSwn=E^Zv8;n$w;E#Od;`xGDCBh57m-b z&({}Ac1Z-`Xr|!v&bO*Pt^{y1gx@_@1_K+e%alX4D|Dt7TH!J_ZoMkxKqDIxKRa}# z*FVzu7_xKLW51fjNelktwjz3Eg>FY6Ex>WVveirfUPq=umDPA0MEn zIWjfVHuYg&2O=UzBAla^Hv^1X(?c$H|FP$Dz;X(v1KssG4Frd@-@llD=Tv$vdSSBf zC-(0=m18OHYyaaK&O*+LnXm#|Q!jZ_9^aP5H)*7P#o^>9bHw<$utciaeev<_Mu-UE z6b9Xg)930!At@qP;l--?|BfTZ`=inn#9~P+a7TtB3x zD3e_pTurMyR~b&r?kRfX(QCv1THzGNtb%Gid7X12fWg*oHA} zCp3=&YAyZ6tFEzp^0h$8S}HJ;QF+?Hf{NrE(@`fCucrv%5R{hR9E#e$-cf->dXJg_ z*XBFf;A4J5`WgY}_0FdPN$uHi(R=Ox5!nDIrFat1n;WrX^3bvhTMEW^$H1tYo0v4s zMxr1DbNq@JIFwAMhl6~UaiA`*GsWucX%1svrw%Ol7I2Hhx0&wM5_w>127CvVvw@3u zQ34oP(%4})yMs&IPh9CfnY`x$?PI}s^fiC5?Uz-=GF%a`-xVv<9UeM~sbefLK%mro zHNr?n;u*|)Amj{_KSNZsZY(Y!suja1^?ry?*jP2NZU3uY)@?g{d@MefHQI;HjhF5j zxjEdee60~dBX8zNa~>=!&l(IpM^hc*yDfO)L2i|Dj-D6{vpoF}frafmN8 zSbt|b)?9IgCe1cQ9?)0L>1Z@!7O7JB3J$Hz>JG6V+%FaO8T{;YcIjyyr3iR`dU)E5 zdsVp;CojidLS!FV1#VkDD)x_=UKN*Fp<=tMnMXGl z_F_)@!C4b&C~+15EfoW$`v{UllE zhnpCkNC%^^4;dI)2$bpXvqW+Kro=%g$c9mX2k_y1?Dl-sRCrT9uHqB<@>}y2GNNlH zX3Mj&eTRrf`zh+if!<9S7IF+`mXG2!hhXQ_ntbe>KOQSLjEKPzc7xgPCU6(?dZxQf ztUaETyNTSwYBvHT*;nu@atlD%Y*s55qufKKphVm?y3Ho{_0mqrC6cv_!aMR61a(OMK*q`t~9a=bHX(l#T|v+ zImp=6R-Y)himS8kGnq|JFTcPOoP4UA&1#3UvD>p%DrUT_ub8inIz| zS{ba~nw_^#oP&*9I`A`Z1b(Wkz^!=l(A9s@Ihlu1LZr=xV0UFbVzpCz_Vmz$QM&$Z(4-qc3 z?>S@yfqSYHIxFl>;-;TK%oS^Oa6G_OsVj#%@c?RrH?UC^Py(n#pa7Kqu}4VyQFq6x zLD^EI4t2-5f0$+g31T)pl80H708mD!qEdd&7@;ZrTS_tQ8QR7R;ghK7=|lHqL6+Iq1;n7gngT1*b=T7 zA@Eq;*&PASN_g=RH~C4ZIU1>{5Hen<5+_$#pEV4UoNA6+?v`P9%bXF`aQZRC8P?KJ zA_O2TeuSTz?hv_~aDFskJwRxSP|;DLOjHdssfjb|BEf;mENDb@;#mjHmh3 zgu?FYb%7HGSE<`D4-uAYZ9_mVIy3}jh-1jn+p~!?DDyd8G;yX+l7% zo(5lR2+k7JX4S>H)oRng89rsms~<6cWn`~L0V>t3hW69X&)6;i%_1EXby4lcP+W` zFgs4FImFTk2>2g+&Ea9aBKVK$N&VfZu!U-`oYNc@EhoiLxUl*hau+QJkzkNJ)cXALL|`u53|sTlRcf7(5lpNgh`R#rcf zH>C&A${WxFC`B@LaW-D6>ui_@=^?Vu4{v0QD0Kt!4LGb6YK6~yElL}i*C7K98B!&j z7Gb-*ra!ojs114{Wk-qxzb>6d9)>F7eoshKNc?XYj@3NDE!DA<2x{4suaJeBOE(4A zRukH}REq%BVv3q>&ok*D=TI-jFTH6h+KndC9nV&0=SV(71X*sX`BA(I;Ry_(6p{#b zWhMqFRozXBB^J-HcpJ9A-HCMphtm=mvS=Dr1cf0kX2HZ7_xd5M+x@zO z(e#H{mWj5H*0XaV!;@(a;gN1YgH5M7xW?*I6Zl%KmG5fK-UW7Cs7Y3PJ&hu88iiFr zPB3!>74r`TsA}=Aszk3<9Y|H3_%Ka_vJ=rUbo3|H08<&U?y7U*87S2yT82!m|0oLZ z{JASjEIFA$9!*y7wCUc}s1tb9ueOe|;y=Oiu{eguvqp`od&&SqBLS`ej=t;x#VUK6 zEd*9Zr82-4u}W!6(3hGMBRa@#VXqXkM+-Mo2*OwziCWXJhE711KTKdFf!*(Be`Zq> zmhEps)|C16{`|VjM*>&*)}j6~F2U+ywwa`7W(gL}tVq|n%F$HP%pfqNfJ>0<`Zq8- z!xVNS!|W|${9_hZBSu5GdimsVpnDvOQ~A_Tac_0L{Io8Yyq{c@YvwX2Q$ zf;bx+*B~8q=JzGCgPHo_Cn4h8^(>S)huf6m9Lw$&y4}*$B-zBbqYNMbgGS+?1k;XQ z&ksKoc0q~m0&#graz+I5mc5Lo23t?O3Wv_(>SbnmmoZZ7@D?)h8+ce5W6UWw)O_4A zl;IaZ{WPPq&uk=KK|Z6d6Yy@dJbX}1X$A}<=j5ghi;m&^QxEF`5uGKjdLfDb;KaFI&8O%R%+PiTo*yk zM)i_=2SOt~{b}m_)nw&Mg87aaz@WJoi5872dP=ExGxvQV5f}?oLQA_+yUO=Ns7rR*i#=FX3Iur*3(a2 z+ihECGYNapky(GCvgV7J{kgOXS8@pzD zt1L7MILSOpuWqlP5O2BuSp9&>4GTE2B5oX|x6sVj>-sp4aH7|BiN=2w>usuk}bs&^E-W z4C3^iVjEhXcebS;4cp_?lfH}J8-lIH3TME=Z881bq}@JCd0Z>)eNT9%9sy^oJI5)u zU%9#o>i6`*jbQ12O4>i;8-^}Pw1(4fgg}dp&?GUfqb%*M|h*CW80(dx-(6G8G z?dsqY5qm4RhD0jV?HZ=(5fOv z0AZp~cd50?lprqwOm)hasMmGJer2QX)9=@VUYk8yiyxz`^27Abs@5tALILqr-MyDy zyYEZdzfd*fdQpqRIM%L<_4@r)wZGv(Onnj-!HcAFqa>fzm}MpBt7nlh&zN0lf1Z-d&1!n<4kn8g}gU;VD*g;EBYZfC$_Jtsyo^+ z#}(>(xUqPB&0@A$9K&9Jiux7-Z{JD5yFV=MI5l`zRp4D$LU;Y*z$IJ*3r9L7aJ|mn z%L>#X@9C3tHYx6D7SEizvy0VtR1x$S9gJt{#lx8SPJz5$efPyBeD}wT*Vimg#Kjy< zoua-shZR{4PBdoi2>0{FLrk=KV`!-9Db-DV$4l<6?x3uQwl^tCGQQ9vENPOyy`u5k zst+&h6}yw&vC1A6O%~9jV;vaKr0g1^SV-kx&w);V5;)WxwARLO~W>Oof5BXfp zHf`*V%t(PQMrYtan0xx3snd}vG!nH#>!S&<9)r+~ON#R5%`#Iml$Ds5rN=oB zjpdKp1VzEoQ8mSJQ)>!P?Y=Q)a@%f?HqiK_6yx7mNFa`X z{RB6keuS==oMN%qck}5z=!$(^blo;_27k6^5C0&ick`+0qmNv!SW;2{+rqpug(nh* zD;cjx3n^)+l*Yq7Y22eWksCmsL=rEG&GuUxeYKaZocvh~8(wn>*Wza#5M$Sjk1TV7 zNLQ!-UpLxKXWk2?!>dCiq8Asv77D&Kd@LC14-q;>4Y_UEcT9*t5|@L-%UqYOfX8Hm)w$&fmFLQ+C~};|Bxe zso{t;EN~hcPO?am^iRc- zwbW?e9#x`FVvcVRP+rU>%=wu7a*p4ouT+B>X^IxE*n^}^4Man8GP1$PeVVIiJi3B_ z7>1QEnbbW$#EyCe0Sqkd6JnjA3W+ys$%G{bVDMx})C|i&t6XicI3dmk|10HW`bo!l zp~g>DEV%dPbD6=Pwp>9&)FR=HwENKc`&NNcwJZZ<^d!|+!}e0jYbAo!W)cwJ&Sy#z zmyBG}XGmHXNRnHkwUB;>{^*P*CKLiR@PSnHPcQuVvkQ}M!=&V|om7(o_B9Jqexu!| z7(Y2$>S9lgo=g`zm=-6nf}BDZqg$XLeE_Mic4ZArNy1pgU!4cWBKm8{6gCxcburr; z#n)vV1oaN<*m4v!!XE5SdJk+f&&!MwPsj|%Le^dT6|-cP7hWh6f!NS_JTAbh(tfLq zkTl~hRl+OX;(@P=km~Q-9I#Pf$cyA(CL0#!LK*C20M*@-Va(vtC7N-L?lN8#E8L}< z1VNM$syZ{yW-ux`8jLR8^p*@+0+c*IP|cC#$0CI5hR*;(wDMih`sWheYSV`&GbDNI zS-)N8vEy_7cA0l9#I9Xh-o=c`965ay_qjy^LLZ7(ITV|xq=bgEOlZITIivUsN&CB@ z>*WbfYYzJzpd9vg%X*Av*l76X9F0NCO5e(ZIX&uCHXB*_wiWzAV zOc*UQ#UeMwPDauY)l(tT!A)|(Ap^&V+Lj_(8!*w_7BakohzxIbM2TR93pP@)YZef zb;dd>;_B}f!01|V(tHQ+f9Qx2g$={nQ+0`N933(=>b>hD4`X;g6%ZAcMGHR#5Hc7t z*2d`Y@iyD4jlH&IH12wac-goAyy>Ej-z%rsibNE|Oojz~8LSdXF1}A^>GDMMV&_0~ zDZ91sX*}BCuG)Io@7RC5v)KPG%+Mw$I0IC$J-m$)Ov%|wg_#%)H-ocm)y{O28(?PObv?H=ytL8Q&-?W-;cpb6(0z>;YO_0Tnw44 z_*vO-agxH!v2xWa&Q7mX;Z<;kceZ)vaJFAgrG&!9121Ai{ z5hq9%twB(B)r_V##WB6#LS@VfH>vGr)H}gD?OQ~6VbIUXHxGk<-HCC(`Cjj7n8+GCAYN9 zx{qQ8n^d8?Tqn3EwRW!4A6H%{e;t4l~g35Z2SiF zYJbeh4QlVu65wjFIxigZz>Uto6B0ed;#!s>Koc`eA4vd&K4sc_*QiHp71qX4hXmj{ z-Zj!#lk{gSeT?B2Xogmzs^qa9i8a~5C>6SvzP(MEb9+uIDK00twxRYK{-^Ypqf zJqACZBI>tOzF=`(l$6!EdJHtwh(C$l2Dy$=nId8SY&bT@(PaNWRd$1QPTVCbegwyg z(9$(R)V@uJpTqQPgm={`b}ibpFaCA++m=$AEAo{K)Bj>!zd;K*k+SC208`YYxxt<2 zbRYbs`@nb`wC0-6THf(QY%qAgSj~hG!76tO81Vz44&UM6tp{-g zNY@T4W?4xIo*X1cLTw*Ez0c8M?Q=X%{O4a*NZv?i@b*{41F|{Y6_%7!Nm(bTF64ri zxayDXnHvTiRy3GyKDtpa=hO|Xh ztn@0DB@ne<)^gY=fh%}VV%YCr8I7&VLvzsa(BWbnZOO|qVgUZ$a6D7wHFhTpfSKXfdC48gPh5v_gFeq53A~u zCkRQnN2GrZ;4g}{u>&Si_oC>AE)3Pv%7u8$Fyvwv3?9K%wMph!NJ&vJbSUZ9OSXoi zjAH}zn&^HNBT3!dxB0S0vqOjN{J4yXcc~q`k9|`W^QyRwIkbe}m79v?WAh6(<>vL0E84Z{*qQtHwvJt5|YC8Js98U(D z2{Ti|nck%DlyQs5r)&Ap6#GDW0^9=$fxc%BUp7?gz8rBppR#q7ym!jq3Q}ntEP>7$ zzP)ic>eu%5wLvrqVwn8TqsuaZ*kOlN)A^{>x-K>pYGMSt<^`oN2^2~p9v%rAH&Gil zcZXC7yx`!eZ_H+hUTC8L>y3S_) zxJx_;6G~(mr9rzed&2G1%1b=x(i${DW}b_>p!@I`4!Y5DGm>MaScq|mxGZ>{aJKek zLc>e zOQeq|O)iL3Y;I|a2WImMWtsF2VDn(@!909(TctF)WSc-6Tg$^JNJ|kTO-Rwv1hu+# z;@(cUT0}8RXe2kM!E=}%2O6Ug5wp!|HAZzZh^-W!-ICKN)9hl-FrcvHObR~recKex}mW_ zL?Tte=fCZBD_XL1F)X;U5h&TMbtb0Ma|Fi(02tfjyYz7bZGCr%3ZjaDe|?d+i{OY;FNHfGAZM{$<{fd07FjbmzUw*NU0I~M?gYY7@c*oXy4uZ_Qpu_` z*D;(HlT}qwGk9Hy`t z@^2d#U`@J<_E&%oT+8VAVdToqZOC|&|Wp3 zeuq%OdpOTycO!H-@?sZp=^%EplQD;d5MM?EiwW3(bz_X|-r0s@a*Kjp@n&<+xVdIN zCt%%W$oh7eV^~iZ*(ESm2og>&avkCq)RQ&wb3_LqLaU-_4dZOg(1yBO4_0H9+reWU zLC(+80u*p8c^Op zz51X~3MhFawHw)mnX-9xi^EJ&y6{-Rm7S6jPd1neLjyG}&(4B}alDoAYp_C%!T-bC z+d#>6o^_seZ&h_yclAfLBwMm%$G0jvpRp+mOuBQCHRdct4)^`F@`FdEfh8_;>Fay^sBotS0ArCL0s61cT7& zkn{Q?{DFNT^RZ&96_rz>IFX$P@?aU&M=ujAD41&e78um7Ag6UHt0g&l;X`+hmjcT{ z5ym65D5VG>I`wfq_3y8y-<8n;WR2{&1D)L=IxsviK@dGswMx`R)}9u!N(i&OCiD=s zxK>IvI9)d35eX%?M`QID{$w3qQ(tN^B*rWW$|yl8L}GcQdxY^g((=!{lajrl2>RV` zt{HOGyQls+5^dkT5Ae_pIlN*^d`mgGgYQ;^iPzbpAQC`HQEqRKd`vxcfRnMDFw6H1 zw*00|y-JyR`f*N;LszIv_WNmf0ncx`9{T`?^+#g#t_z0X51l}h(3xZ)Z60`$hF9#Z z(<#VS-|GjTS+{s$r>01?(qUJq)~7$a-WdXwzvjp!OL(mhjmdx-{&BAygz}2(0W}L! zDMp``a8lKQiFW=|`nETj_dZ|LBC#Nvu6mS3&uP>fiZB4k75OqV|mPD7vaofAYPU{j!X^_0PTco7n~{s%g4V!IY+p01h3U zCHbLWbUGbb!Lv1rtokY6lv^*O^|LrGb>oosm$-)q)Pvd=EHnkR-**A>U*{Gp$g04` zd`A!y1XMGg%7s$&=4CI@k_V_Ia>Zm#>02m_9PRpT#B%HHWbWnWqS$(X)cdKc`G>JW zzye4g8WNI)8ae!*8)r^Kt=6xJ8ri$8Kkrp(R_l!PX$FU?aG*oLmJLCa36I?i9gt5H z1SS}l#q!h>3?c$rM(Q6b^0_+UPXkRGEz#zVFi8@~wiEji6rW~^;EA|7UyZ>4QV9J~ zvh~3xERV>k{72QXnEH(Qt}M`LswM+-24@-6^>c|&H3q1M@v8vd$OaF@tVJ0wkK}*$ zkHVF@@6NR<5RDwJAcX4G&j~@$Qvh;0eGQMyB}@-ZpP-n4f+tQVO{usTnz{mKxO;zp zUcBsJaXBr2#qyc7gxroewLCl9v}60CX{V=lSRI)XUB3^=v^l}nsk$G1-pWEp;1qnt zsp5g@l1UZkcG!5w%WONJM7cqs7aU@305Yov_)YhGBIH>O?a=@^!8@%(S#Mw+aj1j! ze|5SMK{*-EPnVOK>$*>hi=XvV&w6xcOUCu`P_(tX>{Wh<14CJc(H~L z)L|Mrg$DiO6ZVN zYzFn$N!g&38F-*WZ=tatrP1#iGR=-t^+_A~`}8lF$CI!YSs_9kS{Gc!FNblOqz6)! zx2TdU(&HXu&N542f$997%=Qi!&n`1jhWCsLZ%Cz3+eyF!%Uj5!(u6@>Q*GKX(-KpbMnDEv8CkaD6 zW*cC9efQGt;-!=FC0BHNd;7aDo!Pl#cCfs(h#Yom9faChxLTBu*tlLd1E1*I9Bie$ zb#bCain{#Edf^p%0auuu6mov-S$qi>x-$p7FM(C|RJF9rED|}$xYhOH9=mjRn3uk91^Ws73i`~E&0*Qrj?>#}+ z-uyqFgRvl#sVSzSf?V9@+b%wt>kPlhFMdDP91lo^<+G1N6?FB$=yn5dkD6iT3cNL6Xi+f}}PRkwOLZmff_&6L?NkRTA-`~y7FdoQi$7Yrd6D7* zL{GhlxP|idBXRw8qEAgp6nd#<2Est}3#)2Kfg>TkFzPlb2QR-c%IleL#q27|`R?3c zc4nd9d!^b4MEH0@gvDn3!*s{7SP z3y^^E9*jZKpz0ztSMFEw8`kZ@yK9aKm<}m-pgDP1bXL@hbf%NT6EgmJhAObXTCd`ag!Ut- zK=_6c94y{Hpgs%V1c(#tcZYi(==|gW9~Pev4lrXGCQ~%zj>S~FYcbU>dyfpkvzqFV z-boqHz5hdU}rvDGpf5eg9|4&c*FCWVNe<1aLBKq$hPyJsM)bsRDo_g;8OPl)t z`tAC6b`DDGbVSN_;K>h7uLwq8y)n))MiS`r82`(rFQbb%q<_D=yS9Q;E63Q{uv((Oy&cMP_OX5qt`WY;x^WNCNKn$hl zI4{I2gUOs&Jnw{2mYal+yFs^hg3nCELWuogL04EI~5-rDgO~frX%rdu|}IhEqgG**#lMp@f1g zM@h{%TTt={&nTwGXrJcLm~-)+QD4_R#q%;Vsgu;JPaDdNIFED}E26XcSd8wSBNEy3 z;&Cl4BeqnY`qpKX4Y_$4wH(B70N|EI^paSul!7e8QF)Q6D?wK-Q}s~~Ca~ty34{s< zd6m}sL_V3#a|)5>LH#heb)fT8{Yf7QzfcV#D=pvszO-5shwyoqHh{F-SPbBQl%*5! ze*$#ubY9aDTCHn2`MiIM3KD0;fi|Isgt&b7dA6KVsrTk{I~je}6aK5~`e6`eHa{UV z8kc2)mKL^}%fCbb>wO`gmOz@;rj>U+tDYLjFVvs*Gjx!fmyY>55MxoEZDKjEDR1P1 zqVd=BLG!|poB7(mq4N)EU26VFG$RO&S`@Qu%nT9{ZlV}~!i{YxMpI5Nyl9His~~Bj zn03?$5^j2mL;jxzg-EA`tFWA2{RpIiNs`G&lRF0~oD{hngS><=pnpbumKgd%$~Uk( zK?7R4%#qF{T7xq+&pgRB74m_9<>%DVDbive14H%w44sm6=kLeJ$vEu+@E*s(w%<9) zJ8Qbf>6c*bbX;p5>=Y#q8N>3c#zOc@GbCYPQ7z{C8p30AdoB&(INhwqXioE$RavgE z&IVAoU7p10*{sb zd&?G?^2v+6`w=i%35?4Y=%yImsR6qUa!CyHLh(Jp7@TTN$~;bdO^k|l6Wr>n?Zb(s z6t#kk87`WLXh+MUbvN5=F}^^Gd7K1^XT!AsJQ&n&Aw#l0%>wEu)!d^PHj&IcKzT0A zFW`Uq{d%2iT41jwekCV+#9<^5`$PQg$ma4**klLsh*1N5O)#n$bTKQ6hK zFnCe8SxR%8Wcn}bB&Ft}rt}m0HF^%UKM%4p-%`QeF z&2Us*CP(*3ejV}{@QvUDE%?{Rox`WyIhWPD!d$y9jB>lf#8rV1FK#DrZ($NTv>L=iOdRIbD$Hp5hBs*!S42Gy11s=S0&c9N@t zKD7uZp)DWnb4075o+v9U!z}VtW(kDg2Etj&A}O2}sVaI%UR-KMRlKdEujc57GzF!q zDA9tm9-B855$1|Q_H#g#dgmQ^t1i}v;JvvKWvXn`2+B0hRibZ7BUljZ+E*r|wcUa; zHX?V#fxGW!4Ey~s6IVI!+3^wsCnHd+%A^;nC0gi@e$3e-s(m~spw1DiX96i!uLc3C zQqJZ9nT~l?Cy|jtwg|6DhHwhBIQhu;_VJB!^{OE>isLJJ7jGSYL(3b!j>c+FSH$A+aQ0{uK}xVvfL68rGFUCGk5W#` z2Mfx9f^{e9TpiA$#4f~XX7kk*Z&q*B6~=shN5;GP9XJ^){&Xgl`kLht^?Hf?otNH1 zw*liF@_CQJtV;!8^i&?`Ojd+ugqa~CzA0Ol`L6KN3Rx(in}RYk)qVh6y+o9z$Hgh7 z7_q!sp=$2UJU{bhtGE38E&<)s^=%%lfr7@xcq|_)PuVq}> zC%OZWYBOAi43|sPxYn|j*#cg0uziXdiJK_!LmDSBT(EHT6aC=o>{U{LAFh6qPjgD5 zr=th^LY(_#y70Nyhy5vk>GC@#J6}`Y&rLDBWBO!Q<$dY*8lUyYAye&v_@}UoOZof& zNUM0gX z8{<@}hv_u0?y%3wuU>kvLkyW$5g5o1G1#5e;?a87J4ZhW5CpM+-{}2)j)43r|2jE4 z(J{K*{ow2*atjG1RK;X)u=q@&WM%k;R!xC}rx8f=484rdT;WHcIkL)YnmjtWgawDS z9Obxz^vtEv%$sQDQs8vS(aFxkGz@+8)2HpuON4X0yn|2YDgjb4f!$(NP(CS^3*5dG z`ep>X{WQS7YcdB_aAT*gK zCdiXD)Nx~AMv6`tF_bjbVJVUN)hp$ipm1ImBG86HO;L(& z6QI}->2U7zQ~KOP?d@45kbvz6!HvTmm{Q>5WR!Gtj@-~pE@^N|dJ9(4F_9NRu@f_7 zehI}DVxr5Pk}l`tIs?j2*rmYM`!?1-KfYBc2Po z6j0>c+Rf4P{~686%Y}kywgZu(K%?S ziFH9yk(N-Dzi4L~!9ZDc3AONr7%vAkrxlLVA`LhWM9?_f(-@%MV{!`dd4GSrQ@Z3y z=>X*sxR$ITg$I*RjzQJKTfGxR@o?FmWqp!^7EhQZJXAnHG{ug^nKn-M`u!lo9 zQsg9ru4W!j!&xQQKB5$$lo$qEvKkI=Qj?bh$?@fqE95~(8>Nf`(S|;sgufzCV2g{@ zWw1lQZ~#j}q>9M^Bz_kZf4QD~kC9!LEq68?6*C*qV4ft#hTR$hYB+ihO9UUI0;;7I zZQsC4V0{T-&_)5JE8&@~(FJKfTRTEVHX{ojXP#U^!-^U7=wE4bP zD6Y(8q9+2&D1)dLxuNyo%!42+nQc#BhzV)1{v=S5d@vcG~00Hy274*^T{4MXvs)Yf|5 z>*bV7$jiCWNz3^jbT-r^R`X}lN}g6DpwGMD7Ha1d%7=E4X?(@ql;QVkqC4zTx%r>&eCJZ17dTT&DdkWcmB6flG`|t{H!$?jP?f zww+hwWF7={vEHzVBH%&nYY$>yYY-PgFgo|_nY9PQAUv3L2BS_-_s8F)Poy=0?Xq5- zV$P~CXGg{yq5D;oo!pG@|8zRaSfkA-PL7G!=E44Cc|2S9+qkp&RiXJN>cG*q`PCK< z5w-))a2F@J0GlnZDoHTiZ`Pu4-w<+W;X znxUxO`})#HPl6SRGo49@EPtdq7ugp$dh_k(eMXhuCuQRp#u{Tf_;8$R5adJf+*4na z%`3FL8jP?EmTbEkdQi595K{;>el=Q$n;^`Td;9;I!6;Yx1Z~h#6KIH5Ck>|44$f1z zm?o3opUhe{k=ye}dkd7))5f}n?_4jSEl+{=S_6&Je0dnnq?w5s;_Y2;(l#@}oPzP~!ic8&YSujY9WfrS(@U-Pht zpZ@6Qn(Ec#gY~Al{Ie-iV<~C|>UbN1my-DWA_2l*&^#f04kk4B`G&d|pb1oJ*jynt zCsp99-(ffKB0Aj6(&oMv9creqw(Il>Yh(B4g0&LGnzKZ_O_)iY<_ACbR5zV|2vL8l zM7gzv80k zX9Hb!(q`xrs7{Ao7x5tooJ`cr}<4&0=hN7&~FEFRhM%N|K*r5Nw1^R9)bM?*D{1kV_kT6~@RYK0gdLdu*pagwabSD&odUgZ-QNS@^XfcuX5uW~*-)zouG+kA59I_2BsL5b4-e z9U9lwtKc->1eYm>S}-qw8)`Qp*TRz|ih)$$05V)Ner;6{fjP($&Ww9BHBVF5R+r)I zS-^9B9f))N_y)m%q@jsi-SCM`4FYZ%8Z2t(>rX9H^f&Nj)&tbeBj3TcH^BDK?=QwxDJ;P+2kDI?v96GF0&ise3q^Gr@Fka2)h z1P2B&PI8JLnxD+eg%Kh9ZmkUaL}}f6%`R*X+45n8V&)__4@8a}%Qd~GOoWs3;Ey)u z0;p%T=kFP7kUGX!M|HUQ(F2T#4Oz^toepr0R0HpAh;mZReR@-(@pYxDmjGd9*6-K5 zFKt?xD0|=;z%rK=9J}?p zvm#E-iAKT=%uXp^dnB>m%i0+2J#+R=2(nH=`Y~PDwsFCzbhBpT1tI)$HoAFU>L* zCPnhSX9Es7TU=b4XH-m=3v0o^eF4nt*2l6kzQBmn*wF)Wmc^GDyHdShzo_~whHfhZ z|F5}wprgBc^Ighn=Xv9k1omt5F=<$XmP$B~yprAeOWJ>ue?sn>49O507fBve*Ru1) zmAc)va?rKC0CvyZsH;H2iVnC-Px1q(A_KDWOEZo`^U^ueUj)f>E|ri|j111R+dRA&2t>vC-#F&Pbf2(JEfN7?F%$ZQL)0aE%-- zsGTgq7%&GCh#H-$SUR0Pk#r)Ng|UifojRr>S1g%^;iZ!MKIJk+>2xm>{+5hCm|mto za6s6p-3rFe1{rfp4Z7wF)IGI}DPbMPbZ+y%K2MuTV7od%kU(xzWl`lfNo_hY|9O+M~K4fO|8{*%&u zv82-wT6ynZNz)2X`6g&(;50L%P;W;$^Qo0quKF6gbq;jSvF%FC=HjiW{;%@fQ!AGY z>m}`v>QoCibPn(_xS?}3AK#!dP#wv!ijPCrAv?9LiH*Yo1# zY6-eHY{5wB8vFi+v7Kg&3m_xa_oe2POqA|omE^mhN^A3aY?5?W32SUDlaoGZqa4|1!tFcyD$mO>sK8A!-o_Y(WBroE&MIqt=J#Cg5McGhW& zsx%@+)^j&ai0vl|=m<^3b11#bh&|MFPkYuG+G^*EX|vl{4WagGyv3i*URR{Kb?Yy) z&!^~ISEz-Fo+AGVRtWo-OhBp$iOlgsB!uY8*O;h>1wiw2i96|ROJhDg>C(x$>pBv& zoFi|x*HMSWKh5?0;|h4D8u1V6DNFz183A2GTGQE>Y=70UC2^D_)d+b+zv>@hH>9+P zLK_k%rK(QoN8Th!T?0zXm*i8>6gRA=xO~Cz4K!G3Lnv=iGUL5<(Z?L&d#X0Tt&VgQ zR5@Nm*B;Zl+&Q>}q8Z`G@Wk%&vZ!8|3lo>pG`00q=4)wJ!K%uxpw(W@E?`=@p@X+V zyO(d%uc!h;V>ffLtgoZPxA3XhqT?8&C(terbdE6=LiF(lA2(qWTpvj$728rr|Bk1` z4JI16`q9D4HV!IuXf$8tL`!iME7qJ!RgJlWJ~1fX$_J|W?S=qMBdw`@UpLEA!)@NJ z3nwp?^+^wn0W!3hWK8rx=Me@eZc?cGx4zN7Pj*ZY3$hyc+t!o!)Za^qf_urW5xSO? zpWzR#1p%B?M@FXM-mX%hL-7lmQUzy?V(K87D=~V}m}i;b7s?NznwjK_hB-n?~S?G(tu* zg@6b`_HIF^T)O3MRCWq6C>8M%%!>t8EUFe=Isi`y3Hus6rBcvYi8``BJSnf*KRwaL z0$f>AlhQAvcC}A9qJb%sOv9??t0fW|!FWbMLL=AS z{j0bt|0s$`89ShZ3bn$jq9m91S^yC4{GQ1v&h1XlETpQ*x_i4rT94QMHUFftlh<@%ml zOSf>;3zstpSDZn(%NdM)KcXwjXzW+J_DymYmG{;w<%+Qh1sGIQaSN+kxpw5=LpzM1 zt5jKyfP`9A+*)x4qrogt=boeF7JckZ_~)%`co1?QJs}q2nN?KEqVSk$u;1Jm9XTJM zf8`ondJg3xaur>Nnv}6>j~VlbG!Yn@R;ZP!*xGRp&9S_<6MIGq!a0<)C|*(s(RAy^ zF||xc76dhz{(E3Pu*G}%B?erOXYz3~t@~01@HGW!RKszou};{A#Qp?+r^?n~8ydfV zuc^tO2k*p~KOiQ<=f^vw*7Avx=G?{q!0$QSkG;AxRuQE^VzC6hPZZ@56O?ilyOFEN z?y$&Jgg~)p+-X5Y1h|%S6;%UnIL$9C4tC}a7jX692Q)5$p=9q?65^sW4{vAPBk_=o z-fD2PULf(%;zRRL=E~@I$WtBtuAy=7WJ%Mau)%}^lZ;!(1`?b*SiFzI?;=r%S?3(< zC`0qdoKo2LBP2OS+96v8FzM)RiG*Sz z^G+lLWGE1-3`17{mt%-5Y6KfxHiwI27^C4jW6?}H7Bo#FAySk_N^O!eHj>l0=1Nwe z-ofH_Wu4KJsw&PM$Z4#UBSIa~aBqhH3elV~*sT_vPs1QKV;nu_Csb<$h+G);F0TgC zoQyqCK^lUvur+|o^SKOx`oc%014b@KP6^!iaJ5f$(MCU8;IK!;A!uC+tNvM5epD?p zpNX^ZD6FS+zvaWlLtsv|tVt`uEOPYFdTu~li3y*i{az&+xYt#l&H~4 zCS(Vi24C-Nu2v{S73YOWT&DF?uw_>lJkYsLYBLxRx@)prtmHxo5E;2IAf7ojg(Yyw zb4|Z-r(!WY&?{%Q))lWrST1klJRq$`WtU`mME~@gO&!XdQafj@wBn=V^1IOWaQD93 z8oY>n^rHatU@_43gT=f!c&M}S7Jff2zY8_al8V2)l8Yv>&=zJ-tOYl?5? zWA<=?!IEIK1}qMA?hWO?tRDw(#@kpYzOzGAkN}~YOL*X2v>$kACNV4W>e$|^`E_re z%xT}Ji&~c$39?CGtoE@@9cV1Yz?Z8zK7y5xj`M{g3QCB z>QK3dMYp9_M)|Lz{t!4Tm8vO020GP)(T6#q%!VWF+rJvcedrJ-4c2kWuIgk~o#BJK z%YEY-R(9D1^Ty6uDq_RkQBy}Oh?__qwp(Lii{rEj3n(y znPm%PDSCO3Pmw(vbpcoXO{haKy6DO?9{s#|hB_fGreeIKUm%ZEpyjLqv>@S}^9g+t zmxPv6;Y-`4cz;evKTO~0zgMlY77?Brq zhNStRwPj>}l!RO7{=e{G*I}8aX+6Pa4xVw@W!}}}lZCvO4GqtG*)GEd+==_AWdkxw zZM)j74>pcq18Nfp28H&qv1^wkb&8L;3!P zqeuH%uw`vv>k`t)_|v3GfiZqmClWw*Wz zXi+9rlNKdB>W;UrOxV03Lrgo%dPq7KSKjT1m7fk44Xvr!-R7C0q|v4KtI^d_#>oIs z{n6b3Trapa3E*!^t&(V}Z>lG~F!=Qv%QQ9bv|8u@5{GOF*ALc$|@S?1hm9~(jv~Vzpb8x&R~<$1B8Gypk@3n|40KUxIZg5 z2S~?sdST;TB3?AZj*-2#@u+PkwOY&6vhg<6S;pv3mK|S&W3An2IMc)@>xy`T-xyhjSYyh*zl1=W&-NKmRc`)PQs^e3&KSuNfje1Ge% zyArpx#?5UCsPN!AeWLQ&yDoZy>$5EgxXRkW9P*2k`OM`7A$T{ejIr_Jz4)|ZSRIDN z0(w~TAj!PLeBfGZNR$lokgD$38krQwe<}XbbZa!+)E#Q8G{M^q44PEk6VCUOdZWGK z`m6mJOhSL&K6-!LlZH9^co7+r$3(Z)Vl#J}YO=T7#H6c@bkJH)W<7QL)%SMa<%gTew^b9NI_uCS`&64FPA2f8v2(O~R0 zV3G6{?5tw+o`OxCA{Q0QAD-#YNfdol|vsnZS4I zDHNYACNJXZY_HcVgZdMSjGNB^HX0F+6-O1kaf?x<4N^%l} zt57@Eg|^`?pB0ZwjUh71BSIAoY6eXJi3Yojw$HQL@S>+JSqal@wM{q4TAu=5>&V`u zKzJVyPCkGQqY;`06+fOfWP$mx#eUk5MHK~O@FU8QojRMvGNe#>Gge2Inky=xtIK8a zIzI3U98tImCs@m#lftLX-Drp8IS#57C`*&q5(wwrBm*=oRsG|p zDs?7aW;GZjVv+UJ(@Vgve5;}sW;Ej-7QjXaO2z`{DtenN&m(2)pJL6*n^xa^eeF`u zn>19(L{+V|Oz9gTLJ}-&kw!4}Hov2>af58620{vKmT!?wC3n32-+03WD7jrtquNxO z+I5r>C>Nt2!O416clBZEp6R9}vngQ24sC9ZxGBBHW5Y%^`R8Jr1Ln}Wr5a^=*4P6L z!0@L0eWMLWc1lNhZcEyThRv}um#R;OC zS!H{~M6BnU3snj^N`xvxms3GXrGjnBp(OIeGopm+b@-m1*O_eE#3bWSL$RmgJ2k|( zAUwlg44ysl%543uq4|dOw_)bC^(Z{(ff;OsB2b?c!Pn1XQDrd?Ha(3+WqXehSvCug zgjx7HG^bLb#E&A_#JNuUHQqPrg$ ze6=i-k4GUWl4ucfe7^?)LD1Qo5|xjmOhh$%7pi)`XeDT#lj1@jjFsWuf`b=&AR?t)pad>hsPqNslgNLMt*g*(HnN zqT_uo4^va6C)8B8eY_7=+tCR!FlwfZ)DYD+{#CnTiXN#;4iy1Jd(o)tPPp8w#V|N| z1y~RUaVqvp!8f%RC=;M8I>=DPnl>69E>5^iQtn)q|g}>;9jHW1_QmJ;ZBq|QU zs--S*U);)Q`tA~uAm}zYpZb}ZHYnRn;UGm96Yiy{F!P`Yd}6FILQGFGny@{c-Mb5T z?1OJMl~A+_E!&eNJ(?<7qhi1#6jdaWjqM2vjo4=>hKt~PDlz9L`7{HDct^i#_WN`( zHV4{pRDic-f4cq^+-)8HD!uB%`sDXxV&x#!nm%FSvN*M?_#vV{+GTtnbU6cGu-A>0 z(URp&FKBuF@4YNd>=Z|@ETz2QWMhYfnmk4JtQ6lyS}L7Zx^HtqIk&U8C-Vh|Dy68XR057Ybv3Ac0AavrCu<1+S~kV_PY-w1?!U-LMJKCxzTeL|ZA z&^HLzEvA`ZGP^ELER>&uTDnI;!*`C>d3x1UvI@oUN{XBA6Hv2E5fInctkYtNRer88B z^Cp_v0b9mtN4=ci#;>QqwLam={d-sj*hxQ*3+va!4dAT1>g#a@s3hF=;R=|=OAX_v zh7PuAbs4SzN-WasZnwbB+IuF;;Lli`n{69zWVaic`o~UAdCq zPzT>CzCjjzy8`d0>i5WSoD0{%Y`7g}WW&*`d<$UQe8nQ>7Fd#q@j9ffUnE4h{x?xOhT}1r>izOUgT_ zAKI6Nl?~a)ptoFD7v9FN;JaF~NBHHLWCC7OemYblRb-uH1fGGK5-lwVPs0~NM7lm{ zLY8IlZ>4(J$w8sl)3apBDfof@!ij_N&b0CjW)p@k+~p%CzE_1fJ2YNs3qUF4;vtXV zD@j`G5TgUN#(Xb#Eb4^Y^Y_vI=y6dmXsd^kuzao?t)J^6cJXy2#ngsesQDjJn7R}0 z4)Sr&h<8!d>+v9wN`x ztmHcWjwK}dx+=FV!)}<&0W7g_W}F5lA1h=U%4`iec*@4tnO1NdoKiJgIXbNw6r(RB zIkZs#p!UmJT-%25At@zD?63{B!0F|$@bdJZAh|)jNO~;JBm|BLxb?mTtc3;;z_`Sx z;CH}D%NPD)jJ95|F}k6p!II9#Xhq0`*Y=~9qkM1=gLF+;C$S+(#CV_6Zwyi-uT+h- zE?UEVx~Go4(4+syOK(#cLvl%}TAtzf3e2r4S*3FF*~t^)ik3ESl9Tk%oQcE}Z^Nv$ zLCW_CMan94pY&D&71@M>4o743>>6E>WvaE8&zyo|=$8fmdabgZE9lvnp({RPt7z(W z&f6%J8%$G_`UVAuK`Lw90v{J7-$Y~Y=aR5J8Kl&Vko~P|kM{Sfj4L*%Fd^BXXu0*d zuYBbzv+thl!v@)fjB44S%i!VQ=ySqTLnl%==H62%;-_DwC(uKclazNhe} zl7ToiMC}EgogO&_q^1@mTzVTb6u|&LYhGy?p+tFtnl9Fa=DDSbmI>N4(Ka|QZi23a z2|8q-qD@dNC#j}RmL<%XEYKaWP0J_L%p{+BfoAZ%qi`Jp7q&tL-)0(%1VL?fj)2@n z%}!7XBx=mgl?utV)$II@=QTU^+6Bx`!fPqz^@3(6Qm$=wUal&M?8`7BFAcMEht1C2iiz&YX6Fhjg3Zo7zB#D4t&~^LEg7AV zP}rP1nUeB28=F(k4bCZ&p{B=?mKQNO@2zEV4rFi+@`4&lX$}Ce#l(ib{ z&f4rKjeRI>7V(U+yh)oK(1WyDW{3{3y*7);JY2k$p4d>}tYVXcbgFQ?SeMO^m4dK= zu4LL{QA)`!Zz-kFaESVkwUkoS z14`z*$fqirt4{vuQt=%*!*k$FWEsn0IVYKDQ$Y3fIr(}U%~aWvp=XMM1Wxs09Tn1s z{6TG0UGSOP2T;zUAQ85}=!r&0<%JDg<=3c%V|=;ak-L+S&2Q;7huo#nI^~O#yZm)s zni7}JG-m^pu_?Yj8Lk{@stTF$7xg!*lG=966?EEsMT>u$QtOY=n!cYPPeDl=e0_wk zZ;!7hQSX$Ap%9o=+V<;mS18JOpH)iSBkh|TRDvh5!!cFm`ehZG4xK=$VG>2FpK!24 zvs{}Yl(UR6@rSn(&FLzaZ@r1;98(VQsGZAK!Ue@Yj!h3jy}wjOpJtS3WdjDdTHX=C zo3{&bq$}G@xp43Xdm#mH)M?<phi&H#(7J z+u+Ud9uI8^-b7D$+D1<%Jz0Hi4c>r8^XQWf-iTPBKlJ2j@a8Ez%UrL2@b`}syrI6m zHcdqEhVZijP`t}S=*l>DLRbEz)_D zA-y37a8ws!H2S^m0yyIPDPzzsfQmA20vWHM=yazqwRC4Z)SGqZ?HUoEIIoeG_S`gL zt^&`&8>t`)W=H!9f@$^^^wl8&9POKM07of=vqGj6z!{(iIDq3htIBe>-mRMVNTg7d z1y*fs5LgF!@Iz_LL*fz((8_ECYK9T0VL00dYPfL=0~sNvQ=n#6qaslAACktrB)rsy zt<8ZN#4+1LoH2&LR0K2DG6!nd;ANq>Sz}h}jZ6ARq8JZVIa2dhlw`=46nk|zgXdV0 z8fqR3gya<7N`ET;A1br@4waeHRmd-d=O~R(LC!h%yHhGNX@q#S6uLsFg7ph%&Vn*( z8}~bC48k>10%LXW8V}58@Ls1(!X1j#pkPb-No(HW7hGxH0XnY~S%d(7&_rrJs7Q_0 zMv60k6Vl;nlj^*~s`H@sQ@SMGnRJbPJPI83LdHk738~z=jumzGBCuq+K@OH)k(wRu za+YsWhBI=LQ>%V1pEigM$`jVpY2HZIqXe+OHjx_oP^3mrf^V%XK@JN@S%N$9H6nPm z3N7WiRe}Y*1BReT4G}mZHQ>G#uo*0gg%pP2hOH}HeVab?{-gfkj;7n>0&(;Sf+zo6yyKSgS~ zQbXwUSx(f}=h+mg!MTY>XGd$KDa-&Wq=d&2j#;=XDM};ohScUwahT(q&o?1sEEdhHbpLU2HBd|=_I}<-aSXZ!#p0^ z&7ljHliONOg)W{Vbn$89n9ybwBpPjK)XnfufGy-=$ZVUeg#Gb!G1=A5SR{1umhf`>9?9cMn zqPJYI#Wb3k*T-aDcU=IMF*wS_in+!)`0~sMS1>308U=Wl~zqSDK#)^08@@z-|GZS<~uSgdo+C7+-(% z$9$4aSoPc5*&lP;)06FI{L1b)% z<|1y-yHF(5n!*H9Y_<&(C=MWDqGt7pe+5^pNSwpyAZ>0RKGFn-T{wX9bdqaR3zr!>w0E9G z@icmVwAi*Pl=xDgI^U{jDDYxd#S<5{D%6`s|2MHJpio;C&z|}4;svb=9{TE875~vz zMahsGcf73%I=PTl@kFvJo@iMW7~;=sS*XeG#ViXNe6f}Vul(&Ti}M=!>RJ}eTN>=h z%HvkcV&^8yLZA&!{WY^JKKnJcEJy)s8x}W)VUbe6zIKL%fIKxUglfsK;Oh%8EcC+j z7#1H2!-6HUB)@=R;ionk7Um}i*{_;mksE9q7MeboBg4X9zov!-C^Y($iyIctSc+|H zSZqinA)21jCx*q7>GvnZzC&rX82;ND7EdL^V&lSw1%#i*@!!Ub+tQLv@wpdmQ^a6eCIt|(Nde+? zkAmLs96f9762g%4RF3{sLzYS5vA-~r;$t&gOo}HkdN!LBJo3CI1vLe1<)P7ay`G;ghOgZh} z#ELj;a!yu6aODeH5v$pV_`>rV5or1sFd~pn@56vyfl#*^5#=_f1Eeg|;ZMVKINLHE zKDxzpAQKBR-^O%Mj3MXjWJSM9ro(=l4k>Zx3p^+*>;k647q$sTe6ejhq}?Q{7sGCn zlWceD>DYVK6AA-rHIduJEC;3UtZqr&fp^h@*robQ#zWdqGR@i{B!S6-j8`;5Svxrz zu~M&+<_^d|^w}pay9EcV94S?kw6m^X2waTMw2Pz(L@2Tmc4H*%Yzjok^$UYl5F#q7 z!(snytGSSNkgPV=LbHK{YIO@B$!dfkRwDv2!cN#?E6hQzib4$9Q3%?@R9Mt3)8aIo5W$<+M6zA@K!95PDi{h|+xXkr3G8>+6oFW^3b(k$Opw_NeoTm* z*MVOONa!1CXapp14C}W*t$A(}lK_x(=FKB7C?+8v*?BREKgV+5)U;|OaL=(P(_2SK zB-7Rrc=QrM2TtPU=wd|-KtodlUv(1i^F}1d;c43qmxtYua(HI81S9AQH&O&6a0>zu zr2xF3U<6ak!3Y38H5tITWHCTY&mW24@d5KAt6jM-z*x{D zn{0(<8N)a8w+%r=b8R~za7<=`zI{!t1kh#lrN&Bd1`fPe?i=AV^X`oPi-jFlf<4Q} zO1Xk14$#WIF+@yD)&Y*I4<#$%l&l0&e%s*(?S$AGewbxR?1UjokY32lgj!hBjUtbg zaj?LLTUNrH9ICnQ%N!Jyh7q~RIOwR6rsxBwU%&9^L)ufI=!4XAX-GNOIqz;4VTUVM z&fUC|UB|iOgmz}APJ5rs$4LPIqKR6hNQGw1gsd$yA!@$%B>oknaLX|#?d8AR`7w$a z)TaqablK0+c;v)G(u^bH8bbrQc~!Z~(G>PekA{Y-ObpA9Y2?BOJg~JXgRfrGJfoMU z1IC@B8+i^o{J|>xUueJzYUE^ZeoqfIApSKyOA}{uKJwnMXd)ll@*upl$%2T8C`fbQ zF;Nhn8E69sn;EO26S00x;Ymyued6dpFA73(3rIJt_sH4+>-U7oqC_k1P|E?C?-+^HW8P+= zIxp0vrDC)Oo<^i%Fq6x;sNA58q2Ad+kcFhu^cZ39^o?OsACKUfC@riapURP=bt%3w zUtN}7V9#y(#xcqM##EOHtAJf#zx!kkZkLcHUpbxGWSILArB6qqO&@tMwxgC6w1sS) z0mo*K^W!m5u!5)9op6zO%!d_F!GH6Z)lhq%6eDSJ;6P}0JaH<3rmoOThL;PPnnQ3) z5Y?Ha)1;*)XagCqvo^xmFt4;}Tj#?8Niw(osxhyY;CkJOj&p@H*e96ZnVMJh;n2Y7 z%O)=3i=ws><$YTsY8&%vMnP&R7_E-=W)r0OYtgZSG(42V8RnH+CrCr0|JJNICH;K4 zWnK}`T7xO*_!Y-!h}96I!5Tt0L~!RA4Ow&M7btqNu2S;cvb4R;S##w!HWs`GB7)~Q zJoAN?jdgm9jl~{C`q{?D+Q?$N7=1DY#E+${DM!==h0Q@7VYaDM!ai@mNC{*rs^`?Y z2dD2Ssm{`b5K%@4Wwd$UAhus~ZH;SM5XPFXfobLa^!E+`3DQvq$W;aO{Y<35`MNeq zQTfPZE|~;(X|-T7Ww(lJZY&VBf{e0!0fi%1ufuJ=DuZtqkLZAu)P%1e<9fyQRnjQi z*E!+fYA(MD9XDTguq*#ioA0=;yk0rH5iS!zu?K(CMUdi>)CRc-v}mLW@=Yc(#E{}_ z2ztIz6_HChzwdVoN`I$rj>C)!3@J68%FS0?i?H5X^&-ahH-Xk4KRWr0(B#ohU&+m4C@$GvpQt;WONd3RZL zsn05tvzh;Z^f;e&ylMKBp!k`hETRD6kvr3@DyQq(cs|hiCeH|iLRBo_p%XGI)s?xx zAzw)x*|T2t71BR=Mhk&4qwlWE*o~t7yxEIyywUf!YK9NxfOHg<fH*G~qfaNQ8BL+RN7&b@`7(-e8u7^U7OHjOo~aKms1KbfJ^V;XC#5SeQhz0S zQ3!b30xT@o&8YwjUvFs&utZ@GCFrJa-UCMX#)VRV!}Sl_i9#_NoC_44%tPu90!`u1 zKEpwS;-&jxg#gdhRZ@%2vi00#Owj$txyI@(IsFeX|@OMj&5b2ld=m& zM^)aSLsbRc>P*V3Is+dhLE{~clz=#BW`vf^_?R}CB%R?+=e5_%?QMJHg1XfKXGJtY z;oaeH%$Li7*vF~i8SAP9gJSf{=(GAKnsr?qW_i0eq&a3T@DeW<>0Q;mS=(R0d|r!F zvt!OsD>ik)SKKldY=;O zSS%66G2YeP{iy^tUpWT@Z9;7Vj=H=%>Vig*J+9D=%q$M;D$v+D&Rc8!S){2_VK2>x zrFgMXd|e!Y^Ha<@StLwQ7f?u-*qWQw6jyn_H@;H#g2$yjY_UiqkL7v#^aR>K=Qw?@aP zU*#Qi9Q1vT+z{FC-H~N;2bDSeb@}*D| zSo=E~@py+=J4z_5{baZ7g?v2Q$VUS-a*N6%g8#@dO60kTt(%B#7bt1(`sjy5Y$6eQ zp){sm!5`&)8we|r+HKAe^CsK03E~X&waO+4Em-;Xumj#wMXIYec63L_;8F1Ku<~zL z(yz7=;J!qm04arJ5F2Q4yJ#o!#*Htxwb11)*OjjdWI4nDH&~2f6i3G1k!osseOQ61 ziov>@8D8Hgz4g_+CrU7W-66FH$OxGZO*r9m58oNnepUhCiBW0!dE6RGwnWMBlaj(b zELcY;^0KuQ7j9ATPIruWtkCyKg|h~;Sxq{V)g-GPg5oY|Maq)%0>&gq>|nOGz|t^! zbV#fki_TT|A`uhQo75y_6B<%&@Zs-gW#P|@m zj1D;$fU;Ox1QzdC`y4F=lRuPt+yu4q$oBs<0HBbeSuD-X&kbg0QZ>L%&33Vlj(JYs z*e0H|!#GrZ;04zTFGNK|v2blBPtW^cW6wNjaG)J9>7GyD^}XDdk8pF3j%@kf_ZuKM zKV%RAqpP|uDd>ues#|WMBjjHYF+_D769b%}qX=2*%^P;yVo2LT-QC(EW~0`wA*WsX z9p!c0;?^EmhfW;S<}vF8Ss82vr5%N5%(b6;_bT~boN~=Q5GkN5xfAa-_lkVa%D>-B zFfx6)JK3ZyzzZ4WplDz7fOq9Rmx1hYRNHjHwmxIp5kqgaZNTiGwqwAAuX+lYRzI>y zOiiseW^_$d(z=G1#dLp2===8V=;iY;TiLgUr$|Kh2izPWf8I>J6Bm19Ko)95W2i|^ zs6UMc2%AP8Da!JNGB{f(>PbYK>144ZI?^x7^)`C0*-WgEPf-xVQ%At*ru(0H=Ds*0X)A9+R!Vi|TSpi&O@GwY78n)a>tL354ZmyTcOno08A%l`G z`GNaeONH)qu=u-&JJQQ>G`CLTk%j|LyPmKE8jif7S}s(CPwBf`PjX2M^QvtZ<^eld zB_?fC{tFr_sQHZ*3i}*qa`%NY#o9Mj@$%`G-@H$C%v0G-zGwoYX~J*fF)R=k5xTal{aCVS0Xxu z@@vYg`MmK?t^pN%-loU;-06SA^P7Ab%4FAEWU@6L4{hthL?9qwb9F=kf1-AE?}$`Zl`rCVK-U_R_cX zG5RA&oF{sByHyQtVTGol4$0d$u-bMfp&1HaVaiaFoW_iRySjmf9)Ul zGJ93gX;j_vNO>gM)!2Q+*{#B8N$y#o1qITiXoZ#0{4`A!twt0SOs=p<8m)=`!1mSP zn}+SG91T3bA2{++!RuTeyeGAp3*Zn0%a;Yb3VvhH1YJq7M6^M+aO*5&F+#Ld+moUw z;$=J{bp@Zs4Or`Bh;q!A&@wLQkR3@9HoX^&32rWry6ZK});jac7%XmYzUENngag8b zU!*3Hnibz)A`brhaDR$L-HFycnb8WC^HG!-vM^WvG^n$J4mQ!9ikzLQpu7Q9Lz zeDN8mAr4~Dl0tT}nRua57Fa4h1>v%cSE>obIV(&Ptnla*55gbn1uI8mLeFd0-v)YDSxTIEKDo!fN4Hlg01DWCKLrDZK>##4(Tin2n2~_ z!-#Q960H@TQf&$fMh&0)QPlHqZjPK*8*I<~3@|b%#CB}AHCW-31vS=$gd!TaKp-y& zn%5;d2MiuCM8|+HbT0PUKl;dQXbZ>M=VE`6%gTVgh`MlrgSJ2U3!j{i1~=FXRA&9- zQ(S(Y2LHP-Fi@aFs<0;1KrY0S=ElGT)?`j0&AA36YnTqle(kG47nQ9n-o0;le;;$v zby%j6TB%QQmfsOEiOv5c9pu@uZAM2+GjqkD?Dp+_yHv8meh7FajU?A#_L}9};1*uW z>(JO4S;|;2Ws0cHE@#(g*U*PAse7mO#?!;Ts-+JK) z1M!g2qrEsf@WR8vZ?VmAc4;_{P(>p#{KrC(@S%ueVbFstFO(^KIvbiPviK0xKUs+Ug3L59=+na{%9CQ~ZN-tmP;*sg`816$`YBu%pC`id7Iv&Ho z{>uFQkpd=5vY|GdoPfTjT}^$1|7-XL4Rf#|xlNMm5$Pk@(l|Fo8UAfA-B#x&jV2IH z-HTtH=Iz-O?Z*mixt5*TVwJB1wnwnLp0SBDA$`Hlxe0Yb-tki?g<8}izW-mu5b_zlT4 z7v|LoO{Y#)z9ya6k51F66PqzHlmE?BdYmZCQof6NoaZ^c3(E{BI4~0LKHR)JpYJ*h zvh}Vo!Volri@Sl_>USpJwG(dZT|w3FnsaTvE5h(yvz@s6B~!+6)EtLBf;70rhA>M! zn6N-@p5k}SQ!G3FnJ0t-tvAEQ73V`(uII8S4{H7M&!98LAbnD(!NI(im*yyLT*`yU z>A{2{M(T%H|D=6JX~7)gxZqRPopaFRf=`*7iR#-uS{MFctH<+(-~f_zjTiTt10C{! zzqr@TkYrH5xYrbK6JlxcKaY#ev|^fGA>*RIS-P#6fjweOUrQ#Wu$Sxg z)rmli5LSEro+aN4dC&M~CE4#;lC8VHKQ~dL$EVo9IT?QR%H8JJ0o9f)(yyHE7nG&3 zc`L5tewHqw&u`zjgwn+u_W~rcoi=WH>5*GraszaT5a*hcmP4><4YQ@ObzXQtF5Yue zd(1GVJ&THBTA47Ekkd$%Hoq`A!-X0KVsgH}bwTV+BRu6?l;al&1b#3P%AQHLUVHF! zPdP{|t)1wA$l!y<5b^;w-KEM3gi8-PwhhOw+-KlBm@i*)#6sf*9tpRZ8|RmXWZn60 zOwDaFRDT&9)Hv{VF^oOqUI`)VL_E35(K#B@9B?eCpA?-h0Pi%!TlY0#&^(^pv9|t1#qHj8cfy`jORMStGj~u+Bc0>r+Zeh?q@g2<%4+w-^|_;xVo7=Bce}pgDTF z8a6}~Z17c^CU$kiAN+g-b<@)@IQc?JK88`l#NXDKsgC0NxrF!68%W<>58+35Jn?~7I_p$SS-w~VrLs;1gI#wy7^HTYkh4w;O>LJP zsfxww6j{Y$1tIv7!0CtqLXP>^smY_}y{PuOy%*1_Vhpj?a*vKyaXEgac((%=?n-}% zEzzd_3`YNn+yfp^bBx1DA}nFLf1x1- zMN!iJ<(UlIEm4I*8oi?mX~UV&>inp}6=0B|?qD}7K!%Qq3xUK&a&{dc~SfZ>d6rrLc$?IDA{8H zlA}MEx8fj;`$nU1tw)I2h%4}CH2M}=3{Ckj`o*lsF!5nQ5jPv8hS$6EMid1nRS6B_ zAO48q=u#gx)a#(AY9IDuPg*6{--w5qw~N>7Wk~Fe-$mF6osjqduGsXxs6tJY1uUX= z*c#u~ZIJkQ}OrIKH%V9`dx1T`^r(Om59u5pa|v)q%%Xz=p&$#94|Y%O1-M`+ zj0_p`OLBivQd=YDqgd2BFn>C@m5!8;q$i`@b`J`xFiM)A^!E{@mOaGye9{Gt>G~{) zVo9iKI3R$QG^;;kdF87|j^>NrIu`9r#M^lV#B`WOA-=j8n`_@laEet?Jp9BjDER4bizwU7Pmb5mUL}WjQ+0(0p?CeztSK6RtYVs_sRim z#?3;Ljplw-e2!ZtEiGQTPjn8SQViOtr=VgCTI8#*jylD?t{|lKhvD-cYelUPIyga< zm6GRq;U>7hk{Qeh5brFolihd|m>n#Byn73s(a5oK;wpwTA~faJaSn(814;*Z0fEE5 zGeD+ml}AudUkZ zm2V4_pt`@j6AT$LFL<80l_t;`KF|%uL{zSaeh{euWYCkK6^>33ULgV*D1mY~X1L`M z%~eBYr!-v%Py~v*LoUlwPoZE~;0dfG0?5n)R?NJ62=orsQA%2`@c(;pW)=%^0`7NN zR&6a4)B&*H2kOGp8MVO#$SO44NQa|0gS#q}G{8%c{}h(90n1JU%MQ;ojm~7&a0Co= zGwA|EnifIQ1dy6^1uLH8er(l+jq4upgyr)rWWeZVnGQn{th=L6&sS0bq(-pa?7JYH)8%u4?y)iXniM|&~V2ZcMGZ=22lmC6Fv@`06UA%7#(1Lsz+{x zZLKrmnGwW;nKk-rN&zCct{V%Y3PB`g0-eRD&`V~57J`CPz}TCK`O96Bn1B@d6!{ED zd%S1?1!y)~2;Ti>WoVEuS&xeSP&MTo=p)bu!_Z+?(j)*s2gi4KK;9OOA?N%k7^?wHI7dkLH{iJGD>gyS214`K$@4tm zF{&|zYIW^)>95h9m>c}xzB=AOMn;=3cn^*Sn`>W>FXbNB=AB?VWsGSW zilAm1ls$mC9CSzV6@xh16XaO}TJXf}so6oJFyEZJ@$3DevrW_!rKUFN=aMy6`+tvz zKA%hxrKR<^B>ZqRbA?nr1>w(hK~|ybR2|pB%|Kj7e#54w=bKB>kaF!i_6edI@Q}XN z#h8>1AM!?OOr-00V^ka*9@##S?(~Fp8j}SSuLDr{iB3Fg9ZKETS}Ng#2i0$SR-oZw zF>XXZ1)s#^I>VPi$<#kPGut-El(WJCu!s!mtMNJ9HV218IVA!(D^widLOD3UjXt6r zoV*}?2NF2FemGoWjYi)|H|VMVQfs)CiTt`0CXF_-v39X|5IDHNdI4^;k$*(OM%D3A zwp}t=bRT%=Bqq&(uiE_w`+&4$5K)&ztBp@7|4ysl{FX`$*wSyca6O`F12#awUyHU3 z*nah5c|e1DZ6I(qc|d2hL;+Ji4O1yMTM~f)N`O+WP=p%&FP^M3RoN=6s%Wq-jNj~kRkZ9IfMqU zO=J)qGLeN1t=9tW4+_!@?MJ1zt#nTY5@bKhRIl{^7Tv2@naG~fIlbmQNfnc`G0p-t z)-aiQn2L1IL{0Nz<8Z<*XFf6~=-emv;T3Rtpf4r(X@0z>UQkvZ6qi}@XXCPf@DLHRm2LhG#5?Mo$ zRc!Ykr_yzRyN(mbk{3%U*%mzk*Lm_llMH;YU@NsU7n2aD)`vm_bK%iM+Z}0}2(e@s zX}pyLblP_4xWxrFar^?AdubELLMw6aU+A)YdKXCr{8Z6w;=o%&J~7k<)kxj#?5(Xp zs;U>hL)aMqbOhMccetQh{bk*BBom@iUO3Z~^H4H-!OlZ35v#am%Q_kn&xZ35qe9uN z@~>zoCIHmpuuw9?z89C#y@H77R?CVi$8$p-WW-_hm>qU&L+YWjoVg%tTChg4C$pv_ z>dOL_x!6vimjyAVMPpd;+2`^w$ zSDal8Y-Gow1#ao6=|N4m8%&xDFE*aPDMJh8Qe)6t$@ACZY;=}6TS_6m|GX69_Z7j~ z&@qPFsxR*=OrZq(vU4cegS z^SjXjf+sSC7Efe+W{OCQWK^=5LAv{3^pm0)i4ei_clyJLA3%ZM>|Ym-NGBMr4u?PA z4MCHF{o<6tQD2}*dD5;O~N*ZK&|mKccnlPoFxY?%HM>Cs1-uyC?;% z8Lii5YWo2l;(i;KnSj{chD^C>d)S3YpiM2_rV1|bw)_xNYD~8~g5yIWM6R_8w)sp0 z4y@C9dMyM1%+1MC5lat)fRlv6AoxQJg3l&3LB`kY7UPQ})+)5H$Iwl1s>H%hd7Tbm zvlhmgZ*aTmfrfB9Dc?R24$rBWTAVZqFJoHC^m1vq4z4W}Lmy5EGv?vV?MVHKcTrp+ zLshD69Wgg6VV~?S9a*Q9Y?ggQ)rmC262Z$f}ZtGp1V(4&$aqyT#}dD*((ky8ioQba7DE z7Nbiu04}QG$P113nn<+a1YKgZQF9(Fj9jwkHLH5{qnpjD=d`jgO!_p#bkh2H91~Ez zIF8BLROXnc_WwwO%~pae6s2gGqkf^0a^ zAj7udbgCGBFmb`PzoBDIIn6yMJ-|NUf~~w}mW#U=Gc#@mg@fD8-*0Nn4qq1zNvJbUL+_2U51L`-pj9c6aeen+J+XGOf%5)$L5vocQJz z7I;J~Q!FsX)#iY=Jr4(@?RaZ51EgFPPSh<7@N+E&sF34U1_&OA0iM{N0SZgZ0H4^N z0UC7@0}M2}2m@5L{|hj{gn|tNq`Pd8&PEu~jwhW@w}k47HmP#hF=lRRrXk{o`{ zK?eC-!k|75f9bY(Az9Y;k>K@awYV!@C`+lO5ynP9-6EAGS2WVjN zQgB#jVW>KlYys2@*48eyRA@s4H&qgq;FKOEPb!t-h@sq!y&EdzA*m!VVt9pP1eq}= zjZ=G?noDS{X3R&9LTVlZf-1^Mk-Vnw>7xU6nvbS;4Z&Es?Ec)fCk6tG_WY^uHtSPF;c(BnGXUGa^ z?Azp@U+-?^l+^b&r=()@1yn^UEsIl9Uio62^4FAc+W6;3b@I>u8JzMZ9pvOD-B6s8 z!38gDOk%m?SA!M)FNqaWmwXE=)Odl(^DBmgFxkH?u?~XS{OP2filBbJ07`(rPX7SU zo|jz?>azx5!!Fmg{;*3%Wp)V^w=uQ>-HT(Fl+iZ3d`y0}7o|ErvK_kwircYEgK{go zlrkyM6$V|7zHL<~3xm>JBtXgb3vs9hlq^yxmns=PWvNWeEcLPO@Q;V&Yxb0{+3XfV zoL+3Vo_Ox&f9LJr`~TT{8z{N1>fW>JR`q9fOQjFXvL!=RS;j3aAvrOY!6fwc3Sd8n zKr(O5A}_27nU^<1q^vdJV|dK03~qu00u&IzfCx@#5+{g6kme&Gh=4XWAc&H5zytvT zI*B17D5fDM(Ie(DzyIFn+^?=`bqljd-g--R-&^ON&wcjZXYYOX*=KUyWc9$%BsR&3 zOHfc!d&5IdA{$N3AS~)+cJO{b9Z&%z5Ak=?8_9Nk4W20!!i~_ja`CHiD<@%qf0SV+ zJ8OIQ)#}twtx38sgf^L=q0l6!mE`zIlfIv@_eql*;x{|LWZ&FlmT&9hH#>GzE;kv! z8AG#Syo6z3<#7Gi_lJdog<%wsTw~B0z{o6$agyEx>#q#*xD95&AjdRFn7c=TwawKe zePSFm-3o(7d<$@1!hW!)KI+P&nI!nq5e>%PXmL}Yl@y$1XLG^~-l6KVolW&VTj=E^ z{WC3QiddP?kxsX!BgO8s2vh&w{ppor!yZu1kipJP8H7FD?bB>Y?kG1xf1!uAOJ!$M zVh7s+4s_XLSqVq>2JcmKjsrJ1RjbYbvv8`GYjs1+=*zs{9<9zgW5=|95SYU? z6+Q`#4QW_a9ci+2Iw7G!~<*B?W@6xQ+8cy<~dF;iK=C31XZ!%o$7f^8&jHztqE2|~Elt#!` zpof%c!q%dKuG)U+Y&??f%y$r0;>fBHPWPA<6{s9SF8!5d zRmF<#H!MUvmY`umw;Uf$%+FF_Fa_rqN#N13+E^Lp2ahYev+*l#X9&lbaJ>vi!rb~T z!!~QSrOECXfW%ZKepJB&FH9S2Gd@Pk`Rc%QHm1e4WP8==NaGZVPy-vh9RA!R*dVXD zwmDGcuxP~TA4gJS4QIQ%9`+xx{S69qu`%69^|f^4(_)N^movSNAe|666cK{S`L&^B zTI-re6!7&-9)1d-$`p|!hCDVkishMoH+D-ALOZpag1ARb#sh39+NQUmD3F(1G;H74g;564TO8CiCLFCvIS6>+(QfnGKNRY5;&qGa2d8i4BlA7AV zaK{zPZMd?$dmW+dg?h)Cvvl36dMD=Ly)&!Y^7fdn3%AGg+KO>uXc)3;e1gT2Z0fBK zJ|fv3rnngq7AOf}C0J^od5UllleMy#`SAQw?K{_Pt_6lR+8!HkZFuCwiq2AG)*qLXWS|Qt1p6%)tvR$2Ld(;Zq9+hXi zYK3f9<=J+ukZnhv?aCFhU72U=t&pvkXX~zzt(#}-RI_c&!Q08RJ#vL?kIb_@!n4i6 zEp4)(YTKQUvo|!kDXSheE}g>*oOygiUc(jDhVlXvSLE5YuaIqfo^9I-*|z1`F86Fl zWV(XLYwbne@N%5IRF55U+L0{uW>V!za9sH?+`LD>wX39OJ$-W%)7A-n13mex!M$Wy zH7x183BIh86I-}BEZr-c1GkiI<{mIknVdDx7TsV+p(R{G<>})K4{Bx8)=ZXJn&3(} z)Pb|OAapOKI&PBePRNvy&fAhFs(8t;$d(OO`B-pImi9@>XYLx5(fjjzVx9bdD*@f$ z9?hpJup5pV5@>Tr4Xh8Hb#~XsOX==JdI^dKo#VFL7tls;D|cmH{-nvR zz-k7MnBEBQ+>VAz10a)2#3gCFJI=_*IulY+Mmpo|Zb!~2TiZSH@kuUVqaMu5=5KDi zY=Ya@6!D9Ip0wH0YTn8n!wgzu2hxOXP+)Tj9-V2eTcZsWcfSQ2bm_JvV}U9-{7mK+l!p0d|&Aku7T z`D8ZyNQ3o?8Ciepb0;rLrs*74snXM1Et=4JAY=9|W@a1|=L`SiD#V9d7)p!#+n67q z!C)BIQ@6E$eYk}S>bPH}Is(tqkt^nS9Ag(q!Sy97#@yo`X8U)J2IF9OiyfI3*QUvb z5GQW4IEzwsl^QeF214>xRi4g7TX;->;qGO6gv(T0P{Sxu1lM=RGzaa@WlyC!9-^h1 z-eDhB|2B-?9sbmM+vU~WB8!?ucy0DJ+(Q2*0LbN?Z4yf-xu#Ful_7hv_2cnh%uC&u!1!FNDwya7^}rZaX*!h`T%$@Ayf* z2)WuX9R~8o$?p?;13%F1je9dewY1j$D{~M$mvjw5&gu%*I^{2=$=hLc9T?+`p6j@m zPL7@Y=AKKd5xT0U4??)G4E7xCFwX|y1%^?Ncp%M*_-u4F&AiQi%MZ7bZKlzqcibDp zB{X#^m(XtQiCT3Tpn2dKv39j;hJ}d>8(Ae(kP7I8Rlp^uHO6A(YITVCDJ4T$%YdM@ z<7FBi-Fi@C;VRX08Uq^7*(3qeblTGvH5?)Tz8QbC4-QM4q?zNKx5BwGv>dwLsU0AK zcl+hG3<@?=KnkBDYKkpR0rj4)1LWI%%^r6e119dp#-qN6|M@HGJ%USZ14Ee0F`$5( z6XU|Z_k2?mhAj(xfw+X}kS^=wWCfp5ueXq=x6X2H^onk!qK#Uv4)ivgL)fsc^n8VQ z&WNa%XDcGlu$(n$Nsb{s>4|*eZM|XED0gww59%3(Bef1Zg^Gu%+H1kKhc_g6+P#Eg z8;ccjH;%gA)2)$w+swN<2%6M7Ths;a(ekOGw#`Zi)LHAS+wT=AJEY|I^9-?6`5m3O zg&KzgbgW+iOxEx9upa9*_npI7^ofO18!%J^u!-s+6ayJ*tZ-QGv8If6E^!xOVz$P0 zE)tT-Az+Vz-fx{8?to0~R}8}|lWD5t2ES+YhGAdY@Pm9p)_B>Zj)i~%$PVpS+QdtV zW&Yc&drp-)_Ph2L_mwZ@jpR*yKO?pZCs3#-fFq-oT*Ol>nFo6&9 zTnelQ76hL$n|bqL2G`4Zl(e??&IcCPShl;&S!ibwnq-&zRh?~|x82s%buvEJB^$IDt7SVv#gku+DtJ<<@D5 zeViTEd0(TZ1Y+#2cpn)~#m@(dEV7-^(tTvj=fk+{KC=1REwHlg1VbO8Wqg+5CK?CE zMECQ?5mN#CWgl&5;OqxAkOJi$UGVN^a^_{&CTP0(%iA`@L$I%^4AN}}qIj4mbfz^V* zysBc9vz1!&%64~fcIX=sL`+UhHHJqih6A-oHFdFty4hM4(z9iD^3c5BVkC>B)`l4E z!z^>_K|WS)AqDGitMywCiz|ESkc<|gACM<|shuCbBRd-%!DXx_fNHJ09hll7x@-B( z#Jr=~C#c0ik1%9PO{?`|=0j~#MrDH@>7oXXOS-^>&CKyb{sU$K2k*4Weu41U7jS5Q z26(#6J(ER#ZF}r2`nJcu=A%5nRDOyg ziS>wQbPSHH<2}Ww)J@imI>H9+azV)xJt{S~sV6ZgHOE1mDXnm}kMlc%llYa%OzhlyqH|;eUyjg zcC)e|%%yAVl7y3O%3$MWG2^zWBz3WrplJdC@*K?3mji3nnKonm<~HuV7?$(I9ENP4 z$+KY5g&Zi<_*pPFMm+vneO(h~?-9bex4njR6eq#&iS5W94w~loJa={R6x*To_MLVZ z2ssH~euN)UrS(9q=#o6jH3VvAgB0${vvP?E!`dSv5ta2h3XZ(HwgK}Vnl6E* zCrz|?U&9ZpQB_vS9BJAHq%!T`H8c}Ptr{wmqkvztA#6R_(AoQ0`6;oHD*FI?tdg-> z`|9GMoR%BkR~G_r2|IxH;|fL-n!~>E_}W!uuxO>W6)!)g2ofYZU^0@9dpN$`wRdv$ zcFXVLlPg8cchvI2A?mu%1xQ3+UC zM!P{+8Oh|?9;dl6&lI1VC8&v;W#z+#Qoo+!?*)t^v4hM;xED2zp#3#ZGtgodCf9cW zZMa%CJx@v=E8xHLs~Kwm==Ej}l3KeLcfNYX}-lw~evS=w(l2y^b-4mMA z{9&K2f0B1oKLQr+H8h0^FgN>Huhm%1Yhfw}iESQ@c!r&hs;CH@5TRo`8;gyuJx@2f z<09|-8W`PpE+|q8&r=OqPxjDwcTDg{eW4eNwY>gksT-4Y!-&e;`GpMVY}I9x^9CXu{%CJ#2cXm8>+Fx~5u!-51?D&8R|_&%Le>(ft;S5#C;xnye7a{Y zB_FfO=|&t?iLE%JfkNm&k@Xz66uJ?ak?`gmNPMrR&X|x`P^&Xxdgmz5Hu@*~2k4*F z^(re*+qBwqXBAn^`2tfDJDc#9MRmArdD^6>%~)A_pnU5*?W^PqJ}-3S-iGcGLXWnt z%r<)K&G63Jdt?26($dpp4<#3P4Hci{)!Xe*VBV17L!>1s)o0+DwG{Hkp{GYJg^IG2 zIZL6Hm?H4p&&5$EXkFl$PY9qd`v8?6ZtQP=qV5YH9v~SK&lvlh0EYM5KV~lV8+MpGcc1$V@Tj* z5<3b!3U;AN3Z3{BbzLr?Kgd| z{*s$IFYRIt8Sf;IO-?s%@AA^0RmpWNN$~>7>YO!*wcrmd!4yhl85 zXNmHb9g*qP{j~Bw`7#fh9P~ zO(l20SdV~wyK9F7OMo@d8n?bT9msGlTMu9nhAgm%(R74$z#Q(p;fyU>!yLZ9K=I*n z@r(glaoOsZ^*eO}E3!K$unN1&$3`G^*xf~pZHUg9Q=kC;o~GS_F2}J9NfvE_k{E+H z&hOtao%Nblt8~F~-(~PREmtlJLTtQ!XJer*!0Kk2tj3d8W5|}vrk}7HwdrDx%`wvQ zd>x_mMbC+qBDw5r9Itnok4E}p#YLteN$5~!hX?qGJB(IP+1XkOorbfDq-qGNmYRHR zs5zy%zVgoRv#DA*(yUY#$;$}H#{yit56*g)Y{5@mzVL;ELD;50CE*P+(HpA@Ex z%EBrI!>XB$F8j)+Q4ND>gaeCTfQV@h!hqx9UTK4qG#`gp!_fcr#?ryoY#}($v;u^j z$)_`x2W*XOKRswEEC(?~3&9B%f;+-OaD>4wLG&ha@32|pzB^52okJ#=;Mk8xO~0OK z7VLXpUuWQ*u^T1FcUWyD)tllDfcH@6jgs0mM@yJKrWnB0>LOhaovulyWTG?2z?z35 zrsEl$5XF&?V}dXeD?cjVcaj)gKXXru`j+TI|HNFRcbOs96|M%WD2!0B7pD5n26>vX zJDKeY+|yLDTC8tF;i6#|FdgBZF3d1wrjWJd* zy4milw><@GUA-T5#tqZ+(Ts7wy7BFdfNPdRc}1HegdY@$_U>=L-!R5TYNJ9dSGo>B z$!19hqocNt6U*aKB&+;9%3+2{Ky$N`0`52Vu_kV;cC$ftR>2L>Wy47)hkX|gwHnw5 zjoC-5xyy|Nm$}ex<2!CF%prfAK+6nGi)oVH3n~@FhZFcVYV|WwUi0D^Gw6e?SkDA~ z-H!51zGjmzkowf8letQ_L7djQP}RxnE))q*s{d5g*g7t5$$Z_|Y~hT&woQmwq-~QC z9&DS8@)(xDU}0Iud7u!qc%Tq)jjt;NK6qbpkBi3#+1)**`N|vzpGNj9P+El%=WOg` z@h?i+;VL{|JdGsBU+}t!CLtELp$R9_ZWcN?np9(P3w?AJjaeKDJup~NVF4f2Hme#m z{M`mLY-e5w{uazO83s5M1-l<44ZHl~PWA^KlO*&eX}FEV)(VNX<^~;c%jC?yPSD7a z4sd+)DFeMkWK%qKQm89SaW81vizxyiY)c6F?0v~kkUgN86GUJK2r>TqLhN8Tu!HFX z?GIGg!42xm^Z}n|3)>dY2f&iGKO2|=?Ash?1Iq}<9}O3{HLAce!rfVHxA-08+B*vo z+BuCFZW)1%?9lYj+4TRH%vYN5qnI7B9!_BE#oo)VP5a|)>d59d1ik?lSxha1ZMz0O zg`v~d9L|?&Q%5V45YYUzsl{TDJwi(_-Kw|Wz%qp_!B5)|BjvsI)-Ejf?y#L1fNSlY zTJ8}C70tQcK7w@Xb#b;Ft*!k#B&e14pVV7dX65U-!}n{5_%|j55#@eLFdfEq2d&Br7D7Y&Q1PsTM zfVILJ^+r7CtxYoGhp<6?0u>x**kWnDy6%?eV9#fe%ww;i853ye4NGnc3aI|tHV>H$ zH`}2JmDHN3S__%1n99_x4O%j2ca|^OnB{>Arglf^X#!l^Z^l=}tn>Buo7hxDkY%Zb z!L?fdi>B&{9zU_pFxxjXecH3ADNQL{72c_}KRX=KzxTaH_9fAm_vi~U3&_E6_}QBK zVPS+em9#Ce3XFI~J)i{BSVoD1tj4Rx3AI?k2}=V0tHKFf%Gl9sy~v4_jd~~2`#*Cx zv#7fZY)(I%ySYs-zb!+K~*L}n{fsk(u zUtvehE*uElh4!c%mQri~qzDh;Ko3|JDL5YSRYRk@!cz^DVT5}b5OHeluZZyAPVKj; zm$t3^EC*8D3KOvlX=@%G~F?odNI`$Yjn1VP4KWK38noL)o|Mp|kBFeFY5Yi!_* zL3}L@{JwO8xS!Vm(iZ59v8VI3_U{i1%!z{=Cj+hx!c~eib2*q`=THF0e@e`m4|BtUJ)1z|WR-VH1uM1b)Wl z82^!;obr0>@y90Bmeej6wmX!@(xF?rTN=|z_}3Zgv~J-~8*f-RxH;;J`;7Uvyo5ebDc}&7YeEz!21d>*aN+dP*|t= zyxwSf+w*V$QketK;Zsu)8}Fm3RoxnHQGuJzc>mg1}4 zXfF69wFLJ;$>Hm7!K}bT_r{NDQ>bwZp9HN&XNzHX=;D_ z(amXKC9#h`ow&(vlDV$#A(3St-f21$EB!}Dlg-Y0)V(@n6$CD9m}1^o-U!u8Y~uFU zjZ;4X+=F4?0O6Z=TAlP{IzjSL@?Nk&eqthtBpp}0cFTSpbOEw(NCafL1;C7noK%j$ zoS%HvM;I$;su#N5{(6Y1f>~5(1qZuznRjWxV zC)b#<2lH8zRA>hahVZX%Oy49q-I}_#R(omZlG|Ye@&=QKl`x#Dp#p4(<0-!XZ64zg z7&Olri;cjIUg_^sw~4EarMEp99)lX3Og99Ekxqlt8XO6bG(sln$G0K*A_%`|%O zrus{sF8raQ4wD6k+18nWiHPba>G+2IoIPQL6O$4&p-1QJG)>yJ9<#_lT-rQ0Zg69w z+fGBngZd`-t8%n0e$}M~jf)4hPt!+D(k?#on1ZI$y$5iqe-1|;%mrF2M9izcE8C8A z^cFU$Kh4~vCQ}*B{g)X4IqfA@!4J8GdmZ+rK?Zpix2}SHF%;v? zj4WluOeZM{%*DF~*lT?*iKp2Y;d#d0!F<*(4dBZ5X|2VWbDHhX@um|tCPQuQf;__4 zn7$cS$Y-3tNe3&GZloTBHG7w=rd;ekTJ@Q%ript}r)g4!h_9A@p(y`6Rv3s8$}VG4 z$so2p-7p!b{YP1}{3{$V$Zf_|Sn6&T_m=U%GBROEEWY|7rz_3AhXvTIVRjD{f}5FJ zju(4!B|Qm}n0QjZ((2}-oy=`u<;4ZDp8h>+7>we#8?C>P)|VK|>GY&Os}@1JYzPnv zY6>LDJxmwiD1yGz_XRJ&`3qT~rJrtx$TJyh%Q9j!wjh31vqMQ1o9h( z$VO~Lx)1?qukr#MZYO{owHSu*_+4-S3NSgv*i!4iGMhqAZZ4u1@t@&6ASKi~rgjm3 z&8;$k6x~}AHl`OPAqY`HxGJmtCp!DUr$nEG#aMRaUQCiScSuG_@58fnld!1Xem5eJ zs6cNqO$I72`-b7x)tTJn!VU}rV-)i}fl7z9IlGZ}|I6@AKNS99QrQNf~R@GWZk>r9Lh@QG< z`V#d=K}o4*>#Mil zU$(_8gQy@SI1<%lv;ff~n>^Yvny~IgnqJ#Kqzl*9QxoPJ>7`FY>N>D)3kapi9iyCc z*D3e*hK-vxU$P~`G5Wo`hJjRFl0*QO{Yjm}9TDHaARq^Vm_?5vzPGM8P7&n{zuqvc zI7cB|xCtSAaH82*(#{+#rgWs|(<{uOcLQSE3#D z1H&9K;p?!ziZJRzo18k156icto{s3drbx8J_gEgnGV|AH-r%1OOSZtds(tey_)COL z8xn1CP<0@;3P8>v8|cia%fNI(Z5!#oZ+L=Be*;B3jT&KMyso!@TiK-SL$`i#*{M5F zEgyHALdR~Qa_%br$lHk(*i069!H0%@`U*h)aG1UbWLlmd<|t2utatG4VV?>ErYC(Q zz~A9#+~=JEKLazyL5^+9`5 zfnD0btPgS#w>}u!jOS1+F!GN+u^9mypGoo%Wb2cuFI2d*RCE(>q%nF5Vn0A3N^@G7{<&uTT28L_Ah}^ zFL5Fzybixu!Z28iXR2}gY$j{ODe+CdN#%v9%0y{7pVA{l^;X`EZ(4@7XVA`y!dFB2 z;x6qs4s(MZT!10{mZn0IlYxtnr#8plzPiQ+Rn|53;v@f{wAcr*QKGXCP|J+^s*StS z^E#L?)e(5mVvTSEEbqpLq)3cZX2LsG{2=K*Qq z0~#TlXoe7=txaU!YW`-6ff^diSX0(r0oQQdki(!43o!hp#k>wt6_e8&5(qh1f50Hn zI)IJMfG}iLXVqdVX#YiE5>8&mvHmhJ31?!qBL;UdB6hZ9Nh~2oQ;x8fv=I8_Y$+xg zB^AUSS~N=Xx@<7CXq4o2S<+t(``JS3isOqwST1!rLf#W9_MuoUBw59U=06oGE;LV) z(Iu;rw^eK@smm@FS)$bn?=aFXGz2uPib6xiP7I)YG$JoBV$OwI^i{6e)`mXyizWA& zXUZDZz@A;Eqy?L13so3AtRfS2Inuht)P9a~bQofax#5 z-6yKBG{4I?;~Z^mWFPjF!oqxyr+{0|B0vHMWI={`gKyng4aIjP{vIP?;L@;ddW_~A z@j~|2D06^-eRJ!#%96FF1|;MgLOpea?M;^pQI93YS?!~ln2o@^Lo4gW?{NN{iPvhH z)lREL*wf)U6WdV{?(V7AjH8w)3y-sU`#!BH!}|-&lrSfxe@5vW_dDR6#=_`HpV-fZ zm}>E}%4Jynrs3AvhTlgN4&9n|p25R}mk1A|q#`^vV@~y3bb-fpf>UMz*8UYxdy0ZW z%NiU2Muv_SVBZqvTlp5l1t4THNKopf%e1gpe5fbX~Ded#iog^)U6xJM=~C5LoIRLNtjTf)SY9!Ecku zZ8?3P#0lFqJ(c)OhYiUv(;5m;H9*FhHv4>WrnlP&22Nz0>B8PVGhNu*XQm}6p;$^( zn(H@$cWIgtvTX!14!gdR-fO=Q?J{+EI-^s1F@R1%$P22& z>g%1kCjv{1Iu{7_MpyzQMXw~z@2)+LH>oXLqaNOP*fij-V_g^O@&>com6e6>T!?M$ zGv1SPHkvh>KIsfI^0+G3Z*8ZX*dgR*P7+BFjm7R;cMr2wRpjs~fE7@al#m}%0GqA= z7R@%|Nvt2_$<-e~0>f1&B>8?2XFH@&nopXY*RCNZO9S(`D+X6dx0B7ymRlbK z!SN;iWt^Lh8nmp;LR9Q+GEILoU3J8}%8+Cbi0hL0r~0Zx`7U(O3`3w;ro8374?z8} z$pSmnJA`EolcHH^%36|1DWSG(#aUJtHYdSUJKaUYy+n#=nK+SluquV)>d=qlzMLU~ zW=2Sd8l2B;X|!}g{EI6(Ys@(NV`c@mt3E`&G99&U@eKzNqvSamot&P`wiB!6sBy7c zxxtkph{33EYl_x)6*?|Dc&t1e@=nG z)4BgsxAe+X>)nf{H`SBw2|TOXv0x7Sxc4pn%i6$vd!54>TX+^LmXHCHknvsFDH5)) z?Iv0%1HeA4w2qqsI+-Paz^z&Tp5ah=M;)|@Y{j1`@~IU4w(}RM=i)IzO|Pi9fsnuC z$POJj?He1Rg?@-j;va zS|r(b+5=Lx%K<{W8!F(2!)-Xm=KR4X^!+rzHhO=yma%g@e8;WC|{wPf%uqInGU|Abo%0%M z1Z7XNVBJ%Pt$T&_=JP&aU$?B3r38!FJF^WOv0>=}M%Fv&u1GUCa|izJiKd>A^E7)x z3_(K^YYy+)wQ2pI*^siq6y+Nwx+&f8*v1q&fTh^HC`BaiT;flBB))VQz~9?vtLeu2 zI(nr0Y1z=qx0-&z{e{>*^37g0DJE?DsNvg3$YHc*+eb)b1n6#xX|kOmjh)Tg&0Q+B zy~ZtH}yLEotol4Yz6iTY~3&W7Y8dP$R(e zc%zD-Cv*@O@orT+_-e8OPfJ=mJh^_ywk4P0=ePT%JET+rR zk(%#67S_=Gi){lJ7~Qh1m>WSfcEWn2>fELOr#eLz3}Murh^h z!^N;Gpl!n->f{X=-e}Ws*%uR6+%#VSh73UUqKTgB>QvxLX0S;45uwZ=#S|NogwrwK zpG^uO0-fsR(M3a^%w->qFZ-3_^s=yPAbmRMIES0H)u8s;^JF5`)N<69W5%UhFS~r( z_A4Io$WFI+<&LW!b@f!FhbV1LTrJ>AaI_aOi>s6(X0byrVis5G1w^$%prt(}ym$0L zjDZ09wk54N__h(PNcXn=JV7jb!cy{?+ zSMp-2%Z`xcs_=Xi9}IJ^=Ecl%Q}!i8Z@Qhm^JdcOmxo(laoy2bS+H08I z1*S}u+KeG)QZ|~r)N=Gm$HBm0>l$|+Ic~PD;KIXvzyJ-hV1PYA0DCh3_GJ3)*=P1G zoyoVSGaB3A2!<`zrq=&z7Ed2#13Mo6k71M9J?1Lrh5#uW;_ljJtbuH+haw&9JRlHT zW*1xSy9Bx2wH;JTu;4z`-cRT(_kU+&2JK)uK$W7=jP~$>MR8HcOf5uyDgvkN9&P|^ z^z9~i8jr8y>5H_HKEM+LWUP_xHMb1n)y#q*g5<&=gACQz#*i z))~SpREt0l#UdY55gfPGhz=MLgSlD)=^-zn(b2bB`z#F*>GYo9S2q=_Q)RXfelT?1HF52XG^SGk!t%-ms|J?#KQn7Y zkWl|I>TBZpNpx^j&fPU&!tmV6i2ezH5R!w+#la7aM5E>S-nYXbbZ96~Q%_7`zkMhf zak?*91rToj*=W;W*=%n?m?lACJnZ;fk3Dpw5` zS>Cl`#qcv6`fuHaazsxLSk$O40H!U!CRd*|0G(0rrh6mi%rqJfj9BxX@zDHeI&^Di z{H8a)`>Ut)|7Ab(+~TkQWZ_K20d>$uI5>XO_=`Ft*6go#bxDRsfU$l!)nOL8(Ih55 z4;ZiF)#Jk68GYI|e5px;r|6)C_+59bF`a~eoP_`&opHK6qU|sOKda|BQRQIMF`>tZ z7Z0T$tv#8)U#UG=*HAP$mDg&2dt4ZoRnz__gKYl$L3NZynjHSnApGEmb-tFoNGNO3 zl0m|28e1RN7`-W;3}g8w|4j{IN+OR1Ed2i(isM@URX@mISbmH>NdHUfa`&lS(;x&M zrF6|7WHv<2nsNE80xQVd(}~|C1kBUzZb6nI(rHw{f%h4h@qB*O7@qllo-#Du2$;us zfw3Tr=UJQzE*rR&BS#zo@i-1vjqPrhEaKDw-f(k(Skp76g;iTJaZzh1j*w_M(9YR$33v4BsRXEJc%ZRPYL0NUOowxr8<_x$ z<;{@%wQ*sK=(-(_pz*W(PahS>^nu!eb)zHjtkL=yc5zBI)4wHcXoxgzfZF0OoZjP$ zy?Snh$hp-5jmtAFNqg;IZ%PAA7@%G)jN=}?p<=Qo=*==t=nX-Zjaj{+G9vfsjo~JU z-n<#Dm|*!2>7F;>KruM-U_P+=p*_ zUi!UPpSTSmGNG_>`CZO%3SL6YOk2{9#F!@%J*)oQ$JaL4ui+P@^ZM0JE#!VN!$!+6 z@d84nC_~Jil}{Bu#!v@t`*qs1c`%4GS4Qsgm4sFRlSaVmQwAoIj<3GUix1LT%v(B3%&a0dAQ@;~*X&#XWibJ{yrcYLH>{NqCdN={F@@6F zO)#cfixLvqVWN?E4CY!+g`J9uM2H|;S}R!5f}7MVx|CPgG{8_xoWD&JA5NM7n2^nP zOmGa@_yUecr%R3`%@&j>9%-D9ewL_M(`jq+(_F4`DG6djBANh5wXTJ9hC+~<_+tP7 z5O6sUnN)|XecM*M_BR2Gi%Fe&>oXJei6AH;cB#VlKPqm0jcPJc63MYU8p$8tWzmmo z?FZNqB!UkNh{t7OTWlIi#-U+)D;d4c7FW@^Lpd)eNL5c*TbDin_X=`<9ld~L`cQ|f zcm`<(b$&}DV5$mBly)P>tBt`L=s0)~IA>AD=aiZGx>hpeB0U*~#7HU`KK808z>~rF zOF2XP8^DXhlj1iVYituqmL6=z0#Eof)>mE2g}<}n9P^}OU^}dDbE%!QCaHo;3narA zM$q!5hodS`i{`fdpb1|c4m(Qp(xm8p44Cef$fv>g>UuPLLr(){ys;Wo#Ui&@2AOO0 zR$#1xU3=8jb;?_?7N|qDz!Hm9jNPi5nGfU?6X@*J7omL|Z55qIv#;1z^t+e}4qB)y z!v84fm7OEjnoBD+8%*9`1S!Oh&Pa*~@?2rpNctGNRxNMWM%U%!U3WywvTD(4$f^4Y z7SbGB1em-Oz#cJaWQ5$7vGZJ-qV53hI^gD?K&gdQp<+OPs9IpLj#|S3Cf9JFtX8j? zs7bUNF;`i1ve}Y2ZelXev8+$J+zvxfpmP_PJuI-=^(mmA)?~LO6+psGr=<~cKDRO( z5W3-(bu}FE5roY+BgWBDOfnc7_wCWq@|)mnw51a_CFlP~V=+ik!ClN!4ECbH~bK3`hrTwGgII(+> zT4xqt48;FkW#IcR9ZsePBBKriPcmjBS;xEz{#CQ7@s2~YWD!iACkXRB&lkvJla_y^ zDyA)tm=bZsVpEz%|f@`sZ320VPYs9S=KH3TIZyA-Zk~P1fL=cH6^n+Dj7_H z1WZ$OS{Mre7V}~KyqM}9Z~UTAozVo|Usb4TEl%6jR8WR>c01FZux5dtz%nrvmSyGt z^<@gZQM43@;elaP?;$8c~j(7;#Re;g$?UDiD?jtRx!TFy_iNJM7Bv=wp&v6E&* zydaDCpse3m3tVBc7*xVPyCH{e8xyKSaBP^0st{NRO)!#PdTYwH8P88&i}>=KC+Q4w zo$i!`Hm4Lc`x6ShRt0G4N+pp$9>iIKQqTqkE+6O0lt zkrQDi=G0F!(CjnsrZ7!%%A{`MsEE@l5zuNbIPHQNkE;1vdkPC^>n#n3Etq9yBFl`g zFt|m>DPnw!k=avH8ipK7W3q8&KMHOvTe?|Fuu!=K0d<#Tj%NBrmp$+l4pyyD zh0J{>Puh~ILiAnoa+E>Tc1ImlGZJVS4EQS1)1^oiJ((=AZkp3h(`U(4GT{gZ+4NPquhWcy- z_^AXAZ;_gUAHRf6kX2K}zuPoQzb=WD#6WC9qcFgPMj;JVZ)R!9x@6&C^ufqUHEawr zB&7(wayv)q+xJVhFpP_mYuymcDT$0`j#L~k?4X)<3=wV#Rm;|<{%mdEWzgwJJ?Hlh zN}8j8`)Cke3>;`&5o97Zn`ZGpkXJGhd8`};+a9I`5rFFQLd-!^Hb-sNnN8AGQ?eim zVHYKn$JtS}<}ZI0{FG0K=C%bQ+W(gCDEpL|Z%6B=i^_rbNY*+5O(2WYE$&KhK)G!Y zS8STz2`Onm>`np)WTTdh zZ<@^p8JGUFj(y)G4i^!;zaJ7WR$(L#C#hW&iL0j7lX$V+)slFzOitqGox~l%nNWFe zMU<1c0G=9{#GW+U+F4jm?biDWwJR;7_Pd*0&tue{$7<$aCkR@k_h$sQ{IikXrwlEo z#FYcRKhx=5aE^0_nb;8bKjpNJi)woRr;XTGBz5`nvepDrPo|BqBe72@#u5ljEJ(%b z*`aVI0s(BAa3-WFYzdDxB12%`o<4yD-&V+rO;LM#Sh16)CY6a^*= zV}fM-F3)y3460#k4g)iCB#Jn|BD-RjQ1vq;%n?@_N!qNUV@T`@c(Xho?8S2KYdk%C zU-II&tpbc=o(#YXf@jRMR1=0&~R{>OklxqGvh__O3exzoSw-pkp;sd z_zAx65goWrGcteYfT6)yMux`*Op`@ln>}@rdOo{qWT_@5(}%g8cjgwd^JumnP+)2c zD0~<}!S{&3h6yvUCEY+@Iqchn~|rd~sP3-^xpi<6E}4 z>@6%V>6Jt))Ep59Ol$U3a-CtB9KiW;1D$<>XfrHAPuDm!&&0AJH(v=XY&M;neON3R z&Gy@UX?>Au@TggeU!zI$+(u${;-B2sgY?aayy@}31$zxYo^2O^sr;`{>OsSt9D@zB zEjWPD#V-eBeW4b}oyo6SO9~y3=sZ;Wn@VlGQ1@(yRgqM!gSd~vi1cx~H)d<1M2!$r z7&bJ_6%;>iqMdsH z#C;kQ%ZsYqc)r|D?N9Gp6=|p&xqK&9KN_VwL_dB`=ubPyLtBF?hroxXr`5Hj$^~WI zRtYI4TGX~@kx=_;WyW9bsAwt%9O-|#JtBinW{=QzpM=eo?Gf6g9B7YNsftzDBTUeB zdqmp}0NFw*Gz`kh21zIA*#&#VO6?9p^p(n(vSPiNF}XUp1pxicxjmw~mRlF22wE_s zWEx2y#GV<^&QL@^6DJQf{eo|dbVD-tr*|nDAF(|owA}VQZO6!MMux3~yWTr>3ml38 zAVt1Nru7ejY{K^Md&6da>DX?vNp+pZQ^T%_qGo>hwx672^@Js8BM8mm0L`dFd7DF~ zZ_`WP?C%U?%Ie`0@M`x7=wY|l#vl$Z*e8*H3E276$t0P^U(l@47Fga4fwpIPuVk9ueFlJ$=E)jL6*kqcMbpR-_j_Cp;|21}CbLRT9j zW|VQ5=r0>JW>lmTGn-+_=6r-jO%N`sbv_0;C>aTW?9t7Zj4#b&a88)R$2Mr-?E81&M*?1EVIYU$D^?sgo}eRJil!((H@Q|Tb=gm$owqJ(p z4nIsiZy$8Djb|G@@#TfYLcv!Q3%+us)!M6eH{+QOn$|_;A;h(M#Gx$1ZZ*YOPHCF0 z)&>Tme0&;uetT)Gl+yGRt91K?E1l|7>C`VPK`S>-YhmV0djdb?+ct~l6j28ch_v1>Cdf(okE|Jjw zOhXRb#i9pQbaZt^kbp8)1I#eop|{Rt2AOoX#~fiV$pdOO-lV6Sd?vF71cEt>fij^ ztmuMT8Y3N)wW8;gAROk1sEu{Wa~KZWSkG8|Eb0fcEW#BUI&`PQ<;rrFnHQ5KjOfmgrB}`}t1JP!$3hl_yW%v?D~r&RhE9Ym zopP3$Un9$uXE_zJaKxuni?W2ioC#St{8P*_^AfV`^jgk^EF23eW|_a8EMXcS3RyTX zRLY`SwgtHSw!?*^M8zyKs^u!ra%adwOz>isMP(sCy9RwMWVx)IWvP(mM94y5)nY9( zzfLVuuBhcy$Z}~p%dE198<6Ep$U@lEVl7KABTK}WkcB9?#Vj)i$+F37c_?Jj<%OMm zrJYrlFad{t$Kg_0QD@XpsO8R(rLuC)DocRwv5=**Le48oq@$3fvJx&zAbDhfOUP1L z@#dA~vH+KmrLwXu3Uq-;&V?+M6>R3EWC<+jp^&ArQq3w$Vr~$tV%C>kaw-@ zi1Njv3u;*2DZ zFR6EawqydGKr3v$eR!nxidN~Y@oj5cS0xfi9LD2Z*WWZR912@KrR7gGbaqi|E`1MS zSjqxG`?C#&PxkzkPj@#J1v?g0E$qCpue>>Zz;rW&2@@hP0Bva0x(E|8T|=cE9*Q=O z2-3DV*|i3`PE)Ee`;ECJol zg)D*f$1F3iB1;fk?%-Xu1lAw3995P;k8>eQVEr-6ys~INmcHB@vIN#2vz%6zNF@IR zNNFgr{+Q+bx8}2k?)-vh39LV6IZVmOOHYL?71n?H8)OMu+qsa%=g#N+wAP?7oW;=B z!1rS-ONHUgKj0k+d_QKHc{Q~J=%4?#XOVxh(NTpiKIWduPGTP(iMj?`S>B`BuhHWz z={&M$sw%+3Q+i+2pD=w#zf2pT5-dMp^E(ph6XD1Fh|WVWZbcWt#^D$4hEFd*Y?-{{BN)I4XJwCdMxtRXkaeTLDC#mOos(^R-tv|CHH zD@qSZw9`<=I0ZEJ|M&7>mUekju|l-79sJ_a@o&g>s#fwoiQ=PD;NYOr)v#s1oTr*I zhN`;jo`vmfm3soYm_&2cl6=7pjE`#HFOUfW^39Wl#yp)SvL))ZBduqGki<)=>9BB2(?E5{|HU`~KgSwep6W(X{}JP=`5vA9Ve;KsjOnSLo*jhCOepbza>W{r*0x zQ*XAUGhgDdiM7Cbw+x9slNqT8;h16<40sW z0U5%e@~*6A7;b5aHT6S=!NYJvP6TG&Zq9NCmz^;?(Mt3?xU8F@((~eyfo~X>Tur-f zjbt$jx?o(kznv7T>bKctD!feJ#hVnO z0;ujDmI^ZJwI7sv5T*KpFcGyBI&diHLP4;P^2WTf$WTL;Vp8S3>wk7 z2$y+fk?cxePP%HQUnVX6=TaaO0g9VXeMi}xKqPB($R%C8n>u7aL>D{HyI^b0@ZGxc z5x&dpM;qaL*2Z!q(Kd;dl7ezcIy1{dyEcdPGOIsf(06LkIhX!)-H{|at8pFDB*Lm3 zbrXd*k+H&m>|l%X!|}&eTTEml9Xwz zP;1j-2CKiJ=JQ$2JJ(oq!8}=3tV7KQVL#sIN3XHwKvBz8_E7VYtme+zY8H{0QrB@+ z5;T$yUfE@Ae|)6%%xuz#?SWk^4+TUY6bk6r8#OwPVWqt+gwHN~Vj6fNXw-V!#apK% zeb)j5UBkm#&+%ia(Rx)qI})hnK$cS(QFMl8u<=r223AXqCerLhL#WaiQJ&weH>S;3 z!}NBk{Kh1%k>Rqg7~OdC$gd+P*cv@%%O++^G8&H>u!?SGEMg+gYSRU=4Xre%^|FA^ zOjLUw5{u56$j=t(O}uV*?UCYjHnzntQcjK?1;cFMr-3XzgN@;|bM1`Ly{5vR40I}H z^kV^+5+bapyPQSAIz>tMvs5`&0x|3w>A&z(MuR7$97z3eqloMk z(Kg(^h7V?;cvrpXLlWlFm-?FKR{Y(!$88qWv6}fJsoOP+dEuSy=om_^eY-MiR;*r_1c2?OhD_xgN8tTih4*hZTGtiP7}$zT9Yxj*cxSlC4CoZ0iRRhyNikr=G#e&-_L~az8L!V*?(pRwaZEQbK$!$ zY5sjq<;AA>{*ZsqXl5{;ExeObk^m?*`!4G>KUTxCzoC+sr1Rh4Aym8bwY(gpiil>1 zRb9@q|FAm2Xg8LYD=ResTS8m+g>1XPEL3+Pe513)0BI$E@4 zo+Y8s(GorM@95wKCexknFRU>^k;$ebU#ZWGnD=KNz0DP&*l`0oSGamhSF^ePk$;Z8(Y+-|rlx;OZbyWE+lTnG0D8t`5qQ zZ8(x;ChSQT_PvxP+i+AvAxpv4!5WGij$~QnUAkgLJ0Yx zHi=6>dBT#q9X}2;CBbrDRcSTFy(4Jjc8DfqQ6nd{fGZ2icFa=kbj-rIsycm+!(SW7 zBHSjh5{no>Sd!c{$!~ujfbFCUdWeOe(aVzmvI%*J$tloj-l_SKi-cST79baQp$pS3 z$Sp*$0J&%|sX%U#{p)BjdC>Q=v*{i%W>@>rG^}WP{=E!Un#RdD@-lOrKf$JDTsG%T z1I%h})maJlIj|lW8N`fZr+jZdn*Ktk7S%Hi3-mb0dto9z(?=s<5s+6(-k&-IsSZZq{Vi9A2#JH zOqp3_7Zho-B7S95CsgWh>@313+CvKtYPKebFy&D}EsMMhK7pIZhL$4j7P3^JJo69K z5+u&Uy!V0ftg?hPA!Ny*Tw2eCk%qI*&t~ELY!1)qAyXtg=Da97nB!|4{B`N?h&EN? zNaRhC>niJ=41}HLw6=DSfXA%OdK8hrKi~3!ozo~L(uKd{!RZtPWFOc;t&BkkI?Q{4 zMO-v39iF#FY?cirm(TL7vINd_jCW08nB|BF$4`>#%j#s+{*m*cNf50^4`2K#f&ymEU?Mf{gM?kswd? z-=LT|2NB4L4N{7G7!?U@R#}3|cZ_$6PCE5-<9leSQHO2O1IPPLN;Q5#(%)G7GY@q zgH4e0kd6OfC`SR6{Q$SN)4wTk#JIyDTcYo9JdQW9Ty<505Gu;%$YRIa6mQrn`5w1A zTtP?=(+OiQNMgf<-Hu^to{x#v?5Oz|E6$bqHR{Oc$zS9EgH0AM`$Kvamg&R17l{5x zT?mpnm}T|(Sh4PpZgAL?<7-(1SYBr44Vf3+QvWg^TZPhBWd!Bh90m7CI+=5)7R{h* z1uyu1{Nm2QFM?_qvlJ;^s3c|(RKu8MW@$bXb7PjE8pbTM$`Y)2F-v9VbY5A)>b$_a z8mcg+qI@2+R2b8uY6)w|xll`$F@1A+mI`Ak@~%TYPMs{I+*={7oEQ+=SA1SQcAo?JjQvE*pzsYdbgYxO&_T8BDZIxC#k(3FZ%0$ z7phRWN!^%prVH&^Nf#OskNvZH>o3dW`?sd!z1gpbFAr?%1qb%YdTS{REUbhp53KBV zj1H?c3AsR~nT4LOxT8ZG*5TRJR7@HC!7zBV1B zNmACB_Vku{8q=gajjtWxY5Y12Nx6$ov^7x3ySYg7&WhFY~tiXilLoF*X;gIEGneYi|cNr6gt6fN(TY=3< z?QmHNHkV6Th+GHRZsK9%b$?gk618#cZf($&?8T>}Sqd#By6HLlaaLKhNrmqj?|D|ytOi4O zYm#|k$l~?3ISEhcydEvc8?UhRlzuGgk2b^4>ZR!0e?(4;xjE?#VU>$Yl5_i%y=kc^ zm-@A-x|Y6?Ur*06f#;Sjh)dcuQ)Hl`D~q#VAKZ-E56aL%-h%*ag=h6`tXw!7`F}2s zJlo||r?z-(p#a_N7!}YxO>c4u+dGgQ!-5kZt?Z56vBH9f)zg8kCV`GTn*@j991g`* zFSDG?+`*uNss0Y$`)D6?$`X!CoCsNb;qxvp6uzGc-z%%$%h#pfp+3-&H^fXFv5t8X@K5=u7UVb}~8SWeh2zXSaZeXF1lhU5CR*+}CNSJzUD zo{Ye1sFQtEibM*=wq~aQ+f$74uB=v|83@j>N60=EAYf3)D=^{591a zPWi6_8vE8*a|jNwikfd&W6dF^z$$8f+!|{x8DUnOK`yIU6P!!7n-y#3>V-AcTr&Br zSTh%3t*PdcrD(;PC)ZeW$-uN?&5vJW%_Y0kiZ$Q3#+pl-)QUAfVU0BxmLi>VKE?6I zbUZ!H2}xTNIPQGfPdvsINeZ8Go>k7_^nG#^lb;ORUrS1Qj}m-iB%S$J#FKI;hYPTf zA6r}ZwanRO?%-waq=wSUN5nF>sPmusGWWk1g_9tbnGT*A;ZG<8R4dJ5MRl-lDJhE; zWlLWcD2gT?;&VYTt6W`Rt6I5^G>7pL(PFzgYNI0r-qI|Gn@PJ?Aot@P~(55%X z)SG<3gUkMrW^hB?Hny^r1FwV2p3uavPtVC)CG1U{B576ap7}n?9#Wr2(%0IfuN-rr zD0hSjmTcn?$m*#%Hz%YbNILDPteR_79X-}AxHE*_{K#=rlMlZDoapgVii%v znA11Gt)LlZ<6YDKloT+;`N8{B#gUwRtIteHG(ra_Iqv1(878kJD)V!^jdDpe0v8)Kw_<$pRFOsOR;qVxEX1jSKVm0xC~% zdLM8ya&dW=PT~Qwtl0G^Q z8+w-plEtcpdMZ93*9LdTMU|W9k3k;Fz<-g5yz4r(ZRLRuaKUtz@lS7|mi6gjRVGo7 z4S-p_7X$mA8{`Z7p^?^)F7rD$o%;|Rj<022z23VFs^DlgKic|@W>M%Z?+%r1Fm5{p zsV0gRn97P=bSjAcd?g*c>;``93r@c!WxDK49^C<|tY1FffnMSUQHAx-h_45Z9H}_4 z{>Zd5Gb2+SPJG2^O)*Q+(ij6il{81hkb=K?GzFJbKvt@Q^d%gGimsw1U5+)TP>b!r z_Yqb=hUfzkM^s_`Suia|G{6CTMzsVf;vt`ajCDOs=MX=GT*^ih=UwDn^!=Sf{KNn$ zDrb7^U9R)J%k>A+hVNbG?z&EE3-}<#75ohE;vR6IUtyU3k#n1 z;Nsfx9%Tt@;&B%hGU%@8_8$ZyH^Zw&VW8apXT{&N8lhRw@vg2H`XzQguPj>4;ga`- zEEO(U3{G&rXUY0?VXgE*H87ga2t;xPb?>&qnq`!nn|Obw$W=m%W26I_E*YyPdo**q{vpSz1&!k!-!>Ldsql(bt?1H z%9{6>@X=VOSgb7_S|VGr5LK5*cuu@Wmh+HC)?E$^U(^xJgZ1JOOI&z^^RfQbXzM>zaoIyVXnJM^wRRf3Iu-to-}CwtJd98BUO>A3s_v;`drz_?!AgLRNtyl0%Zr`Xh&JTsd#4Yi z=af`D-uqB_q${{TC=g8M{%|(?f%J1a`+=9&2~GuiHryZFZL20uf}JmTd6^4oM`_Xh zL2{k+9uLQ%xo3JvLm}o(?qOy3hl5gJHl{~u*RUS;S@byl_a3hB55RrX3@+?M6v7qm z7_c?I>|j0BuEyzhImVu^?ABgW#Z+qMKNS?+!k<4cbB5vQ6UZy2B0ur2tXiFdwQLBSjeq(@*|*MCoQC@ify(za)Nu>yxggQchVZ(e`Nq9ZV|Qh} zdPQrblKOA_kzi4GIlHxAy85z@IO6Zas(bfZFPIRVAVK|Ha za2jXMA5IVmp#4{k_FrV&Wg!T0K5SPE{|%iPdt*O;LfGR9r^d=oyb%w5WM4t-O}|tD z-Q#QGLhQmyI0S@}z@5P{L3apZpKi48%OLi<0b(&=5t(E_P~p7<)JQ+{srewm&~~%^ z5`EaUUsq#`90>6ef`)vAHg=HWYhilQLWW3YtYQ!urs$x=On2pnsCW}QC35LC;v{?Z z=Q<0wVIe|V^dMd2D$K*pmaROWuJ^;Fzdj8(K3xIF>M-fl{}7mT&qZU>L1f_cQx(vy z5t9a=X}F8)dZV2yNSDm^1;qi^F{7D6s!w|AFe~U8{Sg8qZrS0MT-yFWid??5$B+cS zAH#0p<)PmQwZKsh^PXFLd@-5T_n^KW^Y59wyHb!6SHbgMA0e`aMUR+MWQJf$I9U$L z@WNuZB}1^9aJ=JCR65?O$OXgcoF3-;j;Ge_Z}MY7DI-wFX}yF12PE^|{NrboNya}0 zd60JlTKj7m_1`@}=}mFrq7P}TP_bJ1U*gzb0-<`fCyvbe(-0(q%?HJ&x_rmw;sRszcDcjtpxdQTZB$5%932Q=;( zE;rm{J>t0B|K#FXVM~D567OOPZiRC=&!{V5eh%`k?-di=OyLmqp>WQ+VuG7hmat#= zo{*)YvoFTL`XItt-qldS7-LGI`Vtvb=u6cYqb!l-c$N&E22YK#N|VjjG&P4SQ!{`t zbuv%gzn!yScz(?5H1uQ#lZ<{Z>Q~rloh6}wul@Tgoi@kSHT8Gqy=7Fop5@O1&V!z+ z)=t4aKVO0}rH@vQ$#mrR@vG2q##o0tE zim&B~eP*AD&8!S-CE0~apH?@sVbkgdHnWSBUJaPpNV2#8BQr_3vq-Xc>UVKwkCCvd znH{+}lAT)($=>zGj2Rz{uRp+CjJ5zzw1!ne69WyR4<74_=oY@mP zSe%Q6gBOp+fs@J)_UkoKRtwKZcPspbgnE8L6rpvdiRa zLGL0}l*1M1t!_?(7fqbgvaLNc!zDrdJwJ!aMNm;awA*p$oxIHIkA7k1JEr&3FXNA_ zBfSqne>8m2@xhk`e8)w^$2d4lIu2n?2SpMLYEtxjzS%alC#o0Rnp zjC7uN8EY!cZ9!Rrx^AZ<3iCFA(&IwpwWo`!0jVfGr!5_DI?#im$0ky{rXm|#a=$s&t87KJjDN6RN!)ZInlb^wp6v3YmYy- zmFtX=5;Ai+TT2ylIbqWJnagkN)2_GZzIoB=Z^UoRf%caHo4NsIIR5z6fJSX$|l5=Kdw@euyFw>m_y_#Hmv@cmxPhiUe5hfmdU`4F8^u+75 zRjCtY<()|Yqv{mpf{p5&xx8ky9A!C2x2QbN+fGpl{1(Qe1l;t9$TpacEg)cijDA2A z)+IS}j+cC;4&paezzdDFQ|~10UuSuZ@?ZPiWA=mVG}x~lX{{3&zWE92s<&?+X*~j5 z3IW2~zc<`vqen2ZikMmd>_L_Wf3~aF27dNHjsrh?O!fGgt3k51e{(cx-qv^#6S+{s zSihr|>w_!3N&R6E1I}#ML6`Oi#%!R5hd_*h>dG(s>^Opiu94+rO&zp0H11~h!}@wd z_EA0Et88q46xzc7JHQ2;_?}RI#J*|@1c3k^25-fiy1O@@-ZjnHC>86r-@N!hL=sw= z%^_gw3OF~etU5?>;jA2vui3GR0{%~sCXONem(o}G#Hr@&lT^OKCyr8QpQP{=K5>3K z`y@L=__V?ZI7_bcf`DGPYx4(~^EA()_PaGD#5lm)zoAWR81d^`$;fSW;|U1}v7^?0 zpxzx`i5--`X>UmwtUu|a4)lgPL+NJMj5iez7+8phjhkw%^if^BLJMOw%I_vzeVtxC z;M2xdIyKs#qH13s;5rMm`vnrx-J2Yi}nrH>i#sntsN6hDFV z>E2=j(1${Tm<4heOe>1=&}r`G<{u}*U;nX7k4^gLFFm+?GW zhZXR=tKO~aIa{aBrf{X1zDJTFe$=hY!Rz!ou7R7rxPQV3@lckGt7}4nZnqfeqq|{a zx7*#+-F(TGZuioymvy_BZ|k;F^(co#rG_yp@iZa$MF*Tcw1pt#qQ4aA_-@EG2AdrR$0bg+5=>O4k=ZO>AzZ z?NS2hzoD2=C=B{<9PkPB-!$M8=zmG^6KiR@rI=7?0i?gY_=(jp-Cjxn!LKMKfYy&F zC4ko5QUb`_D<%}$1DUTZegbjf3&kk}1FtS647Jk7_Q!vY4W`!*_|#~n`v!c1pXO{R zP>l%j@<1m>H_(aE4RpfwTIOmVDNHQv8xYaX#%#SedQ<1%TOqB{w|494W1P^45Q65?wct~RD3?m{N@ddKueIe1!TEneZUy-c4ZAff+5x)xj>DNk$GS`bQ zH`4V7dSjij^ipTaTlz3%2$2;5=bNzFaQPZ>{wKCbK}WFZyNYO?u?Z#5-h5$Cb~dK= zvHD$7C@U!WvLlfzWY}EH@K4HME{`Uy^{sJJvA`bkZ(6wr8#SWMVMIHVrh0`;%5FqV zYam@oW08QzA9MAsNjR;gTVftBr(irlf-qCI0xzk%u*^ofL)?-dmy#a=bnqlG9gUQk z)J#nHOtcC!q2qVyOyV7Bf3wc7O1GdYoT z5ecV~;|X#qP@YM;8{m_T2?(_b31m~*eqz?v=Kbw&=WQYKQvG9->-1+PxvBHg+q-zt zSk)X#vZ}4&gNe6%d*V&+@|LH%CeVe3kc^)QxOVNwO2!&gPj}m!G&CP*9GVZ*8?Uyt zGocL|7Qj5;zHQMLWgbQ1B~`=0kL9VVj=4rUp@Wuy5Chvu|b z`~)A;^3o%e)^YNz^ocRn6v1_#nM%?#h|USl;*!@-TFU)-iaPWk_ce~AUGJ&?OqV0* zyK6t)1s1z&PX{UAka7&f;?|YBcJG z0_N54)AjwPn4RY%^q3yBS(`o(hmjt(grKS!z8$d?1p1gqLp|Nt*I1x8dcR>G{6H@Y zjV|XNcQ#Hod^q!sNV`Tfy99vUwd(|q-L=OGID6{XcNH?>JW?fbm-9B#)7I+IBx_X& z*250UikLVdfR(*TS0f`~^mGJrkuk0>cJ>+j8gNzbV%_IxD*5Fu^fr||y9-zzo6IF$ zS+~y8j|l)O4!yp!E>zO&Octv*6 zu+-4bF%p+(LpnhjEY0DjDIq>nNnviL!yqW zkeZK_MQAE9GMq{RQ5uQvbb{SoGxFVCGh*ITH_}c|+RV@8BT!vOnfZBmwlK77B8Y>Y zPQ~s7=6$%3;xowLvOGr(^&yEY1#6IzZkB+($M8H$m_9%PaLwkJUd+%RO{;pe1m4ev z_XXak$lkG98(A62DojG2pn?k!y21wYI?wB>wN87V zOv19ZVTW^>*Carun?ooy*~BsgGI7#i6mZNEpc1k$Ndlu%I-B+-&*p*oyYiHT=>uVsIMHJ{I&lW9 zwypb;Lx_N#&HEZhBnlq2Jnd2*WXst)Y7{V?Fu@0`Gx$<7PrKx~J!6wr1J6zFE$Mx%A(d+OjZa63Ye(Mq~4YQRZWSx5^soTA8Xf*#tkmfQwSK1A-_#@Oclhin)?xSeG7(h#+j$rwyz;e{qU@fyR)#vxv zPdIn`W%>yW{eW?(mhp3rJC6U6YDAvv1z1yQ0Mk+}6zV7&mcUxtwUKqiiDezc1X$B8 z-J0*ZYbPWGOSP{qifh2-HZf1sR1nyt-Vt_u5`0#FhBvxNLz4}-@d>79Tj9nuJcDaiz+j6xK3%;S!Iwd@6!j` z57k>gMt4h9)%VnIKtInq5i6D^8SACNPI6=YhSm$bbO3cbO{U{NO<;|SnlWwRXV;M0 zoXx4R%KFYYQDwDK)&^$UK9=mW?LGRU&5qX6DEl*Ri>+6b{^~j;Ny|mm)zh zoiiy)Dxjd2k$^BNcbFMczg`#>mDCc=)YJ<5T3Tt@H!JIFiALTs#c!CVmS~ptt(3~j z66N>)to=M^&fK_Uzwht&`~TG!^PK0|x3$+=d+oK>UVHCU(v9RvwPu#eYukO}M$i<2 zv=kl$MciORrhprZQuT#e0zob#Pi@YSB{kBYs+A5=l0VNd!TYf}1RjI(i&Y=?&M|+sFX|_QJ}VzF4qW| zSk?&=^(?2rAojfwnFNNJ>l3#X*0)?#vQr_5tWX=Jt}#5fx6uE_U}`cS^SzvErSDkK zhn6uhg;R!`fk#StoJg#XNNY=~e9;s;gMPADM0cgEyId}V?W9p3UG?Y&w*)|C!YHZS zk@HZXOxd|AU9vX;xH@heUrHGlz$K}~3WABJI-R0|$eWFL#t~HpGRT!Vtk{l0HaVIj z0}RMbD?Qcba~mw8FPsvk9qnD05@!uvrN`67m(WrSE61~}vO3g_Dv~<&rW;AECt%sJ zTS%F*=co!?4DbK~$}KHDiTaHWYTu@52cxaz;ZO$%IK;TWno{d*9?~k3DPXuY8EVe`#8aikCh^XCUsC-5 z7b|=x;>Ne7p9s;4gwyH)aW|Un?5VtmSH~5bG&1i8{gnuClZ{hrz9=~hvXSf+y)PE< zw*`o}Kz>cNsdGX!Vy&#I>XReIS(_>ALyNBfZhjA(q+H3Jl2gL196n>RMgh7Av%~~j-*Q)y+-k1Ew<5p zM=2ZQej(JFAe+&-N^=D0fSIH+FJl>MQ8k%mwY16yLy#jlY&4a6p0Mu#=inj_Y76Kd zF1R$?&=rT)m7q159Nl+|u)s7eYzczUp*4<5^2;NQuS1j51BI-8=kMovV?BE5kOznH zZf3dB5cwIugJrKs3bcoa@?6j>DC3tO_pDZDAdgk84yq$vHKO7|hbejy%;5Ah4=L^Ti*;UpI_Z43RM1HYi# zc{mus;wqxRVg!WPMi~nM0;QBIK7bpT193?61hG;fEOMU*=EICK`)1NXw@lC_+IixrUE1HUyI2ys?|Hv@$ ziS;Ih{0!6vtYUC8rmNrvOoKZmxU*DEWrLz@@iMhdqiUO`lD6X(ZQTUP>}*Ii>4FRx zA~%N)>6^f9HP$6C8-q>SOH4{l@j*l9AjA6W{nQY)4bM2bLkKL67wp1Q1ZX@4fP5ZB z5X^cwG_bzB+ApTTxVSGNRIy3p21g|{Xe^21)Ha+xkr8^oN3XetoFhg7 za)69+q)}ZCdQ3=g5o3nU>7qhHmTXLxY$sVTN@KDp<{}}Bx`~ogd{5Fn8^@i*sdT6j zeil;+f>IVj(Iul$BNTdXCp2({R2@N+-YSJQnH2j)7!+cawrj{y6xfb1aamAYpGK{M z1G3;5-Z7r3lM$9O?I343)2r-qDNCMA=d|*nh7_jM(M5DKH*9iHjx{@2X#(kRcdA^w zP}3vsiyT7Q60YOeN~tA2^`cP){0iH0>D4H9d~;O6_BC$MVq9M;O(P z_m1LGugS>R#~2ZnCxgP;kOQTKC|7*aA;L%oeo?brhZ*uVth27qOn@$UFCJxzA2Q`c zTp4v`EZ-psje`+*L*SHxsGGTBDlzCnwc6J8ET$Bh5pkjBw<1E-S$yo~KiC!KRivuiT5Xf#P7ASLA# zwY~rvAb=RyEG_a&%9VvU-V*wGO$p4%CY*#5SF;m<-tv16tfyvl}*U5sYe5o=) zJz~6`I|BWgS=mI6a4S(sT?nr0#a<>TixMo=lT}q0swOJ>V8bLMLgtFDfvBO-+w}CQ zw40u4-Si|RAnA&q5#Iuf1}d;f3epvj5fzM!WtjGuoTPC(DF_*RaJR;}P29invGqlo z-u@SEVr#$at~i_iY=!5s8o9wbnfUuPa%*+IAJ)Z5RXj|dsp?dGNS&`w)O2C}BJbuX ziaD?NU&ij8`FS@JB1!*gjpM`4cWQUOh4t}BjSsBq)?MqUY@W_z8#-HI5zn(Dj^yy_ z{4Dp3!VaBTDMr#Dl+HdV8G~ki$hARM94-L^qcYTbjytEpDRW{xbnU$wRNRDfjCJ-= zFgarDR}9Bb1+>XAMy47DJmjgBxu3T1l8^MaG-y^TM8)8yRkeEH6-f-#4|-^aPJo#!Ak-1|K0Q*zVB@{LkCjOG=) zPOd2;UBxG|Jo9=)T8~7bmK}~bjKVu2{|<$CH0M?| zSsjiMjYhndkI?bS8Zl<~6YXMJ<- z5~1s}7Dgg;@tKEYt}p#FD7$qEl+9QjEpH4o6w5vhDXdx3Sv-7QDUI(asff{@aR_iG zAEG6r?8$team03_K#9T*hQ3!0SmJN?3MH(hl~Lx7=0SwQb;N)}EPh^?XI)kd6by3=Buj$^2WgdE3!GAFITul?Lgq_z|KPi`5K%eN(adNmWh!9;q^-c?marvf^i2tF2T}#V z3b+n<*A?rSCI|FAj3s=EX*VfY#R#N-VqonDLJTi(72e1+5)KD;IvM(I;G^U(s89J> zbHs~v-WPcAGzDV;52E9dCB*{%6p-7>=aUcZxx)TtYfCrJfxy^XYCUrzUOYpR{Ns$G zxK!d0tE|5CN;G^cCJBVNRB8pzW-IUfv*z?MXraHwA5@SJuV6Ti#~BiH3_BI71jP0= zo^Q~?RFoeZL_BK7+QKci;{e`lO~$-nIo_Cb<;Tm6_cSe-C)VU4s&OOJ%&1Ng(|vM= z?Qw8Qz}o~=U(uA~X}TL{6M`6P(3=zo+3omSO-vf!HqGH2x9Jt^11yMus@p8V>}-Hn zmne6c#w*iQXG^SW^_FDM;5o#L)JLc3pCqHxM zfO$?fWS!?^V^C!d{IJR#FxxlfY+tW|f!66ac`V!MyUG;H%*JwurWL4V#zE{iam`iv zu42E5`L6CscX5}FYkYP4pmgvP_0tG>in5o)dqRuh4@JY~I z7dKW_7tB8rccO$#LETUrx#Im5Fw$yR_8MR$_DNSWBynXCg8<|HDR9OY;*3Nl_q5_RQhbpHHU%dG(Z%NaIK_U2?Ka(+b0~J{1-%%6vtSGe zo-01(2=44ZRuO16HvAr`qIB$(vN(hwVof%{3X@esWF9_WN-KqZPu& zj!9?xZNo7M$9J*)WGGbphgZj=V0E`qAmQE^Y-V;AQfi7%8&Zlk3OdXI=4-PADVZF#wg;}Hr9pep;i#(wTUIjKg>s3bi<>^JOKem`acM(=LxZvTQ;jK_!_5I88ozR z28~?jl7?>lI8geSM_%tnE1O5g%{RCEn?3!dgPh-~ui?}CG-CZO(o#aF?!BwfX}kL; zGRnJG{JSV=P{k`Yj-ZGJsdET8Cj0KoCC*#>g?H|eobf;HkbKs0)xXdoIm59^?2mNy z_c15^AMi)sT4cc_l`N36D32PT6?tfynqSKDtNEq3-u%VY&#eB>am~+ve#3X~`Q^(u z-Lj(i?Z8~NTKvYqmgVL*6N9)Er4r{n4(Kx6!id~N28@Oj3od?pDI;a!*dg{z=~?Dl z$~+%CIy%;RlgeQ`j@qUut?8%CmfHblOs3iuwD1cysG(j>f;^i(?ree->vUbpU&ue|*5 z0xb`R&0o7}_3Hb-^VM~`$Ty=9F)H==CGXwRvEBf_5v|>9etn`jbk+tTkT>54nA~He z-#Yx+)F}p4DJ)*5j~6Ina6hlV)|D-upTAi8Zh@O>#(N#8G*Ry~U_th~2)p7XS)&-< z43Vo8bi&%%2}dtb*!;rU-`)7tZ~ghl-&xUo)lHvV`P9pIuYJZNIawa#CW~W)iCP3H z4|%&*ao9kk=c&J7hXbE@AL)4$3}{xRfzg+*@+>-v`qRz>6K-kJzjFWi<$cYgsW3b` z(<=z%hF9njNWwfligs%iRs#$mkU;F>Wa+4+hV`LBon%=v%Nq&#xxp>zUy9V?4FN<# zaaC4^V3M!%`^UAAS@~{$pt$^HUCLh`d(Wv0bZA^CET?ZY{-UN7AUfpdaKQHdHf#IPVOX9#L1zf_xC=8RNi0$D%BpC!DeKAd8yG zG}nN~ILa|NqO47Na%Z7`)@lftW2>g}nYqyTH~zqwT0p~rjFP~u{aBAe$XDr)I1Ux1 zy@B}^{}lvrARk?qx9_Du-P7-ibb#eu|5yWIRPt)xIlK{y4YuLl3(mgzn@4v$x{m$H z<;H~$XZn2?U%TK8ue1SxM_Kcz-Ss0cP6)y>z$(s2Bh4J1taCBG48eS;s0}_ZE?^|I zLE(Z7$9vcKj18wjAZfrY&A|1s!(X0fTGnEmg22)Qfu-3_XUoL!iCkUssIkvg9xvNk zHb^cg(aE*Va;_}(Qk`uNWs?ei(q^xr&OBNcqilY}?I?inOU|oq_14Dq*2@1XZ<6_~ zY?XyIV__y{o37yWi;MMBG5LhJ;0IyZ=L_XukPMIIueIk52($NsKCRvWlil1^> zb@&3n$wUl($wWk>WTJ_{%5>5xqDgWB(1|}nuX-1MUJvo7);q1b!8)IV8*sLx9w6Zu61KeocJ)U3pUa>GFp#t56&ObNgMub9WHrEvQj`czi;g@P z70masBAEdfRDb|l0EwJh88nqwAax2CM|p~{yDPkSWwUp@K22xD)Y_lph72h)N?pVx zTc43067xsY3F&rI7m6tdesgMmMly{nt!)tH3WMn#j?d?AzTZRevc?wq#aDd%SA_zr zVmE z@&mflgJk?ZTEsW0#YBKVw)h804f86_aXvy99173m3RN71X*&nIvFl)5G^DB1N(IjzNyBD>&>-6Bjv9@&!SUH)?g1^1UmLse_C7x`4UfShSW$YC%I?Nc(UC&H&j3BrPX zi+7SHzw$mP_5(z)6XKof zy?&}@VGLrX%6Z|oxF)!{kThighs~ohIRKb~ORvA3NXo$(Zr z$G)9X%8l8S&9JQa-fChcN;QvLb!)j}MVsVgiSaSTn1xl}X5aks($I&)uh=Jz^ne2e zhKV0cQk6ISMRto;wUW3d6Ch*{&`o;3=E;H-`k}1!(e>n_(`(e#Dooz8jjkuhAG)QA z%33e84w52S=oLwHtf#zkZ#bmd{JxprRab2&i+Xj%LowkHIji~I%K?vTk}S~n7MDe` z!Nl`kh-YS&;vZ^Cy3Niw%A3F}2o&J$dY*-8OeQAYN^H^43@KTLT$4qGqZdW}Rf4VL zurh}kv5>q*8CQ#z2y6*O1J+X^+$^brwYz@n?apL+qle6UlA>z30eRGr3K=d(NP#`N zRr8XxOy)U_6NgEO5<3ZSKJx)_w;UV8oui(Ya`dRe~ zj3ymYn7uq(ED@+fKFLxD5^$hVDbIY*qh^vpkrxy|W3x39%wNEV;$@Or$w#x=St2yl zpt$pY&7>jb?nA9YdA^0d`s!blwmDaG6sTqo4!wdF)+>uD11y6`{VMFl%~P=&PzKqk z0fmVWR-I9=(nkXzt5|Xe2nY5I$}8F;jx9>XFvj0Ys2eVdoc*v~p{c5xl&gkynT4(z zJ(Ft2Ep%N~HTsUf%_Md|kge8%%P*D+g}fJhY03~YiDQdcF`%lnI9gDrN?!5Linq$a zZpD(-jRS}@!Sk@slL+fdn=^T5QT50APDqyfPJVq)@>jm|;c`EL_ABmJTsL(-pgM-l zFFvT}sQJZ*^i1kFq+8w8`H0flj%aO@@AG=cr#gZM?xNzOl?J*41OliR+OB47vWkF}TU0d|`k|ieZ?NuB@-IS^Hl13(i+_axe5mebHB~=X>HFv1 zFZ{*DpQ=i#5{yX;>MXBpoGRh1k!`gr`ba`p=163vBc%egv_(w{d)iZ6qv8M*z+e2E zfbolOIGFV1?}C=?bPgu$A$}Am_bVi!fW;^LLfipTN&?KSQU4Ow3Zj{IF;tsS}GEv>>rIr9QU<=PJ(jI_2bDn(Mq$guEg{y1&kwSjua;wPKrN4 zxwf1461KO2r1L69U@CS)S3*)oLVYa+tx2Uhfv%<|7kAk4f@6@*Ay%Pmh1QiHqZ2MS z3?>~(IH8K_*M?n$ec5-HX8Q@{HTvT4$oiD?n>t{VzfdOc`87e9OQmZvHL-LSd2*1) z0v$C+l*37|ke`QzR1%2nn1TABkPt}>=NYmR*;h#0p z=_Dc;Or9D_vBK*>pc~2d9k?Za_)P_G)+AJ^rl(6b(8y*|r#QLrY)=+ZlU{v)I3vRh z9cE$hH2#DaFG!Kxj;7+gsgUAIkuTB2aCPypzEQW-g_PlEiq zsxL_&drM1l^JD~G=i^0jJfQwCtQ`l?#LR*n+@7$OEG0%nxsKhQ(6uWoiWh<3%>hDh z7o7Hr=)%8QyGiwiPuT$brqZcYDhT+)fBg2+=^&L3_!9V*kX9;NgXjTZzU3H!U-YH3 zxo~4;))6$6f$s zL5ossZN#?7f+hFL2*Y)=o`oj2$#gw~W|{<({6G{7${VYW&ajhUN)~2Hs4WFI_@y+? z3@sq3rKeHK11OGz$oxjJ3wphYIP_!ZMA1@Kd{{7ZhJtR{j=J8DP=cKu!ePKt=4(;d zu^|OZhn>|>)To8J(nX3L`GPy5`nTpV(-GBU5K(0v{ArqbDt4ujLe*d~3Rwj&UYIW{ z#IRy$)PwNypDJ~9Y2!lL;52h{*ExfjyjzsFws>*g_@boH7LLw_D6)ru4lDRq9)2IV zGA!pO)%k?=HUI!`UAzXi$3b6vI5!laA?Je+q^SJDsP@f|YBjHd#nR|or@^6%Cyf6~&rUz6DF=A=r=XP+T) z|2|4yCNR3+6p~c?#ov+`^-=O4e;{#0ABo?2fyBPLe*5o89Mwn3Yd37A%^$r;Vq+gA zUww|mz57Uf>h~n>*+=3%o3@hpsXuKcam{~|xK|(5-Yg6q*hk{;o+Yu=N8+b+;(K4! zUi=h^eNpA(>gVV_s$KgkiQRcFA@%Z9ljWe;(qVGY<|j!%*248-(t)LLo8O#6FZuZKs*hC#Sq17W$RbeTsld-@Zy_dK zim5JOLI{w7_1HS=*;MNk z(w$7;`EK7K+G_v`NY;f;ERGwUvW`xqccl|#ro63cb40lCX@r8L@v1k`#xb!lCBMxY zs;C7KouOvoDG*Ia@nVwQtu%l)73NUKVv>n&nl;n5BirNLCgC})elkJm1+$a2 zn08R=$V<$Dn`JaFUn1CqTE4zR{6zCJ=kvnB9FgFsKdXb)F(htGJa#AS)azU||c4Yi!8 zuqu4ZtcNH!s;Z$;-r{&o4O8NGrk*I!(thYjB1Vib$}d*T8~59ZbmI9z2Su;bY0Q|l{-A`aeC#t03?TK+9rFc^ z1b)S{D`4oh0h4%k6DM}^UHeE2$M@zJ=BxlKt!GlYw#qN8vjjZ0kOlFUar8@(2K1}S z&SeG#`zkR1+rl4<4vdN%1TqAtgkV+|9D-qa#~|@8{6v&cqH~!c1^TzbQ@ep(Kro4K z1JK$l{?;#)97nG1Uiy?yhCIJJKc3PzJ4z7m5IfG;CO59@!i}f&&5W>Sg&76MJ7>mI zdgVp)Mls}i^5P7JTpz4>TxEeNq5LUZB|M!m!b68X=pIvUqY0QQSyDy0W)b&JHm?@% z%$LIE>lAk;ixSKjgJR$!_`n*rX3Vf~;5A4G*>yGuZYm@ffNW%y7j5Ey?gEf|^9>S< zcs}^m^#YJ?N!1sCbW5tf0Hj+|^#vf^lDG@u0Qkq;58aZgF97M5#H|RG3qZOhRbK$o zEr|ozD;Iz$2@hH41t8t>R$lAJ-R!QCW!KF`CpLG_iZuNlC`89xF)DWMJ z`%doe=xmrB?)c5r#5OML(At@ytFOyCY*s}XXNzM{u5_LAZMlEZ5W#95r}y)k96rB> zG;I|}`)v%?Vvz9~tP2!Tt|RG*2M>wOWH`B_+ADQx%d<`?w-a{%q6VmuHx?pvJplU{ z`1?|qbIyb3IQrV!vx?Qgqk$Su8gu|ykaqb|tBtN4My12&kMw1WckfemlZsDyMLnxD zE!_gGLtg4i(?SE^8|{2`$z(>F;seD!$gT0 z3c`)dC;q-}Sc$PEN*eA2KZ%>;*V}~2t+9#=1+Su96;u2}u)ku^4Ug}4sUVmmlMMvx z7jX|_Al3}%q@o`-t7H$NS~mF78<0}nt17POgU||4wkYBdo7*3Gnyy(Cg_VRPt z8YRZQTpfX8{bcXEkbQ;TxOjZqF@rJdQj>4C^2DAMJ17|CPlQCBw+j>Od>Wkw;e4X^ zwIXQ#Kix3^__Ri^!3J~dtdcuq6`(S$i6O#bcYnlq5b|i2#ga*|$bP&`B-HhWDZ2gcsZ6CK6{#c9GBT;N-CuAojW3~s% z$`{A>^rZ5IK2wTTlP`j$Ll<+z5HB4|2go8071rVwv$hpVi_n*9u+%X zO^1!Q9Hh0?>iArec=3Mgo8^7Sq}0FgAQh&nn@=^q4BIb!>%?H5LHwq-hJWOA$ta zpGqfAbID>DRHS{-RMz>mtjp*mctu#mp>~=9Dkr%a`fLtXjNOG|sGa3Tbf+|N1XT5O z5{It&EOmE^l_8=5!&>9fb5pJawzo58qmG#;)ybn&@&3HFv#d3R(@B!#4D4#I6(Bz( zr&LYDV;uBnw;NTY*#T;nxx_Wg)ste|z3?4~Uj#=v0WA3-_A|g7*K6F^VZqeEkL~Lc zyC9O`Wn(Tmz+0?lgpUaXcm2G=oR*0%PxHkwoLySN7Y%#ghJoAH>xp;x!r%RpFA`lQ z<||($-rSWamdEMNt{}QI24Ls-cYSklkQhnE{2GnOaxDsy6C?|THlAwr0a7MIF2Bw6%9Deb_}?S1;}b6Ewa;Hr*f0MGV!_VRK$%eC@^ot^_rOIai5AT?@FCsIg${t z@YDuFmI+4$oyLb(F2&#ewfCn~ z`0i1PD4aR`gD5EP9;N8E!^hUO3Gi;SK(8Fb%8T^!|C^6e{9Pt-Bv;OHs@7Wj`mG69 znl8-IpBU+6`%i6MeZOLV1vgYpa^|9~e&;IXcnUP9e=@UcM#T8AzyvNO-*%q*>O7`! z;H#HSk`mLEJhko%+z` zP=s~p1Ah)l^fX-O+$lUZj1(X>N_LnIW8#mQBZ|z$1QP%%D4Zz*0~?MY;9?0AW0d%L znJgGgvCb!@*{SHN(E&NGk|+>InK|evqM(tAr+$l8E2}891K1}Tew)@? zR)FTxpFvy2g zA%g=ZE$(GOZMe2@24H2!9c!;sfKi6GfomCgH5^-DyoE67w4C^w53ew#5(;*GCJFVsiN@8f?y-Kk^7;&WX15v( zmNS&H)8v~zMgYW@oMj&Z_3iI=aliD$eVBZBBoGgZ?*oTsxhRYA4YCknrEl6bKy+L) zOJ_>uSS2o6GI<~`FZ;yHn{7+Dwu-|Fhf^-#9D##^QT9u_g3hW1T>?HhePtq36~6)xh=%;KOdulQ-c*|B_n@mkfz z4i)}y434ogw)E?$60oWSJ>+7$@_>aUEu{db+Xt)A8X>@!-|{H(k3O-lZZ!M+3R-Ne@av`4^takMeLfhxTaH!c2idVZ#gpc$IifcXV^rH;N@) zv1)S)?~Hq5&%9dECoS<-^~qJ$y{968qBYgq;$QP|$BErdx=zI84c$6l0ic3Q*S_%r z%v9BArT2My|JK%eFRxkGzB`ue+KC>7d6K1^;BhdZ*v)v98hrqH=}zOok{ZlbR4J6PjQ;(+y-z`*zU4t9e-uI-3^@$tNE zRFH%CGRe$7cY`CiMw9M*lnHE;lMQ{w{vewU5_^r(8Sn zIK{Q|PwnG<+zs;{`*@$Rjj6IXyyD{`R+oLek}^iiqS0EDN4P`#c%P~4`mE;a-uLm| zA2O}>CDVF-FV{K2E9qO_$L)I^fVA7WhcUa;&dfOC-s0#aDyg{M@G+mK3rQle>QnzX zf7K@}UaO+&li{XoLG0P?xol%~*Idl~-E+mJSv3&xNgx8zZ9nb;Vthe*bpgz&Zq@RR z4NV2IqF^ECa0i%OotwQYSehk;rK&C_5p-3bO!!sh+Gro#3{p6`q8T~;7Hz5r?7J@crok4ok|V{*WHB`f#nmQS{V|<|n%x$w zcvoiesj%>spi@IfHhyF^$6Zo;*)QIpg^pN9N40N44^~SGC9CCe zO{K)}_&g^H=>#V)KDsG#c@L3-fzGHip7cxF`8b}auQqpFMr*EbJO&k?$Vc{J0R5xU z1;ad3ifF^^0t?zfIdxhuYR@o$bap|+F96`oTYk9q^b18+=74^>rloC`q^U7+sc{(w zC}PB+fN3)fYJihT;B$WAYZyhzvOw|PlPplY_aqAxuS#-( z;#D82aA1Mry(d|qc&|y6XQYEe&xOKi`O+)?47WsMKxC^8u-kn%!ful>&i7j^HldLa zJ5U}#4gPRDK=~$H$a8^cR*wj^vr16X#waDN21{-BrhOqal--F-K7*NwVL1h%&wp}X(ia&Cc1@9dUy1eWH$cSCcxH#Aqix2n)wUf&JPjknId z8=8x!{@u{r|L@;&{=YXg_sP5hBDGeD9%^eTdQU=g@tju&RVp(&RM*hlt>sBVb1jd> zW%4U!>kKq!iw#yIYd6~n&81u=H23MgLvvAd|DOrXHCUS}p}D4`|8EJ+-BIi(p}AI0 z>uS)-7T2n%pM>UaEl(1fyR|%>p}CF|J418byX|PL;>^y_T$i4N=5DQxc(vIWysPRb zw(k;}YuDG}47C@5;spf3I_Ec_(z)~4Mt%G-`C3z~u^ zcdB<^A^MDOVgtu}oHN2z8S!;PiV_^khgE;mS~u(M<%fCd*3>Sm!tPQ zwzoKPv6tenY;SSIXfMS#Z*Otiv)ZHY*Klu~lLp(MJ3_jb)^Fe5;>h$~im%(=;)r|2 zr`TXa7F!S@99n(qI`xlI*z}%gJ#ki(vf3q6o$oMD0<Hg8^}T zJ~NEYe2&33(CH$Zv=qbiK287`6gIIF;tFoGB!pq4e|1>Oao#Q#=?WbKO=69L?{n;g zfDQ#Lj0O(dqlN~IPwlD5a4RA=7uIkBUoCYozYx^nl{lA!yiq=?cz%1^m+Fo;z;T!KB0#X!$Fm~Eg4C4MeJD8I+iA+w@-0<5`!N3F4EKD!{QKay8GyB@vGiBeeoS+%FE3vJVm z0!_F9+CB}^C&)spF`%rFmWmGGQh$19@Rc|6btl(n?ff#JUgq1*4!8ap00`2Atj1qzrI+9 zb4GRooBg`;4q;P0`39me4yOQTmJ&3u>w>68V8@J8Ym5^{yBgz=)iDkr@=1(S!(TB@ zjhc)BT}wS&?HgmSSVf($lTzE2IuC)@yQ`?P28gWtoZl_D@{ye>sKcWLSB*xwwH}Xn zEH%zuMr#JSggAnAbz?yBr92;qMJ#dmV1+wI39y81QsuEiXl;dTkoIn%VVH}`Vw*^eGv8{d$(+$b-Gpk1yrl290!H~2o z8ASyMp9C3>laU-D_JoLzcre6g%K4-9VuHHFvC$G+8UTn$ebnL9Vfh*aiVeh=%%O40 zAnhenCJ8QP8*Ku#(zC{TI+>$Jg#aZUH?~XGgjx)zZiG$l@wh3dnoHN9{S`PJ}}oeBmL?HqEBc84A!S@Ada z(-7$OaTs;n>_b~^Hooi>F~Dr)t4-ZLvCYd);UUI{fzCeBtz35cKzvfTy2QctXf_&f z^v1_Jr#}GCPwNly&-2Z-C14c2jbw&l|JhUP!7geJ|93sL{w6B-kxEdo+o|=|Cr1uB zHyVJ@Ad&)9I29TSW&vM0wq7C|&zrc1zwTaB1i0P38h5O;!fiCt3yqcHLppyrBdA2ocG-z-FGT#uxYQ(b} zxMY3UZh?-Vaz6)KnhjwR?MO!+Iuj!`U#cbDT~NxD=}g3FUa+=pJx07EnYeqLuwsrE z6Bm?I6Uk1)6MV+GV$^hd3O&zg*QGF*m2l&klK-fD&!_J9^aF9V#aGdExqytZGLC=Q z0p1?5YuT>;m6TERvG|z2bK3;cr3<1!vk6R7t}AHv9XN(&p$arpgFUCZjq0uzkZk?7 z?x)mq!?C&o>_V`R>2AH}lX@RIKN#QRiYHd6-$_4Z)F7}Yh%LSbH$V{vg^|W)6S9ax zaWxaDhFwMj5OVU&0WdR`$PH`?#zxpl85aZ+*s&2P`5fA%5DqijWI(%*Ep9nxz>{q| zr??daK-i${1Q-J-fCYHPTPot^CzjGf5HXsgO~N2>q%5Uj2-}Vh(BwC^Gv9aNML+ac z_~+Ul3di7LIsI?Qq@Mb~hpds0gNiC?Pj0*L`^{UD|GbOtJ>0YZHm#VW(Lf94f`dp< zlp=N>Mb$i$%pkVCm5n2KkUZUS78eK)W=hg*RQ!b-KR9D(Gs!{>H`{Q$qNBVkX5UIF zzS4TC`LIJ{Nig*S9bdT_oYMK3064h;_`N=?$(5O0`M6_GwdmPESzBX1&q zf9*|d_u^<0S^^wgm}%m`nhYy*OQEX&x~QA*=xu& z!$0S-6Tq96YHALgg&cnG`!?lk+V5C#F|EVxC|xLcBCrlF;K6Qm2p3;7!zQ(w_}-rk zGSFA|xMp199zDdJ03bfGUnyHFW+P45RAC3*J)T8Bri5L)g9wnA;NE}*rCM2Ar8-@i z2eW}GG#*n-q6{0y8|a(1{y+vBPzpCrgJ809{gUZuWz&Ty*IRb{N-itbf7B}MOX#Z) zAUjGI|B`q6q?7m8jce-4>7%2t`7_`A&7=Ca+wmMo(R_XKcH%N|D*6+%uajO374+)n z{P|Js9nD+(i_UcdE@|4(1%V}tIetCL9z8_bG(>L5IUFHv`D_+vjGG#8V|HkbrY{Df zuq{@ATm@{CK04E-bFXucA?P&8_+K1`6yMU59R^B8EJsHvn?}a~fo(ueao6=4gpP~L z2iSqXUZ5+Fw3I@%*7*WfJp#+OIgP%oh_dm##~mP3q2?c z=#b;g_qj=vF4mYsSK+vU$p3wp3%+G*-9) z*lj`iTkW7qp&+YlQqAf;Ol5|6TMZ9@uTDyDAX2+U$oX@V0Y zc}GIH?9r{f{#dUcG)AJM3!@r1NR)NbCCw<)HE1CNI5%Xf7{DfQqYnBZJ`B2OJ%$|C zMLwyEc$BKTm~=3fv7VRw=)gP2l0jL@K7e*Im*>tMsf$OPMhG1sT@yKQyV*AD^o?hc zi09hLFif~`RTO@YaRA^|Oq~LerCeLYX(_q#x3rcNr4uN;*_>LD0&@bqd>0-*aDVuk zhkkeQpC5f;#lJg@2;uC&Z7*N{=6&A$146`FQU+~bnZPx_zEDc)-L&G=N*kNDoVrXS zK3lGIDVuajHPfdkeM5o`>!cVJm7)X*B!+=as~}|`LFD##e?#Spf6N!&9uyRv7jvW5 z$v^<1>zYq>E(Uzp<$vyBv-fT7_FW;3?;$(o|;!)=c!X`-sGukbYkg()YZ8-n1a>SBff^x zKx6Qz@5ZU@LU1LOrgn%pM*IkOoAfWQ{p9^zNLqY3Q}U0Xac4#**$4N?{=@3*xV_El zOtSCRBl`o&o{DSVsay6z-Le~k(9XQ#E9{orFPz#O9uEb%2MAPbR3+*hE2$X# z88yGSDX*I!AYxen%-D?Cv@(!5xml+>(;xM1%W5P-aq{#g^Kg2tTp&WmcP*tJpW z7dKGQ%xJBY5=S7G(m@O=5q>;_oX!B7amf`-7p_aIAXS!m0F|0~0F=6E1nnIaK`KNI z7YgHR%xGGhG=%9OQ%)Vr6H}XMFH`>6SDxH|5)!kaKZR>R6K76o9W~ADGiad}#L&jz zL*`Y9K&CEIB}4n;dXk7QUW;l(2HDR%Q-f_%5Chl9<0gj8Mm26ikl`sLt1iIRtVnp@#_#A@=QsLv`8xYtU z)<_So@Edl5Oc=S!;mfG$F-$lkrYo~yFttMr>>7o=*31nGP2;`|wd`x!-Dnr8=eCIKpN19|NcdaOkf5EU2 z%kPRX8X)nbt?`gZ!bn*t+@XQWQ)3|2dH3f%Vp)U~?sGTAaY8T$sQeuYXtFAs?vdX^SUwq@R5hh!7wEQ?ph^D=;>&!TAts?x9HOL&k&o>rq!=kvWt?{w)C!+c zQE$xU6Hj|i%p~ngM>ACG${XcBP9G$)QZ`q+3A{_a7A+uVk)0(QDCKy@frQJ$@lKaA z5HzgJMZJMTa%C>E8Au0~1)A~$lSWk>Q0oS4E}4#$MXv5@(oO{^CzebM$~Rt|EVe@7 z+Rv>sq{}QwW%yHhN9yTly7(RG@AxL-Y-vOuCP7!eQlmY%K;yf@1&zVd*q{o^pMvOt z78fMIJdf&ND3-}C7e6tj@%PHgT7(-2md9J=kM)j=$An1rD1%-@#YPeWihfxPgHV9C zwY&bn`i^U$nvqc;pt4gSnifcbu)su(v#ME}d5$rqIbD%JJybb48yY3PQZ~kQ%2-zp zRH1mhGkZ+eE6bKz&9_6_Vo5h&>Hwmw_>;U=XwH!0Dqj=18wENmND1g@?|kT~3=MLp zz|)p$q7o@18bJ6`Bub3K-B-(l4+&LLr<|F?gt(|`+1TKB)78ZAu#uL2ZRi(&i9-N^ zov|B;yLaPJ*9}_TX>9l*9?Uz?E0So#wX5Et;OYjHaM`0hhTBa)Y}!jFCk%P)0|`(e0te!4bc?%EtM#%)ix`P$gbRiQ;$h0?xtW z@0<&S77_(qZEv)-lb!g4uHmGw2bBti{c$vEiX%*~_=il%-D^xWe{-i^#ns4*SGdBj z_%_Y4=!(hpgh#U6A&rSe20!u_>JJ~#F>s)ogefbaro4ea#W&^q=Bv4+(dKk_wj!Y9 z(9)RH8e7ncvQYL|-6&`g!|Vv5LMlY;r(9I=+~Q&inv@A*%QL?@UrK{Ri4@-TU8|7& zvsB2emBA2EDxdJbfoPydlDP%4>PmE`vGav+n8o))ydfIq#D(Am<&lS3gZ4O#qahtO z0RuNVqq}HDByj&@y9rBp`pRhCu%IwqK6hD3CITy9nFUd960-@4?Sd%341lzPh{DfA z+aE#+7rFUz5CX43AJr@q7o+%`yG+>dOH#aGFgmBN^ac>hSkGw}R%RX=wP^{CW}!gv zjsTUxvR3dPV1zrPHCz^@!9A)M+FLnX2AuW^X=K2iPc5+@$SYyODR;@J0<750rUi<{ z`ITf=MKqUAtpITt&tgD-*$_arVO)F*&x^iM-tPSn51i+q6|#a>v4G}tL1KMF-L(N| zG}A9?by>*(w>w%w2XjNCTo&437Ijc35CThZ1n8&hChf!n>Z(J)xy#gFS#>hv;a{>F zi#pP|Y(l32qdb6Cpt#9zYr|f=!hAVo#LkR{Q2vMxCZQ4nHwum(Qogh!#aJm9Ki0&( z?d26{@*-e4KAol5UJBfpK!$28b)37bGAg9d*;rsbM?%*tq`h)Ss*nP&{E74j_ z3X>W~AS@Jzt-)$^@q#8Q4*RFk+4;>ICi4QN8hRvx9G&=;5{XidL~eylqsEO<;z?B} zHj_iEaa0{$j7$51RGj1Z4;|6Sn6tPtL#b%W2vs*O@&ncfsvYJaZmnkn2hmHdydSpg zj#By(a6;b~=xxm^@n~JX`wawnLWQm01fZas#4AQSXcN^^t*8Wxupy-Tj#nXu@&`{ zn|=qeABFQ}eoa?AS44(YE6+Vw{XSovI{(~r1svz~I^cBXZ&%=AN7^H{0PO47DOjtY zJiU~V=!edcw*b~FWwhSQ*RYBDLt9+X97r!wL@l#SIP^zm(j3_&)}kp$0Tjn5gIfw( zk|!oRh8rKIEPT!sgHY3V%KjWTq!s!XWRw6-lsfy?C^-98TMY1)6<4x6f; zBB`KD1aWtQh}?P7BBJbh`aS)Q^CTWWOy_E%{7S4;RyIFGy=nV%+z`$4Y1oRn6!Fn~ z*dKZ6dva|_ClFTQP@GL(8W%ij0K+-ABcNa zA`-%mQp&w+ovYtP%6}mrR!Veq2tJZm2~uPwNm{7EkIDLrd()$%p~m@U1Csd=@S)jn zu+!{Fp03`Vs6X_MezR_M3Gld1g}gLmt5$hz@T9^fdX)xsRF@UbXm%O`fw%J*M9^j> zl+ReV2^10=R>7mxngq_AniJAi%7_s1Q1kW3xs$7X)|!yIQejf%!=mu)TM5R3!lk+e z9Q=j{rEcO7t^9N&b{b;aP=PWKn?to}(7{dpeZUP4s^JcLgIjZ07nsum7F=|~Y+X~A z#aJi{yz4MRt%PY|(9XH{r0SWrpyI zY-{$8zvJBV_+=l$^Ms^II+|3R4k?BdFO}=sp#+&oc?EivtPJ$J*cB5%N`qQ)S)55j z1fO%%Z-*rMra}kA^th2?Ib?|R%849eeJ=z#Oj0HZU};GLfM9BnIASJ{|31(|MMZle zEfs0NT*8`vK=t&2wI;-kc-Ay4Y6y>&hq`n2aPcLveDd6a1XU<}0XC&{J8O@FmYL?3 zU7%lfr?GL0s}4jkG-^I(buv$8+iiM}BUh?x&HxJphZCq_oT~oO55u0 zd4)^UhBQN)R4#XZy!uF$kVFwXn8(LTaDW7fRX$4T3_+`;Zi&O*v#vRJ^t{#)qA+eV zw5*0pm|ROJQWHxd$9q$r2fkWx%*v{|A(UGEsRbtP>B1Bc3)*bU7Sp=T&AcMm4Xs8Q zu)zmZBspdke7W{xxXaGKVN5iv|tAy?d zhfam7VzgJGKzvulRl)?*nqi{CRhdo{AmbfE#Z}bZ*>7==F_DXBpvyw0bIb9vm z+?LbkEuN=FqD3w3v**rkpB>FYTl}ORe54>O8tqXKTx%B_C^vt39oC$)bO{ z;=8DKD)o+!PFTEP@scwaM@w5;7tL#H6JYI27PKt(yn8Myl0#8hMQV|1WLNo zqK*M_blSX@g>$2Qk2tGk&hqw_>8rub7n7J*gk%I%yFPubZQ$v9-vOB z@M_udcV+*j&3=-ZHJ0CFK=D^4vHtOPn&o8;@R!XTU!h% zA6T+@u8or&gJoJvJMf>Vfj7y3`e*QQyp6LRtVbfE3r&uXrAOI>$4T?r&p5m?`1{6h zk7}w&`>(1<#4@OM01OfN9rh&QlO1hZ4Dt?}p58ipaocHeuiO4DZ1J@7{}T)KHoHy1;)V?At!IGDA;a@&QvBDwAg4GP3vjj&J!GbH~51!gmNykN$!5 ze_`j|Np0I%7B!#?#i~Zv;`0V3J?XzgCXLTtZ>td2nu|Bp# z#XI5tXKP5N^KG?`4ml6?cS$$AEj_(;_S_aGaF;l1+VVMbTH4wgdT3t4oA>R4)4L`u zp0lJC#mjVVS2CKnXz9Y1MJ4au|B(}ysSJxWq`aq?w_IUP7>RNJI z)U6l4C%^RI9$22O2`1{b<3sC;-T{>|$|kd*o4r#pa(cEomGa{%w&Yac623WWeYjDj4zj(!mj?bMLiKr-nCueGTz)~nb*6N>76cH1GKSU zQJZ;VIIYdLM759R$l%c^jFtOdz&?ZWoqW;aY|AK?brH5|@20YM8|6k++O6V)Z5Q=6 zQg(EutikLWmOX3+estQB)@=hZwCKig-?nnau9>}X{P+qUWGBz1Y$puPDG)7gIaAm= zZQkk2ok<#1W^_otyuEGS+?MF{mc=b?^V%ZG8@^SUoolG`m`cCIZ+%wQvoPger@Utg+){tT(2=8(V$%S4zK(*S7X~Sa+b)yaLlHM>yhEdiXbQfM<}_TOrm#KP??G-_uzC-mJ;VnTJ6nY#mJ+LkPD zozvnROV?9Q<9&PD>dt@bDf`~7mhDu85=hl*?SO63d0M9fqPie$9ZuP;)2&Ncg!;Z- z2W2$J_T9%WWo!c0IJt{*_(iu;uB%;A4eIYHD?eu6ZFVnfpn8qFIC>mQ*;@Xk_&1q< zQ}`!eMo|6iY}=%34bfu5r`G?U%CK|g!p!X>1%fx*S6j~_qHo_#jphJTE-xah}P zD1TzhoJ0C7Wept)ZJ+zMqBoRh;=7D_hsg$KJCgr&r$Wkk?9CnM=8SWAibwDh$gvqw zS)#eOMM(3O#dDpz`P7zZxxA@M7B4)Tgk-uK5uMaJ4=425$ONecozqe@?=*d7@^lp} z?>=u)Rn&48zI{P9=L`%21j%v0B6#%gc>Yb}-*o=T7c0N)T>iZhdR~zMw&oJwYijQ2 zbzFPB=e_WkwD-sj69Uo)@b4l1tp1;?pyMw zOZFm{=UwpH?H7Nfyy(DJiGo@44VEW%_V=8B@7zC(Tl|OXZhhwUzaRG7aLORByiQ5` z_=kRaM9pWO58oQMOTUpXweR)&zdZia+;gdQ&)oTwdv;s#-Y*e1xpuy@bP|6fBMPA%l>1ZJ5PJyj$sGwvir$D zZ9b%a`j$Cs+fI0N;A?+x`BURPC;aWf=Q^JI!{XN;d+oWIf18%}o(oO$; z&gRq>wYO;6Sxr|>dh~18ZmzZWlOFr_N6+5rkPE-Dd4Ro-J@L(B54xs!|Bp8hwf8C4 zA2n{te_y-$H=Bpq`-9^z-22BDw?E~*HQe4`zwX}ae)9MwYlgfv#@>H@`~Cy3&yRWS zeQzCN@1OjS_wE1Y>Er%m>RX4~`-HEm-Tkd)Iu(z+U z_Y?N{-c?szJo(y_-@eA)zkmLIONX8L_vhQ+zRBLNy!+R8fByT=f9cA%Z?X4l&TC)w z_{=ZA@#VK~xA(_yyzR)yW0-WTlB@7^~y+JpZ73Zvf;Kjo}GhoZ3_MVw=!2ausGhQ08WrMx{^y;>GpBXmnE0eZ7XYcioco+TY zTbI5yXUj|W{=32bub!Lx^*!fr`MteAx@zi@nn&-s;xk)bxA);KyS@0Kf!}%Jn_D(- z@yd^V2L?_z-SpTNhQ)Jw`Bt|0#SO2#vPJWX{yX*dAN}sEJ3_MY>voaPO;_cJSP1@CZszwM5Pt{B(y%R9esy0qs#+w#@HpUgdY(bFa$ zJnx3xmo@)=_m8golQ+Zif9T~QUm8B|*sJS&$qdi??@ufpJoi=qnSK3*_Wr>$U%TNm z|Gwx8&3?PRU%cSFyUsbQ=1(*HbM5`iLBBZr=9i}5b*8`4-tYg>jUT!Cl8;<+wSR@Z zzyG7xKJ=q$?|bNW{~CM$=9=sNG2^cNKmDM8lfD0H=9& zNna|yw&(gNOiB29`;ETpx4*unc;f_4R?z!rYj3*w%^Qm^pAZgk>90>X_2*IJ?MuU< z_I~l>xBlBHM<3pCc{t485B$aLVbe5XI0NIA0p3(`FAq^M!m!TRBw)dg5e|l zJ8kwtOug3SE&l)E|Ge@~?`8D9H`wZbVYmNM`p+w0wU(lP-Dz>#{oiU^)W!mPWi>Wg zMIAkE%$S45ju|s*?0d(KI{1C>8-38|gOar2QPHHs8GE?ZR4+pqlb;IG*=&%@)dcx; zA*fFk{r7Dxz@OKFY2D{Y_P4AxD(;w!~Pb~<(9)2UZCwM$~BG^#-WX;clr-Env zjp-MHms764RvIC;w4mKopv&XA$m zT)r@1;6VqEzwOIU|GZ}G>Z@+c<|iC_+Po{T?!RQ_y|2D@@~N+H-ZE|a4L6P$xo_hM zpIvkFzu$7}ZFhX{o^_c*?Jm2IKkSI(zI5xOKUtIAZE$JtLl1lT_pfdF(F3Vyuf6wa zeDApNM}6>^snbq4@k1xiIAzwHmeUrrops)d%WnC~*Y8}r{%c=fyyOR;I;C_@I!qlH zo)-EeM|51cdpNq^(A2P+J<~qu+*?rV{S}g@&_&$TeE9EH)z5U2ZwWV zHKTS-H-tmde$%+r(dm(?e6}Xr6z!X;tvM(hpB|h|)n=zo8vEY5_hv`r@)zuL{Lu&G z_TP2zK0^l#teH#$hu7_v&1a6v?OU_F(0u6rnF;B9=D3WXE{5rj%TL|os9e6|OQ)2M zDC9GBJCD!g4;r2t*zw&%=1!|UswO}2h#^PirqxZ#<~#m6F~56w?e+kVHS@~PmW{)Zp){*L<($@r-g(nH1s7t{|=&8 zI#&M2JwLej$)`5`@uG__zvW9mxc5g7KK{(JM_vE@pFHr`4K#ul&Zh zzjN<>4?Or(|6K=uWX50r_V$*JMazEqeEpt_mkix~=6UCT?dvQ4^PXJ??y={@BPUN0 z|DV6&TR+4u7lx+>X9{7*?IevHeQelqOYV@cUwBA%T<(DMg zHl6PHQt^VnWc_IW45^<;b^IV4685W`vHTp*!*aTaFs-Z7v%HV)yvEyUV6 z?_X;8@cLJ7{&3{I`r%Ffij%#iUe-I1IWgdW|ER*KU5b7S_zwat<5fJBBTGIQ%n=a>GpD2i=<4qgghT`Ko+g7o zAlQ`|huqYi^Rr<-*n{0wKJo80ek0XWYnX=O*`Q#x3M3j0^gc8=82FM_cK46+Q$CgZ zIsZ66$kygg^@Ey1c2Y2e`h0(Ey-$njf-?-541))nJpYFcUib-rR^(;o1zyU}6Js7AmwtwE5c-}?tS|5c&Q$Mi1ZfTorg{ZFU8kY1)5(Fwmu z{a!FNoLCs0I>$e#-+uHnAC9KZtpEOSSlZ7W>emKiY7n;m%uuKVDgI~uFt>|g*7tYy z>$73{hdFg-ps)(9l+O=-2W%OhLxK}>`Z8bmAhjigsA;dp5B>t>;Rt^y%TogT|Mt!FQ7Uow9D8ME8Y7(f0f{!Tfq7nhhVvd*3(U!J^X ztqP@VnJbW5=9<&nrNutJq|(aD7#_N0k!;)5$F9z*YNxucb*p_FAfJkda6u1XoAq_u z6(v2u1GzvE49D7YdTUF|J3!91o2~XAcR_iKlapq*Et!>cw4U+ zkFgWiYgp+W%iCXNZvbzTh`m+6qX2i61G~cC)wbxcZtq(Cu1+7*?OiK^)#+N5u72OU z+q+g;s?)VnR{cJ@+xwty?^-FW&M$9l^}AL`s^1Ug-GZ6rceW7aS>7=tie5jyCm!l~ zi$5lRa}xdSEsWDYd1;YIb-caHml6xx8RR^RZ~e^nj(oio>@>3GciShkFhNdE@; zYIuH+r|SCcTxWw$Mj}jGvZ$pR)>))izt8UWermV(Io;mpc6)E>_I_Ho_tU$*pV94o zUbpx8-QI_Hdtbo&q31-1TFKe*QFNZ?eRrhmchdiLyvsX&P84|?+CH{Z*^Ow&0enZSy~-PX3^qkhpD~zn0y z2W=dRZn#MBqQp1`eT0E$2oSR8GTel1R)rLUg_w=qbj!lZ$c5J7Cy4kIiF82)o`4{NzwfzackU$E-uwUWCzH8n&Y3f3%AIoN%B}#_v8nY=6wS+=|bxCIbOxoU}ddo4{FiE4D?2XoHv^sQ{VCgE( zqwyc}HWpd2$4K)FY^qvw>?W((V6s~5VurxO&0YhW5KtOzh1drp`xU+js46fQa%Ma1 zJw+)_moAnG$?i*Ojj$FoXfnHGYTRgfTegebTzjXDp`AFpRiAAXtC)5W$0Jc>M=A{_ zB_%-p>7gDaz(2zoq|I>p`G;iW6iM5cWVk)hUSN@Tfou8N7))&+nN;0W z67(jEPYny(Z{MSE)0okCh|_2*PH;MKDrl%5+lkm9pJecAz~-eHr&bJt4i(FH#iX*7 zw#tDoy#)5_z2f9UKd}~63nH?79iUh6ay;?di8h(>aR7;@0H3AFl98hXIT1$XMcrc| z9Co!W4jIkz9uFKn;l+yN3asQnfu)@2DlS9b&f&#M1{Aa+pppSWS51^n!;2M+5<^$| z0}#!~z(${CGMgO55o7e0Tq-OVVY(;4l*=ZEv9cB+Ef&Vnt!j$kNGWjW%|o29h4wIG z2`3<;SYnqjg_A*5 zCbNK}hq5PHOrf=~ac2XE4v|jWDY+NentdL4mVOS(^csm9UaS^a&P(ZkfNaep-MMiQ z8cmzej;@jrUwGs5fS^i7=<8wyCs=HbDv{=TvY-l|N8!}#dK#|^{{ok_`5asZI8r>_ zAe9W;Di(0G3jxyu`J}?cJ6mjvM66qWMj|!cVwo6BoeZ(Lkln zUIeZM9DNo`;n;Y~&^_Eh=^Dd}6}F(j6JG3QC&Ef^!bV;WjBLqffMryoa+DAwDf)Y< z7iH;Rf}Z0h5?kWUoNAakfOCcd&KQcv23gLq%TbBH0&!Vhz=M2{d?pQ$WM79d zM-a+EOGQBLWjG#|+94AcG_3TrPE%~~NDg`=_G&tk$z#tZQSyAK=Oc_-23^H1l+IEw zwf!8~W`b56D{-g_uWq|Mq?D*P+04cqM+VI7#kmE#j+F@afuo$Rf)gi~EJ3nyoYQE@ zCX+3o1tzMUm9#%_SlCO(!%#u#j@%YMM9gEPFyPfW5CrPN#8b87aV8UZmY)kS%{h^5 zKBiRqT&dRqD1Fp;Q8xqxu<@w|ELrf8yiP%xYFO>|b7(r*Aq z^|1yH({Cqf^jNuG!G!ZSl&&t?WHDg=NnIOFX#@t2H6VmwLQ1_KO!EwCMk_F!+y$df z3ZdQI@5HJmK;1A{5#c;9qV#mSDRj^^8K&d;dP*NpEqIoxBBI>8*(F%&>cWd-4J_>b zyb!Ll7yyF5x((^7??I|&l&HcnyqG5W$k^||bX8-dUKpvUijy)|gP10?(hyOD_$m?S zik!`6k%kIi1$+8sv0jvd5sAfY@=WFU>QP3d)K!=66&m`8>ewfhmvPvpn z7X|lXf@_t5E3#^e)QX9O7N%4FI$W4LIAWQD;k!oRp~5WxgvBjxp*DV!63yA?YPzXT%`fym`JX{3_Cr3r$#ycV+N< z1n;N;yWAfG!e9v11+C@T`0Eg!lBA1>f*%}N(Oc{73g$g3G%-3Vq^E?Q@^Agv%G7U@d8e-6cAt?g)VwjE6;BSsG0+zKM5d3>HU~e3M0$%Ik=quUF5GHXw}K8xc!3&8D|nvBqU(*huNq$u+6U zRk%&S(IZBNFZNaN8G1=5G_ASFX<(vqwE@M#!woJxEDtuiN{YPQo2h*DD5Y-&?=1dJ5i8=|6L}WDjlrusW;LJf z9y%JxRcY)1j`|Un?^`mxA{2{z8#s}Pu5>;Mue-ayQNa=^lr&*oWxzJ&s+ka#gwVOALeNggp-hI}!8!G~`taJo>h!~H}XvOU>b}>Ok zi1&~=V!qW|j|DhXJ`RyJsB>h!&--|ffuk6ea9G=5U(=!Ai}#*zb>a5G(QcUX%_bSG zs!H4sJkwK%QwS)fOxP9?TVfpWjo^sa2XORcnG3Qqs87W^TO1z(J^-gI>JH+a9{JN% z(N-axjr$Q`whBJx@Sgy_IzZY{ksC{7fzghRFN#d~RlE*i&bk;S7b<@J;zc6r#6ATx zdgL!ytRq&K&(L8k0Ry%Vl~w>CWeE=>B_jOFi^|wd0@f_m5x`MJR+G(WP?1rW%apx4 zI)yW9AHF*iyIm#_xo{f)g)|c3s4aXBXCy-a_^cd90VnfY(Fmg!s?_l@F3uPDh?XLU zUD1iNOSKG~I>{n^kYUEW1E63jzzPt|guy=IcXBmGs&&`XKBAO92!9x84g7lW+r;{aiL-*7 zKscN8uQ>SMfSD4McXZQq$#I%2oKUnCKY{z8G<`KMA&q9Bt-v0h7ksKdlLZP(ytA$K zYh-*ma(AFU#xMB>CFyIX?}pqraP%npQOuS^I12p?-J(QO5emS%7OOl-txs^OMgIDw zaY1k}W8q2QXTed?e+x$szRm1B`Qv0u;1qByT+PAXaqwvlKEuIhIrtn0pXcBU9DI?3 zzvtjf9DJFBf8gLBIrt|IzQVy*Irtg}|A&Kr=HTlbe1n5;a_}!4e2ar`bMUVme20U7 zjHt8n3SS_PGpIIL24VWRJY75O1V(Hji33nnzgyE5!F!n?9X+CnQGFH_()9Q+7i z>O>TLC%|<8pNNv;DW7XaqSVRA^GTZ0W}u6}XTKV9b|w%i7hAE|*NMFz23jL_C?L5s zP1cpI0cAg?U(aw9TaAq&EdE5-1TQp)mFCk3#6udnR0}#CY@cBEpsOY>yE5S;)VB}k&s|P)M6fgy;+2tuaY38WEYy(HV2do3dN7TsSjfPcAfiriE zvSLQUuOQ*zNK+xsnuiyUFxmDHYOH9Zu@BrMcixQ-N9BEI{`qUa)})*Q!(2qClBz8@xYmQic4l|Qoi%~7&a!LA3DBNk+R;Q3EFGPg@ibU9u7fO+ z)Xu~$JXPF|z{f!e$?|)Y(m@(jDC9JNX;y<~^csXe=OwEq-IBA!oj^=@OhPRVPg4RL zkD}Y7$d*14QbrSA9MqwWj?Ezm(;Zo(%xK@maJ5oh5X5aJU?hdFTb&z=jdfAM%F5RY zbZNNtk=i?r-lPv@@tq-m)Hu?l>W*wcZllmz#p`Bt7HQ1SE-;(Xme4iuY9UcJ0lUeh zz*XtIp*VDH1heP7-P}ZLOL4{^a+hNX37DL);&cO3DAVYh#!B68F9)pD%gcD@X$Oe6 zO4)>DXBH+K*$!-yiDD(`p*c?}5aJ3XSn3K;{5ZA?;{z#cpd|T>MGo;Z6N^VQ48aFz zvf`|@Mb$nZLs3Oy#lp(a1z{Ye2kbR~!$i@tXz^13`sZ*90})(2nvd2 zwPqp?VluIKFu(VoJ_%O9r3nD?Z*N`$t`^dC@U}eUyJ!4~28avr= z97NQ)wxM``sRJ7WFu}#D5RoP6D`!{Qc2VQ{iEPQ%P#yjZ!dV{uIatTR;T#;n!I2ys z#lg`WJb;5^I5?Jr2XgQr4j#VO5-v<6g_# ze2=fQ(IZ3;n7qnBs$mIsQ+tqJnKqOd&rngu~aK`KSre;7nlth z@?2U-g?u#Aqh5a~-s!=WLT)_441Z;c&Z*#3mM>!b0y5pA^r}s+R4!8lhKA4 zMb2Ovb4bDa{>X8C7u^qGK_g@95o z=;d>b*xjbFa3>sfXOss$7dH#AxgfWIHN?n9m|oh4q-Bu!=t(onT&qcY9=lQV=e;D1 zRDPIMP&aF$DMw~M$@Nrz7oDf$ruQdL%4M!e@Ra4z1*Ft7>l zWze=!u252TvZ%C+`fq8Bz|=)jB#B{a4boV|WlJ*;ut+9rS;mMPD<~C&Tfv{w$VW$4 zwg=g5$LKfg7EmY>7l5LYD3Xn$aU0#QoR3)&+B}4zVr0{_BIXz)SzV&#VGzgQlW!&E z5*`{eO$APS2BRv`x!wcorflMp4nqGXK0I=be0@mgt$s>it&B| zP4NNHSHh=K!bDo`FsT)a*G1E;S0(ub8awwv+##@9;HmAH5Rbyae93|wx^<(S%=Z-q zdYI-X*;qeVFQpg*pCpnD)pe!&!MGI@8z_9!;`TO@CG6*35*l+2G!fi)mw`6nHcugP z>iVfgDy36~G^lNq!fy!Q1-~tPrgSFZy@Y`$<9!MPm*SnRd>gNLH; z2+5KZn=VzrexsIk=327jW=G4qn8; zi#d1+2fxU{OF4KM2QTN~mpFI@2bXj3%N)FtgI95|i-T8l@EQ(&g@a$^;I$mQj)T{8 z@M|3WItOpy;Ef!-iGw!-ju4NJ=3-ldy>gQ7`1;>mUMbxfCSPtTC58bU%~#`@vi?6! zt+uRTu104WJTpi-r9mGPwr>8yg`9siPyfqgB>N63DTs=(T3vMhfYD--ryFW&}09NCtk@bPwAY*s*-84oi ziCv(T>8X{kHIw{jcrM|!NVgBt zGsCA@l&YxZ`5=PD2W^YirS~atnYgwRmr-2OLRYhNY3f;|-2y2fZPK38W$JDdB)f;- z-@|c#m&EAx~P0?Cy!UXl{Wuqcqj6C71s_B`1|2 z%*giW0tplY^M7&U6~pHtLGzp+KS)b$9`Z!e|Kx8Yhv_-~1LK^8#{Ez(bf z-%*l->D4&fFJ0-kn3(Tq%4;6(_Z6t4ds^>(Q{bcvDv)k2KLOz$sil&1_e(%kQU8dF zlSB~qK$bwrPz3)`Nfy2??wip6ijWs7!7AN&UKf66MJDN|$3$7UAFT0IfO7cbpHuOo z2qz%}mCrKxa`|x8d|zq)H*}mt`QxP9Hmg=6M)*7QyLHI!k5Pb zaTlJQHA}~o-Btp2Zc6^A^s~Ubi`1T_o&CST{Ldo@!ddX|D)IjlQF%1>y$jtF@EZ9* zCI9tItB9dK1Yfz2teFKBEmxX~As=0otpN&Ztb4g1V?v~2spZzZ z5uR**>9;$@8@BMHlrqoSE`t)+zwSHhMWZAfo|NxtA}e;~_W^jGaVBVF9JSob&lCPZ z;wHPvoit;C{nrHe1HKNAb#9FtwZxG^GKKF~>u&_qEKd2>DJ1AL{`KDva4YvkduB-^ zf$b;geJm#E)D0TC#3oGRxv&2g?(HYFxuT9nyHoVk*>v}jFEl@};O2wP;*E2W*oZUG z4f?ojMw0^@FQcKiM%2PU_oCNiIdcUae#?|LPvYRy?1{K(^rX6`-%Bv+aXm=pWZ)iT zWFX5GSUYGk5w?uO;dgtnp@t-_WDBUt+zvd=S`_)QBPU%YgV@J_qsZ=ywmoDoQ`PQW#q&aYPEsdAZ@TVL>n6D8|WA49~cm* z4Gatn3JeYm2@DPL#g)tcK>BNJU+bRTH|9dycEP`nvc>3K)gKhySQk@V)#m2$H@}G)Tyl8$ zfh$d8SEff?eLF8Y_CP?&4{PgBicNQI-}dL?owU{;YyDo!tzqK9vecKU(UhkWD z+ApzeQ1iI6Bl;OW7?hUz^0l~<+k^6V*0rqurqAHWpZA?T`+fG{mK8sD7=3ox;P&O# zwayNQ2QSd)%rx2R#N7~o^dcnAc5D8b53($A1MY-2*?o6ST-ym%|LVTy%eYm`!lE6U z8pj(}o!wY9Cp^CI!IQ^#^&TJJD0InO)32N2*GHWEW$GiR;}0xc_VRRYQ49-M)nwzpSr*4cSV^)s(NULwq3e-$b`VX z8&AFa(Gc_AVV^W?B_tiZ*89B|+G~?S-`JIJ>ugFoIK2CV59h5)>Tu#63F(_Jj=HrzIeXiQEa%OW$sMf+M?JW!SxVQz zp*!Y`8IaO@)yy?-gqNh0>|fkDO;t+I(|9#XfH5^BosGl6o(FNL&mQXAf8@|ld_G^*t-*q! z_ZA-*;5+ccp?$-44u7}&*P%IGn(w@^+BdEA$JX8K9~;uDFTQ-`;k(Pz=5F10qkF$2 zX;(%C*tf^k9hMg;ly%aF4*M`%xNdrSBtT-f1#? z?-RW)UrLV{e$94kZC7p4@XhlJAMT@jWB8%A8%%pHo*w>;tHlRDtZ6+Wp{nhT^>gAz z_;>KV9W#E~h{;_h1-Ebc_K20eM%K&v_YWhc{WdJ3q(SGAuRPUfaryH@N6vldsdplJ z%^kV){0GSc%lD4#t9k2UdYzji<6b+{Sv&p7bl=#|mbm=&>65v&GY_ zF&VbYquRVOcXGz#+rqA#YrQSwTE>HUr%qnT`0?#eqSC(Tka<06)tsSglQOqHKC}0x z_?h@Ro(N0pyeHFp>G0`=f&aOkaL(yD{sSaPIexomXT{*Ida+zHuaL?Zr#Muld)@ zKD_2!RMM2N?7cI#_Vh6v*!Qy|A~@1e zw9PlEMO3k2X!W}}!(ZHD2x=5m{mY&+hKTtQC!Cwx7+cs=;*Xw)H~w(&y3h0h&l)e@ z_G@WuyVIyInmppYM}IQ*Z8-nd@uQt{8h!TWTZd+)<;?-k6xkds!)`6QRZUVnIu=G>IA z4PFiIrM_hWrgm_)PICk*Wbf-&?l}h8=suFJI~*5O6sh<4fUto{dVko zc|8mTqd)QfIWMqp!=TCgA2&~H^uqp8+eexIbui?mU1bZ+2W}te|GoC0Ie6!-vd6sd znjf>T2pihTKmT$<_(vOG&&fZ3X5sEuDdqXr&z=f=Vf(-G8|{03-_}m`E%R-?0y=JZ z%CbE7w^K<2$62OKy|eT}`C7{<{jVjR>V9qMS@P~ri%vbm4=QMRX0zLbLt#zCOA?*``qbR zx$Iw;rViNX$o_qw|JFv|Ii7ysKILRWOJ~C^iKmXeGSHcuzp$ZkU8%FO!T9)lhqpVg zeca;o-8z??$L|f^JULubIJci`SjXg)!ang;Kb^~+UAS96VeF~B?-#Z#nY-r6uYN8Z zQQl`x;o&F7Tc5qtE2U1x_-_7t%3EYD8ecK_hyBaLs>Y|UyrAtLdvE;heLkJ4e)KQe z`EyG5u-9{o*7|PPHfzz#MY*E~S_3D2UgUK%{ZM%O2a2Z!IHoi|{dBRP>$N_E8{3Ne zRxNyLRoS}YxC!GQI;j1o*t+TYoZnncC(KRjRr=I}(GvOJoCVss%Eb#K-#EGBxo$Y*=$>lj|%JHVitM zKl${?{sR*>teO08+mT1kqI&VmvVAZ^N*8qR zF2KuUFk^=6Ye#*O>h-(#FOxpt^o7FMsO!mr8O9>`zRhcAB1b* zLJU4aB79n-DRC)2!IUTEo#ImCqqz0ucUr5Fqx?{MM7t~nGQn+vtAN`HR|%K?w2x2) z{|H<)+*P<+aGIw8hhe=6Ux1vx@DmYE6M(Ma$p&Nz*$Zca{tspu&LRK+ literal 504170 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 Vm%fA&Y;`rim4!V7T-B_F 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 z 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�AqQ}b&( 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%0Ax0DsSE*KQ0&i*0Pow z7b;#*t?omu(NEZ|mjG88exnD=g#!X>x$#TBK?nKk2;xM)$2cIciHnu^G)@@WwNWrR zb+ISdt^z_M_p^Vg+ND-rjq~%Aupd`}OM^u<91ITfFAwXT1mk7-w^}ix`DkJAJ2}h% z9jd7FHDc@mca4>vjzv`BuB2x%fiVvfr1Wil}0>%Kw}Q))uNjun_nlO9H%# z0xeSyaW5o>N^z$oUP(8MPXRFNUQ#`tI!flFKSeGU(O=1-|KwUPiCb}g>~WnVZ9%OX zt*O@Ws4%>A#J${zy{JCnaIi#X95x;12pH090gMC3T~ZhU!43wT9m_AHH7zq!kTgX}kcC!LKnXffj~u}DN%YR(OCBP157%es>A>?ZNZZo^m&3(ruCpyx z2~o_ZhbPYpAMoiNTJaf)2iZ%B7f-pNJ~^&VJv3Or7qzVCllk;Coph)!F_1W0bCJff zys#=d6;P53Ig?b|%UHGC7chV- z&=-o?04murkA1REtK>RL&W-odX4GtN)y|$ z4lzRZ0GktAd1ueD_y(dd4vz;;wMGMbFOItecFH(C#yDZTw=oV`9peBZNn)I?lySP$ zWD4j8>gkBVs-h!(;p17FqDzdcT>e48;*3%Ks zvWTF}96tlOI4FX3bz^dLiLMgFld#?$cjVkLQ-Eb`Q%YtDp*=a-Anoly!!Q?>#WsDS z%Ve>u{2fEutxk<0mYgj4`w)LSqqPO*EXDi8-8oxk4fk@~$A#&zn)@64*e7z*W;d`1DTM~9b~cOOi(Tj{m+D7 z0gD_SkymZamX(qMR&QFL`JQQ3sOv&m*|VjvFy1+n#^T9RIGdP#D>f~nWN>N3aK@6e zT+>(|CY=nmmQdkvf|oF=*RoQm79&+_dLc;pJOpkmhz7RS*%PD?8Q3LyQjtoui&{`Ph1i z$lo^R@WR&M0qx+vdUqN|TwNlnJ(`VV554h;cTIl)o=58s-pe|*$))K4Bj0NzGYtEu zhO`H}s5$&=4rzZKmHS8~DA*Fxo^b)#)+brDYCvcZsaMrgprK$E@OeyoiEO$n?&0t1 zl`$@`%=|YiP+6K@XT)ZlB8l4I564vvzOA0)NjubVsw8qjb!KE>Gz-S)P*R`O50oDwA?hYxIz5$#gR0`C1!QA*qg8cFhP9+<{5b`CYBR>jjQCcL` zlI||9R}wlCSB{?wYuo8z#5)`uL)#K+Qz$M-N^{6g!-xBfbFsFrR-xw=9cLEiIwaiq zEh(&Ta^018d3r!xZTD4_i4_#Oc#+1xVNx27Ie2WNK~hGZz~WPDz(6qccW700>V4?K6O*1+ zJSV4q11x3KAh2H$8(mIzC{pvOMnavww7_>b)o{LKGD1#Q-T*K&mdFika*RgUNf{Re z5~t}RQ1yhn!hjYiJ;jU$6PS6Mo#GR>f&d5`Bu;=afC5;6R}9l4UiX}Oc`71CbF@hq z2qtBz3`5w7a)2hk8yrTihyBoB?VoEWr5%Hd(Im)yDo?LyZMgc9D2@V7TKj2ve(84^E%^-Hfkz*g`4{ejb6$t-|DM_bW!XkDTbv?zWm z8kJ#`OW-9B(>rMH3jMD1QlJVl(09YCL*gDi#2w-npV(8$HfGB~f7qY1Ll?ui1O1p1 zb|()aKw_e*>(qL*+N$^J)^?Z;OjVLzF+LC3ZFZV00Zjv5$6w1Jn5^8*WICE|{BD~a zyOPVw>OUS5_9gU{9b|JG>orw()H!><+PJ1SDIXVy10TBe(ark*MJEtbV&IzW?aeF1 zspwD4zD{~ER5;Tx(0zW~bMwG<|H5PKTpVJ?gL( zXNsFHaAWJxE=^wyL}6R3pc$97Nt@0zb?$2BX3%MJ;JYO^H!x5;rZF}}EJsHfNsNvG z0^5K*UQ;Y@4K7YzX#st`K=&bO--2qb^O#E{uzZ`-D6~56Nar?P$)U`V70>9l3zucomM=Ei* zW-QiJ;=8PcF7aFgVZd$^vWQmaLbz3lM#$MK;TFc>F^paBwJWFEXo1;Va`5pO%eHcA zRZPXyEgXSayCJ8Xh>^V4K)8l|AKiIjZ+Z7`STLWfL9M;s&M z0@fFN*WKX2?Pl8!r*HfSiFmGEi^zlvSHHc+#1CE&$T{pzCMZT{)%e{mQQ!Z~|6oIL&Po!+8XhKRMS4BEaj zfoq;VR?q5va`h>B8&7UOWrb+mk>p+K$hxGO=~G<3Hp7N>QjE&PS%(A?!@wrPY~sUr z?)2|Qm5Z*dR-c~|M9zx&kgf~^0r&-KKFuzMG&DG5fE0(89i6GSo3J+V5= zXm0FNKZ{X?#Guc7{f1u;llmN%&|xxT4o0{z`4JM1Xfny8{K{|kH~eZ|d5T{Jo_UsE zU9gi%7e;_$KeH4pR*(4F&vcs2-0-H3Yh4JgOaf08$A}-{Zj=7W`pfR}k}&#mrS2b1 z#4*4r80 z6m+Y)azRLD&!c-Mv;qdO7$SoK4veiewqc5rQUiO+8rj1m$iSp*eNfT_V*4|tYeowD z1EEX@L&VDBwA+2Hw`O?%mhvNdV3A=sgBDOo#b$V46jvT7X%rIuMC{kes1FhZNmCiF z#pqOMlrd16wmP?Wk}7=T(PGjW-U$kIYdu!IMppJ>o9g6Jjg%_UwLH%7<^l_*Ty69I z5xdj`rY)ubv9m>g#)e(6jZ8SmW36*Gbm=udSr6DoNzHnQi-ed+RqW+l26^`3R6z^Q zdgsMGRP5TQPfQ!AYG$-n>X{*smC~WXW@=T`UCgHjn{mmdOc$<8Yavw!^8hn7^8hGy z(+Ju-DuPsquEZb4)>zTBcI;H9gGy3*J-;lknf5Ble|+kDuQ(QoS(`-RF3?2SDD9(` znSG`#(H=J17^01NRU(k7i?5QQlQ2C=#7F;xYGf)X!kQNMwMjt?%r*5gr~pXZs%Zns=vcm zY;EJ?=)*i%!y4(qrG9M>$iyPoqHk+aGisP{%|J7=v0xg87|6BduF{6=9$OAGUYq!> zAcvnbRu8mHABM1X4FC&q)>>fKqzO`+Ud|Jx_?18=L6T{%6Cd+j2xMq@66yTRd|KABHEI>OlO9>KLjhn7p>NRfxF^kq&S_73F&p41U zc_=(yOBo0n=5x_l;P5%0i);o`%&|aIeqhq5zyUpOz;c*pRC5Cx1ukDY{(xj`VkY6LaekB9A3OGheCEQCz@0)!>4@V0pTr z3X&^~#n@bs0P{SmgQ3_ad!IOyDUH9E<$DosAXpx6tv}0qV>%{8s?7{~4HX+niU|K! zchihefVH(%e_(&dHIT8k+C_oT7&iriD`rq2%nMNCtT1ac&oQPnr^^#)lqx4e*K4eRgC@~Iqsg?&D5~`#Em6^e0O0#Snr8tV=VIyt*1{(U& z1#|#`U9szlTf6b3>jtgvF)MrvKg>JOE0$=(w5#5s;O z9l>udE*KxDXweiT7jV<-6jQ`SolzJgi)NsTqQBAY{fvWSp1G>V*|W^P)t6Bv-A9Sj zcku$o!RW3^D<0MML$-Ia2Rb>rhLgS?RH{~AfuT`T9ASx~XDW4f=`qz@>pVXIRC>Iu zc-2e&+_q_!ZC6aDCoGc5h%_cP8T{B^qCX^{V_-lv36sc`DY=b5(LZa2K&qLf(dKlq zwtSFe(9)RH=4mj5vXFS}ZdA32Ve1G7213;>x6aHhx0slMer1B#vdn*^S}%h`i4@+I zu3gAU9aPAyRbe5buOwlA1JOW_By$^N#Y$?B-`PTlDDkBbYlwz9ejy3D7Na;}BOFfM zIBMmv9~iji8Qn!YB7ytI+D%x((wCrh!-B$ea_)+{mI&;CRTjsc$1KBt&Rt>ai@Fpq7>v#-mEHhC!s@x~9J|ayqc-h> zqgf~ryrV&7uwn@O2Q0$fqBUF*m%%-%7us7At^iJZg)~~golh;P9muP*gj4Q1%t2|Y zVm>rr&~bRmGOHq*E0kXS(TxgfE= zq3+rMG@9v&T3uE$!0nEf(80{mD3{fhFpD|}mkXBQXwXmBP1=bE)K!Oob62RpTGeS0 z5C4+gSk#fuWfM9L807)9D#cBHTO0P`RTs%1BX(vqgtAABFbUNWxN&gY)Z`NGJOG&J zo&CD|eKnfA2$)zvS#+=Adf>(cGE`$}I;jWRrSv4FuMBN32MCGG=6`#%@h2K*?djrngRB zTn;B!J}e+Ag;>4lySD!@@j`91W{(}`*KwfXJziVyI-k`QHWWQq&p)?b!Ds8-x<$2? z*Hh=boALdqp0DNCJo$6QWLUfA+;i3M^VO;I&plVb5pvf7r?9=vz@>(?Z`cN~ub@$| z)(wjT?0a0+uis864#L|Guhh6108~)hl0;?hz8v?KT$8u0P zKTL0lC!(3SkZzUCeGZKV;5B`h?9Usg4nhB_7A1fam(IB%4$is3HUqpB(G6^mu%I@w zcatl<1um}YqCm`@)YW;Ow1~LlJU!35`8)zWPgW#I!wMexJ3{LIbdsj5QlGc9Q$r9mEv%OQlV|6L~p~w zQ5GMFd)6Ql!jXE(y=$Lq;)TlpZW7i=bc_f-KCcy|SgHA>jT-Ej?7z4-{fyMQoNYGX zGYJ6+1Afioe)4&qdiQ4ip?CC~eXEOs$8{>?rPfi{<*~t23j66*8Pri-hj2!-Cn6Ad zJC8vGZPq~figg=Dp>*`Q=ED(v?aJWnRC7Yw8Z9D(Jk)&sbh_ZvK6_0_U8yjo=5x>E$r8fzgrxjCnpFB7QcR6LCDXM-2{MuLa`dWO8R&J9 zD<**SjqavpF(yqFe9ln66O!mwxekcwF(ajN$PnoznH*w&F9bOyWKqBngry}30D`GO z;)t0*_WM9TDk|FJX(>+w<`VY&1FEMF>@^{7#IvSZsiN1*Lfx1>oPS9wpVAEps*w8v zY)a|jI#r3Y)CV-N#$}O;MGT}ge3CVVR`&|2@a4Tu}Y$p&JeUp>eh+Z z-r<^a(c`s`pzF=8&Cs$ME@5(Qp-4@vhXm-RJU`fK!7)3l>V{Bi^_Lc#xTg!pgILgJ z=c7Q7&CR?b*bS{l8L&YDs_|H8MXUFmwMCUNzq!ir9vXJI4Z(7T+q_;8SgN^@S^<2Z z6dHgJ-jP^oaFx&(B`R|ykLYlexOt11l?AmbfE#Z}bZ=(o7Xn8^7v z&}AXhan+8yFDf!PbFLB&vYxlrTtt9zl?IPN6^bOtfRw^+4$r!m5(WN%VYI=WmT?SZ ztWhYKquXN{t?i|-AFjZsfDr27%c8i`jBu+T2CjxCTxxoQM#!9A)NA^*n1$nSE(_j; z+Bvept6p{R@$VcQI&I0av*HD-h88Y8Jzg@n^z`8~;!~HMxqQ{|{NaVmmj3Phr3Vbh ztCkK8p1yG9@ZeB9f91--;gxarKDZ!0<(zog@EQ7a>Z!|CEgfFzd37)H4)HwCm8L-a z&iPAL4aUREVsg4V;st}JEnK=#jl^dT4$ogOe|Ua;>d@f)VOQt;rA@VZCsXHfd7VRp zXD)l^U|Q{IL(9(mlPkWBdgoH_Vey-mE?&Cqtflet!J#u3u3Ra=hLCT`!2FUSg3kR1hhz~gW?7>r44G+#6T6p^DgF}ZMHtZhWv2eiw zl$%ZYSC3o%4TERRoj)`mgsAlL?2*D}Q}!>$E&IA?~#TzNYAiLU6qe5dj+ z8GPs9k^>$ge;@gUhn1_AFJCq!LM#Ir#t1nMCI^wX5BWxM#`3|zA<~cF`(9~1LxZO- zJALWGl~mM<)Rh@dPa=P;`py_Ub+MT6WY4>lv~JRV@vg}8`JFd(j(s^5SOyO}49=Oq zYRT|nhou|`nnkCThaCn`Z_0T!ar}7lu9SZL!llD+S~)m0chxCN7M^Wh zO-@LqM`FU`?-mZ9aa2C|+v9gsH3icCxhfK|460oKLqvXoJ<0fFSDO}tyuhaC4b5M= z^0c(qEB|C#WYzpB2pr9sBIhnpU`(#uaUJhyOgT;L*}_*l%bV@0YwDg+>xI_X+TWe6 zbiuMS=Pz8^rmsiY$F^7>qij>hcD;COFLqEvKKV7l{~FkLcy2yJ&s+AlrZVJ{W_uYq zc6}!dzLUA*&sgCLglAO$K>DAtb1$T}oh*wQ&_uDq=vsQtT)wttxuIoCnBB*o%a@*W z0$ZyY(SJp;pUc#IA`Kr^qj$L}{vLO^N)45&Ac;T7LmkgdcxYX(Nhs8oAT0ZX!m###+ zA6xHT>D^DA4W0WG=Dke+HP%YPPgenI2k!2;qf)N`bCLR)=g zYmGmxuJzRQw|QN|>Fk%)wd}OGr5BHrUwZH;EYH^j6OY;P{dyzsm3bLu)3Tsty^}9; zMz=Ya^0V{uL*uM%#;Jtz>!|0i^Lke0nsDrdx%U9y8@jvTTs(MA3hTn9X|8-V=6O$( zUu%er4z}hRzlhg2A@Xnu7z2OJ3%ZlY7w7p#;cVQFuA!{fLJltD%jKr9t3NB_(Fi8* zh9Y z9hT!k>*NKLZNT7+0`bzpvxKeF7M{M!ElJ~iMu+69hF30JFc_acxO8yk!j-Y)4QYjC z=X&aVUEVM8TieP;7pB}(l-Jrll?zTdYwS1~>m4%5jji_mmC~=p>&oGUtnNUkSq0`% z4tK+kzew*eSe&aHmV`YTuNE-$&Slrz4E+Gl#zUDU*=7Ywuc>-7urUdSBzUGTj4ee z&D_(?3GLg-mQal{3wEK*%4MsDP91cHrE4gs@xC){wesJ+l>N(b%Qh6D3{th)GkHgJ zKCxkdC>ErxqbNH*-I~fG)DQ4RD5E*HeIJ|3*aWO`avSBai;h#Sd0kQj^>NC|j@iD= z*0Khw*SD9W$LlHE!~Z4ze*^y?&;PPDE*x5R#{754;`xpnF zXATZ6JT=eu2KSC?xN2~8?zAq)#`8~EGDw~1gs9d-gDcH$c7pvL(Kr3TxNUJNmt;ds zsrP@=Hs9-HJ#72cjfH$q>RVjf_>ba@h*PFBiIRK*o;%$GtDxUAn($JaN-Sf1jK=<2QK0tp8WG zC-(IBU-Xp)zn;DH*H_>0!>67(^0DyvDPFQspI+|&%|E`X>q8HQ&&}Rz;z5rLzx46{ z{q6fYx0E*i@Ro1g@uJm#`HAr5`#<&uoLw&cEV*wl`{%yun!mr~zAq1beHy5h4hzvZ;MZ=QDOUN3&zeFH~Kn794Z4J+TYd7meq8T@VE z9dG)>*S3so`SsGL?s;O%JN|HD*?aKleg8WA_P&qa`RwNB1@|}ZzV>VTJiq+YTb{k& z-jCmM$CtPL>si}>|Lhif@A;3#$rB%Z^Oq-Wd&J(4*tUAz&HLZ`{sXr?ZtoXf`=*2Y zPI}{gbGAKY@1OhnCvLv%rWOA*f7>>D|K|IC^U|~G*ZuNc+e+Kj-kB$!-T%R3H~+7z zw)NQi-`(^1e>i84Bi{Y5+a}xltT#XV`a`db?)v7o{p|htYmS+{?3Y)qdvx10d;i*D z?|#`gFB<;7_uPT@{?yf9x%yk*zIgrA=MJ&=pWpO~eXi*~dv1xnzx+S{@1I=p^uxb<;<;gazkOu; zr*6FYbD!&e{#<*1-)qlZQhvuNm%QxxHTHhu%sUS`dHWq-Kl1rY?fp$J|KbNPz32^B zz3urc?fpyVPhURmtY;n^e*QXpzwGv(-~N#=J@|>sp1Xr=RS6?}N|ZVeg+m_~5}ez3i56J@foVd%tP*yY9XF z;UhmZdHZI2uN?l$S8R+FuL(`^x>e%gD?0v#FybFK(xl5iqb^9as z{;Pc_UB006=XadH{c(HWyms!guFZE``l0Pl+53TmFM9Yb`+VU$w{G9I-AnHI0t{U4 zzwVyx42vy#`CLcz@%y)K-L82>|DAHvSATW(&7qAq&s)=V<X)sYvx#AJ}?-MUxD z*WY!|)f;Ae(=7M$lYaTGd;a45%TDwTwD&Vc9{cq5v%mYjGi{#pyrb*a?(^~kj{nG7 z?+E*Tz_T0gKlo#({`zCyQTBf0&6_TrJ@}JbzGS+z=ly8#)BAp)^J^DAVDiE9u6^-} zfoER)4;z2$on-mn@{6gTIB?nx%Ph6lpmk-(MRUpc9y@!-tYSAhyVWai~s)O%l%93{jdMw zs!d-#@ztAd@~^b_Ti0Lx$CGY*#Xo+{zs}x&_Kx)*`qD?{{N$(p_4fXTM_YQ8e_j|tl*t`?JvgHd02Y1-}!%6+O`}}U(+Sdge?fv6t zpLE}c?};~`7Hqcn2T!cM>vwP4`jvXy1%fxYuHSTbo#&NIr8keiIXLfAec#=c%1#`-;LP^vlSanc7At#l z@W3y3E2A!TJF->j%fZVZ#7-KtzHr%5WiSUD4lY^0p>5FF&y+(r_}Px%ys+x?_8V_0 zV>$TKX%`NaA9>=chboDK{rvp~4oEg87nc|K)2QJJr-I9b8v~aGr>AFz-WPwIeVzOE zb$0fzk&ZB9K{F0+Je>bOe2A|Oj%1hsS70o~Qm?Ao%>I9V7{fOHyMp{NVL zo62Zd+~}ZEsI^*!PUoa>R=X(NRi3PuqLsR}mp9u+(N@vkt&_U5t}EM{A|4 zys9{(_&{;i^<$@Vicb`uv5o4l6<1W>DSpylSKU$kro79#_8B}ZIc53AjZe>5{MZwl zpF8yM0gcuvbm*`#KR0}!@@^LzHYRJ%&b|9y3u$b%aM7}jDmQnpR{a8kBje%|M!gj+_ffezg(@S}9keP}ZE9jzkXw+}Pv<LdUx_}>y(TH zV%^$noiz!%K2Fsx(Zl*{2CJPlqcyDBQ>nHs&g+t(bGB`p)IH9{S>x6^QsW%zt7>a| zWr!)=HNnX_KCWYeF5N9r>ukFn@7!5AJTXk^u5;EzXr1SVw$~0;b{fNa1iH;%S5WO@ zd*jihe78D(PoL#G=MCTV%Df0|e^s`ow{yI6Uv=ww`zM%3sv@*rQPd>X+|kvY>+iJr z%G@9iwzI}vrJK8Ck*Y-PrgYMJuF4(mWF2C=?QGFiwuzta?dt8C<<#D`aPDyBf@qI6 zb*Wu78r#PM)Wf>5l>?O>REoJ#UA-dJ?A(U_^S-tH(l1HntWwPPicK17J3d6isxs9b zgB5e#eN`scG0wKV;ho)lRZd!kyTz+I}!?iPH z3DvoS)Jbc5rn+_impC-{RX2{ie99{#|ij`M_yUP3_{PoBgxKE?%;t z)0gfZBa`ml^BeR~_QafvbxW76T=ndMLxK8dUE-`CD_9W~mE?xO7qP+Rmg-e&O zyLrVWn#{Jk=U#pN$j6^tzcGKo;w{@=Kl0|OGoO8)u=ch0PQHI8F*zk`+@zdE%a$K_ z>E$EGPM-S2%ct#x?AyQGe_$({^3?_RuH_Y-I_J!qy?5W7!>{_Z?b0=VcybE0|Jie1 zeDmzbUtGU&tID$6TKz#H=XQgY&YEytyv|i) zb?KrUuNvoMo8PXJvyW4f%J!&c*A~~ds(?+Zxu5mcx~kQ-ZJu*)X<2=L4X{g9w%3&% zl^$-{)iW3dE2sG|(^{#{WhS<+XIiz@cXie0cD?3XKcK(A-nU{~qpxB|?!Yd0bN!h6 z`p}IJazlS-zYb-cyM^_1`#NlwyD?%=yG;@Pos0=TciEH_6>LnsK6%sVl!|U?8(!U% z#+)&xn?Kl;&V1G_gK7LabMHlC){mFEjcfRB(>Oiz)41#GobgO0qh$tSOjO_>o8aQ# z#*;Op{1pmT)r0NQae_;vlM~xc#X4cAP!CWJ(e-b~>cbF0r9(MuofVzgNQ$n~fy7zS z0arvsU`$adP_Jwkg%Z|)fYl&iy%jzfaX<~;I##Q6R&>GXDi-$dPHbPW2Un#UHLg{- za9l|wB&r~|lOh80iK%pE6Ic}s=B$n#%__96x;$3lBJVO zSPg_yv{$HxIYFG~zWv}e4=z@Pyu!PmI3Ku69t&Oc#bZ4h3RSG9oqx>9&0BNLps8pPcV%QVi80AtnSI=mQ z6^x2?hK;!b{SstvuTZmV6dhW*vAuQeUHp{($eTjZhmAqWD_}FJ!}W7P;Hprlk?;Nr z9s3g%8;hm4Clt`&a*=&p%_xyeRbR{rw}L;TNL9wW1gK`Pp&tE^PiJKScxu_9%ARUg zH;i>v1UsR#Wpk8NlqeK-1FO`v;YyZeeOPy`Qhh>4nQ2R8~l3{{~7v}IZ**LIyrGD6v5jjO7vsPYd83vN4B>EiQyE zUT-O$j?GYRr?H^eO6ryheRVkSW>X+0QW1<{#YdQa_OulUHiVDX*w1 zGnO{N7C;1wQ!lwcktgL8DUYR2#(dH!N;pzZ%_dG2&g1?8Q$fF% zWwex~ml><9C>A7|Z5wOTvuxgohB83O*Ng`O}-hf=q?5+<)rw#>N*vx3G;!lT~|6W3`*Vl^-H zL6Lgkp9Gx~{LS!*my?-aY9^!8NUta}OJ&UkUJ4s!u&)fxlfn5i*d&9^GPpnn7s}uw z8C)!bC(Gaxz{6(f(Ir!V9I4mOVwg>X_I#Q2 zmkaoFJX0+;aX*(o}w;jo$_gv2KP~T+Es85WQ^K6NvCElDl zO%I-VE^PsbW94;!zMOg>Pz+NA@a36-(*wCCyX`RcA#=$Jz)H3gbh03qu-m-JfL6PoG+9Hd;`N zk~|?R=v_G$lnayv&qok6mlKYwMaLrhTg3_cDZP>3X42=?(ejEz5j4MU45#<$| zOlDY(h#9u%ON&cTODF{FZRJMg(jFGoTS0LZW@1#6erT=cN~;0WD8q_xF&R3mFxOOK z4-mBxHCSH-kVI1Py+JA7$KQW66kKRq<~ zC^%~PG}j^}wMj57ePn!fQ%TU9AU-uL z%rw78;buvuGo!1`RkbPARvi5q6CmwGsvsY4)oQ{HWhsuPm>2^pR^IWFUXtGr2fmTm zZ)ZmdCwmghQ7wolX)g42^_nMOHM% zyyDVgYi&%CvAmE9%l0EM{Ze4BRV9Q;WvxM4Qn(grPy}m6h1FO(x*7)0P0XZ((-Dy? zv8E2$UUpD3*hi6>vIH<-aS!s)g0M&bg|ywHYo+3%J}GombZtvAkx?(7@NDqa!%_9j zfs;yWlfiS5&7X*Alkv4!l#UVSAtG63(Eb-*u^Wo@|(UI93kJHo)1 zjI>p(l+msNOb_Ja3ls0sVtb6k+U1u>FO){iB9tSSHh)&IM>sjvnpIB#4 z0Ot)ypT!zDX}q=Q9&Vv@&C#_YTTtMMuC=q{V6iumMt%|)!CcJ*^QTntydXwW^!I!( zDy4slFY8WMZQgNqD_9^@m1gJ*zvBRY&Z z46`1zR0QNUz{z309ZKSYMk+n6+C)P;l7k+ey(1mT)MT{AQ_A^J&qo+X84N4#pmf%- zjz)51fC*Y|ti;JFyxNWLkW#9#xT@4#V9kLoJvX;N*Rc`do^X`Yr{TECrIaAuJf+%P zo=>J(Kr@o47OAAsz(I?_TL?qZWZ3^J_aR~)!-oOym; zgcx-b2`%=1C(&U7)Ek4t5@l1Tn?a{p(_tT8W~B7-w1Af~6-5+!HwzE*U0rl- zqDczdKQDwE%1r>l-?0rDj^2k;V2D9ZO0fFPmVpIQJO*qDZGs| zTqpwM&tRJiWUvF$kvA0rFSEeZUN(lK6gNZ~SHz(fWCLNMNme1Yc@9#Eb3!32gzQJ0 zxyc#FtBIl+Yh+`-7=c5!&?02XAEgLQvNzR33sIXjCR-gM`y^Uqf^gGIv=PE4am7+v z%9n`niSYnmuY~8}7E=_P2~9*T$ln6+^b&a5$3!6N3DH(S7@&%tDxTD*58H5*&>n;q zmQ{TDHd63FNpOoY$cn7~VMOwgL_!M_D;y~iwzVLLWDN!(8VP0LBjThkdMb=34j;SN z?j`Y}Ye}0A1nF0$of>tv^ax3DYJ16d#lZ?R|T5?=kT1pyf zbrGa&#a!H@*yI}Xcn zqcV*vm_wBtOZm|R;~RHDMiMuwlogjdr1C7{ml+*rM>`Q_*HSyG^|Pvsm6f#2mCCUT z*<1`seI<44K(L#n#KYAOe7@5m{pZLevw&V3!I(2O)M+1iGtIEV8K20?Z#ABjbOD zc@?lPoC@wWIC`qgmALQ4!X+pQ@j5cM63h=Mj986B|6}D?gStRa0v*A70vyFS3WtRb zwnDAOV|W+)o#S|?eL(R8PBT|JRN@KXCEW%$pMZv{7&|0fOB@BfD;!Dt1{^(kr4@NO z)WPCiS{!czJ_#qT@J`{K9=_{#q&4a51(6``@jR+ug51>?wQ z-+|Y=n82<^$whEqKX-MAV`A@t89l-m%+--pnD^0P5Cdt4$}a~%DkVIFlpY6RXDVVl z1vpEI8ZgWe(f4d-IaIhfyk<5H=a1(JIkE4)a#B(AsVuHCn;e)@XDz8HdtwwWM3b(b zn8xr`YVjJSgN$HPp58$KVtKr`Po)VV|avrcW=by^p z&j3qGP}ud(GNg~v=iwk@Rc&8f8>JtrKZG<|fp#tS09p7{jm70qdE#B##6L&IpF-|V zYB2l>7cKE!0DWxazJQ}g)UaZ{#ldmtoanM8n#@oDR>oK-@*4vLXO;_H20xfERyyo0 ze1%^E{|FrA{wp|o@ImL72w$|c1TFw4g&Sq?*E0B`4E{z2Uy{L>W$?E$_=*hvP6mH3 zgMX00S7q>zGWcII_$L{BO$J|=!8c^^zh&^xGWezpz9oZi%iv#R@EsZas|@~42H%yz z_hj(zGWfm>ejtOXIZN9EOqLvAg$!28V3= zx9}CK`;>Kd?E{f^TCT6-dOeKJX6$i5 za(<$1*iV$hBwDc?Yi*_34Z`9-=iKo^lV5&DjzB!5)5|PJr-Ka`OgRj;XTW7jd_@)Z zAqkgKPJg+xh+M~&Qc0I(lvP684|?gL$_%7t5hnel+oS%n9US!@Fe2n0PN#=A8jH&- zstb$6H8&F8f`r3ji>Km9dUWl0b5#Y!NH!NDrKxnIM>TcY`~-4LaYZS&-GJ_kyN3gV z2t^N#{wp$qjkKCQStPy{vAyGqYs{w93glPPOB(74w~ggylbjfoQAZYD$ew+I_y;tt zKqF1IHDIXZU^9?kL^&0Q`>l8vXJno6F0DX1uOj8q2Cxs@Y0yzIw?$SOwn5xTObhJ$ zztR}(KuwS2zB&hv?ZKgbJ2<=`*`KjzjiIbd*>#W!)RAD?6GakIIyzX>)LhY){3xg~rTn^5I!J>?K5}}%-0a5CxC6ppW(DP@U2-XLHxLsZGuLu!Q&R$) zCRKTpDxCjBNS#f1Zcv9lJF$QuOm_sGv_yZ;g*&R{8HU@a0)|%^+ZDoz*qY~5v{Lze zK$nHfA*sF7=uH|`DZV@8kDEfeSVO~39m)<8+}nQN@vXT}u|XIg>} zu(%S3s>>bPXAcxrES5P^8G0ft19L)YSTBT0;okTR_U}P)++vZf;sRlJQ%cfD7NxHY z?k9u$%isZkNsL5NmmnX|&2!UI>Ne^7r|;PpG#CYNzbIN71};-I)azDQd;o`uU@?`H zRHlKTPsI(0oW&_(@|v-Axk3?Fu!UO`ABN51w;yG@xf<~cB17fGW;kswnq7} zQ<@i?S2WZ=kK+AB2`dFK!TqZcQA#pY$S%KeS>m=g>aq$TrnZ9iph>+Yk{Ie=M*ZJVHmxf`-9#qYR?Dn} z!pJPPvQL`Hw@mw7rg(!4qU~whW#qgC_yTDAjc964I9P z&ymsR0u~nnV!fc3FEnF+oW{a~aMYbq9*nZMd4NkR3M-_h9Qg<{@;jNd4B{RmsdFW_ zZ<4;`Flzn@1&`s&53>sDW{YXc5jBjrAFZ6oFHLOly}+v;K21@w;gdw7e#C@S#nqM> z?*$UL5bs42xESx1P|;DYP*N7M$+U1vbAF7#)Wtp=aKWG};nl;NEoGiUBb*D9A`*27=VLd8-pp{>BXw1z6tF&=#l#p6WUBMdENmC*B1KtR4I zZVp{ah3Pvt%_8y0j1x1qVzm5x&Wa5qrwO|vhWghLu{DjQ#TC_-9El3WaFkG9(k$@0 z6+mB$Sijl)tq8@&0 zfKdXR3%>(k8~nELrL&MJC>$Cw^$3T@RLNiqU}@o5X;e81@uBN((sZX_dShShfeSq_ zWv~ZHIaJFyPNih=q~pFvTB9BV^KC3Y`J+WHj};fO($ReyVp2C^!opc>(6(IurtB5) zsS(K=@(v-q264p(U5odFXs}w)*Tbg|0n=@{QkLe%4rMW&8q#ryI~vvza%u~v%@c9T zpSM(p+TLuTLjt01K2q;490|xW@+lU>kpCy53<9&_< zw&7h`zjFacfrqFS8JoweKW&26UP>DeI{W#5oRefxqFdfX*065pABBSRadpi%6pll5 zhD9gog($_Bx>E>gXq#9$H5dyHhkcECV1)2cdH8&Ur$gImrX@<%nBd|{{yU&fkJ7Hg zAG-2gLKC_GVKjRuksfx4pHN}J)(o~E9J=#`pdp#0Ievr>3zdc~LKtz7hCPZfdN{QO zd?{`*aN;i&+5QdoamW|dc$ zmQI-A8#xh1J5|^#rWRjlDz@ZTVOO&pLlDP1tJq{M!Y}}faqC3LMGs|p65Kz5mw<^h z{!$sdOa?EP!7F6&N*TOL20tc)SIgkXW$+U+c#RBRD}$eu!B5HHbuxIp4BjAvH_G6r zWpKR=-Xw!J%iw2Z@D>@oRR(X9!P{l<4jKHc4Bjb&cgf)0GI$T*815`6_g%!HdZ`NS|CK=c2YwbVeol%5iIriTXp))$%?R7$*t%s7IE^bAN;%#<%Zc>S4n-rIro{%P> z8m0zxv5Zg4 z7ru~|C_7m%wDcn~&2#zBDP>YI%w@sr$ll=en$GiNPj>4F1#F)UQK3}W@!8h6Z;pvFx|TBsz$A0^;WQGbg{CJDoIuH>)RJ`Y*Cwp?LmxdBRX8b@03K zWz&=n_i0h%0RoSaUjLvG+ew>BuLVA`#KAMOiXX(h;R}Npb)_b{KQLw=mCJGL{T?+~RJ-jUGUe)~M z=trb0OpfH;S_?`46B3yK$n!IhArQU^zAzqed;QW`Gk=`gZi`@%P09Zw{deHq6KQah z&j0k&OETuX!NH$Ng9+YLPo@{o|38Q-M>EV8#1$ss&GLat{_B}`AZD0G@D=*V=2>u{ z{f`-TpbnpAAD0}$Wn3I^D-cKMPn!B!EU##*O%|^i{td(xz6oLDmYSrv*NU^yn7y2J z5!Qna{e5%trtZEuu6fIhui>Y;418gl+a#Sth$gOo2i-i~!${8$t*H(^?Fvek4MMh? zQWWRi{|O;arB5yY0~q&^Mk_uI;fSSRb5PN2-7EWLDBSS^9@KK1Ur$e##q>j>+-%CucanMt^;);yy#UCt?^Bq+Tt&FvWUn7tc{)qtACVSn#a6{Oi zN%JR(aI1WKJ~;y~%3+H?kkGt1g&VrSzuNrQe>}myIlx&>^BM_kwL$MwUJRYQNl%yU zMCzMZRCH~lVx*@$aQa=!x3Ng@N;$H1mSpNp_NG8}$H z7@LPkvXU$g^|{_N`CdkpAA5-Wl{bhT3>34AJg@nmi7?6ocIQbuFX)BvBUlJ`N4P~WXWIdo)GTGjO6DNmm3TKp?f(YeY5PM+ zhqIt-K$w)LU|7doLO9vcTWQY#$#cYj?;+d`zR(NU5#F>nHu92guF92^`H92y)J93C7I;vW(a5*QK`5*!i|5*iW~5*`u} z>W}-M14DyCgF{0?Lqo$t!$Tv&{KEpm0&zcda9BuKXjoWScvwWZe|SK6V0ch?aCk^~ zXn0t7cz8qvM2tZ45nvsGXb}iv4EOJ%b3f*N{UPKQPtPdMW5)4*)N=xfjX+Nx-H$KtG*gKaksKd{NC|3~kCIK1W&F5RGcz%}{)OlJ)E!8)oZeI)aQSlL^2oP!vnO>N@sw%yo9-P)k2w1Kms3A9 zE*RlI>v8YlhYpPxR{mva=?m9Ky#JQ>BMZOoInr>i{p9c4k01H$(A0|osVhdd9(8H_ zFw+|&vvN1w7&YtHk!1%}<(s}3lob2(@k^J!&rfQz|L4w=F0D=KxW000b>}llD~$yU zi>s8QZgIcB5k9Kw&hl^G$SWT;{BDH%;omopYCrw-2mN0AWYp7ZBjc^R-I7gDU)ptg zadh&~Q(vAt8`V~{?&G%B|Rm3&vz5=Y){XB{(N5b?Jv{2RGymXbf{HEucU|<7Z(lB@OygU z=DpFgGG?7v-D^+ca~at;e=TqK#kU!jDF+|z@>r+L@8X~L`T6tFnVZ|?esL}B;mo(Y z)O@t-%Hhn1S`RS2Q+XrP{d~yK`|tJ|(<*uXyF;TUjCsfN!>4=eR*t#9`s8r`5pRwe z8hLQstLuLoQ_!>Z!CRaBvuyur+uQQCDXa0j4c9z=e==*yf#bLO4Qt4{HZjQZ!YI|) zk`QJ^H)F)uH=~)G#jjM1J>1V0e(|Gc#`X`cKl$0|^J7B{2{m4K-Nzm4JMiic*)ij8 zRNdLyE4XIdp5;?L1{wB_d$;}0;@7^rIPRf(?>Bzj+;)7*>Grp_FCH~Mu(SWK3Df3{ zpWSn2SjRRmkKZ_Of;#WBAIHzTH#TOLuKR>%1`k@j{?RcLmN*Z7C1&7~32VN6BYnjB zV-tqzU-~Xvd3(aB9p7{ht{af;pZNac^?}ChnV%aDC(L;~dqP^PA39ukJG<60^25q^ zn2A}bUuj0&51v?d>G6cdp_3=Rv3KIY-39d%t2?|Ho@F~bv6bBxHc+A$c+yi|U`t43$h_9n>WLEdr zausXF)lCigckYRM6}`?L?`^z!_Z`1QmTY6qtcP9;Ila<&E_=CeOyo(UYw+{Ge02J* zaUs(%y>4Pa-m^^Ilb2sG=bdFPKj_kZU0$93T2A_{hPn&-FV-;atOJErl|{HKfh{SxBqX*zlQXKPGYtf}UC|1|HoTGN=u zR}02HvCkCh8rt~FYu}h+mdBj0-qX(PZOKUf=zOyI$5S^w>xR!afA?!Z8*}@EW@F9l z@vnFN$vo6$`JHngbuVyz|GAgmeI%=3`P`gK4<;`y_;vr`pDyGbF9_c-`G+-kZx=iq ztG+zzkZ*!y`KyKX8P|M6>g7ZiS6bYR4u>4nFfi}xk(-raaGs(5_fC!e&tVlBQA z`JUSa{m$ZZvGqlZGa8Fs$DEGdTkJh~dCByT+SescwrIvB=r7NitlJVcF!RRGIrti(Q)6z>0mjnjP$$X?_r)JLYUrm0!q`#?R(mRTuOG1Xa zgw8(Er*xj{vJ(?um{|J3sqm)`tyooh^4F75-v^&64Lf*eMGwXAr9CX`BFA(KEW4T# z{noB$3(CIzX4PSzjP+%e?+*@H_QD5cuE!reexRGCe0kNtpe{QHmp@r}??T#$DdltK z-d%HL{nqje#@}XjQ+;0UJL}b-R$uh2n7Y2Ce`LqFiq-QqFY5B9R}5{{b4uK-{T1)} zl)d-F`b!mavQOJyJ<-1MOvJ2)%nqrQF^{Z|y{fOP%-DINP49lMRDQoYcwL3%TBX;Q z%&}fOdQ2JPZ3q~&YV4GfaVvj6^wP2^-+VIttKh&BQ@&W*-skxJU#6trczRvc{ee|y zZ^vxX9?7d(baVBhx60R4?F#tq>WmTZRk`HMv@A_lSl*jDp~3%RsAX^aNB+p?bMbj`);efsv7Q>qQtcGIny?|)cr-MIFHALb6O!xM=EOiG487Ee9XcUtBA zy8|w@3Cq7Xa9KO$;i{wvNv7{j!L{g?bqX;-A?~2u;$>;8T}%kEv(t< zzw`M=9@|h;IB7&>$jlFG*xT9fMt9WK&I_{6X?<}>Z9x5wK}l{^wL?#@8vOK%ZMCDO zPjfyM{6%f$?nevm)q71}k~Ppa*eQN`#h&ooM;FhSZZ7RHGc@eL^f|+QJE|63o<3>Z zFWut4?J(o>HIX4#&!o=yaOfh%x5@=G;+GDXeo-v7kOUCwXJJayA@aE#lpGw`#f`Q5MQ zz#IiXcS1jVLaPcoM4-pUcxiQ6Iks9coyMhasNyv2+ok%Ryf zv_{a-)LOhUw&{*-V_rVCnX82-&sttxP$fc5J}$gw40l!>hdom^V_3fmFFjxc^`{Tn z$r$bsDT|l&tMRf+^WeXH7~IvaQfst2Cn2JsTv#~*X~PxwEM`G10unn&$pvAqPR zK*dN+fes+-IXGJH*!p=gE8yzk_QTOSi`I6urXrsnIu%OK72ach5PUjKN)H*z5v>;- z*m5w1(He>zy^oFcWOCt(;7Z{t;V2EllN@@OBl^Of&*ax+v<{?r zCdQ@s1XCWxcZy4mk>Zk(AHCDsjU45V(j(fn8OS%>Zn*t$2jPyw4H@FeoQB^3*9dnV z?hYI?82CuQa17-11e}U+$~!sIv*dU#9sj?#uLk&bUajsb~^A` zLA>CO!Vx`b*(g8sF4EIFo#NDof)0*LUx?EPn9`>*qBz&HAp2NPMi1xfA=qCR;I0MO ePFfTLJj$xMV~_(2aisyeiUB&ZtQ?4wNdFH+GW!<* diff --git a/core/Cargo.toml b/core/Cargo.toml index 94b21f93d77..30899cfc0bd 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -67,8 +67,6 @@ parking_lot = { workspace = true, features = ["deadlock_detection"] } derive_more = { workspace = true } itertools = { workspace = true } -sealed = "0.5.0" - [dev-dependencies] criterion = { workspace = true } hex = { workspace = true } diff --git a/core/benches/apply_blocks/apply_blocks.rs b/core/benches/apply_blocks/apply_blocks.rs index 917d29dee22..f1aea86d233 100644 --- a/core/benches/apply_blocks/apply_blocks.rs +++ b/core/benches/apply_blocks/apply_blocks.rs @@ -3,62 +3,44 @@ use std::{collections::BTreeSet, str::FromStr as _}; use eyre::Result; -use iroha_config::sumeragi::default::DEFAULT_CONSENSUS_ESTIMATION_MS; -use iroha_core::{block::PendingBlock, prelude::*, wsv::World}; -use iroha_crypto::{HashOf, MerkleTree, SignatureOf, SignaturesOf}; +use iroha_core::{ + block::{BlockBuilder, CommittedBlock}, + prelude::*, + sumeragi::network_topology::Topology, + wsv::World, +}; use iroha_data_model::{ asset::{AssetDefinition, AssetDefinitionId}, - block::{BlockHeader, VersionedCommittedBlock}, isi::InstructionBox, prelude::*, }; +use iroha_genesis::GenesisTransaction; -/// Create block, bypassing validation +/// Create block fn create_block( - height: u64, - previous_block_hash: Option>, + wsv: &mut WorldStateView, instructions: Vec, account_id: AccountId, key_pair: KeyPair, -) -> Result { +) -> CommittedBlock { let transaction = TransactionBuilder::new(account_id) .with_instructions(instructions) - .sign(key_pair.clone())?; - - let transactions_hash = [&transaction] - .iter() - .map(|tx| tx.hash()) - .collect::>() - .hash(); - let timestamp = current_time().as_millis(); - let header = BlockHeader { - timestamp, - consensus_estimation: DEFAULT_CONSENSUS_ESTIMATION_MS, - height, - view_change_index: 1, - previous_block_hash, - transactions_hash, // Single transaction is merkle root hash - rejected_transactions_hash: None, - committed_with_topology: Vec::new(), - }; - - let signature = SignatureOf::from_hash( - key_pair, - HashOf::from_untyped_unchecked(Hash::new(header.payload())), - )?; - let signatures = SignaturesOf::from(signature); - - let pending_block = PendingBlock { - header, - transactions: vec![TransactionValue { - value: transaction, - error: None, - }], - event_recommendations: Vec::new(), - signatures, - }; - - Ok(pending_block.commit_unchecked().into()) + .sign(key_pair.clone()) + .unwrap(); + + let topology = Topology::new(Vec::new()); + BlockBuilder::new( + vec![AcceptedTransaction::accept_genesis(GenesisTransaction( + transaction, + ))], + topology.clone(), + Vec::new(), + ) + .chain(0, wsv) + .sign(key_pair) + .unwrap() + .commit(&topology) + .unwrap() } fn delete_every_nth( @@ -158,16 +140,14 @@ fn build_wsv( } } - let block = create_block(1, None, instructions, account_id, key_pair)?; - + let block = create_block(&mut wsv, instructions, account_id, key_pair); wsv.apply(&block)?; - Ok(wsv) } pub struct WsvApplyBlocks { wsv: WorldStateView, - blocks: Vec, + blocks: Vec, } impl WsvApplyBlocks { @@ -183,7 +163,7 @@ impl WsvApplyBlocks { let assets_per_domain = 1000; let genesis_id: AccountId = "genesis@genesis".parse()?; let key_pair = KeyPair::generate()?; - let wsv = build_wsv( + let mut wsv = build_wsv( domains, accounts_per_domain, assets_per_domain, @@ -199,19 +179,12 @@ impl WsvApplyBlocks { .into_iter() .collect::, _>>()?; - let mut previous_block_hash = wsv.latest_block_hash(); - let mut blocks = Vec::new(); - for (instructions, height) in instructions.into_iter().zip(wsv.height() + 1..) { - let block = create_block( - height, - previous_block_hash, - instructions, - genesis_id.clone(), - key_pair.clone(), - )?; - previous_block_hash = Some(block.hash()); - blocks.push(block); - } + let blocks = instructions + .into_iter() + .map(|instructions| { + create_block(&mut wsv, instructions, genesis_id.clone(), key_pair.clone()) + }) + .collect(); Ok(Self { wsv, blocks }) } diff --git a/core/benches/kura.rs b/core/benches/kura.rs index 02cbdb6b82c..cb082b94ba4 100644 --- a/core/benches/kura.rs +++ b/core/benches/kura.rs @@ -8,19 +8,18 @@ use iroha_core::{ block::*, kura::{BlockStore, LockStatus}, prelude::*, + sumeragi::network_topology::Topology, wsv::World, }; use iroha_crypto::KeyPair; -use iroha_data_model::{ - block::VersionedCommittedBlock, prelude::*, transaction::TransactionLimits, -}; +use iroha_data_model::{prelude::*, transaction::TransactionLimits}; use tokio::{fs, runtime::Runtime}; async fn measure_block_size_for_n_validators(n_validators: u32) { let alice_id = AccountId::from_str("alice@test").expect("tested"); let bob_id = AccountId::from_str("bob@test").expect("tested"); let xor_id = AssetDefinitionId::from_str("xor#test").expect("tested"); - let alice_xor_id = ::Id::new(xor_id, alice_id); + let alice_xor_id = AssetId::new(xor_id, alice_id); let transfer = TransferBox::new( IdBox::AssetId(alice_xor_id), 10_u32.to_value(), @@ -29,7 +28,7 @@ async fn measure_block_size_for_n_validators(n_validators: u32) { let keypair = KeyPair::generate().expect("Failed to generate KeyPair."); let tx = TransactionBuilder::new(AccountId::from_str("alice@wonderland").expect("checked")) .with_instructions([transfer]) - .sign(keypair) + .sign(keypair.clone()) .expect("Failed to sign."); let transaction_limits = TransactionLimits { max_instruction_number: 4096, @@ -42,26 +41,21 @@ async fn measure_block_size_for_n_validators(n_validators: u32) { iroha_core::kura::Kura::new(iroha_config::kura::Mode::Strict, dir.path(), false).unwrap(); let _thread_handle = iroha_core::kura::Kura::start(kura.clone()); - let mut block = BlockBuilder { - transactions: vec![tx], - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: iroha_core::sumeragi::network_topology::Topology::new(Vec::new()), - key_pair: KeyPair::generate().expect("Failed to generate KeyPair"), - wsv: &mut WorldStateView::new(World::new(), kura), - } - .build(); + let mut wsv = WorldStateView::new(World::new(), kura); + let topology = Topology::new(Vec::new()); + let mut block = BlockBuilder::new(vec![tx], topology, Vec::new()) + .chain_first(&mut wsv) + .sign(KeyPair::generate().unwrap()) + .unwrap(); for _ in 1..n_validators { block = block .sign(KeyPair::generate().expect("Failed to generate KeyPair.")) .unwrap(); } - let block: VersionedCommittedBlock = block.commit_unchecked().into(); let mut block_store = BlockStore::new(dir.path(), LockStatus::Unlocked); block_store.create_files_if_they_do_not_exist().unwrap(); - - block_store.append_block_to_chain(&block).unwrap(); + block_store.append_block_to_chain(&block.into()).unwrap(); let metadata = fs::metadata(dir.path().join("blocks.data")).await.unwrap(); let file_size = Byte::from_bytes(u128::from(metadata.len())).get_appropriate_unit(false); diff --git a/core/benches/validate_blocks/validate_blocks.rs b/core/benches/validate_blocks/validate_blocks.rs index 50073869332..b6c9fc9e473 100644 --- a/core/benches/validate_blocks/validate_blocks.rs +++ b/core/benches/validate_blocks/validate_blocks.rs @@ -4,12 +4,14 @@ use std::{collections::BTreeSet, str::FromStr as _}; use eyre::Result; use iroha_core::{ - block::BlockBuilder, prelude::*, smartcontracts::Execute, sumeragi::network_topology::Topology, + block::{BlockBuilder, CommittedBlock}, + prelude::*, + smartcontracts::Execute, + sumeragi::network_topology::Topology, wsv::World, }; use iroha_data_model::{ asset::{AssetDefinition, AssetDefinitionId}, - block::VersionedCommittedBlock, isi::InstructionBox, prelude::*, transaction::TransactionLimits, @@ -21,7 +23,7 @@ fn create_block( account_id: AccountId, key_pair: KeyPair, wsv: &mut WorldStateView, -) -> Result { +) -> Result { let transaction = TransactionBuilder::new(account_id) .with_instructions(instructions) .sign(key_pair.clone())?; @@ -29,17 +31,15 @@ fn create_block( let transaction_limits = &wsv.transaction_validator().transaction_limits; let transaction = AcceptedTransaction::accept(transaction, transaction_limits)?; - let pending_block = BlockBuilder { - transactions: vec![transaction], - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: Topology::new(Vec::new()), - key_pair, - wsv, - } - .build(); + let topology = Topology::new(Vec::new()); + let pending_block = BlockBuilder::new(vec![transaction], topology.clone(), Vec::new()) + .chain_first(wsv) + .sign(key_pair) + .unwrap() + .commit(&topology) + .unwrap(); - Ok(pending_block.commit_unchecked().into()) + Ok(pending_block) } fn populate_wsv( diff --git a/core/benches/validation.rs b/core/benches/validation.rs index 3a1247cca62..ea30e4e14db 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -145,25 +145,18 @@ fn sign_blocks(criterion: &mut Criterion) { .expect("Failed to accept transaction."); let key_pair = KeyPair::generate().expect("Failed to generate KeyPair."); let kura = iroha_core::kura::Kura::blank_kura_for_testing(); + let mut wsv = WorldStateView::new(World::new(), kura); + let topology = Topology::new(Vec::new()); let mut success_count = 0; let mut failures_count = 0; - let _ = criterion.bench_function("sign_block", |b| { - b.iter(|| { - let block = BlockBuilder { - transactions: vec![transaction.clone()], - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: Topology::new(Vec::new()), - key_pair: key_pair.clone(), - wsv: &mut WorldStateView::new(World::new(), kura.clone()), - } - .build(); - match block.sign(key_pair.clone()) { - Ok(_) => success_count += 1, - Err(_) => failures_count += 1, - } + let block = BlockBuilder::new(vec![transaction], topology, Vec::new()).chain_first(&mut wsv); + + let _ = criterion.bench_function("sign_block", |b| { + b.iter(|| match block.clone().sign(key_pair.clone()) { + Ok(_) => success_count += 1, + Err(_) => failures_count += 1, }); }); println!("Success count: {success_count}, Failures count: {failures_count}"); diff --git a/core/src/block.rs b/core/src/block.rs index 14f68e405cf..1397a14110b 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -1,8 +1,9 @@ -//! This module contains [`Block`] structures for each state, it's -//! transitions, implementations and related traits -//! implementations. [`Block`]s are organised into a linear sequence -//! over time (also known as the block chain). A Block's life-cycle -//! starts from [`PendingBlock`]. +//! This module contains [`Block`] structures for each state. Transitions are modeled as follows: +//! 1. If a new block is constructed by the node: +//! `BlockBuilder` -> `BlockBuilder` -> `ValidBlock` -> `CommittedBlock` +//! 2. If a block is received, i.e. deserialized: +//! `VersionedSignedBlock` -> `ValidBlock` -> `CommittedBlock` +//! [`Block`]s are organised into a linear sequence over time (also known as the block chain). #![allow( clippy::module_name_repetitions, clippy::std_instead_of_core, @@ -10,7 +11,7 @@ clippy::arithmetic_side_effects )] -use std::error::Error; +use std::error::Error as _; use iroha_config::sumeragi::default::DEFAULT_CONSENSUS_ESTIMATION_MS; use iroha_crypto::{HashOf, KeyPair, MerkleTree, SignatureOf, SignaturesOf}; @@ -21,45 +22,37 @@ use iroha_data_model::{ transaction::{error::TransactionRejectionReason, prelude::*}, }; use iroha_genesis::GenesisTransaction; -use parity_scale_codec::{Decode, Encode}; -use sealed::sealed; use thiserror::Error; +pub use self::{chained::Chained, commit::CommittedBlock, valid::ValidBlock}; use crate::{ prelude::*, sumeragi::network_topology::{SignatureVerificationError, Topology}, - tx::{AcceptTransactionFail, TransactionValidator}, + tx::AcceptTransactionFail, }; -/// Errors occurred on block commit -#[derive(Debug, Error, displaydoc::Display, Clone, Copy)] -pub enum BlockCommitError { - /// Error during signature verification - SignatureVerificationError(#[from] SignatureVerificationError), -} - -/// Errors occurred on signing block or adding additional signature -#[derive(Debug, Error, displaydoc::Display)] -pub enum BlockSignError { - /// Failed to create signature - Sign(#[source] iroha_crypto::error::Error), - /// Failed to add signature for block - AddSignature(#[source] iroha_crypto::error::Error), +/// Error during transaction validation +#[derive(Debug, displaydoc::Display, Error)] +pub enum TransactionValidationError { + /// Failed to accept transaction + Accept(#[from] AcceptTransactionFail), + /// A transaction is marked as accepted, but is actually invalid + NotValid(#[from] TransactionRejectionReason), + /// A transaction is marked as rejected, but is actually valid + RejectedIsValid, } -/// Errors occurred on block revalidation -#[derive(Debug, Error, displaydoc::Display)] -pub enum BlockRevalidationError { - /// Block is empty - Empty, +/// Errors occurred on block validation +#[derive(Debug, displaydoc::Display, Error)] +pub enum BlockValidationError { /// Block has committed transactions HasCommittedTransactions, /// Mismatch between the actual and expected hashes of the latest block. Expected: {expected:?}, actual: {actual:?} LatestBlockHashMismatch { /// Expected value - expected: Option>, + expected: Option>, /// Actual value - actual: Option>, + actual: Option>, }, /// Mismatch between the actual and expected height of the latest block. Expected: {expected}, actual: {actual} LatestBlockHeightMismatch { @@ -70,10 +63,8 @@ pub enum BlockRevalidationError { }, /// The transaction hash stored in the block header does not match the actual transaction hash TransactionHashMismatch, - /// The hash of a rejected transaction stored in the block header does not match the actual hash or this transaction - RejectedTransactionHashMismatch, - /// Error during transaction revalidation - TransactionRevalidation(#[from] TransactionRevalidationError), + /// Error during transaction validation + TransactionValidation(#[from] TransactionValidationError), /// Mismatch between the actual and expected topology. Expected: {expected:?}, actual: {actual:?} TopologyMismatch { /// Expected value @@ -87,505 +78,505 @@ pub enum BlockRevalidationError { ViewChangeIndexTooLarge, } -/// Error during transaction revalidation -#[derive(Debug, Error, displaydoc::Display)] -pub enum TransactionRevalidationError { - /// Failed to accept transaction - Accept(#[from] AcceptTransactionFail), - /// Transaction isn't valid but must be - NotValid(#[from] TransactionRejectionReason), - /// Rejected transaction in valid - RejectedIsValid, -} +/// Builder for blocks +#[derive(Debug, Clone)] +pub struct BlockBuilder(B); -/// Transaction data is permanently recorded in chunks called -/// blocks. -#[derive(Debug, Clone, Decode, Encode)] -pub struct PendingBlock { - /// Block header - pub header: BlockHeader, - /// Array of transactions. - pub transactions: Vec, - /// Event recommendations. - pub event_recommendations: Vec, - /// Signatures of peers which approved this block - pub signatures: SignaturesOf, -} +mod pending { + use iroha_data_model::transaction::TransactionValue; -/// Builder for `PendingBlock` -pub struct BlockBuilder<'world> { - /// Block's transactions. - pub transactions: Vec, - /// Block's event recommendations. - pub event_recommendations: Vec, - /// The view change index this block was committed with. Produced by consensus. - pub view_change_index: u64, - /// The topology thihs block was committed with. Produced by consensus. - pub committed_with_topology: Topology, - /// The keypair used to sign this block. - pub key_pair: KeyPair, - /// The world state to be used when validating the block. - pub wsv: &'world mut WorldStateView, -} - -impl BlockBuilder<'_> { - /// Create a new [`PendingBlock`] from transactions. - pub fn build(self) -> PendingBlock { - let timestamp = crate::current_time().as_millis(); - let height = self.wsv.height() + 1; - let previous_block_hash = self.wsv.latest_block_hash(); - let transaction_validator = self.wsv.transaction_validator(); - // TODO: Need to check if the `transactions` vector is empty. It shouldn't be allowed. - - let mut header = BlockHeader { - timestamp, - consensus_estimation: DEFAULT_CONSENSUS_ESTIMATION_MS, - height, - view_change_index: self.view_change_index, - previous_block_hash, - transactions_hash: None, - rejected_transactions_hash: None, - committed_with_topology: self.committed_with_topology.sorted_peers, - }; - - let mut txs = Vec::new(); - - for tx in self.transactions { - match transaction_validator.validate(tx, self.wsv) { - Ok(transaction) => txs.push(TransactionValue { - value: transaction, - error: None, - }), - Err((transaction, error)) => { - iroha_logger::warn!( - reason = %error, - caused_by = ?error.source(), - "Transaction validation failed", - ); - txs.push(TransactionValue { - value: transaction, - error: Some(error), - }); - } - } - } - header.transactions_hash = txs - .iter() - .filter(|tx| tx.error.is_none()) - .map(|tx| tx.value.hash()) - .collect::>() - .hash(); - header.rejected_transactions_hash = txs - .iter() - .filter(|tx| tx.error.is_some()) - .map(|tx| tx.value.hash()) - .collect::>() - .hash(); - // TODO: Validate Event recommendations somehow? - - let signature = SignatureOf::from_hash( - self.key_pair, - HashOf::from_untyped_unchecked(Hash::new(header.payload())), - ) - .expect("Signing of new block failed."); - let signatures = SignaturesOf::from(signature); - - PendingBlock { - header, - transactions: txs, - event_recommendations: self.event_recommendations, - signatures, - } - } -} - -impl PendingBlock { - const fn is_genesis(&self) -> bool { - self.header.height == 1 - } + use super::*; - /// Calculate the partial hash of the current block. - pub fn partial_hash(&self) -> HashOf { - HashOf::from_untyped_unchecked(Hash::new(self.header.payload())) + /// First stage in the life-cycle of a [`Block`]. + /// In the beginning the block is assumed to be verified and to contain only accepted transactions. + /// Additionally the block must retain events emitted during the execution of on-chain logic during + /// the previous round, which might then be processed by the trigger system. + #[derive(Debug, Clone)] + pub struct Pending { + /// Unix timestamp + timestamp_ms: u64, + /// Collection of transactions which have been accepted. + /// Transaction will be validated when block is chained. + transactions: Vec, + /// The topology at the time of block commit. + commit_topology: Topology, + /// Event recommendations for use in triggers and off-chain work + event_recommendations: Vec, } - /// Return signatures that are verified with the `hash` of this block, - /// removing all other signatures. - #[inline] - pub fn retain_verified_signatures(&mut self) -> impl Iterator> { - self.signatures.retain_verified_by_hash(self.partial_hash()) - } + impl BlockBuilder { + /// Create [`Self`] + /// + /// # Panics + /// + /// if the given list of transaction is empty + #[inline] + pub fn new( + transactions: Vec, + commit_topology: Topology, + event_recommendations: Vec, + ) -> Self { + assert!(!transactions.is_empty(), "Empty block created"); + + Self(Pending { + timestamp_ms: iroha_data_model::current_time() + .as_millis() + .try_into() + .expect("Time should fit into u64"), + transactions, + commit_topology, + event_recommendations, + }) + } - /// Commit block to the store. - /// When calling this function, the user is responsible for the validity of the block signatures. - /// Preference should be given to [`Self::commit`], where signature verification is built in. - #[inline] - pub fn commit_unchecked(self) -> CommittedBlock { - let Self { - header, - transactions, - event_recommendations, - signatures, - } = self; - - CommittedBlock { - event_recommendations, - header, - transactions, - signatures: signatures.transmute(), + fn make_header( + timestamp_ms: u64, + previous_height: u64, + previous_block_hash: Option>, + view_change_index: u64, + transactions: &[TransactionValue], + commit_topology: Topology, + ) -> BlockHeader { + BlockHeader { + timestamp_ms, + consensus_estimation_ms: DEFAULT_CONSENSUS_ESTIMATION_MS, + height: previous_height + 1, + view_change_index, + previous_block_hash, + transactions_hash: transactions + .iter() + .map(TransactionValue::hash) + .collect::>() + .hash(), + commit_topology: commit_topology.ordered_peers, + } } - } - /// Verify signatures and commit block to the store. - /// - /// # Errors - /// - /// Not enough signatures - #[inline] - pub fn commit( - mut self, - topology: &Topology, - ) -> Result { - let hash = self.partial_hash(); - if let Err(err) = topology.verify_signatures(&mut self.signatures, hash) { - return Err((self, err.into())); + fn categorize_transactions( + transactions: Vec, + wsv: &mut WorldStateView, + ) -> Vec { + transactions + .into_iter() + .map(|tx| match wsv.transaction_validator().validate(tx, wsv) { + Ok(tx) => TransactionValue { + value: tx, + error: None, + }, + Err((tx, error)) => { + iroha_logger::warn!( + reason = %error, + caused_by = ?error.source(), + "Transaction validation failed", + ); + TransactionValue { + value: tx, + error: Some(error), + } + } + }) + .collect() } - Ok(self.commit_unchecked()) - } + /// Chain the block with existing blockchain. + pub fn chain( + self, + view_change_index: u64, + wsv: &mut WorldStateView, + ) -> BlockBuilder { + let transactions = Self::categorize_transactions(self.0.transactions, wsv); + + BlockBuilder(Chained(BlockPayload { + header: Self::make_header( + self.0.timestamp_ms, + wsv.height(), + wsv.latest_block_hash(), + view_change_index, + &transactions, + self.0.commit_topology, + ), + transactions, + event_recommendations: self.0.event_recommendations, + })) + } - /// Add additional signatures for [`SignedBlock`]. - /// - /// # Errors - /// Fails if signature generation fails - pub fn sign(mut self, key_pair: KeyPair) -> Result { - SignatureOf::from_hash(key_pair, self.partial_hash()) - .map(|signature| { - self.signatures.insert(signature); - self - }) - .map_err(BlockSignError::Sign) + /// Create a new blockchain with current block as the first block. + pub fn chain_first(self, wsv: &mut WorldStateView) -> BlockBuilder { + let transactions = Self::categorize_transactions(self.0.transactions, wsv); + + BlockBuilder(Chained(BlockPayload { + header: Self::make_header( + self.0.timestamp_ms, + 0, + None, + 0, + &transactions, + self.0.commit_topology, + ), + transactions, + event_recommendations: self.0.event_recommendations, + })) + } } +} - /// Add additional signature for [`SignedBlock`] - /// - /// # Errors - /// Fails if given signature doesn't match block hash - pub fn add_signature(&mut self, signature: SignatureOf) -> Result<(), BlockSignError> { - signature - .verify_hash(self.partial_hash()) - .map(|_| { - self.signatures.insert(signature); - }) - .map_err(BlockSignError::AddSignature) - } +mod chained { + use super::*; - /// Create dummy [`ValidBlock`]. Used in tests - /// - /// # Panics - /// If generating keys or block signing fails. - #[allow(clippy::restriction)] - #[cfg(test)] - pub fn new_dummy() -> Self { - let timestamp = crate::current_time().as_millis(); - - let header = BlockHeader { - timestamp, - consensus_estimation: DEFAULT_CONSENSUS_ESTIMATION_MS, - height: 1, - view_change_index: 0, - previous_block_hash: None, - transactions_hash: None, - rejected_transactions_hash: None, - committed_with_topology: Vec::new(), - }; - - let key_pair = KeyPair::generate().unwrap(); - let signature = SignatureOf::from_hash(key_pair, HashOf::new(&header).transmute()) - .expect("Signing of new block failed."); - let signatures = SignaturesOf::from(signature); - - Self { - header, - transactions: Vec::new(), - event_recommendations: Vec::new(), - signatures, + /// When a [`Pending`] block is chained with the blockchain it becomes [`Chained`] block. + #[derive(Debug, Clone)] + pub struct Chained(pub(super) BlockPayload); + + impl BlockBuilder { + /// Sign this block and get [`SignedBlock`]. + /// + /// # Errors + /// + /// Fails if signature generation fails + pub fn sign(self, key_pair: KeyPair) -> Result { + let signature = SignatureOf::new(key_pair, &self.0 .0)?; + + Ok(ValidBlock( + SignedBlock { + payload: self.0 .0, + signatures: SignaturesOf::from(signature), + } + .into(), + )) } } } -/// This sealed trait represents the ability to revalidate a block. Should be -/// implemented for both [`PendingBlock`] and [`VersionedCommittedBlock`]. -/// Public users should only use this trait's extensions [`InGenesis`] and -/// [`InBlock`]. -#[sealed] -pub trait Revalidate: Sized { - /// # Errors - /// - When the block is deemed invalid. - fn revalidate(&self, wsv: &mut WorldStateView) -> Result<(), BlockRevalidationError>; - - /// Return whether or not the block contains transactions already committed. - fn has_committed_transactions(&self, wsv: &WorldStateView) -> bool; -} - -#[sealed] -impl Revalidate for PendingBlock { - /// Revalidate a block against the current state of the world. - /// - /// # Errors - /// - Block is empty - /// - Block has committed transactions - /// - There is a mismatch between candidate block height and actual blockchain height - /// - There is a mismatch between candidate block previous block hash and actual latest block hash - /// - Block header transaction hashes don't match with computed transaction hashes - /// - Error during revalidation of individual transactions - #[allow(clippy::too_many_lines)] - fn revalidate(&self, wsv: &mut WorldStateView) -> Result<(), BlockRevalidationError> { - let latest_block_hash = wsv.latest_block_hash(); - let block_height = wsv.height(); - let transaction_validator = wsv.transaction_validator(); - - if self.transactions.is_empty() { - return Err(BlockRevalidationError::Empty); - } +mod valid { + use super::*; + use crate::sumeragi::network_topology::Role; - if self.has_committed_transactions(wsv) { - return Err(BlockRevalidationError::HasCommittedTransactions); - } + /// Block that was validated and accepted + #[derive(Debug, Clone)] + #[repr(transparent)] + pub struct ValidBlock(pub(super) VersionedSignedBlock); - if latest_block_hash != self.header.previous_block_hash { - return Err(BlockRevalidationError::LatestBlockHashMismatch { - expected: latest_block_hash, - actual: self.header.previous_block_hash, - }); + impl ValidBlock { + pub(crate) fn payload(&self) -> &BlockPayload { + self.0.payload() } - - if block_height + 1 != self.header.height { - return Err(BlockRevalidationError::LatestBlockHeightMismatch { - expected: block_height + 1, - actual: self.header.height, - }); + pub(crate) fn signatures(&self) -> &SignaturesOf { + self.0.signatures() } - revalidate_hashes( - &self.transactions, - self.header.transactions_hash, - self.header.rejected_transactions_hash, - )?; + /// Validate a block against the current state of the world. + /// + /// # Errors + /// + /// - Block is empty + /// - There is a mismatch between candidate block height and actual blockchain height + /// - There is a mismatch between candidate block previous block hash and actual latest block hash + /// - Block has committed transactions + /// - Block header transaction hashes don't match with computed transaction hashes + /// - Error during validation of individual transactions + /// - Topology field is incorrect + pub fn validate( + block: VersionedSignedBlock, + topology: &Topology, + wsv: &mut WorldStateView, + ) -> Result { + let actual_commit_topology = &block.payload().header.commit_topology; + let expected_commit_topology = &topology.ordered_peers; + + if actual_commit_topology != expected_commit_topology { + let actual_commit_topology = actual_commit_topology.clone(); + + return Err(( + block, + BlockValidationError::TopologyMismatch { + expected: expected_commit_topology.clone(), + actual: actual_commit_topology, + }, + )); + } - revalidate_transactions( - &self.transactions, - wsv, - transaction_validator, - self.is_genesis(), - )?; + if !block.payload().header.is_genesis() + && topology + .filter_signatures_by_roles(&[Role::Leader], block.signatures()) + .is_empty() + { + return Err((block, SignatureVerificationError::LeaderMissing.into())); + } - Ok(()) - } + let expected_block_height = wsv.height() + 1; + let actual_height = block.payload().header.height; + + if expected_block_height != actual_height { + return Err(( + block, + BlockValidationError::LatestBlockHeightMismatch { + expected: expected_block_height, + actual: actual_height, + }, + )); + } - /// Check if a block has transactions that are already in the blockchain. - fn has_committed_transactions(&self, wsv: &WorldStateView) -> bool { - self.transactions - .iter() - .any(|tx| wsv.has_transaction(tx.value.hash())) - } -} + let expected_previous_block_hash = wsv.latest_block_hash(); + let actual_block_hash = block.payload().header.previous_block_hash; + + if expected_previous_block_hash != actual_block_hash { + return Err(( + block, + BlockValidationError::LatestBlockHashMismatch { + expected: expected_previous_block_hash, + actual: actual_block_hash, + }, + )); + } -#[sealed] -impl Revalidate for VersionedCommittedBlock { - /// Revalidate a block against the current state of the world. - /// - /// # Errors - /// - Block is empty - /// - Block has committed transactions - /// - There is a mismatch between candidate block height and actual blockchain height - /// - There is a mismatch between candidate block previous block hash and actual latest block hash - /// - Block header transaction hashes don't match with computed transaction hashes - /// - Error during revalidation of individual transactions - #[allow(clippy::too_many_lines)] - fn revalidate(&self, wsv: &mut WorldStateView) -> Result<(), BlockRevalidationError> { - let latest_block_hash = wsv.latest_block_hash(); - let block_height = wsv.height(); - let transaction_validator = wsv.transaction_validator(); - let is_genesis = block_height == 0; - - if self.has_committed_transactions(wsv) { - return Err(BlockRevalidationError::HasCommittedTransactions); - } + if block + .payload() + .transactions + .iter() + .any(|tx| wsv.has_transaction(tx.hash())) + { + return Err((block, BlockValidationError::HasCommittedTransactions)); + } - match self { - VersionedCommittedBlock::V1(block) => { - if block.transactions.is_empty() { - return Err(BlockRevalidationError::Empty); - } + if let Err(error) = Self::validate_transactions(&block, wsv) { + return Err((block, error.into())); + } - if latest_block_hash != block.header.previous_block_hash { - return Err(BlockRevalidationError::LatestBlockHashMismatch { - expected: latest_block_hash, - actual: block.header.previous_block_hash, - }); + let VersionedSignedBlock::V1(block) = block; + Ok(ValidBlock( + SignedBlock { + payload: block.payload, + signatures: block.signatures, } + .into(), + )) + } - if block_height + 1 != block.header.height { - return Err(BlockRevalidationError::LatestBlockHeightMismatch { - expected: block_height + 1, - actual: block.header.height, - }); - } + fn validate_transactions( + block: &VersionedSignedBlock, + wsv: &mut WorldStateView, + ) -> Result<(), TransactionValidationError> { + let is_genesis = block.payload().header.is_genesis(); - if !is_genesis { - // Recrate topology with witch block must be committed at given view change index - // And then verify committed_with_topology field and block signatures - let topology = { - let last_committed_block = wsv - .latest_block_ref() - .expect("Not in genesis round so must have at least genesis block"); - let new_peers = wsv.peers_ids().iter().cloned().collect(); - let view_change_index = block - .header - .view_change_index - .try_into() - .map_err(|_| BlockRevalidationError::ViewChangeIndexTooLarge)?; - Topology::recreate_topology( - &last_committed_block, - view_change_index, - new_peers, - ) - }; - - if topology.sorted_peers != block.header.committed_with_topology { - return Err(BlockRevalidationError::TopologyMismatch { - expected: topology.sorted_peers, - actual: block.header.committed_with_topology.clone(), - }); + block.payload() + .transactions + .iter() + // TODO: Unnecessary clone? + .cloned() + .try_for_each(|TransactionValue{value, error}| { + let transaction_validator = wsv.transaction_validator(); + let limits = &transaction_validator.transaction_limits; + + if error.is_none() { + let tx = if is_genesis { + AcceptedTransaction::accept_genesis(GenesisTransaction(value)) + } else { + AcceptedTransaction::accept(value, limits)? + }; + + transaction_validator.validate(tx, wsv).map_err(|(_tx, error)| { + TransactionValidationError::NotValid(error) + })?; + } else { + let tx = if is_genesis { + AcceptedTransaction::accept_genesis(GenesisTransaction(value)) + } else { + AcceptedTransaction::accept(value, limits)? + }; + + match transaction_validator.validate(tx, wsv) { + Err(rejected_transaction) => Ok(rejected_transaction), + Ok(_) => Err(TransactionValidationError::RejectedIsValid), + }?; } - topology.verify_signatures( - &mut block.signatures.clone(), - HashOf::from_untyped_unchecked(block.partial_hash().internal), - )?; - } + Ok(()) + }) + } + + /// The manipulation of the topology relies upon all peers seeing the same signature set. + /// Therefore we must clear the signatures and accept what the proxy tail giveth. + /// + /// # Errors + /// + /// - Not enough signatures + /// - Not signed by proxy tail + pub(crate) fn commit_with_signatures( + mut self, + topology: &Topology, + signatures: SignaturesOf, + ) -> Result { + if topology + .filter_signatures_by_roles(&[Role::Leader], &signatures) + .is_empty() + { + return Err((self, SignatureVerificationError::LeaderMissing.into())); + } + + if !self.signatures().is_subset(&signatures) { + return Err((self, SignatureVerificationError::SignatureMissing.into())); + } + + if !self.0.replace_signatures(signatures) { + return Err((self, SignatureVerificationError::UnknownSignature.into())); + } - revalidate_hashes( - &block.transactions, - block.header.transactions_hash, - block.header.rejected_transactions_hash, - )?; + self.commit(topology) + } - revalidate_transactions( - &block.transactions, - wsv, - transaction_validator, - block.is_genesis(), - )?; + /// Verify signatures and commit block to the store. + /// + /// # Errors + /// + /// - Not enough signatures + /// - Not signed by proxy tail + pub fn commit( + self, + topology: &Topology, + ) -> Result { + // TODO: Should the peer that serves genesis have a fixed role of ProxyTail in topology? + if !self.payload().header.is_genesis() + && topology.is_consensus_required().is_some() + && topology + .filter_signatures_by_roles(&[Role::ProxyTail], self.signatures()) + .is_empty() + { + return Err((self, SignatureVerificationError::ProxyTailMissing.into())); + } - Ok(()) + #[allow(clippy::collapsible_else_if)] + if self.payload().header.is_genesis() { + // At genesis round we blindly take on the network topology from the genesis block. + } else { + let roles = [ + Role::ValidatingPeer, + Role::Leader, + Role::ProxyTail, + Role::ObservingPeer, + ]; + + let votes_count = topology + .filter_signatures_by_roles(&roles, self.signatures()) + .len(); + if votes_count.lt(&topology.min_votes_for_commit()) { + return Err(( + self, + SignatureVerificationError::NotEnoughSignatures { + votes_count, + min_votes_for_commit: topology.min_votes_for_commit(), + } + .into(), + )); + } } + + Ok(CommittedBlock(self.0)) + } + + /// Add additional signatures for [`Self`]. + /// + /// # Errors + /// + /// If signature generation fails + pub fn sign(self, key_pair: KeyPair) -> Result { + self.0.sign(key_pair).map(ValidBlock) + } + + /// Add additional signature for [`Self`] + /// + /// # Errors + /// + /// If given signature doesn't match block hash + pub fn add_signature( + &mut self, + signature: SignatureOf, + ) -> Result<(), iroha_crypto::error::Error> { + self.0.add_signature(signature) + } + + #[cfg(test)] + pub(crate) fn new_dummy() -> Self { + BlockBuilder(Chained(BlockPayload { + header: BlockHeader { + timestamp_ms: 0, + consensus_estimation_ms: DEFAULT_CONSENSUS_ESTIMATION_MS, + height: 1, + view_change_index: 0, + previous_block_hash: None, + transactions_hash: None, + commit_topology: Vec::new(), + }, + transactions: Vec::new(), + event_recommendations: Vec::new(), + })) + .sign(KeyPair::generate().unwrap()) + .unwrap() } } - /// Check if a block has transactions that are already in the blockchain. - fn has_committed_transactions(&self, wsv: &WorldStateView) -> bool { - match self { - VersionedCommittedBlock::V1(block) => block - .transactions - .iter() - .any(|tx| wsv.has_transaction(tx.value.hash())), + impl From for VersionedSignedBlock { + fn from(source: ValidBlock) -> Self { + source.0 } } } -/// Revalidate merkle tree root hashes of the transaction -fn revalidate_hashes( - transactions: &[TransactionValue], - transactions_hash: Option>>, - rejected_transactions_hash: Option>>, -) -> Result<(), BlockRevalidationError> { - // Validate that header transactions hashes are matched with actual hashes - transactions - .iter() - .filter(|tx| tx.error.is_none()) - .map(|tx| tx.value.hash()) - .collect::>() - .hash() - .eq(&transactions_hash) - .then_some(()) - .ok_or_else(|| BlockRevalidationError::TransactionHashMismatch)?; - - transactions - .iter() - .filter(|tx| tx.error.is_some()) - .map(|tx| tx.value.hash()) - .collect::>() - .hash() - .eq(&rejected_transactions_hash) - .then_some(()) - .ok_or_else(|| BlockRevalidationError::RejectedTransactionHashMismatch)?; - Ok(()) -} +mod commit { + use super::*; -/// Revalidate transactions to ensure that valid transactions indeed valid and invalid are still invalid -fn revalidate_transactions( - transactions: &[TransactionValue], - wsv: &mut WorldStateView, - transaction_validator: TransactionValidator, - is_genesis: bool, -) -> Result<(), TransactionRevalidationError> { - // Check that valid transactions are still valid - for tx in transactions.iter().cloned() { - if tx.error.is_some() { - let _rejected_tx = if is_genesis { - Ok(AcceptedTransaction::accept_genesis(GenesisTransaction( - tx.value, - ))) - } else { - AcceptedTransaction::accept(tx.value, &transaction_validator.transaction_limits) - } - .map_err(TransactionRevalidationError::Accept) - .and_then(|tx| match transaction_validator.validate(tx, wsv) { - Err(rejected_transaction) => Ok(rejected_transaction), - Ok(_) => Err(TransactionRevalidationError::RejectedIsValid), - })?; - } else { - let tx = if is_genesis { - Ok(AcceptedTransaction::accept_genesis(GenesisTransaction( - tx.value, - ))) - } else { - AcceptedTransaction::accept(tx.value, &transaction_validator.transaction_limits) - } - .map_err(TransactionRevalidationError::Accept)?; + /// Represents a block accepted by consensus. + /// Every [`Self`] will have a different height. + #[derive(Debug, Clone)] + // TODO: Make it pub(super) at most + pub struct CommittedBlock(pub(crate) VersionedSignedBlock); - transaction_validator - .validate(tx, wsv) - .map_err(|(_tx, error)| error) - .map_err(TransactionRevalidationError::NotValid)?; + impl CommittedBlock { + /// Calculate block hash + pub fn hash(&self) -> HashOf { + self.0.hash() + } + pub(crate) fn payload(&self) -> &BlockPayload { + self.0.payload() + } + pub(crate) fn signatures(&self) -> &SignaturesOf { + self.0.signatures() } } - Ok(()) -} + impl CommittedBlock { + pub(crate) fn produce_events(&self) -> Vec { + let tx = self.payload().transactions.iter().map(|tx| { + let status = tx.error.as_ref().map_or_else( + || PipelineStatus::Committed, + |error| PipelineStatus::Rejected(error.clone().into()), + ); -impl From<&PendingBlock> for Vec { - fn from(block: &PendingBlock) -> Self { - block - .transactions - .iter() - .map(|transaction| -> Event { PipelineEvent { entity_kind: PipelineEntityKind::Transaction, - status: PipelineStatus::Validating, - hash: transaction.payload().hash().into(), + status, + hash: tx.payload().hash().into(), } - .into() - }) - .chain([PipelineEvent { + }); + let current_block = core::iter::once(PipelineEvent { entity_kind: PipelineEntityKind::Block, - status: PipelineStatus::Validating, - hash: block.partial_hash().into(), - } - .into()]) - .collect() + status: PipelineStatus::Committed, + hash: self.hash().into(), + }); + + tx.chain(current_block).collect() + } + } + + impl From for ValidBlock { + fn from(source: CommittedBlock) -> Self { + ValidBlock(source.0) + } + } + + impl From for VersionedSignedBlock { + fn from(source: CommittedBlock) -> Self { + source.0 + } } } @@ -602,12 +593,13 @@ mod tests { #[test] pub fn committed_and_valid_block_hashes_are_equal() { - let valid_block = PendingBlock::new_dummy(); - let committed_block = valid_block.clone().commit_unchecked(); + let valid_block = ValidBlock::new_dummy(); + let topology = Topology::new(Vec::new()); + let committed_block = valid_block.clone().commit(&topology).unwrap(); assert_eq!( - *valid_block.partial_hash(), - committed_block.partial_hash().internal + valid_block.payload().hash(), + committed_block.payload().hash() ) } @@ -640,21 +632,17 @@ mod tests { // Creating a block of two identical transactions and validating it let transactions = vec![tx.clone(), tx]; - let valid_block = BlockBuilder { - transactions, - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: Topology::new(Vec::new()), - key_pair: alice_keys, - wsv: &mut wsv, - } - .build(); + let topology = Topology::new(Vec::new()); + let valid_block = BlockBuilder::new(transactions, topology, Vec::new()) + .chain_first(&mut wsv) + .sign(alice_keys) + .expect("Valid"); // The first transaction should be confirmed - assert!(valid_block.transactions[0].error.is_none()); + assert!(valid_block.payload().transactions[0].error.is_none()); // The second transaction should be rejected - assert!(valid_block.transactions[1].error.is_some()); + assert!(valid_block.payload().transactions[1].error.is_some()); } #[test] @@ -711,23 +699,17 @@ mod tests { // Creating a block of two identical transactions and validating it let transactions = vec![tx0, tx, tx2]; - let valid_block = BlockBuilder { - transactions, - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: Topology::new(Vec::new()), - key_pair: alice_keys, - wsv: &mut wsv.clone(), - } - .build(); + let topology = Topology::new(Vec::new()); + let valid_block = BlockBuilder::new(transactions, topology, Vec::new()) + .chain_first(&mut wsv) + .sign(alice_keys) + .expect("Valid"); // The first transaction should fail - assert!(valid_block.transactions[0].error.is_some()); + assert!(valid_block.payload().transactions[0].error.is_some()); // The third transaction should succeed - assert!(valid_block.transactions[2].error.is_none()); - - valid_block.revalidate(&mut wsv).unwrap(); + assert!(valid_block.payload().transactions[2].error.is_none()); } #[test] @@ -770,25 +752,21 @@ mod tests { // Creating a block of where first transaction must fail and second one fully executed let transactions = vec![tx_fail, tx_accept]; - let valid_block = BlockBuilder { - transactions, - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: Topology::new(Vec::new()), - key_pair: alice_keys, - wsv: &mut wsv, - } - .build(); + let topology = Topology::new(Vec::new()); + let valid_block = BlockBuilder::new(transactions, topology, Vec::new()) + .chain_first(&mut wsv) + .sign(alice_keys) + .expect("Valid"); // The first transaction should be rejected assert!( - valid_block.transactions[0].error.is_some(), + valid_block.payload().transactions[0].error.is_some(), "The first transaction should be rejected, as it contains `FailBox`." ); // The second transaction should be accepted assert!( - valid_block.transactions[1].error.is_none(), + valid_block.payload().transactions[1].error.is_none(), "The second transaction should be accepted." ); } diff --git a/core/src/block_sync.rs b/core/src/block_sync.rs index 9eefb40334a..89b1dd2518e 100644 --- a/core/src/block_sync.rs +++ b/core/src/block_sync.rs @@ -8,11 +8,10 @@ use std::{fmt::Debug, sync::Arc, time::Duration}; use iroha_config::block_sync::Configuration; use iroha_crypto::HashOf; -use iroha_data_model::{block::VersionedCommittedBlock, prelude::*}; +use iroha_data_model::{block::VersionedSignedBlock, prelude::*}; use iroha_logger::prelude::*; use iroha_macro::*; use iroha_p2p::Post; -use iroha_version::prelude::*; use parity_scale_codec::{Decode, Encode}; use tokio::sync::mpsc; @@ -44,8 +43,8 @@ pub struct BlockSynchronizer { gossip_period: Duration, block_batch_size: u32, network: IrohaNetwork, - latest_hash: Option>, - previous_hash: Option>, + latest_hash: Option>, + previous_hash: Option>, } impl BlockSynchronizer { @@ -136,38 +135,13 @@ pub mod message { use super::*; use crate::sumeragi::view_change::ProofChain; - declare_versioned_with_scale!(VersionedMessage 1..2, Debug, Clone, iroha_macro::FromVariant); - - impl VersionedMessage { - /// Convert from `&VersionedMessage` to V1 reference - pub const fn as_v1(&self) -> &Message { - match self { - Self::V1(v1) => v1, - } - } - - /// Convert from `&mut VersionedMessage` to V1 mutable reference - pub fn as_mut_v1(&mut self) -> &mut Message { - match self { - Self::V1(v1) => v1, - } - } - - /// Performs the conversion from `VersionedMessage` to V1 - pub fn into_v1(self) -> Message { - match self { - Self::V1(v1) => v1, - } - } - } - /// Get blocks after some block #[derive(Debug, Clone, Decode, Encode)] pub struct GetBlocksAfter { /// Hash of latest available block - pub latest_hash: Option>, + pub latest_hash: Option>, /// Hash of second to latest block - pub previous_hash: Option>, + pub previous_hash: Option>, /// Peer id pub peer_id: PeerId, } @@ -175,8 +149,8 @@ pub mod message { impl GetBlocksAfter { /// Construct [`GetBlocksAfter`]. pub const fn new( - latest_hash: Option>, - previous_hash: Option>, + latest_hash: Option>, + previous_hash: Option>, peer_id: PeerId, ) -> Self { Self { @@ -191,20 +165,19 @@ pub mod message { #[derive(Debug, Clone, Decode, Encode)] pub struct ShareBlocks { /// Blocks - pub blocks: Vec, + pub blocks: Vec, /// Peer id pub peer_id: PeerId, } impl ShareBlocks { /// Construct [`ShareBlocks`]. - pub const fn new(blocks: Vec, peer_id: PeerId) -> Self { + pub const fn new(blocks: Vec, peer_id: PeerId) -> Self { Self { blocks, peer_id } } } /// Message's variants that are used by peers to communicate in the process of consensus. - #[version_with_scale(version = 1, versioned_alias = "VersionedMessage")] #[derive(Debug, Clone, Decode, Encode, FromVariant)] pub enum Message { /// Request for blocks after the block with `Hash` for the peer with `PeerId`. @@ -249,7 +222,7 @@ pub mod message { .take(1 + block_sync.block_batch_size as usize) .map_while(|height| block_sync.kura.get_block_by_height(height)) .skip_while(|block| Some(block.hash()) == *latest_hash) - .map(|block| VersionedCommittedBlock::clone(&block)) + .map(|block| VersionedSignedBlock::clone(&block)) .collect::>(); if blocks.is_empty() { @@ -280,7 +253,7 @@ pub mod message { #[iroha_futures::telemetry_future] #[log("TRACE")] pub async fn send_to(self, network: &IrohaNetwork, peer: PeerId) { - let data = NetworkMessage::BlockSync(Box::new(VersionedMessage::from(self))); + let data = NetworkMessage::BlockSync(Box::new(self)); let message = Post { data, peer_id: peer.clone(), diff --git a/core/src/kura.rs b/core/src/kura.rs index a02f772d822..80fa8975744 100644 --- a/core/src/kura.rs +++ b/core/src/kura.rs @@ -1,6 +1,6 @@ //! Translates to warehouse. File-system and persistence-related //! logic. [`Kura`] is the main entity which should be used to store -//! new [`Block`](`crate::block::VersionedCommittedBlock`)s on the +//! new [`Block`](`crate::block::VersionedSignedBlock`)s on the //! blockchain. #![allow(clippy::std_instead_of_alloc, clippy::arithmetic_side_effects)] use std::{ @@ -13,19 +13,20 @@ use std::{ use iroha_config::kura::Mode; use iroha_crypto::{Hash, HashOf}; -use iroha_data_model::block::VersionedCommittedBlock; +use iroha_data_model::block::VersionedSignedBlock; use iroha_logger::prelude::*; use iroha_version::scale::{DecodeVersioned, EncodeVersioned}; +use parity_scale_codec::DecodeAll; use parking_lot::Mutex; -use crate::handler::ThreadHandler; +use crate::{block::CommittedBlock, handler::ThreadHandler}; const INDEX_FILE_NAME: &str = "blocks.index"; const DATA_FILE_NAME: &str = "blocks.data"; const HASHES_FILE_NAME: &str = "blocks.hashes"; const LOCK_FILE_NAME: &str = "kura.lock"; -const SIZE_OF_BLOCK_HASH: u64 = std::mem::size_of::>() as u64; +const SIZE_OF_BLOCK_HASH: u64 = Hash::LENGTH as u64; /// The interface of Kura subsystem #[derive(Debug)] @@ -39,8 +40,8 @@ pub struct Kura { #[allow(clippy::type_complexity)] block_data: Mutex< Vec<( - HashOf, - Option>, + HashOf, + Option>, )>, >, /// Path to file for plain text blocks. @@ -143,7 +144,7 @@ impl Kura { fn init_fast_mode( block_store: &BlockStore, block_index_count: usize, - ) -> Result>, Error> { + ) -> Result>, Error> { let block_hashes_count = block_store .read_hashes_count()? .try_into() @@ -158,7 +159,7 @@ impl Kura { fn init_strict_mode( block_store: &mut BlockStore, block_index_count: usize, - ) -> Result>, Error> { + ) -> Result>, Error> { let mut block_hashes = Vec::with_capacity(block_index_count); let mut block_indices = vec![BlockIndex::default(); block_index_count]; @@ -170,9 +171,10 @@ impl Kura { let mut block_data_buffer = vec![0_u8; block.length.try_into()?]; match block_store.read_block_data(block.start, &mut block_data_buffer) { - Ok(_) => match VersionedCommittedBlock::decode_all_versioned(&block_data_buffer) { + Ok(_) => match VersionedSignedBlock::decode_all_versioned(&block_data_buffer) { Ok(decoded_block) => { - if previous_block_hash != decoded_block.as_v1().header.previous_block_hash { + if previous_block_hash != decoded_block.payload().header.previous_block_hash + { error!("Block has wrong previous block hash. Not reading any blocks beyond this height."); break; } @@ -282,7 +284,7 @@ impl Kura { /// Get the hash of the block at the provided height. #[allow(clippy::expect_used)] - pub fn get_block_hash(&self, block_height: u64) -> Option> { + pub fn get_block_hash(&self, block_height: u64) -> Option> { let hash_data_guard = self.block_data.lock(); if block_height == 0 || block_height > hash_data_guard.len() as u64 { return None; @@ -294,7 +296,7 @@ impl Kura { } /// Search through blocks for the height of the block with the given hash. - pub fn get_block_height_by_hash(&self, hash: &HashOf) -> Option { + pub fn get_block_height_by_hash(&self, hash: &HashOf) -> Option { self.block_data .lock() .iter() @@ -306,7 +308,7 @@ impl Kura { #[allow(clippy::expect_used)] // The below lint suggests changing the code into something that does not compile due // to the borrow checker. - pub fn get_block_by_height(&self, block_height: u64) -> Option> { + pub fn get_block_by_height(&self, block_height: u64) -> Option> { let mut data_array_guard = self.block_data.lock(); if block_height == 0 || block_height > data_array_guard.len() as u64 { return None; @@ -329,8 +331,8 @@ impl Kura { block_store .read_block_data(start, &mut block_buf) .expect("Failed to read block data."); - let block = VersionedCommittedBlock::decode_all_versioned(&block_buf) - .expect("Failed to decode block"); + let block = + VersionedSignedBlock::decode_all_versioned(&block_buf).expect("Failed to decode block"); let block_arc = Arc::new(block); data_array_guard[block_number].1 = Some(Arc::clone(&block_arc)); @@ -344,8 +346,8 @@ impl Kura { /// call `get_block_by_height` directly. pub fn get_block_by_hash( &self, - block_hash: &HashOf, - ) -> Option> { + block_hash: &HashOf, + ) -> Option> { let index = self .block_data .lock() @@ -356,17 +358,17 @@ impl Kura { } /// Put a block in kura's in memory block store. - pub fn store_block(&self, block: VersionedCommittedBlock) { - self.block_data - .lock() - .push((block.hash(), Some(Arc::new(block)))); + pub fn store_block(&self, block: CommittedBlock) { + let block = Arc::new(VersionedSignedBlock::from(block)); + self.block_data.lock().push((block.hash(), Some(block))); } /// Replace the block in `Kura`'s in memory block store. - pub fn replace_top_block(&self, block: VersionedCommittedBlock) { + pub fn replace_top_block(&self, block: CommittedBlock) { + let block = Arc::new(VersionedSignedBlock::from(block)); let mut data = self.block_data.lock(); data.pop(); - data.push((block.hash(), Some(Arc::new(block)))); + data.push((block.hash(), Some(block))); } } @@ -465,12 +467,12 @@ impl BlockStore { let mut index_file = std::fs::OpenOptions::new() .read(true) .open(path.clone()) - .add_err_context(path.clone())?; + .add_err_context(&path)?; let start_location = start_block_height * (2 * std::mem::size_of::() as u64); let block_count = dest_buffer.len(); if start_location + (2 * std::mem::size_of::() as u64) * block_count as u64 - > index_file.metadata().add_err_context(path.clone())?.len() + > index_file.metadata().add_err_context(&path)?.len() { return Err(Error::OutOfBoundsBlockRead { start_block_height, @@ -479,25 +481,23 @@ impl BlockStore { } index_file .seek(SeekFrom::Start(start_location)) - .add_err_context(path.clone())?; - let mut buffer = [0; core::mem::size_of::()]; + .add_err_context(&path)?; // (start, length), (start,length) ... for current_buffer in dest_buffer.iter_mut() { + let mut buffer = [0; core::mem::size_of::()]; + *current_buffer = BlockIndex { start: { - index_file - .read_exact(&mut buffer) - .add_err_context(path.clone())?; + index_file.read_exact(&mut buffer).add_err_context(&path)?; u64::from_le_bytes(buffer) }, length: { - index_file - .read_exact(&mut buffer) - .add_err_context(path.clone())?; + index_file.read_exact(&mut buffer).add_err_context(&path)?; u64::from_le_bytes(buffer) }, }; } + Ok(()) } @@ -532,8 +532,8 @@ impl BlockStore { let index_file = std::fs::OpenOptions::new() .read(true) .open(path.clone()) - .add_err_context(path.clone())?; - Ok(index_file.metadata().add_err_context(path)?.len() + .add_err_context(&path)?; + Ok(index_file.metadata().add_err_context(&path)?.len() / (2 * std::mem::size_of::() as u64)) // Each entry is 16 bytes. } @@ -546,16 +546,16 @@ impl BlockStore { &self, start_block_height: u64, block_count: usize, - ) -> Result>> { + ) -> Result>> { let path = self.path_to_blockchain.join(HASHES_FILE_NAME); let mut hashes_file = std::fs::OpenOptions::new() .read(true) .open(path.clone()) - .add_err_context(path.clone())?; + .add_err_context(&path)?; let start_location = start_block_height * SIZE_OF_BLOCK_HASH; if start_location + (SIZE_OF_BLOCK_HASH) * block_count as u64 - > hashes_file.metadata().add_err_context(path.clone())?.len() + > hashes_file.metadata().add_err_context(&path)?.len() { return Err(Error::OutOfBoundsBlockRead { start_block_height, @@ -564,22 +564,23 @@ impl BlockStore { } hashes_file .seek(SeekFrom::Start(start_location)) - .add_err_context(path.clone())?; + .add_err_context(&path)?; - let mut buffer = [0; Hash::LENGTH]; (0..block_count) .map(|_| { + let mut buffer = [0; Hash::LENGTH]; + hashes_file .read_exact(&mut buffer) - .add_err_context(path.clone()) - .map(|_| HashOf::from_untyped_unchecked(Hash::prehashed(buffer))) + .add_err_context(&path) + .and_then(|_| HashOf::decode_all(&mut buffer.as_slice()).map_err(Error::Codec)) }) .collect() } /// Get the number of hashes in the hashes file, which is /// calculated as the size of the hashes file in bytes divided by - /// `size_of(HashOf)`. + /// `size_of(HashOf)`. /// /// # Errors /// IO Error. @@ -592,8 +593,8 @@ impl BlockStore { let hashes_file = std::fs::OpenOptions::new() .read(true) .open(path.clone()) - .add_err_context(path.clone())?; - Ok(hashes_file.metadata().add_err_context(path)?.len() / SIZE_OF_BLOCK_HASH) + .add_err_context(&path)?; + Ok(hashes_file.metadata().add_err_context(&path)?.len() / SIZE_OF_BLOCK_HASH) } /// Read block data starting from the @@ -611,11 +612,12 @@ impl BlockStore { let mut data_file = std::fs::OpenOptions::new() .read(true) .open(path.clone()) - .add_err_context(path.clone())?; + .add_err_context(&path)?; data_file .seek(SeekFrom::Start(start_location_in_data_file)) - .add_err_context(path.clone())?; - data_file.read_exact(dest_buffer).add_err_context(path)?; + .add_err_context(&path)?; + data_file.read_exact(dest_buffer).add_err_context(&path)?; + Ok(()) } @@ -631,26 +633,26 @@ impl BlockStore { .write(true) .create(true) .open(path.clone()) - .add_err_context(path.clone())?; + .add_err_context(&path)?; let start_location = block_height * (2 * std::mem::size_of::() as u64); if start_location + (2 * std::mem::size_of::() as u64) - > index_file.metadata().add_err_context(path.clone())?.len() + > index_file.metadata().add_err_context(&path)?.len() { index_file .set_len(start_location + (2 * std::mem::size_of::() as u64)) - .add_err_context(path.clone())?; + .add_err_context(&path)?; } index_file .seek(SeekFrom::Start(start_location)) - .add_err_context(path.clone())?; + .add_err_context(&path)?; // block0 | block1 // start, length| start, length ... et cetera. index_file .write_all(&start.to_le_bytes()) - .add_err_context(path.clone())?; + .add_err_context(&path)?; index_file .write_all(&length.to_le_bytes()) - .add_err_context(path)?; + .add_err_context(&path)?; Ok(()) } @@ -670,9 +672,9 @@ impl BlockStore { let index_file = std::fs::OpenOptions::new() .write(true) .open(path.clone()) - .add_err_context(path.clone())?; + .add_err_context(&path)?; let new_byte_size = new_count * (2 * std::mem::size_of::() as u64); - index_file.set_len(new_byte_size).add_err_context(path)?; + index_file.set_len(new_byte_size).add_err_context(&path)?; Ok(()) } @@ -691,18 +693,18 @@ impl BlockStore { let mut data_file = std::fs::OpenOptions::new() .write(true) .open(path.clone()) - .add_err_context(path.clone())?; + .add_err_context(&path)?; if start_location_in_data_file + block_data.len() as u64 - > data_file.metadata().add_err_context(path.clone())?.len() + > data_file.metadata().add_err_context(&path)?.len() { data_file .set_len(start_location_in_data_file + block_data.len() as u64) - .add_err_context(path.clone())?; + .add_err_context(&path)?; } data_file .seek(SeekFrom::Start(start_location_in_data_file)) - .add_err_context(path.clone())?; - data_file.write_all(block_data).add_err_context(path)?; + .add_err_context(&path)?; + data_file.write_all(block_data).add_err_context(&path)?; Ok(()) } @@ -715,36 +717,38 @@ impl BlockStore { pub fn write_block_hash( &mut self, block_height: u64, - hash: HashOf, + hash: HashOf, ) -> Result<()> { let path = self.path_to_blockchain.join(HASHES_FILE_NAME); let mut hashes_file = std::fs::OpenOptions::new() .write(true) .create(true) .open(path.clone()) - .add_err_context(path.clone())?; + .add_err_context(&path)?; let start_location = block_height * SIZE_OF_BLOCK_HASH; if start_location + SIZE_OF_BLOCK_HASH - > hashes_file.metadata().add_err_context(path.clone())?.len() + > hashes_file.metadata().add_err_context(&path)?.len() { hashes_file .set_len(start_location + SIZE_OF_BLOCK_HASH) - .add_err_context(path.clone())?; + .add_err_context(&path)?; } hashes_file .seek(SeekFrom::Start(start_location)) - .add_err_context(path.clone())?; - hashes_file.write_all(hash.as_ref()).add_err_context(path)?; + .add_err_context(&path)?; + hashes_file + .write_all(hash.as_ref()) + .add_err_context(&path)?; Ok(()) } - /// Write the hashes to the hashes file overwriting any previous hashes. + /// Write the hashes to the hashes file overwriting any previous hashes. /// /// # Errors /// IO Error. pub fn overwrite_block_hashes( &mut self, - hashes: &[HashOf], + hashes: &[HashOf], ) -> Result<()> { let path = self.path_to_blockchain.join(HASHES_FILE_NAME); let hashes_file = std::fs::OpenOptions::new() @@ -752,12 +756,12 @@ impl BlockStore { .create(true) .truncate(true) .open(path.clone()) - .add_err_context(path.clone())?; + .add_err_context(&path)?; let mut hashes_file = BufWriter::new(hashes_file); for hash in hashes { hashes_file .write_all(hash.as_ref()) - .add_err_context(path.clone())?; + .add_err_context(&path)?; } Ok(()) } @@ -776,19 +780,19 @@ impl BlockStore { .write(true) .create(true) .open(path.clone()) - .add_err_context(path)?; + .add_err_context(&path)?; let path = self.path_to_blockchain.join(DATA_FILE_NAME); std::fs::OpenOptions::new() .write(true) .create(true) .open(path.clone()) - .add_err_context(path)?; + .add_err_context(&path)?; let path = self.path_to_blockchain.join(HASHES_FILE_NAME); std::fs::OpenOptions::new() .write(true) .create(true) .open(path.clone()) - .add_err_context(path)?; + .add_err_context(&path)?; Ok(()) } @@ -799,7 +803,7 @@ impl BlockStore { /// # Errors /// Fails if any of the required platform-specific functions /// fail. - pub fn append_block_to_chain(&mut self, block: &VersionedCommittedBlock) -> Result<()> { + pub fn append_block_to_chain(&mut self, block: &VersionedSignedBlock) -> Result<()> { let bytes = block.encode_versioned(); let new_block_height = self.read_index_count()?; let start_location_in_data_file = if new_block_height == 0 { @@ -830,7 +834,7 @@ pub enum Error { /// Failed to create the directory {1:?} MkDir(#[source] std::io::Error, PathBuf), /// Failed to serialize/deserialize block - Codec(#[from] iroha_version::error::Error), + Codec(#[from] parity_scale_codec::Error), /// Failed to allocate buffer Alloc(#[from] std::collections::TryReserveError), /// Tried reading block data out of bounds: {start_block_height}, {block_count} @@ -851,14 +855,14 @@ pub enum Error { trait AddErrContextExt { type Context; - fn add_err_context(self, context: Self::Context) -> Result; + fn add_err_context(self, context: &Self::Context) -> Result; } impl AddErrContextExt for Result { type Context = PathBuf; - fn add_err_context(self, path: Self::Context) -> Result { - self.map_err(|e| Error::IO(e, path)) + fn add_err_context(self, path: &Self::Context) -> Result { + self.map_err(|e| Error::IO(e, path.clone())) } } @@ -869,7 +873,7 @@ mod tests { use tempfile::TempDir; use super::*; - use crate::block::PendingBlock; + use crate::block::ValidBlock; fn indices(value: [(u64, u64); N]) -> [BlockIndex; N] { let mut ret = [BlockIndex { @@ -969,7 +973,7 @@ mod tests { let mut block_store = BlockStore::new(dir.path(), LockStatus::Unlocked); block_store.create_files_if_they_do_not_exist().unwrap(); - let dummy_block = PendingBlock::new_dummy().commit_unchecked().into(); + let dummy_block = ValidBlock::new_dummy().into(); let append_count = 35; for _ in 0..append_count { @@ -985,7 +989,7 @@ mod tests { let mut block_store = BlockStore::new(dir.path(), LockStatus::Unlocked); block_store.create_files_if_they_do_not_exist().unwrap(); - let dummy_block = PendingBlock::new_dummy().commit_unchecked().into(); + let dummy_block = ValidBlock::new_dummy().into(); let append_count = 35; for _ in 0..append_count { @@ -1001,7 +1005,7 @@ mod tests { let mut block_store = BlockStore::new(dir.path(), LockStatus::Unlocked); block_store.create_files_if_they_do_not_exist().unwrap(); - let dummy_block = PendingBlock::new_dummy().commit_unchecked().into(); + let dummy_block = ValidBlock::new_dummy().into(); let append_count = 35; for _ in 0..append_count { @@ -1021,15 +1025,14 @@ mod tests { let mut block_store = BlockStore::new(dir.path(), LockStatus::Unlocked); block_store.create_files_if_they_do_not_exist().unwrap(); - let dummy_block: VersionedCommittedBlock = - PendingBlock::new_dummy().commit_unchecked().into(); - let block_data = dummy_block.encode_versioned(); + let dummy_block = ValidBlock::new_dummy().into(); let append_count = 35; for _ in 0..append_count { block_store.append_block_to_chain(&dummy_block).unwrap(); } + let block_data = dummy_block.encode_versioned(); for i in 0..append_count { let BlockIndex { start, length } = block_store.read_block_index(i).unwrap(); assert_eq!(i * block_data.len() as u64, start); diff --git a/core/src/lib.rs b/core/src/lib.rs index 4ba13ecfca6..2ccbacd4f06 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -22,8 +22,8 @@ use parity_scale_codec::{Decode, Encode}; use tokio::sync::broadcast; use crate::{ - block_sync::message::VersionedMessage as BlockSyncMessage, prelude::*, - sumeragi::message::VersionedPacket as SumeragiPacket, + block_sync::message::Message as BlockSyncMessage, prelude::*, + sumeragi::message::MessagePacket as SumeragiPacket, }; /// The interval at which sumeragi checks if there are tx in the `queue`. @@ -33,16 +33,16 @@ pub const TX_RETRIEVAL_INTERVAL: Duration = Duration::from_millis(100); pub type IrohaNetwork = iroha_p2p::NetworkHandle; /// Ids of peers. -pub type PeersIds = HashSet<::Id>; +pub type PeersIds = HashSet; /// Parameters set. pub type Parameters = HashSet; /// API to work with collections of [`DomainId`] : [`Domain`] mappings. -pub type DomainsMap = HashMap<::Id, Domain>; +pub type DomainsMap = HashMap; /// API to work with a collections of [`RoleId`]: [`Role`] mappings. -pub type RolesMap = HashMap<::Id, Role>; +pub type RolesMap = HashMap; /// API to work with a collections of [`AccountId`] [`Permissions`] mappings. pub type PermissionTokensMap = HashMap; diff --git a/core/src/smartcontracts/isi/block.rs b/core/src/smartcontracts/isi/block.rs index 017f03a4a6d..e72a8161d5e 100644 --- a/core/src/smartcontracts/isi/block.rs +++ b/core/src/smartcontracts/isi/block.rs @@ -1,7 +1,7 @@ //! This module contains trait implementations related to block queries use eyre::{Result, WrapErr}; use iroha_data_model::{ - block::{BlockHeader, VersionedCommittedBlock}, + block::{BlockHeader, VersionedSignedBlock}, evaluate::ExpressionEvaluator, query::{ block::FindBlockHeaderByHash, @@ -17,9 +17,11 @@ impl ValidQuery for FindAllBlocks { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result + 'wsv>, QueryExecutionFail> { + ) -> Result + 'wsv>, QueryExecutionFail> { Ok(Box::new( - wsv.all_blocks().rev().map(|block| Clone::clone(&*block)), + wsv.all_blocks() + .rev() + .map(|block| VersionedSignedBlock::clone(&block)), )) } } @@ -33,7 +35,7 @@ impl ValidQuery for FindAllBlockHeaders { Ok(Box::new( wsv.all_blocks() .rev() - .map(|block| block.as_v1().header.clone()), + .map(|block| block.payload().header.clone()), )) } } @@ -51,6 +53,6 @@ impl ValidQuery for FindBlockHeaderByHash { .find(|block| block.hash() == hash) .ok_or_else(|| QueryExecutionFail::Find(FindError::Block(hash)))?; - Ok(block.as_v1().header.clone()) + Ok(block.payload().header.clone()) } } diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 21d97aec86c..bb33e436c7b 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -179,15 +179,13 @@ mod tests { use std::str::FromStr as _; use iroha_crypto::{Hash, HashOf, KeyPair}; - use iroha_data_model::{ - block::VersionedCommittedBlock, query::error::FindError, transaction::TransactionLimits, - }; + use iroha_data_model::{query::error::FindError, transaction::TransactionLimits}; use once_cell::sync::Lazy; use super::*; use crate::{ - block::*, kura::Kura, smartcontracts::isi::Registrable as _, tx::AcceptedTransaction, - wsv::World, PeersIds, + block::*, kura::Kura, smartcontracts::isi::Registrable as _, + sumeragi::network_topology::Topology, tx::AcceptedTransaction, wsv::World, PeersIds, }; static ALICE_KEYS: Lazy = Lazy::new(|| KeyPair::generate().unwrap()); @@ -292,33 +290,22 @@ mod tests { let mut transactions = vec![valid_tx; valid_tx_per_block]; transactions.append(&mut vec![invalid_tx; invalid_tx_per_block]); - let first_block: VersionedCommittedBlock = BlockBuilder { - transactions: transactions.clone(), - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: crate::sumeragi::network_topology::Topology::new(vec![]), - key_pair: ALICE_KEYS.clone(), - wsv: &mut wsv.clone(), - } - .build() - .commit_unchecked() - .into(); + let topology = Topology::new(vec![]); + let first_block = BlockBuilder::new(transactions.clone(), topology.clone(), Vec::new()) + .chain_first(&mut wsv) + .sign(ALICE_KEYS.clone())? + .commit(&topology) + .expect("Block is valid"); wsv.apply(&first_block)?; kura.store_block(first_block); for _ in 1u64..blocks { - let block: VersionedCommittedBlock = BlockBuilder { - transactions: transactions.clone(), - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: crate::sumeragi::network_topology::Topology::new(vec![]), - key_pair: ALICE_KEYS.clone(), - wsv: &mut wsv.clone(), - } - .build() - .commit_unchecked() - .into(); + let block = BlockBuilder::new(transactions.clone(), topology.clone(), Vec::new()) + .chain(0, &mut wsv) + .sign(ALICE_KEYS.clone())? + .commit(&topology) + .expect("Block is valid"); wsv.apply(&block)?; kura.store_block(block); @@ -390,7 +377,7 @@ mod tests { assert_eq!( FindBlockHeaderByHash::new(block.hash()).execute(&wsv)?, - block.as_v1().header + block.payload().header ); assert!( @@ -439,17 +426,12 @@ mod tests { let tx_limits = &wsv.transaction_validator().transaction_limits; let va_tx = AcceptedTransaction::accept(tx, tx_limits)?; - let vcb: VersionedCommittedBlock = BlockBuilder { - transactions: vec![va_tx.clone()], - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: crate::sumeragi::network_topology::Topology::new(vec![]), - key_pair: ALICE_KEYS.clone(), - wsv: &mut wsv.clone(), - } - .build() - .commit_unchecked() - .into(); + let topology = Topology::new(vec![]); + let vcb = BlockBuilder::new(vec![va_tx.clone()], topology.clone(), Vec::new()) + .chain_first(&mut wsv) + .sign(ALICE_KEYS.clone())? + .commit(&topology) + .expect("Block is valid"); wsv.apply(&vcb)?; kura.store_block(vcb); @@ -468,10 +450,7 @@ mod tests { let found_accepted = FindTransactionByHash::new(va_tx.hash()).execute(&wsv)?; if found_accepted.transaction.error.is_none() { - assert_eq!( - va_tx.hash().transmute(), - found_accepted.transaction.value.hash() - ) + assert_eq!(va_tx.hash(), found_accepted.transaction.hash()) } Ok(()) } diff --git a/core/src/smartcontracts/isi/tx.rs b/core/src/smartcontracts/isi/tx.rs index dbc85541346..9729ed44153 100644 --- a/core/src/smartcontracts/isi/tx.rs +++ b/core/src/smartcontracts/isi/tx.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use eyre::{Result, WrapErr}; use iroha_crypto::HashOf; use iroha_data_model::{ - block::VersionedCommittedBlock, + block::VersionedSignedBlock, evaluate::ExpressionEvaluator, prelude::*, query::{ @@ -18,11 +18,11 @@ use iroha_telemetry::metrics; use super::*; -pub(crate) struct BlockTransactionIter(Arc, usize); -pub(crate) struct BlockTransactionRef(Arc, usize); +pub(crate) struct BlockTransactionIter(Arc, usize); +pub(crate) struct BlockTransactionRef(Arc, usize); impl BlockTransactionIter { - fn new(block: Arc) -> Self { + fn new(block: Arc) -> Self { Self(block, 0) } } @@ -31,9 +31,7 @@ impl Iterator for BlockTransactionIter { type Item = BlockTransactionRef; fn next(&mut self) -> Option { - let block = self.0.as_v1(); - - if self.1 < block.transactions.len() { + if self.1 < self.0.payload().transactions.len() { let res = Some(BlockTransactionRef(Arc::clone(&self.0), self.1)); self.1 += 1; @@ -45,17 +43,15 @@ impl Iterator for BlockTransactionIter { } impl BlockTransactionRef { - fn block_hash(&self) -> HashOf { + fn block_hash(&self) -> HashOf { self.0.hash() } fn authority(&self) -> &AccountId { - let block = self.0.as_v1(); - - &block.transactions[self.1].payload().authority + &self.0.payload().transactions[self.1].payload().authority } fn value(&self) -> TransactionValue { - self.0.as_v1().transactions[self.1].clone() + self.0.payload().transactions[self.1].clone() } } @@ -115,9 +111,9 @@ impl ValidQuery for FindTransactionByHash { .ok_or_else(|| FindError::Transaction(tx_hash))?; let block_hash = block.hash(); - let block = block.as_v1(); block + .payload() .transactions .iter() .find(|transaction| transaction.value.hash() == tx_hash) diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index ba9aef57c0e..3c33390cf10 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -1002,7 +1002,7 @@ impl<'wrld> Runtime> { pub fn execute_validator_validate_transaction( &self, wsv: &'wrld mut WorldStateView, - authority: &::Id, + authority: &AccountId, module: &wasmtime::Module, transaction: VersionedSignedTransaction, ) -> Result { @@ -1078,7 +1078,7 @@ impl<'wrld> Runtime> { pub fn execute_validator_validate_instruction( &self, wsv: &'wrld mut WorldStateView, - authority: &::Id, + authority: &AccountId, module: &wasmtime::Module, instruction: InstructionBox, ) -> Result { @@ -1154,7 +1154,7 @@ impl<'wrld> Runtime> { pub fn execute_validator_validate_query( &self, wsv: &'wrld WorldStateView, - authority: &::Id, + authority: &AccountId, module: &wasmtime::Module, query: QueryBox, ) -> Result { @@ -1254,7 +1254,7 @@ impl<'wrld> Runtime> { pub fn execute_validator_migration( &self, wsv: &'wrld mut WorldStateView, - authority: &::Id, + authority: &AccountId, module: &wasmtime::Module, ) -> Result { let span = wasm_log_span!("Running migration"); diff --git a/core/src/snapshot.rs b/core/src/snapshot.rs index feb6830d441..bef4d0140da 100644 --- a/core/src/snapshot.rs +++ b/core/src/snapshot.rs @@ -15,7 +15,7 @@ use std::{ use iroha_config::snapshot::Configuration; use iroha_crypto::HashOf; -use iroha_data_model::block::VersionedCommittedBlock; +use iroha_data_model::block::VersionedSignedBlock; use iroha_logger::prelude::*; use serde::{de::DeserializeSeed, Serialize}; use tokio::sync::mpsc; @@ -219,8 +219,8 @@ pub enum Error { /// Height at which block hashes differs between snapshot and [`Kura`] height: usize, /// Hash of the block stored in snapshot - snapshot_block_hash: HashOf, + snapshot_block_hash: HashOf, /// Hash of the block stored in kura - kura_block_hash: HashOf, + kura_block_hash: HashOf, }, } diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index dbb0acb815b..133e3018c46 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -1,12 +1,14 @@ //! The main event loop that powers sumeragi. -#![allow(clippy::cognitive_complexity)] use std::sync::mpsc; -use iroha_data_model::{block::*, peer::PeerId, transaction::error::TransactionRejectionReason}; +use iroha_data_model::{ + block::*, events::pipeline::PipelineEvent, peer::PeerId, + transaction::error::TransactionRejectionReason, +}; use iroha_p2p::UpdateTopology; use tracing::{span, Level}; -use super::*; +use super::{view_change::ProofBuilder, *}; use crate::{block::*, sumeragi::tracing::instrument}; /// `Sumeragi` is the implementation of the consensus. @@ -78,13 +80,12 @@ impl Sumeragi { /// # Errors /// Fails if network sending fails #[instrument(skip(self, packet))] - #[allow(clippy::needless_pass_by_value)] // TODO: Fix. fn post_packet_to(&self, packet: MessagePacket, peer: &PeerId) { if peer == &self.peer_id { return; } let post = iroha_p2p::Post { - data: NetworkMessage::SumeragiPacket(Box::new(packet.into())), + data: NetworkMessage::SumeragiPacket(Box::new(packet)), peer_id: peer.clone(), }; self.network.post(post); @@ -101,17 +102,16 @@ impl Sumeragi { } } - #[allow(clippy::needless_pass_by_value)] fn broadcast_packet(&self, msg: MessagePacket) { let broadcast = iroha_p2p::Broadcast { - data: NetworkMessage::SumeragiPacket(Box::new(msg.into())), + data: NetworkMessage::SumeragiPacket(Box::new(msg)), }; self.network.broadcast(broadcast); } /// Connect or disconnect peers according to the current network topology. fn connect_peers(&self, topology: &Topology) { - let peers = topology.sorted_peers.clone().into_iter().collect(); + let peers = topology.ordered_peers.clone().into_iter().collect(); self.network.update_topology(UpdateTopology(peers)); } @@ -121,13 +121,13 @@ impl Sumeragi { self.block_time + self.commit_time } - fn send_events(&self, events: impl Into>) { + fn send_events(&self, events: impl IntoIterator>) { let addr = &self.peer_id.address; if self.events_sender.receiver_count() > 0 { - for event in events.into() { + for event in events { self.events_sender - .send(event) + .send(event.into()) .map_err(|err| warn!(%addr, ?err, "Event not sent")) .unwrap_or(0); } @@ -172,7 +172,7 @@ impl Sumeragi { .and_then(|packet : MessagePacket| { if let Err(error) = view_change_proof_chain.merge( packet.view_change_proofs, - &self.current_topology.sorted_peers, + &self.current_topology.ordered_peers, self.current_topology.max_faults(), self.wsv.latest_block_hash(), ) { @@ -195,67 +195,37 @@ impl Sumeragi { debug!(?e, "Early return."); e })?; - // we must connect to peers so that our block_sync can find us - // the genesis block. + match self.message_receiver.try_recv() { Ok(packet) => { if let Some(message) = packet.message { - let (block, new_wsv) = match message { - Message::BlockCreated(BlockCreated { block }) => { - let mut new_wsv = self.wsv.clone(); - // If we receive a committed genesis block that is - // valid, use it without question. During the - // genesis round we blindly take on the network - // topology described in the provided genesis - // block. - let block = { - let span = span!( - Level::TRACE, - "Genesis Round Peer is revalidating the block." - ); - let _enter = span.enter(); - match block.revalidate(&mut new_wsv) { - Ok(()) => block, - Err(error) => { - error!(?error); - continue; - } - } - }; - // Omit signature verification during genesis round - (block.commit_unchecked().into(), new_wsv) - } - Message::BlockSyncUpdate(BlockSyncUpdate { block }) => { - let mut new_wsv = self.wsv.clone(); - // Omit signature verification during genesis round - match block.revalidate(&mut new_wsv) { - Ok(()) => (block, new_wsv), - Err(error) => { - error!(?error); - continue; - } - } - } + let mut new_wsv = self.wsv.clone(); + + let block = match message { + Message::BlockCreated(BlockCreated { block }) + | Message::BlockSyncUpdate(BlockSyncUpdate { block }) => block, msg => { trace!(?msg, "Not handling the message, waiting for genesis..."); continue; } }; - if block.is_genesis() { - match &block { - VersionedCommittedBlock::V1(block) => { - assert!( - !block.transactions.iter().any(|tx| tx.error.is_some()), - "Genesis transaction set contains invalid transactions" - ); + let block = + match ValidBlock::validate(block, &self.current_topology, &mut new_wsv) + .and_then(|block| { + block + .commit(&self.current_topology) + .map_err(|(block, error)| (block.into(), error)) + }) { + Ok(block) => block, + Err((_, error)) => { + error!(?error, "Received invalid genesis block"); + continue; } - } + }; - self.commit_block(block, new_wsv); - return Err(EarlyReturn::GenesisBlockReceivedAndCommitted); - } - debug!("Received a block that was not genesis."); + self.commit_block(block, new_wsv); + return Err(EarlyReturn::GenesisBlockReceivedAndCommitted); } } Err(mpsc::TryRecvError::Disconnected) => return Err(EarlyReturn::Disconnected), @@ -267,8 +237,6 @@ impl Sumeragi { fn sumeragi_init_commit_genesis(&mut self, genesis_network: GenesisNetwork) { std::thread::sleep(Duration::from_millis(250)); - info!("Initializing iroha using the genesis block."); - assert_eq!(self.wsv.height(), 0); assert_eq!(self.wsv.latest_block_hash(), None); @@ -278,56 +246,45 @@ impl Sumeragi { .map(AcceptedTransaction::accept_genesis) .collect(); - // Don't start genesis round. Instead just commit the genesis block. - assert!( - !transactions.is_empty(), - "Genesis transaction set contains no valid transactions" + let mut new_wsv = self.wsv.clone(); + let genesis = BlockBuilder::new(transactions, self.current_topology.clone(), vec![]) + .chain_first(&mut new_wsv) + .sign(self.key_pair.clone()) + .expect("Genesis signing failed"); + + let genesis_msg = MessagePacket::new( + ProofChain::default(), + Some(BlockCreated::from(genesis.clone()).into()), ); - let mut new_wsv = self.wsv.clone(); - let block = BlockBuilder { - transactions, - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: self.current_topology.clone(), - key_pair: self.key_pair.clone(), - wsv: &mut new_wsv, - } - .build(); + let genesis = genesis + .commit(&self.current_topology) + .expect("Genesis invalid"); + assert!( - !block.transactions.iter().any(|tx| tx.error.is_some()), - "Genesis transaction set contains invalid transactions" + !genesis + .payload() + .transactions + .iter() + .any(|tx| tx.error.is_some()), + "Genesis contains invalid transactions" ); - { - info!(block_partial_hash = %block.partial_hash(), "Publishing genesis block."); - - info!( - role = ?self.current_topology.role(&self.peer_id), - block_partial_hash = %block.partial_hash(), - "Created a block to commit.", - ); + info!( + role = ?self.current_topology.role(&self.peer_id), + block_hash = %genesis.hash(), + "Genesis block created", + ); - self.send_events(&block); - let msg = MessagePacket::new( - ProofChain::default(), - Some(BlockCreated::from(block.clone()).into()), - ); - self.broadcast_packet(msg); - // Omit signature verification during genesis round - self.commit_block(block.commit_unchecked(), new_wsv); - } + self.commit_block(genesis, new_wsv); + self.broadcast_packet(genesis_msg); } - fn commit_block(&mut self, block: impl Into, new_wsv: WorldStateView) { + fn commit_block(&mut self, block: CommittedBlock, new_wsv: WorldStateView) { self.update_state::(block, new_wsv); } - fn replace_top_block( - &mut self, - block: impl Into, - new_wsv: WorldStateView, - ) { + fn replace_top_block(&mut self, block: CommittedBlock, new_wsv: WorldStateView) { self.update_state::(block, new_wsv); } @@ -345,48 +302,43 @@ impl Sumeragi { fn update_state( &mut self, - block: impl Into, + block: CommittedBlock, mut new_wsv: WorldStateView, ) { - let committed_block = block.into(); - info!( addr=%self.peer_id.address, role=%self.current_topology.role(&self.peer_id), block_height=%self.wsv.height(), - block_hash=%committed_block.hash(), + block_hash=%block.hash(), "{}", Strategy::LOG_MESSAGE, ); Strategy::before_update_hook(self); new_wsv - .apply_without_execution(&committed_block) + .apply_without_execution(&block) .expect("Failed to apply block on WSV. Bailing."); self.wsv = new_wsv; - let events_buffer = core::mem::take(&mut self.wsv.events_buffer); - self.send_events(events_buffer); + let wsv_events = core::mem::take(&mut self.wsv.events_buffer); + self.send_events(wsv_events); // Parameters are updated before updating public copy of sumeragi self.update_params(); - let events: Vec<_> = (&committed_block).into(); - let topology = committed_block - .as_v1() - .header() - .committed_with_topology - .clone(); - let block_signees = committed_block + let block_topology = block.payload().header.commit_topology.clone(); + let block_signees = block .signatures() + .into_iter() .map(|s| s.public_key()) .cloned() .collect::>(); + let events = block.produce_events(); // https://github.com/hyperledger/iroha/issues/3396 // Kura should store the block only upon successful application to the internal WSV to avoid storing a corrupted block. // Public-facing WSV update should happen after that and be followed by `BlockCommited` event to prevent client access to uncommitted data. - Strategy::kura_store_block(&self.kura, committed_block); + Strategy::kura_store_block(&self.kura, block); // Update WSV copy that is public facing self.public_wsv_sender @@ -401,13 +353,11 @@ impl Sumeragi { } }); - // This sends "Block committed" event, so it should be done - // AFTER public facing WSV update + // NOTE: This sends "Block committed" event, + // so it should be done AFTER public facing WSV update self.send_events(events); - - self.update_topology(&block_signees, topology); - - self.cache_transaction() + self.update_topology(&block_signees, block_topology); + self.cache_transaction(); } fn update_params(&mut self) { @@ -435,21 +385,14 @@ fn suggest_view_change( view_change_proof_chain: &mut ProofChain, current_view_change_index: u64, ) { - let suspect_proof = { - let mut proof = Proof { - latest_block_hash: sumeragi.wsv.latest_block_hash(), - view_change_index: current_view_change_index, - signatures: Vec::new(), - }; - proof + let suspect_proof = + ProofBuilder::new(sumeragi.wsv.latest_block_hash(), current_view_change_index) .sign(sumeragi.key_pair.clone()) .expect("Proof signing failed"); - proof - }; view_change_proof_chain .insert_proof( - &sumeragi.current_topology.sorted_peers, + &sumeragi.current_topology.ordered_peers, sumeragi.current_topology.max_faults(), sumeragi.wsv.latest_block_hash(), suspect_proof, @@ -466,7 +409,7 @@ fn prune_view_change_proofs_and_calculate_current_index( ) -> u64 { view_change_proof_chain.prune(sumeragi.wsv.latest_block_hash()); view_change_proof_chain.verify_with_state( - &sumeragi.current_topology.sorted_peers, + &sumeragi.current_topology.ordered_peers, sumeragi.current_topology.max_faults(), sumeragi.wsv.latest_block_hash(), ) as u64 @@ -479,7 +422,7 @@ fn handle_message( voting_block: &mut Option, current_view_change_index: u64, view_change_proof_chain: &mut ProofChain, - voting_signatures: &mut Vec>, + voting_signatures: &mut Vec>, ) { let current_topology = &sumeragi.current_topology; let role = current_topology.role(&sumeragi.peer_id); @@ -501,21 +444,24 @@ fn handle_message( peer_latest_block_hash=?sumeragi.wsv.latest_block_hash(), peer_latest_block_view_change_index=?sumeragi.wsv.latest_block_view_change_index(), consensus_latest_block_hash=%block.hash(), - consensus_latest_block_view_change_index=%block.as_v1().header.view_change_index, + consensus_latest_block_view_change_index=%block.payload().header.view_change_index, "Soft fork occurred: peer in inconsistent state. Rolling back and replacing top block." ); sumeragi.replace_top_block(block, new_wsv) } - Err(BlockSyncError::BlockNotValid(error)) => { + Err((_, BlockSyncError::BlockNotValid(error))) => { error!(%addr, %role, %block_hash, ?error, "Block not valid.") } - Err(BlockSyncError::SoftForkBlockNotValid(error)) => { + Err((_, BlockSyncError::SoftForkBlockNotValid(error))) => { error!(%addr, %role, %block_hash, ?error, "Soft-fork block not valid.") } - Err(BlockSyncError::SoftForkBlockSmallViewChangeIndex { - peer_view_change_index, - block_view_change_index, - }) => { + Err(( + _, + BlockSyncError::SoftForkBlockSmallViewChangeIndex { + peer_view_change_index, + block_view_change_index, + }, + )) => { debug!( %addr, %role, peer_latest_block_hash=?sumeragi.wsv.latest_block_hash(), @@ -525,10 +471,13 @@ fn handle_message( "Soft fork doesn't occurred: block has the same or smaller view change index" ); } - Err(BlockSyncError::BlockNotProperHeight { - peer_height, - block_height, - }) => { + Err(( + _, + BlockSyncError::BlockNotProperHeight { + peer_height, + block_height, + }, + )) => { warn!(%addr, %role, %block_hash, %block_height, %peer_height, "Other peer send irrelevant or outdated block to the peer (it's neither `peer_height` nor `peer_height + 1`).") } } @@ -542,21 +491,19 @@ fn handle_message( || role == Role::Leader && !is_consensus_required { error!(%addr, %role, "Received BlockCommitted message, but shouldn't"); - } else if let Some(mut voted_block) = voting_block.take() { - let voting_block_hash = voted_block.block.partial_hash(); - - if hash.internal == voting_block_hash.into() { - // The manipulation of the topology relies upon all peers seeing the same signature set. - // Therefore we must clear the signatures and accept what the proxy tail giveth. - voted_block.block.signatures.clear(); - add_signatures::(&mut voted_block, signatures.transmute()); + } else if let Some(voted_block) = voting_block.take() { + let voting_block_hash = voted_block.block.payload().hash(); - match voted_block.block.commit(current_topology) { + if hash == voting_block_hash { + match voted_block + .block + .commit_with_signatures(current_topology, signatures) + { Ok(committed_block) => { sumeragi.commit_block(committed_block, voted_block.new_wsv) } - Err((_, err)) => { - error!(%addr, %role, %hash, ?err, "Block failed to be committed") + Err((_, error)) => { + error!(%addr, %role, %hash, ?error, "Block failed to be committed") } }; } else { @@ -576,12 +523,12 @@ fn handle_message( .is_consensus_required() .expect("Peer has `ValidatingPeer` role, which mean that current topology require consensus"); - if let Some(v_block) = vote_for_block(sumeragi, block_created) { - let block_hash = v_block.block.partial_hash(); + if let Some(v_block) = vote_for_block(sumeragi, ¤t_topology, block_created) { + let block_hash = v_block.block.payload().hash(); let msg = MessagePacket::new( view_change_proof_chain.clone(), - Some(BlockSigned::from(&v_block.block).into()), + Some(BlockSigned::from(v_block.block.clone()).into()), ); sumeragi.broadcast_packet_to(msg, [current_topology.proxy_tail()]); @@ -595,13 +542,13 @@ fn handle_message( "Peer has `ObservingPeer` role, which mean that current topology require consensus", ); - if let Some(v_block) = vote_for_block(sumeragi, block_created) { + if let Some(v_block) = vote_for_block(sumeragi, ¤t_topology, block_created) { if current_view_change_index >= 1 { - let block_hash = v_block.block.partial_hash(); + let block_hash = v_block.block.payload().hash(); let msg = MessagePacket::new( view_change_proof_chain.clone(), - Some(BlockSigned::from(&v_block.block).into()), + Some(BlockSigned::from(v_block.block.clone()).into()), ); sumeragi.broadcast_packet_to(msg, [current_topology.proxy_tail()]); @@ -613,9 +560,7 @@ fn handle_message( } } (Message::BlockCreated(block_created), Role::ProxyTail) => { - // NOTE: False positive from nursery - #[allow(clippy::iter_with_drain)] - if let Some(mut new_block) = vote_for_block(sumeragi, block_created) { + if let Some(mut new_block) = vote_for_block(sumeragi, current_topology, block_created) { // NOTE: Up until this point it was unknown which block is expected to be received, // therefore all the signatures (of any hash) were collected and will now be pruned add_signatures::(&mut new_block, voting_signatures.drain(..)); @@ -633,7 +578,7 @@ fn handle_message( let valid_signatures = current_topology.filter_signatures_by_roles(roles, &signatures); if let Some(voted_block) = voting_block.as_mut() { - let voting_block_hash = voted_block.block.partial_hash(); + let voting_block_hash = voted_block.block.payload().hash(); if hash == voting_block_hash { add_signatures::(voted_block, valid_signatures); @@ -674,24 +619,28 @@ fn process_message_independent( if cache_full || (deadline_reached && cache_non_empty) { let transactions = sumeragi.transaction_cache.clone(); - info!(txns=%transactions.len(), "Creating block..."); + info!(%addr, txns=%transactions.len(), "Creating block..."); // TODO: properly process triggers! let mut new_wsv = sumeragi.wsv.clone(); let event_recommendations = Vec::new(); - let new_block = BlockBuilder { + let new_block = match BlockBuilder::new( transactions, + sumeragi.current_topology.clone(), event_recommendations, - view_change_index: current_view_change_index, - committed_with_topology: sumeragi.current_topology.clone(), - key_pair: sumeragi.key_pair.clone(), - wsv: &mut new_wsv, - } - .build(); + ) + .chain(current_view_change_index, &mut new_wsv) + .sign(sumeragi.key_pair.clone()) + { + Ok(block) => block, + Err(error) => { + error!(?error, "Failed to sign block"); + return; + } + }; - sumeragi.send_events(&new_block); if let Some(current_topology) = current_topology.is_consensus_required() { - info!(%addr, partial_hash=%new_block.partial_hash(), "Block created"); + info!(%addr, block_payload_hash=%new_block.payload().hash(), "Block created"); *voting_block = Some(VotingBlock::new(new_block.clone(), new_wsv)); let msg = MessagePacket::new( @@ -708,20 +657,13 @@ fn process_message_independent( Ok(committed_block) => { let msg = MessagePacket::new( view_change_proof_chain.clone(), - Some( - BlockCommitted::from( - Into::::into( - committed_block.clone(), - ), - ) - .into(), - ), + Some(BlockCommitted::from(committed_block.clone()).into()), ); sumeragi.broadcast_packet(msg); sumeragi.commit_block(committed_block, new_wsv); } - Err(err) => error!(%addr, role=%Role::Leader, ?err), + Err((_, error)) => error!(%addr, role=%Role::Leader, ?error), } } } @@ -738,12 +680,7 @@ fn process_message_independent( let msg = MessagePacket::new( view_change_proof_chain.clone(), - Some( - BlockCommitted::from(Into::::into( - committed_block.clone(), - )) - .into(), - ), + Some(BlockCommitted::from(committed_block.clone()).into()), ); let current_topology = current_topology @@ -767,7 +704,7 @@ fn process_message_independent( sumeragi.broadcast_packet_to( msg, current_topology - .sorted_peers + .ordered_peers .iter() .take(current_topology.min_votes_for_commit()), ); @@ -775,10 +712,10 @@ fn process_message_independent( } sumeragi.commit_block(committed_block, new_wsv); } - Err((block, err)) => { + Err((block, error)) => { // Restore the current voting block and continue the round *voting_block = Some(VotingBlock::voted_at(block, new_wsv, voted_at)); - trace!(?err, "Not enough signatures, waiting for more..."); + trace!(?error, "Not enough signatures, waiting for more..."); } } } @@ -787,8 +724,7 @@ fn process_message_independent( } } -// NOTE: False positive useless_let_if_seq from nursery -#[allow(clippy::too_many_arguments, clippy::useless_let_if_seq)] +#[allow(clippy::too_many_arguments)] fn reset_state( peer_id: &PeerId, pipeline_time: Duration, @@ -799,7 +735,7 @@ fn reset_state( // below is the state that gets reset. current_topology: &mut Topology, voting_block: &mut Option, - voting_signatures: &mut Vec>, + voting_signatures: &mut Vec>, round_start_time: &mut Instant, last_view_change_time: &mut Instant, view_change_time: &mut Duration, @@ -814,8 +750,9 @@ fn reset_state( } while *old_view_change_index < current_view_change_index { - *old_view_change_index += 1; error!(addr=%peer_id.address, "Rotating the entire topology."); + + *old_view_change_index += 1; current_topology.rotate_all(); was_commit_or_view_change = true; } @@ -923,12 +860,7 @@ pub(crate) fn run( &mut sumeragi.transaction_cache, &mut expired_transactions, ); - sumeragi.send_events( - expired_transactions - .iter() - .map(expired_event) - .collect::>(), - ); + sumeragi.send_events(expired_transactions.iter().map(expired_event)); let current_view_change_index = prune_view_change_proofs_and_calculate_current_index( &sumeragi, @@ -956,7 +888,7 @@ pub(crate) fn run( if let Some(VotingBlock { block, .. }) = voting_block.as_ref() { // NOTE: Suspecting the tail node because it hasn't yet committed a block produced by leader - warn!(peer_public_key=%sumeragi.peer_id.public_key, %role, block=%block.partial_hash(), "Block not committed in due time, requesting view change..."); + warn!(peer_public_key=%sumeragi.peer_id.public_key, %role, block=%block.payload().hash(), "Block not committed in due time, requesting view change..."); } else { // NOTE: Suspecting the leader node because it hasn't produced a block // If the current node has a transaction, the leader should have as well @@ -1008,16 +940,16 @@ pub(crate) fn run( fn add_signatures( block: &mut VotingBlock, - signatures: impl IntoIterator>, + signatures: impl IntoIterator>, ) { for signature in signatures { - if let Err(err) = block.block.add_signature(signature) { + if let Err(error) = block.block.add_signature(signature) { let err_msg = "Signature not valid"; if EXPECT_VALID { - error!(?err, err_msg); + error!(?error, err_msg); } else { - debug!(?err, err_msg); + debug!(?error, err_msg); } } } @@ -1037,54 +969,27 @@ fn expired_event(txn: &AcceptedTransaction) -> Event { fn vote_for_block( sumeragi: &Sumeragi, + topology: &Topology, BlockCreated { block }: BlockCreated, ) -> Option { - let block_hash = block.partial_hash(); + let block_hash = block.payload().hash(); let addr = &sumeragi.peer_id.address; let role = sumeragi.current_topology.role(&sumeragi.peer_id); trace!(%addr, %role, block_hash=%block_hash, "Block received, voting..."); let mut new_wsv = sumeragi.wsv.clone(); - let mut block = { - let span = span!(Level::TRACE, "block revalidation"); - let _enter = span.enter(); - - match block.revalidate(&mut new_wsv) { - Ok(()) => block, - Err(err) => { - warn!(%addr, %role, ?err); - return None; - } + let block = match ValidBlock::validate(block, topology, &mut new_wsv) { + Ok(block) => block, + Err((_, error)) => { + warn!(%addr, %role, ?error, "Block validation failed"); + return None; } }; - if sumeragi - .current_topology - .filter_signatures_by_roles(&[Role::Leader], block.retain_verified_signatures()) - .is_empty() - { - error!( - %addr, %role, leader=?sumeragi.current_topology.is_non_empty().map(|topology| &topology.leader().address), hash=%block.partial_hash(), - "The block is rejected as it is not signed by the leader." - ); - - return None; - } - - if block.header.committed_with_topology != sumeragi.current_topology.sorted_peers { - error!( - %addr, %role, block_topology=?block.header.committed_with_topology, my_topology=?sumeragi.current_topology, hash=%block.partial_hash(), - "The block is rejected as because the topology field is incorrect." - ); - - return None; - } - let signed_block = block .sign(sumeragi.key_pair.clone()) .expect("Block signing failed"); - sumeragi.send_events(&signed_block); Some(VotingBlock::new(signed_block, new_wsv)) } @@ -1125,7 +1030,7 @@ trait ApplyBlockStrategy { fn before_update_hook(sumeragi: &mut Sumeragi); /// Operation to invoke in kura to store block. - fn kura_store_block(kura: &Kura, block: VersionedCommittedBlock); + fn kura_store_block(kura: &Kura, block: CommittedBlock); } /// Commit new block strategy. Used during normal consensus rounds. @@ -1142,7 +1047,7 @@ impl ApplyBlockStrategy for NewBlockStrategy { } #[inline] - fn kura_store_block(kura: &Kura, block: VersionedCommittedBlock) { + fn kura_store_block(kura: &Kura, block: CommittedBlock) { kura.store_block(block) } } @@ -1159,20 +1064,20 @@ impl ApplyBlockStrategy for ReplaceTopBlockStrategy { } #[inline] - fn kura_store_block(kura: &Kura, block: VersionedCommittedBlock) { + fn kura_store_block(kura: &Kura, block: CommittedBlock) { kura.replace_top_block(block) } } enum BlockSyncOk { - CommitBlock(VersionedCommittedBlock, WorldStateView), - ReplaceTopBlock(VersionedCommittedBlock, WorldStateView), + CommitBlock(CommittedBlock, WorldStateView), + ReplaceTopBlock(CommittedBlock, WorldStateView), } #[derive(Debug)] enum BlockSyncError { - BlockNotValid(BlockRevalidationError), - SoftForkBlockNotValid(BlockRevalidationError), + BlockNotValid(BlockValidationError), + SoftForkBlockNotValid(BlockValidationError), SoftForkBlockSmallViewChangeIndex { peer_view_change_index: u64, block_view_change_index: u64, @@ -1184,64 +1089,95 @@ enum BlockSyncError { } fn handle_block_sync( - block: VersionedCommittedBlock, + block: VersionedSignedBlock, wsv: &WorldStateView, finalized_wsv: &WorldStateView, -) -> Result { - let block_height = block.as_v1().header.height; +) -> Result { + let block_height = block.payload().header.height; let wsv_height = wsv.height(); if wsv_height + 1 == block_height { // Normal branch for adding new block on top of current let mut new_wsv = wsv.clone(); - block - .revalidate(&mut new_wsv) - .map(|_| BlockSyncOk::CommitBlock(block, new_wsv)) - .map_err(BlockSyncError::BlockNotValid) + let topology = { + let last_committed_block = new_wsv + .latest_block_ref() + .expect("Not in genesis round so must have at least genesis block"); + let new_peers = new_wsv.peers_ids().iter().cloned().collect(); + let view_change_index = block.payload().header().view_change_index; + Topology::recreate_topology(&last_committed_block, view_change_index, new_peers) + }; + ValidBlock::validate(block, &topology, &mut new_wsv) + .and_then(|block| { + block + .commit(&topology) + .map_err(|(block, err)| (block.into(), err)) + }) + .map(|block| BlockSyncOk::CommitBlock(block, new_wsv)) + .map_err(|(block, error)| (block, BlockSyncError::BlockNotValid(error))) } else if wsv_height == block_height && block_height > 1 { // Soft-fork on genesis block isn't possible // Soft fork branch for replacing current block with valid one let mut new_wsv = finalized_wsv.clone(); - block - .revalidate(&mut new_wsv) - .map_err(BlockSyncError::SoftForkBlockNotValid) - .and_then(|_| { + let topology = { + let last_committed_block = new_wsv + .latest_block_ref() + .expect("Not in genesis round so must have at least genesis block"); + let new_peers = new_wsv.peers_ids().iter().cloned().collect(); + let view_change_index = block.payload().header().view_change_index; + Topology::recreate_topology(&last_committed_block, view_change_index, new_peers) + }; + ValidBlock::validate(block, &topology, &mut new_wsv) + .and_then(|block| { + block + .commit(&topology) + .map_err(|(block, err)| (block.into(), err)) + }) + .map_err(|(block, error)| (block, BlockSyncError::SoftForkBlockNotValid(error))) + .and_then(|block| { let peer_view_change_index = wsv.latest_block_view_change_index(); - let block_view_change_index = block.as_v1().header.view_change_index; + let block_view_change_index = block.payload().header.view_change_index; if peer_view_change_index < block_view_change_index { Ok(BlockSyncOk::ReplaceTopBlock(block, new_wsv)) } else { - Err(BlockSyncError::SoftForkBlockSmallViewChangeIndex { - peer_view_change_index, - block_view_change_index, - }) + Err(( + block.into(), + BlockSyncError::SoftForkBlockSmallViewChangeIndex { + peer_view_change_index, + block_view_change_index, + }, + )) } }) } else { // Error branch other peer send irrelevant block - Err(BlockSyncError::BlockNotProperHeight { - peer_height: wsv_height, - block_height, - }) + Err(( + block, + BlockSyncError::BlockNotProperHeight { + peer_height: wsv_height, + block_height, + }, + )) } } #[cfg(test)] mod tests { - use std::str::FromStr; - use super::*; use crate::smartcontracts::Registrable; - fn create_data_for_test() -> (WorldStateView, Arc, VersionedCommittedBlock) { + fn create_data_for_test( + topology: &Topology, + leader_key_pair: KeyPair, + ) -> (WorldStateView, Arc, VersionedSignedBlock) { // Predefined world state - let alice_id = AccountId::from_str("alice@wonderland").expect("Valid"); + let alice_id: AccountId = "alice@wonderland".parse().expect("Valid"); let alice_keys = KeyPair::generate().expect("Valid"); let account = Account::new(alice_id.clone(), [alice_keys.public_key().clone()]).build(&alice_id); - let domain_id = DomainId::from_str("wonderland").expect("Valid"); + let domain_id = "wonderland".parse().expect("Valid"); let mut domain = Domain::new(domain_id).build(&alice_id); assert!(domain.add_account(account).is_none()); - let world = World::with([domain], Vec::new()); + let world = World::with([domain], topology.ordered_peers.clone()); let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(world, Arc::clone(&kura)); @@ -1254,115 +1190,128 @@ mod tests { .with_instructions([fail_box]) .sign(alice_keys.clone()) .expect("Valid"); - let tx: AcceptedTransaction = - AcceptedTransaction::accept(tx, &wsv.transaction_validator().transaction_limits) - .map(Into::into) - .expect("Valid"); + let tx = AcceptedTransaction::accept(tx, &wsv.transaction_validator().transaction_limits) + .expect("Valid"); // Creating a block of two identical transactions and validating it - let transactions = vec![tx.clone(), tx]; - let block = BlockBuilder { - transactions, - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: Topology::new(Vec::new()), - key_pair: alice_keys.clone(), - wsv: &mut wsv.clone(), - } - .build(); + let block = BlockBuilder::new(vec![tx.clone(), tx], topology.clone(), Vec::new()) + .chain_first(&mut wsv) + .sign(leader_key_pair.clone()) + .expect("Block is valid"); - let genesis_block = VersionedCommittedBlock::from(block.commit_unchecked()); - - kura.store_block(genesis_block.clone()); - wsv.apply(&genesis_block).expect("Failed to apply block"); - - // Create block for testing purposes - // Creating an instruction - let asset_definition_id = AssetDefinitionId::from_str("xor#wonderland").expect("Valid"); - let create_asset_definition: InstructionBox = - RegisterBox::new(AssetDefinition::quantity(asset_definition_id)).into(); + let genesis = block.commit(topology).expect("Block is valid"); + wsv.apply(&genesis).expect("Failed to apply block"); + kura.store_block(genesis); // Making two transactions that have the same instruction - let tx = TransactionBuilder::new(alice_id) - .with_instructions([create_asset_definition]) + let create_asset_definition1 = RegisterBox::new(AssetDefinition::quantity( + "xor1#wonderland".parse().expect("Valid"), + )); + let create_asset_definition2 = RegisterBox::new(AssetDefinition::quantity( + "xor2#wonderland".parse().expect("Valid"), + )); + + let tx1 = TransactionBuilder::new(alice_id.clone()) + .with_instructions([create_asset_definition1]) .sign(alice_keys.clone()) .expect("Valid"); - let tx: AcceptedTransaction = - AcceptedTransaction::accept(tx, &wsv.transaction_validator().transaction_limits) - .map(Into::into) - .expect("Valid"); + let tx1 = AcceptedTransaction::accept(tx1, &wsv.transaction_validator().transaction_limits) + .map(Into::into) + .expect("Valid"); + let tx2 = TransactionBuilder::new(alice_id) + .with_instructions([create_asset_definition2]) + .sign(alice_keys) + .expect("Valid"); + let tx2 = AcceptedTransaction::accept(tx2, &wsv.transaction_validator().transaction_limits) + .map(Into::into) + .expect("Valid"); // Creating a block of two identical transactions and validating it - let transactions = vec![tx.clone(), tx]; - let block = BlockBuilder { - transactions, - event_recommendations: Vec::new(), - view_change_index: 0, - committed_with_topology: Topology::new(Vec::new()), - key_pair: alice_keys, - wsv: &mut wsv.clone(), - } - .build(); - - let block = VersionedCommittedBlock::from(block.commit_unchecked()); + let block = BlockBuilder::new(vec![tx1, tx2], topology.clone(), Vec::new()) + .chain(0, &mut wsv.clone()) + .sign(leader_key_pair) + .expect("Block is valid"); - (wsv, kura, block) + (wsv, kura, block.into()) } #[test] #[allow(clippy::redundant_clone)] fn block_sync_invalid_block() { - let (finalized_wsv, _, mut block) = create_data_for_test(); + let leader_key_pair = KeyPair::generate().unwrap(); + let topology = Topology::new(vec![PeerId::new( + &"127.0.0.1:8080".parse().unwrap(), + leader_key_pair.public_key(), + )]); + let (finalized_wsv, _, mut block) = create_data_for_test(&topology, leader_key_pair); let wsv = finalized_wsv.clone(); // Malform block to make it invalid - block.as_mut_v1().transactions.clear(); + block.payload_mut().header.commit_topology.clear(); let result = handle_block_sync(block, &wsv, &finalized_wsv); - assert!(matches!(result, Err(BlockSyncError::BlockNotValid(_)))) + assert!(matches!(result, Err((_, BlockSyncError::BlockNotValid(_))))) } #[test] fn block_sync_invalid_soft_fork_block() { - let (finalized_wsv, kura, mut block) = create_data_for_test(); + let leader_key_pair = KeyPair::generate().unwrap(); + let topology = Topology::new(vec![PeerId::new( + &"127.0.0.1:8080".parse().unwrap(), + leader_key_pair.public_key(), + )]); + let (finalized_wsv, kura, mut block) = create_data_for_test(&topology, leader_key_pair); let mut wsv = finalized_wsv.clone(); - kura.store_block(block.clone()); - wsv.apply(&block).expect("Failed to apply block"); + let validated_block = ValidBlock::validate(block.clone(), &topology, &mut wsv).unwrap(); + let committed_block = validated_block.commit(&topology).expect("Block is valid"); + wsv.apply_without_execution(&committed_block) + .expect("Failed to apply block"); + kura.store_block(committed_block); // Malform block to make it invalid - block.as_mut_v1().transactions.clear(); + block.payload_mut().header.commit_topology.clear(); let result = handle_block_sync(block, &wsv, &finalized_wsv); assert!(matches!( result, - Err(BlockSyncError::SoftForkBlockNotValid(_)) + Err((_, BlockSyncError::SoftForkBlockNotValid(_))) )) } #[test] #[allow(clippy::redundant_clone)] fn block_sync_not_proper_height() { - let (finalized_wsv, _, mut block) = create_data_for_test(); + let topology = Topology::new(Vec::new()); + let leader_key_pair = KeyPair::generate().unwrap(); + let (finalized_wsv, _, mut block) = create_data_for_test(&topology, leader_key_pair); let wsv = finalized_wsv.clone(); // Change block height - block.as_mut_v1().header.height = 42; + block.payload_mut().header.height = 42; let result = handle_block_sync(block, &wsv, &finalized_wsv); assert!(matches!( result, - Err(BlockSyncError::BlockNotProperHeight { - peer_height: 1, - block_height: 42 - }) + Err(( + _, + BlockSyncError::BlockNotProperHeight { + peer_height: 1, + block_height: 42 + } + )) )) } #[test] #[allow(clippy::redundant_clone)] fn block_sync_commit_block() { - let (finalized_wsv, _, block) = create_data_for_test(); + let leader_key_pair = KeyPair::generate().unwrap(); + let topology = Topology::new(vec![PeerId::new( + &"127.0.0.1:8080".parse().unwrap(), + leader_key_pair.public_key(), + )]); + let (finalized_wsv, _, block) = create_data_for_test(&topology, leader_key_pair); let wsv = finalized_wsv.clone(); let result = handle_block_sync(block, &wsv, &finalized_wsv); assert!(matches!(result, Ok(BlockSyncOk::CommitBlock(_, _)))) @@ -1370,15 +1319,23 @@ mod tests { #[test] fn block_sync_replace_top_block() { - let (finalized_wsv, kura, mut block) = create_data_for_test(); + let leader_key_pair = KeyPair::generate().unwrap(); + let topology = Topology::new(vec![PeerId::new( + &"127.0.0.1:8080".parse().unwrap(), + leader_key_pair.public_key(), + )]); + let (finalized_wsv, kura, mut block) = create_data_for_test(&topology, leader_key_pair); let mut wsv = finalized_wsv.clone(); - kura.store_block(block.clone()); - wsv.apply(&block).expect("Failed to apply block to wsv"); + let validated_block = ValidBlock::validate(block.clone(), &topology, &mut wsv).unwrap(); + let committed_block = validated_block.commit(&topology).expect("Block is valid"); + wsv.apply_without_execution(&committed_block) + .expect("Failed to apply block"); + kura.store_block(committed_block); assert_eq!(wsv.latest_block_view_change_index(), 0); // Increase block view change index - block.as_mut_v1().header.view_change_index = 42; + block.payload_mut().header.view_change_index = 42; let result = handle_block_sync(block, &wsv, &finalized_wsv); assert!(matches!(result, Ok(BlockSyncOk::ReplaceTopBlock(_, _)))) @@ -1386,47 +1343,63 @@ mod tests { #[test] fn block_sync_small_view_change_index() { - let (finalized_wsv, kura, mut block) = create_data_for_test(); + let leader_key_pair = KeyPair::generate().unwrap(); + let topology = Topology::new(vec![PeerId::new( + &"127.0.0.1:8080".parse().unwrap(), + leader_key_pair.public_key(), + )]); + let (finalized_wsv, kura, mut block) = create_data_for_test(&topology, leader_key_pair); let mut wsv = finalized_wsv.clone(); // Increase block view change index - block.as_mut_v1().header.view_change_index = 42; + block.payload_mut().header.view_change_index = 42; - kura.store_block(block.clone()); - wsv.apply(&block).expect("Failed to apply block to wsv"); + let validated_block = ValidBlock::validate(block.clone(), &topology, &mut wsv).unwrap(); + let committed_block = validated_block.commit(&topology).expect("Block is valid"); + wsv.apply_without_execution(&committed_block) + .expect("Failed to apply block"); + kura.store_block(committed_block); assert_eq!(wsv.latest_block_view_change_index(), 42); // Decrease block view change index back - block.as_mut_v1().header.view_change_index = 0; + block.payload_mut().header.view_change_index = 0; let result = handle_block_sync(block, &wsv, &finalized_wsv); assert!(matches!( result, - Err(BlockSyncError::SoftForkBlockSmallViewChangeIndex { - peer_view_change_index: 42, - block_view_change_index: 0 - }) + Err(( + _, + BlockSyncError::SoftForkBlockSmallViewChangeIndex { + peer_view_change_index: 42, + block_view_change_index: 0 + } + )) )) } #[test] #[allow(clippy::redundant_clone)] fn block_sync_genesis_block_do_not_replace() { - let (finalized_wsv, _, mut block) = create_data_for_test(); + let topology = Topology::new(Vec::new()); + let leader_key_pair = KeyPair::generate().unwrap(); + let (finalized_wsv, _, mut block) = create_data_for_test(&topology, leader_key_pair); let wsv = finalized_wsv.clone(); // Change block height and view change index // Soft-fork on genesis block is not possible - block.as_mut_v1().header.height = 1; - block.as_mut_v1().header.view_change_index = 42; + block.payload_mut().header.view_change_index = 42; + block.payload_mut().header.height = 1; let result = handle_block_sync(block, &wsv, &finalized_wsv); assert!(matches!( result, - Err(BlockSyncError::BlockNotProperHeight { - peer_height: 1, - block_height: 1, - }) + Err(( + _, + BlockSyncError::BlockNotProperHeight { + peer_height: 1, + block_height: 1, + } + )) )) } } diff --git a/core/src/sumeragi/message.rs b/core/src/sumeragi/message.rs index abe5e0619b4..65f309be4a1 100644 --- a/core/src/sumeragi/message.rs +++ b/core/src/sumeragi/message.rs @@ -6,42 +6,15 @@ clippy::module_name_repetitions )] -use iroha_crypto::{HashOf, SignatureOf, SignaturesOf}; -use iroha_data_model::block::VersionedCommittedBlock; +use iroha_crypto::{HashOf, SignaturesOf}; +use iroha_data_model::block::{BlockPayload, VersionedSignedBlock}; use iroha_macro::*; -use iroha_version::prelude::*; use parity_scale_codec::{Decode, Encode}; use super::view_change; -use crate::block::PendingBlock; - -declare_versioned_with_scale!(VersionedPacket 1..2, Debug, Clone, iroha_macro::FromVariant); - -impl VersionedPacket { - /// Convert `&`[`Self`] to V1 reference - pub const fn as_v1(&self) -> &MessagePacket { - match self { - Self::V1(v1) => v1, - } - } - - /// Convert `&mut` [`Self`] to V1 mutable reference - pub fn as_mut_v1(&mut self) -> &mut MessagePacket { - match self { - Self::V1(v1) => v1, - } - } - - /// Perform the conversion from [`Self`] to V1 - pub fn into_v1(self) -> MessagePacket { - match self { - Self::V1(v1) => v1, - } - } -} +use crate::block::{CommittedBlock, ValidBlock}; /// Helper structure, wrapping messages and view change proofs. -#[version_with_scale(version = 1, versioned_alias = "VersionedPacket")] #[derive(Debug, Clone, Decode, Encode)] pub struct MessagePacket { /// Proof of view change. As part of this message handling, all @@ -96,19 +69,14 @@ impl From for MessagePacket { #[non_exhaustive] pub struct BlockCreated { /// The corresponding block. - pub block: PendingBlock, + pub block: VersionedSignedBlock, } -impl From for BlockCreated { - fn from(block: PendingBlock) -> Self { - Self { block } - } -} - -impl BlockCreated { - /// Get hash of block. - pub fn hash(&self) -> HashOf { - self.block.partial_hash() +impl From for BlockCreated { + fn from(block: ValidBlock) -> Self { + Self { + block: block.into(), + } } } @@ -117,16 +85,19 @@ impl BlockCreated { #[non_exhaustive] pub struct BlockSigned { /// Hash of the block being signed. - pub hash: HashOf, + pub hash: HashOf, /// Set of signatures. - pub signatures: SignaturesOf, + pub signatures: SignaturesOf, } -impl From<&PendingBlock> for BlockSigned { - fn from(block: &PendingBlock) -> Self { +impl From for BlockSigned { + fn from(block: ValidBlock) -> Self { + let block_hash = block.payload().hash(); + let VersionedSignedBlock::V1(block) = block.into(); + Self { - hash: block.partial_hash(), - signatures: block.signatures.clone(), + hash: block_hash, + signatures: block.signatures, } } } @@ -136,21 +107,19 @@ impl From<&PendingBlock> for BlockSigned { #[non_exhaustive] pub struct BlockCommitted { /// Hash of the block being signed. - pub hash: iroha_data_model::block::PartialBlockHash, + pub hash: HashOf, /// Set of signatures. - pub signatures: SignaturesOf, + pub signatures: SignaturesOf, } -impl From for BlockCommitted { - fn from(block: VersionedCommittedBlock) -> Self { +impl From for BlockCommitted { + fn from(block: CommittedBlock) -> Self { + let block_hash = block.payload().hash(); + let VersionedSignedBlock::V1(block) = block.into(); + Self { - hash: block.partial_hash(), - signatures: block - .signatures() - .cloned() - .collect::>>() - .try_into() - .expect("Can't send a committed block message without signatures."), + hash: block_hash, + signatures: block.signatures, } } } @@ -160,18 +129,11 @@ impl From for BlockCommitted { #[non_exhaustive] pub struct BlockSyncUpdate { /// The corresponding block. - pub block: VersionedCommittedBlock, + pub block: VersionedSignedBlock, } -impl From for BlockSyncUpdate { - fn from(block: VersionedCommittedBlock) -> Self { +impl From for BlockSyncUpdate { + fn from(block: VersionedSignedBlock) -> Self { Self { block } } } - -impl BlockSyncUpdate { - /// Get hash of block. - pub fn hash(&self) -> HashOf { - self.block.hash() - } -} diff --git a/core/src/sumeragi/mod.rs b/core/src/sumeragi/mod.rs index 9e786c0ef1f..b45d2f08c0f 100644 --- a/core/src/sumeragi/mod.rs +++ b/core/src/sumeragi/mod.rs @@ -22,7 +22,7 @@ use iroha_telemetry::metrics::Metrics; use network_topology::{Role, Topology}; use tokio::sync::watch; -use crate::{handler::ThreadHandler, kura::BlockCount}; +use crate::{block::ValidBlock, handler::ThreadHandler, kura::BlockCount}; pub mod main_loop; pub mod message; @@ -33,11 +33,9 @@ use parking_lot::Mutex; use self::{ message::{Message, *}, - view_change::{Proof, ProofChain}, -}; -use crate::{ - block::*, kura::Kura, prelude::*, queue::Queue, EventsSender, IrohaNetwork, NetworkMessage, + view_change::ProofChain, }; +use crate::{kura::Kura, prelude::*, queue::Queue, EventsSender, IrohaNetwork, NetworkMessage}; /* The values in the following struct are not atomics because the code that @@ -135,7 +133,7 @@ impl SumeragiHandle { block_index += 1; let mut block_txs_accepted = 0; let mut block_txs_rejected = 0; - for tx in &block.as_v1().transactions { + for tx in &block.payload().transactions { if tx.error.is_none() { block_txs_accepted += 1; } else { @@ -173,9 +171,12 @@ impl SumeragiHandle { #[allow(clippy::cast_possible_truncation)] if let Some(timestamp) = wsv.genesis_timestamp() { // this will overflow in 584942417years. - self.metrics - .uptime_since_genesis_ms - .set((current_time().as_millis() - timestamp) as u64) + self.metrics.uptime_since_genesis_ms.set( + (current_time() - timestamp) + .as_millis() + .try_into() + .expect("Timestamp should fit into u64"), + ) }; self.metrics.connected_peers.set(online_peers_count); @@ -244,13 +245,28 @@ impl SumeragiHandle { .expect("Sumeragi should be able to load the block that was reported as presented. If not, the block storage was probably disconnected.") }); + let current_topology = match wsv.height() { + 0 => { + assert!(!configuration.trusted_peers.peers.is_empty()); + Topology::new(configuration.trusted_peers.peers.clone()) + } + height => { + let block_ref = kura.get_block_by_height(height).expect("Sumeragi could not load block that was reported as present. Please check that the block storage was not disconnected."); + let mut topology = + Topology::new(block_ref.payload().header.commit_topology.clone()); + topology.rotate_set_a(); + topology + } + }; + let block_iter_except_last = (&mut blocks_iter).take(block_count.saturating_sub(skip_block_count + 1)); for block in block_iter_except_last { - block.revalidate(&mut wsv).expect( - "The block should be valid in init. Blocks loaded from kura assumed to be valid", - ); - wsv.apply_without_execution(block.as_ref()) + let block = ValidBlock::validate(Clone::clone(&block), ¤t_topology, &mut wsv) + .expect("Kura blocks should be valid") + .commit(¤t_topology) + .expect("Kura blocks should be valid"); + wsv.apply_without_execution(&block) .expect("Block application in init should not fail. Blocks loaded from kura assumed to be valid"); } @@ -258,30 +274,17 @@ impl SumeragiHandle { let finalized_wsv = wsv.clone(); if let Some(latest_block) = blocks_iter.next() { - latest_block.revalidate(&mut wsv).expect( - "The block should be valid in init. Blocks loaded from kura assumed to be valid", - ); - wsv.apply_without_execution(latest_block.as_ref()) + let latest_block = + ValidBlock::validate(Clone::clone(&latest_block), ¤t_topology, &mut wsv) + .expect("Kura blocks should be valid") + .commit(¤t_topology) + .expect("Kura blocks should be valid"); + wsv.apply_without_execution(&latest_block) .expect("Block application in init should not fail. Blocks loaded from kura assumed to be valid"); } info!("Sumeragi has finished loading blocks and setting up the WSV"); - let current_topology = match wsv.height() { - 0 => { - assert!(!configuration.trusted_peers.peers.is_empty()); - Topology::new(configuration.trusted_peers.peers.clone()) - } - height => { - let block_ref = kura.get_block_by_height(height).expect("Sumeragi could not load block that was reported as present. Please check that the block storage was not disconnected."); - let mut topology = Topology { - sorted_peers: block_ref.as_v1().header.committed_with_topology.clone(), - }; - topology.rotate_set_a(); - topology - } - }; - let (public_wsv_sender, public_wsv_receiver) = watch::channel(wsv.clone()); let (public_finalized_wsv_sender, public_finalized_wsv_receiver) = watch::channel(finalized_wsv.clone()); @@ -361,14 +364,14 @@ pub struct VotingBlock { /// At what time has this peer voted for this block pub voted_at: Instant, /// Valid Block - pub block: PendingBlock, + pub block: ValidBlock, /// WSV after applying transactions to it pub new_wsv: WorldStateView, } impl VotingBlock { /// Construct new `VotingBlock` with current time. - pub fn new(block: PendingBlock, new_wsv: WorldStateView) -> VotingBlock { + pub fn new(block: ValidBlock, new_wsv: WorldStateView) -> VotingBlock { VotingBlock { block, voted_at: Instant::now(), @@ -377,7 +380,7 @@ impl VotingBlock { } /// Construct new `VotingBlock` with the given time. pub(crate) fn voted_at( - block: PendingBlock, + block: ValidBlock, new_wsv: WorldStateView, voted_at: Instant, ) -> VotingBlock { diff --git a/core/src/sumeragi/network_topology.rs b/core/src/sumeragi/network_topology.rs index cca11ce4dc6..3612e0dd48f 100644 --- a/core/src/sumeragi/network_topology.rs +++ b/core/src/sumeragi/network_topology.rs @@ -9,8 +9,11 @@ use std::collections::HashSet; use derive_more::Display; -use iroha_crypto::{HashOf, PublicKey, SignatureOf, SignaturesOf}; -use iroha_data_model::{block::VersionedCommittedBlock, prelude::PeerId}; +use iroha_crypto::{PublicKey, SignatureOf, SignaturesOf}; +use iroha_data_model::{ + block::{BlockPayload, VersionedSignedBlock}, + prelude::PeerId, +}; use iroha_logger::trace; /// The ordering of the peers which defines their roles in the current round of consensus. @@ -27,7 +30,7 @@ use iroha_logger::trace; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Topology { /// Current order of peers. The roles of peers are defined based on this order. - pub(crate) sorted_peers: Vec, + pub(crate) ordered_peers: Vec, } /// Topology with at least one peer @@ -46,28 +49,28 @@ impl Topology { /// Create a new topology. pub fn new(peers: impl IntoIterator) -> Self { Topology { - sorted_peers: peers.into_iter().collect(), + ordered_peers: peers.into_iter().collect(), } } /// True, if the topology contains at least one peer and thus requires consensus pub fn is_non_empty(&self) -> Option { - (!self.sorted_peers.is_empty()).then_some(NonEmptyTopology { topology: self }) + (!self.ordered_peers.is_empty()).then_some(NonEmptyTopology { topology: self }) } /// Is consensus required, aka are there more than 1 peer. pub fn is_consensus_required(&self) -> Option { - (self.sorted_peers.len() > 1).then_some(ConsensusTopology { topology: self }) + (self.ordered_peers.len() > 1).then_some(ConsensusTopology { topology: self }) } /// How many faulty peers can this topology tolerate. pub fn max_faults(&self) -> usize { - (self.sorted_peers.len().saturating_sub(1)) / 3 + (self.ordered_peers.len().saturating_sub(1)) / 3 } /// The required amount of votes to commit a block with this topology. pub fn min_votes_for_commit(&self) -> usize { - let len = self.sorted_peers.len(); + let len = self.ordered_peers.len(); if len > 3 { self.max_faults() * 2 + 1 } else { @@ -75,13 +78,13 @@ impl Topology { } } - /// Index of leader among `sorted_peers` + /// Index of leader among `ordered_peers` #[allow(clippy::unused_self)] // In order to be consistent with `proxy_tail_index` method fn leader_index(&self) -> usize { 0 } - /// Index of leader among `sorted_peers` + /// Index of leader among `ordered_peers` fn proxy_tail_index(&self) -> usize { // NOTE: proxy tail is the last element from the set A so that's why it's `min_votes_for_commit - 1` self.min_votes_for_commit() - 1 @@ -94,7 +97,7 @@ impl Topology { roles: &[Role], signatures: I, ) -> Vec> { - let mut public_keys: HashSet<&PublicKey> = HashSet::with_capacity(self.sorted_peers.len()); + let mut public_keys: HashSet<&PublicKey> = HashSet::with_capacity(self.ordered_peers.len()); for role in roles { match (role, self.is_non_empty(), self.is_consensus_required()) { (Role::Leader, Some(topology), _) => { @@ -125,7 +128,7 @@ impl Topology { /// What role does this peer have in the topology. pub fn role(&self, peer_id: &PeerId) -> Role { - match self.sorted_peers.iter().position(|p| p == peer_id) { + match self.ordered_peers.iter().position(|p| p == peer_id) { Some(index) if index == self.leader_index() => Role::Leader, Some(index) if index < self.proxy_tail_index() => Role::ValidatingPeer, Some(index) if index == self.proxy_tail_index() => Role::ProxyTail, @@ -139,8 +142,8 @@ impl Topology { /// Add or remove peers from the topology. pub fn update_peer_list(&mut self, mut new_peers: HashSet) { - self.sorted_peers.retain(|peer| new_peers.remove(peer)); - self.sorted_peers.extend(new_peers); + self.ordered_peers.retain(|peer| new_peers.remove(peer)); + self.ordered_peers.extend(new_peers); } /// Rotate peers after each failed attempt to create a block. @@ -149,10 +152,25 @@ impl Topology { } /// Rotate peers n times where n is a number of failed attempt to create a block. - pub fn rotate_all_n(&mut self, n: usize) { - let len = self.sorted_peers.len(); - if let Some(rem) = n.checked_rem(len) { - self.sorted_peers.rotate_left(rem); + pub fn rotate_all_n(&mut self, n: u64) { + let len = self + .ordered_peers + .len() + .try_into() + .expect("`usize` should fit into `u64`"); + if let Some(mut rem) = n.checked_rem(len) { + // In case where `n` is larger than `usize` could fit + let usize_max = usize::MAX + .try_into() + .expect("`usize` should fit into `u64`"); + while rem > usize_max { + rem -= usize_max; + self.ordered_peers.rotate_left(usize::MAX); + } + let rem = rem + .try_into() + .expect("`rem` is smaller or equal then `usize::MAX`"); + self.ordered_peers.rotate_left(rem); } } @@ -160,13 +178,13 @@ impl Topology { pub fn rotate_set_a(&mut self) { let rotate_at = self.min_votes_for_commit(); if rotate_at > 0 { - self.sorted_peers[..rotate_at].rotate_left(1); + self.ordered_peers[..rotate_at].rotate_left(1); } } /// Pull peers up in the topology to the top of the a set while preserving local order. pub fn lift_up_peers(&mut self, to_lift_up: &[PublicKey]) { - self.sorted_peers + self.ordered_peers .sort_by_cached_key(|peer| !to_lift_up.contains(&peer.public_key)); } @@ -179,13 +197,14 @@ impl Topology { /// Recreate topology for given block and view change index pub fn recreate_topology( - block: &VersionedCommittedBlock, - view_change_index: usize, + block: &VersionedSignedBlock, + view_change_index: u64, new_peers: HashSet, ) -> Self { - let mut topology = Topology::new(block.as_v1().header().committed_with_topology.clone()); + let mut topology = Topology::new(block.payload().header().commit_topology.clone()); let block_signees = block .signatures() + .into_iter() .map(|s| s.public_key()) .cloned() .collect::>(); @@ -207,17 +226,14 @@ impl Topology { /// - Not enough signatures /// - Missing proxy tail signature /// - Missing leader signature - pub fn verify_signatures( + pub fn verify_signatures( &self, - signatures: &mut SignaturesOf, - hash: HashOf, + signatures: &SignaturesOf, ) -> Result<(), SignatureVerificationError> { if self.is_consensus_required().is_none() { return Ok(()); } - let _ = signatures.retain_verified_by_hash(hash); - let votes_count = self .filter_signatures_by_roles( &[ @@ -258,34 +274,34 @@ impl Topology { impl<'topology> NonEmptyTopology<'topology> { /// Get leader's [`PeerId`]. pub fn leader(&self) -> &'topology PeerId { - &self.topology.sorted_peers[self.topology.leader_index()] + &self.topology.ordered_peers[self.topology.leader_index()] } } impl<'topology> ConsensusTopology<'topology> { /// Get proxy tail's peer id. pub fn proxy_tail(&self) -> &'topology PeerId { - &self.topology.sorted_peers[self.topology.proxy_tail_index()] + &self.topology.ordered_peers[self.topology.proxy_tail_index()] } /// Get leader's [`PeerId`] pub fn leader(&self) -> &'topology PeerId { - &self.topology.sorted_peers[self.topology.leader_index()] + &self.topology.ordered_peers[self.topology.leader_index()] } /// Get validating [`PeerId`]s. pub fn validating_peers(&self) -> &'topology [PeerId] { - &self.sorted_peers[self.leader_index() + 1..self.proxy_tail_index()] + &self.ordered_peers[self.leader_index() + 1..self.proxy_tail_index()] } /// Get observing [`PeerId`]s. pub fn observing_peers(&self) -> &'topology [PeerId] { - &self.sorted_peers[self.proxy_tail_index() + 1..] + &self.ordered_peers[self.proxy_tail_index() + 1..] } /// Get voting [`PeerId`]s. pub fn voting_peers(&self) -> &'topology [PeerId] { - &self.sorted_peers[self.leader_index()..=self.proxy_tail_index()] + &self.ordered_peers[self.leader_index()..=self.proxy_tail_index()] } } @@ -314,6 +330,10 @@ pub enum SignatureVerificationError { /// Minimal required number of signatures min_votes_for_commit: usize, }, + /// The block doesn't contain an expected signature. Expected signature can be leader or the current peer + SignatureMissing, + /// Found signature that does not correspond to block payload + UnknownSignature, /// The block doesn't have proxy tail signature ProxyTailMissing, /// The block doesn't have leader signature @@ -322,9 +342,10 @@ pub enum SignatureVerificationError { #[cfg(test)] mod tests { - use iroha_crypto::{KeyPair, SignaturesOf}; + use iroha_crypto::KeyPair; use super::*; + use crate::block::ValidBlock; macro_rules! peers { ($($id:literal),+$(,)?) => {{ @@ -345,7 +366,7 @@ mod tests { fn extract_ports(topology: &Topology) -> Vec { topology - .sorted_peers + .ordered_peers .iter() .map(|peer| peer.address.port()) .collect() @@ -370,10 +391,10 @@ mod tests { let mut topology = topology(); // Will lift up 1, 2, 4, 6 let to_lift_up = &[ - topology.sorted_peers[1].public_key().clone(), - topology.sorted_peers[2].public_key().clone(), - topology.sorted_peers[4].public_key().clone(), - topology.sorted_peers[6].public_key().clone(), + topology.ordered_peers[1].public_key().clone(), + topology.ordered_peers[2].public_key().clone(), + topology.ordered_peers[4].public_key().clone(), + topology.ordered_peers[6].public_key().clone(), ]; topology.lift_up_peers(to_lift_up); assert_eq!(extract_ports(&topology), vec![1, 2, 4, 6, 0, 3, 5]) @@ -385,9 +406,9 @@ mod tests { // New peers will be 0, 2, 5, 7 let new_peers = { let mut peers = HashSet::from([ - topology.sorted_peers[0].clone(), - topology.sorted_peers[5].clone(), - topology.sorted_peers[2].clone(), + topology.ordered_peers[0].clone(), + topology.ordered_peers[5].clone(), + topology.ordered_peers[2].clone(), ]); peers.extend(peers![7]); peers @@ -902,17 +923,15 @@ mod tests { let peers = peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; let topology = Topology::new(peers); - let dummy = "value to sign"; - let mut signatures = key_pairs + let dummy = ValidBlock::new_dummy(); + let signatures = key_pairs .iter() - .map(|key_pair| SignatureOf::new(key_pair.clone(), &dummy).expect("Failed to sign")) - .collect::, _>>() - .expect("Failed to create `SignaturesOf`"); + .map(|key_pair| { + SignatureOf::new(key_pair.clone(), dummy.payload()).expect("Failed to sign") + }) + .collect(); - assert_eq!( - topology.verify_signatures(&mut signatures, HashOf::new(&dummy)), - Ok(()) - ); + assert_eq!(topology.verify_signatures(&signatures), Ok(())); } #[test] @@ -925,17 +944,16 @@ mod tests { let peers = peers![0,: key_pairs_iter]; let topology = Topology::new(peers); - let dummy = "value to sign"; - let mut signatures = key_pairs + let dummy = ValidBlock::new_dummy(); + let signatures = key_pairs .iter() .enumerate() .map(|(_, key_pair)| { - SignatureOf::new(key_pair.clone(), &dummy).expect("Failed to sign") + SignatureOf::new(key_pair.clone(), dummy.payload()).expect("Failed to sign") }) - .collect::, _>>() - .expect("Failed to create `SignaturesOf`"); + .collect(); - let result = topology.verify_signatures(&mut signatures, HashOf::new(&dummy)); + let result = topology.verify_signatures(&signatures); assert_eq!(result, Ok(())) } @@ -950,12 +968,12 @@ mod tests { let peers = peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; let topology = Topology::new(peers); - let dummy = "value to sign"; - let mut signatures = SignatureOf::new(key_pairs[0].clone(), &dummy) + let dummy = ValidBlock::new_dummy(); + let signatures = SignatureOf::new(key_pairs[0].clone(), dummy.payload()) .expect("Failed to sign") .into(); - let result = topology.verify_signatures(&mut signatures, HashOf::new(&dummy)); + let result = topology.verify_signatures(&signatures); assert_eq!( result, Err(SignatureVerificationError::NotEnoughSignatures { @@ -976,16 +994,15 @@ mod tests { let peers = peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; let topology = Topology::new(peers); - let dummy = "value to sign"; - let mut signatures = key_pairs + let dummy = ValidBlock::new_dummy(); + let signatures = key_pairs .iter() .enumerate() .filter(|(i, _)| *i != 0) // Skip leader - .map(|(_, key_pair)| SignatureOf::new(key_pair.clone(), &dummy).expect("Failed to sign")) - .collect::, _>>() - .expect("Failed to create `SignaturesOf`"); + .map(|(_, key_pair)| SignatureOf::new(key_pair.clone(), dummy.payload()).expect("Failed to sign")) + .collect(); - let result = topology.verify_signatures(&mut signatures, HashOf::new(&dummy)); + let result = topology.verify_signatures(&signatures); assert_eq!(result, Err(SignatureVerificationError::LeaderMissing)) } @@ -1000,16 +1017,15 @@ mod tests { let peers = peers![0, 1, 2, 3, 4, 5, 6: key_pairs_iter]; let topology = Topology::new(peers); - let dummy = "value to sign"; - let mut signatures = key_pairs + let dummy = ValidBlock::new_dummy(); + let signatures = key_pairs .iter() .enumerate() .filter(|(i, _)| *i != 4) // Skip proxy tail - .map(|(_, key_pair)| SignatureOf::new(key_pair.clone(), &dummy).expect("Failed to sign")) - .collect::, _>>() - .expect("Failed to create `SignaturesOf`"); + .map(|(_, key_pair)| SignatureOf::new(key_pair.clone(), dummy.payload()).expect("Failed to sign")) + .collect(); - let result = topology.verify_signatures(&mut signatures, HashOf::new(&dummy)); + let result = topology.verify_signatures(&signatures); assert_eq!(result, Err(SignatureVerificationError::ProxyTailMissing)) } } diff --git a/core/src/sumeragi/view_change.rs b/core/src/sumeragi/view_change.rs index 0f593aba4b8..d9560ffe8e2 100644 --- a/core/src/sumeragi/view_change.rs +++ b/core/src/sumeragi/view_change.rs @@ -10,8 +10,8 @@ use std::collections::HashSet; use derive_more::{Deref, DerefMut}; use eyre::Result; -use iroha_crypto::{Hash, HashOf, KeyPair, PublicKey, Signature}; -use iroha_data_model::{block::VersionedCommittedBlock, prelude::PeerId}; +use iroha_crypto::{HashOf, KeyPair, PublicKey, SignatureOf, SignaturesOf}; +use iroha_data_model::{block::VersionedSignedBlock, prelude::PeerId}; use parity_scale_codec::{Decode, Encode}; use thiserror::Error; @@ -25,64 +25,74 @@ pub enum Error { ViewChangeNotFound, } -/// The proof of a view change. It needs to be signed by f+1 peers for proof to be valid and view change to happen. #[derive(Debug, Clone, Decode, Encode)] -pub struct Proof { +struct ProofPayload { /// Hash of the latest committed block. - pub latest_block_hash: Option>, + latest_block_hash: Option>, /// Within a round, what is the index of the view change this proof is trying to prove. - pub view_change_index: u64, + view_change_index: u64, +} + +/// The proof of a view change. It needs to be signed by f+1 peers for proof to be valid and view change to happen. +#[derive(Debug, Clone, Decode, Encode)] +pub struct SignedProof { + signatures: SignaturesOf, /// Collection of signatures from the different peers. - pub signatures: Vec, + payload: ProofPayload, } -impl Proof { - /// Produce a signature payload in the form of a [`Hash`] - pub fn signature_payload(&self) -> Hash { - let mut buf = [0_u8; Hash::LENGTH + std::mem::size_of::()]; - if let Some(hash) = self.latest_block_hash { - buf[..Hash::LENGTH].copy_from_slice(hash.as_ref()); - } - buf[Hash::LENGTH..].copy_from_slice(&self.view_change_index.to_le_bytes()); - // Now we hash the buffer to produce a payload that is completely - // different between view change proofs in the same sumeragi round. - Hash::new(buf) +/// Builder for proofs +#[repr(transparent)] +pub struct ProofBuilder(SignedProof); + +impl ProofBuilder { + /// Constructor from index. + pub fn new( + latest_block_hash: Option>, + view_change_index: u64, + ) -> Self { + let proof = SignedProof { + payload: ProofPayload { + latest_block_hash, + view_change_index, + }, + signatures: [].into_iter().collect(), + }; + + Self(proof) } /// Sign this message with the peer's public and private key. - /// This way peers vote for changing the view (changing the roles of peers). /// /// # Errors /// Can fail during creation of signature - pub fn sign(&mut self, key_pair: KeyPair) -> Result<()> { - let signature = Signature::new(key_pair, self.signature_payload().as_ref())?; - self.signatures.push(signature); - Ok(()) + pub fn sign(mut self, key_pair: KeyPair) -> Result { + let signature = SignatureOf::new(key_pair, &self.0.payload)?; + self.0.signatures.insert(signature); + Ok(self.0) } +} +impl SignedProof { /// Verify the signatures of `other` and add them to this proof. - pub fn merge_signatures(&mut self, other: Vec) { - let signature_payload = self.signature_payload(); + fn merge_signatures(&mut self, other: SignaturesOf) { for signature in other { - if signature.verify(signature_payload.as_ref()).is_ok() - && !self.signatures.contains(&signature) - { - self.signatures.push(signature); + if signature.verify(&self.payload).is_ok() { + self.signatures.insert(signature); } } } /// Verify if the proof is valid, given the peers in `topology`. - pub fn verify(&self, peers: &[PeerId], max_faults: usize) -> bool { + fn verify(&self, peers: &[PeerId], max_faults: usize) -> bool { let peer_public_keys: HashSet<&PublicKey> = peers.iter().map(|peer_id| &peer_id.public_key).collect(); - let signature_payload = self.signature_payload(); let valid_count = self .signatures .iter() .filter(|signature| { - signature.verify(signature_payload.as_ref()).is_ok() + signature.verify(&self.payload).is_ok() && peer_public_keys.contains(signature.public_key()) }) .count(); @@ -97,7 +107,7 @@ impl Proof { /// Structure representing sequence of view change proofs. #[derive(Debug, Clone, Encode, Decode, Deref, DerefMut, Default)] -pub struct ProofChain(Vec); +pub struct ProofChain(Vec); impl ProofChain { /// Verify the view change proof chain. @@ -105,25 +115,26 @@ impl ProofChain { &self, peers: &[PeerId], max_faults: usize, - latest_block: Option>, + latest_block_hash: Option>, ) -> usize { self.iter() .enumerate() .take_while(|(i, proof)| { - proof.latest_block_hash == latest_block - && proof.view_change_index == (*i as u64) + proof.payload.latest_block_hash == latest_block_hash + && proof.payload.view_change_index == (*i as u64) && proof.verify(peers, max_faults) }) .count() } /// Remove invalid proofs from the chain. - pub fn prune(&mut self, latest_block: Option>) { + pub fn prune(&mut self, latest_block_hash: Option>) { let valid_count = self .iter() .enumerate() .take_while(|(i, proof)| { - proof.latest_block_hash == latest_block && proof.view_change_index == (*i as u64) + proof.payload.latest_block_hash == latest_block_hash + && proof.payload.view_change_index == (*i as u64) }) .count(); self.truncate(valid_count); @@ -139,14 +150,15 @@ impl ProofChain { &mut self, peers: &[PeerId], max_faults: usize, - latest_block: Option>, - new_proof: Proof, + latest_block_hash: Option>, + new_proof: SignedProof, ) -> Result<(), Error> { - if new_proof.latest_block_hash != latest_block { + if new_proof.payload.latest_block_hash != latest_block_hash { return Err(Error::BlockHashMismatch); } - let next_unfinished_view_change = self.verify_with_state(peers, max_faults, latest_block); - if new_proof.view_change_index != (next_unfinished_view_change as u64) { + let next_unfinished_view_change = + self.verify_with_state(peers, max_faults, latest_block_hash); + if new_proof.payload.view_change_index != (next_unfinished_view_change as u64) { return Err(Error::ViewChangeNotFound); // We only care about the current view change that may or may not happen. } @@ -169,7 +181,7 @@ impl ProofChain { mut other: Self, peers: &[PeerId], max_faults: usize, - latest_block_hash: Option>, + latest_block_hash: Option>, ) -> Result<(), Error> { // Prune to exclude invalid proofs other.prune(latest_block_hash); diff --git a/core/src/tx.rs b/core/src/tx.rs index 2607c715e31..5475849e548 100644 --- a/core/src/tx.rs +++ b/core/src/tx.rs @@ -40,6 +40,8 @@ pub enum AcceptTransactionFail { TransactionLimit(#[source] TransactionLimitError), /// Failure during signature verification SignatureVerification(#[source] SignatureVerificationFail), + /// The genesis account can only sign transactions in the genesis block + UnexpectedGenesisAccountSignature, } fn instruction_size(isi: &InstructionBox) -> usize { @@ -86,6 +88,10 @@ impl AcceptedTransaction { transaction: VersionedSignedTransaction, limits: &TransactionLimits, ) -> Result { + if *iroha_genesis::GENESIS_ACCOUNT_ID == transaction.payload().authority { + return Err(AcceptTransactionFail::UnexpectedGenesisAccountSignature); + } + match &transaction.payload().instructions { Executable::Instructions(instructions) => { let instruction_count: u64 = instructions @@ -204,10 +210,6 @@ impl TransactionValidator { ) -> Result<(), TransactionRejectionReason> { let authority = &tx.payload().authority; - if wsv.height() > 0 && *iroha_genesis::GENESIS_ACCOUNT_ID == *authority { - return Err(TransactionRejectionReason::UnexpectedGenesisAccountSignature); - } - if !wsv .domain(&authority.domain_id) .map_err(|_e| { diff --git a/core/src/wsv.rs b/core/src/wsv.rs index 2a8b458361f..e1e9d1adc48 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -24,7 +24,7 @@ use iroha_config::{ use iroha_crypto::HashOf; use iroha_data_model::{ account::AccountId, - block::{CommittedBlock, VersionedCommittedBlock}, + block::VersionedSignedBlock, events::notification::{TriggerCompletedEvent, TriggerCompletedOutcome}, isi::error::{InstructionExecutionError as Error, MathError}, parameter::Parameter, @@ -42,6 +42,7 @@ use serde::{ }; use crate::{ + block::CommittedBlock, kura::Kura, smartcontracts::{ triggers::{ @@ -273,7 +274,7 @@ pub struct WorldStateView { /// Configuration of World State View. pub config: Configuration, /// Blockchain. - pub block_hashes: Vec>, + pub block_hashes: Vec>, /// Hashes of transactions mapped onto block height where they stored pub transactions: HashMap, u64>, /// Buffer containing events generated during `WorldStateView::apply`. Renewed on every block commit. @@ -612,8 +613,8 @@ impl WorldStateView { deprecated(note = "This function is to be used in testing only. ") )] #[iroha_logger::log(skip_all, fields(block_height))] - pub fn apply(&mut self, block: &VersionedCommittedBlock) -> Result<()> { - self.execute_transactions(block.as_v1())?; + pub fn apply(&mut self, block: &CommittedBlock) -> Result<()> { + self.execute_transactions(block)?; debug!("All block transactions successfully executed"); self.apply_without_execution(block)?; @@ -623,17 +624,17 @@ impl WorldStateView { /// Apply transactions without actually executing them. /// It's assumed that block's transaction was already executed (as part of validation for example). - #[iroha_logger::log(skip_all, fields(block_height))] - pub fn apply_without_execution(&mut self, block: &VersionedCommittedBlock) -> Result<()> { - let hash = block.hash(); - let block = block.as_v1(); - iroha_logger::prelude::Span::current().record("block_height", block.header.height); - trace!("Applying block"); - let time_event = self.create_time_event(block)?; + #[iroha_logger::log(skip_all, fields(block_height = block.payload().header.height))] + pub fn apply_without_execution(&mut self, block: &CommittedBlock) -> Result<()> { + let block_hash = block.hash(); + trace!(%block_hash, "Applying block"); + + let time_event = self.create_time_event(block); self.events_buffer.push(Event::Time(time_event)); - let block_height = block.header().height; + let block_height = block.payload().header.height; block + .payload() .transactions .iter() .map(|tx| &tx.value) @@ -653,7 +654,7 @@ impl WorldStateView { ); } - self.block_hashes.push(hash); + self.block_hashes.push(block_hash); self.apply_parameters(); @@ -691,33 +692,31 @@ impl WorldStateView { /// Get a reference to the latest block. Returns none if genesis is not committed. #[inline] - pub fn latest_block_ref(&self) -> Option> { + pub fn latest_block_ref(&self) -> Option> { self.kura .get_block_by_height(self.block_hashes.len() as u64) } /// Create time event using previous and current blocks - fn create_time_event(&self, block: &CommittedBlock) -> Result { - let prev_interval = self - .latest_block_ref() - .map(|latest_block| { - let header = &latest_block.as_v1().header; - header.timestamp.try_into().map(|since| TimeInterval { - since: Duration::from_millis(since), - length: Duration::from_millis(header.consensus_estimation), - }) - }) - .transpose()?; + fn create_time_event(&self, block: &CommittedBlock) -> TimeEvent { + let prev_interval = self.latest_block_ref().map(|latest_block| { + let header = &latest_block.payload().header; + + TimeInterval { + since: header.timestamp(), + length: header.consensus_estimation(), + } + }); let interval = TimeInterval { - since: Duration::from_millis(block.header.timestamp.try_into()?), - length: Duration::from_millis(block.header.consensus_estimation), + since: block.payload().header.timestamp(), + length: block.payload().header.consensus_estimation(), }; - Ok(TimeEvent { + TimeEvent { prev_interval, interval, - }) + } } /// Execute `block` transactions and store their hashes as well as @@ -727,7 +726,7 @@ impl WorldStateView { /// Fails if transaction instruction execution fails fn execute_transactions(&mut self, block: &CommittedBlock) -> Result<()> { // TODO: Should this block panic instead? - for tx in &block.transactions { + for tx in &block.payload().transactions { if tx.error.is_none() { self.process_executable( tx.payload().instructions(), @@ -791,7 +790,7 @@ impl WorldStateView { } /// Load all blocks in the block chain from disc - pub fn all_blocks(&self) -> impl DoubleEndedIterator> + '_ { + pub fn all_blocks(&self) -> impl DoubleEndedIterator> + '_ { let block_count = self.block_hashes.len() as u64; (1..=block_count).map(|height| { self.kura @@ -803,8 +802,8 @@ impl WorldStateView { /// Return a vector of blockchain blocks after the block with the given `hash` pub fn block_hashes_after_hash( &self, - hash: Option>, - ) -> Vec> { + hash: Option>, + ) -> Vec> { hash.map_or_else( || self.block_hashes.clone(), |block_hash| { @@ -830,7 +829,7 @@ impl WorldStateView { } /// Return an iterator over blockchain block hashes starting with the block of the given `height` - pub fn block_hashes_from_height(&self, height: usize) -> Vec> { + pub fn block_hashes_from_height(&self, height: usize) -> Vec> { self.block_hashes .iter() .skip(height.saturating_sub(1)) @@ -915,14 +914,14 @@ impl WorldStateView { /// Returns [`Some`] milliseconds since the genesis block was /// committed, or [`None`] if it wasn't. #[inline] - pub fn genesis_timestamp(&self) -> Option { + pub fn genesis_timestamp(&self) -> Option { if self.block_hashes.is_empty() { None } else { let opt = self .kura .get_block_by_height(1) - .map(|genesis_block| genesis_block.as_v1().header.timestamp); + .map(|genesis_block| genesis_block.payload().header.timestamp()); if opt.is_none() { error!("Failed to get genesis block from Kura."); @@ -944,7 +943,7 @@ impl WorldStateView { } /// Return the hash of the latest block - pub fn latest_block_hash(&self) -> Option> { + pub fn latest_block_hash(&self) -> Option> { self.block_hashes.iter().nth_back(0).copied() } @@ -952,11 +951,11 @@ impl WorldStateView { pub fn latest_block_view_change_index(&self) -> u64 { self.kura .get_block_by_height(self.height()) - .map_or(0, |block| block.as_v1().header.view_change_index) + .map_or(0, |block| block.payload().header.view_change_index) } /// Return the hash of the block one before the latest block - pub fn previous_block_hash(&self) -> Option> { + pub fn previous_block_hash(&self) -> Option> { self.block_hashes.iter().nth_back(1).copied() } @@ -1163,11 +1162,11 @@ impl WorldStateView { Ok(()) } - /// Find a [`VersionedSignedTransaction`] by hash. + /// Find a [`VersionedSignedBlock`] by hash. pub fn block_with_tx( &self, hash: &HashOf, - ) -> Option> { + ) -> Option> { let height = *self.transactions.get(hash)?; self.kura.get_block_by_height(height) } @@ -1253,21 +1252,25 @@ mod tests { #![allow(clippy::restriction)] use super::*; - use crate::block::PendingBlock; + use crate::{block::ValidBlock, sumeragi::network_topology::Topology}; #[test] fn get_block_hashes_after_hash() { const BLOCK_CNT: usize = 10; - let mut block = PendingBlock::new_dummy().commit_unchecked(); + let topology = Topology::new(Vec::new()); + let block = ValidBlock::new_dummy().commit(&topology).unwrap(); let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(World::default(), kura); let mut block_hashes = vec![]; for i in 1..=BLOCK_CNT { - block.header.height = i as u64; - block.header.previous_block_hash = block_hashes.last().copied(); - let block: VersionedCommittedBlock = block.clone().into(); + let mut block = block.clone(); + + let VersionedSignedBlock::V1(v1_block) = &mut block.0; + v1_block.payload.header.height = i as u64; + v1_block.payload.header.previous_block_hash = block_hashes.last().copied(); + block_hashes.push(block.hash()); wsv.apply(&block).unwrap(); } @@ -1282,13 +1285,17 @@ mod tests { fn get_blocks_from_height() { const BLOCK_CNT: usize = 10; - let mut block = PendingBlock::new_dummy().commit_unchecked(); + let topology = Topology::new(Vec::new()); + let block = ValidBlock::new_dummy().commit(&topology).unwrap(); let kura = Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(World::default(), kura.clone()); for i in 1..=BLOCK_CNT { - block.header.height = i as u64; - let block: VersionedCommittedBlock = block.clone().into(); + let mut block = block.clone(); + + let VersionedSignedBlock::V1(v1_block) = &mut block.0; + v1_block.payload.header.height = i as u64; + wsv.apply(&block).unwrap(); kura.store_block(block); } @@ -1296,7 +1303,7 @@ mod tests { assert_eq!( &wsv.all_blocks() .skip(7) - .map(|block| block.as_v1().header.height) + .map(|block| block.payload().header.height) .collect::>(), &[8, 9, 10] ); diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 83f27f29f8c..217961f466a 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -84,10 +84,9 @@ impl TestGenesis for GenesisNetwork { RawGenesisBlock::from_path(manifest_dir.join("../../configs/peer/genesis.json")) .expect("Failed to deserialize genesis block from file"); - let rose_definition_id = ::Id::from_str("rose#wonderland") - .expect("valid names"); - let alice_id = - ::Id::from_str("alice@wonderland").expect("valid names"); + let rose_definition_id = + AssetDefinitionId::from_str("rose#wonderland").expect("valid names"); + let alice_id = AccountId::from_str("alice@wonderland").expect("valid names"); let mint_rose_permission = PermissionToken::new( "CanMintAssetsWithDefinition".parse().unwrap(), @@ -711,7 +710,7 @@ pub trait TestClient: Sized { /// # Errors /// If predicate is not satisfied, after maximum retries. fn submit_till( - &mut self, + &self, instruction: impl Instruction + Debug + Clone, request: R, f: impl Fn(::Target) -> bool, @@ -726,7 +725,7 @@ pub trait TestClient: Sized { /// # Errors /// If predicate is not satisfied, after maximum retries. fn submit_all_till( - &mut self, + &self, instructions: Vec, request: R, f: impl Fn(::Target) -> bool, @@ -741,7 +740,7 @@ pub trait TestClient: Sized { /// # Errors /// If predicate is not satisfied after maximum retries. fn poll_request( - &mut self, + &self, request: R, f: impl Fn(::Target) -> bool, ) -> eyre::Result<()> @@ -755,7 +754,7 @@ pub trait TestClient: Sized { /// # Errors /// If predicate is not satisfied after maximum retries. fn poll_request_with_period( - &mut self, + &self, request: R, period: Duration, max_attempts: u32, @@ -851,7 +850,7 @@ impl TestClient for Client { } fn submit_till( - &mut self, + &self, instruction: impl Instruction + Debug + Clone, request: R, f: impl Fn(::Target) -> bool, @@ -867,7 +866,7 @@ impl TestClient for Client { } fn submit_all_till( - &mut self, + &self, instructions: Vec, request: R, f: impl Fn(::Target) -> bool, @@ -883,7 +882,7 @@ impl TestClient for Client { } fn poll_request_with_period( - &mut self, + &self, request: R, period: Duration, max_attempts: u32, @@ -906,7 +905,7 @@ impl TestClient for Client { } fn poll_request( - &mut self, + &self, request: R, f: impl Fn(::Target) -> bool, ) -> eyre::Result<()> diff --git a/crypto/src/hash.rs b/crypto/src/hash.rs index dd77afd4229..be6a701015b 100644 --- a/crypto/src/hash.rs +++ b/crypto/src/hash.rs @@ -216,7 +216,7 @@ crate::ffi::ffi_item! { impl Clone for HashOf { fn clone(&self) -> Self { - Self(self.0, PhantomData) + *self } } impl Copy for HashOf {} @@ -230,7 +230,7 @@ impl Eq for HashOf {} impl PartialOrd for HashOf { fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) + Some(self.cmp(other)) } } impl Ord for HashOf { @@ -256,7 +256,7 @@ impl HashOf { /// Don't use this method if not required. #[inline] #[must_use] - pub const fn transmute(self) -> HashOf { + pub(crate) const fn transmute(self) -> HashOf { HashOf(self.0, PhantomData) } diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index 496884bf9b7..4a89c6c9d84 100755 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -23,7 +23,7 @@ use core::{fmt, str::FromStr}; #[cfg(feature = "base64")] pub use base64; -use derive_more::Display; +use derive_more::{DebugCustom, Display}; use error::{Error, NoSuchAlgorithm}; use getset::{CopyGetters, Getters}; pub use hash::*; @@ -308,8 +308,9 @@ impl From for (PublicKey, PrivateKey) { ffi::ffi_item! { /// Public Key used in signatures. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, CopyGetters)] - #[cfg_attr(not(feature="ffi_import"), derive(derive_more::DebugCustom, Hash, DeserializeFromStr, SerializeDisplay, Decode, Encode, IntoSchema))] - #[cfg_attr(not(feature="ffi_import"), debug(fmt = "{{digest: {digest_function}, payload: {payload:X?}}}"))] + #[cfg_attr(not(feature="ffi_import"), derive(DebugCustom, Display, Hash, DeserializeFromStr, SerializeDisplay, Decode, Encode, IntoSchema))] + #[cfg_attr(not(feature="ffi_import"), debug(fmt = "{{digest: {digest_function}, payload: {}}}", "self.normalize()"))] + #[cfg_attr(not(feature="ffi_import"), display(fmt = "{}", "self.normalize()"))] pub struct PublicKey { /// Digest function #[getset(get_copy = "pub")] @@ -362,8 +363,8 @@ impl FromStr for PublicKey { } #[cfg(not(feature = "ffi_import"))] -impl fmt::Display for PublicKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl PublicKey { + fn normalize(&self) -> String { let multihash: &multihash::Multihash = &self .clone() .try_into() @@ -375,7 +376,7 @@ impl fmt::Display for PublicKey { let dig_size = hex::encode(bytes_iter.by_ref().take(1).collect::>()); let key = hex::encode_upper(bytes_iter.by_ref().collect::>()); - write!(f, "{fn_code}{dig_size}{key}") + format!("{fn_code}{dig_size}{key}") } } @@ -391,8 +392,9 @@ impl From for PublicKey { ffi::ffi_item! { /// Private Key used in signatures. #[derive(Clone, PartialEq, Eq, CopyGetters)] - #[cfg_attr(not(feature="ffi_import"), derive(derive_more::DebugCustom, Serialize))] - #[cfg_attr(not(feature="ffi_import"), debug(fmt = "{{digest: {digest_function}, payload: {payload:X?}}}"))] + #[cfg_attr(not(feature="ffi_import"), derive(DebugCustom, Display, Serialize))] + #[cfg_attr(not(feature="ffi_import"), debug(fmt = "{{digest: {digest_function}, payload: {}}}", "hex::encode_upper(payload)"))] + #[cfg_attr(not(feature="ffi_import"), display(fmt = "{}", "hex::encode_upper(payload)"))] pub struct PrivateKey { /// Digest function #[getset(get_copy = "pub")] @@ -403,12 +405,6 @@ ffi::ffi_item! { } } -impl fmt::Display for PrivateKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", hex::encode_upper(&self.payload)) - } -} - #[ffi_impl_opaque] impl PrivateKey { /// Key payload diff --git a/crypto/src/signature.rs b/crypto/src/signature.rs index edaa5249e3c..a3bfaa00a59 100644 --- a/crypto/src/signature.rs +++ b/crypto/src/signature.rs @@ -10,7 +10,7 @@ use derive_more::{Deref, DerefMut}; use iroha_macro::ffi_impl_opaque; use iroha_primitives::const_vec::ConstVec; use iroha_schema::{IntoSchema, TypeId}; -use parity_scale_codec::{Decode, Encode, Input}; +use parity_scale_codec::{Decode, Encode}; #[cfg(not(feature = "ffi_import"))] use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] @@ -103,16 +103,6 @@ impl Signature { Ok(()) } - - /// Get the payload of the public key in this signature. - pub fn key_payload(&self) -> &[u8] { - self.public_key.payload() - } - - /// Get the encrypted payload of this signature. - pub fn signature_payload(&self) -> &[u8] { - self.payload.as_ref() - } } // TODO: Enable in ffi_import @@ -220,38 +210,17 @@ impl SignatureOf { /// # Errors /// Fails if signing fails #[cfg(any(feature = "std", feature = "import_ffi"))] - pub fn from_hash(key_pair: KeyPair, hash: HashOf) -> Result { + fn from_hash(key_pair: KeyPair, hash: HashOf) -> Result { Signature::new(key_pair, hash.as_ref()).map(|signature| Self(signature, PhantomData)) } - /// Transmutes signature to some specific type - pub fn transmute(self) -> SignatureOf { - SignatureOf(self.0, PhantomData) - } - - /// Transmutes signature to some specific type - /// - /// # Warning: - /// - /// This method uses [`core::mem::transmute`] internally - pub const fn transmute_ref(&self) -> &SignatureOf { - #[allow(unsafe_code, trivial_casts)] - // SAFETY: transmuting is safe, because we're casting a - // pointer of type `SignatureOf` into a pointer of type - // `SignatureOf`, where `` and `` type parameters are - // normally related types that have the exact same alignment. - unsafe { - &*((self as *const Self).cast::>()) - } - } - /// Verify signature for this hash /// /// # Errors /// /// Fails if the given hash didn't pass verification #[cfg(any(feature = "std", feature = "import_ffi"))] - pub fn verify_hash(&self, hash: HashOf) -> Result<(), Error> { + fn verify_hash(&self, hash: HashOf) -> Result<(), Error> { self.0.verify(hash.as_ref()) } } @@ -324,7 +293,7 @@ impl Eq for SignatureWrapperOf {} #[cfg(not(feature = "ffi_import"))] impl PartialOrd for SignatureWrapperOf { fn partial_cmp(&self, other: &Self) -> Option { - self.0.public_key().partial_cmp(other.0.public_key()) + Some(self.cmp(other)) } } #[cfg(not(feature = "ffi_import"))] @@ -349,7 +318,7 @@ impl core::hash::Hash for SignatureWrapperOf { /// /// GUARANTEE 1: Each signature corresponds to a different public key #[allow(clippy::derived_hash_with_manual_eq)] -#[derive(Hash, Encode, Serialize, IntoSchema)] +#[derive(Hash, Decode, Encode, Deserialize, Serialize, IntoSchema)] #[serde(transparent)] // Transmute guard #[repr(transparent)] @@ -399,38 +368,6 @@ impl Ord for SignaturesOf { } } -#[cfg(not(feature = "ffi_import"))] -impl<'de, T> Deserialize<'de> for SignaturesOf { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use serde::de::Error as _; - - let signatures = >>::deserialize(deserializer)?; - - if signatures.is_empty() { - return Err(D::Error::custom( - "Could not deserialize SignaturesOf. Input contains 0 signatures", - )); - } - - Ok(Self { signatures }) - } -} -#[cfg(not(feature = "ffi_import"))] -impl Decode for SignaturesOf { - fn decode(input: &mut I) -> Result { - let signatures = >>::decode(input)?; - - if signatures.is_empty() { - return Err("Could not decode SignaturesOf. Input contains 0 signatures".into()); - } - - Ok(Self { signatures }) - } -} - #[cfg(not(feature = "ffi_import"))] impl IntoIterator for SignaturesOf { type Item = SignatureOf; @@ -475,11 +412,9 @@ impl From> for btree_set::BTreeSet> { } #[cfg(not(feature = "ffi_import"))] -impl TryFrom>> for SignaturesOf { - type Error = Error; - - fn try_from(signatures: btree_set::BTreeSet>) -> Result { - signatures.into_iter().collect() +impl From>> for SignaturesOf { + fn from(source: btree_set::BTreeSet>) -> Self { + source.into_iter().collect() } } @@ -493,48 +428,21 @@ impl From> for SignaturesOf { } #[cfg(not(feature = "ffi_import"))] -impl FromIterator> for Result, Error> { - fn from_iter>>(iter: T) -> Self { - let mut iter = iter.into_iter(); - iter.next() - .ok_or(Error::EmptySignatureIter) - .map(move |first_signature| core::iter::once(first_signature).chain(iter)) - .map(|signatures| signatures.map(SignatureWrapperOf).collect()) - .map(|signatures| SignaturesOf { signatures }) +impl FromIterator> for SignaturesOf { + fn from_iter>>(signatures: T) -> Self { + Self { + signatures: signatures.into_iter().map(SignatureWrapperOf).collect(), + } } } #[cfg(not(feature = "ffi_import"))] impl SignaturesOf { - /// Transmutes signature generic type - /// - /// # Warning - /// - /// This method uses [`core::mem::transmute`] internally - #[allow(unsafe_code, clippy::transmute_undefined_repr)] - pub fn transmute(self) -> SignaturesOf { - // SAFETY: Safe because we are transmuting to a pointer of - // type `` which is related to type ``. - let signatures = unsafe { core::mem::transmute(self.signatures) }; - SignaturesOf { signatures } - } - /// Adds a signature. If the signature with this key was present, replaces it. pub fn insert(&mut self, signature: SignatureOf) { self.signatures.insert(SignatureWrapperOf(signature)); } - /// Return signatures that have passed verification, remove all others. - #[cfg(feature = "std")] - pub fn retain_verified_by_hash( - &mut self, - hash: HashOf, - ) -> impl ExactSizeIterator> { - self.signatures - .retain(|sign| sign.verify_hash(hash).is_ok()); - self.iter() - } - /// Return all signatures. #[inline] pub fn iter(&self) -> impl ExactSizeIterator> { @@ -548,11 +456,6 @@ impl SignaturesOf { self.signatures.len() } - /// Clear signatures. - pub fn clear(&mut self) { - self.signatures.clear() - } - /// Verify signatures for this hash /// /// # Errors @@ -568,6 +471,11 @@ impl SignaturesOf { }) }) } + + /// Returns true if the set is a subset of another, i.e., other contains at least all the elements in self. + pub fn is_subset(&self, other: &Self) -> bool { + self.signatures.is_subset(&other.signatures) + } } #[cfg(feature = "std")] @@ -588,11 +496,6 @@ impl SignaturesOf { pub fn verify(&self, item: &T) -> Result<(), SignatureVerificationFail> { self.verify_hash(HashOf::new(item)) } - - /// Return signatures that have passed verification, remove all others. - pub fn retain_verified(&mut self, value: &T) -> impl ExactSizeIterator> { - self.retain_verified_by_hash(HashOf::new(value)) - } } /// Verification failed of some signature due to following reason @@ -695,36 +598,6 @@ mod tests { assert!(signature.verify(message).is_ok()) } - #[test] - #[cfg(feature = "std")] - #[cfg(not(feature = "ffi_import"))] - fn decode_signatures_of() { - use parity_scale_codec::DecodeAll; - - let no_signatures: SignaturesOf = SignaturesOf { - signatures: btree_set::BTreeSet::new(), - }; - let bytes = no_signatures.encode(); - - let signatures = SignaturesOf::::decode_all(&mut &bytes[..]); - assert!(signatures.is_err()); - } - - #[test] - #[cfg(feature = "std")] - #[cfg(not(feature = "ffi_import"))] - fn deserialize_signatures_of() -> Result<(), serde_json::Error> { - let no_signatures: SignaturesOf = SignaturesOf { - signatures: btree_set::BTreeSet::new(), - }; - let serialized = serde_json::to_string(&no_signatures)?; - - let signatures = serde_json::from_str::>(serialized.as_str()); - assert!(signatures.is_err()); - - Ok(()) - } - #[test] #[cfg(feature = "std")] #[cfg(not(feature = "ffi_import"))] @@ -734,11 +607,9 @@ mod tests { SignatureOf::new(key_pair.clone(), &1).expect("Failed to sign"), SignatureOf::new(key_pair.clone(), &2).expect("Failed to sign"), SignatureOf::new(key_pair, &3).expect("Failed to sign"), - ]; - let signatures = signatures - .into_iter() - .collect::, Error>>() - .expect("One signature must stay"); + ] + .into_iter() + .collect::>(); // Signatures with the same public key was deduplicated assert_eq!(signatures.len(), 1); } diff --git a/data_model/src/asset.rs b/data_model/src/asset.rs index 112234a2d18..9f658d98f00 100644 --- a/data_model/src/asset.rs +++ b/data_model/src/asset.rs @@ -220,6 +220,8 @@ pub mod model { Clone, PartialEq, Eq, + PartialOrd, + Ord, Decode, Encode, Deserialize, diff --git a/data_model/src/block.rs b/data_model/src/block.rs index c08d59e8c32..d2d502292db 100644 --- a/data_model/src/block.rs +++ b/data_model/src/block.rs @@ -6,347 +6,331 @@ #[cfg(not(feature = "std"))] use alloc::{boxed::Box, format, string::String, vec::Vec}; -use core::{cmp::Ordering, fmt::Display}; +use core::{fmt::Display, time::Duration}; use derive_more::Display; use getset::Getters; -#[cfg(feature = "std")] -use iroha_crypto::SignatureOf; -use iroha_crypto::{Hash, HashOf, MerkleTree, SignaturesOf}; +use iroha_crypto::{HashOf, KeyPair, MerkleTree, SignaturesOf}; +use iroha_data_model_derive::model; +use iroha_macro::FromVariant; use iroha_schema::IntoSchema; -use iroha_version::{declare_versioned_with_scale, version_with_scale}; +use iroha_version::{declare_versioned, version_with_scale}; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; -pub use self::{ - committed::{CommittedBlock, PartialBlockHash, VersionedCommittedBlock}, - header::BlockHeader, -}; -use crate::{events::prelude::*, model, peer, transaction::prelude::*}; +pub use self::model::*; +use crate::{events::prelude::*, peer, transaction::prelude::*}; -mod header { - pub use self::model::*; +#[model] +pub mod model { use super::*; - #[model] - pub mod model { - use super::*; - - /// Header of the block. The hash should be taken from its byte representation. - #[derive( - Debug, - Display, - Clone, - PartialEq, - Eq, - Getters, - Decode, - Encode, - Deserialize, - Serialize, - IntoSchema, - )] - #[cfg_attr( - feature = "std", - display(fmt = "Block №{height} (hash: {});", "HashOf::new(&self)") - )] - #[cfg_attr(not(feature = "std"), display(fmt = "Block №{height}"))] - #[getset(get = "pub")] - #[ffi_type] - pub struct BlockHeader { - /// Unix time (in milliseconds) of block forming by a peer. - pub timestamp: u128, - /// Estimation of consensus duration in milliseconds - pub consensus_estimation: u64, - /// A number of blocks in the chain up to the block. - pub height: u64, - /// Value of view change index used to resolve soft forks - pub view_change_index: u64, - /// Hash of a previous block in the chain. - /// Is an array of zeros for the first block. - pub previous_block_hash: Option>, - /// Hash of merkle tree root of the tree of valid transactions' hashes. - pub transactions_hash: Option>>, - /// Hash of merkle tree root of the tree of rejected transactions' hashes. - pub rejected_transactions_hash: Option>>, - /// Network topology when the block was committed. - // TODO: Derive with getset once FFI impl is fixed - #[getset(skip)] - pub committed_with_topology: Vec, - } + #[derive( + Debug, + Display, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Getters, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + )] + #[cfg_attr( + feature = "std", + display(fmt = "Block №{height} (hash: {});", "HashOf::new(&self)") + )] + #[cfg_attr(not(feature = "std"), display(fmt = "Block №{height}"))] + #[getset(get = "pub")] + #[allow(missing_docs)] + #[ffi_type] + pub struct BlockHeader { + /// Number of blocks in the chain including this block. + pub height: u64, + /// Creation timestamp (unix time in milliseconds). + #[getset(skip)] + pub timestamp_ms: u64, + /// Hash of the previous block in the chain. + pub previous_block_hash: Option>, + /// Hash of merkle tree root of transactions' hashes. + pub transactions_hash: Option>>, + /// Topology of the network at the time of block commit. + #[getset(skip)] // FIXME: Because ffi related issues + pub commit_topology: Vec, + /// Value of view change index. Used to resolve soft forks. + pub view_change_index: u64, + /// Estimation of consensus duration (in milliseconds). + pub consensus_estimation_ms: u64, } - impl BlockHeader { - /// Serialize the header's data for hashing purposes. - pub fn payload(&self) -> Vec { - let mut data = Vec::new(); - data.extend(&self.timestamp.to_le_bytes()); - data.extend(&self.consensus_estimation.to_le_bytes()); - data.extend(&self.height.to_le_bytes()); - data.extend(&self.view_change_index.to_le_bytes()); - if let Some(hash) = self.previous_block_hash.as_ref() { - data.extend(hash.as_ref()); - } - if let Some(hash) = self.transactions_hash.as_ref() { - data.extend(hash.as_ref()); - } - if let Some(hash) = self.rejected_transactions_hash.as_ref() { - data.extend(hash.as_ref()); - } - for id in &self.committed_with_topology { - data.extend(id.payload()); - } - data - } + #[derive( + Debug, + Display, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Getters, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + )] + #[display(fmt = "({header})")] + #[getset(get = "pub")] + #[allow(missing_docs)] + #[ffi_type] + pub struct BlockPayload { + /// Block header + pub header: BlockHeader, + /// array of transactions, which successfully passed validation and consensus step. + #[getset(skip)] // FIXME: Because ffi related issues + pub transactions: Vec, + /// Event recommendations. + #[getset(skip)] // NOTE: Unused ATM + pub event_recommendations: Vec, } - impl PartialOrd for BlockHeader { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + /// Signed block + #[version_with_scale(version = 1, versioned_alias = "VersionedSignedBlock")] + #[derive( + Debug, + Display, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Getters, + Encode, + Serialize, + IntoSchema, + )] + #[cfg_attr(not(feature = "std"), display(fmt = "Signed block"))] + #[cfg_attr(feature = "std", display(fmt = "{}", "self.hash()"))] + #[getset(get = "pub")] + #[ffi_type] + pub struct SignedBlock { + /// Signatures of peers which approved this block. + #[getset(skip)] + pub signatures: SignaturesOf, + /// Block payload + pub payload: BlockPayload, } +} - impl Ord for BlockHeader { - fn cmp(&self, other: &Self) -> Ordering { - self.timestamp.cmp(&other.timestamp) - } +#[cfg(any(feature = "ffi_export", feature = "ffi_import"))] +declare_versioned!(VersionedSignedBlock 1..2, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, FromVariant, iroha_ffi::FfiType, IntoSchema); +#[cfg(all(not(feature = "ffi_export"), not(feature = "ffi_import")))] +declare_versioned!(VersionedSignedBlock 1..2, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, FromVariant, IntoSchema); + +impl BlockPayload { + /// Calculate block payload [`Hash`](`iroha_crypto::HashOf`). + #[cfg(feature = "std")] + pub fn hash(&self) -> iroha_crypto::HashOf { + iroha_crypto::HashOf::new(self) } } -mod committed { - use iroha_macro::FromVariant; +impl BlockHeader { + /// Checks if it's a header of a genesis block. + #[inline] + pub const fn is_genesis(&self) -> bool { + self.height == 1 + } - pub use self::model::*; - use super::*; + /// Creation timestamp + pub fn timestamp(&self) -> Duration { + Duration::from_millis(self.timestamp_ms) + } - #[cfg(any(feature = "ffi_import", feature = "ffi_export"))] - declare_versioned_with_scale!(VersionedCommittedBlock 1..2, Debug, Clone, PartialEq, Eq, FromVariant, Deserialize, Serialize, iroha_ffi::FfiType, IntoSchema); - #[cfg(all(not(feature = "ffi_import"), not(feature = "ffi_export")))] - declare_versioned_with_scale!(VersionedCommittedBlock 1..2, Debug, Clone, PartialEq, Eq, FromVariant, Deserialize, Serialize, IntoSchema); + /// Consensus estimation + pub fn consensus_estimation(&self) -> Duration { + Duration::from_millis(self.consensus_estimation_ms) + } +} - #[model] - pub mod model { - use super::*; +impl SignedBlock { + #[cfg(feature = "std")] + fn hash(&self) -> iroha_crypto::HashOf { + iroha_crypto::HashOf::from_untyped_unchecked(iroha_crypto::HashOf::new(self).into()) + } +} - /// The hash of a [`VersionedCommittedBlock`] used for signing in consensus. - /// The normal [`Hashof`] will change based on who - /// has signed the block. If you want to compare the contents of a block only - /// use this hash instead. - #[derive( - Debug, - Display, - Clone, - Copy, - PartialEq, - Eq, - Getters, - Decode, - Encode, - Deserialize, - Serialize, - IntoSchema, - )] - #[display(fmt = "({internal})")] - #[repr(transparent)] - #[serde(transparent)] - #[ffi_type(unsafe {robust})] - pub struct PartialBlockHash { - /// The hash value. - pub internal: Hash, - } +impl VersionedSignedBlock { + /// Block payload + // FIXME: Leaking concrete type BlockPayload from Versioned container. Payload should be versioned + pub fn payload(&self) -> &BlockPayload { + let VersionedSignedBlock::V1(block) = self; + block.payload() + } - /// The `CommittedBlock` struct represents a block accepted by consensus - #[version_with_scale(version = 1, versioned_alias = "VersionedCommittedBlock")] - #[derive( - Debug, - Display, - Clone, - PartialEq, - Eq, - Getters, - Decode, - Encode, - Deserialize, - Serialize, - IntoSchema, - )] - #[display(fmt = "({header})")] - #[getset(get = "pub")] - #[ffi_type] - pub struct CommittedBlock { - /// Block header - pub header: BlockHeader, - // TODO: Derive with getset once FFI impl is fixed - #[getset(skip)] - pub transactions: Vec, - /// Event recommendations. - // TODO: Derive with getset once FFI impl is fixed - #[getset(skip)] - pub event_recommendations: Vec, - /// Signatures of peers which approved this block - #[getset(skip)] - pub signatures: SignaturesOf, - } + /// Used to inject faulty payload for testing + #[cfg(debug_assertions)] + #[cfg(feature = "transparent_api")] + pub fn payload_mut(&mut self) -> &mut BlockPayload { + let VersionedSignedBlock::V1(block) = self; + &mut block.payload } - impl VersionedCommittedBlock { - /// Checks if it's a header of a genesis block. - #[inline] - pub const fn is_genesis(&self) -> bool { - let VersionedCommittedBlock::V1(block) = self; - block.header.height == 1 - } + /// Signatures of peers which approved this block. + pub fn signatures(&self) -> &SignaturesOf { + let VersionedSignedBlock::V1(block) = self; + &block.signatures + } - /// Convert from `&VersionedCommittedBlock` to V1 reference - #[inline] - pub const fn as_v1(&self) -> &CommittedBlock { - match self { - Self::V1(v1) => v1, - } - } + /// Calculate block hash + #[cfg(feature = "std")] + pub fn hash(&self) -> HashOf { + iroha_crypto::HashOf::new(self) + } - /// Convert from `&mut VersionedCommittedBlock` to V1 mutable reference - #[inline] - pub fn as_mut_v1(&mut self) -> &mut CommittedBlock { - match self { - Self::V1(v1) => v1, - } - } + /// Add additional signatures to this block + /// + /// # Errors + /// + /// If given signature doesn't match block hash + #[cfg(feature = "std")] + #[cfg(feature = "transparent_api")] + pub fn sign(mut self, key_pair: KeyPair) -> Result { + iroha_crypto::SignatureOf::new(key_pair, self.payload()).map(|signature| { + let VersionedSignedBlock::V1(block) = &mut self; + block.signatures.insert(signature); + self + }) + } - /// Performs the conversion from `VersionedCommittedBlock` to V1 - #[inline] - pub fn into_v1(self) -> CommittedBlock { - match self { - Self::V1(v1) => v1, - } - } + /// Add additional signatures to this block + /// + /// # Errors + /// + /// If given signature doesn't match block hash + #[cfg(feature = "std")] + #[cfg(feature = "transparent_api")] + pub fn add_signature( + &mut self, + signature: iroha_crypto::SignatureOf, + ) -> Result<(), iroha_crypto::error::Error> { + signature.verify(self.payload())?; - /// Calculate the [`PartialBlockHash`] of this block. - #[cfg(feature = "std")] - #[inline] - pub fn partial_hash(&self) -> PartialBlockHash { - match self { - Self::V1(v1) => v1.partial_hash(), - } - } + let VersionedSignedBlock::V1(block) = self; + block.signatures.insert(signature); + + Ok(()) + } - /// Calculate the [`HashOf`] for this block. + /// Add additional signatures to this block + #[cfg(feature = "std")] + #[cfg(feature = "transparent_api")] + pub fn replace_signatures( + &mut self, + signatures: iroha_crypto::SignaturesOf, + ) -> bool { + #[cfg(not(feature = "std"))] + use alloc::collections::BTreeSet; #[cfg(feature = "std")] - pub fn hash(&self) -> HashOf { - match self { - Self::V1(v1) => v1.hash().transmute(), + use std::collections::BTreeSet; + + let VersionedSignedBlock::V1(block) = self; + block.signatures = BTreeSet::new().into(); + + for signature in signatures { + if self.add_signature(signature).is_err() { + return false; } } - /// Return signatures that are verified with the `hash` of this block - #[cfg(feature = "std")] - #[inline] - pub fn signatures(&self) -> impl ExactSizeIterator> { - self.as_v1().signatures().map(SignatureOf::transmute_ref) - } + true } +} - impl Display for VersionedCommittedBlock { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - self.as_v1().fmt(f) - } - } +mod candidate { + use parity_scale_codec::Input; - impl PartialOrd for VersionedCommittedBlock { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } + use super::*; - impl Ord for VersionedCommittedBlock { - fn cmp(&self, other: &Self) -> Ordering { - self.as_v1().cmp(other.as_v1()) - } + #[derive(Decode, Deserialize)] + struct SignedBlockCandidate { + signatures: SignaturesOf, + payload: BlockPayload, } - impl CommittedBlock { - /// Checks if it's a header of a genesis block. - pub const fn is_genesis(&self) -> bool { - self.header.height == 1 - } + impl SignedBlockCandidate { + fn validate(self) -> Result { + #[cfg(feature = "std")] + self.validate_signatures()?; + #[cfg(feature = "std")] + self.validate_header()?; - /// Calculate the partial hash of the current block. - /// [`CommitedBlock`] should have the same partial hash as [`PendingBlock`]. - #[cfg(feature = "std")] - #[inline] - pub fn partial_hash(&self) -> PartialBlockHash { - PartialBlockHash { - internal: Hash::new(self.header.payload()), + if self.payload.transactions.is_empty() { + return Err("Block is empty"); } + + Ok(SignedBlock { + payload: self.payload, + signatures: self.signatures, + }) } - /// Calculate the complete hash of the block that includes signatures. + #[cfg(feature = "std")] - #[inline] - pub fn hash(&self) -> HashOf { - let mut data = Vec::new(); - data.extend(self.header.payload()); - for s in self.signatures.iter() { - data.extend(s.key_payload()); - data.extend(s.signature_payload()); + fn validate_header(&self) -> Result<(), &'static str> { + let actual_txs_hash = self.payload.header().transactions_hash; + + let expected_txs_hash = self + .payload + .transactions + .iter() + .map(TransactionValue::hash) + .collect::>() + .hash(); + + if expected_txs_hash != actual_txs_hash { + return Err("Transactions' hash incorrect. Expected: {expected_txs_hash:?}, actual: {actual_txs_hash:?}"); } - HashOf::from_untyped_unchecked(Hash::new(&data)) - } + // TODO: Validate Event recommendations somehow? - /// Return signatures that are verified with the `hash` of this block - #[cfg(feature = "std")] - #[inline] - pub fn signatures(&self) -> impl ExactSizeIterator> { - self.signatures.iter() + Ok(()) } - } - impl PartialOrd for CommittedBlock { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) + #[cfg(feature = "std")] + fn validate_signatures(&self) -> Result<(), &'static str> { + self.signatures + .verify(&self.payload) + .map_err(|_| "Transaction contains invalid signatures") } } - impl Ord for CommittedBlock { - fn cmp(&self, other: &Self) -> Ordering { - self.header.cmp(&other.header) + impl Decode for SignedBlock { + fn decode(input: &mut I) -> Result { + SignedBlockCandidate::decode(input)? + .validate() + .map_err(Into::into) } } + impl<'de> Deserialize<'de> for SignedBlock { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use serde::de::Error as _; - #[cfg(feature = "std")] - impl From<&CommittedBlock> for Vec { - fn from(block: &CommittedBlock) -> Self { - let tx = block.transactions.iter().map(|tx| { - let status = tx.error.as_ref().map_or_else( - || PipelineStatus::Committed, - |error| PipelineStatus::Rejected(error.clone().into()), - ); - - PipelineEvent { - entity_kind: PipelineEntityKind::Transaction, - status, - hash: tx.payload().hash().into(), - } - .into() - }); - let current_block = core::iter::once( - PipelineEvent { - entity_kind: PipelineEntityKind::Block, - status: PipelineStatus::Committed, - hash: block.hash().into(), - } - .into(), - ); - - tx.chain(current_block).collect() + SignedBlockCandidate::deserialize(deserializer)? + .validate() + .map_err(D::Error::custom) } } +} - #[cfg(feature = "std")] - impl From<&VersionedCommittedBlock> for Vec { - #[inline] - fn from(block: &VersionedCommittedBlock) -> Self { - block.as_v1().into() - } +impl Display for VersionedSignedBlock { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let VersionedSignedBlock::V1(block) = self; + block.fmt(f) } } @@ -355,39 +339,12 @@ pub mod stream { //! Blocks for streaming API. use derive_more::Constructor; - use iroha_macro::FromVariant; use iroha_schema::IntoSchema; - use iroha_version::prelude::*; use parity_scale_codec::{Decode, Encode}; pub use self::model::*; use super::*; - declare_versioned_with_scale!(VersionedBlockMessage 1..2, Debug, Clone, FromVariant, IntoSchema); - - impl VersionedBlockMessage { - /// Convert from `&VersionedBlockPublisherMessage` to V1 reference - pub const fn as_v1(&self) -> &BlockMessage { - match self { - Self::V1(v1) => v1, - } - } - - /// Convert from `&mut VersionedBlockPublisherMessage` to V1 mutable reference - pub fn as_mut_v1(&mut self) -> &mut BlockMessage { - match self { - Self::V1(v1) => v1, - } - } - - /// Performs the conversion from `VersionedBlockPublisherMessage` to V1 - pub fn into_v1(self) -> BlockMessage { - match self { - Self::V1(v1) => v1, - } - } - } - #[model] pub mod model { use core::num::NonZeroU64; @@ -395,56 +352,25 @@ pub mod stream { use super::*; /// Request sent to subscribe to blocks stream starting from the given height. - #[version_with_scale(version = 1, versioned_alias = "VersionedBlockSubscriptionRequest")] #[derive(Debug, Clone, Copy, Constructor, Decode, Encode, IntoSchema)] #[repr(transparent)] pub struct BlockSubscriptionRequest(pub NonZeroU64); - /// Message sent by the stream producer - /// Block sent by the peer. - #[version_with_scale(version = 1, versioned_alias = "VersionedBlockMessage")] + /// Message sent by the stream producer containing block. #[derive(Debug, Clone, Decode, Encode, IntoSchema)] #[repr(transparent)] - pub struct BlockMessage(pub VersionedCommittedBlock); + pub struct BlockMessage(pub VersionedSignedBlock); } - impl From for VersionedCommittedBlock { + impl From for VersionedSignedBlock { fn from(source: BlockMessage) -> Self { source.0 } } - declare_versioned_with_scale!(VersionedBlockSubscriptionRequest 1..2, Debug, Clone, FromVariant, IntoSchema); - - impl VersionedBlockSubscriptionRequest { - /// Convert from `&VersionedBlockSubscriberMessage` to V1 reference - pub const fn as_v1(&self) -> &BlockSubscriptionRequest { - match self { - Self::V1(v1) => v1, - } - } - - /// Convert from `&mut VersionedBlockSubscriberMessage` to V1 mutable reference - pub fn as_mut_v1(&mut self) -> &mut BlockSubscriptionRequest { - match self { - Self::V1(v1) => v1, - } - } - - /// Performs the conversion from `VersionedBlockSubscriberMessage` to V1 - pub fn into_v1(self) -> BlockSubscriptionRequest { - match self { - Self::V1(v1) => v1, - } - } - } - /// Exports common structs and enums from this module. pub mod prelude { - pub use super::{ - BlockMessage, BlockSubscriptionRequest, VersionedBlockMessage, - VersionedBlockSubscriptionRequest, - }; + pub use super::{BlockMessage, BlockSubscriptionRequest}; } } @@ -466,6 +392,8 @@ pub mod error { Copy, PartialEq, Eq, + PartialOrd, + Ord, iroha_macro::FromVariant, Decode, Encode, diff --git a/data_model/src/events/data/events.rs b/data_model/src/events/data/events.rs index 7acfe505346..c6dfe09c0fe 100644 --- a/data_model/src/events/data/events.rs +++ b/data_model/src/events/data/events.rs @@ -16,6 +16,8 @@ macro_rules! data_event { Clone, PartialEq, Eq, + PartialOrd, + Ord, Filter, HasOrigin, parity_scale_codec::Decode, @@ -37,7 +39,19 @@ pub mod model { /// Generic [`MetadataChanged`] struct. /// Contains the changed metadata (`(key, value)` pair), either inserted or removed, which is determined by the wrapping event. - #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + #[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + )] // TODO: Generics are not supported. Figure out what to do //#[getset(get = "pub")] #[ffi_type] @@ -65,7 +79,18 @@ pub mod model { /// Event #[derive( - Debug, Clone, PartialEq, Eq, FromVariant, Decode, Encode, Deserialize, Serialize, IntoSchema, + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + FromVariant, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, )] #[ffi_type] pub enum DataEvent { @@ -145,7 +170,18 @@ mod asset { /// Depending on the wrapping event, [`Self`] represents the added or removed asset quantity. #[derive( - Debug, Clone, PartialEq, Eq, Getters, Decode, Encode, Deserialize, Serialize, IntoSchema, + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Getters, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, )] #[getset(get = "pub")] #[ffi_type] @@ -156,7 +192,18 @@ mod asset { /// [`Self`] represents updated total asset quantity. #[derive( - Debug, Clone, PartialEq, Eq, Getters, Decode, Encode, Deserialize, Serialize, IntoSchema, + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Getters, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, )] #[getset(get = "pub")] #[ffi_type] @@ -167,7 +214,18 @@ mod asset { /// [`Self`] represents updated total asset quantity. #[derive( - Debug, Clone, PartialEq, Eq, Getters, Decode, Encode, Deserialize, Serialize, IntoSchema, + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Getters, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, )] #[getset(get = "pub")] #[ffi_type] @@ -481,6 +539,8 @@ mod validator { Clone, PartialEq, Eq, + PartialOrd, + Ord, parity_scale_codec::Decode, parity_scale_codec::Encode, serde::Deserialize, diff --git a/data_model/src/events/execute_trigger.rs b/data_model/src/events/execute_trigger.rs index b9222c16387..9b05dde3163 100644 --- a/data_model/src/events/execute_trigger.rs +++ b/data_model/src/events/execute_trigger.rs @@ -18,7 +18,8 @@ pub mod model { Clone, PartialEq, Eq, - Hash, + PartialOrd, + Ord, Getters, Decode, Encode, @@ -43,7 +44,6 @@ pub mod model { Ord, PartialEq, Eq, - Hash, Constructor, Decode, Encode, diff --git a/data_model/src/events/mod.rs b/data_model/src/events/mod.rs index 93ef1b49aaa..37382ddcc8a 100644 --- a/data_model/src/events/mod.rs +++ b/data_model/src/events/mod.rs @@ -23,7 +23,18 @@ pub mod model { #[allow(missing_docs)] #[derive( - Debug, Clone, PartialEq, Eq, FromVariant, Decode, Encode, Deserialize, Serialize, IntoSchema, + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + FromVariant, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, )] #[ffi_type] pub enum Event { @@ -185,45 +196,18 @@ pub mod stream { pub use self::model::*; use super::*; - declare_versioned_with_scale!(VersionedEventMessage 1..2, Debug, Clone, FromVariant, IntoSchema); - - impl VersionedEventMessage { - #[allow(missing_docs)] - pub const fn as_v1(&self) -> &EventMessage { - match self { - Self::V1(v1) => v1, - } - } - - #[allow(missing_docs)] - pub fn as_mut_v1(&mut self) -> &mut EventMessage { - match self { - Self::V1(v1) => v1, - } - } - - #[allow(missing_docs)] - pub fn into_v1(self) -> EventMessage { - match self { - Self::V1(v1) => v1, - } - } - } - #[model] pub mod model { use super::*; /// Message sent by the stream producer. /// Event sent by the peer. - #[version_with_scale(version = 1, versioned_alias = "VersionedEventMessage")] #[derive(Debug, Clone, Decode, Encode, IntoSchema)] #[repr(transparent)] pub struct EventMessage(pub Event); /// Message sent by the stream consumer. /// Request sent by the client to subscribe to events. - #[version_with_scale(version = 1, versioned_alias = "VersionedEventSubscriptionRequest")] #[derive(Debug, Clone, Constructor, Decode, Encode, IntoSchema)] #[repr(transparent)] pub struct EventSubscriptionRequest(pub FilterBox); @@ -234,40 +218,12 @@ pub mod stream { source.0 } } - - declare_versioned_with_scale!(VersionedEventSubscriptionRequest 1..2, Debug, Clone, FromVariant, IntoSchema); - - impl VersionedEventSubscriptionRequest { - #[allow(missing_docs)] - pub const fn as_v1(&self) -> &EventSubscriptionRequest { - match self { - Self::V1(v1) => v1, - } - } - - #[allow(missing_docs)] - pub fn as_mut_v1(&mut self) -> &mut EventSubscriptionRequest { - match self { - Self::V1(v1) => v1, - } - } - - #[allow(missing_docs)] - pub fn into_v1(self) -> EventSubscriptionRequest { - match self { - Self::V1(v1) => v1, - } - } - } } /// Exports common structs and enums from this module. pub mod prelude { #[cfg(feature = "http")] - pub use super::stream::{ - EventMessage, EventSubscriptionRequest, VersionedEventMessage, - VersionedEventSubscriptionRequest, - }; + pub use super::stream::{EventMessage, EventSubscriptionRequest}; #[cfg(feature = "transparent_api")] pub use super::Filter; pub use super::{ diff --git a/data_model/src/events/notification.rs b/data_model/src/events/notification.rs index 423d5f77826..8f98f3f0c73 100644 --- a/data_model/src/events/notification.rs +++ b/data_model/src/events/notification.rs @@ -21,7 +21,18 @@ pub mod model { /// Notification event for events that arise during block application process like trigger execution for example #[derive( - Debug, Clone, FromVariant, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema, + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + FromVariant, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, )] #[ffi_type] #[non_exhaustive] @@ -33,11 +44,11 @@ pub mod model { #[derive( Debug, Clone, - Getters, PartialEq, Eq, PartialOrd, Ord, + Getters, Constructor, Decode, Encode, @@ -56,12 +67,12 @@ pub mod model { #[derive( Debug, Clone, - FromVariant, - EnumDiscriminants, PartialEq, Eq, PartialOrd, Ord, + FromVariant, + EnumDiscriminants, Decode, Encode, Deserialize, @@ -113,12 +124,12 @@ pub mod model { #[derive( Debug, Clone, - Constructor, - Getters, PartialEq, Eq, PartialOrd, Ord, + Constructor, + Getters, Decode, Encode, Deserialize, diff --git a/data_model/src/events/pipeline.rs b/data_model/src/events/pipeline.rs index d375cba3a18..e42f9a8d3ee 100644 --- a/data_model/src/events/pipeline.rs +++ b/data_model/src/events/pipeline.rs @@ -40,6 +40,7 @@ pub mod model { /// If `Some::`, filter by the [`StatusKind`]. If `None`, accept all the [`StatusKind`]. pub(super) status_kind: Option, /// If `Some::`, filter by the [`struct@Hash`]. If `None`, accept all the [`struct@Hash`]. + // TODO: Can we make hash typed like HashOf? pub(super) hash: Option, } @@ -69,7 +70,18 @@ pub mod model { /// Strongly-typed [`Event`] that tells the receiver the kind and the hash of the changed entity as well as its [`Status`]. #[derive( - Debug, Clone, PartialEq, Eq, Getters, Decode, Encode, Deserialize, Serialize, IntoSchema, + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Getters, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, )] #[getset(get = "pub")] #[ffi_type] @@ -88,6 +100,8 @@ pub mod model { Clone, PartialEq, Eq, + PartialOrd, + Ord, FromVariant, EnumDiscriminants, Decode, @@ -117,6 +131,8 @@ pub mod model { Clone, PartialEq, Eq, + PartialOrd, + Ord, FromVariant, Decode, Encode, diff --git a/data_model/src/events/time.rs b/data_model/src/events/time.rs index a85ec84abfc..82e76481191 100644 --- a/data_model/src/events/time.rs +++ b/data_model/src/events/time.rs @@ -23,6 +23,8 @@ pub mod model { Copy, PartialEq, Eq, + PartialOrd, + Ord, Getters, Decode, Encode, diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index b8fcf553afb..d66a385484b 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -30,7 +30,7 @@ use core::{ str::FromStr, }; -use block::VersionedCommittedBlock; +use block::VersionedSignedBlock; #[cfg(not(target_arch = "aarch64"))] use derive_more::Into; use derive_more::{AsRef, DebugCustom, Deref, Display, From, FromStr}; @@ -779,7 +779,7 @@ pub mod model { PermissionToken(permission::PermissionToken), PermissionTokenSchema(permission::PermissionTokenSchema), Hash(HashValue), - Block(VersionedCommittedBlockWrapper), + Block(VersionedSignedBlockWrapper), BlockHeader(block::BlockHeader), Ipv4Addr(iroha_primitives::addr::Ipv4Addr), Ipv6Addr(iroha_primitives::addr::Ipv6Addr), @@ -811,10 +811,10 @@ pub mod model { /// Transaction hash Transaction(HashOf), /// Block hash - Block(HashOf), + Block(HashOf), } - /// Cross-platform wrapper for [`VersionedCommittedBlock`]. + /// Cross-platform wrapper for [`VersionedSignedBlock`]. #[cfg(not(target_arch = "aarch64"))] #[derive( Debug, @@ -833,12 +833,12 @@ pub mod model { Serialize, IntoSchema, )] - // SAFETY: VersionedCommittedBlockWrapper has no trap representations in VersionedCommittedBlock + // SAFETY: VersionedSignedBlockWrapper has no trap representations in VersionedSignedBlock #[schema(transparent)] #[ffi_type(unsafe {robust})] #[serde(transparent)] #[repr(transparent)] - pub struct VersionedCommittedBlockWrapper(VersionedCommittedBlock); + pub struct VersionedSignedBlockWrapper(VersionedSignedBlock); /// Cross-platform wrapper for `BlockValue`. #[cfg(target_arch = "aarch64")] @@ -862,11 +862,11 @@ pub mod model { #[as_ref(forward)] #[deref(forward)] #[from(forward)] - // SAFETY: VersionedCommittedBlockWrapper has no trap representations in Box + // SAFETY: VersionedSignedBlockWrapper has no trap representations in Box #[ffi_type(unsafe {robust})] #[serde(transparent)] #[repr(transparent)] - pub struct VersionedCommittedBlockWrapper(pub(super) Box); + pub struct VersionedSignedBlockWrapper(pub(super) Box); /// Limits of length of the identifiers (e.g. in [`domain::Domain`], [`account::Account`], [`asset::AssetDefinition`]) in number of chars #[derive( @@ -1054,8 +1054,8 @@ macro_rules! val_vec { } #[cfg(target_arch = "aarch64")] -impl From for VersionedCommittedBlock { - fn from(block_value: VersionedCommittedBlockWrapper) -> Self { +impl From for VersionedSignedBlock { + fn from(block_value: VersionedSignedBlockWrapper) -> Self { *block_value.0 } } @@ -1133,8 +1133,8 @@ impl Value { } } -impl From for Value { - fn from(block_value: VersionedCommittedBlock) -> Self { +impl From for Value { + fn from(block_value: VersionedSignedBlock) -> Self { Value::Block(block_value.into()) } } @@ -1327,7 +1327,7 @@ from_and_try_from_value_identifiable!( from_and_try_from_and_try_as_value_hash! { Transaction(HashOf), - Block(HashOf), + Block(HashOf), } from_and_try_from_and_try_as_value_numeric! { @@ -1427,7 +1427,7 @@ where } } -impl TryFrom for VersionedCommittedBlock { +impl TryFrom for VersionedSignedBlock { type Error = ErrorTryFromEnum; fn try_from(value: Value) -> Result { diff --git a/data_model/src/predicate.rs b/data_model/src/predicate.rs index b619681f9a1..aff82bc25de 100644 --- a/data_model/src/predicate.rs +++ b/data_model/src/predicate.rs @@ -992,7 +992,7 @@ pub mod value { Display(string::StringPredicate), /// Apply predicate to the numerical value. Numerical(numerical::SemiRange), - /// Timestamp (currently for [`VersionedCommittedBlock`] only). + /// Timestamp (currently for [`VersionedSignedBlock`] only). TimeStamp(numerical::SemiInterval), /// IpAddress enumerable by `u32` Ipv4Addr(ip_addr::Ipv4Predicate), @@ -1058,7 +1058,9 @@ pub mod value { ValuePredicate::Numerical(pred) => pred.applies(input), ValuePredicate::Display(pred) => pred.applies(&input.to_string()), ValuePredicate::TimeStamp(pred) => match input { - Value::Block(block) => pred.applies(block.as_v1().header.timestamp), + Value::Block(block) => { + pred.applies(block.payload().header.timestamp().as_millis()) + } _ => false, }, ValuePredicate::Ipv4Addr(pred) => match input { diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index 512c39e845c..9c1d657b022 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -28,7 +28,7 @@ use self::{ }; use crate::{ account::Account, - block::VersionedCommittedBlock, + block::VersionedSignedBlock, seal, transaction::{TransactionPayload, TransactionValue, VersionedSignedTransaction}, Identifiable, Value, @@ -71,7 +71,7 @@ pub mod model { use iroha_crypto::HashOf; use super::*; - use crate::permission::PermissionTokenId; + use crate::{block::VersionedSignedBlock, permission::PermissionTokenId}; /// Sized container for all possible Queries. #[allow(clippy::enum_variant_names)] @@ -146,7 +146,7 @@ pub mod model { /// Transaction pub transaction: TransactionValue, /// The hash of the block to which `tx` belongs to - pub block_hash: HashOf, + pub block_hash: HashOf, } /// Type returned from [`Metadata`] queries @@ -203,9 +203,10 @@ impl PartialOrd for TransactionQueryOutput { impl Ord for TransactionQueryOutput { #[inline] fn cmp(&self, other: &Self) -> Ordering { - self.payload() - .creation_time_ms - .cmp(&other.payload().creation_time_ms) + let tx1 = self.transaction.payload(); + let tx2 = other.transaction.payload(); + + tx1.creation_time().cmp(&tx2.creation_time()) } } @@ -1163,7 +1164,7 @@ pub mod transaction { } impl FindTransactionsByAccountId { - ///Construct [`FindTransactionsByAccountId`]. + /// Construct [`FindTransactionsByAccountId`]. pub fn new(account_id: impl Into>) -> Self { Self { account_id: account_id.into(), @@ -1197,7 +1198,7 @@ pub mod block { use super::Query; use crate::{ - block::{BlockHeader, VersionedCommittedBlock}, + block::{BlockHeader, VersionedSignedBlock}, prelude::EvaluatesTo, }; @@ -1220,16 +1221,16 @@ pub mod block { #[derive(Display)] #[display(fmt = "Find block header with `{hash}` hash")] #[repr(transparent)] - // SAFETY: `FindBlockHeaderByHash` has no trap representation in `EvaluatesTo>` + // SAFETY: `FindBlockHeaderByHash` has no trap representation in `EvaluatesTo>` #[ffi_type(unsafe {robust})] pub struct FindBlockHeaderByHash { /// Block hash. - pub hash: EvaluatesTo>, + pub hash: EvaluatesTo>, } } impl Query for FindAllBlocks { - type Output = Vec; + type Output = Vec; } impl Query for FindAllBlockHeaders { @@ -1242,7 +1243,7 @@ pub mod block { impl FindBlockHeaderByHash { /// Construct [`FindBlockHeaderByHash`]. - pub fn new(hash: impl Into>>) -> Self { + pub fn new(hash: impl Into>>) -> Self { Self { hash: hash.into() } } } @@ -1436,7 +1437,7 @@ pub mod error { pub use self::model::*; use super::*; - use crate::{block::VersionedCommittedBlock, permission, prelude::*, validator}; + use crate::{block::VersionedSignedBlock, permission, prelude::*, validator}; #[model] pub mod model { @@ -1515,7 +1516,7 @@ pub mod error { /// Failed to find metadata key: `{0}` MetadataKey(Name), /// Block with hash `{0}` not found - Block(HashOf), + Block(HashOf), /// Transaction with hash `{0}` not found Transaction(HashOf), /// Peer with id `{0}` not found diff --git a/data_model/src/transaction.rs b/data_model/src/transaction.rs index d73f4f4c0e5..021042cd154 100644 --- a/data_model/src/transaction.rs +++ b/data_model/src/transaction.rs @@ -259,16 +259,16 @@ declare_versioned!(VersionedSignedTransaction 1..2, Debug, Display, Clone, Parti impl VersionedSignedTransaction { /// Return transaction payload - // TODO: Leaking concrete type TransactionPayload from Versioned container. Payload should be versioned + // FIXME: Leaking concrete type TransactionPayload from Versioned container. Payload should be versioned pub fn payload(&self) -> &TransactionPayload { let VersionedSignedTransaction::V1(tx) = self; - tx.payload() + &tx.payload } /// Return transaction signatures pub fn signatures(&self) -> &SignaturesOf { let VersionedSignedTransaction::V1(tx) = self; - tx.signatures() + &tx.signatures } /// Calculate transaction [`Hash`](`iroha_crypto::HashOf`). @@ -299,10 +299,6 @@ impl VersionedSignedTransaction { } /// Add additional signatures to this transaction - /// - /// # Errors - /// - /// - if signature verification fails #[cfg(feature = "std")] #[cfg(feature = "transparent_api")] pub fn merge_signatures(&mut self, other: Self) -> bool { @@ -329,26 +325,28 @@ impl From for (AccountId, Executable) { impl SignedTransaction { #[cfg(feature = "std")] fn hash(&self) -> iroha_crypto::HashOf { - // TODO: Redundant clone. How to construct a versioned reference? - // or should we return HashOf - iroha_crypto::HashOf::new(&self.clone().into()) - } - - fn payload(&self) -> &TransactionPayload { - &self.payload - } - - fn signatures(&self) -> &SignaturesOf { - &self.signatures + iroha_crypto::HashOf::from_untyped_unchecked(iroha_crypto::HashOf::new(self).into()) } } impl TransactionValue { - /// Used to return payload of the transaction + /// Calculate transaction [`Hash`](`iroha_crypto::HashOf`). + #[cfg(feature = "std")] + pub fn hash(&self) -> iroha_crypto::HashOf { + self.value.hash() + } + + /// [`Transaction`] payload. #[inline] pub fn payload(&self) -> &TransactionPayload { self.value.payload() } + + /// [`iroha_crypto::SignatureOf`]<[`TransactionPayload`]>. + #[inline] + pub fn signatures(&self) -> &SignaturesOf { + self.value.signatures() + } } impl PartialOrd for TransactionValue { @@ -406,7 +404,7 @@ mod candidate { #[cfg(feature = "std")] fn validate_signatures(&self) -> Result<(), &'static str> { self.signatures - .verify_hash(self.payload.hash()) + .verify(&self.payload) .map_err(|_| "Transaction contains invalid signatures") } } @@ -593,8 +591,6 @@ pub mod error { InstructionExecution(#[cfg_attr(feature = "std", source)] InstructionExecutionFail), /// Failure in WebAssembly execution WasmExecution(#[cfg_attr(feature = "std", source)] WasmExecutionFail), - /// The genesis account can only sign transactions in the genesis block - UnexpectedGenesisAccountSignature, /// Transaction rejected due to being expired Expired, } diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index ebc01c96330..f078ffe49be 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -656,41 +656,53 @@ }, "BlockHeader": { "Struct": [ - { - "name": "timestamp", - "type": "u128" - }, - { - "name": "consensus_estimation", - "type": "u64" - }, { "name": "height", "type": "u64" }, { - "name": "view_change_index", + "name": "timestamp_ms", "type": "u64" }, { "name": "previous_block_hash", - "type": "Option>" + "type": "Option>" }, { "name": "transactions_hash", "type": "Option>>" }, { - "name": "rejected_transactions_hash", - "type": "Option>>" + "name": "commit_topology", + "type": "Vec" }, { - "name": "committed_with_topology", - "type": "Vec" + "name": "view_change_index", + "type": "u64" + }, + { + "name": "consensus_estimation_ms", + "type": "u64" + } + ] + }, + "BlockMessage": "VersionedSignedBlock", + "BlockPayload": { + "Struct": [ + { + "name": "header", + "type": "BlockHeader" + }, + { + "name": "transactions", + "type": "Vec" + }, + { + "name": "event_recommendations", + "type": "Vec" } ] }, - "BlockMessage": "VersionedCommittedBlock", "BlockRejectionReason": { "Enum": [ { @@ -712,26 +724,6 @@ } ] }, - "CommittedBlock": { - "Struct": [ - { - "name": "header", - "type": "BlockHeader" - }, - { - "name": "transactions", - "type": "Vec" - }, - { - "name": "event_recommendations", - "type": "Vec" - }, - { - "name": "signatures", - "type": "SignaturesOf" - } - ] - }, "Conditional": { "Struct": [ { @@ -1107,7 +1099,7 @@ } ] }, - "EvaluatesTo>": { + "EvaluatesTo>": { "Struct": [ { "name": "expression", @@ -1920,7 +1912,7 @@ "Struct": [ { "name": "hash", - "type": "EvaluatesTo>" + "type": "EvaluatesTo>" } ] }, @@ -1974,7 +1966,7 @@ { "tag": "Block", "discriminant": 5, - "type": "HashOf" + "type": "HashOf" }, { "tag": "Transaction", @@ -2159,7 +2151,7 @@ }, "Hash": "Array", "HashOf>": "Hash", - "HashOf": "Hash", + "HashOf": "Hash", "HashOf": "Hash", "HashOf": "Hash", "HashValue": { @@ -2172,7 +2164,7 @@ { "tag": "Block", "discriminant": 1, - "type": "HashOf" + "type": "HashOf" } ] }, @@ -3093,8 +3085,8 @@ "Option>>": { "Option": "HashOf>" }, - "Option>": { - "Option": "HashOf" + "Option>": { + "Option": "HashOf" }, "Option": { "Option": "InstructionBox" @@ -3954,14 +3946,14 @@ } ] }, - "SignatureOf": "Signature", + "SignatureOf": "Signature", "SignatureOf": "Signature", "SignatureOf": "Signature", - "SignaturesOf": { + "SignaturesOf": { "Struct": [ { "name": "signatures", - "type": "SortedVec>" + "type": "SortedVec>" } ] }, @@ -3973,6 +3965,18 @@ } ] }, + "SignedBlock": { + "Struct": [ + { + "name": "signatures", + "type": "SignaturesOf" + }, + { + "name": "payload", + "type": "BlockPayload" + } + ] + }, "SignedQuery": { "Struct": [ { @@ -4109,8 +4113,8 @@ "SortedVec": { "Vec": "RoleId" }, - "SortedVec>": { - "Vec": "SignatureOf" + "SortedVec>": { + "Vec": "SignatureOf" }, "SortedVec>": { "Vec": "SignatureOf" @@ -4234,7 +4238,7 @@ }, { "name": "block_hash", - "type": "HashOf" + "type": "HashOf" } ] }, @@ -4265,13 +4269,9 @@ "discriminant": 4, "type": "WasmExecutionFail" }, - { - "tag": "UnexpectedGenesisAccountSignature", - "discriminant": 5 - }, { "tag": "Expired", - "discriminant": 6 + "discriminant": 5 } ] }, @@ -4680,7 +4680,7 @@ { "tag": "Block", "discriminant": 16, - "type": "VersionedCommittedBlock" + "type": "VersionedSignedBlock" }, { "tag": "BlockHeader", @@ -4820,48 +4820,12 @@ } ] }, - "VersionedBlockMessage": { - "Enum": [ - { - "tag": "V1", - "discriminant": 1, - "type": "BlockMessage" - } - ] - }, - "VersionedBlockSubscriptionRequest": { - "Enum": [ - { - "tag": "V1", - "discriminant": 1, - "type": "BlockSubscriptionRequest" - } - ] - }, - "VersionedCommittedBlock": { - "Enum": [ - { - "tag": "V1", - "discriminant": 1, - "type": "CommittedBlock" - } - ] - }, - "VersionedEventMessage": { - "Enum": [ - { - "tag": "V1", - "discriminant": 1, - "type": "EventMessage" - } - ] - }, - "VersionedEventSubscriptionRequest": { + "VersionedSignedBlock": { "Enum": [ { "tag": "V1", "discriminant": 1, - "type": "EventSubscriptionRequest" + "type": "SignedBlock" } ] }, diff --git a/genesis/src/lib.rs b/genesis/src/lib.rs index ca3a1e3507d..398c81d2b42 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -325,7 +325,7 @@ impl RawGenesisDomainBuilder { /// Add an account to this domain without a public key. #[cfg(test)] - pub fn account_without_public_key(mut self, account_name: Name) -> Self { + fn account_without_public_key(mut self, account_name: Name) -> Self { let account_id = AccountId::new(account_name, self.domain_id.clone()); self.transaction .isi diff --git a/macro/utils/Cargo.toml b/macro/utils/Cargo.toml index 4f8ca144381..74e9e6faf51 100644 --- a/macro/utils/Cargo.toml +++ b/macro/utils/Cargo.toml @@ -12,8 +12,6 @@ is-it-maintained-issue-resolution = { repository = "https://github.com/hyperledg is-it-maintained-open-issues = { repository = "https://github.com/hyperledger/iroha" } maintenance = { status = "actively-developed" } -[features] - [dependencies] syn = { workspace = true, features = ["default", "parsing", "printing"] } quote = { workspace = true } diff --git a/primitives/src/addr.rs b/primitives/src/addr.rs index 00465a6fdfe..0e704f10353 100644 --- a/primitives/src/addr.rs +++ b/primitives/src/addr.rs @@ -6,7 +6,7 @@ #[cfg(not(feature = "std"))] use alloc::{format, string::String, vec::Vec}; -use derive_more::{AsRef, From, IntoIterator}; +use derive_more::{AsRef, DebugCustom, Display, From, IntoIterator}; use iroha_macro::FromVariant; pub use iroha_primitives_derive::socket_addr; use iroha_schema::IntoSchema; @@ -38,10 +38,8 @@ ffi::ffi_item! { /// An Iroha-native version of [`std::net::Ipv4Addr`], duplicated here /// to remain `no_std` compatible. #[derive( - AsRef, - From, - IntoIterator, - Debug, + DebugCustom, + Display, Clone, Copy, PartialEq, @@ -49,12 +47,17 @@ ffi::ffi_item! { PartialOrd, Ord, Hash, + AsRef, + From, + IntoIterator, DeserializeFromStr, SerializeDisplay, Encode, Decode, IntoSchema, )] + #[display(fmt = "{}.{}.{}.{}", "self.0[0]", "self.0[1]", "self.0[2]", "self.0[3]")] + #[debug(fmt = "{}.{}.{}.{}", "self.0[0]", "self.0[1]", "self.0[2]", "self.0[3]")] #[repr(transparent)] pub struct Ipv4Addr([u8; 4]); @@ -69,13 +72,6 @@ impl Ipv4Addr { } } -impl core::fmt::Display for Ipv4Addr { - #[inline] - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}.{}.{}.{}", self.0[0], self.0[1], self.0[2], self.0[3]) - } -} - impl core::ops::Index for Ipv4Addr { type Output = u8; @@ -123,9 +119,6 @@ ffi::ffi_item! { /// An Iroha-native version of [`std::net::Ipv6Addr`], duplicated here /// to remain `no_std` compatible. #[derive( - AsRef, - From, - IntoIterator, Debug, Clone, Copy, @@ -134,6 +127,9 @@ ffi::ffi_item! { PartialOrd, Ord, Hash, + AsRef, + From, + IntoIterator, DeserializeFromStr, SerializeDisplay, Encode, @@ -261,7 +257,8 @@ ffi::ffi_item! { /// This struct provides an Iroha-native version of [`std::net::SocketAddrV4`]. It is duplicated here /// in order to remain `no_std` compatible. #[derive( - Debug, + DebugCustom, + Display, Clone, Copy, PartialEq, @@ -275,6 +272,8 @@ ffi::ffi_item! { Decode, IntoSchema, )] + #[display(fmt = "{}:{}", "self.ip", "self.port")] + #[debug(fmt = "{}:{}", "self.ip", "self.port")] pub struct SocketAddrV4 { /// The Ipv4 address. pub ip: Ipv4Addr, @@ -292,12 +291,6 @@ impl From<([u8; 4], u16)> for SocketAddrV4 { } } -impl core::fmt::Display for SocketAddrV4 { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}:{}", self.ip, self.port) - } -} - impl core::str::FromStr for SocketAddrV4 { type Err = ParseError; @@ -314,7 +307,8 @@ ffi::ffi_item! { /// This struct provides an Iroha-native version of [`std::net::SocketAddrV6`]. It is duplicated here /// in order to remain `no_std` compatible. #[derive( - Debug, + DebugCustom, + Display, Clone, Copy, PartialEq, @@ -328,6 +322,8 @@ ffi::ffi_item! { Decode, IntoSchema, )] + #[display(fmt = "[{}]:{}", "self.ip", "self.port")] + #[debug(fmt = "[{}]:{}", "self.ip", "self.port")] pub struct SocketAddrV6 { /// The Ipv6 address. pub ip: Ipv6Addr, @@ -345,12 +341,6 @@ impl From<([u16; 8], u16)> for SocketAddrV6 { } } -impl core::fmt::Display for SocketAddrV6 { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "[{}]:{}", self.ip, self.port) - } -} - impl core::str::FromStr for SocketAddrV6 { type Err = ParseError; @@ -411,7 +401,8 @@ ffi::ffi_item! { /// This enum provides an Iroha-native version of [`std::net::SocketAddr`]. It is duplicated here /// in order to remain `no_std` compatible. #[derive( - Debug, + DebugCustom, + Display, Clone, PartialEq, Eq, @@ -475,16 +466,6 @@ impl SocketAddr { } } -impl core::fmt::Display for SocketAddr { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - SocketAddr::Ipv4(addr) => write!(f, "{}", addr), - SocketAddr::Ipv6(addr) => write!(f, "{}", addr), - SocketAddr::Host(addr) => write!(f, "{}", addr), - } - } -} - impl From<([u8; 4], u16)> for SocketAddr { fn from(value: ([u8; 4], u16)) -> Self { Self::Ipv4(value.into()) @@ -785,10 +766,10 @@ mod test { port: 9019, }); - assert_eq!( - serde_json::from_str::(&serde_json::to_string(&v6).unwrap()).unwrap(), - v6 - ); + let kita = &serde_json::to_string(&v6).unwrap(); + println!("{kita}"); + let kara = serde_json::from_str::(kita).unwrap(); + assert_eq!(kara, v6); let host = SocketAddr::Host(SocketAddrHost { host: "localhost".into(), diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index 11712455494..c7087903abd 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -5,7 +5,9 @@ use iroha_crypto::MerkleTree; use iroha_data_model::{ - block::stream::prelude::*, http::VersionedBatchedResponse, query::error::QueryExecutionFail, + block::stream::{BlockMessage, BlockSubscriptionRequest}, + http::VersionedBatchedResponse, + query::error::QueryExecutionFail, }; use iroha_genesis::RawGenesisBlock; use iroha_schema::prelude::*; @@ -19,7 +21,7 @@ macro_rules! types { $( $callback!($t); )+ #[cfg(target_arch = "aarch64")] - $callback!(Box); + $callback!(Box); }} } } @@ -42,18 +44,18 @@ pub fn build_schemas() -> MetaMap { schemas! { QueryExecutionFail, - VersionedBlockMessage, - VersionedBlockSubscriptionRequest, - VersionedEventMessage, - VersionedEventSubscriptionRequest, + BlockMessage, + BlockSubscriptionRequest, + EventMessage, + EventSubscriptionRequest, VersionedBatchedResponse, VersionedBatchedResponse>, VersionedSignedQuery, // Never referenced, but present in type signature. Like `PhantomData` - UpgradableBox, - RegistrableBox, MerkleTree, + RegistrableBox, + UpgradableBox, // SDK devs want to know how to read serialized genesis block RawGenesisBlock, @@ -97,7 +99,6 @@ types!( BTreeSet, BTreeSet, BTreeSet, - BTreeSet>, BatchedResponse, BatchedResponse>, BlockHeader, @@ -110,7 +111,7 @@ types!( Box, Box, BurnBox, - CommittedBlock, + SignedBlock, Conditional, ConfigurationEvent, ConstString, @@ -225,7 +226,7 @@ types!( Greater, Hash, HashOf>, - HashOf, + HashOf, HashOf, IdBox, IdentifiableBox, @@ -268,7 +269,7 @@ types!( Option, Option, Option>>, - Option>, + Option>, Option, Option, Option, @@ -328,12 +329,9 @@ types!( SetParameterBox, Signature, SignatureCheckCondition, - SignatureOf, SignatureOf, SignatureOf, - SignatureWrapperOf, SignatureWrapperOf, - SignaturesOf, SignaturesOf, SignedQuery, SignedTransaction, @@ -377,12 +375,8 @@ types!( Vec, VersionedBatchedResponse, VersionedBatchedResponse>, - VersionedBlockMessage, - VersionedBlockSubscriptionRequest, - VersionedCommittedBlock, - VersionedCommittedBlockWrapper, - VersionedEventMessage, - VersionedEventSubscriptionRequest, + VersionedSignedBlock, + VersionedSignedBlockWrapper, VersionedSignedQuery, VersionedSignedTransaction, WasmExecutionFail, @@ -416,11 +410,8 @@ mod tests { asset::NewAssetDefinition, block::{ error::BlockRejectionReason, - stream::{ - BlockMessage, BlockSubscriptionRequest, VersionedBlockMessage, - VersionedBlockSubscriptionRequest, - }, - BlockHeader, CommittedBlock, VersionedCommittedBlock, + stream::{BlockMessage, BlockSubscriptionRequest}, + BlockHeader, SignedBlock, VersionedSignedBlock, }, domain::NewDomain, http::{BatchedResponse, VersionedBatchedResponse}, @@ -439,7 +430,7 @@ mod tests { }, transaction::{error::TransactionLimitError, SignedTransaction, TransactionLimits}, validator::Validator, - VersionedCommittedBlockWrapper, + VersionedSignedBlockWrapper, }; use iroha_genesis::RawGenesisBlock; use iroha_primitives::{ diff --git a/tools/kagami/src/genesis.rs b/tools/kagami/src/genesis.rs index 22c64d14053..70ab9699517 100644 --- a/tools/kagami/src/genesis.rs +++ b/tools/kagami/src/genesis.rs @@ -146,7 +146,7 @@ pub fn generate_default(validator: ValidatorMode) -> color_eyre::Result::Id::from_str("alice@wonderland")?; + let alice_id = AccountId::from_str("alice@wonderland")?; let mint = MintBox::new( 13_u32.to_value(), IdBox::AssetId(AssetId::new("rose#wonderland".parse()?, alice_id.clone())), diff --git a/tools/kura_inspector/src/main.rs b/tools/kura_inspector/src/main.rs index 1840558e05c..8f0fda6a01a 100644 --- a/tools/kura_inspector/src/main.rs +++ b/tools/kura_inspector/src/main.rs @@ -8,7 +8,7 @@ use std::path::{Path, PathBuf}; use clap::{Parser, Subcommand}; use iroha_core::kura::{BlockIndex, BlockStore, LockStatus}; -use iroha_data_model::block::VersionedCommittedBlock; +use iroha_data_model::block::VersionedSignedBlock; use iroha_version::scale::DecodeVersioned; /// Kura inspector @@ -136,7 +136,7 @@ fn print_blockchain(block_store_path: &Path, from_height: u64, block_count: u64) block_store .read_block_data(idx.start, &mut block_buf) .expect(&format!("Failed to read block № {} data.", meta_index + 1)); - let block = VersionedCommittedBlock::decode_all_versioned(&block_buf) + let block = VersionedSignedBlock::decode_all_versioned(&block_buf) .expect(&format!("Failed to decode block № {}", meta_index + 1)); println!("Block#{} :", meta_index + 1); println!("{block:#?}"); diff --git a/tools/parity_scale_decoder/src/main.rs b/tools/parity_scale_decoder/src/main.rs index fb5df8a7956..7f432285715 100644 --- a/tools/parity_scale_decoder/src/main.rs +++ b/tools/parity_scale_decoder/src/main.rs @@ -24,11 +24,8 @@ use iroha_data_model::{ asset::NewAssetDefinition, block::{ error::BlockRejectionReason, - stream::{ - BlockMessage, BlockSubscriptionRequest, VersionedBlockMessage, - VersionedBlockSubscriptionRequest, - }, - BlockHeader, CommittedBlock, VersionedCommittedBlock, + stream::{BlockMessage, BlockSubscriptionRequest}, + BlockHeader, SignedBlock, VersionedSignedBlock, }, domain::NewDomain, http::{BatchedResponse, VersionedBatchedResponse}, @@ -47,7 +44,7 @@ use iroha_data_model::{ }, transaction::{error::TransactionLimitError, SignedTransaction, TransactionLimits}, validator::Validator, - VersionedCommittedBlockWrapper, + VersionedSignedBlockWrapper, }; use iroha_primitives::{ addr::{Ipv4Addr, Ipv6Addr}, @@ -265,13 +262,12 @@ mod tests { #[test] fn decode_trigger_sample() { - let account_id = - ::Id::from_str("alice@wonderland").expect("Valid"); - let rose_definition_id = ::Id::new( + let account_id = AccountId::from_str("alice@wonderland").expect("Valid"); + let rose_definition_id = AssetDefinitionId::new( "rose".parse().expect("Valid"), "wonderland".parse().expect("Valid"), ); - let rose_id = ::Id::new(rose_definition_id, account_id.clone()); + let rose_id = AssetId::new(rose_definition_id, account_id.clone()); let trigger_id = "mint_rose".parse().expect("Valid"); let action = Action::::new( vec![MintBox::new(1_u32, rose_id)], From 2f3b134aadaa49e361017f43b906555705f6c79e Mon Sep 17 00:00:00 2001 From: BAStos525 <66615487+BAStos525@users.noreply.github.com> Date: Wed, 20 Sep 2023 12:34:27 +0300 Subject: [PATCH 08/55] [ci] #3849: Fix stable/lts configs pushing job (#3894) Signed-off-by: BAStos525 --- .github/workflows/iroha2-release.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/iroha2-release.yml b/.github/workflows/iroha2-release.yml index e19fb17f9ce..596e97b6239 100644 --- a/.github/workflows/iroha2-release.yml +++ b/.github/workflows/iroha2-release.yml @@ -59,22 +59,23 @@ jobs: runs-on: ubuntu-latest container: image: hyperledger/iroha2-ci:nightly-2023-06-25 + permissions: + contents: write steps: - uses: actions/checkout@v3 with: ref: iroha2-dev - - name: Setup git config - run: | - cd .git - git config --local user.name "sorabot" - git config --local user.email "<>" + token: ${{ secrets.G_ACCESS_TOKEN }} - name: Update configs run: | ./scripts/update_configs.sh lts ./scripts/update_configs.sh stable - name: Commit config changes - run: | - git config --global --add safe.directory /__w/iroha/iroha - git add -A - git diff-index --quiet HEAD || git commit -m "[documentation]: Update lts/stable configs following a release" --signoff - git push origin iroha2-dev + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: '[documentation]: Update lts/stable configs following a release' + branch: iroha2-dev + commit_options: '--signoff' + commit_user_name: sorabot + commit_user_email: <> + commit_author: sorabot From 9f77e553d15bdfc5b0131c28ae9c1a559911f36a Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Wed, 20 Sep 2023 15:25:08 +0300 Subject: [PATCH 09/55] [ci] #3622: Use cargo manifest lints instead of unmaintained cargo-lints Since the implementation of rust-lang/rfcs#3389, it is now possible to specify workspace-level lints for rustc and clippy. This PR updates the cargo configuration and CI to use this new feature instead of cargo-lints. Note that it was only stabilized in `nightly-2023-09-10`. Using it with out current toolchain requires either a -Zlints flag or a modification to `.cargo/config.toml`: ``` [unstable] lints = true ``` Note that unlike the original suggestion in #3622, this doesn't make the lints crate level, but merely replaces a clunky unmaintained tool with a standard solution for configuring lints. In particular this PR: - Removes old lints.toml configuration files for cargo-lints - Adds [lint] tables to Cargo.toml of the root and wasm workspaces. The lints are duplicated between the two - Replaces `cargo lints clippy` invocations with `cargo clippy -Zlints` in CI scripts - Silences/fixes some new lints that popped up due to differences in how between `cargo lints` and workspaces - Does a drive-by fix to iroha_genesis: it now too shares cargo metadata as do other crates Signed-off-by: Nikita Strygin --- .github/workflows/iroha2-dev-pr-static.yml | 4 +- .github/workflows/iroha2-dev-pr-wasm.yaml | 2 +- Cargo.toml | 152 +++++++++++++++++++ Dockerfile.build | 1 - Dockerfile.build.glibc | 1 - cli/Cargo.toml | 3 + cli/derive/Cargo.toml | 3 + client/Cargo.toml | 3 + client_cli/Cargo.toml | 3 + config/Cargo.toml | 3 + config/base/Cargo.toml | 3 + config/base/derive/Cargo.toml | 3 + core/Cargo.toml | 3 + crypto/Cargo.toml | 3 + crypto/src/lib.rs | 2 + data_model/Cargo.toml | 3 + data_model/derive/Cargo.toml | 3 + data_model/src/lib.rs | 2 + dsl/Cargo.toml | 12 +- dsl/src/lib.rs | 3 + ffi/Cargo.toml | 3 + ffi/derive/Cargo.toml | 3 + futures/Cargo.toml | 3 + futures/derive/Cargo.toml | 3 + genesis/Cargo.toml | 12 +- lints.toml | 167 --------------------- logger/Cargo.toml | 3 + macro/Cargo.toml | 3 + macro/derive/Cargo.toml | 3 + p2p/Cargo.toml | 3 + primitives/Cargo.toml | 4 +- schema/Cargo.toml | 3 + schema/derive/Cargo.toml | 3 + schema/gen/Cargo.toml | 3 + substrate/Cargo.toml | 3 + telemetry/Cargo.toml | 3 + telemetry/derive/Cargo.toml | 3 + tools/kagami/Cargo.toml | 3 + tools/kagami/src/main.rs | 3 +- tools/kura_inspector/Cargo.toml | 3 + tools/parity_scale_decoder/Cargo.toml | 3 + tools/swarm/Cargo.toml | 3 + tools/swarm/src/main.rs | 2 + tools/wasm_builder_cli/Cargo.toml | 2 + tools/wasm_builder_cli/src/main.rs | 2 + version/Cargo.toml | 3 + version/derive/Cargo.toml | 3 + wasm/Cargo.toml | 152 +++++++++++++++++++ wasm/derive/Cargo.toml | 3 + wasm/lints.toml | 1 - wasm/trigger/Cargo.toml | 3 + wasm/trigger/derive/Cargo.toml | 3 + wasm/validator/Cargo.toml | 3 + wasm/validator/derive/Cargo.toml | 3 + wasm/validator/src/permission.rs | 4 + wasm_builder/Cargo.toml | 3 + wasm_codec/Cargo.toml | 2 + wasm_codec/derive/Cargo.toml | 3 + 58 files changed, 463 insertions(+), 181 deletions(-) delete mode 100644 lints.toml delete mode 120000 wasm/lints.toml diff --git a/.github/workflows/iroha2-dev-pr-static.yml b/.github/workflows/iroha2-dev-pr-static.yml index 4c84fedb4f6..88b71c134c7 100644 --- a/.github/workflows/iroha2-dev-pr-static.yml +++ b/.github/workflows/iroha2-dev-pr-static.yml @@ -32,10 +32,10 @@ jobs: run: cargo fmt --all -- --check - name: Lints without features if: always() - run: cargo lints clippy --workspace --benches --tests --examples --no-default-features --quiet + run: cargo clippy -Zlints --workspace --benches --tests --examples --no-default-features --quiet - name: Lints with all features enabled if: always() - run: cargo lints clippy --workspace --benches --tests --examples --all-features --quiet + run: cargo clippy -Zlints --workspace --benches --tests --examples --all-features --quiet - name: Documentation if: always() run: cargo doc --no-deps --quiet diff --git a/.github/workflows/iroha2-dev-pr-wasm.yaml b/.github/workflows/iroha2-dev-pr-wasm.yaml index ca9f785c51c..d78d1d03e2c 100644 --- a/.github/workflows/iroha2-dev-pr-wasm.yaml +++ b/.github/workflows/iroha2-dev-pr-wasm.yaml @@ -35,7 +35,7 @@ jobs: run: cargo fmt --all -- --check - name: Lints if: always() - run: cargo lints clippy --workspace --benches --tests --examples --quiet + run: cargo clippy -Zlints --workspace --benches --tests --examples --quiet - name: Documentation if: always() run: cargo doc --no-deps --quiet diff --git a/Cargo.toml b/Cargo.toml index e9717ddedd8..cfad00e687a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -130,6 +130,158 @@ serde_with = { version = "2.2.0", default-features = false } parity-scale-codec = { version = "3.2.1", default-features = false } json5 = "0.4.1" +[workspace.lints] +rust.anonymous_parameters = "deny" + +# lower the priority to allow overriding later +clippy.pedantic = { level = "deny", priority = -1 } +clippy.all = { level = "deny", priority = -1 } +clippy.dbg_macro = "deny" + +# clippy.nursery = "deny" +clippy.debug_assert_with_mut_call = "deny" +clippy.derive_partial_eq_without_eq = "deny" +clippy.empty_line_after_outer_attr = "deny" +clippy.fallible_impl_from = "deny" +clippy.future_not_send = "deny" +clippy.iter_with_drain = "deny" +clippy.mutex_integer = "deny" +clippy.needless_collect = "deny" +clippy.path_buf_push_overwrite = "deny" +clippy.suboptimal_flops = "deny" +clippy.trailing_empty_array = "deny" +clippy.transmute_undefined_repr = "deny" +clippy.trivial_regex = "deny" +clippy.unused_peekable = "deny" +clippy.unused_rounding = "deny" + +rust.future_incompatible = "deny" +rust.missing_copy_implementations = "deny" +rust.missing_docs = "deny" +rust.nonstandard_style = "deny" +rust.private_doc_tests = "deny" +rust.rust_2018_idioms = "deny" +rust.trivial_casts = "deny" +rust.trivial_numeric_casts = "deny" +rust.unconditional_recursion = "deny" +rust.unsafe_code = "deny" +rust.unused = "deny" +rust.unused_import_braces = "deny" +rust.variant_size_differences = "deny" +rust.unused_tuple_struct_fields = "deny" +rust.explicit_outlives_requirements = "deny" +rust.non_ascii_idents = "deny" +# TODO: reenable +# rust.unreachable_pub = "deny" +# rust.unsafe_op_in_unsafe_fn = "deny" + +# These are up to personal taste. We don't want these to be enabled ever. +clippy.string_add = "allow" +clippy.as_conversions = "allow" +clippy.else_if_without_else = "allow" +clippy.enum_glob_use = "allow" +clippy.exhaustive_enums = "allow" +clippy.exhaustive_structs = "allow" +clippy.implicit_return = "allow" +clippy.inconsistent_struct_constructor = "allow" +clippy.indexing_slicing = "allow" +clippy.arithmetic_side_effects = "allow" +clippy.let_underscore_must_use = "allow" +clippy.match_wildcard_for_single_variants = "allow" +clippy.missing_docs_in_private_items = "allow" +clippy.module_name_repetitions = "allow" +clippy.shadow_reuse = "allow" +clippy.shadow_same = "allow" + +# These are normally decisions, which need to be audited by a human. +clippy.unwrap_in_result = "allow" +clippy.expect_used = "allow" +clippy.unreachable = "allow" +clippy.wildcard_enum_match_arm = "allow" +clippy.wildcard_imports = "allow" +# Our preferred style. +clippy.non-ascii-literal = "allow" +clippy.std_instead_of_core = "allow" + +# This lint could be useful in theory. The trade-off of making +# refactoring away from references difficult isn't worth it in all +# cases, so if it is enabled, it should be enabled locally. +clippy.pattern_type_mismatch = "allow" + +# Style guide. +clippy.mod-module-files = "allow" +clippy.separated-literal-suffix = "allow" +# Most trybuild code triggers a false-positive. + +# Not all public items should be inline. We only inline **trivial** functions. +clippy.missing_inline_in_public_items = "allow" + +# --- Re-enable candidates ----- + +# Lots of false-positives. +clippy.self-named-module-files = "allow" +clippy.manual_let_else = "allow" + +# We often need to shadow the name of the method to specialise. +# As soon as trait specialisation is stable we need to remove it. +clippy.same_name_method = "allow" +clippy.pub_use = "allow" + +# Style guide candidate. Explicitly converting the return value to +# () is good for refactoring, and if there is necessary +# processing of the data returned by a function, it should +# **really** be marked as #[must_use] +clippy.semicolon_if_nothing_returned = "allow" + +# This lint has way too many false-positives, so even enabling it +# as a warning is too much. Instead prefer adding explicit +# `#[deny]` directives +clippy.must_use_candidate = "allow" + +# Unstable and many false-positives +## https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn +clippy.missing_const_for_fn = "allow" + +# Too much affected code. Often impossible to apply suggestion on stable rust. +rust.elided_lifetimes_in_paths = "allow" + +# This lint produces a lot of false positives. Recommend local #[deny] directives +clippy.use_self = "allow" + +# We don't want to manually deny every `clippy.restriction.*` lint. +clippy.blanket-clippy-restriction-lints = "allow" + +# A lot of false-positive. +clippy.partial_pub_fields = "allow" + +# Should be enabled per trait impl rather than globally. +clippy.missing_trait_methods = "allow" + +# We allow this and deny `clippy.semicolon_inside_block`. +clippy.semicolon_outside_block = "allow" + +# It is debatable whether it's actually easier to read, +# additionally, not all patterns are covered by the inlined syntax +clippy.uninlined_format_args = "allow" + +rust.unknown_lints = "warn" +# these lints were duplicated, with `allow` taking precedence +# clippy.inconsistent_struct_constructor = "warn" +# clippy.match_wildcard_for_single_variants = "warn" +# clippy.arithmetic_side_effects = "warn" +clippy.option_if_let_else = "warn" +clippy.or_fun_call = "warn" +clippy.redundant_pub_crate = "warn" +clippy.string_lit_as_bytes = "warn" +clippy.suspicious_operation_groupings = "warn" +clippy.useless_let_if_seq = "warn" + +# unstable +# rust.non_exhaustive_omitted_patterns = "warn" + +rust.single_use_lifetimes = "warn" +rust.unused_lifetimes = "warn" + [workspace] resolver = "2" members = [ diff --git a/Dockerfile.build b/Dockerfile.build index c2d5e7c3632..c1d97aaa77e 100644 --- a/Dockerfile.build +++ b/Dockerfile.build @@ -12,7 +12,6 @@ RUN rustup component add llvm-tools-preview clippy RUN rustup component add rust-src RUN rustup component add rustfmt RUN rustup target add wasm32-unknown-unknown -RUN cargo install cargo-lints RUN cargo install webassembly-test-runner RUN cargo install cargo-llvm-cov diff --git a/Dockerfile.build.glibc b/Dockerfile.build.glibc index 5b9ee42d4b8..8ae5ff306c0 100644 --- a/Dockerfile.build.glibc +++ b/Dockerfile.build.glibc @@ -12,7 +12,6 @@ RUN rustup component add llvm-tools-preview clippy RUN rustup component add rust-src RUN rustup component add rustfmt RUN rustup target add wasm32-unknown-unknown -RUN cargo install cargo-lints RUN cargo install webassembly-test-runner RUN cargo install cargo-llvm-cov diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 77d51e16893..ba0bd4ac4d1 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -14,6 +14,9 @@ license.workspace = true keywords.workspace = true categories.workspace = true +[lints] +workspace = true + [features] default = ["bridge", "telemetry", "schema-endpoint"] diff --git a/cli/derive/Cargo.toml b/cli/derive/Cargo.toml index 60ea4adab49..d258df86e55 100644 --- a/cli/derive/Cargo.toml +++ b/cli/derive/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/client/Cargo.toml b/client/Cargo.toml index 11b16f5d52f..64c6d60fb16 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -14,6 +14,9 @@ license.workspace = true keywords.workspace = true categories.workspace = true +[lints] +workspace = true + [badges] is-it-maintained-issue-resolution = { repository = "https://github.com/hyperledger/iroha" } is-it-maintained-open-issues = { repository = "https://github.com/hyperledger/iroha" } diff --git a/client_cli/Cargo.toml b/client_cli/Cargo.toml index b75ecf0bc3c..dd48bdddb81 100644 --- a/client_cli/Cargo.toml +++ b/client_cli/Cargo.toml @@ -14,6 +14,9 @@ license.workspace = true keywords.workspace = true categories = ["cryptography::cryptocurrencies", "command-line-utilities"] +[lints] +workspace = true + [badges] is-it-maintained-issue-resolution = { repository = "https://github.com/hyperledger/iroha" } is-it-maintained-open-issues = { repository = "https://github.com/hyperledger/iroha" } diff --git a/config/Cargo.toml b/config/Cargo.toml index 89a01d1bc68..4d0bf7dfc40 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] iroha_config_base = { workspace = true } iroha_data_model = { workspace = true } diff --git a/config/base/Cargo.toml b/config/base/Cargo.toml index 67734ac2ca7..93241f408b7 100644 --- a/config/base/Cargo.toml +++ b/config/base/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] iroha_config_derive = { workspace = true } iroha_crypto = { workspace = true, features = ["std"] } diff --git a/config/base/derive/Cargo.toml b/config/base/derive/Cargo.toml index 7b446dbe35e..8aa95845755 100644 --- a/config/base/derive/Cargo.toml +++ b/config/base/derive/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/core/Cargo.toml b/core/Cargo.toml index 30899cfc0bd..df812f281e7 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,6 +14,9 @@ license.workspace = true keywords.workspace = true categories.workspace = true +[lints] +workspace = true + [features] default = ["bridge", "cli", "telemetry"] diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index f8095874243..ab3f3a44028 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [features] default = ["std"] # Enable static linkage of the rust standard library. diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index 4a89c6c9d84..e866bb85d15 100755 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -1,5 +1,7 @@ //! This module contains structures and implementations related to the cryptographic parts of the Iroha. #![cfg_attr(not(feature = "std"), no_std)] +// in no_std some code gets cfg-ed out, so we silence the warnings +#![cfg_attr(not(feature = "std"), allow(unused, unused_tuple_struct_fields))] #![allow(clippy::arithmetic_side_effects)] #[cfg(not(feature = "std"))] diff --git a/data_model/Cargo.toml b/data_model/Cargo.toml index f5aaf21c9a0..6d7203ec735 100644 --- a/data_model/Cargo.toml +++ b/data_model/Cargo.toml @@ -8,6 +8,9 @@ authors.workspace = true license.workspace = true categories = ["cryptography::cryptocurrencies", "api-bindings"] +[lints] +workspace = true + [badges] is-it-maintained-issue-resolution = { repository = "https://github.com/hyperledger/iroha" } is-it-maintained-open-issues = { repository = "https://github.com/hyperledger/iroha" } diff --git a/data_model/derive/Cargo.toml b/data_model/derive/Cargo.toml index 0fd8e83b862..0fb3f485bbd 100644 --- a/data_model/derive/Cargo.toml +++ b/data_model/derive/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index d66a385484b..45c9791b156 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -10,6 +10,8 @@ clippy::extra_unused_lifetimes, // Thanks to `EnumKind` not knowing how to write a derive macro. clippy::items_after_test_module, // Clippy bug )] +// in no_std some code gets cfg-ed out, so we silence the warnings +#![cfg_attr(not(feature = "std"), allow(unused, unused_tuple_struct_fields))] #![cfg_attr(not(feature = "std"), no_std)] #[cfg(not(feature = "std"))] diff --git a/dsl/Cargo.toml b/dsl/Cargo.toml index 3c3adf0c2b6..7cdbd40ee01 100755 --- a/dsl/Cargo.toml +++ b/dsl/Cargo.toml @@ -1,8 +1,14 @@ [package] name = "iroha_dsl" -version = "2.0.0-pre-rc.19" -edition = "2021" -authors = ["Yasser"] + +edition.workspace = true +version.workspace = true +authors.workspace = true + +license.workspace = true + +[lints] +workspace = true [lib] proc-macro = true diff --git a/dsl/src/lib.rs b/dsl/src/lib.rs index f254dc88040..c1378c24b1d 100755 --- a/dsl/src/lib.rs +++ b/dsl/src/lib.rs @@ -1,3 +1,6 @@ +// TODO: add docs +#![allow(missing_docs)] + use std::{convert::TryFrom, iter::Peekable, str::FromStr}; use litrs::Literal; diff --git a/ffi/Cargo.toml b/ffi/Cargo.toml index 3c95a1734af..64c50507343 100644 --- a/ffi/Cargo.toml +++ b/ffi/Cargo.toml @@ -8,6 +8,9 @@ authors.workspace = true license.workspace = true categories = ["development-tools::ffi"] +[lints] +workspace = true + [features] # Enables sharing mutable references of non-robust transmutable types across FFI. # When handing out non-robust mutable references across FFI, it's possible for the caller diff --git a/ffi/derive/Cargo.toml b/ffi/derive/Cargo.toml index 9cfa904eef3..d8c320bfa11 100644 --- a/ffi/derive/Cargo.toml +++ b/ffi/derive/Cargo.toml @@ -8,6 +8,9 @@ authors.workspace = true license.workspace = true categories = ["development-tools::ffi"] +[lints] +workspace = true + [lib] proc-macro = true diff --git a/futures/Cargo.toml b/futures/Cargo.toml index a9cc5e8f75a..592064ea911 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [features] default = [] # Support lightweight telemetry, including diagnostics diff --git a/futures/derive/Cargo.toml b/futures/derive/Cargo.toml index b1850f24d02..772801c9f21 100644 --- a/futures/derive/Cargo.toml +++ b/futures/derive/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [features] default = ["telemetry"] # Support lightweight telemetry, including diagnostics diff --git a/genesis/Cargo.toml b/genesis/Cargo.toml index 32a2ec623c2..994afeb51a9 100644 --- a/genesis/Cargo.toml +++ b/genesis/Cargo.toml @@ -1,8 +1,14 @@ [package] name = "iroha_genesis" -version = "2.0.0-pre-rc.19" -authors = ["Iroha 2 team "] -edition = "2021" + +edition.workspace = true +version.workspace = true +authors.workspace = true + +license.workspace = true + +[lints] +workspace = true [dependencies] iroha_config = { workspace = true } diff --git a/lints.toml b/lints.toml deleted file mode 100644 index b36eb51c845..00000000000 --- a/lints.toml +++ /dev/null @@ -1,167 +0,0 @@ -# For all clippy lints please visit: https://rust-lang.github.io/rust-clippy/master/ -deny = [ - 'anonymous_parameters', - 'clippy::all', - 'clippy::dbg_macro', - - # 'clippy::nursery', - 'clippy::debug_assert_with_mut_call', - 'clippy::derive_partial_eq_without_eq', - 'clippy::empty_line_after_outer_attr', - 'clippy::fallible_impl_from', - 'clippy::future_not_send', - 'clippy::iter_with_drain', - 'clippy::mutex_integer', - 'clippy::needless_collect', - 'clippy::path_buf_push_overwrite', - 'clippy::suboptimal_flops', - 'clippy::trailing_empty_array', - 'clippy::transmute_undefined_repr', - 'clippy::trivial_regex', - 'clippy::unused_peekable', - 'clippy::unused_rounding', - - 'clippy::pedantic', - 'future_incompatible', - 'missing_copy_implementations', - 'missing_docs', - 'nonstandard_style', - 'private_doc_tests', - 'rust_2018_idioms', - 'trivial_casts', - 'trivial_numeric_casts', - 'unconditional_recursion', - 'unsafe_code', - 'unused', - 'unused_import_braces', - 'variant_size_differences', - 'unused_tuple_struct_fields', - 'explicit_outlives_requirements', - 'non_ascii_idents', - # TODO: reenable - # 'unreachable_pub', - # 'unsafe_op_in_unsafe_fn', -] - -allow = [ - # These are up to personal taste. We don't want these to be enabled ever. - 'clippy::string_add', - 'unknown_lints', - 'clippy::as_conversions', - 'clippy::else_if_without_else', - 'clippy::enum_glob_use', - 'clippy::exhaustive_enums', - 'clippy::exhaustive_structs', - 'clippy::implicit_return', - 'clippy::inconsistent_struct_constructor', - 'clippy::indexing_slicing', - 'clippy::arithmetic_side_effects', - 'clippy::let_underscore_must_use', - 'clippy::match_wildcard_for_single_variants', - 'clippy::missing_docs_in_private_items', - 'clippy::module_name_repetitions', - 'clippy::pattern_type_mismatch', - 'clippy::shadow_reuse', - 'clippy::shadow_same', - - # These are normally decisions, which need to be audited by a human. - 'clippy::unwrap_in_result', - 'clippy::expect_used', - 'clippy::unreachable', - 'clippy::wildcard_enum_match_arm', - 'clippy::wildcard_imports', - # Our preferred style. - 'clippy::non-ascii-literal', - 'clippy::std_instead_of_core', - - # This lint could be useful in theory. The trade-off of making - # refactoring away from references difficult isn't worth it in all - # cases, so if it is enabled, it should be enabled locally. - 'clippy::pattern_type_mismatch', - - # Style guide. - 'clippy::mod-module-files', - 'clippy::separated-literal-suffix', - # Most trybuild code triggers a false-positive. - - # Not all public items should be inline. We only inline **trivial** functions. - 'clippy::missing_inline_in_public_items', - - 'unknown_lints', - - # --- Re-enable candidates ----- - - # Lots of false-positives. - 'clippy::self-named-module-files', - 'clippy::manual_let_else', - - # We often need to shadow the name of the method to specialise. - # As soon as trait specialisation is stable we need to remove it. - 'clippy::same_name_method', - 'clippy::pub_use', - - # Style guide candidate. Explicitly converting the return value to - # () is good for refactoring, and if there is necessary - # processing of the data returned by a function, it should - # **really** be marked as #[must_use] - 'clippy::semicolon_if_nothing_returned', - - # This lint has way too many false-positives, so even enabling it - # as a warning is too much. Instead prefer adding explicit - # `#[deny]` directives - 'clippy::must_use_candidate', - - # Unstable and many false-positives - ## https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn - 'clippy::missing_const_for_fn', - - # Too much affected code. Often impossible to apply suggestion on stable rust. - 'elided_lifetimes_in_paths', - - # This lint produces a lot of false positives. Recommend local #[deny] directives - 'clippy::use_self', - - # We don't want to manually deny every `clippy::restriction::*` lint. - 'clippy::blanket-clippy-restriction-lints', - - # A lot of false-positive. - 'clippy::partial_pub_fields', - - # Should be enabled per trait impl rather than globally. - 'clippy::missing_trait_methods', - - # We allow this and deny `clippy::semicolon_inside_block`. - 'clippy::semicolon_outside_block', - - # It is debatable whether it's actually easier to read, - # additionally, not all patterns are covered by the inlined syntax - 'clippy::uninlined_format_args', -] - -warn = [ - # These are lints which should really be conveyed to the author, - # but not necessarily fixed. - - 'unknown_lints', - 'clippy::inconsistent_struct_constructor', - 'clippy::match_wildcard_for_single_variants', - 'clippy::arithmetic_side_effects', - 'clippy::option_if_let_else', - 'clippy::or_fun_call', - 'clippy::redundant_pub_crate', - 'clippy::string_lit_as_bytes', - 'clippy::suspicious_operation_groupings', - 'clippy::useless_let_if_seq', - - # unstable - # 'non_exhaustive_omitted_patterns', - - 'single_use_lifetimes', - 'unused_lifetimes', - - # A couple of false positives. - # 'unused_qualifications', - - # Lots of false-positives. - # 'unused_crate_dependencies', -] diff --git a/logger/Cargo.toml b/logger/Cargo.toml index 12e94839986..918e23bb3ba 100644 --- a/logger/Cargo.toml +++ b/logger/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] iroha_config = { workspace = true } iroha_data_model = { workspace = true } diff --git a/macro/Cargo.toml b/macro/Cargo.toml index 8fd1b71b41d..aee10f93f8b 100644 --- a/macro/Cargo.toml +++ b/macro/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [badges] is-it-maintained-issue-resolution = { repository = "https://github.com/hyperledger/iroha" } is-it-maintained-open-issues = { repository = "https://github.com/hyperledger/iroha" } diff --git a/macro/derive/Cargo.toml b/macro/derive/Cargo.toml index e7dd8d06e2a..5f09f48c489 100644 --- a/macro/derive/Cargo.toml +++ b/macro/derive/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/p2p/Cargo.toml b/p2p/Cargo.toml index 758888f1fde..d28d34b35eb 100644 --- a/p2p/Cargo.toml +++ b/p2p/Cargo.toml @@ -8,6 +8,9 @@ authors.workspace = true license.workspace = true categories = ["network-programming"] +[lints] +workspace = true + [dependencies] iroha_logger = { workspace = true } iroha_crypto = { workspace = true } diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 43ef5bbabfb..bbbd408827d 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [badges] is-it-maintained-issue-resolution = { repository = "https://github.com/hyperledger/iroha" } is-it-maintained-open-issues = { repository = "https://github.com/hyperledger/iroha" } @@ -39,7 +42,6 @@ smallstr = { version = "0.3.0", default-features = false, features = ["serde", " thiserror = { workspace = true, optional = true } displaydoc = { workspace = true } - [dev-dependencies] serde_json = { workspace = true, features = ["alloc"] } trybuild = { workspace = true } diff --git a/schema/Cargo.toml b/schema/Cargo.toml index d696b5c0426..d118ec66407 100644 --- a/schema/Cargo.toml +++ b/schema/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] iroha_schema_derive = { workspace = true } diff --git a/schema/derive/Cargo.toml b/schema/derive/Cargo.toml index fa2fea8a9bf..d17a56721ee 100644 --- a/schema/derive/Cargo.toml +++ b/schema/derive/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/schema/gen/Cargo.toml b/schema/gen/Cargo.toml index f231c08239b..53e89aa94b1 100644 --- a/schema/gen/Cargo.toml +++ b/schema/gen/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] iroha_genesis = { workspace = true } iroha_primitives = { workspace = true } diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index f1ce840ced3..184b9e572ac 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -7,4 +7,7 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] diff --git a/telemetry/Cargo.toml b/telemetry/Cargo.toml index d63dd4f830f..6a3e7ae10de 100644 --- a/telemetry/Cargo.toml +++ b/telemetry/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [features] # Support developer-specific telemetry. # Should not be enabled on production builds. diff --git a/telemetry/derive/Cargo.toml b/telemetry/derive/Cargo.toml index 6348a5683a7..b2c53970a87 100644 --- a/telemetry/derive/Cargo.toml +++ b/telemetry/derive/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/tools/kagami/Cargo.toml b/tools/kagami/Cargo.toml index 8d3830559c9..7a4d4145ecf 100644 --- a/tools/kagami/Cargo.toml +++ b/tools/kagami/Cargo.toml @@ -9,6 +9,9 @@ description = "A tool used to generate cryptographic keys, docs, the schema and license.workspace = true +[lints] +workspace = true + [dependencies] iroha_crypto = { workspace = true } iroha_config = { workspace = true } diff --git a/tools/kagami/src/main.rs b/tools/kagami/src/main.rs index b869fbd8c20..f5f56789939 100644 --- a/tools/kagami/src/main.rs +++ b/tools/kagami/src/main.rs @@ -4,7 +4,8 @@ #![allow( clippy::arithmetic_side_effects, clippy::std_instead_of_core, - clippy::std_instead_of_alloc + clippy::std_instead_of_alloc, + missing_docs )] use std::{ io::{stdout, BufWriter, Write}, diff --git a/tools/kura_inspector/Cargo.toml b/tools/kura_inspector/Cargo.toml index 8833be01cc0..31854303380 100644 --- a/tools/kura_inspector/Cargo.toml +++ b/tools/kura_inspector/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] iroha_core = { workspace = true } iroha_version = { workspace = true } diff --git a/tools/parity_scale_decoder/Cargo.toml b/tools/parity_scale_decoder/Cargo.toml index 42dfb4747d3..34458b12eb4 100644 --- a/tools/parity_scale_decoder/Cargo.toml +++ b/tools/parity_scale_decoder/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [features] # Disable colour for all program output. # Useful for Docker-based deployment and terminals without colour support. diff --git a/tools/swarm/Cargo.toml b/tools/swarm/Cargo.toml index cbd4508bf93..1500d1526b4 100644 --- a/tools/swarm/Cargo.toml +++ b/tools/swarm/Cargo.toml @@ -6,6 +6,9 @@ version.workspace = true authors.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] iroha_crypto.workspace = true iroha_data_model.workspace = true diff --git a/tools/swarm/src/main.rs b/tools/swarm/src/main.rs index bcd4a2b297e..18e83f64be9 100644 --- a/tools/swarm/src/main.rs +++ b/tools/swarm/src/main.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + mod cli; mod compose; mod ui; diff --git a/tools/wasm_builder_cli/Cargo.toml b/tools/wasm_builder_cli/Cargo.toml index 51f4d0e0e56..2cd39c40274 100644 --- a/tools/wasm_builder_cli/Cargo.toml +++ b/tools/wasm_builder_cli/Cargo.toml @@ -6,6 +6,8 @@ version.workspace = true authors.workspace = true license.workspace = true +[lints] +workspace = true [dependencies] iroha_wasm_builder.workspace = true diff --git a/tools/wasm_builder_cli/src/main.rs b/tools/wasm_builder_cli/src/main.rs index dde4bd00e49..4ecd5a589ce 100644 --- a/tools/wasm_builder_cli/src/main.rs +++ b/tools/wasm_builder_cli/src/main.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use std::path::PathBuf; use clap::{Args, Parser}; diff --git a/version/Cargo.toml b/version/Cargo.toml index 91041519a36..89b396ff8a9 100644 --- a/version/Cargo.toml +++ b/version/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [features] default = ["std", "derive", "scale", "json"] # Enable static linkage of the rust standard library. diff --git a/version/derive/Cargo.toml b/version/derive/Cargo.toml index 5667539058d..be02b1e5acf 100644 --- a/version/derive/Cargo.toml +++ b/version/derive/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 0320c154c9a..ecc18d3b244 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -30,6 +30,158 @@ proc-macro2 = "1.0.49" webassembly-test = "0.1.0" +[workspace.lints] +rust.anonymous_parameters = "deny" + +# lower the priority to allow overriding later +clippy.pedantic = { level = "deny", priority = -1 } +clippy.all = { level = "deny", priority = -1 } +clippy.dbg_macro = "deny" + +# clippy.nursery = "deny" +clippy.debug_assert_with_mut_call = "deny" +clippy.derive_partial_eq_without_eq = "deny" +clippy.empty_line_after_outer_attr = "deny" +clippy.fallible_impl_from = "deny" +clippy.future_not_send = "deny" +clippy.iter_with_drain = "deny" +clippy.mutex_integer = "deny" +clippy.needless_collect = "deny" +clippy.path_buf_push_overwrite = "deny" +clippy.suboptimal_flops = "deny" +clippy.trailing_empty_array = "deny" +clippy.transmute_undefined_repr = "deny" +clippy.trivial_regex = "deny" +clippy.unused_peekable = "deny" +clippy.unused_rounding = "deny" + +rust.future_incompatible = "deny" +rust.missing_copy_implementations = "deny" +rust.missing_docs = "deny" +rust.nonstandard_style = "deny" +rust.private_doc_tests = "deny" +rust.rust_2018_idioms = "deny" +rust.trivial_casts = "deny" +rust.trivial_numeric_casts = "deny" +rust.unconditional_recursion = "deny" +rust.unsafe_code = "deny" +rust.unused = "deny" +rust.unused_import_braces = "deny" +rust.variant_size_differences = "deny" +rust.unused_tuple_struct_fields = "deny" +rust.explicit_outlives_requirements = "deny" +rust.non_ascii_idents = "deny" +# TODO: reenable +# rust.unreachable_pub = "deny" +# rust.unsafe_op_in_unsafe_fn = "deny" + +# These are up to personal taste. We don't want these to be enabled ever. +clippy.string_add = "allow" +clippy.as_conversions = "allow" +clippy.else_if_without_else = "allow" +clippy.enum_glob_use = "allow" +clippy.exhaustive_enums = "allow" +clippy.exhaustive_structs = "allow" +clippy.implicit_return = "allow" +clippy.inconsistent_struct_constructor = "allow" +clippy.indexing_slicing = "allow" +clippy.arithmetic_side_effects = "allow" +clippy.let_underscore_must_use = "allow" +clippy.match_wildcard_for_single_variants = "allow" +clippy.missing_docs_in_private_items = "allow" +clippy.module_name_repetitions = "allow" +clippy.shadow_reuse = "allow" +clippy.shadow_same = "allow" + +# These are normally decisions, which need to be audited by a human. +clippy.unwrap_in_result = "allow" +clippy.expect_used = "allow" +clippy.unreachable = "allow" +clippy.wildcard_enum_match_arm = "allow" +clippy.wildcard_imports = "allow" +# Our preferred style. +clippy.non-ascii-literal = "allow" +clippy.std_instead_of_core = "allow" + +# This lint could be useful in theory. The trade-off of making +# refactoring away from references difficult isn't worth it in all +# cases, so if it is enabled, it should be enabled locally. +clippy.pattern_type_mismatch = "allow" + +# Style guide. +clippy.mod-module-files = "allow" +clippy.separated-literal-suffix = "allow" +# Most trybuild code triggers a false-positive. + +# Not all public items should be inline. We only inline **trivial** functions. +clippy.missing_inline_in_public_items = "allow" + +# --- Re-enable candidates ----- + +# Lots of false-positives. +clippy.self-named-module-files = "allow" +clippy.manual_let_else = "allow" + +# We often need to shadow the name of the method to specialise. +# As soon as trait specialisation is stable we need to remove it. +clippy.same_name_method = "allow" +clippy.pub_use = "allow" + +# Style guide candidate. Explicitly converting the return value to +# () is good for refactoring, and if there is necessary +# processing of the data returned by a function, it should +# **really** be marked as #[must_use] +clippy.semicolon_if_nothing_returned = "allow" + +# This lint has way too many false-positives, so even enabling it +# as a warning is too much. Instead prefer adding explicit +# `#[deny]` directives +clippy.must_use_candidate = "allow" + +# Unstable and many false-positives +## https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn +clippy.missing_const_for_fn = "allow" + +# Too much affected code. Often impossible to apply suggestion on stable rust. +rust.elided_lifetimes_in_paths = "allow" + +# This lint produces a lot of false positives. Recommend local #[deny] directives +clippy.use_self = "allow" + +# We don't want to manually deny every `clippy.restriction.*` lint. +clippy.blanket-clippy-restriction-lints = "allow" + +# A lot of false-positive. +clippy.partial_pub_fields = "allow" + +# Should be enabled per trait impl rather than globally. +clippy.missing_trait_methods = "allow" + +# We allow this and deny `clippy.semicolon_inside_block`. +clippy.semicolon_outside_block = "allow" + +# It is debatable whether it's actually easier to read, +# additionally, not all patterns are covered by the inlined syntax +clippy.uninlined_format_args = "allow" + +rust.unknown_lints = "warn" +# these lints were duplicated, with `allow` taking precedence +# clippy.inconsistent_struct_constructor = "warn" +# clippy.match_wildcard_for_single_variants = "warn" +# clippy.arithmetic_side_effects = "warn" +clippy.option_if_let_else = "warn" +clippy.or_fun_call = "warn" +clippy.redundant_pub_crate = "warn" +clippy.string_lit_as_bytes = "warn" +clippy.suspicious_operation_groupings = "warn" +clippy.useless_let_if_seq = "warn" + +# unstable +# rust.non_exhaustive_omitted_patterns = "warn" + +rust.single_use_lifetimes = "warn" +rust.unused_lifetimes = "warn" + [package] name = "iroha_wasm" diff --git a/wasm/derive/Cargo.toml b/wasm/derive/Cargo.toml index aea05d5be96..42aa8006f4a 100644 --- a/wasm/derive/Cargo.toml +++ b/wasm/derive/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/wasm/lints.toml b/wasm/lints.toml deleted file mode 120000 index 883d2da34b1..00000000000 --- a/wasm/lints.toml +++ /dev/null @@ -1 +0,0 @@ -../lints.toml \ No newline at end of file diff --git a/wasm/trigger/Cargo.toml b/wasm/trigger/Cargo.toml index 117b4585933..f14c79c46df 100644 --- a/wasm/trigger/Cargo.toml +++ b/wasm/trigger/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [features] # Enables debugging tools such as `dbg()` and `DebugUnwrapExt` debug = ["iroha_wasm/debug"] diff --git a/wasm/trigger/derive/Cargo.toml b/wasm/trigger/derive/Cargo.toml index 2dedb97d33c..05feb5bd61e 100644 --- a/wasm/trigger/derive/Cargo.toml +++ b/wasm/trigger/derive/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/wasm/validator/Cargo.toml b/wasm/validator/Cargo.toml index 607f70bc836..e9454e6c78a 100644 --- a/wasm/validator/Cargo.toml +++ b/wasm/validator/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [features] # Enables debugging tools such as `dbg()` and `DebugUnwrapExt` debug = ["iroha_wasm/debug"] diff --git a/wasm/validator/derive/Cargo.toml b/wasm/validator/derive/Cargo.toml index 19eb1ea27da..04f6438d9f1 100644 --- a/wasm/validator/derive/Cargo.toml +++ b/wasm/validator/derive/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/wasm/validator/src/permission.rs b/wasm/validator/src/permission.rs index 300e7c8e5d2..6d6bb263f72 100644 --- a/wasm/validator/src/permission.rs +++ b/wasm/validator/src/permission.rs @@ -84,6 +84,7 @@ pub mod asset { /// Pass condition that checks if `authority` is the owner of `asset_id`. #[derive(Debug, Clone)] pub struct Owner<'asset> { + /// Asset id to check against pub asset_id: &'asset AssetId, } @@ -115,6 +116,7 @@ pub mod asset_definition { /// Pass condition that checks if `authority` is the owner of `asset_definition_id`. #[derive(Debug, Clone)] pub struct Owner<'asset_definition> { + /// Asset definition id to check against pub asset_definition_id: &'asset_definition AssetDefinitionId, } @@ -139,6 +141,7 @@ pub mod account { /// Pass condition that checks if `authority` is the owner of `account_id`. #[derive(Debug, Clone)] pub struct Owner<'asset> { + /// Account id to check against pub account_id: &'asset AccountId, } @@ -175,6 +178,7 @@ pub mod trigger { /// Pass condition that checks if `authority` is the owner of `trigger_id`. #[derive(Debug, Clone)] pub struct Owner<'trigger> { + /// Trigger id to check against pub trigger_id: &'trigger TriggerId, } diff --git a/wasm_builder/Cargo.toml b/wasm_builder/Cargo.toml index 64954992991..f7abb4db419 100644 --- a/wasm_builder/Cargo.toml +++ b/wasm_builder/Cargo.toml @@ -8,6 +8,9 @@ authors.workspace = true license.workspace = true categories = ["development-tools::build-utils"] +[lints] +workspace = true + [dependencies] eyre = { workspace = true } serde_json = { workspace = true, features = ["std"] } diff --git a/wasm_codec/Cargo.toml b/wasm_codec/Cargo.toml index 302bcad24ea..e75b860c9e5 100644 --- a/wasm_codec/Cargo.toml +++ b/wasm_codec/Cargo.toml @@ -6,6 +6,8 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true [dependencies] iroha_core_wasm_codec_derive = { version = "=2.0.0-pre-rc.19", path = "derive" } diff --git a/wasm_codec/derive/Cargo.toml b/wasm_codec/derive/Cargo.toml index 5cbc4f6dbc4..27119faf744 100644 --- a/wasm_codec/derive/Cargo.toml +++ b/wasm_codec/derive/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true license.workspace = true +[lints] +workspace = true + [lib] proc-macro = true From 389eb2878cc6dc56223d86fdd09be9aa818eba67 Mon Sep 17 00:00:00 2001 From: 0x009922 Date: Thu, 21 Sep 2023 19:10:43 +0700 Subject: [PATCH 10/55] [fix]: `mkdir -r` with store path, not lock path (#3908) * [fix]: `mkdir -r` with store path, not lock path Signed-off-by: Dmitry Balashov * [fix]: use `store_path` in the err Signed-off-by: Dmitry Balashov * [refactor]: `&` Signed-off-by: Dmitry Balashov * [refactor]: apply lint Signed-off-by: Dmitry Balashov --------- Signed-off-by: Dmitry Balashov --- core/src/kura.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/kura.rs b/core/src/kura.rs index 80fa8975744..28f5515ada8 100644 --- a/core/src/kura.rs +++ b/core/src/kura.rs @@ -413,20 +413,20 @@ impl BlockStore { /// /// # Panics /// * if you pass in `LockStatus::Unlocked` and it is unable to lock the block store. - pub fn new(path: &Path, already_locked: LockStatus) -> Self { + pub fn new(store_path: &Path, already_locked: LockStatus) -> Self { if matches!(already_locked, LockStatus::Unlocked) { - let path = path.join(LOCK_FILE_NAME); + let lock_path = store_path.join(LOCK_FILE_NAME); if let Err(e) = fs::File::options() .read(true) .write(true) .create_new(true) - .open(path.clone()) + .open(&lock_path) { match e.kind() { - std::io::ErrorKind::AlreadyExists => Err(Error::Locked(path)), + std::io::ErrorKind::AlreadyExists => Err(Error::Locked(lock_path)), std::io::ErrorKind::NotFound => { - match std::fs::create_dir_all(&path) - .map_err(|e| Error::MkDir(e, path.clone())) + match std::fs::create_dir_all(store_path) + .map_err(|e| Error::MkDir(e, store_path.to_path_buf())) { Err(e) => Err(e), Ok(_) => { @@ -434,22 +434,22 @@ impl BlockStore { .read(true) .write(true) .create_new(true) - .open(path.clone()) + .open(&lock_path) { - Err(Error::IO(e, path)) + Err(Error::IO(e, lock_path)) } else { Ok(()) } } } } - _ => Err(Error::IO(e, path)), + _ => Err(Error::IO(e, lock_path)), } .expect("Kura must be able to lock the blockstore"); } } BlockStore { - path_to_blockchain: path.to_path_buf(), + path_to_blockchain: store_path.to_path_buf(), } } From 867fc377f2588ab8fb0f86946f0bb6ff81a1c6c7 Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Fri, 22 Sep 2023 12:20:13 +0300 Subject: [PATCH 11/55] [fix] #3906: Fix wasm memory leak Signed-off-by: Shanin Roman --- Cargo.lock | 12 ++++++------ configs/peer/validator.wasm | Bin 492656 -> 493320 bytes core/src/smartcontracts/wasm.rs | 4 +++- core/src/validator.rs | 6 ++++-- wasm/Cargo.toml | 2 +- wasm/src/lib.rs | 3 ++- wasm_builder/Cargo.toml | 2 +- 7 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc139524157..35701a3bc9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6415,9 +6415,9 @@ dependencies = [ [[package]] name = "wasm-opt" -version = "0.113.0" +version = "0.114.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65a2799e08026234b07b44da6363703974e75be21430cef00756bbc438c8ff8a" +checksum = "4d005a95f934878a1fb446a816d51c3601a0120ff929005ba3bab3c749cfd1c7" dependencies = [ "anyhow", "libc", @@ -6431,9 +6431,9 @@ dependencies = [ [[package]] name = "wasm-opt-cxx-sys" -version = "0.113.0" +version = "0.114.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d26f86d1132245e8bcea8fac7f02b10fb885b6696799969c94d7d3c14db5e1" +checksum = "6d04e240598162810fad3b2e96fa0dec6dba1eb65a03f3bd99a9248ab8b56caa" dependencies = [ "anyhow", "cxx", @@ -6443,9 +6443,9 @@ dependencies = [ [[package]] name = "wasm-opt-sys" -version = "0.113.0" +version = "0.114.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497d069cd3420cdd52154a320b901114a20946878e2de62c670f9d906e472370" +checksum = "2efd2aaca519d64098c4faefc8b7433a97ed511caf4c9e516384eb6aef1ff4f9" dependencies = [ "anyhow", "cc", diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index 06c460d42c9896e7857615c8a83303e7d3970663..13671a3555766bc342a16d93d6f5fd1e2d192d4c 100644 GIT binary patch delta 156244 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⋙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 CPef4w diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 3c33390cf10..32d6e1770e7 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -186,7 +186,9 @@ pub mod error { Trap::StackOverflow | Trap::MemoryOutOfBounds | Trap::TableOutOfBounds - | Trap::IndirectCallToNull => Self::ExecutionLimitsExceeded(err), + | Trap::IndirectCallToNull + | Trap::OutOfFuel + | Trap::Interrupt => Self::ExecutionLimitsExceeded(err), _ => Self::Other(err), }, None => Self::HostExecution(err), diff --git a/core/src/validator.rs b/core/src/validator.rs index 22fec3ec897..0784bc594ff 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -27,10 +27,12 @@ impl From for ValidationFail { match call_error { ExecutionLimitsExceeded(_) => Self::TooComplex, - HostExecution(error) | Other(error) => Self::InternalError(error.to_string()), + HostExecution(error) | Other(error) => { + Self::InternalError(format!("{error:#}")) + } } } - _ => Self::InternalError(err.to_string()), + _ => Self::InternalError(format!("{err:#}")), } } } diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index ecc18d3b244..71b4c307a13 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -200,7 +200,7 @@ iroha_data_model.workspace = true iroha_wasm_derive = { version = "=2.0.0-pre-rc.19", path = "derive" } parity-scale-codec = { version = "3.1.5", default-features = false } -wee_alloc = "0.4.5" +lol_alloc = "0.4.0" [dev-dependencies] webassembly-test.workspace = true diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 74e27f17301..5f688e43fbe 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -24,13 +24,14 @@ use data_model::{ use debug::DebugExpectExt as _; pub use iroha_data_model as data_model; pub use iroha_wasm_derive::main; +use lol_alloc::{FreeListAllocator, LockedAllocator}; use parity_scale_codec::{DecodeAll, Encode}; pub mod debug; pub mod log; #[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; +static ALLOC: LockedAllocator = LockedAllocator::new(FreeListAllocator::new()); #[no_mangle] extern "C" fn _iroha_wasm_alloc(len: usize) -> *const u8 { diff --git a/wasm_builder/Cargo.toml b/wasm_builder/Cargo.toml index f7abb4db419..9d1a340e47b 100644 --- a/wasm_builder/Cargo.toml +++ b/wasm_builder/Cargo.toml @@ -16,4 +16,4 @@ eyre = { workspace = true } serde_json = { workspace = true, features = ["std"] } sha256 = "1.2.2" path-absolutize = { workspace = true } -wasm-opt = "0.113.0" +wasm-opt = "0.114.1" From 90009de9600eecd7d7abf7ebd9446d92c2679797 Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Thu, 21 Sep 2023 08:59:36 +0300 Subject: [PATCH 12/55] [fix] #3905: Fix `apply_blocks` and `validate_blocks` benchmark Signed-off-by: Shanin Roman --- core/Cargo.toml | 8 +- core/benches/apply_blocks/apply_blocks.rs | 212 ------------------ core/benches/apply_blocks/oneshot.rs | 15 -- core/benches/blocks/apply_blocks.rs | 79 +++++++ .../apply_blocks_benchmark.rs} | 0 core/benches/blocks/apply_blocks_oneshot.rs | 31 +++ .../validate_blocks.rs => blocks/common.rs} | 148 +++++------- core/benches/blocks/validate_blocks.rs | 82 +++++++ .../validate_blocks_benchmark.rs} | 0 .../benches/blocks/validate_blocks_oneshot.rs | 31 +++ core/benches/validate_blocks/oneshot.rs | 15 -- core/src/block.rs | 6 +- 12 files changed, 289 insertions(+), 338 deletions(-) delete mode 100644 core/benches/apply_blocks/apply_blocks.rs delete mode 100644 core/benches/apply_blocks/oneshot.rs create mode 100644 core/benches/blocks/apply_blocks.rs rename core/benches/{apply_blocks/benchmark.rs => blocks/apply_blocks_benchmark.rs} (100%) create mode 100644 core/benches/blocks/apply_blocks_oneshot.rs rename core/benches/{validate_blocks/validate_blocks.rs => blocks/common.rs} (67%) create mode 100644 core/benches/blocks/validate_blocks.rs rename core/benches/{validate_blocks/benchmark.rs => blocks/validate_blocks_benchmark.rs} (100%) create mode 100644 core/benches/blocks/validate_blocks_oneshot.rs delete mode 100644 core/benches/validate_blocks/oneshot.rs diff --git a/core/Cargo.toml b/core/Cargo.toml index df812f281e7..b97c91d7d3e 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -89,22 +89,22 @@ harness = false [[bench]] name = "apply_blocks" harness = false -path = "benches/apply_blocks/benchmark.rs" +path = "benches/blocks/apply_blocks_benchmark.rs" [[bench]] name = "validate_blocks" harness = false -path = "benches/validate_blocks/benchmark.rs" +path = "benches/blocks/validate_blocks_benchmark.rs" [[example]] name = "apply_blocks" harness = false -path = "benches/apply_blocks/oneshot.rs" +path = "benches/blocks/apply_blocks_oneshot.rs" [[example]] name = "validate_blocks" harness = false -path = "benches/validate_blocks/oneshot.rs" +path = "benches/blocks/validate_blocks_oneshot.rs" [package.metadata.cargo-all-features] denylist = [ diff --git a/core/benches/apply_blocks/apply_blocks.rs b/core/benches/apply_blocks/apply_blocks.rs deleted file mode 100644 index f1aea86d233..00000000000 --- a/core/benches/apply_blocks/apply_blocks.rs +++ /dev/null @@ -1,212 +0,0 @@ -#![allow(missing_docs, clippy::restriction)] - -use std::{collections::BTreeSet, str::FromStr as _}; - -use eyre::Result; -use iroha_core::{ - block::{BlockBuilder, CommittedBlock}, - prelude::*, - sumeragi::network_topology::Topology, - wsv::World, -}; -use iroha_data_model::{ - asset::{AssetDefinition, AssetDefinitionId}, - isi::InstructionBox, - prelude::*, -}; -use iroha_genesis::GenesisTransaction; - -/// Create block -fn create_block( - wsv: &mut WorldStateView, - instructions: Vec, - account_id: AccountId, - key_pair: KeyPair, -) -> CommittedBlock { - let transaction = TransactionBuilder::new(account_id) - .with_instructions(instructions) - .sign(key_pair.clone()) - .unwrap(); - - let topology = Topology::new(Vec::new()); - BlockBuilder::new( - vec![AcceptedTransaction::accept_genesis(GenesisTransaction( - transaction, - ))], - topology.clone(), - Vec::new(), - ) - .chain(0, wsv) - .sign(key_pair) - .unwrap() - .commit(&topology) - .unwrap() -} - -fn delete_every_nth( - domains: usize, - accounts_per_domain: usize, - assets_per_domain: usize, - nth: usize, -) -> Result> { - let mut instructions: Vec = Vec::new(); - for i in 0..domains { - let domain_id = DomainId::from_str(&i.to_string())?; - if i % nth == 0 { - instructions.push(UnregisterBox::new(domain_id.clone()).into()); - } else { - for j in 0..accounts_per_domain { - if j % nth == 0 { - let account_id = - AccountId::new(Name::from_str(&j.to_string())?, domain_id.clone()); - instructions.push(UnregisterBox::new(account_id.clone()).into()); - } - } - for k in 0..assets_per_domain { - if k % nth == 0 { - let asset_definition_id = - AssetDefinitionId::new(Name::from_str(&k.to_string())?, domain_id.clone()); - instructions.push(UnregisterBox::new(asset_definition_id).into()); - } - } - } - } - Ok(instructions) -} - -fn restore_every_nth( - domains: usize, - accounts_per_domain: usize, - assets_per_domain: usize, - nth: usize, -) -> Result> { - let mut instructions: Vec = Vec::new(); - for i in 0..domains { - let domain_id = DomainId::from_str(&i.to_string())?; - if i % nth == 0 { - let domain = Domain::new(domain_id.clone()); - instructions.push(RegisterBox::new(domain).into()); - } - for j in 0..accounts_per_domain { - if j % nth == 0 || i % nth == 0 { - let account_id = AccountId::new(Name::from_str(&j.to_string())?, domain_id.clone()); - let account = Account::new(account_id.clone(), []); - instructions.push(RegisterBox::new(account).into()); - } - } - for k in 0..assets_per_domain { - if k % nth == 0 || i % nth == 0 { - let asset_definition_id = - AssetDefinitionId::new(Name::from_str(&k.to_string())?, domain_id.clone()); - let asset_definition = AssetDefinition::new( - asset_definition_id, - iroha_data_model::asset::AssetValueType::Quantity, - ); - instructions.push(RegisterBox::new(asset_definition).into()); - } - } - } - Ok(instructions) -} - -fn build_wsv( - domains: usize, - accounts_per_domain: usize, - assets_per_domain: usize, - account_id: AccountId, - key_pair: KeyPair, -) -> Result { - let kura = iroha_core::kura::Kura::blank_kura_for_testing(); - let mut wsv = WorldStateView::new(World::with([], BTreeSet::new()), kura); - - let mut instructions: Vec = Vec::new(); - for i in 0..domains { - let domain_id = DomainId::from_str(&i.to_string())?; - let domain = Domain::new(domain_id.clone()); - instructions.push(RegisterBox::new(domain).into()); - for j in 0..accounts_per_domain { - let account_id = AccountId::new(Name::from_str(&j.to_string())?, domain_id.clone()); - let account = Account::new(account_id.clone(), []); - instructions.push(RegisterBox::new(account).into()); - } - for k in 0..assets_per_domain { - let asset_definition_id = - AssetDefinitionId::new(Name::from_str(&k.to_string())?, domain_id.clone()); - let asset_definition = AssetDefinition::new( - asset_definition_id, - iroha_data_model::asset::AssetValueType::Quantity, - ); - instructions.push(RegisterBox::new(asset_definition).into()); - } - } - - let block = create_block(&mut wsv, instructions, account_id, key_pair); - wsv.apply(&block)?; - Ok(wsv) -} - -pub struct WsvApplyBlocks { - wsv: WorldStateView, - blocks: Vec, -} - -impl WsvApplyBlocks { - /// Create [`WorldStateView`] and blocks for benchmarking - /// - /// # Errors - /// - Failed to parse [`AccountId`] - /// - Failed to generate [`KeyPair`] - /// - Failed to create instructions for block - pub fn setup() -> Result { - let domains = 100; - let accounts_per_domain = 1000; - let assets_per_domain = 1000; - let genesis_id: AccountId = "genesis@genesis".parse()?; - let key_pair = KeyPair::generate()?; - let mut wsv = build_wsv( - domains, - accounts_per_domain, - assets_per_domain, - genesis_id.clone(), - key_pair.clone(), - )?; - - let nth = 100; - let instructions = [ - delete_every_nth(domains, accounts_per_domain, assets_per_domain, nth), - restore_every_nth(domains, accounts_per_domain, assets_per_domain, nth), - ] - .into_iter() - .collect::, _>>()?; - - let blocks = instructions - .into_iter() - .map(|instructions| { - create_block(&mut wsv, instructions, genesis_id.clone(), key_pair.clone()) - }) - .collect(); - - Ok(Self { wsv, blocks }) - } - - /// Run benchmark body. - /// - /// # Errors - /// - Not enough blocks - /// - Failed to apply block - /// - /// # Panics - /// If wsv isn't one block ahead of finalized wsv. - pub fn measure(Self { wsv, blocks }: &Self) -> Result<()> { - let mut finalized_wsv = wsv.clone(); - let mut wsv = finalized_wsv.clone(); - - for block in blocks { - finalized_wsv = wsv.clone(); - wsv.apply(block)?; - assert_eq!(wsv.height(), finalized_wsv.height() + 1); - } - - Ok(()) - } -} diff --git a/core/benches/apply_blocks/oneshot.rs b/core/benches/apply_blocks/oneshot.rs deleted file mode 100644 index 2a2950d5371..00000000000 --- a/core/benches/apply_blocks/oneshot.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Oneshot execution of `apply_blocks` benchmark. -//! Can be useful to profile using flamegraph. -//! -//! ```bash -//! CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph --root --release --example apply_blocks -//! ``` - -mod apply_blocks; - -use apply_blocks::WsvApplyBlocks; - -fn main() { - let bench = WsvApplyBlocks::setup().expect("Failed to setup benchmark"); - WsvApplyBlocks::measure(&bench).expect("Failed to execute bnechmark"); -} diff --git a/core/benches/blocks/apply_blocks.rs b/core/benches/blocks/apply_blocks.rs new file mode 100644 index 00000000000..50c6ba37b5e --- /dev/null +++ b/core/benches/blocks/apply_blocks.rs @@ -0,0 +1,79 @@ +#![allow(missing_docs, clippy::restriction)] + +use eyre::Result; +use iroha_core::{block::CommittedBlock, prelude::*}; +use iroha_data_model::prelude::*; + +#[path = "./common.rs"] +mod common; + +use common::*; + +pub struct WsvApplyBlocks { + wsv: WorldStateView, + blocks: Vec, +} + +impl WsvApplyBlocks { + /// Create [`WorldStateView`] and blocks for benchmarking + /// + /// # Errors + /// - Failed to parse [`AccountId`] + /// - Failed to generate [`KeyPair`] + /// - Failed to create instructions for block + pub fn setup() -> Result { + let domains = 100; + let accounts_per_domain = 1000; + let assets_per_domain = 1000; + let account_id: AccountId = "alice@wonderland".parse()?; + let key_pair = KeyPair::generate()?; + let wsv = build_wsv(&account_id, &key_pair); + + let nth = 100; + let instructions = [ + populate_wsv(domains, accounts_per_domain, assets_per_domain, &account_id), + delete_every_nth(domains, accounts_per_domain, assets_per_domain, nth), + restore_every_nth(domains, accounts_per_domain, assets_per_domain, nth), + ] + .into_iter() + .collect::, _>>()?; + + let blocks = { + // Clone wsv because it will be changed during creation of block + let mut wsv = wsv.clone(); + instructions + .into_iter() + .map(|instructions| { + let block = + create_block(&mut wsv, instructions, account_id.clone(), key_pair.clone()); + wsv.apply_without_execution(&block).map(|_| block) + }) + .collect::, _>>()? + }; + + Ok(Self { wsv, blocks }) + } + + /// Run benchmark body. + /// + /// # Errors + /// - Not enough blocks + /// - Failed to apply block + /// + /// # Panics + /// If wsv isn't one block ahead of finalized wsv. + pub fn measure(Self { wsv, blocks }: &Self) -> Result<()> { + let mut finalized_wsv = wsv.clone(); + let mut wsv = finalized_wsv.clone(); + + assert_eq!(wsv.height(), 0); + for (block, i) in blocks.iter().zip(1..) { + finalized_wsv = wsv.clone(); + wsv.apply(block)?; + assert_eq!(wsv.height(), i); + assert_eq!(wsv.height(), finalized_wsv.height() + 1); + } + + Ok(()) + } +} diff --git a/core/benches/apply_blocks/benchmark.rs b/core/benches/blocks/apply_blocks_benchmark.rs similarity index 100% rename from core/benches/apply_blocks/benchmark.rs rename to core/benches/blocks/apply_blocks_benchmark.rs diff --git a/core/benches/blocks/apply_blocks_oneshot.rs b/core/benches/blocks/apply_blocks_oneshot.rs new file mode 100644 index 00000000000..e6469db88d8 --- /dev/null +++ b/core/benches/blocks/apply_blocks_oneshot.rs @@ -0,0 +1,31 @@ +//! Oneshot execution of `apply_blocks` benchmark. +//! Can be useful to profile using flamegraph. +//! +//! ```bash +//! CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph --root --release --example apply_blocks +//! ``` + +mod apply_blocks; + +use apply_blocks::WsvApplyBlocks; +use iroha_config::base::proxy::Builder; +use iroha_data_model::Level; +use iroha_logger::{Configuration, ConfigurationProxy}; + +fn main() { + let log_config = Configuration { + max_log_level: Level::INFO.into(), + compact_mode: false, + ..ConfigurationProxy::default() + .build() + .expect("Default logger config should always build") + }; + // Can't use logger because it's failed to initialize. + #[allow(clippy::print_stderr)] + if let Err(err) = iroha_logger::init(&log_config) { + eprintln!("Failed to initialize logger: {err}"); + } + iroha_logger::info!("Starting..."); + let bench = WsvApplyBlocks::setup().expect("Failed to setup benchmark"); + WsvApplyBlocks::measure(&bench).expect("Failed to execute bnechmark"); +} diff --git a/core/benches/validate_blocks/validate_blocks.rs b/core/benches/blocks/common.rs similarity index 67% rename from core/benches/validate_blocks/validate_blocks.rs rename to core/benches/blocks/common.rs index b6c9fc9e473..64e4f5adf8d 100644 --- a/core/benches/validate_blocks/validate_blocks.rs +++ b/core/benches/blocks/common.rs @@ -11,66 +11,102 @@ use iroha_core::{ wsv::World, }; use iroha_data_model::{ + account::Account, asset::{AssetDefinition, AssetDefinitionId}, + domain::Domain, isi::InstructionBox, prelude::*, transaction::TransactionLimits, }; +use serde_json::json; -/// Create block and validate it -fn create_block( +/// Create block +pub fn create_block( + wsv: &mut WorldStateView, instructions: Vec, account_id: AccountId, key_pair: KeyPair, - wsv: &mut WorldStateView, -) -> Result { +) -> CommittedBlock { let transaction = TransactionBuilder::new(account_id) .with_instructions(instructions) - .sign(key_pair.clone())?; - - let transaction_limits = &wsv.transaction_validator().transaction_limits; - let transaction = AcceptedTransaction::accept(transaction, transaction_limits)?; + .sign(key_pair.clone()) + .unwrap(); + let limits = wsv.transaction_validator().transaction_limits; let topology = Topology::new(Vec::new()); - let pending_block = BlockBuilder::new(vec![transaction], topology.clone(), Vec::new()) - .chain_first(wsv) - .sign(key_pair) - .unwrap() - .commit(&topology) - .unwrap(); + let block = BlockBuilder::new( + vec![AcceptedTransaction::accept(transaction, &limits).unwrap()], + topology.clone(), + Vec::new(), + ) + .chain(0, wsv) + .sign(key_pair) + .unwrap() + .commit(&topology) + .unwrap(); + + // Verify that transactions are valid + for tx in &block.payload().transactions { + assert_eq!(tx.error, None); + } - Ok(pending_block) + block } -fn populate_wsv( +pub fn populate_wsv( domains: usize, accounts_per_domain: usize, assets_per_domain: usize, + owner_id: &AccountId, ) -> Result> { let mut instructions: Vec = Vec::new(); for i in 0..domains { let domain_id = DomainId::from_str(&i.to_string())?; let domain = Domain::new(domain_id.clone()); instructions.push(RegisterBox::new(domain).into()); + let can_unregister_domain = GrantBox::new( + PermissionToken::new( + "CanUnregisterDomain".parse().unwrap(), + &json!({ "domain_id": domain_id.clone() }), + ), + owner_id.clone(), + ); + instructions.push(can_unregister_domain.into()); for j in 0..accounts_per_domain { let account_id = AccountId::new(Name::from_str(&j.to_string())?, domain_id.clone()); let account = Account::new(account_id.clone(), []); instructions.push(RegisterBox::new(account).into()); + let can_unregister_account = GrantBox::new( + PermissionToken::new( + "CanUnregisterAccount".parse().unwrap(), + &json!({ "account_id": account_id.clone() }), + ), + owner_id.clone(), + ); + instructions.push(can_unregister_account.into()); } for k in 0..assets_per_domain { let asset_definition_id = AssetDefinitionId::new(Name::from_str(&k.to_string())?, domain_id.clone()); let asset_definition = AssetDefinition::new( - asset_definition_id, + asset_definition_id.clone(), iroha_data_model::asset::AssetValueType::Quantity, ); instructions.push(RegisterBox::new(asset_definition).into()); + let can_unregister_asset_definition = GrantBox::new( + PermissionToken::new( + "CanUnregisterAssetDefinition".parse().unwrap(), + &json!({ "asset_definition_id": asset_definition_id }), + ), + owner_id.clone(), + ); + instructions.push(can_unregister_asset_definition.into()); } } Ok(instructions) } -fn delete_every_nth( +pub fn delete_every_nth( domains: usize, accounts_per_domain: usize, assets_per_domain: usize, @@ -101,7 +137,7 @@ fn delete_every_nth( Ok(instructions) } -fn restore_every_nth( +pub fn restore_every_nth( domains: usize, accounts_per_domain: usize, assets_per_domain: usize, @@ -136,10 +172,12 @@ fn restore_every_nth( Ok(instructions) } -fn build_wsv(account_id: &AccountId, key_pair: &KeyPair) -> WorldStateView { +pub fn build_wsv(account_id: &AccountId, key_pair: &KeyPair) -> WorldStateView { let kura = iroha_core::kura::Kura::blank_kura_for_testing(); let mut wsv = WorldStateView::new(World::with([], BTreeSet::new()), kura); wsv.config.transaction_limits = TransactionLimits::new(u64::MAX, u64::MAX); + wsv.config.wasm_runtime_config.fuel_limit = u64::MAX; + wsv.config.wasm_runtime_config.max_memory = u32::MAX; { let domain = Domain::new(account_id.domain_id.clone()); @@ -165,73 +203,3 @@ fn build_wsv(account_id: &AccountId, key_pair: &KeyPair) -> WorldStateView { wsv } - -#[derive(Clone)] -pub struct WsvValidateBlocks { - wsv: WorldStateView, - instructions: Vec>, - key_pair: KeyPair, - account_id: AccountId, -} - -impl WsvValidateBlocks { - /// Create [`WorldStateView`] and blocks for benchmarking - /// - /// # Errors - /// - Failed to parse [`AccountId`] - /// - Failed to generate [`KeyPair`] - /// - Failed to create instructions for block - pub fn setup() -> Result { - let domains = 100; - let accounts_per_domain = 1000; - let assets_per_domain = 1000; - let genesis_id: AccountId = "genesis@genesis".parse()?; - let key_pair = KeyPair::generate()?; - let wsv = build_wsv(&genesis_id, &key_pair); - - let nth = 100; - let instructions = [ - populate_wsv(domains, accounts_per_domain, assets_per_domain), - delete_every_nth(domains, accounts_per_domain, assets_per_domain, nth), - restore_every_nth(domains, accounts_per_domain, assets_per_domain, nth), - ] - .into_iter() - .collect::, _>>()?; - - Ok(Self { - wsv, - instructions, - key_pair, - account_id: genesis_id, - }) - } - - /// Run benchmark body. - /// - /// # Errors - /// - Not enough blocks - /// - Failed to apply block - /// - /// # Panics - /// If wsv isn't one block ahead of finalized wsv. - pub fn measure( - Self { - wsv, - instructions, - key_pair, - account_id, - }: Self, - ) -> Result<()> { - let mut finalized_wsv = wsv; - let mut wsv = finalized_wsv.clone(); - - for instructions in instructions { - finalized_wsv = wsv.clone(); - let block = create_block(instructions, account_id.clone(), key_pair.clone(), &mut wsv)?; - wsv.apply_without_execution(&block)?; - assert_eq!(wsv.height(), finalized_wsv.height() + 1); - } - - Ok(()) - } -} diff --git a/core/benches/blocks/validate_blocks.rs b/core/benches/blocks/validate_blocks.rs new file mode 100644 index 00000000000..f5c1dcbc4d2 --- /dev/null +++ b/core/benches/blocks/validate_blocks.rs @@ -0,0 +1,82 @@ +#![allow(missing_docs, clippy::restriction)] + +use eyre::Result; +use iroha_core::prelude::*; +use iroha_data_model::{isi::InstructionBox, prelude::*}; + +#[path = "./common.rs"] +mod common; + +use common::*; + +#[derive(Clone)] +pub struct WsvValidateBlocks { + wsv: WorldStateView, + instructions: Vec>, + key_pair: KeyPair, + account_id: AccountId, +} + +impl WsvValidateBlocks { + /// Create [`WorldStateView`] and blocks for benchmarking + /// + /// # Errors + /// - Failed to parse [`AccountId`] + /// - Failed to generate [`KeyPair`] + /// - Failed to create instructions for block + pub fn setup() -> Result { + let domains = 100; + let accounts_per_domain = 1000; + let assets_per_domain = 1000; + let account_id: AccountId = "alice@wonderland".parse()?; + let key_pair = KeyPair::generate()?; + let wsv = build_wsv(&account_id, &key_pair); + + let nth = 100; + let instructions = [ + populate_wsv(domains, accounts_per_domain, assets_per_domain, &account_id), + delete_every_nth(domains, accounts_per_domain, assets_per_domain, nth), + restore_every_nth(domains, accounts_per_domain, assets_per_domain, nth), + ] + .into_iter() + .collect::, _>>()?; + + Ok(Self { + wsv, + instructions, + key_pair, + account_id, + }) + } + + /// Run benchmark body. + /// + /// # Errors + /// - Not enough blocks + /// - Failed to apply block + /// + /// # Panics + /// If wsv isn't one block ahead of finalized wsv. + pub fn measure( + Self { + wsv, + instructions, + key_pair, + account_id, + }: Self, + ) -> Result<()> { + let mut finalized_wsv = wsv; + let mut wsv = finalized_wsv.clone(); + + assert_eq!(wsv.height(), 0); + for (instructions, i) in instructions.into_iter().zip(1..) { + finalized_wsv = wsv.clone(); + let block = create_block(&mut wsv, instructions, account_id.clone(), key_pair.clone()); + wsv.apply_without_execution(&block)?; + assert_eq!(wsv.height(), i); + assert_eq!(wsv.height(), finalized_wsv.height() + 1); + } + + Ok(()) + } +} diff --git a/core/benches/validate_blocks/benchmark.rs b/core/benches/blocks/validate_blocks_benchmark.rs similarity index 100% rename from core/benches/validate_blocks/benchmark.rs rename to core/benches/blocks/validate_blocks_benchmark.rs diff --git a/core/benches/blocks/validate_blocks_oneshot.rs b/core/benches/blocks/validate_blocks_oneshot.rs new file mode 100644 index 00000000000..631eff07f25 --- /dev/null +++ b/core/benches/blocks/validate_blocks_oneshot.rs @@ -0,0 +1,31 @@ +//! Oneshot execution of `validate_blocks` benchmark. +//! Can be useful to profile using flamegraph. +//! +//! ```bash +//! CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph --root --release --example validate_blocks +//! ``` + +mod validate_blocks; + +use iroha_config::base::proxy::Builder; +use iroha_data_model::Level; +use iroha_logger::{Configuration, ConfigurationProxy}; +use validate_blocks::WsvValidateBlocks; + +fn main() { + let log_config = Configuration { + max_log_level: Level::INFO.into(), + compact_mode: false, + ..ConfigurationProxy::default() + .build() + .expect("Default logger config should always build") + }; + // Can't use logger because it's failed to initialize. + #[allow(clippy::print_stderr)] + if let Err(err) = iroha_logger::init(&log_config) { + eprintln!("Failed to initialize logger: {err}"); + } + iroha_logger::info!("Starting..."); + let bench = WsvValidateBlocks::setup().expect("Failed to setup benchmark"); + WsvValidateBlocks::measure(bench).expect("Failed to execute bnechmark"); +} diff --git a/core/benches/validate_blocks/oneshot.rs b/core/benches/validate_blocks/oneshot.rs deleted file mode 100644 index f381e38f649..00000000000 --- a/core/benches/validate_blocks/oneshot.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Oneshot execution of `validate_blocks` benchmark. -//! Can be useful to profile using flamegraph. -//! -//! ```bash -//! CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph --root --release --example validate_blocks -//! ``` - -mod validate_blocks; - -use validate_blocks::WsvValidateBlocks; - -fn main() { - let bench = WsvValidateBlocks::setup().expect("Failed to setup benchmark"); - WsvValidateBlocks::measure(bench).expect("Failed to execute bnechmark"); -} diff --git a/core/src/block.rs b/core/src/block.rs index 1397a14110b..55f48805171 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -535,10 +535,12 @@ mod commit { pub fn hash(&self) -> HashOf { self.0.hash() } - pub(crate) fn payload(&self) -> &BlockPayload { + /// Get block payload + pub fn payload(&self) -> &BlockPayload { self.0.payload() } - pub(crate) fn signatures(&self) -> &SignaturesOf { + /// Get block signatures + pub fn signatures(&self) -> &SignaturesOf { self.0.signatures() } } From d6ea22b38c1bdfcc114d4441b9895b30e0bbd560 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Tue, 12 Sep 2023 14:42:54 +0300 Subject: [PATCH 13/55] [refactor] #3882: Update iroha_data_model_derive to use syn 2.0 Signed-off-by: Nikita Strygin --- Cargo.lock | 12 +- data_model/derive/Cargo.toml | 6 +- data_model/derive/src/filter.rs | 19 ++- data_model/derive/src/has_origin.rs | 117 +++++++----------- data_model/derive/src/id.rs | 80 ++++++------ data_model/derive/src/lib.rs | 73 +++++++---- data_model/derive/src/model.rs | 56 +++++---- data_model/derive/src/partially_tagged.rs | 31 ++--- .../derive/tests/partial_tagged_serde.rs | 83 +++++++++++++ ffi/derive/Cargo.toml | 3 +- ffi/derive/src/convert.rs | 64 ++-------- ffi/derive/src/getset_gen.rs | 2 +- ffi/derive/src/impl_visitor.rs | 3 +- ffi/derive/src/lib.rs | 3 +- ffi/derive/src/wrapper.rs | 2 +- macro/utils/Cargo.toml | 5 +- {ffi/derive => macro/utils}/src/emitter.rs | 3 +- macro/utils/src/lib.rs | 102 +++++++++++++++ 18 files changed, 413 insertions(+), 251 deletions(-) create mode 100644 data_model/derive/tests/partial_tagged_serde.rs rename {ffi/derive => macro/utils}/src/emitter.rs (97%) diff --git a/Cargo.lock b/Cargo.lock index 35701a3bc9e..b26ac45ea5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3172,14 +3172,15 @@ dependencies = [ name = "iroha_data_model_derive" version = "2.0.0-pre-rc.19" dependencies = [ + "darling", "iroha_data_model", "iroha_macro_utils", - "proc-macro-error", + "manyhow", "proc-macro2", "quote", "serde", "serde_json", - "syn 1.0.109", + "syn 2.0.26", "trybuild", ] @@ -3226,9 +3227,9 @@ name = "iroha_ffi_derive" version = "2.0.0-pre-rc.19" dependencies = [ "darling", - "drop_bomb", "getset", "iroha_ffi", + "iroha_macro_utils", "manyhow", "parse-display", "proc-macro2", @@ -3311,10 +3312,13 @@ dependencies = [ name = "iroha_macro_utils" version = "2.0.0-pre-rc.19" dependencies = [ - "proc-macro-error", + "darling", + "drop_bomb", + "manyhow", "proc-macro2", "quote", "syn 1.0.109", + "syn 2.0.26", ] [[package]] diff --git a/data_model/derive/Cargo.toml b/data_model/derive/Cargo.toml index 0fb3f485bbd..bee036dd7ef 100644 --- a/data_model/derive/Cargo.toml +++ b/data_model/derive/Cargo.toml @@ -14,12 +14,12 @@ workspace = true proc-macro = true [dependencies] -syn = { workspace = true, features = ["default", "full", "extra-traits"] } +syn2 = { workspace = true, features = ["default", "full", "extra-traits"] } quote = { workspace = true } +darling = { workspace = true } proc-macro2 = { workspace = true } -proc-macro-error = { workspace = true } +manyhow = { workspace = true } iroha_macro_utils = { workspace = true } -serde_json = { workspace = true, features = ["std"] } [dev-dependencies] iroha_data_model = { workspace = true, features = ["http"] } diff --git a/data_model/derive/src/filter.rs b/data_model/derive/src/filter.rs index f9cbe87c09a..4725f0c45ac 100644 --- a/data_model/derive/src/filter.rs +++ b/data_model/derive/src/filter.rs @@ -4,9 +4,9 @@ clippy::arithmetic_side_effects )] -use proc_macro::TokenStream; +use proc_macro2::TokenStream; use quote::{format_ident, quote}; -use syn::{ +use syn2::{ parse::{Parse, ParseStream}, punctuated::Punctuated, Attribute, Generics, Ident, Token, Variant, Visibility, @@ -113,15 +113,15 @@ impl EventEnum { } impl Parse for EventEnum { - fn parse(input: ParseStream) -> syn::Result { + fn parse(input: ParseStream) -> syn2::Result { let _attrs = input.call(Attribute::parse_outer)?; let vis = input.parse()?; let _enum_token = input.parse::()?; let ident = input.parse::()?; let generics = input.parse::()?; let content; - let _brace_token = syn::braced!(content in input); - let variants = content.parse_terminated(EventVariant::parse)?; + let _brace_token = syn2::braced!(content in input); + let variants = content.parse_terminated(EventVariant::parse, Token![,])?; if ident.to_string().ends_with("Event") { Ok(EventEnum { vis, @@ -130,7 +130,7 @@ impl Parse for EventEnum { variants, }) } else { - Err(syn::Error::new_spanned( + Err(syn2::Error::new_spanned( ident, "Bad ident: only derivable for `...Event` enums", )) @@ -139,7 +139,7 @@ impl Parse for EventEnum { } impl Parse for EventVariant { - fn parse(input: ParseStream) -> syn::Result { + fn parse(input: ParseStream) -> syn2::Result { let variant = input.parse::()?; let variant_ident = variant.ident; let field_type = variant @@ -148,7 +148,7 @@ impl Parse for EventVariant { .next() .expect("Variant should have at least one unnamed field") .ty; - if let syn::Type::Path(path) = field_type { + if let syn2::Type::Path(path) = field_type { let field_ident = path .path .get_ident() @@ -163,7 +163,7 @@ impl Parse for EventVariant { Ok(EventVariant::IdField(variant_ident)) } } else { - Err(syn::Error::new_spanned( + Err(syn2::Error::new_spanned( field_type, "Unexpected AST type variant", )) @@ -220,7 +220,6 @@ pub fn impl_filter(event: &EventEnum) -> TokenStream { #event_filter_and_impl } - .into() } /// Generates the event filter for the event. E.g. for `AccountEvent`, `AccountEventFilter` diff --git a/data_model/derive/src/has_origin.rs b/data_model/derive/src/has_origin.rs index 85dab5114bb..18df35f8d10 100644 --- a/data_model/derive/src/has_origin.rs +++ b/data_model/derive/src/has_origin.rs @@ -4,102 +4,80 @@ clippy::unwrap_in_result )] -use iroha_macro_utils::{attr_struct, AttrParser}; -use proc_macro::TokenStream; -use proc_macro_error::abort; +use darling::{FromDeriveInput, FromVariant}; +use iroha_macro_utils::{attr_struct2, parse_single_list_attr, parse_single_list_attr_opt}; +use manyhow::Result; +use proc_macro2::TokenStream; use quote::quote; -use syn::{ - parse::{Parse, ParseStream}, - parse_quote, - punctuated::Punctuated, - Attribute, Generics, Ident, Token, Type, Variant, Visibility, -}; +use syn2::{parse_quote, Ident, Token, Type}; mod kw { - syn::custom_keyword!(origin); - syn::custom_keyword!(variant); + syn2::custom_keyword!(origin); } +const HAS_ORIGIN_ATTR: &str = "has_origin"; + pub struct HasOriginEnum { ident: Ident, - variants: Punctuated, + variants: Vec, origin: Type, } +impl FromDeriveInput for HasOriginEnum { + fn from_derive_input(input: &syn2::DeriveInput) -> darling::Result { + let ident = input.ident.clone(); + + let Some(variants) = darling::ast::Data::::try_from(&input.data)?.take_enum() else { + return Err(darling::Error::custom("Expected enum")); + }; + + let origin = parse_single_list_attr::(HAS_ORIGIN_ATTR, &input.attrs)?.ty; + + Ok(Self { + ident, + variants, + origin, + }) + } +} + pub struct HasOriginVariant { ident: Ident, - extractor: Option, + extractor: Option, } -struct HasOriginAttr(core::marker::PhantomData); +impl FromVariant for HasOriginVariant { + fn from_variant(variant: &syn2::Variant) -> darling::Result { + let ident = variant.ident.clone(); + let extractor = parse_single_list_attr_opt(HAS_ORIGIN_ATTR, &variant.attrs)?; -impl AttrParser for HasOriginAttr { - const IDENT: &'static str = "has_origin"; + Ok(Self { ident, extractor }) + } } -attr_struct! { - pub struct Origin { +attr_struct2! { + pub struct OriginAttr { _kw: kw::origin, _eq: Token![=], ty: Type, } } -attr_struct! { - pub struct OriginExtractor { +attr_struct2! { + pub struct OriginExtractorAttr { ident: Ident, _eq: Token![=>], - extractor: syn::Expr, + extractor: syn2::Expr, } } -impl Parse for HasOriginEnum { - fn parse(input: ParseStream) -> syn::Result { - let attrs = input.call(Attribute::parse_outer)?; - let _vis = input.parse::()?; - let _enum_token = input.parse::()?; - let ident = input.parse::()?; - let generics = input.parse::()?; - if !generics.params.is_empty() { - abort!(generics, "Generics are not supported"); - } - let content; - let _brace_token = syn::braced!(content in input); - let variants = content.parse_terminated(HasOriginVariant::parse)?; - let origin = attrs - .iter() - .find_map(|attr| HasOriginAttr::::parse(attr).ok()) - .map(|origin| origin.ty) - .expect("Attribute `#[has_origin(origin = Type)]` is required"); - Ok(HasOriginEnum { - ident, - variants, - origin, - }) - } -} +pub fn impl_has_origin(input: &syn2::DeriveInput) -> Result { + let enum_ = HasOriginEnum::from_derive_input(input)?; -impl Parse for HasOriginVariant { - fn parse(input: ParseStream) -> syn::Result { - let variant = input.parse::()?; - let Variant { - ident, - fields, - attrs, - .. - } = variant; - match fields { - syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {} - fields => abort!(fields, "Only supports tuple variants with single field"), - }; - let extractor = attrs - .iter() - .find_map(|attr| HasOriginAttr::::parse(attr).ok()); - Ok(HasOriginVariant { ident, extractor }) - } -} + // TODO: verify enum is non-empty (or make it work with empty enums) + // TODO: verify all the enum variants are newtype variants + // TODO: verify there are no generics on the enum -pub fn impl_has_origin(enum_: &HasOriginEnum) -> TokenStream { let enum_ident = &enum_.ident; let enum_origin = &enum_.origin; let variants_match_arms = &enum_ @@ -116,9 +94,9 @@ pub fn impl_has_origin(enum_: &HasOriginEnum) -> TokenStream { }, ) }) - .collect::>(); + .collect::>(); - quote! { + Ok(quote! { impl HasOrigin for #enum_ident { type Origin = #enum_origin; @@ -131,6 +109,5 @@ pub fn impl_has_origin(enum_: &HasOriginEnum) -> TokenStream { } } } - } - .into() + }) } diff --git a/data_model/derive/src/id.rs b/data_model/derive/src/id.rs index afb742b2420..ad57dfd789e 100644 --- a/data_model/derive/src/id.rs +++ b/data_model/derive/src/id.rs @@ -1,33 +1,16 @@ #![allow(clippy::str_to_string, clippy::mixed_read_write_in_expression)] +use manyhow::{bail, Result}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; -use syn::parse_quote; +use syn2::parse_quote; -fn derive_identifiable(input: &syn::ItemStruct) -> TokenStream { +pub fn impl_id(input: &syn2::ItemStruct) -> Result { let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let (id_type, id_expr) = get_id_type(input); + let identifiable_derive = derive_identifiable(input)?; - quote! { - impl #impl_generics Identifiable for #name #ty_generics #where_clause { - type Id = #id_type; - - #[inline] - fn id(&self) -> &Self::Id { - #id_expr - } - } - } -} - -pub fn impl_id(input: &syn::ItemStruct) -> TokenStream { - let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let identifiable_derive = derive_identifiable(input); - - quote! { + Ok(quote! { #identifiable_derive impl #impl_generics ::core::cmp::PartialOrd for #name #ty_generics #where_clause where Self: Identifiable { @@ -55,65 +38,82 @@ pub fn impl_id(input: &syn::ItemStruct) -> TokenStream { self.id().hash(state); } } - } + }) +} + +fn derive_identifiable(input: &syn2::ItemStruct) -> Result { + let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let (id_type, id_expr) = get_id_type(input)?; + + Ok(quote! { + impl #impl_generics Identifiable for #name #ty_generics #where_clause { + type Id = #id_type; + + #[inline] + fn id(&self) -> &Self::Id { + #id_expr + } + } + }) } -fn get_id_type(input: &syn::ItemStruct) -> (TokenStream, TokenStream) { +fn get_id_type(input: &syn2::ItemStruct) -> Result<(TokenStream, TokenStream)> { match &input.fields { - syn::Fields::Named(fields) => { + syn2::Fields::Named(fields) => { for field in &fields.named { let (field_name, field_ty) = (&field.ident, &field.ty); if is_identifier(&field.attrs) { - return (quote! {#field_ty}, quote! {&self.#field_name}); + return Ok((quote! {#field_ty}, quote! {&self.#field_name})); } if is_transparent(&field.attrs) { - return ( + return Ok(( quote! {<#field_ty as Identifiable>::Id}, quote! {Identifiable::id(&self.#field_name)}, - ); + )); } } } - syn::Fields::Unnamed(fields) => { + syn2::Fields::Unnamed(fields) => { for (i, field) in fields.unnamed.iter().enumerate() { - let (field_id, field_ty): (syn::Index, _) = (i.into(), &field.ty); + let (field_id, field_ty): (syn2::Index, _) = (i.into(), &field.ty); if is_identifier(&field.attrs) { - return (quote! {#field_ty}, quote! {&self.#field_id}); + return Ok((quote! {#field_ty}, quote! {&self.#field_id})); } if is_transparent(&field.attrs) { - return ( + return Ok(( quote! {<#field_ty as Identifiable>::Id}, quote! {Identifiable::id(&self.#field_id)}, - ); + )); } } } - syn::Fields::Unit => {} + syn2::Fields::Unit => {} } match &input.fields { - syn::Fields::Named(named) => { + syn2::Fields::Named(named) => { for field in &named.named { let field_ty = &field.ty; if field.ident.as_ref().expect("Field must be named") == "id" { - return (quote! {#field_ty}, quote! {&self.id}); + return Ok((quote! {#field_ty}, quote! {&self.id})); } } } - syn::Fields::Unnamed(_) | syn::Fields::Unit => {} + syn2::Fields::Unnamed(_) | syn2::Fields::Unit => {} } - abort!(input, "Identifier not found") + bail!(input, "Identifier not found") } -fn is_identifier(attrs: &[syn::Attribute]) -> bool { +fn is_identifier(attrs: &[syn2::Attribute]) -> bool { attrs.iter().any(|attr| attr == &parse_quote! {#[id]}) } -fn is_transparent(attrs: &[syn::Attribute]) -> bool { +fn is_transparent(attrs: &[syn2::Attribute]) -> bool { attrs .iter() .any(|attr| attr == &parse_quote! {#[id(transparent)]}) diff --git a/data_model/derive/src/lib.rs b/data_model/derive/src/lib.rs index 607ff1720e6..61b17a51b09 100644 --- a/data_model/derive/src/lib.rs +++ b/data_model/derive/src/lib.rs @@ -7,8 +7,9 @@ mod id; mod model; mod partially_tagged; -use proc_macro::TokenStream; -use syn::parse_macro_input; +use iroha_macro_utils::Emitter; +use manyhow::{emit, manyhow, Result}; +use proc_macro2::TokenStream; /// Macro which controls how to export item's API. The behaviour is controlled with `transparent_api` /// feature flag. If the flag is active, item's public fields will be exposed as public, however, if @@ -80,19 +81,37 @@ use syn::parse_macro_input; /// ``` /// /// It assumes that the derive is imported and referred to by its original name. +#[manyhow] #[proc_macro_attribute] -#[proc_macro_error::proc_macro_error] -pub fn model(_attr: TokenStream, input: TokenStream) -> TokenStream { - model::impl_model(&parse_macro_input!(input)).into() +pub fn model(attr: TokenStream, input: TokenStream) -> TokenStream { + let mut emitter = Emitter::new(); + + if !attr.is_empty() { + emit!(emitter, attr, "This attribute does not take any arguments"); + } + + let Some(input) = emitter.handle(syn2::parse2(input)) else { + return emitter.finish_token_stream(); + }; + + let result = model::impl_model(&mut emitter, &input); + + emitter.finish_token_stream_with(result) } /// Same as [`model`] macro, but only processes a single item. /// /// You should prefer using [`model`] macro over this one. +#[manyhow] #[proc_macro] -#[proc_macro_error::proc_macro_error] pub fn model_single(input: TokenStream) -> TokenStream { - model::process_item(parse_macro_input!(input)).into() + let mut emitter = Emitter::new(); + + let Some(input) = emitter.handle(syn2::parse2(input)) else { + return emitter.finish_token_stream(); + }; + + emitter.finish_token_stream_with(model::process_item(input)) } /// Derive macro for `Identifiable` trait which also automatically implements [`Ord`], [`Eq`], @@ -209,10 +228,12 @@ pub fn model_single(input: TokenStream) -> TokenStream { /// } /// ``` /// -#[proc_macro_error::proc_macro_error] +#[manyhow] #[proc_macro_derive(IdEqOrdHash, attributes(id, opaque))] -pub fn id_eq_ord_hash(input: TokenStream) -> TokenStream { - id::impl_id(&parse_macro_input!(input)).into() +pub fn id_eq_ord_hash(input: TokenStream) -> Result { + let input = syn2::parse2(input)?; + + id::impl_id(&input) } /// [`Filter`] is used for code generation of `...Filter` structs and `...EventFilter` enums, as well as @@ -377,10 +398,12 @@ pub fn id_eq_ord_hash(input: TokenStream) -> TokenStream { /// ``` /// /// It assumes that the derive is imported and referred to by its original name. +#[manyhow] #[proc_macro_derive(Filter)] -pub fn filter_derive(input: TokenStream) -> TokenStream { - let event = parse_macro_input!(input as filter::EventEnum); - filter::impl_filter(&event) +pub fn filter_derive(input: TokenStream) -> Result { + let input = syn2::parse2(input)?; + + Ok(filter::impl_filter(&input)) } /// Derive `::serde::Serialize` trait for `enum` with possibility to avoid tags for selected variants @@ -409,10 +432,12 @@ pub fn filter_derive(input: TokenStream) -> TokenStream { /// &serde_json::to_string(&Outer::A(42)).expect("Failed to serialize"), r#"{"A":42}"# /// ); /// ``` -#[proc_macro_error::proc_macro_error] +#[manyhow] #[proc_macro_derive(PartiallyTaggedSerialize, attributes(serde_partially_tagged, serde))] -pub fn partially_tagged_serialize_derive(input: TokenStream) -> TokenStream { - partially_tagged::impl_partially_tagged_serialize(&parse_macro_input!(input)) +pub fn partially_tagged_serialize_derive(input: TokenStream) -> Result { + let input = syn2::parse2(input)?; + + Ok(partially_tagged::impl_partially_tagged_serialize(&input)) } /// Derive `::serde::Deserialize` trait for `enum` with possibility to avoid tags for selected variants @@ -470,10 +495,12 @@ pub fn partially_tagged_serialize_derive(input: TokenStream) -> TokenStream { /// serde_json::from_str::(r#"{"B":42}"#).expect("Failed to deserialize"), Outer::Inner1(Inner::B(42)) /// ); /// ``` -#[proc_macro_error::proc_macro_error] +#[manyhow] #[proc_macro_derive(PartiallyTaggedDeserialize, attributes(serde_partially_tagged, serde))] -pub fn partially_tagged_deserialize_derive(input: TokenStream) -> TokenStream { - partially_tagged::impl_partially_tagged_deserialize(&parse_macro_input!(input)) +pub fn partially_tagged_deserialize_derive(input: TokenStream) -> Result { + let input = syn2::parse2(input)?; + + Ok(partially_tagged::impl_partially_tagged_deserialize(&input)) } /// Derive macro for `HasOrigin`. @@ -559,8 +586,10 @@ pub fn partially_tagged_deserialize_derive(input: TokenStream) -> TokenStream { /// assert_eq!(&layer_id, layer_sub_layer_event.origin_id()); /// assert_eq!(&sub_layer_id, sub_layer_created_event.origin_id()); /// ``` -#[proc_macro_error::proc_macro_error] +#[manyhow] #[proc_macro_derive(HasOrigin, attributes(has_origin))] -pub fn has_origin_derive(input: TokenStream) -> TokenStream { - has_origin::impl_has_origin(&parse_macro_input!(input)) +pub fn has_origin_derive(input: TokenStream) -> Result { + let input = syn2::parse2(input)?; + + has_origin::impl_has_origin(&input) } diff --git a/data_model/derive/src/model.rs b/data_model/derive/src/model.rs index 8a7426baca3..73aa757c87c 100644 --- a/data_model/derive/src/model.rs +++ b/data_model/derive/src/model.rs @@ -1,10 +1,11 @@ +use iroha_macro_utils::Emitter; +use manyhow::emit; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::{quote, ToTokens}; -use syn::{parse_quote, Attribute}; +use syn2::{parse_quote, Attribute}; -pub fn impl_model(input: &syn::ItemMod) -> TokenStream { - let syn::ItemMod { +pub fn impl_model(emitter: &mut Emitter, input: &syn2::ItemMod) -> TokenStream { + let syn2::ItemMod { attrs, vis, mod_token, @@ -14,14 +15,17 @@ pub fn impl_model(input: &syn::ItemMod) -> TokenStream { .. } = input; - let syn::Visibility::Public(vis_public) = vis else { - abort!( + let syn2::Visibility::Public(vis_public) = vis else { + emit!( + emitter, input, "The `model` attribute can only be used on public modules" ); + return quote!(); }; if ident != "model" { - abort!( + emit!( + emitter, input, "The `model` attribute can only be used on the `model` module" ); @@ -40,16 +44,16 @@ pub fn impl_model(input: &syn::ItemMod) -> TokenStream { } } -pub fn process_item(item: syn::Item) -> TokenStream { - let mut input: syn::DeriveInput = match item { - syn::Item::Struct(item_struct) => item_struct.into(), - syn::Item::Enum(item_enum) => item_enum.into(), - syn::Item::Union(item_union) => item_union.into(), +pub fn process_item(item: syn2::Item) -> TokenStream { + let mut input: syn2::DeriveInput = match item { + syn2::Item::Struct(item_struct) => item_struct.into(), + syn2::Item::Enum(item_enum) => item_enum.into(), + syn2::Item::Union(item_union) => item_union.into(), other => return other.into_token_stream(), }; let vis = &input.vis; - if matches!(vis, syn::Visibility::Public(_)) { + if matches!(vis, syn2::Visibility::Public(_)) { return process_pub_item(input); } @@ -70,21 +74,21 @@ pub fn process_item(item: syn::Item) -> TokenStream { } } -fn process_pub_item(input: syn::DeriveInput) -> TokenStream { +fn process_pub_item(input: syn2::DeriveInput) -> TokenStream { let (impl_generics, _, where_clause) = input.generics.split_for_impl(); let attrs = input.attrs; let ident = input.ident; match input.data { - syn::Data::Struct(item) => match &item.fields { - syn::Fields::Named(fields) => { + syn2::Data::Struct(item) => match &item.fields { + syn2::Fields::Named(fields) => { let fields = fields.named.iter().map(|field| { let field_attrs = &field.attrs; let field_name = &field.ident; let field_ty = &field.ty; - if !matches!(field.vis, syn::Visibility::Public(_)) { + if !matches!(field.vis, syn2::Visibility::Public(_)) { return quote! {#field,}; } @@ -107,12 +111,12 @@ fn process_pub_item(input: syn::DeriveInput) -> TokenStream { expose_ffi(attrs, &item) } - syn::Fields::Unnamed(fields) => { + syn2::Fields::Unnamed(fields) => { let fields = fields.unnamed.iter().map(|field| { let field_attrs = &field.attrs; let field_ty = &field.ty; - if !matches!(field.vis, syn::Visibility::Public(_)) { + if !matches!(field.vis, syn2::Visibility::Public(_)) { return quote! {#field,}; } @@ -133,7 +137,7 @@ fn process_pub_item(input: syn::DeriveInput) -> TokenStream { expose_ffi(attrs, &item) } - syn::Fields::Unit => { + syn2::Fields::Unit => { let item = quote! { pub struct #ident #impl_generics #where_clause; }; @@ -141,7 +145,7 @@ fn process_pub_item(input: syn::DeriveInput) -> TokenStream { expose_ffi(attrs, &item) } }, - syn::Data::Enum(item) => { + syn2::Data::Enum(item) => { let variants = &item.variants; let item = quote! { @@ -154,13 +158,13 @@ fn process_pub_item(input: syn::DeriveInput) -> TokenStream { } // Triggers in `quote!` side, see https://github.com/rust-lang/rust-clippy/issues/10417 #[allow(clippy::arithmetic_side_effects)] - syn::Data::Union(item) => { + syn2::Data::Union(item) => { let fields = item.fields.named.iter().map(|field| { let field_attrs = &field.attrs; let field_name = &field.ident; let field_ty = &field.ty; - if !matches!(field.vis, syn::Visibility::Public(_)) { + if !matches!(field.vis, syn2::Visibility::Public(_)) { return quote! {#field,}; } @@ -189,7 +193,9 @@ fn process_pub_item(input: syn::DeriveInput) -> TokenStream { } fn expose_ffi(mut attrs: Vec, item: &TokenStream) -> TokenStream { - let mut ffi_attrs = attrs.iter().filter(|&attr| attr.path.is_ident("ffi_type")); + let mut ffi_attrs = attrs + .iter() + .filter(|&attr| attr.path().is_ident("ffi_type")); if ffi_attrs.next().is_none() { return quote! { @@ -201,7 +207,7 @@ fn expose_ffi(mut attrs: Vec, item: &TokenStream) -> TokenStream { attrs.retain(|attr| *attr != parse_quote! (#[ffi_type])); let no_ffi_attrs: Vec<_> = attrs .iter() - .filter(|&attr| !attr.path.is_ident("ffi_type")) + .filter(|&attr| !attr.path().is_ident("ffi_type")) .collect(); quote! { diff --git a/data_model/derive/src/partially_tagged.rs b/data_model/derive/src/partially_tagged.rs index 845520f0670..830d4e65c6a 100644 --- a/data_model/derive/src/partially_tagged.rs +++ b/data_model/derive/src/partially_tagged.rs @@ -1,11 +1,11 @@ #![allow(clippy::too_many_lines)] -use proc_macro::TokenStream; -use proc_macro_error::abort; +use proc_macro2::TokenStream; use quote::{format_ident, quote}; -use syn::{ +use syn2::{ parse::{Parse, ParseStream}, parse_quote, punctuated::Punctuated, + spanned::Spanned, Attribute, Generics, Ident, Token, Type, Variant, Visibility, }; @@ -24,15 +24,15 @@ pub struct PartiallyTaggedVariant { } impl Parse for PartiallyTaggedEnum { - fn parse(input: ParseStream) -> syn::Result { + fn parse(input: ParseStream) -> syn2::Result { let mut attrs = input.call(Attribute::parse_outer)?; let _vis = input.parse::()?; let _enum_token = input.parse::()?; let ident = input.parse::()?; let generics = input.parse::()?; let content; - let _brace_token = syn::braced!(content in input); - let variants = content.parse_terminated(PartiallyTaggedVariant::parse)?; + let _brace_token = syn2::braced!(content in input); + let variants = content.parse_terminated(PartiallyTaggedVariant::parse, Token![,])?; attrs.retain(is_serde_attr); Ok(PartiallyTaggedEnum { attrs, @@ -44,7 +44,7 @@ impl Parse for PartiallyTaggedEnum { } impl Parse for PartiallyTaggedVariant { - fn parse(input: ParseStream) -> syn::Result { + fn parse(input: ParseStream) -> syn2::Result { let variant = input.parse::()?; let Variant { ident, @@ -53,12 +53,17 @@ impl Parse for PartiallyTaggedVariant { .. } = variant; let field = match fields { - syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => fields + syn2::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => fields .unnamed .into_iter() .next() .expect("Guaranteed to have exactly one field"), - fields => abort!(fields, "Only supports tuple variants with single field"), + fields => { + return Err(syn2::Error::new( + fields.span(), + "Only supports tuple variants with single field", + )) + } }; let ty = field.ty; let is_untagged = attrs.iter().any(is_untagged_attr); @@ -104,7 +109,7 @@ fn is_untagged_attr(attr: &Attribute) -> bool { /// Check if `#[serde...]` attribute fn is_serde_attr(attr: &Attribute) -> bool { - attr.path + attr.path() .get_ident() .map_or_else(|| false, |ident| ident.to_string().eq("serde")) } @@ -117,7 +122,7 @@ pub fn impl_partially_tagged_serialize(enum_: &PartiallyTaggedEnum) -> TokenStre let (variants_ident, variants_ty, variants_attrs) = variants_to_tuple(enum_.variants()); let (untagged_variants_ident, untagged_variants_ty, untagged_variants_attrs) = variants_to_tuple(enum_.untagged_variants()); - let serialize_trait_bound: syn::TypeParamBound = parse_quote!(::serde::Serialize); + let serialize_trait_bound: syn2::TypeParamBound = parse_quote!(::serde::Serialize); let mut generics = enum_.generics.clone(); generics .type_params_mut() @@ -177,7 +182,6 @@ pub fn impl_partially_tagged_serialize(enum_: &PartiallyTaggedEnum) -> TokenStre } } } - .into() } pub fn impl_partially_tagged_deserialize(enum_: &PartiallyTaggedEnum) -> TokenStream { @@ -190,7 +194,7 @@ pub fn impl_partially_tagged_deserialize(enum_: &PartiallyTaggedEnum) -> TokenSt let (variants_ident, variants_ty, variants_attrs) = variants_to_tuple(enum_.variants()); let (untagged_variants_ident, untagged_variants_ty, untagged_variants_attrs) = variants_to_tuple(enum_.untagged_variants()); - let deserialize_trait_bound: syn::TypeParamBound = parse_quote!(::serde::de::DeserializeOwned); + let deserialize_trait_bound: syn2::TypeParamBound = parse_quote!(::serde::de::DeserializeOwned); let variants_ty_deserialize_bound = variants_ty .iter() .map(|ty| quote!(#ty: #deserialize_trait_bound).to_string()) @@ -343,5 +347,4 @@ pub fn impl_partially_tagged_deserialize(enum_: &PartiallyTaggedEnum) -> TokenSt } } } - .into() } diff --git a/data_model/derive/tests/partial_tagged_serde.rs b/data_model/derive/tests/partial_tagged_serde.rs new file mode 100644 index 00000000000..99e11e06e0e --- /dev/null +++ b/data_model/derive/tests/partial_tagged_serde.rs @@ -0,0 +1,83 @@ +use std::fmt::Formatter; + +use iroha_data_model_derive::{PartiallyTaggedDeserialize, PartiallyTaggedSerialize}; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +#[allow(variant_size_differences)] // it's a test, duh +#[derive(Debug, PartialEq, Eq, PartiallyTaggedDeserialize, PartiallyTaggedSerialize)] +enum Value { + Bool(bool), + String(String), + #[serde_partially_tagged(untagged)] + Numeric(NumericValue), +} + +// a simpler version of NumericValue than used in data_model +// this one is always i32, but is still serialized as a string literal +// NOTE: debug is actually required for `PartiallyTaggedDeserialize`! +#[derive(Debug, PartialEq, Eq)] +struct NumericValue(i32); + +impl Serialize for NumericValue { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.0.to_string()) + } +} + +struct NumericValueVisitor; + +impl de::Visitor<'_> for NumericValueVisitor { + type Value = NumericValue; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("a string literal containing a number") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + let parsed = v.parse::().map_err(|e| E::custom(e))?; + + Ok(NumericValue(parsed)) + } +} + +impl<'de> Deserialize<'de> for NumericValue { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(NumericValueVisitor) + } +} + +#[test] +fn partially_tagged_serde() { + let values = [ + Value::Bool(true), + Value::String("I am string".to_owned()), + Value::Numeric(NumericValue(42)), + ]; + let serialized_values = [r#"{"Bool":true}"#, r#"{"String":"I am string"}"#, r#""42""#]; + + for (value, serialized_value) in values.iter().zip(serialized_values.iter()) { + let serialized = serde_json::to_string(value) + .unwrap_or_else(|e| panic!("Failed to serialize `{:?}`: {:?}", value, e)); + assert_eq!( + serialized, *serialized_value, + "Serialized form of `{:?}` does not match the expected value", + value + ); + let deserialized: Value = serde_json::from_str(serialized_value) + .unwrap_or_else(|e| panic!("Failed to deserialize `{:?}`: {:?}", serialized_value, e)); + assert_eq!( + *value, deserialized, + "Deserialized form of `{:?}` does not match the expected value", + value + ); + } +} diff --git a/ffi/derive/Cargo.toml b/ffi/derive/Cargo.toml index d8c320bfa11..5004ea9a52c 100644 --- a/ffi/derive/Cargo.toml +++ b/ffi/derive/Cargo.toml @@ -15,6 +15,8 @@ workspace = true proc-macro = true [dependencies] +iroha_macro_utils = { workspace = true } + syn2 = { workspace = true, features = ["full", "visit", "visit-mut", "extra-traits"] } quote = { workspace = true } proc-macro2 = { workspace = true } @@ -22,7 +24,6 @@ manyhow = { workspace = true } darling = { workspace = true } rustc-hash = { workspace = true } -drop_bomb = "0.1.5" parse-display = "0.8.2" [dev-dependencies] diff --git a/ffi/derive/src/convert.rs b/ffi/derive/src/convert.rs index cb409c622af..d8995fedc4f 100644 --- a/ffi/derive/src/convert.rs +++ b/ffi/derive/src/convert.rs @@ -4,21 +4,17 @@ use std::fmt::{Display, Formatter}; use darling::{ ast::Style, util::SpannedValue, FromAttributes, FromDeriveInput, FromField, FromVariant, }; +use iroha_macro_utils::{parse_single_list_attr_opt, Emitter}; use manyhow::{emit, error_message}; use proc_macro2::{Delimiter, Span, TokenStream}; use quote::quote; -use syn2::{ - parse::ParseStream, spanned::Spanned as _, visit::Visit as _, Attribute, Field, Ident, Meta, -}; +use syn2::{parse::ParseStream, spanned::Spanned as _, visit::Visit as _, Attribute, Field, Ident}; -use crate::{ - attr_parse::{ - derive::DeriveAttrs, - doc::DocAttrs, - getset::{GetSetFieldAttrs, GetSetStructAttrs}, - repr::{Repr, ReprKind, ReprPrimitive}, - }, - emitter::Emitter, +use crate::attr_parse::{ + derive::DeriveAttrs, + doc::DocAttrs, + getset::{GetSetFieldAttrs, GetSetStructAttrs}, + repr::{Repr, ReprKind, ReprPrimitive}, }; #[derive(Debug)] @@ -135,47 +131,7 @@ impl syn2::parse::Parse for FfiTypeKindFieldAttribute { } } -fn parse_ffi_type_attr(attrs: &[Attribute]) -> darling::Result> { - let mut accumulator = darling::error::Accumulator::default(); - - // first, ensure there is only one "ffi_type" attribute (we don't support multiple) - let ffi_type_attrs = attrs - .iter() - .filter(|a| a.path().is_ident("ffi_type")) - .collect::>(); - let attr = match *ffi_type_attrs.as_slice() { - [] => { - return accumulator.finish_with(None); - } - [attr] => attr, - [attr, ref tail @ ..] => { - // allow parsing to proceed further to collect more errors - accumulator.push( - darling::Error::custom("Only one #[ffi_type] attribute is allowed!").with_span( - &tail - .iter() - .map(syn2::spanned::Spanned::span) - .reduce(|a, b| a.join(b).unwrap()) - .unwrap(), - ), - ); - attr - } - }; - - let mut kind = None; - - match &attr.meta { - Meta::Path(_) | Meta::NameValue(_) => accumulator.push(darling::Error::custom( - "Expected #[ffi_type(...)] attribute to be a list", - )), - Meta::List(list) => { - kind = accumulator.handle(syn2::parse2(list.tokens.clone()).map_err(Into::into)); - } - } - - accumulator.finish_with(kind) -} +const FFI_TYPE_ATTR: &str = "ffi_type"; pub struct FfiTypeAttr { pub kind: Option, @@ -183,7 +139,7 @@ pub struct FfiTypeAttr { impl FromAttributes for FfiTypeAttr { fn from_attributes(attrs: &[Attribute]) -> darling::Result { - parse_ffi_type_attr(attrs).map(|kind| Self { kind }) + parse_single_list_attr_opt(FFI_TYPE_ATTR, attrs).map(|kind| Self { kind }) } } @@ -193,7 +149,7 @@ pub struct FfiTypeFieldAttr { impl FromAttributes for FfiTypeFieldAttr { fn from_attributes(attrs: &[Attribute]) -> darling::Result { - parse_ffi_type_attr(attrs).map(|kind| Self { kind }) + parse_single_list_attr_opt(FFI_TYPE_ATTR, attrs).map(|kind| Self { kind }) } } diff --git a/ffi/derive/src/getset_gen.rs b/ffi/derive/src/getset_gen.rs index 6458c04a030..89c628de71b 100644 --- a/ffi/derive/src/getset_gen.rs +++ b/ffi/derive/src/getset_gen.rs @@ -1,6 +1,7 @@ use std::default::Default; use darling::ast::Style; +use iroha_macro_utils::Emitter; use manyhow::emit; use proc_macro2::TokenStream; use quote::quote; @@ -13,7 +14,6 @@ use crate::{ getset::{GetSetGenMode, GetSetStructAttrs}, }, convert::{FfiTypeField, FfiTypeFields}, - emitter::Emitter, impl_visitor::{unwrap_result_type, Arg, FnDescriptor}, }; diff --git a/ffi/derive/src/impl_visitor.rs b/ffi/derive/src/impl_visitor.rs index 6c547b10020..c5bd408b01b 100644 --- a/ffi/derive/src/impl_visitor.rs +++ b/ffi/derive/src/impl_visitor.rs @@ -2,6 +2,7 @@ //! //! It also defines descriptors - types that are used for the codegen step +use iroha_macro_utils::Emitter; use manyhow::emit; use proc_macro2::Span; use syn2::{ @@ -11,8 +12,6 @@ use syn2::{ Attribute, Ident, Path, Type, Visibility, }; -use crate::emitter::Emitter; - pub struct Arg { self_ty: Option, name: Ident, diff --git a/ffi/derive/src/lib.rs b/ffi/derive/src/lib.rs index 2bbd93b6489..fdd0673192b 100644 --- a/ffi/derive/src/lib.rs +++ b/ffi/derive/src/lib.rs @@ -3,6 +3,7 @@ use darling::FromDeriveInput; use impl_visitor::{FnDescriptor, ImplDescriptor}; +use iroha_macro_utils::Emitter; use manyhow::{emit, manyhow}; use proc_macro2::TokenStream; use quote::quote; @@ -12,12 +13,10 @@ use wrapper::wrap_method; use crate::{ attr_parse::derive::Derive, convert::{derive_ffi_type, FfiTypeData, FfiTypeInput}, - emitter::Emitter, }; mod attr_parse; mod convert; -mod emitter; mod ffi_fn; mod getset_gen; mod impl_visitor; diff --git a/ffi/derive/src/wrapper.rs b/ffi/derive/src/wrapper.rs index 17fcb77e083..8ea1286eeb4 100644 --- a/ffi/derive/src/wrapper.rs +++ b/ffi/derive/src/wrapper.rs @@ -1,3 +1,4 @@ +use iroha_macro_utils::Emitter; use manyhow::emit; use proc_macro2::{Span, TokenStream}; use quote::quote; @@ -6,7 +7,6 @@ use syn2::{parse_quote, visit_mut::VisitMut, Attribute, Ident, Type}; use crate::{ attr_parse::derive::{Derive, RustcDerive}, convert::FfiTypeInput, - emitter::Emitter, ffi_fn, getset_gen::{gen_resolve_type, gen_store_name}, impl_visitor::{unwrap_result_type, Arg, FnDescriptor, ImplDescriptor, TypeImplTraitResolver}, diff --git a/macro/utils/Cargo.toml b/macro/utils/Cargo.toml index 74e9e6faf51..08c1dce1270 100644 --- a/macro/utils/Cargo.toml +++ b/macro/utils/Cargo.toml @@ -14,6 +14,9 @@ maintenance = { status = "actively-developed" } [dependencies] syn = { workspace = true, features = ["default", "parsing", "printing"] } +syn2 = { workspace = true, features = ["default", "parsing", "printing"] } +darling = { workspace = true } quote = { workspace = true } proc-macro2 = { workspace = true } -proc-macro-error = { workspace = true } +manyhow = { workspace = true } +drop_bomb = "0.1.5" diff --git a/ffi/derive/src/emitter.rs b/macro/utils/src/emitter.rs similarity index 97% rename from ffi/derive/src/emitter.rs rename to macro/utils/src/emitter.rs index 193d961c663..f5edda28b1b 100644 --- a/ffi/derive/src/emitter.rs +++ b/macro/utils/src/emitter.rs @@ -1,8 +1,9 @@ +//! A wrapper type around [`manyhow::Emitter`] that provides a more ergonomic API. + use drop_bomb::DropBomb; use manyhow::ToTokensError; use proc_macro2::TokenStream; -// TODO: move this type to `derive-primitives` crate /// A wrapper type around [`manyhow::Emitter`] that provides a more ergonomic API. /// /// This type is used to accumulate errors during parsing and code generation. diff --git a/macro/utils/src/lib.rs b/macro/utils/src/lib.rs index 2d6d6ef3e70..9f19785d07c 100644 --- a/macro/utils/src/lib.rs +++ b/macro/utils/src/lib.rs @@ -1,5 +1,9 @@ //! Module for various functions and structs to build macros in iroha. +mod emitter; + +pub use emitter::Emitter; + /// Trait for attribute parsing generalization pub trait AttrParser { /// Attribute identifier `#[IDENT...]` @@ -65,3 +69,101 @@ macro_rules! attr_struct { } }; } + +/// Parses a single attribute of the form `#[attr_name(...)]` for darling using a `syn::parse::Parse` implementation. +/// +/// If no attribute with specified name is found, returns `Ok(None)`. +pub fn parse_single_list_attr_opt( + attr_name: &str, + attrs: &[syn2::Attribute], +) -> darling::Result> { + let mut accumulator = darling::error::Accumulator::default(); + + // first, ensure there is only one attribute with the requested name + // take the first one if there are multiple + let matching_attrs = attrs + .iter() + .filter(|a| a.path().is_ident(attr_name)) + .collect::>(); + let attr = match *matching_attrs.as_slice() { + [] => { + return accumulator.finish_with(None); + } + [attr] => attr, + [attr, ref tail @ ..] => { + // allow parsing to proceed further to collect more errors + accumulator.push( + darling::Error::custom(format!("Only one #[{}] attribute is allowed!", attr_name)) + .with_span( + &tail + .iter() + .map(syn2::spanned::Spanned::span) + .reduce(|a, b| a.join(b).unwrap()) + .unwrap(), + ), + ); + attr + } + }; + + let mut kind = None; + + match &attr.meta { + syn2::Meta::Path(_) | syn2::Meta::NameValue(_) => accumulator.push(darling::Error::custom( + format!("Expected #[{}(...)] attribute to be a list", attr_name), + )), + syn2::Meta::List(list) => { + kind = accumulator.handle(syn2::parse2(list.tokens.clone()).map_err(Into::into)); + } + } + + accumulator.finish_with(kind) +} + +/// Parses a single attribute of the form `#[attr_name(...)]` for darling using a `syn::parse::Parse` implementation. +/// +/// If no attribute with specified name is found, returns an error. +pub fn parse_single_list_attr( + attr_name: &str, + attrs: &[syn2::Attribute], +) -> darling::Result { + parse_single_list_attr_opt(attr_name, attrs)? + .ok_or_else(|| darling::Error::custom(format!("Missing `#[{}(...)]` attribute", attr_name))) +} + +/// Macro for automatic [`syn::parse::Parse`] impl generation for keyword +/// attribute structs in derive macros. +#[macro_export] +macro_rules! attr_struct2 { + // Matching struct with named fields + ( + $( #[$meta:meta] )* + // ^~~~attributes~~~~^ + $vis:vis struct $name:ident { + $( + $( #[$field_meta:meta] )* + // ^~~~field attributes~~~!^ + $field_vis:vis $field_name:ident : $field_ty:ty + // ^~~~~~~~~~~~~~~~~a single field~~~~~~~~~~~~~~~^ + ),* + $(,)? } + ) => { + $( #[$meta] )* + $vis struct $name { + $( + $( #[$field_meta] )* + $field_vis $field_name : $field_ty + ),* + } + + impl syn2::parse::Parse for $name { + fn parse(input: syn2::parse::ParseStream) -> syn2::Result { + Ok(Self { + $( + $field_name: input.parse()?, + )* + }) + } + } + }; +} From 3c6e97a363c035ba97a420c4e3690ab430a231a3 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Wed, 13 Sep 2023 14:56:23 +0300 Subject: [PATCH 14/55] [refactor] #3882: Make derive(Filter) use darling Signed-off-by: Nikita Strygin --- Cargo.lock | 3 + data_model/derive/Cargo.toml | 3 + data_model/derive/src/filter.rs | 273 ++++++++++++++---------------- data_model/derive/src/lib.rs | 11 +- data_model/derive/tests/filter.rs | 110 ++++++++++++ 5 files changed, 255 insertions(+), 145 deletions(-) create mode 100644 data_model/derive/tests/filter.rs diff --git a/Cargo.lock b/Cargo.lock index b26ac45ea5f..0f31f1171e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3173,9 +3173,12 @@ name = "iroha_data_model_derive" version = "2.0.0-pre-rc.19" dependencies = [ "darling", + "derive_more", "iroha_data_model", "iroha_macro_utils", + "iroha_schema", "manyhow", + "parity-scale-codec", "proc-macro2", "quote", "serde", diff --git a/data_model/derive/Cargo.toml b/data_model/derive/Cargo.toml index bee036dd7ef..c170ebc37e1 100644 --- a/data_model/derive/Cargo.toml +++ b/data_model/derive/Cargo.toml @@ -23,6 +23,9 @@ iroha_macro_utils = { workspace = true } [dev-dependencies] iroha_data_model = { workspace = true, features = ["http"] } +iroha_schema = { workspace = true } +parity-scale-codec = { workspace = true } +derive_more = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } diff --git a/data_model/derive/src/filter.rs b/data_model/derive/src/filter.rs index 4725f0c45ac..3fccf4e73ac 100644 --- a/data_model/derive/src/filter.rs +++ b/data_model/derive/src/filter.rs @@ -1,50 +1,92 @@ #![allow( clippy::mixed_read_write_in_expression, - clippy::unwrap_in_result, clippy::arithmetic_side_effects )] +use darling::{FromDeriveInput, FromVariant}; +use iroha_macro_utils::Emitter; +use manyhow::emit; use proc_macro2::TokenStream; use quote::{format_ident, quote}; -use syn2::{ - parse::{Parse, ParseStream}, - punctuated::Punctuated, - Attribute, Generics, Ident, Token, Variant, Visibility, -}; +use syn2::{Generics, Ident, Variant, Visibility}; -pub struct EventEnum { +#[derive(FromDeriveInput)] +#[darling(supports(enum_tuple))] +struct EventEnum { vis: Visibility, ident: Ident, generics: Generics, - variants: Punctuated, + data: darling::ast::Data, } -pub enum EventVariant { - EventField { variant: Ident, field: Ident }, - IdField(Ident), +enum EventVariant { + /// A variant of event that delegates to some other event. Identified by conventional naming of the event types: ending with `Event`. + /// Delegates all the filterting to the corresponding event's filter. + Delegating { + variant_name: Ident, + delegated_event_ty_name: Ident, + }, + /// An actual event. Has either an Id or an identifiable object as a payload + /// The presense of the Id field is not required by this macro per se, but will be enfored by `OriginFilter` requiring a `HasOrigin` impl. + Direct(Ident), +} + +impl FromVariant for EventVariant { + fn from_variant(variant: &Variant) -> darling::Result { + let syn2::Fields::Unnamed(fields) = &variant.fields else { + return Err(darling::Error::custom("Expected an enum with unnamed fields").with_span(&variant.fields)); + }; + // note: actually, we have only one field in the event variants + // this is not enforced by this macro, but by `IntoSchema` + let Some(first_field_ty) = fields.unnamed.first().map(|v| &v.ty) else { + return Err(darling::Error::custom("Expected at least one field").with_span(&fields)); + }; + let syn2::Type::Path(path) = first_field_ty else { + return Err(darling::Error::custom("Only identifiers supported as event types").with_span(first_field_ty)); + }; + let Some(first_field_ty_name) = path.path.get_ident() else { + return Err(darling::Error::custom("Only identifiers supported as event types").with_span(first_field_ty)); + }; + + if first_field_ty_name.to_string().ends_with("Event") { + Ok(EventVariant::Delegating { + variant_name: variant.ident.clone(), + delegated_event_ty_name: first_field_ty_name.clone(), + }) + } else { + Ok(EventVariant::Direct(variant.ident.clone())) + } + } } impl EventEnum { + fn variants(&self) -> &[EventVariant] { + match &self.data { + darling::ast::Data::Enum(variants) => variants, + _ => unreachable!("BUG: only enums should be here"), + } + } + /// Used to produce fields like `ByAccount(crate::prelude::FilterOpt)` in `DomainEventFilter`. - fn generate_filter_variants_with_event_fields(&self) -> Vec { - self.variants + fn generate_filter_variants_for_delegating_events(&self) -> Vec { + self.variants() .iter() .filter_map(|variant| match variant { - EventVariant::IdField(_) => None, - EventVariant::EventField { - variant: variant_ident, - field: field_ident, + EventVariant::Direct(_) => None, + EventVariant::Delegating { + variant_name, + delegated_event_ty_name, } => { // E.g. `Account` field in the event => `ByAccount` in the event filter - let filter_variant_ident = format_ident!("By{}", variant_ident); + let filter_variant_ident = format_ident!("By{}", variant_name); // E.g. `AccountEvent` inner field from `Account` variant in event => // `AccountFilter` inside the event filter - let inner_filter_ident = format_ident!( + let inner_filter_ident = + format_ident!( "{}Filter", - field_ident - .to_string() - .strip_suffix("Event") - .expect("Variant name should have suffix `Event`"), + delegated_event_ty_name.to_string().strip_suffix("Event").expect( + "BUG: Variant name should have suffix `Event` (checked in FromVariant)" + ), ); let import_path = quote! {crate::prelude}; Some(quote! { @@ -55,36 +97,36 @@ impl EventEnum { } /// Used to produce fields like `ByCreated` in `DomainEventFilter`. - fn generate_filter_variants_with_id_fields(&self) -> Vec { - self.variants + fn generate_filter_variants_for_direct_events(&self) -> Vec { + self.variants() .iter() .filter_map(|variant| match variant { - EventVariant::IdField(event_variant_ident) => { + EventVariant::Direct(event_variant_ident) => { // Event fields such as `MetadataRemoved` get mapped to `ByMetadataRemoved` let filter_variant_ident = format_ident!("By{}", event_variant_ident); Some(filter_variant_ident) } - EventVariant::EventField { .. } => None, + EventVariant::Delegating { .. } => None, }) .collect() } /// Match arms for `Filter` impls of event filters of the form /// `(Self::ByAccount(filter_opt), crate::prelude::DomainEvent::Account(event)) => {filter_opt.matches(event)}`. - fn generate_filter_impls_with_event_fields(&self) -> Vec { - self.variants + fn generate_filter_impls_for_delegaring_events(&self) -> Vec { + self.variants() .iter() .filter_map(|variant| match variant { - EventVariant::IdField(_) => None, - EventVariant::EventField { - variant: event_variant_ident, + EventVariant::Direct(_) => None, + EventVariant::Delegating { + variant_name, .. } => { let event_ident = &self.ident; - let filter_variant_ident = format_ident!("By{}", event_variant_ident); + let filter_variant_ident = format_ident!("By{}", variant_name); let import_path = quote! {crate::prelude}; Some(quote! { - (Self::#filter_variant_ident(filter_opt), #import_path::#event_ident::#event_variant_ident(event)) => { + (Self::#filter_variant_ident(filter_opt), #import_path::#event_ident::#variant_name(event)) => { filter_opt.matches(event) }}) @@ -93,11 +135,11 @@ impl EventEnum { /// Match arms for `Filter` impls of event filters of the form /// `(Self::ByCreated, crate::prelude::DomainEvent::Created(_))`. - fn generate_filter_impls_with_id_fields(&self) -> Vec { - self.variants + fn generate_filter_impls_for_direct_events(&self) -> Vec { + self.variants() .iter() .filter_map(|variant| match variant { - EventVariant::IdField(event_variant_ident) => { + EventVariant::Direct(event_variant_ident) => { let event_ident = &self.ident; let filter_variant_ident = format_ident!("By{}", event_variant_ident); let import_path = quote! {crate::prelude}; @@ -106,74 +148,15 @@ impl EventEnum { (Self::#filter_variant_ident, #import_path::#event_ident::#event_variant_ident(_)) }) }, - EventVariant::EventField { .. } => None, + EventVariant::Delegating { .. } => None, }) .collect() } } -impl Parse for EventEnum { - fn parse(input: ParseStream) -> syn2::Result { - let _attrs = input.call(Attribute::parse_outer)?; - let vis = input.parse()?; - let _enum_token = input.parse::()?; - let ident = input.parse::()?; - let generics = input.parse::()?; - let content; - let _brace_token = syn2::braced!(content in input); - let variants = content.parse_terminated(EventVariant::parse, Token![,])?; - if ident.to_string().ends_with("Event") { - Ok(EventEnum { - vis, - ident, - generics, - variants, - }) - } else { - Err(syn2::Error::new_spanned( - ident, - "Bad ident: only derivable for `...Event` enums", - )) - } - } -} - -impl Parse for EventVariant { - fn parse(input: ParseStream) -> syn2::Result { - let variant = input.parse::()?; - let variant_ident = variant.ident; - let field_type = variant - .fields - .into_iter() - .next() - .expect("Variant should have at least one unnamed field") - .ty; - if let syn2::Type::Path(path) = field_type { - let field_ident = path - .path - .get_ident() - .expect("Should be an ident-convertible path"); - - if field_ident.to_string().ends_with("Event") { - Ok(EventVariant::EventField { - variant: variant_ident, - field: field_ident.clone(), - }) - } else { - Ok(EventVariant::IdField(variant_ident)) - } - } else { - Err(syn2::Error::new_spanned( - field_type, - "Unexpected AST type variant", - )) - } - } -} - -/// Generates the filter for the event. E.g. for `AccountEvent`, `AccountFilter` +/// Generates the event filter for the event. E.g. for `AccountEvent`, `AccountEventFilter` /// and its `impl Filter` are generated. -pub fn impl_filter(event: &EventEnum) -> TokenStream { +fn impl_event_filter(event: &EventEnum) -> proc_macro2::TokenStream { let EventEnum { vis, ident: event_ident, @@ -181,91 +164,97 @@ pub fn impl_filter(event: &EventEnum) -> TokenStream { .. } = event; - let event_filter_and_impl = impl_event_filter(event); + let id_variants = event.generate_filter_variants_for_direct_events(); + let event_variants = event.generate_filter_variants_for_delegating_events(); - let filter_ident = format_ident!( - "{}Filter", - event_ident - .to_string() - .strip_suffix("Event") - .expect("Events should follow the naming format") - ); - let event_filter_ident = format_ident!("{}Filter", event_ident); + let id_impls = event.generate_filter_impls_for_direct_events(); + let event_impls = event.generate_filter_impls_for_delegaring_events(); + let event_filter_ident = format_ident!("{}Filter", event_ident); let import_path = quote! { crate::prelude }; - let fil_opt = quote! { #import_path::FilterOpt }; - let orig_fil = quote! { #import_path::OriginFilter }; let imp_event = quote! { #import_path::#event_ident }; - let filter_doc = format!(" Filter for {event_ident} entity"); + let event_filter_doc = format!(" Event filter for {event_ident} entity"); quote! { iroha_data_model_derive::model_single! { - #[derive(Debug, Clone, PartialEq, Eq, derive_more::Constructor, Decode, Encode, Deserialize, Serialize, IntoSchema)] - #[doc = #filter_doc] - #vis struct #filter_ident #generics { - origin_filter: #fil_opt<#orig_fil<#imp_event>>, - event_filter: #fil_opt<#event_filter_ident> + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + #[allow(clippy::enum_variant_names, missing_docs)] + #[doc = #event_filter_doc] + #vis enum #event_filter_ident #generics { + #(#id_variants),*, + #(#event_variants),* } } #[cfg(feature = "transparent_api")] - impl #import_path::Filter for #filter_ident { + impl #import_path::Filter for #event_filter_ident { type Event = #imp_event; - fn matches(&self, event: &Self::Event) -> bool { - self.origin_filter.matches(event) && self.event_filter.matches(event) + fn matches(&self, event: &#imp_event) -> bool { + match (self, event) { + #(#id_impls)|* => true, + #(#event_impls),* + _ => false, + } } } - - #event_filter_and_impl } } -/// Generates the event filter for the event. E.g. for `AccountEvent`, `AccountEventFilter` +/// Generates the filter for the event. E.g. for `AccountEvent`, `AccountFilter` /// and its `impl Filter` are generated. -fn impl_event_filter(event: &EventEnum) -> proc_macro2::TokenStream { +pub fn impl_filter(emitter: &mut Emitter, input: &syn2::DeriveInput) -> TokenStream { + let Some(event) = emitter.handle(EventEnum::from_derive_input(input)) else { + return quote!(); + }; + let EventEnum { vis, ident: event_ident, generics, .. - } = event; + } = &event; - let id_variants = event.generate_filter_variants_with_id_fields(); - let event_variants = event.generate_filter_variants_with_event_fields(); + let event_filter_and_impl = impl_event_filter(&event); - let id_impls = event.generate_filter_impls_with_id_fields(); - let event_impls = event.generate_filter_impls_with_event_fields(); + let event_base = event_ident.to_string().strip_suffix("Event").map_or_else( + || { + emit!(emitter, event_ident, "Event name should end with `Event`"); + event_ident.to_string() + }, + ToString::to_string, + ); + let filter_ident = format_ident!("{}Filter", event_base); let event_filter_ident = format_ident!("{}Filter", event_ident); + let import_path = quote! { crate::prelude }; + let fil_opt = quote! { #import_path::FilterOpt }; + let orig_fil = quote! { #import_path::OriginFilter }; let imp_event = quote! { #import_path::#event_ident }; - let event_filter_doc = format!(" Event filter for {event_ident} entity"); + let filter_doc = format!(" Filter for {event_ident} entity"); quote! { iroha_data_model_derive::model_single! { - #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] - #[allow(clippy::enum_variant_names, missing_docs)] - #[doc = #event_filter_doc] - #vis enum #event_filter_ident #generics { - #(#id_variants),*, - #(#event_variants),* + #[derive(Debug, Clone, PartialEq, Eq, derive_more::Constructor, Decode, Encode, Deserialize, Serialize, IntoSchema)] + #[doc = #filter_doc] + #vis struct #filter_ident #generics { + origin_filter: #fil_opt<#orig_fil<#imp_event>>, + event_filter: #fil_opt<#event_filter_ident> } } #[cfg(feature = "transparent_api")] - impl #import_path::Filter for #event_filter_ident { + impl #import_path::Filter for #filter_ident { type Event = #imp_event; - fn matches(&self, event: &#imp_event) -> bool { - match (self, event) { - #(#id_impls)|* => true, - #(#event_impls),* - _ => false, - } + fn matches(&self, event: &Self::Event) -> bool { + self.origin_filter.matches(event) && self.event_filter.matches(event) } } + + #event_filter_and_impl } } diff --git a/data_model/derive/src/lib.rs b/data_model/derive/src/lib.rs index 61b17a51b09..577404cdaa4 100644 --- a/data_model/derive/src/lib.rs +++ b/data_model/derive/src/lib.rs @@ -400,10 +400,15 @@ pub fn id_eq_ord_hash(input: TokenStream) -> Result { /// It assumes that the derive is imported and referred to by its original name. #[manyhow] #[proc_macro_derive(Filter)] -pub fn filter_derive(input: TokenStream) -> Result { - let input = syn2::parse2(input)?; +pub fn filter_derive(input: TokenStream) -> TokenStream { + let mut emitter = Emitter::new(); - Ok(filter::impl_filter(&input)) + let Some(input) = emitter.handle(syn2::parse2(input)) else { + return emitter.finish_token_stream(); + }; + + let result = filter::impl_filter(&mut emitter, &input); + emitter.finish_token_stream_with(result) } /// Derive `::serde::Serialize` trait for `enum` with possibility to avoid tags for selected variants diff --git a/data_model/derive/tests/filter.rs b/data_model/derive/tests/filter.rs new file mode 100644 index 00000000000..27e54a056f1 --- /dev/null +++ b/data_model/derive/tests/filter.rs @@ -0,0 +1,110 @@ +//! A smoke-test for the `derive(Filter)` + +use iroha_data_model::{ + prelude::{HasOrigin, Identifiable}, + IdBox, +}; +use iroha_data_model_derive::{Filter, IdEqOrdHash}; +use iroha_schema::IntoSchema; +use parity_scale_codec::{Decode, Encode}; +use serde::{Deserialize, Serialize}; + +// These are dummy types for the FilterDerive to work +// They would not work with `feature = transparent_api`, but are enough for the smoke test +mod prelude { + use iroha_schema::IntoSchema; + use parity_scale_codec::{Decode, Encode}; + use serde::{Deserialize, Serialize}; + + #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encode, Decode, IntoSchema)] + pub struct FilterOpt(T); + + #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encode, Decode, IntoSchema)] + pub struct OriginFilter(T); + + pub use super::LayerEvent; +} + +#[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + Encode, + Decode, + IntoSchema, +)] +pub struct SubLayerEvent; + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encode, Decode, IntoSchema)] +pub struct SubLayerFilter; + +#[derive( + Copy, + Clone, + IntoSchema, + Ord, + PartialOrd, + Eq, + PartialEq, + Serialize, + Deserialize, + Decode, + Encode, + Debug, + Hash, +)] +pub struct LayerId { + name: u32, +} + +impl HasOrigin for LayerEvent { + type Origin = Layer; + + fn origin_id(&self) -> &::Id { + todo!() + } +} + +#[derive(Debug, IdEqOrdHash)] +pub struct Layer { + id: LayerId, +} + +impl From for IdBox { + fn from(_: LayerId) -> Self { + unreachable!() + } +} + +/// The tested type +#[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + Encode, + Decode, + IntoSchema, + Filter, +)] +pub enum LayerEvent { + SubLayer(SubLayerEvent), + Created(LayerId), +} + +#[test] +fn filter() { + // nothing much to test here... + // I guess we do test that it compiles +} From 65440406187ad37b2ac8c1dde5f48c1d8b649ba8 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Thu, 14 Sep 2023 10:47:31 +0300 Subject: [PATCH 15/55] [refactor] #3882: Make derive(IdEqOrdHash) use darling, add tests Signed-off-by: Nikita Strygin --- data_model/derive/src/id.rs | 189 ++++++++++++------ data_model/derive/src/lib.rs | 11 +- data_model/derive/tests/id_eq_ord_hash.rs | 117 +++++++++++ .../derive/tests/{ => ui_pass}/filter.rs | 6 +- 4 files changed, 255 insertions(+), 68 deletions(-) create mode 100644 data_model/derive/tests/id_eq_ord_hash.rs rename data_model/derive/tests/{ => ui_pass}/filter.rs (95%) diff --git a/data_model/derive/src/id.rs b/data_model/derive/src/id.rs index ad57dfd789e..18af318dcf7 100644 --- a/data_model/derive/src/id.rs +++ b/data_model/derive/src/id.rs @@ -1,16 +1,109 @@ #![allow(clippy::str_to_string, clippy::mixed_read_write_in_expression)] -use manyhow::{bail, Result}; +use darling::{FromAttributes, FromDeriveInput, FromField}; +use iroha_macro_utils::Emitter; +use manyhow::emit; use proc_macro2::TokenStream; -use quote::quote; +use quote::{quote, ToTokens}; use syn2::parse_quote; -pub fn impl_id(input: &syn2::ItemStruct) -> Result { +mod kw { + syn2::custom_keyword!(transparent); +} + +enum IdAttr { + Missing, + Normal, + Transparent, +} + +impl FromAttributes for IdAttr { + fn from_attributes(attrs: &[syn2::Attribute]) -> darling::Result { + let mut accumulator = darling::error::Accumulator::default(); + let attrs = attrs + .iter() + .filter(|v| v.path().is_ident("id")) + .collect::>(); + let attr = match attrs.as_slice() { + [] => { + return accumulator.finish_with(IdAttr::Missing); + } + [attr] => attr, + [attr, ref tail @ ..] => { + accumulator.push( + darling::Error::custom("Only one `#[id]` attribute is allowed!").with_span( + &tail + .iter() + .map(syn2::spanned::Spanned::span) + .reduce(|a, b| a.join(b).unwrap()) + .unwrap(), + ), + ); + attr + } + }; + + let result = match &attr.meta { + syn2::Meta::Path(_) => IdAttr::Normal, + syn2::Meta::List(list) if list.parse_args::().is_ok() => { + IdAttr::Transparent + } + _ => { + accumulator.push( + darling::Error::custom("Expected `#[id]` or `#[id(transparent)]`") + .with_span(&attr), + ); + IdAttr::Normal + } + }; + + accumulator.finish_with(result) + } +} + +#[derive(FromDeriveInput)] +#[darling(supports(struct_any))] +struct IdDeriveInput { + ident: syn2::Ident, + generics: syn2::Generics, + data: darling::ast::Data, +} + +struct IdField { + ident: Option, + ty: syn2::Type, + id_attr: IdAttr, +} + +impl FromField for IdField { + fn from_field(field: &syn2::Field) -> darling::Result { + let ident = field.ident.clone(); + let ty = field.ty.clone(); + let id_attr = IdAttr::from_attributes(&field.attrs)?; + + Ok(Self { ident, ty, id_attr }) + } +} + +impl IdDeriveInput { + fn fields(&self) -> &darling::ast::Fields { + match &self.data { + darling::ast::Data::Struct(fields) => fields, + _ => unreachable!(), + } + } +} + +pub fn impl_id_eq_ord_hash(emitter: &mut Emitter, input: &syn2::DeriveInput) -> TokenStream { + let Some(input) = emitter.handle(IdDeriveInput::from_derive_input(input)) else { + return quote!(); + }; + let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let identifiable_derive = derive_identifiable(input)?; + let identifiable_derive = derive_identifiable(emitter, &input); - Ok(quote! { + quote! { #identifiable_derive impl #impl_generics ::core::cmp::PartialOrd for #name #ty_generics #where_clause where Self: Identifiable { @@ -38,15 +131,15 @@ pub fn impl_id(input: &syn2::ItemStruct) -> Result { self.id().hash(state); } } - }) + } } -fn derive_identifiable(input: &syn2::ItemStruct) -> Result { +fn derive_identifiable(emitter: &mut Emitter, input: &IdDeriveInput) -> TokenStream { let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let (id_type, id_expr) = get_id_type(input)?; + let (id_type, id_expr) = get_id_type(emitter, input); - Ok(quote! { + quote! { impl #impl_generics Identifiable for #name #ty_generics #where_clause { type Id = #id_type; @@ -55,66 +148,42 @@ fn derive_identifiable(input: &syn2::ItemStruct) -> Result { #id_expr } } - }) + } } -fn get_id_type(input: &syn2::ItemStruct) -> Result<(TokenStream, TokenStream)> { - match &input.fields { - syn2::Fields::Named(fields) => { - for field in &fields.named { - let (field_name, field_ty) = (&field.ident, &field.ty); - - if is_identifier(&field.attrs) { - return Ok((quote! {#field_ty}, quote! {&self.#field_name})); - } - if is_transparent(&field.attrs) { - return Ok(( - quote! {<#field_ty as Identifiable>::Id}, - quote! {Identifiable::id(&self.#field_name)}, - )); - } +fn get_id_type(emitter: &mut Emitter, input: &IdDeriveInput) -> (syn2::Type, syn2::Expr) { + for (field_index, IdField { ty, ident, id_attr }) in input.fields().iter().enumerate() { + let field_name = ident.as_ref().map_or_else( + || syn2::Index::from(field_index).to_token_stream(), + ToTokens::to_token_stream, + ); + match id_attr { + IdAttr::Normal => { + return (ty.clone(), parse_quote! {&self.#field_name}); } - } - syn2::Fields::Unnamed(fields) => { - for (i, field) in fields.unnamed.iter().enumerate() { - let (field_id, field_ty): (syn2::Index, _) = (i.into(), &field.ty); - - if is_identifier(&field.attrs) { - return Ok((quote! {#field_ty}, quote! {&self.#field_id})); - } - if is_transparent(&field.attrs) { - return Ok(( - quote! {<#field_ty as Identifiable>::Id}, - quote! {Identifiable::id(&self.#field_id)}, - )); - } + IdAttr::Transparent => { + return ( + parse_quote! {<#ty as Identifiable>::Id}, + parse_quote! {Identifiable::id(&self.#field_name)}, + ); + } + IdAttr::Missing => { + // nothing here } } - syn2::Fields::Unit => {} } - match &input.fields { - syn2::Fields::Named(named) => { - for field in &named.named { - let field_ty = &field.ty; - - if field.ident.as_ref().expect("Field must be named") == "id" { - return Ok((quote! {#field_ty}, quote! {&self.id})); - } - } + for field in input.fields().iter() { + if field.ident.as_ref().is_some_and(|i| i == "id") { + return (field.ty.clone(), parse_quote! {&self.id}); } - syn2::Fields::Unnamed(_) | syn2::Fields::Unit => {} } - bail!(input, "Identifier not found") -} - -fn is_identifier(attrs: &[syn2::Attribute]) -> bool { - attrs.iter().any(|attr| attr == &parse_quote! {#[id]}) -} + emit!( + emitter, + "Could not find the identifier field. Either mark it with `#[id]` or have it named `id`" + ); -fn is_transparent(attrs: &[syn2::Attribute]) -> bool { - attrs - .iter() - .any(|attr| attr == &parse_quote! {#[id(transparent)]}) + // return dummy types + (parse_quote! {()}, parse_quote! {()}) } diff --git a/data_model/derive/src/lib.rs b/data_model/derive/src/lib.rs index 577404cdaa4..657a23633b5 100644 --- a/data_model/derive/src/lib.rs +++ b/data_model/derive/src/lib.rs @@ -230,10 +230,15 @@ pub fn model_single(input: TokenStream) -> TokenStream { /// #[manyhow] #[proc_macro_derive(IdEqOrdHash, attributes(id, opaque))] -pub fn id_eq_ord_hash(input: TokenStream) -> Result { - let input = syn2::parse2(input)?; +pub fn id_eq_ord_hash(input: TokenStream) -> TokenStream { + let mut emitter = Emitter::new(); - id::impl_id(&input) + let Some(input) = emitter.handle(syn2::parse2(input)) else { + return emitter.finish_token_stream(); + }; + + let result = id::impl_id_eq_ord_hash(&mut emitter, &input); + emitter.finish_token_stream_with(result) } /// [`Filter`] is used for code generation of `...Filter` structs and `...EventFilter` enums, as well as diff --git a/data_model/derive/tests/id_eq_ord_hash.rs b/data_model/derive/tests/id_eq_ord_hash.rs new file mode 100644 index 00000000000..91e94df415d --- /dev/null +++ b/data_model/derive/tests/id_eq_ord_hash.rs @@ -0,0 +1,117 @@ +//! Basic tests for traits derived by [`IdEqOrdHash`] macro + +use std::collections::BTreeSet; + +use iroha_data_model_derive::IdEqOrdHash; + +/// fake `Identifiable` trait +/// +/// Doesn't require `Into` implementation +pub trait Identifiable: Ord + Eq { + /// Type of the entity identifier + type Id: Ord + Eq + core::hash::Hash; + + /// Get reference to the type identifier + fn id(&self) -> &Self::Id; +} + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +struct ObjectId(char); + +#[derive(Debug, IdEqOrdHash)] +struct Object { + id: ObjectId, + #[allow(unused)] + data: i32, +} +#[derive(Debug, IdEqOrdHash)] +struct ObjectWithExplicitId { + #[id] + definitely_not_id: ObjectId, + #[allow(unused)] + data: i32, +} +#[derive(Debug, IdEqOrdHash)] +struct ObjectWithTransparentId { + #[id(transparent)] // delegate the id to `Object` type + definitely_not_id: Object, + #[allow(unused)] + data: i32, +} + +// some objects to play with in tests +const ID_A: ObjectId = ObjectId('A'); +const ID_B: ObjectId = ObjectId('B'); +const OBJECT_1A: Object = Object { id: ID_A, data: 1 }; +const OBJECT_1B: Object = Object { id: ID_B, data: 1 }; +const OBJECT_2A: Object = Object { id: ID_A, data: 2 }; +const EXPLICIT_OBJECT_1A: ObjectWithExplicitId = ObjectWithExplicitId { + definitely_not_id: ID_A, + data: 1, +}; +const EXPLICIT_OBJECT_1B: ObjectWithExplicitId = ObjectWithExplicitId { + definitely_not_id: ID_B, + data: 1, +}; +const EXPLICIT_OBJECT_2A: ObjectWithExplicitId = ObjectWithExplicitId { + definitely_not_id: ID_A, + data: 2, +}; +const TRANSPARENT_OBJECT_1A: ObjectWithTransparentId = ObjectWithTransparentId { + definitely_not_id: OBJECT_1A, + data: 1, +}; +const TRANSPARENT_OBJECT_1B: ObjectWithTransparentId = ObjectWithTransparentId { + definitely_not_id: OBJECT_1B, + data: 1, +}; +const TRANSPARENT_OBJECT_2A: ObjectWithTransparentId = ObjectWithTransparentId { + definitely_not_id: OBJECT_2A, + data: 2, +}; + +#[test] +fn id() { + assert_eq!(OBJECT_1A.id(), &ID_A); + assert_eq!(OBJECT_1B.id(), &ID_B); + assert_eq!(EXPLICIT_OBJECT_1A.id(), &ID_A); + assert_eq!(EXPLICIT_OBJECT_1B.id(), &ID_B); + assert_eq!(TRANSPARENT_OBJECT_1A.id(), &ID_A); + assert_eq!(TRANSPARENT_OBJECT_1B.id(), &ID_B); +} + +#[test] +fn id_eq() { + assert_eq!(OBJECT_1A, OBJECT_2A); + assert_ne!(OBJECT_1B, OBJECT_2A); + assert_eq!(EXPLICIT_OBJECT_1A, EXPLICIT_OBJECT_2A); + assert_ne!(EXPLICIT_OBJECT_1B, EXPLICIT_OBJECT_2A); + assert_eq!(TRANSPARENT_OBJECT_1A, TRANSPARENT_OBJECT_2A); + assert_ne!(TRANSPARENT_OBJECT_1B, TRANSPARENT_OBJECT_2A); +} + +#[test] +fn id_ord() { + assert!(OBJECT_1A < OBJECT_1B); + assert!(OBJECT_1B > OBJECT_1A); + assert!(EXPLICIT_OBJECT_1A < EXPLICIT_OBJECT_1B); + assert!(EXPLICIT_OBJECT_1B > EXPLICIT_OBJECT_1A); + assert!(TRANSPARENT_OBJECT_1A < TRANSPARENT_OBJECT_1B); + assert!(TRANSPARENT_OBJECT_1B > TRANSPARENT_OBJECT_1A); +} + +#[test] +fn id_hash() { + let mut set = BTreeSet::new(); + set.insert(OBJECT_1A); + set.insert(OBJECT_2A); + assert_eq!(set.len(), 1); + assert!(set.contains(&OBJECT_1A)); + assert!(!set.contains(&OBJECT_1B)); + assert!(set.contains(&OBJECT_2A)); + set.insert(OBJECT_1B); + assert_eq!(set.len(), 2); + assert!(set.contains(&OBJECT_1A)); + assert!(set.contains(&OBJECT_1B)); + assert!(set.contains(&OBJECT_2A)); +} diff --git a/data_model/derive/tests/filter.rs b/data_model/derive/tests/ui_pass/filter.rs similarity index 95% rename from data_model/derive/tests/filter.rs rename to data_model/derive/tests/ui_pass/filter.rs index 27e54a056f1..94dccc72e95 100644 --- a/data_model/derive/tests/filter.rs +++ b/data_model/derive/tests/ui_pass/filter.rs @@ -103,8 +103,4 @@ pub enum LayerEvent { Created(LayerId), } -#[test] -fn filter() { - // nothing much to test here... - // I guess we do test that it compiles -} +fn main() {} From a2f280a11f30d11457c90035cdc861cf43a72d19 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Fri, 15 Sep 2023 15:01:50 +0300 Subject: [PATCH 16/55] [refactor] #3882: Make PartiallyTaggedSerialize/Deserialize use darling Signed-off-by: Nikita Strygin --- data_model/derive/src/lib.rs | 4 +- data_model/derive/src/partially_tagged.rs | 127 ++++++------------ .../derive/tests/partial_tagged_serde.rs | 7 +- 3 files changed, 49 insertions(+), 89 deletions(-) diff --git a/data_model/derive/src/lib.rs b/data_model/derive/src/lib.rs index 657a23633b5..e61eff96d8c 100644 --- a/data_model/derive/src/lib.rs +++ b/data_model/derive/src/lib.rs @@ -447,7 +447,7 @@ pub fn filter_derive(input: TokenStream) -> TokenStream { pub fn partially_tagged_serialize_derive(input: TokenStream) -> Result { let input = syn2::parse2(input)?; - Ok(partially_tagged::impl_partially_tagged_serialize(&input)) + partially_tagged::impl_partially_tagged_serialize(&input) } /// Derive `::serde::Deserialize` trait for `enum` with possibility to avoid tags for selected variants @@ -510,7 +510,7 @@ pub fn partially_tagged_serialize_derive(input: TokenStream) -> Result Result { let input = syn2::parse2(input)?; - Ok(partially_tagged::impl_partially_tagged_deserialize(&input)) + partially_tagged::impl_partially_tagged_deserialize(&input) } /// Derive macro for `HasOrigin`. diff --git a/data_model/derive/src/partially_tagged.rs b/data_model/derive/src/partially_tagged.rs index 830d4e65c6a..f446f3e1b91 100644 --- a/data_model/derive/src/partially_tagged.rs +++ b/data_model/derive/src/partially_tagged.rs @@ -1,89 +1,52 @@ #![allow(clippy::too_many_lines)] +// darling-generated code triggers this lint +#![allow(clippy::option_if_let_else)] + +use darling::{FromDeriveInput, FromVariant}; +use manyhow::Result; use proc_macro2::TokenStream; use quote::{format_ident, quote}; -use syn2::{ - parse::{Parse, ParseStream}, - parse_quote, - punctuated::Punctuated, - spanned::Spanned, - Attribute, Generics, Ident, Token, Type, Variant, Visibility, -}; +use syn2::{parse_quote, Attribute, Generics, Ident, Type}; +#[derive(FromDeriveInput)] +#[darling(forward_attrs(serde), supports(enum_newtype))] pub struct PartiallyTaggedEnum { - attrs: Vec, ident: Ident, - variants: Punctuated, generics: Generics, + data: darling::ast::Data, + attrs: Vec, } +#[derive(FromVariant)] +#[darling(forward_attrs(serde), attributes(serde_partially_tagged))] pub struct PartiallyTaggedVariant { - attrs: Vec, ident: Ident, - ty: Type, - is_untagged: bool, -} - -impl Parse for PartiallyTaggedEnum { - fn parse(input: ParseStream) -> syn2::Result { - let mut attrs = input.call(Attribute::parse_outer)?; - let _vis = input.parse::()?; - let _enum_token = input.parse::()?; - let ident = input.parse::()?; - let generics = input.parse::()?; - let content; - let _brace_token = syn2::braced!(content in input); - let variants = content.parse_terminated(PartiallyTaggedVariant::parse, Token![,])?; - attrs.retain(is_serde_attr); - Ok(PartiallyTaggedEnum { - attrs, - ident, - variants, - generics, - }) - } -} - -impl Parse for PartiallyTaggedVariant { - fn parse(input: ParseStream) -> syn2::Result { - let variant = input.parse::()?; - let Variant { - ident, - fields, - mut attrs, - .. - } = variant; - let field = match fields { - syn2::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => fields - .unnamed - .into_iter() - .next() - .expect("Guaranteed to have exactly one field"), - fields => { - return Err(syn2::Error::new( - fields.span(), - "Only supports tuple variants with single field", - )) - } - }; - let ty = field.ty; - let is_untagged = attrs.iter().any(is_untagged_attr); - attrs.retain(is_serde_attr); - Ok(PartiallyTaggedVariant { - attrs, - ident, - ty, - is_untagged, - }) - } + fields: darling::ast::Fields, + attrs: Vec, + #[darling(default)] + untagged: bool, } impl PartiallyTaggedEnum { fn variants(&self) -> impl Iterator { - self.variants.iter() + match &self.data { + darling::ast::Data::Enum(variants) => variants.iter(), + _ => unreachable!( + "Only enums are supported. Enforced by `darling(supports(enum_newtype))`" + ), + } } fn untagged_variants(&self) -> impl Iterator { - self.variants.iter().filter(|variant| variant.is_untagged) + self.variants().filter(|variant| variant.untagged) + } +} + +impl PartiallyTaggedVariant { + fn ty(&self) -> &syn2::Type { + self.fields.fields.first().expect( + "BUG: Only newtype enums are supported. Enforced by `darling(supports(enum_newtype))`", + ) } } @@ -95,26 +58,16 @@ fn variants_to_tuple<'lt, I: Iterator>( (Vec::new(), Vec::new(), Vec::new()), |(mut idents, mut types, mut attrs), variant| { idents.push(&variant.ident); - types.push(&variant.ty); + types.push(&variant.ty()); attrs.push(&variant.attrs); (idents, types, attrs) }, ) } -/// Check if enum variant should be treated as untagged -fn is_untagged_attr(attr: &Attribute) -> bool { - attr == &parse_quote!(#[serde_partially_tagged(untagged)]) -} +pub fn impl_partially_tagged_serialize(input: &syn2::DeriveInput) -> Result { + let enum_ = PartiallyTaggedEnum::from_derive_input(input)?; -/// Check if `#[serde...]` attribute -fn is_serde_attr(attr: &Attribute) -> bool { - attr.path() - .get_ident() - .map_or_else(|| false, |ident| ident.to_string().eq("serde")) -} - -pub fn impl_partially_tagged_serialize(enum_: &PartiallyTaggedEnum) -> TokenStream { let enum_ident = &enum_.ident; let enum_attrs = &enum_.attrs; let ref_internal_repr_ident = format_ident!("{}RefInternalRepr", enum_ident); @@ -133,7 +86,7 @@ pub fn impl_partially_tagged_serialize(enum_: &PartiallyTaggedEnum) -> TokenStre let (ref_internal_impl_generics, ref_internal_type_generics, ref_internal_where_clause) = ref_internal_generics.split_for_impl(); - quote! { + Ok(quote! { impl #impl_generics ::serde::Serialize for #enum_ident #type_generics #where_clause { fn serialize(&self, serializer: S) -> Result where @@ -181,10 +134,12 @@ pub fn impl_partially_tagged_serialize(enum_: &PartiallyTaggedEnum) -> TokenStre wrapper.serialize(serializer) } } - } + }) } -pub fn impl_partially_tagged_deserialize(enum_: &PartiallyTaggedEnum) -> TokenStream { +pub fn impl_partially_tagged_deserialize(input: &syn2::DeriveInput) -> Result { + let enum_ = PartiallyTaggedEnum::from_derive_input(input)?; + let enum_ident = &enum_.ident; let enum_attrs = &enum_.attrs; let internal_repr_ident = format_ident!("{}InternalRepr", enum_ident); @@ -211,7 +166,7 @@ pub fn impl_partially_tagged_deserialize(enum_: &PartiallyTaggedEnum) -> TokenSt let (internal_repr_impl_generics, internal_repr_type_generics, internal_repr_where_clause) = internal_repr_generics.split_for_impl(); - quote! { + Ok(quote! { impl #impl_generics ::serde::Deserialize<'de> for #enum_ident #type_generics #where_clause { fn deserialize(deserializer: D) -> Result where @@ -346,5 +301,5 @@ pub fn impl_partially_tagged_deserialize(enum_: &PartiallyTaggedEnum) -> TokenSt } } } - } + }) } diff --git a/data_model/derive/tests/partial_tagged_serde.rs b/data_model/derive/tests/partial_tagged_serde.rs index 99e11e06e0e..d04f79868e6 100644 --- a/data_model/derive/tests/partial_tagged_serde.rs +++ b/data_model/derive/tests/partial_tagged_serde.rs @@ -7,6 +7,7 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; #[derive(Debug, PartialEq, Eq, PartiallyTaggedDeserialize, PartiallyTaggedSerialize)] enum Value { Bool(bool), + #[serde(rename = "StringRenamed")] String(String), #[serde_partially_tagged(untagged)] Numeric(NumericValue), @@ -62,7 +63,11 @@ fn partially_tagged_serde() { Value::String("I am string".to_owned()), Value::Numeric(NumericValue(42)), ]; - let serialized_values = [r#"{"Bool":true}"#, r#"{"String":"I am string"}"#, r#""42""#]; + let serialized_values = [ + r#"{"Bool":true}"#, + r#"{"StringRenamed":"I am string"}"#, + r#""42""#, + ]; for (value, serialized_value) in values.iter().zip(serialized_values.iter()) { let serialized = serde_json::to_string(value) From 017ddff4fd93a999dc968ce43ef37398df2c784e Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Fri, 15 Sep 2023 15:44:25 +0300 Subject: [PATCH 17/55] [feature] #3737: Add support for usage of Self type in serde partially tagged enums Signed-off-by: Nikita Strygin --- data_model/derive/Cargo.toml | 2 +- .../mod.rs} | 35 ++++++++--- .../src/partially_tagged/resolve_self.rs | 63 +++++++++++++++++++ .../derive/tests/partial_tagged_serde_self.rs | 39 ++++++++++++ data_model/src/predicate.rs | 6 +- 5 files changed, 132 insertions(+), 13 deletions(-) rename data_model/derive/src/{partially_tagged.rs => partially_tagged/mod.rs} (92%) create mode 100644 data_model/derive/src/partially_tagged/resolve_self.rs create mode 100644 data_model/derive/tests/partial_tagged_serde_self.rs diff --git a/data_model/derive/Cargo.toml b/data_model/derive/Cargo.toml index c170ebc37e1..5cb877d609f 100644 --- a/data_model/derive/Cargo.toml +++ b/data_model/derive/Cargo.toml @@ -14,7 +14,7 @@ workspace = true proc-macro = true [dependencies] -syn2 = { workspace = true, features = ["default", "full", "extra-traits"] } +syn2 = { workspace = true, features = ["default", "full", "extra-traits", "visit-mut"] } quote = { workspace = true } darling = { workspace = true } proc-macro2 = { workspace = true } diff --git a/data_model/derive/src/partially_tagged.rs b/data_model/derive/src/partially_tagged/mod.rs similarity index 92% rename from data_model/derive/src/partially_tagged.rs rename to data_model/derive/src/partially_tagged/mod.rs index f446f3e1b91..a17fd95aeb0 100644 --- a/data_model/derive/src/partially_tagged.rs +++ b/data_model/derive/src/partially_tagged/mod.rs @@ -2,6 +2,8 @@ // darling-generated code triggers this lint #![allow(clippy::option_if_let_else)] +mod resolve_self; + use darling::{FromDeriveInput, FromVariant}; use manyhow::Result; use proc_macro2::TokenStream; @@ -40,25 +42,36 @@ impl PartiallyTaggedEnum { fn untagged_variants(&self) -> impl Iterator { self.variants().filter(|variant| variant.untagged) } + + /// Returns a type that corresponds to `Self`, handling the generics as necessary + fn self_ty(&self) -> syn2::Type { + let ident = &self.ident; + let (_, type_generics, _) = self.generics.split_for_impl(); + + parse_quote!(#ident #type_generics) + } } impl PartiallyTaggedVariant { - fn ty(&self) -> &syn2::Type { - self.fields.fields.first().expect( + fn ty(&self, self_ty: &syn2::Type) -> syn2::Type { + let ty = self.fields.fields.first().expect( "BUG: Only newtype enums are supported. Enforced by `darling(supports(enum_newtype))`", - ) + ).clone(); + + resolve_self::resolve_self(self_ty, ty) } } /// Convert from vector of variants to tuple of vectors consisting of variant's fields fn variants_to_tuple<'lt, I: Iterator>( + self_ty: &syn2::Type, variants: I, -) -> (Vec<&'lt Ident>, Vec<&'lt Type>, Vec<&'lt [Attribute]>) { +) -> (Vec<&'lt Ident>, Vec, Vec<&'lt [Attribute]>) { variants.fold( (Vec::new(), Vec::new(), Vec::new()), |(mut idents, mut types, mut attrs), variant| { idents.push(&variant.ident); - types.push(&variant.ty()); + types.push(variant.ty(self_ty)); attrs.push(&variant.attrs); (idents, types, attrs) }, @@ -72,9 +85,11 @@ pub fn impl_partially_tagged_serialize(input: &syn2::DeriveInput) -> Result Result { + self_ty: &'a syn2::Type, +} + +impl VisitMut for Visitor<'_> { + fn visit_type_mut(&mut self, ty: &mut syn2::Type) { + match ty { + syn2::Type::Path(path_ty) + if path_ty.qself.is_none() && path_ty.path.is_ident("Self") => + { + *ty = self.self_ty.clone(); + } + _ => syn2::visit_mut::visit_type_mut(self, ty), + } + } +} + +/// Transforms the [`resolving_ty`] by replacing `Self` with [`self_ty`]. +/// +/// This is required to be able to use `Self` in `PartiallyTaggedSerialize` and `PartiallyTaggedDeserialize`, +/// as they define an additional intermediate type during serialization/deserialization. Using `Self` there would refer to an incorrect type. +pub fn resolve_self(self_ty: &syn2::Type, mut resolving_ty: syn2::Type) -> syn2::Type { + Visitor { self_ty }.visit_type_mut(&mut resolving_ty); + resolving_ty +} + +#[cfg(test)] +mod tests { + use quote::ToTokens; + use syn2::{parse_quote, Type}; + + #[test] + fn test_resolve_self() { + let test_types = [ + parse_quote!(i32), + parse_quote!(Self), + parse_quote!(Vec), + parse_quote!((Self, Self)), + parse_quote!(::Type), + ]; + let expected_types = [ + parse_quote!(i32), + parse_quote!(()), + parse_quote!(Vec<()>), + parse_quote!(((), ())), + parse_quote!(<() as Trait>::Type), + ]; + let _: &Type = &test_types[0]; + let _: &Type = &expected_types[0]; + + for (test_type, expected_type) in test_types.iter().zip(expected_types.iter()) { + let resolved = super::resolve_self(&parse_quote!(()), test_type.clone()); + assert_eq!( + resolved, + *expected_type, + "Failed to resolve `Self` in `{}`", + test_type.to_token_stream() + ); + } + } +} diff --git a/data_model/derive/tests/partial_tagged_serde_self.rs b/data_model/derive/tests/partial_tagged_serde_self.rs new file mode 100644 index 00000000000..e4520e6ee03 --- /dev/null +++ b/data_model/derive/tests/partial_tagged_serde_self.rs @@ -0,0 +1,39 @@ +//! A test for `PartiallyTaggedSerialize` and `PartiallyTaggedDeserialize` which uses `Self` as a type + +use iroha_data_model_derive::{PartiallyTaggedDeserialize, PartiallyTaggedSerialize}; + +#[derive(Debug, PartialEq, Eq, PartiallyTaggedSerialize, PartiallyTaggedDeserialize)] +enum Expr { + Negate(Box), + #[serde_partially_tagged(untagged)] + Atom(T), +} + +#[test] +fn partially_tagged_serde() { + use Expr::*; + + let values = [ + Atom(42), + Negate(Box::new(Atom(42))), + Negate(Box::new(Negate(Box::new(Atom(42))))), + ]; + let serialized_values = [r#"42"#, r#"{"Negate":42}"#, r#"{"Negate":{"Negate":42}}"#]; + + for (value, serialized_value) in values.iter().zip(serialized_values.iter()) { + let serialized = serde_json::to_string(value) + .unwrap_or_else(|e| panic!("Failed to serialize `{:?}`: {:?}", value, e)); + assert_eq!( + serialized, *serialized_value, + "Serialized form of `{:?}` does not match the expected value", + value + ); + let deserialized: Expr = serde_json::from_str(serialized_value) + .unwrap_or_else(|e| panic!("Failed to deserialize `{:?}`: {:?}", serialized_value, e)); + assert_eq!( + *value, deserialized, + "Deserialized form of `{:?}` does not match the expected value", + value + ); + } +} diff --git a/data_model/src/predicate.rs b/data_model/src/predicate.rs index aff82bc25de..da9cc267b59 100644 --- a/data_model/src/predicate.rs +++ b/data_model/src/predicate.rs @@ -91,11 +91,11 @@ macro_rules! nontrivial { // references (e.g. &Value). pub enum GenericPredicateBox