From 485c0157f1161e439374df41f71cffc65e667c9b Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Thu, 22 Feb 2024 17:53:56 +0100 Subject: [PATCH 1/9] Add send_mana and prepare_send_mana (#2038) * Add send_mana and prepare_send_mana * Add send-mana to CLI * Add return_strategy * Add SendManaParams * match return_strategy * Adapt CLI * gift * Comment * Update cli/src/wallet_cli/mod.rs Co-authored-by: DaughterOfMars --------- Co-authored-by: DaughterOfMars --- Cargo.lock | 201 +++++++++--------- cli/src/wallet_cli/mod.rs | 41 +++- sdk/src/wallet/mod.rs | 1 + .../operations/transaction/high_level/mod.rs | 1 + .../transaction/high_level/send_mana.rs | 95 +++++++++ .../operations/transaction/prepare_output.rs | 2 +- 6 files changed, 233 insertions(+), 108 deletions(-) create mode 100644 sdk/src/wallet/operations/transaction/high_level/send_mana.rs diff --git a/Cargo.lock b/Cargo.lock index 01d2d20049..ce584ab1fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,9 +29,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" dependencies = [ "cfg-if", "once_cell", @@ -81,9 +81,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540" dependencies = [ "anstyle", "anstyle-parse", @@ -129,9 +129,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "anymap" @@ -159,7 +159,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -268,7 +268,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -341,9 +341,9 @@ checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "a3b1be7772ee4501dba05acbe66bb1e8760f6a6c474a36035631638e4415f130" [[package]] name = "byte-slice-cast" @@ -376,11 +376,10 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" dependencies = [ - "jobserver", "libc", ] @@ -425,9 +424,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ "num-traits", ] @@ -456,9 +455,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", "clap_derive", @@ -466,9 +465,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstream", "anstyle", @@ -485,7 +484,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -519,9 +518,9 @@ dependencies = [ [[package]] name = "clipboard-win" -version = "5.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec832972fefb8cf9313b45a0d1945e29c9c251f1d4c6eafc5fe2124c02d2e81" +checksum = "12f9a0700e0127ba15d1d52dd742097f821cd9c65939303a44d970465040a297" dependencies = [ "error-code", ] @@ -669,7 +668,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -719,14 +718,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "darling" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8" +checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955" dependencies = [ "darling_core", "darling_macro", @@ -734,27 +733,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3" +checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "darling_macro" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77" +checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" dependencies = [ "darling_core", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -815,7 +814,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1170,7 +1169,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1350,9 +1349,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "hex" @@ -1519,9 +1518,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", "hashbrown", @@ -1750,9 +1749,9 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe8f25ce1159c7740ff0b9b2f5cdf4a8428742ba7c112b9f20f22cd5219c7dab" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", "libc", @@ -1777,15 +1776,6 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" -[[package]] -name = "jobserver" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" -dependencies = [ - "libc", -] - [[package]] name = "js-sys" version = "0.3.68" @@ -1979,9 +1969,9 @@ dependencies = [ [[package]] name = "napi" -version = "2.15.1" +version = "2.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43792514b0c95c5beec42996da0c1b39265b02b75c97baa82d163d3ef55cbfa7" +checksum = "02bd92040344a83763379b122f4e714932ccaa700439e647f1e90481dd1999cb" dependencies = [ "bitflags 2.4.2", "ctor", @@ -1993,34 +1983,34 @@ dependencies = [ [[package]] name = "napi-build" -version = "2.1.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b4532cf86bfef556348ac65e561e3123879f0e7566cca6d43a6ff5326f13df" +checksum = "2f9130fccc5f763cf2069b34a089a18f0d0883c66aceb81f2fad541a3d823c43" [[package]] name = "napi-derive" -version = "2.15.1" +version = "2.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d56bb899c164ab1be5e542ae7db8b26750c864bf2eef07295f17754e6358777" +checksum = "e56bd9f0bd84c1f138c5cb22bbf394f75d796b24dad689599ca94cf94e61cc21" dependencies = [ "cfg-if", "convert_case", "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "napi-derive-backend" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cf2d74ac66fd1cccb646be75fdd1c1dce8acfe20a68f61566a31da0d3eb9786" +checksum = "d03b8f403a37007cad225039fc0323b961bb40d697eea744140920ebb689ff1d" dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2101,9 +2091,9 @@ dependencies = [ [[package]] name = "num_threads" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] @@ -2281,9 +2271,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "platforms" @@ -2354,7 +2344,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2468,7 +2458,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2480,7 +2470,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2646,16 +2636,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2821,14 +2812,14 @@ checksum = "e5af959c8bf6af1aff6d2b463a57f71aae53d1332da58419e30ad8dc7011d951" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "salsa20" @@ -2924,35 +2915,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -2967,7 +2958,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3184,7 +3175,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3197,7 +3188,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3219,9 +3210,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", @@ -3263,28 +3254,28 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.13" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3378,7 +3369,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3458,7 +3449,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3528,9 +3519,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -3653,7 +3644,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "wasm-bindgen-shared", ] @@ -3687,7 +3678,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3951,9 +3942,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.39" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] @@ -4031,7 +4022,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4052,5 +4043,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index 5b7ff66755..e167e3ea69 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -24,8 +24,8 @@ use iota_sdk::{ utils::ConvertTo, wallet::{ types::OutputData, BeginStakingParams, ConsolidationParams, CreateDelegationParams, CreateNativeTokenParams, - Error as WalletError, MintNftParams, OutputsToClaim, SendNativeTokenParams, SendNftParams, SendParams, - SyncOptions, TransactionOptions, Wallet, + Error as WalletError, MintNftParams, OutputsToClaim, ReturnStrategy, SendManaParams, SendNativeTokenParams, + SendNftParams, SendParams, SyncOptions, TransactionOptions, Wallet, }, U256, }; @@ -272,6 +272,16 @@ pub enum WalletCommand { #[arg(long, default_value_t = false)] allow_micro_amount: bool, }, + /// Send mana. + SendMana { + /// Recipient address, e.g. rms1qztwng6cty8cfm42nzvq099ev7udhrnk0rw8jt8vttf9kpqnxhpsx869vr3. + address: Bech32Address, + /// Amount of mana to send, e.g. 1000000. + mana: u64, + /// Whether to gift the storage deposit or not. + #[arg(short, long, default_value_t = false)] + gift: bool, + }, /// Send a native token. /// This will create an output with an expiration and storage deposit return unlock condition. SendNativeToken { @@ -1033,6 +1043,29 @@ pub async fn send_command( Ok(()) } +// `send-mana` command +pub async fn send_mana_command( + wallet: &Wallet, + address: impl ConvertTo, + mana: u64, + gift: bool, +) -> Result<(), Error> { + let params = SendManaParams::new(mana, address.convert()?).with_return_strategy(if gift { + ReturnStrategy::Gift + } else { + ReturnStrategy::Return + }); + let transaction = wallet.send_mana(params, None).await?; + + println_log_info!( + "Transaction sent:\n{:?}\n{:?}", + transaction.transaction_id, + transaction.block_id + ); + + Ok(()) +} + // `send-native-token` command pub async fn send_native_token_command( wallet: &Wallet, @@ -1557,6 +1590,10 @@ pub async fn prompt_internal( }; send_command(wallet, address, amount, return_address, expiration, allow_micro_amount).await } + WalletCommand::SendMana { address, mana, gift } => { + ensure_password(wallet).await?; + send_mana_command(wallet, address, mana, gift).await + } WalletCommand::SendNativeToken { address, token_id, diff --git a/sdk/src/wallet/mod.rs b/sdk/src/wallet/mod.rs index 65dc73ccb4..9cc6316633 100644 --- a/sdk/src/wallet/mod.rs +++ b/sdk/src/wallet/mod.rs @@ -62,6 +62,7 @@ pub use self::{ mint_nfts::MintNftParams, }, send::SendParams, + send_mana::SendManaParams, send_native_tokens::SendNativeTokenParams, send_nft::SendNftParams, staking::begin::BeginStakingParams, diff --git a/sdk/src/wallet/operations/transaction/high_level/mod.rs b/sdk/src/wallet/operations/transaction/high_level/mod.rs index 4834aa9328..0312a91efe 100644 --- a/sdk/src/wallet/operations/transaction/high_level/mod.rs +++ b/sdk/src/wallet/operations/transaction/high_level/mod.rs @@ -7,6 +7,7 @@ pub(crate) mod create_account; pub(crate) mod delegation; pub(crate) mod minting; pub(crate) mod send; +pub(crate) mod send_mana; pub(crate) mod send_native_tokens; pub(crate) mod send_nft; pub(crate) mod staking; diff --git a/sdk/src/wallet/operations/transaction/high_level/send_mana.rs b/sdk/src/wallet/operations/transaction/high_level/send_mana.rs new file mode 100644 index 0000000000..cad5629277 --- /dev/null +++ b/sdk/src/wallet/operations/transaction/high_level/send_mana.rs @@ -0,0 +1,95 @@ +// Copyright 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserialize, Serialize}; + +use crate::{ + client::{api::PreparedTransactionData, secret::SecretManage}, + types::block::{ + address::Bech32Address, + output::{ + unlock_condition::{AddressUnlockCondition, StorageDepositReturnUnlockCondition}, + BasicOutputBuilder, + }, + }, + utils::serde::string, + wallet::{ + operations::transaction::{prepare_output::ReturnStrategy, TransactionOptions, TransactionWithMetadata}, + Wallet, + }, +}; + +/// Params for `send_mana()`. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SendManaParams { + #[serde(with = "string")] + mana: u64, + address: Bech32Address, + return_strategy: Option, +} + +impl SendManaParams { + pub fn new(mana: u64, address: Bech32Address) -> Self { + Self { + mana, + address, + return_strategy: None, + } + } + + pub fn with_return_strategy(mut self, return_strategy: ReturnStrategy) -> Self { + self.return_strategy.replace(return_strategy); + self + } +} + +impl Wallet +where + crate::wallet::Error: From, + crate::client::Error: From, +{ + pub async fn send_mana( + &self, + params: SendManaParams, + options: impl Into> + Send, + ) -> crate::wallet::Result { + let options = options.into(); + let prepared_transaction = self.prepare_send_mana(params, options.clone()).await?; + + self.sign_and_submit_transaction(prepared_transaction, options).await + } + + pub async fn prepare_send_mana( + &self, + params: SendManaParams, + options: impl Into> + Send, + ) -> crate::wallet::Result { + log::debug!("[TRANSACTION] prepare_send_mana"); + let return_strategy = params.return_strategy.unwrap_or_default(); + let storage_score_params = self.client().get_storage_score_parameters().await?; + + let mut output_builder = BasicOutputBuilder::new_with_minimum_amount(storage_score_params) + .with_mana(params.mana) + .add_unlock_condition(AddressUnlockCondition::new(params.address)); + + match return_strategy { + ReturnStrategy::Return => { + output_builder = output_builder.add_unlock_condition(StorageDepositReturnUnlockCondition::new( + self.address().await.inner().clone(), + 1, + )?); + let return_amount = output_builder.clone().finish()?.amount(); + output_builder = output_builder.replace_unlock_condition(StorageDepositReturnUnlockCondition::new( + self.address().await.inner().clone(), + return_amount, + )?); + } + ReturnStrategy::Gift => {} + } + + let output = output_builder.finish_output()?; + + self.prepare_transaction(vec![output], options).await + } +} diff --git a/sdk/src/wallet/operations/transaction/prepare_output.rs b/sdk/src/wallet/operations/transaction/prepare_output.rs index 2d08f60fea..3daf27b867 100644 --- a/sdk/src/wallet/operations/transaction/prepare_output.rs +++ b/sdk/src/wallet/operations/transaction/prepare_output.rs @@ -113,7 +113,7 @@ where let min_amount_basic_output = BasicOutput::minimum_amount(&Address::from(Ed25519Address::null()), storage_score_params); - let min_required_storage_deposit = first_output.minimum_amount(storage_score_params); + let min_required_storage_deposit = first_output.amount(); if params.amount > min_required_storage_deposit { second_output_builder = second_output_builder.with_amount(params.amount); From 23623631126768f082def54531f7aaf9077b56be Mon Sep 17 00:00:00 2001 From: DaughterOfMars Date: Thu, 22 Feb 2024 14:51:07 -0500 Subject: [PATCH 2/9] Feat/remove protocol params default (#1969) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove default impl from protocol params * update packable * fix tests * fix some features * update bindings * typo * stupid features * docstr * update network info * add shimmer params * fix last test * fix tests that were broken by merge * wasm fix * fix flaky test * review * comment broken test * deprecated * review * Update sdk/src/client/builder.rs Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> * protocol_parameter_samples * order! * Add missing feature flags, fix Mana values in tests * move network info up so that it can be fetched earlier * fix wasm * fix wallet address set * nvm * more merge issues * fix test * fix offline python test * fix stupid auto import * hope this works --------- Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Co-authored-by: Thibault Martinez Co-authored-by: Thoralf Müller --- Cargo.lock | 68 +---- bindings/core/Cargo.toml | 7 +- bindings/core/src/method/utils.rs | 77 +++-- bindings/core/src/method_handler/utils.rs | 6 + bindings/core/tests/combined.rs | 14 +- .../nodejs/lib/types/client/client-options.ts | 5 +- .../nodejs/lib/types/utils/bridge/index.ts | 6 +- .../nodejs/lib/types/utils/bridge/utils.ts | 8 + bindings/nodejs/lib/utils/utils.ts | 14 + bindings/nodejs/tests/wallet/wallet.spec.ts | 34 ++- bindings/python/iota_sdk/client/client.py | 4 + bindings/python/iota_sdk/utils.py | 12 + .../python/tests/address_generation_test.py | 10 +- bindings/python/tests/test_offline.py | 2 +- bindings/python/tests/test_wallet_destroy.py | 14 +- bindings/wasm/tests/wallet.spec.ts | 3 +- cli/Cargo.toml | 2 +- cli/src/wallet_cli/mod.rs | 2 +- sdk/Cargo.toml | 7 +- sdk/src/client/api/block_builder/mod.rs | 4 +- sdk/src/client/builder.rs | 83 ++++-- sdk/src/client/core.rs | 46 +-- sdk/src/client/node_api/core/routes.rs | 2 + sdk/src/client/node_api/indexer/routes.rs | 4 +- sdk/src/client/node_api/mqtt/mod.rs | 5 +- sdk/src/client/node_manager/syncing.rs | 26 +- sdk/src/client/secret/ledger_nano.rs | 9 +- sdk/src/client/utils.rs | 6 +- sdk/src/types/block/address/bech32.rs | 8 +- sdk/src/types/block/address/multi.rs | 50 ++-- sdk/src/types/block/address/restricted.rs | 14 +- sdk/src/types/block/capabilities.rs | 6 +- sdk/src/types/block/context_input/mod.rs | 9 +- sdk/src/types/block/core/basic.rs | 17 +- sdk/src/types/block/core/block.rs | 27 +- sdk/src/types/block/core/parent.rs | 4 +- sdk/src/types/block/core/validation.rs | 39 ++- sdk/src/types/block/mana/allotment.rs | 17 +- sdk/src/types/block/mana/parameters.rs | 68 +---- sdk/src/types/block/mana/rewards.rs | 30 +- sdk/src/types/block/output/account.rs | 33 +-- sdk/src/types/block/output/anchor.rs | 33 +-- sdk/src/types/block/output/basic.rs | 40 ++- sdk/src/types/block/output/delegation.rs | 46 ++- .../block/output/feature/block_issuer.rs | 14 +- .../types/block/output/feature/metadata.rs | 35 +-- sdk/src/types/block/output/feature/mod.rs | 6 +- .../block/output/feature/state_metadata.rs | 16 +- sdk/src/types/block/output/foundry.rs | 29 +- sdk/src/types/block/output/native_token.rs | 12 +- sdk/src/types/block/output/nft.rs | 28 +- sdk/src/types/block/output/output_id.rs | 2 +- sdk/src/types/block/output/storage_score.rs | 32 +-- .../types/block/output/token_scheme/simple.rs | 11 +- .../output/unlock_condition/expiration.rs | 12 +- .../immutable_account_address.rs | 4 +- .../block/output/unlock_condition/mod.rs | 13 +- .../storage_deposit_return.rs | 6 +- .../block/output/unlock_condition/timelock.rs | 6 +- sdk/src/types/block/payload/mod.rs | 8 +- .../block/payload/signed_transaction/mod.rs | 4 +- .../payload/signed_transaction/transaction.rs | 89 +++--- sdk/src/types/block/protocol/mod.rs | 143 ++-------- sdk/src/types/block/protocol/samples.rs | 252 ++++++++++++++++ sdk/src/types/block/protocol/work_score.rs | 37 +-- sdk/src/types/block/signature/ed25519.rs | 8 +- sdk/src/types/block/slot/epoch.rs | 11 +- sdk/src/types/block/slot/index.rs | 6 +- sdk/src/types/block/unlock/mod.rs | 20 +- sdk/src/types/block/unlock/multi.rs | 6 +- sdk/src/types/fuzz/Cargo.toml | 4 +- sdk/src/wallet/core/builder.rs | 2 +- sdk/src/wallet/core/mod.rs | 22 +- sdk/src/wallet/core/operations/client.rs | 19 +- sdk/src/wallet/operations/transaction/mod.rs | 3 +- sdk/src/wallet/types/balance.rs | 4 +- sdk/src/wallet/update.rs | 3 +- sdk/tests/client/addresses.rs | 17 +- sdk/tests/client/client_builder.rs | 4 +- .../client/input_selection/account_outputs.rs | 269 +++++++++--------- .../client/input_selection/basic_outputs.rs | 116 ++++---- sdk/tests/client/input_selection/burn.rs | 77 ++--- .../input_selection/delegation_outputs.rs | 11 +- .../client/input_selection/expiration.rs | 46 +-- .../client/input_selection/foundry_outputs.rs | 48 ++-- .../client/input_selection/native_tokens.rs | 171 ++++++----- .../client/input_selection/nft_outputs.rs | 58 ++-- sdk/tests/client/input_selection/outputs.rs | 44 +-- .../input_selection/storage_deposit_return.rs | 106 +++---- sdk/tests/client/input_selection/timelock.rs | 12 +- sdk/tests/client/mod.rs | 46 ++- sdk/tests/client/node_api/core.rs | 4 +- sdk/tests/client/signing/account.rs | 13 +- sdk/tests/client/signing/basic.rs | 16 +- sdk/tests/client/signing/delegation.rs | 46 ++- sdk/tests/client/signing/mod.rs | 4 +- sdk/tests/client/signing/nft.rs | 10 +- sdk/tests/mod.rs | 4 +- sdk/tests/types/address/account.rs | 4 +- sdk/tests/types/address/bech32.rs | 4 +- sdk/tests/types/address/ed25519.rs | 4 +- sdk/tests/types/address/multi.rs | 4 +- sdk/tests/types/address/nft.rs | 4 +- sdk/tests/types/address/restricted.rs | 6 +- sdk/tests/types/api/core.rs | 4 +- sdk/tests/types/block.rs | 12 +- sdk/tests/types/block_id.rs | 2 +- sdk/tests/types/ed25519_signature.rs | 5 +- sdk/tests/types/input/utxo.rs | 7 +- sdk/tests/types/mod.rs | 5 + sdk/tests/types/output/account.rs | 8 +- sdk/tests/types/output/basic.rs | 8 +- sdk/tests/types/output/feature/metadata.rs | 4 +- sdk/tests/types/output/foundry.rs | 8 +- sdk/tests/types/output/nft.rs | 8 +- sdk/tests/types/output_id.rs | 2 +- sdk/tests/types/parents.rs | 10 +- sdk/tests/types/payload.rs | 8 +- sdk/tests/types/signed_transaction_payload.rs | 20 +- sdk/tests/types/slot.rs | 2 +- sdk/tests/types/tagged_data_payload.rs | 9 +- sdk/tests/types/transaction.rs | 102 +++---- sdk/tests/types/transaction_id.rs | 2 +- sdk/tests/types/unlock/account.rs | 2 +- sdk/tests/types/unlock/nft.rs | 2 +- sdk/tests/types/unlock/reference.rs | 4 +- sdk/tests/types/unlock/signature.rs | 4 +- sdk/tests/wallet/address_generation.rs | 10 +- sdk/tests/wallet/balance.rs | 1 + sdk/tests/wallet/common/mod.rs | 5 +- sdk/tests/wallet/core.rs | 17 +- sdk/tests/wallet/events.rs | 8 +- .../migrate_stronghold_snapshot_v2_to_v3.rs | 9 +- 133 files changed, 1700 insertions(+), 1524 deletions(-) create mode 100644 sdk/src/types/block/protocol/samples.rs diff --git a/Cargo.lock b/Cargo.lock index ce584ab1fa..d17d9b4709 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -508,7 +508,7 @@ dependencies = [ "prefix-hex", "rustyline", "serde_json", - "strum 0.25.0", + "strum", "thiserror", "tokio", "winapi", @@ -1645,7 +1645,7 @@ dependencies = [ "serde", "serde_json", "serde_repr", - "strum 0.26.1", + "strum", "thiserror", "time", "tokio", @@ -1671,7 +1671,7 @@ dependencies = [ "primitive-types", "serde", "serde_json", - "strum 0.25.0", + "strum", "thiserror", "tokio", "url", @@ -2127,9 +2127,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "packable" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ebbd9715a319d515dbc253604dd00b0e2c8618e4e5e4d3e0b9b4e46b90ef98e" +checksum = "01fc964b1de9aff3b0a0e5c68048d342ca247da967b96b96489617f1bd51cc3d" dependencies = [ "autocfg", "hashbrown", @@ -2140,15 +2140,14 @@ dependencies = [ [[package]] name = "packable-derive" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "858971e010057f7bcae183e545085b83d41280ca8abe0333613a7135fbb54430" +checksum = "0698d973173b50fb1949f7e2e9516544dc1149610262c30b3e9d8ddace1a462e" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", + "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.50", ] [[package]] @@ -2171,7 +2170,7 @@ version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" dependencies = [ - "proc-macro-crate 2.0.2", + "proc-macro-crate", "proc-macro2", "quote", "syn 1.0.109", @@ -2359,16 +2358,6 @@ dependencies = [ "uint", ] -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - [[package]] name = "proc-macro-crate" version = "2.0.2" @@ -2376,7 +2365,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" dependencies = [ "toml_datetime", - "toml_edit 0.20.2", + "toml_edit", ] [[package]] @@ -3147,35 +3136,13 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" -dependencies = [ - "strum_macros 0.25.3", -] - [[package]] name = "strum" version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" dependencies = [ - "strum_macros 0.26.1", -] - -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.50", + "strum_macros", ] [[package]] @@ -3402,17 +3369,6 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - [[package]] name = "toml_edit" version = "0.20.2" diff --git a/bindings/core/Cargo.toml b/bindings/core/Cargo.toml index 0ef374146c..4b7b81d115 100644 --- a/bindings/core/Cargo.toml +++ b/bindings/core/Cargo.toml @@ -11,6 +11,7 @@ publish = false [dependencies] iota-sdk = { path = "../../sdk", default-features = false, features = [ "wallet", + "protocol_parameters_samples", "tls", ] } @@ -23,12 +24,14 @@ iota-crypto = { version = "0.23.1", default-features = false, features = [ "bip44", ] } log = { version = "0.4.20", default-features = false } -packable = { version = "0.10.1", default-features = false } +packable = { version = "0.11.0", default-features = false, features = [ + "primitive-types", +] } prefix-hex = { version = "0.7.1", default-features = false } primitive-types = { version = "0.12.2", default-features = false } serde = { version = "1.0.196", default-features = false } serde_json = { version = "1.0.113", default-features = false } -strum = { version = "0.25.0", default-features = false, features = ["derive"] } +strum = { version = "0.26.1", default-features = false, features = ["derive"] } thiserror = { version = "1.0.56", default-features = false } tokio = { version = "1.35.1", default-features = false } url = { version = "2.4.1", default-features = false, features = ["serde"] } diff --git a/bindings/core/src/method/utils.rs b/bindings/core/src/method/utils.rs index 9bfd0789e3..94b1f472fa 100644 --- a/bindings/core/src/method/utils.rs +++ b/bindings/core/src/method/utils.rs @@ -32,26 +32,47 @@ use crate::OmittedDebug; #[non_exhaustive] pub enum UtilsMethod { /// Transforms bech32 to hex - Bech32ToHex { bech32: Bech32Address }, + Bech32ToHex { + bech32: Bech32Address, + }, /// Transforms a hex encoded address to a bech32 encoded address #[serde(rename_all = "camelCase")] - HexToBech32 { hex: String, bech32_hrp: Hrp }, + HexToBech32 { + hex: String, + bech32_hrp: Hrp, + }, /// Transforms an account id to a bech32 encoded address #[serde(rename_all = "camelCase")] - AccountIdToBech32 { account_id: AccountId, bech32_hrp: Hrp }, + AccountIdToBech32 { + account_id: AccountId, + bech32_hrp: Hrp, + }, /// Transforms an anchor id to a bech32 encoded address #[serde(rename_all = "camelCase")] - AnchorIdToBech32 { anchor_id: AnchorId, bech32_hrp: Hrp }, + AnchorIdToBech32 { + anchor_id: AnchorId, + bech32_hrp: Hrp, + }, /// Transforms an nft id to a bech32 encoded address #[serde(rename_all = "camelCase")] - NftIdToBech32 { nft_id: NftId, bech32_hrp: Hrp }, + NftIdToBech32 { + nft_id: NftId, + bech32_hrp: Hrp, + }, /// Transforms a hex encoded public key to a bech32 encoded address #[serde(rename_all = "camelCase")] - HexPublicKeyToBech32Address { hex: String, bech32_hrp: Hrp }, + HexPublicKeyToBech32Address { + hex: String, + bech32_hrp: Hrp, + }, /// Returns a valid Address parsed from a String. - ParseBech32Address { address: Bech32Address }, + ParseBech32Address { + address: Bech32Address, + }, /// Checks if a String is a valid bech32 encoded address. - IsAddressValid { address: String }, + IsAddressValid { + address: String, + }, /// Generates a new mnemonic. GenerateMnemonic, /// Returns a hex encoded seed for a mnemonic. @@ -66,10 +87,14 @@ pub enum UtilsMethod { protocol_parameters: ProtocolParameters, }, /// Returns the transaction ID (Blake2b256 hash of the provided transaction payload) - TransactionId { payload: SignedTransactionPayloadDto }, + TransactionId { + payload: SignedTransactionPayloadDto, + }, /// Computes the account ID #[serde(rename_all = "camelCase")] - ComputeAccountId { output_id: OutputId }, + ComputeAccountId { + output_id: OutputId, + }, /// Computes the Foundry ID #[serde(rename_all = "camelCase")] ComputeFoundryId { @@ -79,9 +104,14 @@ pub enum UtilsMethod { }, /// Computes the NFT ID #[serde(rename_all = "camelCase")] - ComputeNftId { output_id: OutputId }, + ComputeNftId { + output_id: OutputId, + }, /// Computes the output ID from transaction id and output index - ComputeOutputId { id: TransactionId, index: u16 }, + ComputeOutputId { + id: TransactionId, + index: u16, + }, /// Computes a tokenId from the accountId, serial number and token scheme type. #[serde(rename_all = "camelCase")] ComputeTokenId { @@ -91,9 +121,13 @@ pub enum UtilsMethod { }, /// Computes the hash of the given protocol parameters. #[serde(rename_all = "camelCase")] - ProtocolParametersHash { protocol_parameters: ProtocolParameters }, + ProtocolParametersHash { + protocol_parameters: ProtocolParameters, + }, /// Computes the signing hash of a transaction. - TransactionSigningHash { transaction: TransactionDto }, + TransactionSigningHash { + transaction: TransactionDto, + }, /// Computes the minimum required amount of an output. #[serde(rename_all = "camelCase")] ComputeMinimumOutputAmount { @@ -120,13 +154,18 @@ pub enum UtilsMethod { }, /// Creates a UTXOInput from outputId. #[serde(rename_all = "camelCase")] - OutputIdToUtxoInput { output_id: OutputId }, + OutputIdToUtxoInput { + output_id: OutputId, + }, /// Computes the slot commitment id from a slot commitment. #[serde(rename_all = "camelCase")] - ComputeSlotCommitmentId { slot_commitment: SlotCommitment }, + ComputeSlotCommitmentId { + slot_commitment: SlotCommitment, + }, /// Returns the hex representation of the serialized output bytes. - #[serde(rename_all = "camelCase")] - OutputHexBytes { output: Output }, + OutputHexBytes { + output: Output, + }, /// Verifies the semantic of a transaction. /// Expected response: [`TransactionFailureReason`](crate::Response::TransactionFailureReason) #[serde(rename_all = "camelCase")] @@ -178,4 +217,6 @@ pub enum UtilsMethod { /// Block block: BlockDto, }, + IotaMainnetProtocolParameters, + ShimmerMainnetProtocolParameters, } diff --git a/bindings/core/src/method_handler/utils.rs b/bindings/core/src/method_handler/utils.rs index 2a2ff07a15..78772661ac 100644 --- a/bindings/core/src/method_handler/utils.rs +++ b/bindings/core/src/method_handler/utils.rs @@ -164,6 +164,12 @@ pub(crate) fn call_utils_method_internal(method: UtilsMethod) -> Result { + Response::ProtocolParameters(iota_sdk::types::block::protocol::iota_mainnet_protocol_parameters().clone()) + } + UtilsMethod::ShimmerMainnetProtocolParameters => Response::ProtocolParameters( + iota_sdk::types::block::protocol::shimmer_mainnet_protocol_parameters().clone(), + ), }; Ok(response) diff --git a/bindings/core/tests/combined.rs b/bindings/core/tests/combined.rs index 6c2e89254a..d31787d2cd 100644 --- a/bindings/core/tests/combined.rs +++ b/bindings/core/tests/combined.rs @@ -41,7 +41,12 @@ async fn create_wallet() -> Result<()> { let wallet = WalletOptions::default() .with_storage_path(storage_path.to_string()) - .with_client_options(ClientBuilder::new().from_json(client_options).unwrap()) + .with_client_options( + ClientBuilder::new() + .from_json(client_options) + .unwrap() + .with_protocol_parameters(iota_sdk::types::block::protocol::iota_mainnet_protocol_parameters().clone()), + ) .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) .with_secret_manager(serde_json::from_str::(secret_manager).unwrap()) .build() @@ -79,7 +84,12 @@ async fn client_from_wallet() -> Result<()> { let wallet = WalletOptions::default() .with_storage_path(storage_path.to_string()) - .with_client_options(ClientBuilder::new().from_json(client_options).unwrap()) + .with_client_options( + ClientBuilder::new() + .from_json(client_options) + .unwrap() + .with_protocol_parameters(iota_sdk::types::block::protocol::iota_mainnet_protocol_parameters().clone()), + ) .with_bip_path(Bip44::new(SHIMMER_COIN_TYPE)) .with_secret_manager(serde_json::from_str::(secret_manager).unwrap()) .build() diff --git a/bindings/nodejs/lib/types/client/client-options.ts b/bindings/nodejs/lib/types/client/client-options.ts index 2f4c5e1bbb..5fe0ba5b07 100644 --- a/bindings/nodejs/lib/types/client/client-options.ts +++ b/bindings/nodejs/lib/types/client/client-options.ts @@ -1,6 +1,7 @@ // Copyright 2021-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import type { IMqttBrokerOptions, INetworkInfo, INode } from './network'; +import { ProtocolParameters } from '../models'; +import type { IMqttBrokerOptions, INode } from './network'; /** Options for the client builder */ export interface IClientOptions { @@ -21,7 +22,7 @@ export interface IClientOptions { /** % of nodes that have to return the same response so it gets accepted */ quorumThreshold?: number; /** Data related to the used network */ - networkInfo?: INetworkInfo; + protocolParameters?: ProtocolParameters; /** Options for the MQTT broker */ brokerOptions?: IMqttBrokerOptions; /** Timeout for API requests */ diff --git a/bindings/nodejs/lib/types/utils/bridge/index.ts b/bindings/nodejs/lib/types/utils/bridge/index.ts index 61d2a6b093..3e170e2a52 100644 --- a/bindings/nodejs/lib/types/utils/bridge/index.ts +++ b/bindings/nodejs/lib/types/utils/bridge/index.ts @@ -32,6 +32,8 @@ import type { __OutputManaWithDecay__, __VerifyTransactionSyntax__, __BlockBytes__, + __IotaMainnetProtocolParameters__, + __ShimmerMainnetProtocolParameters__, } from './utils'; export type __UtilsMethods__ = @@ -67,4 +69,6 @@ export type __UtilsMethods__ = | __GenerateManaWithDecay__ | __OutputManaWithDecay__ | __VerifyTransactionSyntax__ - | __BlockBytes__; + | __BlockBytes__ + | __IotaMainnetProtocolParameters__ + | __ShimmerMainnetProtocolParameters__; diff --git a/bindings/nodejs/lib/types/utils/bridge/utils.ts b/bindings/nodejs/lib/types/utils/bridge/utils.ts index 6660fccd85..0dd79ee18f 100644 --- a/bindings/nodejs/lib/types/utils/bridge/utils.ts +++ b/bindings/nodejs/lib/types/utils/bridge/utils.ts @@ -280,3 +280,11 @@ export interface __BlockBytes__ { block: Block; }; } + +export interface __IotaMainnetProtocolParameters__ { + name: 'iotaMainnetProtocolParameters'; +} + +export interface __ShimmerMainnetProtocolParameters__ { + name: 'shimmerMainnetProtocolParameters'; +} diff --git a/bindings/nodejs/lib/utils/utils.ts b/bindings/nodejs/lib/utils/utils.ts index b92bfa3f80..50b079a82c 100644 --- a/bindings/nodejs/lib/utils/utils.ts +++ b/bindings/nodejs/lib/utils/utils.ts @@ -687,4 +687,18 @@ export class Utils { }); return new Uint8Array(blockBytes); } + + static iotaMainnetProtocolParameters(): ProtocolParameters { + const params = callUtilsMethod({ + name: 'iotaMainnetProtocolParameters', + }); + return params; + } + + static shimmerMainnetProtocolParameters(): ProtocolParameters { + const params = callUtilsMethod({ + name: 'shimmerMainnetProtocolParameters', + }); + return params; + } } diff --git a/bindings/nodejs/tests/wallet/wallet.spec.ts b/bindings/nodejs/tests/wallet/wallet.spec.ts index 43db94253b..57542e6cd3 100644 --- a/bindings/nodejs/tests/wallet/wallet.spec.ts +++ b/bindings/nodejs/tests/wallet/wallet.spec.ts @@ -4,7 +4,13 @@ import 'reflect-metadata'; import { describe, it, expect } from '@jest/globals'; -import { Wallet, CoinType, WalletOptions, SecretManager } from '../../lib/'; +import { + Wallet, + CoinType, + WalletOptions, + SecretManager, + Utils, +} from '../../lib/'; describe('Wallet', () => { it('create wallet', async () => { @@ -20,7 +26,9 @@ describe('Wallet', () => { const secretManager = SecretManager.create(strongholdSecretManager); - await secretManager.storeMnemonic('vital give early extra blind skin eight discover scissors there globe deal goat fat load robot return rate fragile recycle select live ordinary claim',); + await secretManager.storeMnemonic( + 'vital give early extra blind skin eight discover scissors there globe deal goat fat load robot return rate fragile recycle select live ordinary claim', + ); const wallet_address = await secretManager.generateEd25519Addresses({ coinType: CoinType.IOTA, @@ -37,6 +45,7 @@ describe('Wallet', () => { storagePath: './test-create-wallet', clientOptions: { nodes: ['https://api.testnet.shimmer.network'], + protocolParameters: Utils.iotaMainnetProtocolParameters(), }, bipPath: { coinType: CoinType.IOTA, @@ -44,14 +53,12 @@ describe('Wallet', () => { secretManager: strongholdSecretManager, }; - const wallet = await Wallet.create(walletOptions); await wallet.destroy(); removeDir(storagePath); }, 20000); - it('recreate wallet', async () => { let storagePath = 'test-recreate-wallet'; removeDir(storagePath); @@ -65,7 +72,9 @@ describe('Wallet', () => { const secretManager = SecretManager.create(strongholdSecretManager); - await secretManager.storeMnemonic('vital give early extra blind skin eight discover scissors there globe deal goat fat load robot return rate fragile recycle select live ordinary claim',); + await secretManager.storeMnemonic( + 'vital give early extra blind skin eight discover scissors there globe deal goat fat load robot return rate fragile recycle select live ordinary claim', + ); const wallet_address = await secretManager.generateEd25519Addresses({ coinType: CoinType.IOTA, @@ -82,6 +91,7 @@ describe('Wallet', () => { storagePath, clientOptions: { nodes: ['https://api.testnet.shimmer.network'], + protocolParameters: Utils.iotaMainnetProtocolParameters(), }, bipPath: { coinType: CoinType.IOTA, @@ -89,12 +99,11 @@ describe('Wallet', () => { secretManager: strongholdSecretManager, }; - const wallet = await Wallet.create(walletOptions); const client = await wallet.getClient(); const hrp = await client.getBech32Hrp(); - expect(hrp).toEqual("smr"); + expect(hrp).toEqual('smr'); await wallet.destroy(); @@ -104,7 +113,7 @@ describe('Wallet', () => { // expect(accounts.length).toStrictEqual(0); await recreatedWallet.destroy(); - removeDir(storagePath) + removeDir(storagePath); }, 20000); it('error after destroy', async () => { @@ -116,8 +125,10 @@ describe('Wallet', () => { snapshotPath: `./${storagePath}/wallet.stronghold`, password: `A12345678*`, }, - } - const secretManager = await SecretManager.create(strongholdSecretManager); + }; + const secretManager = await SecretManager.create( + strongholdSecretManager, + ); await secretManager.storeMnemonic( 'vital give early extra blind skin eight discover scissors there globe deal goat fat load robot return rate fragile recycle select live ordinary claim', ); @@ -137,6 +148,7 @@ describe('Wallet', () => { storagePath, clientOptions: { nodes: ['https://api.testnet.shimmer.network'], + protocolParameters: Utils.iotaMainnetProtocolParameters(), }, bipPath: { coinType: CoinType.IOTA, @@ -163,7 +175,7 @@ describe('Wallet', () => { } removeDir(storagePath); }, 35000); -}) +}); function removeDir(storagePath: string) { const fs = require('fs'); diff --git a/bindings/python/iota_sdk/client/client.py b/bindings/python/iota_sdk/client/client.py index db10174a36..8835d371ff 100644 --- a/bindings/python/iota_sdk/client/client.py +++ b/bindings/python/iota_sdk/client/client.py @@ -16,6 +16,7 @@ from iota_sdk.types.common import HexStr, Node from iota_sdk.types.feature import Feature from iota_sdk.types.network_info import NetworkInfo +from iota_sdk.types.node_info import ProtocolParameters from iota_sdk.types.output import AccountOutput, BasicOutput, FoundryOutput, NftOutput, deserialize_output from iota_sdk.types.payload import Payload from iota_sdk.types.token_scheme import SimpleTokenScheme @@ -36,6 +37,7 @@ def __init__( List[Union[str, Node]]]] = None, nodes: Optional[Union[Union[str, Node], List[Union[str, Node]]]] = None, + protocol_parameters: Optional[ProtocolParameters] = None, ignore_node_health: Optional[bool] = None, api_timeout: Optional[timedelta] = None, node_sync_interval: Optional[timedelta] = None, @@ -81,6 +83,8 @@ def __init__( client_config['primary_nodes'] = convert_nodes(primary_nodes) client_config['nodes'] = convert_nodes(nodes) + if protocol_parameters is not None: + client_config['protocol_parameters'] = protocol_parameters.to_dict() client_config = { k: v for k, diff --git a/bindings/python/iota_sdk/utils.py b/bindings/python/iota_sdk/utils.py index 60ce58ec9e..7154a37a82 100644 --- a/bindings/python/iota_sdk/utils.py +++ b/bindings/python/iota_sdk/utils.py @@ -303,6 +303,18 @@ def block_bytes( 'block': block.as_dict(), })) + @staticmethod + def iota_mainnet_protocol_parameters() -> ProtocolParameters: + """Returns sample protocol parameters for IOTA mainnet. + """ + return ProtocolParameters.from_dict(_call_method('iotaMainnetProtocolParameters')) + + @staticmethod + def shimmer_mainnet_protocol_parameters() -> ProtocolParameters: + """Returns sample protocol parameters for Shimmer mainnet. + """ + return ProtocolParameters.from_dict(_call_method('shimmerMainnetProtocolParameters')) + class UtilsError(Exception): """A utils error.""" diff --git a/bindings/python/tests/address_generation_test.py b/bindings/python/tests/address_generation_test.py index 6c6f6fcbc7..0674245a92 100644 --- a/bindings/python/tests/address_generation_test.py +++ b/bindings/python/tests/address_generation_test.py @@ -2,14 +2,15 @@ # SPDX-License-Identifier: Apache-2.0 import shutil -from iota_sdk import Wallet, MnemonicSecretManager, CoinType, ClientOptions, WalletOptions, Bip44 +from iota_sdk import Wallet, MnemonicSecretManager, CoinType, ClientOptions, WalletOptions, Bip44, Utils def test_address_generation_iota(): db_path = './test_address_generation_iota' shutil.rmtree(db_path, ignore_errors=True) - client_options = ClientOptions(nodes=[]) + client_options = ClientOptions( + nodes=[], protocol_parameters=Utils.iota_mainnet_protocol_parameters()) secret_manager = MnemonicSecretManager( "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast") @@ -28,7 +29,7 @@ def test_address_generation_iota(): address = wallet.address() - assert 'smr1qpg2xkj66wwgn8p2ggnp7p582gj8g6p79us5hve2tsudzpsr2ap4sp36wye' == address + assert 'iota1qpg2xkj66wwgn8p2ggnp7p582gj8g6p79us5hve2tsudzpsr2ap4skprwjg' == address shutil.rmtree(db_path, ignore_errors=True) @@ -36,7 +37,8 @@ def test_address_generation_shimmer(): db_path = './test_address_generation_shimmer' shutil.rmtree(db_path, ignore_errors=True) - client_options = ClientOptions(nodes=[]) + client_options = ClientOptions( + nodes=[], protocol_parameters=Utils.shimmer_mainnet_protocol_parameters()) secret_manager = MnemonicSecretManager( "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast") diff --git a/bindings/python/tests/test_offline.py b/bindings/python/tests/test_offline.py index 536ee757da..5678b7b60e 100644 --- a/bindings/python/tests/test_offline.py +++ b/bindings/python/tests/test_offline.py @@ -11,7 +11,7 @@ with open('../../sdk/tests/client/fixtures/test_vectors.json', "r", encoding="utf-8") as json_file: tv = json.load(json_file) -client = Client() +client = Client(protocol_parameters=Utils.iota_mainnet_protocol_parameters()) def test_mnemonic_address_generation(): diff --git a/bindings/python/tests/test_wallet_destroy.py b/bindings/python/tests/test_wallet_destroy.py index bd9e33d555..796b880b6c 100644 --- a/bindings/python/tests/test_wallet_destroy.py +++ b/bindings/python/tests/test_wallet_destroy.py @@ -3,7 +3,7 @@ import shutil import unittest -from iota_sdk import Wallet, MnemonicSecretManager, CoinType, ClientOptions, WalletOptions, WalletError, Bip44 +from iota_sdk import Wallet, MnemonicSecretManager, CoinType, ClientOptions, WalletOptions, WalletError, Bip44, Utils class WalletDestroy(unittest.TestCase): @@ -11,13 +11,14 @@ def test_wallet_destroy(self): db_path = './test_wallet_destroy' shutil.rmtree(db_path, ignore_errors=True) - client_options = ClientOptions(nodes=[]) + client_options = ClientOptions( + nodes=[], protocol_parameters=Utils.iota_mainnet_protocol_parameters()) secret_manager = MnemonicSecretManager( "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast") bip_path = Bip44( - coin_type=CoinType.SHIMMER + coin_type=CoinType.IOTA ) wallet_options = WalletOptions( None, @@ -29,7 +30,7 @@ def test_wallet_destroy(self): wallet = Wallet(wallet_options) address = wallet.address() - assert 'smr1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6ckj80y' == address + assert 'iota1qpg2xkj66wwgn8p2ggnp7p582gj8g6p79us5hve2tsudzpsr2ap4skprwjg' == address # Destroy the wallet wallet.destroy() @@ -38,14 +39,15 @@ def test_wallet_destroy(self): wallet = Wallet(wallet_options) address = wallet.address() - assert 'smr1qzev36lk0gzld0k28fd2fauz26qqzh4hd4cwymlqlv96x7phjxcw6ckj80y' == address + assert 'iota1qpg2xkj66wwgn8p2ggnp7p582gj8g6p79us5hve2tsudzpsr2ap4skprwjg' == address shutil.rmtree(db_path, ignore_errors=True) def test_wallet_destroy_error(self): db_path = './test_wallet_destroy_error' shutil.rmtree(db_path, ignore_errors=True) - client_options = ClientOptions(nodes=[]) + client_options = ClientOptions( + nodes=[], protocol_parameters=Utils.iota_mainnet_protocol_parameters()) secret_manager = MnemonicSecretManager( "acoustic trophy damage hint search taste love bicycle foster cradle brown govern endless depend situate athlete pudding blame question genius transfer van random vast") diff --git a/bindings/wasm/tests/wallet.spec.ts b/bindings/wasm/tests/wallet.spec.ts index 26fa8454b2..45eae39f1c 100644 --- a/bindings/wasm/tests/wallet.spec.ts +++ b/bindings/wasm/tests/wallet.spec.ts @@ -1,7 +1,7 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Wallet, CoinType, SecretManager } from '../node/lib'; +import { Wallet, CoinType, SecretManager, Utils } from '../node/lib'; describe('wallet tests', () => { jest.setTimeout(100000); @@ -30,6 +30,7 @@ describe('wallet tests', () => { }, clientOptions: { nodes: ['http://localhost:8050'], + protocolParameters: Utils.iotaMainnetProtocolParameters(), }, secretManager: mnemonicSecretManager, }); diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 9714463c52..6717620ffa 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -46,7 +46,7 @@ log = { version = "0.4.20", default-features = false } prefix-hex = { version = "0.7.1", default-features = false, features = ["std"] } rustyline = { version = "13.0.0", features = ["derive"] } serde_json = { version = "1.0.113", default-features = false } -strum = { version = "0.25.0", default-features = false, features = ["derive"] } +strum = { version = "0.26.1", default-features = false, features = ["derive"] } thiserror = { version = "1.0.56", default-features = false } tokio = { version = "1.35.1", default-features = false, features = ["fs"] } zeroize = { version = "1.7.0", default-features = false } diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index e167e3ea69..c9e5bbdfba 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -53,7 +53,7 @@ impl WalletCli { } /// Commands -#[derive(Debug, Subcommand, strum::EnumVariantNames)] +#[derive(Debug, Subcommand, strum::VariantNames)] #[strum(serialize_all = "kebab-case")] #[allow(clippy::large_enum_variant)] pub enum WalletCommand { diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index eed1148c0c..dbadc57941 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -46,7 +46,7 @@ iota-crypto = { version = "0.23.1", default-features = false, features = [ "secp256k1", ] } iterator-sorted = { version = "0.2.0", default-features = false } -packable = { version = "0.10.1", default-features = false, features = [ +packable = { version = "0.11.0", default-features = false, features = [ "primitive-types", ] } paste = { version = "1.0.14", default-features = false } @@ -69,7 +69,9 @@ futures = { version = "0.3.30", default-features = false, features = [ "thread-pool", ], optional = true } instant = { version = "0.1.12", default-features = false, optional = true } -iota-ledger-nano = { version = "1.0.4-alpha.3", default-features = false, features = ["nova"], optional = true } +iota-ledger-nano = { version = "1.0.4-alpha.3", default-features = false, features = [ + "nova", +], optional = true } iota_stronghold = { version = "2.0.0", default-features = false, optional = true } log = { version = "0.4.20", default-features = false, optional = true } once_cell = { version = "1.19.0", default-features = false, optional = true } @@ -154,6 +156,7 @@ irc_30 = ["serde", "dep:url"] ledger_nano = ["dep:iota-ledger-nano"] mqtt = ["std", "tls", "dep:regex", "dep:rumqttc", "dep:once_cell"] participation = ["storage"] +protocol_parameters_samples = ["std", "dep:time"] rocksdb = ["storage", "dep:rocksdb"] serde = [ "hashbrown/serde", diff --git a/sdk/src/client/api/block_builder/mod.rs b/sdk/src/client/api/block_builder/mod.rs index 35c06c12a1..45483daa0b 100644 --- a/sdk/src/client/api/block_builder/mod.rs +++ b/sdk/src/client/api/block_builder/mod.rs @@ -6,7 +6,7 @@ pub mod transaction; pub use self::transaction::verify_semantic; use crate::{ - client::{constants::FIVE_MINUTES_IN_NANOSECONDS, ClientInner, Error, Result}, + client::{constants::FIVE_MINUTES_IN_NANOSECONDS, Client, Error, Result}, types::block::{ core::{BlockHeader, UnsignedBlock}, output::AccountId, @@ -15,7 +15,7 @@ use crate::{ }, }; -impl ClientInner { +impl Client { pub async fn build_basic_block( &self, issuer_id: AccountId, diff --git a/sdk/src/client/builder.rs b/sdk/src/client/builder.rs index c18998754c..85a9d73678 100644 --- a/sdk/src/client/builder.rs +++ b/sdk/src/client/builder.rs @@ -35,9 +35,9 @@ pub struct ClientBuilder { #[cfg_attr(docsrs, doc(cfg(feature = "mqtt")))] #[serde(flatten)] pub broker_options: BrokerOptions, - /// Data related to the used network - #[serde(flatten, default)] - pub network_info: NetworkInfo, + /// Protocol parameters + #[serde(default, skip_serializing_if = "Option::is_none")] + pub protocol_parameters: Option, /// Timeout for API requests #[serde(default = "default_api_timeout")] pub api_timeout: Duration, @@ -62,7 +62,7 @@ impl Default for ClientBuilder { node_manager_builder: crate::client::node_manager::NodeManager::builder(), #[cfg(feature = "mqtt")] broker_options: Default::default(), - network_info: NetworkInfo::default(), + protocol_parameters: None, api_timeout: DEFAULT_API_TIMEOUT, #[cfg(not(target_family = "wasm"))] max_parallel_api_requests: super::constants::MAX_PARALLEL_API_REQUESTS, @@ -182,6 +182,12 @@ impl ClientBuilder { self } + /// Set the protocol parameters. + pub fn with_protocol_parameters(mut self, protocol_parameters: ProtocolParameters) -> Self { + self.protocol_parameters.replace(protocol_parameters); + self + } + /// Build the Client instance. #[cfg(not(target_family = "wasm"))] pub async fn finish(self) -> Result { @@ -202,7 +208,6 @@ impl ClientBuilder { let client_inner = Arc::new(ClientInner { node_manager: RwLock::new(self.node_manager_builder.build(HashSet::new())), - network_info: RwLock::new(self.network_info), api_timeout: RwLock::new(self.api_timeout), #[cfg(feature = "mqtt")] mqtt: super::MqttInner { @@ -215,19 +220,29 @@ impl ClientBuilder { request_pool: crate::client::request_pool::RequestPool::new(self.max_parallel_api_requests), }); - client_inner.sync_nodes(&nodes, ignore_node_health).await?; - let client_clone = client_inner.clone(); + let network_info = match self.protocol_parameters { + Some(protocol_parameters) => NetworkInfo { + protocol_parameters, + tangle_time: None, + }, + None => client_inner.fetch_network_info().await?, + }; + + let client = Client { + inner: client_inner, + network_info: Arc::new(RwLock::new(network_info)), + _sync_handle: Arc::new(RwLock::new(super::SyncHandle(None))), + }; + + client.sync_nodes(&nodes, ignore_node_health).await?; + let client_clone = client.clone(); let sync_handle = tokio::spawn(async move { client_clone .start_sync_process(nodes, node_sync_interval, ignore_node_health) .await }); - - let client = Client { - inner: client_inner, - _sync_handle: Arc::new(RwLock::new(super::SyncHandle(Some(sync_handle)))), - }; + *client._sync_handle.write().await = super::SyncHandle(Some(sync_handle)); Ok(client) } @@ -240,21 +255,31 @@ impl ClientBuilder { #[cfg(feature = "mqtt")] let (mqtt_event_tx, mqtt_event_rx) = tokio::sync::watch::channel(MqttEvent::Connected); + let client_inner = ClientInner { + node_manager: RwLock::new(self.node_manager_builder.build(HashSet::new())), + api_timeout: RwLock::new(self.api_timeout), + #[cfg(feature = "mqtt")] + mqtt: super::MqttInner { + client: Default::default(), + topic_handlers: Default::default(), + broker_options: RwLock::new(self.broker_options), + sender: RwLock::new(mqtt_event_tx), + receiver: RwLock::new(mqtt_event_rx), + }, + last_sync: tokio::sync::Mutex::new(None), + }; + + let network_info = match self.protocol_parameters { + Some(protocol_parameters) => NetworkInfo { + protocol_parameters, + tangle_time: None, + }, + None => client_inner.fetch_network_info().await?, + }; + let client = Client { - inner: Arc::new(ClientInner { - node_manager: RwLock::new(self.node_manager_builder.build(HashSet::new())), - network_info: RwLock::new(self.network_info), - api_timeout: RwLock::new(self.api_timeout), - #[cfg(feature = "mqtt")] - mqtt: super::MqttInner { - client: Default::default(), - topic_handlers: Default::default(), - broker_options: RwLock::new(self.broker_options), - sender: RwLock::new(mqtt_event_tx), - receiver: RwLock::new(mqtt_event_rx), - }, - last_sync: tokio::sync::Mutex::new(None), - }), + inner: Arc::new(client_inner), + network_info: Arc::new(RwLock::new(network_info)), }; Ok(client) @@ -265,7 +290,7 @@ impl ClientBuilder { node_manager_builder: NodeManagerBuilder::from(&*client.node_manager.read().await), #[cfg(feature = "mqtt")] broker_options: *client.mqtt.broker_options.read().await, - network_info: client.network_info.read().await.clone(), + protocol_parameters: Some(client.network_info.read().await.protocol_parameters.clone()), api_timeout: client.get_timeout().await, #[cfg(not(target_family = "wasm"))] max_parallel_api_requests: client.request_pool.size().await, @@ -274,12 +299,10 @@ impl ClientBuilder { } /// Struct containing network related information -// TODO do we really want a default? -#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct NetworkInfo { /// Protocol parameters. - #[serde(default)] pub protocol_parameters: ProtocolParameters, /// The current tangle time. #[serde(skip)] diff --git a/sdk/src/client/core.rs b/sdk/src/client/core.rs index e1e623e7d8..47ad098f4d 100644 --- a/sdk/src/client/core.rs +++ b/sdk/src/client/core.rs @@ -16,7 +16,7 @@ use { #[cfg(not(target_family = "wasm"))] use super::request_pool::RequestPool; #[cfg(target_family = "wasm")] -use crate::{client::constants::CACHE_NETWORK_INFO_TIMEOUT_IN_SECONDS, types::block::PROTOCOL_VERSION}; +use crate::client::constants::CACHE_NETWORK_INFO_TIMEOUT_IN_SECONDS; use crate::{ client::{ builder::{ClientBuilder, NetworkInfo}, @@ -31,6 +31,7 @@ use crate::{ #[derive(Clone)] pub struct Client { pub(crate) inner: Arc, + pub(crate) network_info: Arc>, #[cfg(not(target_family = "wasm"))] pub(crate) _sync_handle: Arc>, } @@ -46,7 +47,6 @@ impl core::ops::Deref for Client { pub struct ClientInner { /// Node manager pub(crate) node_manager: RwLock, - pub(crate) network_info: RwLock, /// HTTP request timeout. pub(crate) api_timeout: RwLock, #[cfg(feature = "mqtt")] @@ -57,12 +57,13 @@ pub struct ClientInner { pub(crate) request_pool: RequestPool, } +#[cfg(not(target_family = "wasm"))] #[derive(Default)] pub(crate) struct SyncHandle(pub(crate) Option>); +#[cfg(not(target_family = "wasm"))] impl Drop for SyncHandle { fn drop(&mut self) { - #[cfg(not(target_family = "wasm"))] if let Some(sync_handle) = self.0.take() { sync_handle.abort(); } @@ -97,9 +98,7 @@ impl Client { pub fn builder() -> ClientBuilder { ClientBuilder::new() } -} -impl ClientInner { /// Gets the network related information such as network_id and if it's the default one, sync it first and set the /// NetworkInfo. pub async fn get_network_info(&self) -> Result { @@ -113,17 +112,15 @@ impl ClientInner { return Ok(self.network_info.read().await.clone()); } } - let info = self.get_info().await?.node_info; - let mut client_network_info = self.network_info.write().await; - client_network_info.protocol_parameters = info - .protocol_parameters_by_version(PROTOCOL_VERSION) - .expect("missing v3 protocol parameters") - .parameters - .clone(); + let network_info = self.fetch_network_info().await?; + *self.network_info.write().await = network_info.clone(); *self.last_sync.lock().await = Some(current_time + CACHE_NETWORK_INFO_TIMEOUT_IN_SECONDS); + + Ok(network_info) } + #[cfg(not(target_family = "wasm"))] Ok(self.network_info.read().await.clone()) } @@ -166,10 +163,6 @@ impl ClientInner { Ok(self.get_network_info().await?.protocol_parameters.token_supply()) } - pub(crate) async fn get_timeout(&self) -> Duration { - *self.api_timeout.read().await - } - /// Validates if a bech32 HRP matches the one from the connected network. pub async fn bech32_hrp_matches(&self, bech32_hrp: &Hrp) -> Result<()> { let expected = self.get_bech32_hrp().await?; @@ -181,6 +174,27 @@ impl ClientInner { }; Ok(()) } +} + +impl ClientInner { + pub(crate) async fn fetch_network_info(&self) -> Result { + let info = self.get_info().await?.node_info; + let protocol_parameters = info + .protocol_parameters_by_version(crate::types::block::PROTOCOL_VERSION) + .expect("missing v3 protocol parameters") + .parameters + .clone(); + let network_info = NetworkInfo { + protocol_parameters, + tangle_time: info.status.relative_accepted_tangle_time, + }; + + Ok(network_info) + } + + pub(crate) async fn get_timeout(&self) -> Duration { + *self.api_timeout.read().await + } /// Resize the client's request pool #[cfg(not(target_family = "wasm"))] diff --git a/sdk/src/client/node_api/core/routes.rs b/sdk/src/client/node_api/core/routes.rs index e50617f142..73c041f34d 100644 --- a/sdk/src/client/node_api/core/routes.rs +++ b/sdk/src/client/node_api/core/routes.rs @@ -87,7 +87,9 @@ impl ClientInner { pub async fn get_info(&self) -> Result { self.get_request(INFO_PATH, None, false).await } +} +impl Client { /// Checks if the account is ready to issue a block. /// GET /api/core/v3/accounts/{bech32Address}/congestion pub async fn get_account_congestion( diff --git a/sdk/src/client/node_api/indexer/routes.rs b/sdk/src/client/node_api/indexer/routes.rs index 1cc529cec1..e6993d16d2 100644 --- a/sdk/src/client/node_api/indexer/routes.rs +++ b/sdk/src/client/node_api/indexer/routes.rs @@ -10,7 +10,7 @@ use crate::{ DelegationOutputQueryParameters, FoundryOutputQueryParameters, NftOutputQueryParameters, OutputQueryParameters, }, - ClientInner, Error, Result, + Client, Error, Result, }, types::{ api::plugins::indexer::OutputIdsResponse, @@ -21,7 +21,7 @@ use crate::{ }, }; -impl ClientInner { +impl Client { /// Get account, anchor, basic, delegation, nft and foundry outputs filtered by the given parameters. /// GET with query parameter returns all outputIDs that fit these filter criteria. /// Returns Err(Node(NotFound) if no results are found. diff --git a/sdk/src/client/node_api/mqtt/mod.rs b/sdk/src/client/node_api/mqtt/mod.rs index 3d8d34dcfa..7e80b04afb 100644 --- a/sdk/src/client/node_api/mqtt/mod.rs +++ b/sdk/src/client/node_api/mqtt/mod.rs @@ -193,11 +193,12 @@ fn poll_mqtt(client: &Client, mut event_loop: EventLoop) { let event = { if p.topic.contains("blocks") || p.topic.contains("included-block") { let payload = &*p.payload; - let protocol_parameters = &client.network_info.read().await.protocol_parameters; + let protocol_parameters = + client.network_info.read().await.protocol_parameters.clone(); match serde_json::from_slice::(payload) { Ok(block_dto) => { - match Block::try_from_dto_with_params(block_dto, protocol_parameters) { + match Block::try_from_dto_with_params(block_dto, &protocol_parameters) { Ok(block) => Ok(TopicEvent { topic: p.topic.clone(), payload: MqttPayload::Block((&block).into()), diff --git a/sdk/src/client/node_manager/syncing.rs b/sdk/src/client/node_manager/syncing.rs index 583dd32b9d..5dda00c1d9 100644 --- a/sdk/src/client/node_manager/syncing.rs +++ b/sdk/src/client/node_manager/syncing.rs @@ -3,16 +3,13 @@ #[cfg(not(target_family = "wasm"))] use { - crate::types::block::PROTOCOL_VERSION, + crate::{client::NetworkInfo, types::block::PROTOCOL_VERSION}, std::{collections::HashSet, time::Duration}, tokio::time::sleep, }; use super::{Node, NodeManager}; -use crate::{ - client::{Client, ClientInner, Error, Result}, - types::block::protocol::ProtocolParameters, -}; +use crate::client::{Client, ClientInner, Error, Result}; impl ClientInner { /// Get a node candidate from the healthy node pool. @@ -46,7 +43,7 @@ impl ClientInner { } #[cfg(not(target_family = "wasm"))] -impl ClientInner { +impl Client { /// Sync the node lists per node_sync_interval milliseconds pub(crate) async fn start_sync_process( &self, @@ -69,7 +66,7 @@ impl ClientInner { log::debug!("sync_nodes"); let mut healthy_nodes = HashSet::new(); - let mut network_nodes: HashMap)>> = HashMap::new(); + let mut network_nodes: HashMap)>> = HashMap::new(); for node in nodes { // Put the healthy node url into the network_nodes @@ -149,11 +146,11 @@ impl ClientInner { // Set the protocol_parameters to the parameters that most nodes have in common and only use these nodes as // healthy_nodes if let Some((parameters, _node_url, tangle_time)) = nodes.first() { - let mut network_info = self.network_info.write().await; - - network_info.tangle_time = *tangle_time; // Unwrap: We should always have parameters for this version. If we don't we can't recover. - network_info.protocol_parameters = parameters.clone(); + *self.network_info.write().await = NetworkInfo { + protocol_parameters: parameters.clone(), + tangle_time: *tangle_time, + }; } healthy_nodes.extend(nodes.iter().map(|(_info, node_url, _time)| node_url).cloned()) @@ -170,10 +167,7 @@ impl ClientInner { Ok(()) } -} -impl Client { - #[cfg(not(target_family = "wasm"))] pub async fn update_node_manager(&self, node_manager: NodeManager) -> Result<()> { let node_sync_interval = node_manager.node_sync_interval; let ignore_node_health = node_manager.ignore_node_health; @@ -198,8 +192,10 @@ impl Client { *self._sync_handle.write().await = crate::client::SyncHandle(Some(sync_handle)); Ok(()) } +} - #[cfg(target_family = "wasm")] +#[cfg(target_family = "wasm")] +impl Client { pub async fn update_node_manager(&self, node_manager: NodeManager) -> Result<()> { *self.node_manager.write().await = node_manager; Ok(()) diff --git a/sdk/src/client/secret/ledger_nano.rs b/sdk/src/client/secret/ledger_nano.rs index 63dda3bf89..b9dac6ec80 100644 --- a/sdk/src/client/secret/ledger_nano.rs +++ b/sdk/src/client/secret/ledger_nano.rs @@ -20,7 +20,7 @@ use iota_ledger_nano::{ get_app_config, get_buffer_size, get_ledger, get_opened_app, LedgerBIP32Index, Packable as LedgerNanoPackable, TransportTypes, }; -use packable::{error::UnexpectedEOF, unpacker::SliceUnpacker, Packable, PackableExt}; +use packable::{error::UnexpectedEOF, PackableExt}; use tokio::sync::Mutex; use super::{GenerateAddressOptions, SecretManage, SecretManagerConfig}; @@ -230,10 +230,8 @@ impl SecretManage for LedgerSecretManager { drop(ledger); drop(lock); - let mut unpacker = SliceUnpacker::new(&signature_bytes); - // Unpack and return signature. - return match Unlock::unpack::<_, true>(&mut unpacker, &())? { + return match Unlock::unpack_bytes_verified(signature_bytes, &())? { Unlock::Signature(s) => match *s { SignatureUnlock(Signature::Ed25519(signature)) => Ok(signature), }, @@ -388,12 +386,11 @@ impl SecretManage for LedgerSecretManager { let signature_bytes = ledger.sign(input_len as u16).map_err(Error::from)?; drop(ledger); drop(lock); - let mut unpacker = SliceUnpacker::new(&signature_bytes); // unpack signature to unlocks let mut unlocks = Vec::new(); for _ in 0..input_len { - let unlock = Unlock::unpack::<_, true>(&mut unpacker, &())?; + let unlock = Unlock::unpack_bytes_verified(&signature_bytes, &())?; // The ledger nano can return the same SignatureUnlocks multiple times, so only insert it once match unlock { Unlock::Signature(_) => { diff --git a/sdk/src/client/utils.rs b/sdk/src/client/utils.rs index 4dd8ec509d..1b50640da4 100644 --- a/sdk/src/client/utils.rs +++ b/sdk/src/client/utils.rs @@ -14,7 +14,7 @@ use crypto::{ use serde::{Deserialize, Serialize}; use zeroize::{Zeroize, ZeroizeOnDrop}; -use super::{Client, ClientInner}; +use super::Client; use crate::{ client::{Error, Result}, types::block::{ @@ -104,7 +104,7 @@ pub async fn request_funds_from_faucet(url: &str, bech32_address: &Bech32Address Ok(faucet_response) } -impl ClientInner { +impl Client { /// Transforms a hex encoded address to a bech32 encoded address pub async fn hex_to_bech32( &self, @@ -164,9 +164,7 @@ impl ClientInner { None => Ok(hex_public_key_to_bech32_address(hex, self.get_bech32_hrp().await?)?), } } -} -impl Client { /// Transforms bech32 to hex pub fn bech32_to_hex(bech32: impl ConvertTo) -> crate::client::Result { bech32_to_hex(bech32) diff --git a/sdk/src/types/block/address/bech32.rs b/sdk/src/types/block/address/bech32.rs index 36cbe7bbea..92db719127 100644 --- a/sdk/src/types/block/address/bech32.rs +++ b/sdk/src/types/block/address/bech32.rs @@ -67,11 +67,11 @@ impl Packable for Hrp { } #[inline] - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { - let len = u8::unpack::<_, VERIFY>(unpacker, visitor).coerce()? as usize; + let len = u8::unpack(unpacker, visitor).coerce()? as usize; let mut bytes = alloc::vec![0u8; len]; unpacker.unpack_bytes(&mut bytes)?; @@ -128,7 +128,7 @@ impl FromStr for Bech32Address { fn from_str(address: &str) -> Result { match bech32::decode(address) { - Ok((hrp, bytes)) => Address::unpack_verified(bytes.as_slice(), &()) + Ok((hrp, bytes)) => Address::unpack_bytes_verified(bytes.as_slice(), &()) .map_err(|_| Error::InvalidAddress) .map(|address| Self { hrp: Hrp(hrp), diff --git a/sdk/src/types/block/address/multi.rs b/sdk/src/types/block/address/multi.rs index 3db33a7d79..c048154398 100644 --- a/sdk/src/types/block/address/multi.rs +++ b/sdk/src/types/block/address/multi.rs @@ -30,8 +30,8 @@ impl WeightedAddress { pub fn new(address: impl Into
, weight: u8) -> Result { let address = address.into(); - verify_address::(&address)?; - verify_weight::(&weight)?; + verify_address(&address)?; + verify_weight(&weight)?; Ok(Self { address, weight }) } @@ -47,21 +47,19 @@ impl WeightedAddress { } } -fn verify_address(address: &Address) -> Result<(), Error> { - if VERIFY - && !matches!( - address, - Address::Ed25519(_) | Address::Account(_) | Address::Nft(_) | Address::Anchor(_) - ) - { +fn verify_address(address: &Address) -> Result<(), Error> { + if !matches!( + address, + Address::Ed25519(_) | Address::Account(_) | Address::Nft(_) | Address::Anchor(_) + ) { Err(Error::InvalidAddressKind(address.kind())) } else { Ok(()) } } -fn verify_weight(weight: &u8) -> Result<(), Error> { - if VERIFY && *weight == 0 { +fn verify_weight(weight: &u8) -> Result<(), Error> { + if *weight == 0 { Err(Error::InvalidAddressWeight(*weight)) } else { Ok(()) @@ -104,15 +102,15 @@ impl MultiAddress { .into_values() .collect::>(); - verify_addresses::(&addresses)?; - verify_threshold::(&threshold)?; + verify_addresses(&addresses)?; + verify_threshold(&threshold)?; let addresses = BoxedSlicePrefix::::try_from(addresses) .map_err(Error::InvalidWeightedAddressCount)?; let multi_address = Self { addresses, threshold }; - verify_multi_address::(&multi_address)?; + verify_multi_address(&multi_address)?; Ok(multi_address) } @@ -141,32 +139,30 @@ impl MultiAddress { } } -fn verify_addresses(addresses: &[WeightedAddress]) -> Result<(), Error> { - if VERIFY && !is_unique_sorted(addresses.iter().map(|a| a.address.pack_to_vec())) { +fn verify_addresses(addresses: &[WeightedAddress]) -> Result<(), Error> { + if !is_unique_sorted(addresses.iter().map(|a| a.address.pack_to_vec())) { Err(Error::WeightedAddressesNotUniqueSorted) } else { Ok(()) } } -fn verify_threshold(threshold: &u16) -> Result<(), Error> { - if VERIFY && *threshold == 0 { +fn verify_threshold(threshold: &u16) -> Result<(), Error> { + if *threshold == 0 { Err(Error::InvalidMultiAddressThreshold(*threshold)) } else { Ok(()) } } -fn verify_multi_address(address: &MultiAddress) -> Result<(), Error> { - if VERIFY { - let cumulative_weight = address.iter().map(|address| address.weight as u16).sum::(); +fn verify_multi_address(address: &MultiAddress) -> Result<(), Error> { + let cumulative_weight = address.iter().map(|address| address.weight as u16).sum::(); - if cumulative_weight < address.threshold { - return Err(Error::InvalidMultiAddressCumulativeWeight { - cumulative_weight, - threshold: address.threshold, - }); - } + if cumulative_weight < address.threshold { + return Err(Error::InvalidMultiAddressCumulativeWeight { + cumulative_weight, + threshold: address.threshold, + }); } Ok(()) diff --git a/sdk/src/types/block/address/restricted.rs b/sdk/src/types/block/address/restricted.rs index d52c316371..48d2e4b602 100644 --- a/sdk/src/types/block/address/restricted.rs +++ b/sdk/src/types/block/address/restricted.rs @@ -34,7 +34,7 @@ impl RestrictedAddress { pub fn new(address: impl Into
) -> Result { let address = address.into(); - verify_address::(&address)?; + verify_address(&address)?; Ok(Self { address, @@ -82,13 +82,11 @@ impl core::fmt::Display for RestrictedAddress { } } -fn verify_address(address: &Address) -> Result<(), Error> { - if VERIFY - && !matches!( - address, - Address::Ed25519(_) | Address::Account(_) | Address::Nft(_) | Address::Anchor(_) | Address::Multi(_) - ) - { +fn verify_address(address: &Address) -> Result<(), Error> { + if !matches!( + address, + Address::Ed25519(_) | Address::Account(_) | Address::Nft(_) | Address::Anchor(_) | Address::Multi(_) + ) { Err(Error::InvalidAddressKind(address.kind())) } else { Ok(()) diff --git a/sdk/src/types/block/capabilities.rs b/sdk/src/types/block/capabilities.rs index 3ba8f8359c..ff46381879 100644 --- a/sdk/src/types/block/capabilities.rs +++ b/sdk/src/types/block/capabilities.rs @@ -201,12 +201,12 @@ impl Packable for Capabilities { Ok(()) } - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { Self::from_prefix_box_slice( - BoxedSlicePrefix::unpack::<_, VERIFY>(unpacker, visitor) + BoxedSlicePrefix::unpack(unpacker, visitor) .map_packable_err(|e| match e { UnpackPrefixError::Item(i) | UnpackPrefixError::Prefix(i) => i, }) diff --git a/sdk/src/types/block/context_input/mod.rs b/sdk/src/types/block/context_input/mod.rs index d3b6af8c6c..f0ebe19dd8 100644 --- a/sdk/src/types/block/context_input/mod.rs +++ b/sdk/src/types/block/context_input/mod.rs @@ -87,7 +87,7 @@ pub(crate) type ContextInputCount = #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Deref, Packable)] #[packable(unpack_error = Error, with = |e| e.unwrap_item_err_or_else(|p| Error::InvalidContextInputCount(p.into())))] pub struct ContextInputs( - #[packable(verify_with = verify_context_inputs_packable)] BoxedSlicePrefix, + #[packable(verify_with = verify_context_inputs)] BoxedSlicePrefix, ); impl TryFrom> for ContextInputs { @@ -138,13 +138,6 @@ impl ContextInputs { } } -fn verify_context_inputs_packable(context_inputs: &[ContextInput]) -> Result<(), Error> { - if VERIFY { - verify_context_inputs(context_inputs)?; - } - Ok(()) -} - fn context_inputs_cmp(a: &ContextInput, b: &ContextInput) -> Ordering { a.kind().cmp(&b.kind()).then_with(|| match (a, b) { (ContextInput::Commitment(_), ContextInput::Commitment(_)) => Ordering::Equal, diff --git a/sdk/src/types/block/core/basic.rs b/sdk/src/types/block/core/basic.rs index f9fe9849c5..f663b85afd 100644 --- a/sdk/src/types/block/core/basic.rs +++ b/sdk/src/types/block/core/basic.rs @@ -193,17 +193,12 @@ impl WorkScore for BasicBlockBody { } } -fn verify_basic_block_body( - basic_block_body: &BasicBlockBody, - _: &ProtocolParameters, -) -> Result<(), Error> { - if VERIFY { - verify_parents_sets( - &basic_block_body.strong_parents, - &basic_block_body.weak_parents, - &basic_block_body.shallow_like_parents, - )?; - } +fn verify_basic_block_body(basic_block_body: &BasicBlockBody, _: &ProtocolParameters) -> Result<(), Error> { + verify_parents_sets( + &basic_block_body.strong_parents, + &basic_block_body.weak_parents, + &basic_block_body.shallow_like_parents, + )?; Ok(()) } diff --git a/sdk/src/types/block/core/block.rs b/sdk/src/types/block/core/block.rs index a2798a8f59..3460514252 100644 --- a/sdk/src/types/block/core/block.rs +++ b/sdk/src/types/block/core/block.rs @@ -113,11 +113,8 @@ impl BlockHeader { } } -fn verify_protocol_version( - protocol_version: &u8, - params: &ProtocolParameters, -) -> Result<(), Error> { - if VERIFY && *protocol_version != params.version() { +fn verify_protocol_version(protocol_version: &u8, params: &ProtocolParameters) -> Result<(), Error> { + if *protocol_version != params.version() { return Err(Error::ProtocolVersionMismatch { expected: params.version(), actual: *protocol_version, @@ -127,8 +124,8 @@ fn verify_protocol_version( Ok(()) } -fn verify_network_id(network_id: &u64, params: &ProtocolParameters) -> Result<(), Error> { - if VERIFY && *network_id != params.network_id() { +fn verify_network_id(network_id: &u64, params: &ProtocolParameters) -> Result<(), Error> { + if *network_id != params.network_id() { return Err(Error::NetworkIdMismatch { expected: params.network_id(), actual: *network_id, @@ -230,10 +227,10 @@ impl Block { visitor: &::UnpackVisitor, ) -> Result::UnpackError, UnexpectedEOF>> { let mut unpacker = CounterUnpacker::new(SliceUnpacker::new(bytes.as_ref())); - let block = Self::unpack::<_, true>(&mut unpacker, visitor)?; + let block = Self::unpack_verified(&mut unpacker, visitor)?; // When parsing the block is complete, there should not be any trailing bytes left that were not parsed. - if u8::unpack::<_, true>(&mut unpacker, &()).is_ok() { + if u8::unpack_inner(&mut unpacker, Some(visitor)).is_ok() { return Err(UnpackError::Packable(Error::RemainingBytesAfterBlock)); } @@ -275,15 +272,15 @@ impl Packable for Block { Ok(()) } - fn unpack( + fn unpack( unpacker: &mut U, - protocol_params: &Self::UnpackVisitor, + protocol_params: Option<&Self::UnpackVisitor>, ) -> Result> { let start_opt = unpacker.read_bytes(); - let header = BlockHeader::unpack::<_, VERIFY>(unpacker, protocol_params)?; - let body = BlockBody::unpack::<_, VERIFY>(unpacker, protocol_params)?; - let signature = Signature::unpack::<_, VERIFY>(unpacker, &())?; + let header = BlockHeader::unpack(unpacker, protocol_params)?; + let body = BlockBody::unpack(unpacker, protocol_params)?; + let signature = Signature::unpack_inner(unpacker, protocol_params)?; let block = Self { header, @@ -291,7 +288,7 @@ impl Packable for Block { signature, }; - if VERIFY { + if protocol_params.is_some() { let block_len = if let (Some(start), Some(end)) = (start_opt, unpacker.read_bytes()) { end - start } else { diff --git a/sdk/src/types/block/core/parent.rs b/sdk/src/types/block/core/parent.rs index d7166b7f77..59adf2a98e 100644 --- a/sdk/src/types/block/core/parent.rs +++ b/sdk/src/types/block/core/parent.rs @@ -75,8 +75,8 @@ impl Parents { } } -fn verify_parents(parents: &[BlockId]) -> Result<(), Error> { - if VERIFY && !is_unique_sorted(parents.iter().map(AsRef::as_ref)) { +fn verify_parents(parents: &[BlockId]) -> Result<(), Error> { + if !is_unique_sorted(parents.iter().map(AsRef::as_ref)) { Err(Error::ParentsNotUniqueSorted) } else { Ok(()) diff --git a/sdk/src/types/block/core/validation.rs b/sdk/src/types/block/core/validation.rs index 66f27ae2b2..257b9b61ed 100644 --- a/sdk/src/types/block/core/validation.rs +++ b/sdk/src/types/block/core/validation.rs @@ -160,35 +160,28 @@ impl ValidationBlockBody { } } -fn verify_protocol_parameters_hash( - hash: &ProtocolParametersHash, - params: &ProtocolParameters, -) -> Result<(), Error> { - if VERIFY { - let params_hash = params.hash(); - - if hash != ¶ms_hash { - return Err(Error::InvalidProtocolParametersHash { - expected: params_hash, - actual: *hash, - }); - } +fn verify_protocol_parameters_hash(hash: &ProtocolParametersHash, params: &ProtocolParameters) -> Result<(), Error> { + let params_hash = params.hash(); + + if hash != ¶ms_hash { + return Err(Error::InvalidProtocolParametersHash { + expected: params_hash, + actual: *hash, + }); } Ok(()) } -fn verify_validation_block_body( +fn verify_validation_block_body( validation_block_body: &ValidationBlockBody, _: &ProtocolParameters, ) -> Result<(), Error> { - if VERIFY { - verify_parents_sets( - &validation_block_body.strong_parents, - &validation_block_body.weak_parents, - &validation_block_body.shallow_like_parents, - )?; - } + verify_parents_sets( + &validation_block_body.strong_parents, + &validation_block_body.weak_parents, + &validation_block_body.shallow_like_parents, + )?; Ok(()) } @@ -239,8 +232,8 @@ pub(crate) mod dto { dto: ValidationBlockBodyDto, params: Option<&ProtocolParameters>, ) -> Result { - if let Some(protocol_params) = params { - verify_protocol_parameters_hash::(&dto.protocol_parameters_hash, protocol_params)?; + if let Some(params) = params { + verify_protocol_parameters_hash(&dto.protocol_parameters_hash, params)?; } ValidationBlockBodyBuilder::new( diff --git a/sdk/src/types/block/mana/allotment.rs b/sdk/src/types/block/mana/allotment.rs index d191fdbd87..60f6b6b3b3 100644 --- a/sdk/src/types/block/mana/allotment.rs +++ b/sdk/src/types/block/mana/allotment.rs @@ -32,7 +32,7 @@ pub struct ManaAllotment { impl ManaAllotment { pub fn new(account_id: AccountId, mana: u64) -> Result { - verify_mana::(&mana)?; + verify_mana(&mana)?; Ok(Self { account_id, mana }) } @@ -64,8 +64,8 @@ impl WorkScore for ManaAllotment { } } -fn verify_mana(mana: &u64) -> Result<(), Error> { - if VERIFY && *mana == 0 { +fn verify_mana(mana: &u64) -> Result<(), Error> { + if *mana == 0 { return Err(Error::InvalidManaValue(*mana)); } @@ -121,14 +121,9 @@ impl ManaAllotments { } } -fn verify_mana_allotments( - allotments: &[ManaAllotment], - protocol_params: &ProtocolParameters, -) -> Result<(), Error> { - if VERIFY { - verify_mana_allotments_unique_sorted(allotments)?; - verify_mana_allotments_sum(allotments, protocol_params)?; - } +fn verify_mana_allotments(allotments: &[ManaAllotment], protocol_params: &ProtocolParameters) -> Result<(), Error> { + verify_mana_allotments_unique_sorted(allotments)?; + verify_mana_allotments_sum(allotments, protocol_params)?; Ok(()) } diff --git a/sdk/src/types/block/mana/parameters.rs b/sdk/src/types/block/mana/parameters.rs index f08af0fd9c..851d8431b2 100644 --- a/sdk/src/types/block/mana/parameters.rs +++ b/sdk/src/types/block/mana/parameters.rs @@ -98,22 +98,6 @@ impl ManaParameters { } } -impl Default for ManaParameters { - fn default() -> Self { - // TODO: use actual values - Self { - bits_count: 63, - generation_rate: Default::default(), - generation_rate_exponent: Default::default(), - decay_factors: Default::default(), - decay_factors_exponent: Default::default(), - decay_factor_epochs_sum: Default::default(), - decay_factor_epochs_sum_exponent: Default::default(), - annual_decay_factor_percentage: Default::default(), - } - } -} - impl ProtocolParameters { /// Applies mana decay to the given mana. pub fn mana_with_decay( @@ -219,65 +203,23 @@ const fn fixed_point_multiply(value: u64, mult_factor: u32, shift_factor: u8) -> ((value as u128 * mult_factor as u128) >> shift_factor) as u64 } -#[cfg(test)] +#[cfg(all(test, feature = "protocol_parameters_samples"))] mod test { use pretty_assertions::assert_eq; use super::*; + use crate::types::block::protocol::iota_mainnet_protocol_parameters; // Tests from https://github.com/iotaledger/iota.go/blob/develop/mana_decay_provider_test.go fn params() -> &'static ProtocolParameters { - use once_cell::sync::Lazy; - static PARAMS: Lazy = Lazy::new(|| { - let mut params = ProtocolParameters { - genesis_slot: 0, - genesis_unix_timestamp: time::OffsetDateTime::now_utc().unix_timestamp() as _, - slots_per_epoch_exponent: 13, - slot_duration_in_seconds: 10, - token_supply: 1813620509061365, - mana_parameters: ManaParameters { - bits_count: 63, - generation_rate: 1, - generation_rate_exponent: 17, - decay_factors_exponent: 32, - decay_factor_epochs_sum_exponent: 21, - annual_decay_factor_percentage: 70, - ..Default::default() - }, - ..Default::default() - }; - params.mana_parameters.decay_factors = { - let epochs_in_table = (u16::MAX as usize).min(params.epochs_per_year().floor() as usize); - let decay_per_epoch = params.decay_per_epoch(); - (1..=epochs_in_table) - .map(|epoch| { - (decay_per_epoch.powi(epoch as _) - * 2f64.powi(params.mana_parameters().decay_factors_exponent() as _)) - .floor() as u32 - }) - .collect::>() - } - .try_into() - .unwrap(); - params.mana_parameters.decay_factor_epochs_sum = { - let delta = params.epochs_per_year().recip(); - let annual_decay_factor = params.mana_parameters().annual_decay_factor(); - (annual_decay_factor.powf(delta) / (1.0 - annual_decay_factor.powf(delta)) - * (2f64.powi(params.mana_parameters().decay_factor_epochs_sum_exponent() as _))) - .floor() as _ - }; - params - }); - &PARAMS + iota_mainnet_protocol_parameters() } #[test] fn mana_decay_no_factors() { - let mana_parameters = ManaParameters { - decay_factors: Box::<[_]>::default().try_into().unwrap(), - ..Default::default() - }; + let mut mana_parameters = params().mana_parameters().clone(); + mana_parameters.decay_factors = Box::<[_]>::default().try_into().unwrap(); assert_eq!(mana_parameters.decay(100, 100), 100); } diff --git a/sdk/src/types/block/mana/rewards.rs b/sdk/src/types/block/mana/rewards.rs index 516d4aa3e0..51ee32f933 100644 --- a/sdk/src/types/block/mana/rewards.rs +++ b/sdk/src/types/block/mana/rewards.rs @@ -4,7 +4,7 @@ use getset::CopyGetters; use packable::Packable; -use crate::types::block::{slot::EpochIndex, Error}; +use crate::types::block::Error; #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Packable, CopyGetters)] #[cfg_attr( @@ -16,33 +16,19 @@ use crate::types::block::{slot::EpochIndex, Error}; #[getset(get_copy = "pub")] pub struct RewardsParameters { /// Used for shift operation during calculation of profit margin. - profit_margin_exponent: u8, + pub(crate) profit_margin_exponent: u8, /// The length of the bootstrapping phase in epochs. - bootstrapping_duration: EpochIndex, + pub(crate) bootstrapping_duration: u32, /// The ratio of the final rewards rate to the generation rate of Mana. - reward_to_generation_ratio: u8, + pub(crate) reward_to_generation_ratio: u8, /// The rate of Mana rewards at the start of the bootstrapping phase. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] - initial_target_rewards_rate: u64, + pub(crate) initial_target_rewards_rate: u64, /// The rate of Mana rewards after the bootstrapping phase. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] - final_target_rewards_rate: u64, + pub(crate) final_target_rewards_rate: u64, /// The exponent used for shifting operation during the pool rewards calculations. - pool_coefficient_exponent: u8, + pub(crate) pool_coefficient_exponent: u8, // The number of epochs for which rewards are retained. - retention_period: u16, -} - -impl Default for RewardsParameters { - fn default() -> Self { - Self { - profit_margin_exponent: 8, - bootstrapping_duration: EpochIndex(1079), - reward_to_generation_ratio: 2, - initial_target_rewards_rate: 616067521149261, - final_target_rewards_rate: 226702563632670, - pool_coefficient_exponent: 11, - retention_period: 384, - } - } + pub(crate) retention_period: u16, } diff --git a/sdk/src/types/block/output/account.rs b/sdk/src/types/block/output/account.rs index 27bfa83597..1651b7fd0b 100644 --- a/sdk/src/types/block/output/account.rs +++ b/sdk/src/types/block/output/account.rs @@ -489,40 +489,40 @@ impl Packable for AccountOutput { Ok(()) } - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { - let amount = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?; + let amount = u64::unpack_inner(unpacker, visitor).coerce()?; - let mana = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?; + let mana = u64::unpack_inner(unpacker, visitor).coerce()?; - let account_id = AccountId::unpack::<_, VERIFY>(unpacker, &()).coerce()?; + let account_id = AccountId::unpack_inner(unpacker, visitor).coerce()?; - let foundry_counter = u32::unpack::<_, VERIFY>(unpacker, &()).coerce()?; + let foundry_counter = u32::unpack_inner(unpacker, visitor).coerce()?; - if VERIFY { + if visitor.is_some() { verify_index_counter(&account_id, foundry_counter).map_err(UnpackError::Packable)?; } - let unlock_conditions = UnlockConditions::unpack::<_, VERIFY>(unpacker, visitor)?; + let unlock_conditions = UnlockConditions::unpack(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_unlock_conditions(&unlock_conditions, &account_id).map_err(UnpackError::Packable)?; } - let features = Features::unpack::<_, VERIFY>(unpacker, &())?; + let features = Features::unpack_inner(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_restricted_addresses(&unlock_conditions, Self::KIND, features.native_token(), mana) .map_err(UnpackError::Packable)?; verify_allowed_features(&features, Self::ALLOWED_FEATURES).map_err(UnpackError::Packable)?; verify_staked_amount(amount, &features).map_err(UnpackError::Packable)?; } - let immutable_features = Features::unpack::<_, VERIFY>(unpacker, &())?; + let immutable_features = Features::unpack_inner(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_allowed_features(&immutable_features, Self::ALLOWED_IMMUTABLE_FEATURES) .map_err(UnpackError::Packable)?; } @@ -639,18 +639,19 @@ mod dto { crate::impl_serde_typed_dto!(AccountOutput, AccountOutputDto, "account output"); } -#[cfg(test)] +#[cfg(all(test, feature = "protocol_parameters_samples"))] mod tests { use pretty_assertions::assert_eq; use super::*; use crate::types::block::{ - output::account::dto::AccountOutputDto, protocol::protocol_parameters, rand::output::rand_account_output, + output::account::dto::AccountOutputDto, protocol::iota_mainnet_protocol_parameters, + rand::output::rand_account_output, }; #[test] fn to_from_dto() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let account_output = rand_account_output(protocol_parameters.token_supply()); let dto = AccountOutputDto::from(&account_output); let output = Output::Account(AccountOutput::try_from(dto).unwrap()); diff --git a/sdk/src/types/block/output/anchor.rs b/sdk/src/types/block/output/anchor.rs index 7f1089e13a..1739933b95 100644 --- a/sdk/src/types/block/output/anchor.rs +++ b/sdk/src/types/block/output/anchor.rs @@ -523,38 +523,38 @@ impl Packable for AnchorOutput { Ok(()) } - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { - let amount = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?; + let amount = u64::unpack_inner(unpacker, visitor).coerce()?; - let mana = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?; + let mana = u64::unpack_inner(unpacker, visitor).coerce()?; - let anchor_id = AnchorId::unpack::<_, VERIFY>(unpacker, &()).coerce()?; - let state_index = u32::unpack::<_, VERIFY>(unpacker, &()).coerce()?; + let anchor_id = AnchorId::unpack_inner(unpacker, visitor).coerce()?; + let state_index = u32::unpack_inner(unpacker, visitor).coerce()?; - if VERIFY { + if visitor.is_some() { verify_index_counter(&anchor_id, state_index).map_err(UnpackError::Packable)?; } - let unlock_conditions = UnlockConditions::unpack::<_, VERIFY>(unpacker, visitor)?; + let unlock_conditions = UnlockConditions::unpack(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_unlock_conditions(&unlock_conditions, &anchor_id).map_err(UnpackError::Packable)?; } - let features = Features::unpack::<_, VERIFY>(unpacker, &())?; + let features = Features::unpack_inner(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_restricted_addresses(&unlock_conditions, Self::KIND, features.native_token(), mana) .map_err(UnpackError::Packable)?; verify_allowed_features(&features, Self::ALLOWED_FEATURES).map_err(UnpackError::Packable)?; } - let immutable_features = Features::unpack::<_, VERIFY>(unpacker, &())?; + let immutable_features = Features::unpack_inner(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_allowed_features(&immutable_features, Self::ALLOWED_IMMUTABLE_FEATURES) .map_err(UnpackError::Packable)?; } @@ -671,16 +671,17 @@ mod dto { crate::impl_serde_typed_dto!(AnchorOutput, AnchorOutputDto, "anchor output"); } -#[cfg(test)] +#[cfg(all(test, feature = "protocol_parameters_samples"))] mod tests { use super::*; use crate::types::block::{ - output::anchor::dto::AnchorOutputDto, protocol::protocol_parameters, rand::output::rand_anchor_output, + output::anchor::dto::AnchorOutputDto, protocol::iota_mainnet_protocol_parameters, + rand::output::rand_anchor_output, }; #[test] fn to_from_dto() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let anchor_output = rand_anchor_output(protocol_parameters.token_supply()); let dto = AnchorOutputDto::from(&anchor_output); let output = Output::Anchor(AnchorOutput::try_from(dto).unwrap()); diff --git a/sdk/src/types/block/output/basic.rs b/sdk/src/types/block/output/basic.rs index 41f81ac911..afa6b3e62d 100644 --- a/sdk/src/types/block/output/basic.rs +++ b/sdk/src/types/block/output/basic.rs @@ -188,7 +188,7 @@ impl BasicOutputBuilder { pub fn finish(self) -> Result { let unlock_conditions = UnlockConditions::from_set(self.unlock_conditions)?; - verify_unlock_conditions::(&unlock_conditions)?; + verify_unlock_conditions(&unlock_conditions)?; let features = Features::from_set(self.features)?; @@ -198,7 +198,7 @@ impl BasicOutputBuilder { features.native_token(), self.mana, )?; - verify_features::(&features)?; + verify_features(&features)?; let mut output = BasicOutput { amount: 0, @@ -368,38 +368,30 @@ impl WorkScore for BasicOutput { impl MinimumOutputAmount for BasicOutput {} -fn verify_unlock_conditions(unlock_conditions: &UnlockConditions) -> Result<(), Error> { - if VERIFY { - if unlock_conditions.address().is_none() { - Err(Error::MissingAddressUnlockCondition) - } else { - verify_allowed_unlock_conditions(unlock_conditions, BasicOutput::ALLOWED_UNLOCK_CONDITIONS) - } +fn verify_unlock_conditions(unlock_conditions: &UnlockConditions) -> Result<(), Error> { + if unlock_conditions.address().is_none() { + Err(Error::MissingAddressUnlockCondition) } else { - Ok(()) + verify_allowed_unlock_conditions(unlock_conditions, BasicOutput::ALLOWED_UNLOCK_CONDITIONS) } } -fn verify_unlock_conditions_packable( +fn verify_unlock_conditions_packable( unlock_conditions: &UnlockConditions, _: &ProtocolParameters, ) -> Result<(), Error> { - verify_unlock_conditions::(unlock_conditions) + verify_unlock_conditions(unlock_conditions) } -fn verify_features(features: &Features) -> Result<(), Error> { - if VERIFY { - verify_allowed_features(features, BasicOutput::ALLOWED_FEATURES) - } else { - Ok(()) - } +fn verify_features(features: &Features) -> Result<(), Error> { + verify_allowed_features(features, BasicOutput::ALLOWED_FEATURES) } -fn verify_features_packable(features: &Features, _: &ProtocolParameters) -> Result<(), Error> { - verify_features::(features) +fn verify_features_packable(features: &Features, _: &ProtocolParameters) -> Result<(), Error> { + verify_features(features) } -fn verify_basic_output(output: &BasicOutput, _: &ProtocolParameters) -> Result<(), Error> { +fn verify_basic_output(output: &BasicOutput, _: &ProtocolParameters) -> Result<(), Error> { verify_restricted_addresses( output.unlock_conditions(), BasicOutput::KIND, @@ -465,14 +457,14 @@ mod dto { crate::impl_serde_typed_dto!(BasicOutput, BasicOutputDto, "basic output"); } -#[cfg(test)] +#[cfg(all(test, feature = "protocol_parameters_samples"))] mod tests { use pretty_assertions::assert_eq; use super::*; use crate::types::block::{ output::{basic::dto::BasicOutputDto, FoundryId, SimpleTokenScheme, TokenId}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::{ address::rand_account_address, output::{ @@ -483,7 +475,7 @@ mod tests { #[test] fn to_from_dto() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let basic_output = rand_basic_output(protocol_parameters.token_supply()); let dto = BasicOutputDto::from(&basic_output); let output = Output::Basic(BasicOutput::try_from(dto).unwrap()); diff --git a/sdk/src/types/block/output/delegation.rs b/sdk/src/types/block/output/delegation.rs index 27a3e8941e..c6415a8927 100644 --- a/sdk/src/types/block/output/delegation.rs +++ b/sdk/src/types/block/output/delegation.rs @@ -163,11 +163,11 @@ impl DelegationOutputBuilder { pub fn finish(self) -> Result { let validator_address = Address::from(self.validator_address); - verify_validator_address::(&validator_address)?; + verify_validator_address(&validator_address)?; let unlock_conditions = UnlockConditions::from_set(self.unlock_conditions)?; - verify_unlock_conditions::(&unlock_conditions)?; + verify_unlock_conditions(&unlock_conditions)?; verify_restricted_addresses(&unlock_conditions, DelegationOutput::KIND, None, 0)?; let mut output = DelegationOutput { @@ -366,50 +366,38 @@ impl WorkScore for DelegationOutput { impl MinimumOutputAmount for DelegationOutput {} -fn verify_validator_address(validator_address: &Address) -> Result<(), Error> { - if VERIFY { - if let Address::Account(validator_address) = validator_address { - if validator_address.is_null() { - return Err(Error::NullDelegationValidatorId); - } - } else { - return Err(Error::InvalidAddressKind(validator_address.kind())); +fn verify_validator_address(validator_address: &Address) -> Result<(), Error> { + if let Address::Account(validator_address) = validator_address { + if validator_address.is_null() { + return Err(Error::NullDelegationValidatorId); } + } else { + return Err(Error::InvalidAddressKind(validator_address.kind())); } Ok(()) } -fn verify_validator_address_packable( - validator_address: &Address, - _: &ProtocolParameters, -) -> Result<(), Error> { - verify_validator_address::(validator_address) +fn verify_validator_address_packable(validator_address: &Address, _: &ProtocolParameters) -> Result<(), Error> { + verify_validator_address(validator_address) } -fn verify_unlock_conditions(unlock_conditions: &UnlockConditions) -> Result<(), Error> { - if VERIFY { - if unlock_conditions.address().is_none() { - Err(Error::MissingAddressUnlockCondition) - } else { - verify_allowed_unlock_conditions(unlock_conditions, DelegationOutput::ALLOWED_UNLOCK_CONDITIONS) - } +fn verify_unlock_conditions(unlock_conditions: &UnlockConditions) -> Result<(), Error> { + if unlock_conditions.address().is_none() { + Err(Error::MissingAddressUnlockCondition) } else { - Ok(()) + verify_allowed_unlock_conditions(unlock_conditions, DelegationOutput::ALLOWED_UNLOCK_CONDITIONS) } } -fn verify_unlock_conditions_packable( +fn verify_unlock_conditions_packable( unlock_conditions: &UnlockConditions, _: &ProtocolParameters, ) -> Result<(), Error> { - verify_unlock_conditions::(unlock_conditions) + verify_unlock_conditions(unlock_conditions) } -fn verify_delegation_output( - output: &DelegationOutput, - _: &ProtocolParameters, -) -> Result<(), Error> { +fn verify_delegation_output(output: &DelegationOutput, _: &ProtocolParameters) -> Result<(), Error> { verify_restricted_addresses(output.unlock_conditions(), DelegationOutput::KIND, None, 0) } diff --git a/sdk/src/types/block/output/feature/block_issuer.rs b/sdk/src/types/block/output/feature/block_issuer.rs index 5334d301c4..7f4a4979fd 100644 --- a/sdk/src/types/block/output/feature/block_issuer.rs +++ b/sdk/src/types/block/output/feature/block_issuer.rs @@ -107,13 +107,11 @@ impl Packable for Ed25519PublicKeyHashBlockIssuerKey { Ok(()) } - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { - Ok(Self( - <[u8; Self::LENGTH]>::unpack::<_, VERIFY>(unpacker, visitor).coerce()?, - )) + Ok(Self(<[u8; Self::LENGTH]>::unpack(unpacker, visitor).coerce()?)) } } @@ -127,8 +125,8 @@ pub struct BlockIssuerKeys( #[packable(verify_with = verify_block_issuer_keys)] BoxedSlicePrefix, ); -fn verify_block_issuer_keys(block_issuer_keys: &[BlockIssuerKey]) -> Result<(), Error> { - if VERIFY && !is_unique_sorted(block_issuer_keys.iter()) { +fn verify_block_issuer_keys(block_issuer_keys: &[BlockIssuerKey]) -> Result<(), Error> { + if !is_unique_sorted(block_issuer_keys.iter()) { return Err(Error::BlockIssuerKeysNotUniqueSorted); } @@ -179,7 +177,7 @@ impl BlockIssuerKeys { block_issuer_keys.sort(); // Still need to verify the duplicate block issuer keys. - verify_block_issuer_keys::(&block_issuer_keys)?; + verify_block_issuer_keys(&block_issuer_keys)?; Ok(Self(block_issuer_keys)) } diff --git a/sdk/src/types/block/output/feature/metadata.rs b/sdk/src/types/block/output/feature/metadata.rs index 8d21874b84..6b65884918 100644 --- a/sdk/src/types/block/output/feature/metadata.rs +++ b/sdk/src/types/block/output/feature/metadata.rs @@ -37,24 +37,17 @@ pub(crate) type MetadataBTreeMap = #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct MetadataFeature(MetadataBTreeMapPrefix); -pub(crate) fn verify_keys(map: &MetadataBTreeMapPrefix) -> Result<(), Error> { - if VERIFY { - for key in map.keys() { - if !key.iter().all(|c| c.is_ascii_graphic()) { - return Err(Error::NonGraphicAsciiMetadataKey(key.to_vec())); - } +pub(crate) fn verify_keys(map: &MetadataBTreeMapPrefix) -> Result<(), Error> { + for key in map.keys() { + if !key.iter().all(|c| c.is_ascii_graphic()) { + return Err(Error::NonGraphicAsciiMetadataKey(key.to_vec())); } } Ok(()) } -pub(crate) fn verify_packed_len( - len: usize, - bytes_length_range: RangeInclusive, -) -> Result<(), Error> { - if VERIFY - && !bytes_length_range.contains(&u16::try_from(len).map_err(|e| Error::InvalidMetadataFeature(e.to_string()))?) - { +pub(crate) fn verify_packed_len(len: usize, bytes_length_range: RangeInclusive) -> Result<(), Error> { + if !bytes_length_range.contains(&u16::try_from(len).map_err(|e| Error::InvalidMetadataFeature(e.to_string()))?) { return Err(Error::InvalidMetadataFeature(format!( "Out of bounds byte length: {len}" ))); @@ -150,8 +143,8 @@ impl MetadataFeatureMap { .map_err(Error::InvalidMetadataFeatureEntryCount)?, ); - verify_keys::(&res.0)?; - verify_packed_len::(res.packed_len(), MetadataFeature::BYTE_LENGTH_RANGE)?; + verify_keys(&res.0)?; + verify_packed_len(res.packed_len(), MetadataFeature::BYTE_LENGTH_RANGE)?; Ok(res) } @@ -183,18 +176,20 @@ impl Packable for MetadataFeature { self.0.pack(packer) } - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { let mut unpacker = CounterUnpacker::new(unpacker); let res = Self( - MetadataBTreeMapPrefix::unpack::<_, VERIFY>(&mut unpacker, visitor) + MetadataBTreeMapPrefix::unpack(&mut unpacker, visitor) .map_packable_err(|e| Error::InvalidMetadataFeature(e.to_string()))?, ); - verify_keys::(&res.0).map_err(UnpackError::Packable)?; - verify_packed_len::(unpacker.counter(), Self::BYTE_LENGTH_RANGE).map_err(UnpackError::Packable)?; + if visitor.is_some() { + verify_keys(&res.0).map_err(UnpackError::Packable)?; + verify_packed_len(unpacker.counter(), Self::BYTE_LENGTH_RANGE).map_err(UnpackError::Packable)?; + } Ok(res) } diff --git a/sdk/src/types/block/output/feature/mod.rs b/sdk/src/types/block/output/feature/mod.rs index 03381a2754..b4149df685 100644 --- a/sdk/src/types/block/output/feature/mod.rs +++ b/sdk/src/types/block/output/feature/mod.rs @@ -223,7 +223,7 @@ impl Features { features.sort_by_key(Feature::kind); // Sort is obviously fine now but uniqueness still needs to be checked. - verify_unique_sorted::(&features)?; + verify_unique_sorted(&features)?; Ok(Self(features)) } @@ -297,8 +297,8 @@ impl StorageScore for Features { } #[inline] -fn verify_unique_sorted(features: &[Feature]) -> Result<(), Error> { - if VERIFY && !is_unique_sorted(features.iter().map(Feature::kind)) { +fn verify_unique_sorted(features: &[Feature]) -> Result<(), Error> { + if !is_unique_sorted(features.iter().map(Feature::kind)) { Err(Error::FeaturesNotUniqueSorted) } else { Ok(()) diff --git a/sdk/src/types/block/output/feature/state_metadata.rs b/sdk/src/types/block/output/feature/state_metadata.rs index 5bb8a3bd6c..83483b104c 100644 --- a/sdk/src/types/block/output/feature/state_metadata.rs +++ b/sdk/src/types/block/output/feature/state_metadata.rs @@ -115,8 +115,8 @@ impl StateMetadataFeatureMap { .map_err(Error::InvalidMetadataFeatureEntryCount)?, ); - verify_keys::(&res.0)?; - verify_packed_len::(res.packed_len(), StateMetadataFeature::BYTE_LENGTH_RANGE)?; + verify_keys(&res.0)?; + verify_packed_len(res.packed_len(), StateMetadataFeature::BYTE_LENGTH_RANGE)?; Ok(res) } @@ -148,18 +148,20 @@ impl Packable for StateMetadataFeature { self.0.pack(packer) } - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { let mut unpacker = CounterUnpacker::new(unpacker); let res = Self( - MetadataBTreeMapPrefix::unpack::<_, VERIFY>(&mut unpacker, visitor) + MetadataBTreeMapPrefix::unpack(&mut unpacker, visitor) .map_packable_err(|e| Error::InvalidMetadataFeature(e.to_string()))?, ); - verify_keys::(&res.0).map_err(UnpackError::Packable)?; - verify_packed_len::(unpacker.counter(), Self::BYTE_LENGTH_RANGE).map_err(UnpackError::Packable)?; + if visitor.is_some() { + verify_keys(&res.0).map_err(UnpackError::Packable)?; + verify_packed_len(unpacker.counter(), Self::BYTE_LENGTH_RANGE).map_err(UnpackError::Packable)?; + } Ok(res) } diff --git a/sdk/src/types/block/output/foundry.rs b/sdk/src/types/block/output/foundry.rs index 5234028d7b..02ac4fac6b 100644 --- a/sdk/src/types/block/output/foundry.rs +++ b/sdk/src/types/block/output/foundry.rs @@ -526,30 +526,30 @@ impl Packable for FoundryOutput { Ok(()) } - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { - let amount = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?; + let amount = u64::unpack_inner(unpacker, visitor).coerce()?; - let serial_number = u32::unpack::<_, VERIFY>(unpacker, &()).coerce()?; - let token_scheme = TokenScheme::unpack::<_, VERIFY>(unpacker, &())?; + let serial_number = u32::unpack_inner(unpacker, visitor).coerce()?; + let token_scheme = TokenScheme::unpack_inner(unpacker, visitor)?; - let unlock_conditions = UnlockConditions::unpack::<_, VERIFY>(unpacker, visitor)?; + let unlock_conditions = UnlockConditions::unpack(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_unlock_conditions(&unlock_conditions).map_err(UnpackError::Packable)?; } - let features = Features::unpack::<_, VERIFY>(unpacker, &())?; + let features = Features::unpack_inner(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_allowed_features(&features, Self::ALLOWED_FEATURES).map_err(UnpackError::Packable)?; } - let immutable_features = Features::unpack::<_, VERIFY>(unpacker, &())?; + let immutable_features = Features::unpack_inner(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_allowed_features(&immutable_features, Self::ALLOWED_IMMUTABLE_FEATURES) .map_err(UnpackError::Packable)?; } @@ -641,18 +641,19 @@ mod dto { crate::impl_serde_typed_dto!(FoundryOutput, FoundryOutputDto, "foundry output"); } -#[cfg(test)] +#[cfg(all(test, feature = "protocol_parameters_samples"))] mod tests { use pretty_assertions::assert_eq; use super::*; use crate::types::block::{ - output::foundry::dto::FoundryOutputDto, protocol::protocol_parameters, rand::output::rand_foundry_output, + output::foundry::dto::FoundryOutputDto, protocol::iota_mainnet_protocol_parameters, + rand::output::rand_foundry_output, }; #[test] fn to_from_dto() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let foundry_output = rand_foundry_output(protocol_parameters.token_supply()); let dto = FoundryOutputDto::from(&foundry_output); let output = Output::Foundry(FoundryOutput::try_from(dto).unwrap()); diff --git a/sdk/src/types/block/output/native_token.rs b/sdk/src/types/block/output/native_token.rs index 20084d4c46..50d0e5b050 100644 --- a/sdk/src/types/block/output/native_token.rs +++ b/sdk/src/types/block/output/native_token.rs @@ -52,7 +52,7 @@ impl NativeToken { pub fn new(token_id: TokenId, amount: impl Into) -> Result { let amount = amount.into(); - verify_amount::(&amount)?; + verify_amount(&amount)?; Ok(Self { token_id, amount }) } @@ -88,8 +88,8 @@ impl Ord for NativeToken { } #[inline] -fn verify_amount(amount: &U256) -> Result<(), Error> { - if VERIFY && amount.is_zero() { +fn verify_amount(amount: &U256) -> Result<(), Error> { + if amount.is_zero() { Err(Error::NativeTokensNullAmount) } else { Ok(()) @@ -219,7 +219,7 @@ impl NativeTokens { native_tokens.sort_by(|a, b| a.token_id().cmp(b.token_id())); // Sort is obviously fine now but uniqueness still needs to be checked. - verify_unique_sorted::(&native_tokens)?; + verify_unique_sorted(&native_tokens)?; Ok(Self(native_tokens)) } @@ -259,8 +259,8 @@ impl NativeTokens { } #[inline] -fn verify_unique_sorted(native_tokens: &[NativeToken]) -> Result<(), Error> { - if VERIFY && !is_unique_sorted(native_tokens.iter().map(NativeToken::token_id)) { +fn verify_unique_sorted(native_tokens: &[NativeToken]) -> Result<(), Error> { + if !is_unique_sorted(native_tokens.iter().map(NativeToken::token_id)) { Err(Error::NativeTokensNotUniqueSorted) } else { Ok(()) diff --git a/sdk/src/types/block/output/nft.rs b/sdk/src/types/block/output/nft.rs index da0146aa14..ec83f5fbf5 100644 --- a/sdk/src/types/block/output/nft.rs +++ b/sdk/src/types/block/output/nft.rs @@ -453,32 +453,32 @@ impl Packable for NftOutput { Ok(()) } - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { - let amount = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?; + let amount = u64::unpack_inner(unpacker, visitor).coerce()?; - let mana = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?; + let mana = u64::unpack_inner(unpacker, visitor).coerce()?; - let nft_id = NftId::unpack::<_, VERIFY>(unpacker, &()).coerce()?; - let unlock_conditions = UnlockConditions::unpack::<_, VERIFY>(unpacker, visitor)?; + let nft_id = NftId::unpack_inner(unpacker, visitor).coerce()?; + let unlock_conditions = UnlockConditions::unpack(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_unlock_conditions(&unlock_conditions, &nft_id).map_err(UnpackError::Packable)?; } - let features = Features::unpack::<_, VERIFY>(unpacker, &())?; + let features = Features::unpack_inner(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_restricted_addresses(&unlock_conditions, Self::KIND, features.native_token(), mana) .map_err(UnpackError::Packable)?; verify_allowed_features(&features, Self::ALLOWED_FEATURES).map_err(UnpackError::Packable)?; } - let immutable_features = Features::unpack::<_, VERIFY>(unpacker, &())?; + let immutable_features = Features::unpack_inner(unpacker, visitor)?; - if VERIFY { + if visitor.is_some() { verify_allowed_features(&immutable_features, Self::ALLOWED_IMMUTABLE_FEATURES) .map_err(UnpackError::Packable)?; } @@ -571,18 +571,18 @@ mod dto { crate::impl_serde_typed_dto!(NftOutput, NftOutputDto, "nft output"); } -#[cfg(test)] +#[cfg(all(test, feature = "protocol_parameters_samples"))] mod tests { use pretty_assertions::assert_eq; use super::*; use crate::types::block::{ - output::nft::dto::NftOutputDto, protocol::protocol_parameters, rand::output::rand_nft_output, + output::nft::dto::NftOutputDto, protocol::iota_mainnet_protocol_parameters, rand::output::rand_nft_output, }; #[test] fn to_from_dto() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let nft_output = rand_nft_output(protocol_parameters.token_supply()); let dto = NftOutputDto::from(&nft_output); let output = Output::Nft(NftOutput::try_from(dto).unwrap()); diff --git a/sdk/src/types/block/output/output_id.rs b/sdk/src/types/block/output/output_id.rs index 70d2b47cba..57d9289257 100644 --- a/sdk/src/types/block/output/output_id.rs +++ b/sdk/src/types/block/output/output_id.rs @@ -60,7 +60,7 @@ crate::string_serde_impl!(OutputId); impl From<[u8; Self::LENGTH]> for OutputId { fn from(bytes: [u8; Self::LENGTH]) -> Self { // Unwrap is fine because size is already known and valid. - Self::unpack_unverified(bytes).unwrap() + Self::unpack_bytes_unverified(bytes).unwrap() } } diff --git a/sdk/src/types/block/output/storage_score.rs b/sdk/src/types/block/output/storage_score.rs index 27e795a745..97ecb38551 100644 --- a/sdk/src/types/block/output/storage_score.rs +++ b/sdk/src/types/block/output/storage_score.rs @@ -18,13 +18,6 @@ use crate::types::block::{ BlockId, }; -const DEFAULT_STORAGE_COST: u64 = 100; -const DEFAULT_FACTOR_DATA: u8 = 1; -const DEFAULT_OFFSET_OUTPUT_OVERHEAD: u64 = 10; -const DEFAULT_OFFSET_ED25519_BLOCK_ISSUER_KEY: u64 = 100; -const DEFAULT_OFFSET_STAKING_FEATURE: u64 = 100; -const DEFAULT_OFFSET_DELEGATION: u64 = 100; - // Parameters of storage score calculations on objects which take node resources. #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Packable)] #[cfg_attr( @@ -35,34 +28,21 @@ const DEFAULT_OFFSET_DELEGATION: u64 = 100; pub struct StorageScoreParameters { /// Number of IOTA tokens required per unit of storage score. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] - storage_cost: u64, + pub(crate) storage_cost: u64, /// Factor to be used for data only fields. - factor_data: u8, + pub(crate) factor_data: u8, /// Offset to be applied to all outputs for the overhead of handling them in storage. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] - offset_output_overhead: u64, + pub(crate) offset_output_overhead: u64, /// Offset to be used for Ed25519-based block issuer keys. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] - offset_ed25519_block_issuer_key: u64, + pub(crate) offset_ed25519_block_issuer_key: u64, /// Offset to be used for staking feature. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] - offset_staking_feature: u64, + pub(crate) offset_staking_feature: u64, /// Offset to be used for delegation. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] - offset_delegation: u64, -} - -impl Default for StorageScoreParameters { - fn default() -> Self { - Self { - storage_cost: DEFAULT_STORAGE_COST, - factor_data: DEFAULT_FACTOR_DATA, - offset_output_overhead: DEFAULT_OFFSET_OUTPUT_OVERHEAD, - offset_ed25519_block_issuer_key: DEFAULT_OFFSET_ED25519_BLOCK_ISSUER_KEY, - offset_staking_feature: DEFAULT_OFFSET_STAKING_FEATURE, - offset_delegation: DEFAULT_OFFSET_DELEGATION, - } - } + pub(crate) offset_delegation: u64, } impl StorageScoreParameters { diff --git a/sdk/src/types/block/output/token_scheme/simple.rs b/sdk/src/types/block/output/token_scheme/simple.rs index 328adf80c5..bf019095f9 100644 --- a/sdk/src/types/block/output/token_scheme/simple.rs +++ b/sdk/src/types/block/output/token_scheme/simple.rs @@ -43,7 +43,7 @@ impl SimpleTokenScheme { maximum_supply, }; - verify_simple_token_scheme::(&token_scheme)?; + verify_simple_token_scheme(&token_scheme)?; Ok(token_scheme) } @@ -80,11 +80,10 @@ impl WorkScore for SimpleTokenScheme { } #[inline] -fn verify_simple_token_scheme(token_scheme: &SimpleTokenScheme) -> Result<(), Error> { - if VERIFY - && (token_scheme.maximum_supply.is_zero() - || token_scheme.melted_tokens > token_scheme.minted_tokens - || token_scheme.minted_tokens - token_scheme.melted_tokens > token_scheme.maximum_supply) +fn verify_simple_token_scheme(token_scheme: &SimpleTokenScheme) -> Result<(), Error> { + if token_scheme.maximum_supply.is_zero() + || token_scheme.melted_tokens > token_scheme.minted_tokens + || token_scheme.minted_tokens - token_scheme.melted_tokens > token_scheme.maximum_supply { return Err(Error::InvalidFoundryOutputSupply { minted: token_scheme.minted_tokens, diff --git a/sdk/src/types/block/output/unlock_condition/expiration.rs b/sdk/src/types/block/output/unlock_condition/expiration.rs index 537a330a38..4c6be5b198 100644 --- a/sdk/src/types/block/output/unlock_condition/expiration.rs +++ b/sdk/src/types/block/output/unlock_condition/expiration.rs @@ -33,8 +33,8 @@ impl ExpirationUnlockCondition { let slot_index = slot_index.into(); let return_address = return_address.into(); - verify_slot_index::(&slot_index)?; - verify_return_address::(&return_address)?; + verify_slot_index(&slot_index)?; + verify_return_address(&return_address)?; Ok(Self { return_address, @@ -95,8 +95,8 @@ impl StorageScore for ExpirationUnlockCondition { } #[inline] -fn verify_return_address(return_address: &Address) -> Result<(), Error> { - if VERIFY && return_address.is_implicit_account_creation() { +fn verify_return_address(return_address: &Address) -> Result<(), Error> { + if return_address.is_implicit_account_creation() { Err(Error::InvalidAddressKind(return_address.kind())) } else { Ok(()) @@ -104,8 +104,8 @@ fn verify_return_address(return_address: &Address) -> Result } #[inline] -fn verify_slot_index(slot_index: &SlotIndex) -> Result<(), Error> { - if VERIFY && *slot_index == 0 { +fn verify_slot_index(slot_index: &SlotIndex) -> Result<(), Error> { + if *slot_index == 0 { Err(Error::ExpirationUnlockConditionZero) } else { Ok(()) diff --git a/sdk/src/types/block/output/unlock_condition/immutable_account_address.rs b/sdk/src/types/block/output/unlock_condition/immutable_account_address.rs index 8554f1c1b3..2a1aba446f 100644 --- a/sdk/src/types/block/output/unlock_condition/immutable_account_address.rs +++ b/sdk/src/types/block/output/unlock_condition/immutable_account_address.rs @@ -37,8 +37,8 @@ impl StorageScore for ImmutableAccountAddressUnlockCondition { } #[inline] -fn verify_address(address: &Address) -> Result<(), Error> { - if VERIFY && !address.is_account() { +fn verify_address(address: &Address) -> Result<(), Error> { + if !address.is_account() { Err(Error::InvalidAddressKind(address.kind())) } else { Ok(()) diff --git a/sdk/src/types/block/output/unlock_condition/mod.rs b/sdk/src/types/block/output/unlock_condition/mod.rs index 489bd883c8..3d28a6a2aa 100644 --- a/sdk/src/types/block/output/unlock_condition/mod.rs +++ b/sdk/src/types/block/output/unlock_condition/mod.rs @@ -205,7 +205,7 @@ impl UnlockConditions { unlock_conditions.sort_by_key(UnlockCondition::kind); // Sort is obviously fine now but uniqueness still needs to be checked. - verify_unique_sorted::(&unlock_conditions)?; + verify_unique_sorted(&unlock_conditions)?; Ok(Self(unlock_conditions)) } @@ -342,8 +342,8 @@ impl StorageScore for UnlockConditions { } #[inline] -fn verify_unique_sorted(unlock_conditions: &[UnlockCondition]) -> Result<(), Error> { - if VERIFY && !is_unique_sorted(unlock_conditions.iter().map(UnlockCondition::kind)) { +fn verify_unique_sorted(unlock_conditions: &[UnlockCondition]) -> Result<(), Error> { + if !is_unique_sorted(unlock_conditions.iter().map(UnlockCondition::kind)) { Err(Error::UnlockConditionsNotUniqueSorted) } else { Ok(()) @@ -351,11 +351,8 @@ fn verify_unique_sorted(unlock_conditions: &[UnlockCondition } #[inline] -fn verify_unique_sorted_packable( - unlock_conditions: &[UnlockCondition], - _: &ProtocolParameters, -) -> Result<(), Error> { - verify_unique_sorted::(unlock_conditions) +fn verify_unique_sorted_packable(unlock_conditions: &[UnlockCondition], _: &ProtocolParameters) -> Result<(), Error> { + verify_unique_sorted(unlock_conditions) } pub(crate) fn verify_allowed_unlock_conditions( diff --git a/sdk/src/types/block/output/unlock_condition/storage_deposit_return.rs b/sdk/src/types/block/output/unlock_condition/storage_deposit_return.rs index abe396db4a..64f85d39cc 100644 --- a/sdk/src/types/block/output/unlock_condition/storage_deposit_return.rs +++ b/sdk/src/types/block/output/unlock_condition/storage_deposit_return.rs @@ -27,7 +27,7 @@ impl StorageDepositReturnUnlockCondition { pub fn new(return_address: impl Into
, amount: u64) -> Result { let return_address = return_address.into(); - verify_return_address::(&return_address)?; + verify_return_address(&return_address)?; Ok(Self { return_address, amount }) } @@ -52,8 +52,8 @@ impl StorageScore for StorageDepositReturnUnlockCondition { } #[inline] -fn verify_return_address(return_address: &Address) -> Result<(), Error> { - if VERIFY && return_address.is_implicit_account_creation() { +fn verify_return_address(return_address: &Address) -> Result<(), Error> { + if return_address.is_implicit_account_creation() { Err(Error::InvalidAddressKind(return_address.kind())) } else { Ok(()) diff --git a/sdk/src/types/block/output/unlock_condition/timelock.rs b/sdk/src/types/block/output/unlock_condition/timelock.rs index cf17805ee0..9e1ffb89b6 100644 --- a/sdk/src/types/block/output/unlock_condition/timelock.rs +++ b/sdk/src/types/block/output/unlock_condition/timelock.rs @@ -19,7 +19,7 @@ impl TimelockUnlockCondition { pub fn new(slot_index: impl Into) -> Result { let slot_index = slot_index.into(); - verify_slot_index::(&slot_index)?; + verify_slot_index(&slot_index)?; Ok(Self(slot_index)) } @@ -39,8 +39,8 @@ impl TimelockUnlockCondition { impl StorageScore for TimelockUnlockCondition {} #[inline] -fn verify_slot_index(slot_index: &SlotIndex) -> Result<(), Error> { - if VERIFY && *slot_index == 0 { +fn verify_slot_index(slot_index: &SlotIndex) -> Result<(), Error> { + if *slot_index == 0 { Err(Error::TimelockUnlockConditionZero) } else { Ok(()) diff --git a/sdk/src/types/block/payload/mod.rs b/sdk/src/types/block/payload/mod.rs index ceb5775cca..5111899c6a 100644 --- a/sdk/src/types/block/payload/mod.rs +++ b/sdk/src/types/block/payload/mod.rs @@ -133,18 +133,18 @@ impl Packable for OptionalPayload { } } - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { - let len = u32::unpack::<_, VERIFY>(unpacker, &()).coerce()? as usize; + let len = u32::unpack_inner(unpacker, visitor).coerce()? as usize; if len > 0 { unpacker.ensure_bytes(len)?; let start_opt = unpacker.read_bytes(); - let payload = Payload::unpack::<_, VERIFY>(unpacker, visitor)?; + let payload = Payload::unpack(unpacker, visitor)?; let actual_len = if let (Some(start), Some(end)) = (start_opt, unpacker.read_bytes()) { end - start diff --git a/sdk/src/types/block/payload/signed_transaction/mod.rs b/sdk/src/types/block/payload/signed_transaction/mod.rs index 262315b4af..b41d706a80 100644 --- a/sdk/src/types/block/payload/signed_transaction/mod.rs +++ b/sdk/src/types/block/payload/signed_transaction/mod.rs @@ -36,7 +36,7 @@ impl SignedTransactionPayload { pub fn new(transaction: Transaction, unlocks: Unlocks) -> Result { let payload = Self { transaction, unlocks }; - verify_signed_transaction_payload::(&payload)?; + verify_signed_transaction_payload(&payload)?; Ok(payload) } @@ -61,7 +61,7 @@ impl WorkScore for SignedTransactionPayload { } } -fn verify_signed_transaction_payload(payload: &SignedTransactionPayload) -> Result<(), Error> { +fn verify_signed_transaction_payload(payload: &SignedTransactionPayload) -> Result<(), Error> { if payload.transaction.inputs().len() != payload.unlocks.len() { return Err(Error::InputUnlockCountMismatch { input_count: payload.transaction.inputs().len(), diff --git a/sdk/src/types/block/payload/signed_transaction/transaction.rs b/sdk/src/types/block/payload/signed_transaction/transaction.rs index c1744e5b7e..4125ecbad7 100644 --- a/sdk/src/types/block/payload/signed_transaction/transaction.rs +++ b/sdk/src/types/block/payload/signed_transaction/transaction.rs @@ -181,7 +181,7 @@ impl TransactionBuilder { .map_err(Error::InvalidOutputCount)?; if let Some(protocol_parameters) = params { - verify_outputs::(&outputs, protocol_parameters)?; + verify_outputs(&outputs, protocol_parameters)?; } Ok(Transaction { @@ -328,16 +328,14 @@ impl WorkScore for Transaction { } } -fn verify_network_id(network_id: &u64, visitor: &ProtocolParameters) -> Result<(), Error> { - if VERIFY { - let expected = visitor.network_id(); +fn verify_network_id(network_id: &u64, visitor: &ProtocolParameters) -> Result<(), Error> { + let expected = visitor.network_id(); - if *network_id != expected { - return Err(Error::NetworkIdMismatch { - expected, - actual: *network_id, - }); - } + if *network_id != expected { + return Err(Error::NetworkIdMismatch { + expected, + actual: *network_id, + }); } Ok(()) @@ -356,10 +354,8 @@ fn verify_inputs(inputs: &[Input]) -> Result<(), Error> { Ok(()) } -fn verify_inputs_packable(inputs: &[Input], _visitor: &ProtocolParameters) -> Result<(), Error> { - if VERIFY { - verify_inputs(inputs)?; - } +fn verify_inputs_packable(inputs: &[Input], _visitor: &ProtocolParameters) -> Result<(), Error> { + verify_inputs(inputs)?; Ok(()) } @@ -370,48 +366,41 @@ fn verify_payload(payload: &OptionalPayload) -> Result<(), Error> { } } -fn verify_payload_packable( - payload: &OptionalPayload, - _visitor: &ProtocolParameters, -) -> Result<(), Error> { - if VERIFY { - verify_payload(payload)?; - } +fn verify_payload_packable(payload: &OptionalPayload, _visitor: &ProtocolParameters) -> Result<(), Error> { + verify_payload(payload)?; Ok(()) } -fn verify_outputs(outputs: &[Output], visitor: &ProtocolParameters) -> Result<(), Error> { - if VERIFY { - let mut amount_sum: u64 = 0; - let mut chain_ids = HashSet::new(); - - for output in outputs.iter() { - let (amount, chain_id) = match output { - Output::Basic(output) => (output.amount(), None), - Output::Account(output) => (output.amount(), Some(output.chain_id())), - Output::Anchor(output) => (output.amount(), Some(output.chain_id())), - Output::Foundry(output) => (output.amount(), Some(output.chain_id())), - Output::Nft(output) => (output.amount(), Some(output.chain_id())), - Output::Delegation(output) => (output.amount(), Some(output.chain_id())), - }; - - amount_sum = amount_sum - .checked_add(amount) - .ok_or(Error::InvalidTransactionAmountSum(amount_sum as u128 + amount as u128))?; - - // Accumulated output balance must not exceed the total supply of tokens. - if amount_sum > visitor.token_supply() { - return Err(Error::InvalidTransactionAmountSum(amount_sum as u128)); - } +fn verify_outputs(outputs: &[Output], visitor: &ProtocolParameters) -> Result<(), Error> { + let mut amount_sum: u64 = 0; + let mut chain_ids = HashSet::new(); + + for output in outputs.iter() { + let (amount, chain_id) = match output { + Output::Basic(output) => (output.amount(), None), + Output::Account(output) => (output.amount(), Some(output.chain_id())), + Output::Anchor(output) => (output.amount(), Some(output.chain_id())), + Output::Foundry(output) => (output.amount(), Some(output.chain_id())), + Output::Nft(output) => (output.amount(), Some(output.chain_id())), + Output::Delegation(output) => (output.amount(), Some(output.chain_id())), + }; + + amount_sum = amount_sum + .checked_add(amount) + .ok_or(Error::InvalidTransactionAmountSum(amount_sum as u128 + amount as u128))?; + + // Accumulated output balance must not exceed the total supply of tokens. + if amount_sum > visitor.token_supply() { + return Err(Error::InvalidTransactionAmountSum(amount_sum as u128)); + } - if let Some(chain_id) = chain_id { - if !chain_id.is_null() && !chain_ids.insert(chain_id) { - return Err(Error::DuplicateOutputChain(chain_id)); - } + if let Some(chain_id) = chain_id { + if !chain_id.is_null() && !chain_ids.insert(chain_id) { + return Err(Error::DuplicateOutputChain(chain_id)); } - - output.verify_storage_deposit(visitor.storage_score_parameters())?; } + + output.verify_storage_deposit(visitor.storage_score_parameters())?; } Ok(()) diff --git a/sdk/src/types/block/protocol/mod.rs b/sdk/src/types/block/protocol/mod.rs index c9ddae04cb..965daca212 100644 --- a/sdk/src/types/block/protocol/mod.rs +++ b/sdk/src/types/block/protocol/mod.rs @@ -1,26 +1,26 @@ // Copyright 2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +#[cfg(feature = "protocol_parameters_samples")] +mod samples; mod work_score; -use alloc::string::String; use core::borrow::Borrow; use crypto::hashes::{blake2b::Blake2b256, Digest}; use getset::{CopyGetters, Getters}; use packable::{prefix::StringPrefix, Packable, PackableExt}; +#[cfg(feature = "protocol_parameters_samples")] +pub use samples::{iota_mainnet_protocol_parameters, shimmer_mainnet_protocol_parameters}; pub use self::work_score::{WorkScore, WorkScoreParameters}; -use crate::{ - types::block::{ - address::Hrp, - helper::network_name_to_id, - mana::{ManaParameters, RewardsParameters}, - output::{StorageScore, StorageScoreParameters}, - slot::{EpochIndex, SlotCommitmentId, SlotIndex}, - Error, PROTOCOL_VERSION, - }, - utils::ConvertTo, +use crate::types::block::{ + address::Hrp, + helper::network_name_to_id, + mana::{ManaParameters, RewardsParameters}, + output::{StorageScore, StorageScoreParameters}, + slot::{EpochIndex, SlotCommitmentId, SlotIndex}, + Error, }; /// Defines the parameters of the protocol at a particular version. @@ -103,65 +103,7 @@ impl Borrow<()> for ProtocolParameters { } } -impl Default for ProtocolParameters { - fn default() -> Self { - Self { - kind: 0, - version: PROTOCOL_VERSION, - // Unwrap: Known to be valid - network_name: String::from("iota-core-testnet").try_into().unwrap(), - bech32_hrp: Hrp::from_str_unchecked("smr"), - storage_score_parameters: Default::default(), - work_score_parameters: Default::default(), - token_supply: 1_813_620_509_061_365, - genesis_slot: 0, - genesis_unix_timestamp: 1582328545, - slot_duration_in_seconds: 10, - epoch_nearing_threshold: 20, - slots_per_epoch_exponent: Default::default(), - mana_parameters: Default::default(), - staking_unbonding_period: 10, - validation_blocks_per_slot: 10, - punishment_epochs: 9, - liveness_threshold_lower_bound: 15, - liveness_threshold_upper_bound: 30, - min_committable_age: 10, - max_committable_age: 20, - congestion_control_parameters: Default::default(), - version_signaling_parameters: Default::default(), - rewards_parameters: Default::default(), - target_committee_size: 32, - chain_switching_threshold: 3, - } - } -} - impl ProtocolParameters { - /// Creates a new [`ProtocolParameters`]. - #[allow(clippy::too_many_arguments)] - pub fn new( - version: u8, - network_name: impl Into, - bech32_hrp: impl ConvertTo, - storage_score_parameters: StorageScoreParameters, - token_supply: u64, - genesis_unix_timestamp: u64, - slot_duration_in_seconds: u8, - epoch_nearing_threshold: u32, - ) -> Result { - Ok(Self { - version, - network_name: >::try_from(network_name.into()).map_err(Error::InvalidStringPrefix)?, - bech32_hrp: bech32_hrp.convert()?, - storage_score_parameters, - token_supply, - genesis_unix_timestamp, - slot_duration_in_seconds, - epoch_nearing_threshold, - ..Default::default() - }) - } - /// Returns the network name of the [`ProtocolParameters`]. pub fn network_name(&self) -> &str { &self.network_name @@ -363,38 +305,23 @@ pub struct CommittableAgeRange { pub struct CongestionControlParameters { /// Minimum value of the reference Mana cost. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] - min_reference_mana_cost: u64, + pub(crate) min_reference_mana_cost: u64, /// Increase step size of the RMC. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] - increase: u64, + pub(crate) increase: u64, /// Decrease step size of the RMC. #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde::string"))] - decrease: u64, + pub(crate) decrease: u64, /// Threshold for increasing the RMC. - increase_threshold: u32, + pub(crate) increase_threshold: u32, /// Threshold for decreasing the RMC. - decrease_threshold: u32, + pub(crate) decrease_threshold: u32, /// Rate at which the scheduler runs (in workscore units per second). - scheduler_rate: u32, + pub(crate) scheduler_rate: u32, /// Maximum size of the buffer in the scheduler. - max_buffer_size: u32, + pub(crate) max_buffer_size: u32, /// Maximum number of blocks in the validation buffer. - max_validation_buffer_size: u32, -} - -impl Default for CongestionControlParameters { - fn default() -> Self { - Self { - min_reference_mana_cost: 500, - increase: 500, - decrease: 500, - increase_threshold: 800000, - decrease_threshold: 500000, - scheduler_rate: 100000, - max_buffer_size: 3276800, - max_validation_buffer_size: 100, - } - } + pub(crate) max_validation_buffer_size: u32, } /// Defines the parameters used to signal a protocol parameters upgrade. @@ -409,37 +336,11 @@ impl Default for CongestionControlParameters { pub struct VersionSignalingParameters { /// The size of the window in epochs that is used to find which version of protocol parameters was /// most signaled, from `current_epoch - window_size` to `current_epoch`. - window_size: u8, + pub(crate) window_size: u8, /// The number of supporters required for a version to win within a `window_size`. - window_target_ratio: u8, + pub(crate) window_target_ratio: u8, /// The offset in epochs required to activate the new version of protocol parameters. - activation_offset: u8, -} - -impl Default for VersionSignalingParameters { - fn default() -> Self { - Self { - window_size: 7, - window_target_ratio: 5, - activation_offset: 7, - } - } -} - -/// Returns a [`ProtocolParameters`] for testing purposes. -#[cfg(any(feature = "test", feature = "rand"))] -pub fn protocol_parameters() -> ProtocolParameters { - ProtocolParameters::new( - 2, - "testnet", - "rms", - crate::types::block::output::StorageScoreParameters::new(500, 1, 10, 1, 1, 1), - 1_813_620_509_061_365, - 1582328545, - 10, - 20, - ) - .unwrap() + pub(crate) activation_offset: u8, } crate::impl_id!( diff --git a/sdk/src/types/block/protocol/samples.rs b/sdk/src/types/block/protocol/samples.rs new file mode 100644 index 0000000000..9fd69a67c3 --- /dev/null +++ b/sdk/src/types/block/protocol/samples.rs @@ -0,0 +1,252 @@ +// Copyright 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::OnceLock; + +use crate::types::block::{ + address::Hrp, + mana::{ManaParameters, RewardsParameters}, + output::StorageScoreParameters, + protocol::{CongestionControlParameters, ProtocolParameters, VersionSignalingParameters, WorkScoreParameters}, + PROTOCOL_VERSION, +}; + +/// Returns IOTA mainnet [`ProtocolParameters`] for testing purposes. +pub fn iota_mainnet_protocol_parameters() -> &'static ProtocolParameters { + static PARAMS: OnceLock = OnceLock::new(); + PARAMS.get_or_init(|| { + ProtocolParameters { + kind: 0, + version: PROTOCOL_VERSION, + network_name: String::from("iota-mainnet").try_into().unwrap(), + bech32_hrp: Hrp::from_str_unchecked("iota"), + storage_score_parameters: StorageScoreParameters { + storage_cost: 100, + factor_data: 1, + offset_output_overhead: 10, + offset_ed25519_block_issuer_key: 100, + offset_staking_feature: 100, + offset_delegation: 100, + }, + work_score_parameters: WorkScoreParameters { + data_byte: 1, + block: 1500, + input: 10, + context_input: 20, + output: 20, + native_token: 20, + staking: 5000, + block_issuer: 1000, + allotment: 1000, + signature_ed25519: 1000, + }, + token_supply: 1_813_620_509_061_365, + genesis_slot: 0, + #[cfg(not(target_family = "wasm"))] + genesis_unix_timestamp: time::OffsetDateTime::now_utc().unix_timestamp() as _, + #[cfg(target_family = "wasm")] + genesis_unix_timestamp: instant::SystemTime::now() + .duration_since(instant::SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), + slot_duration_in_seconds: 10, + epoch_nearing_threshold: 60, + slots_per_epoch_exponent: 13, + mana_parameters: ManaParameters { + bits_count: 63, + generation_rate: 1, + generation_rate_exponent: 17, + // Derived + decay_factors: Default::default(), + decay_factors_exponent: 32, + // Derived + decay_factor_epochs_sum: Default::default(), + decay_factor_epochs_sum_exponent: 21, + annual_decay_factor_percentage: 70, + }, + staking_unbonding_period: 10, + validation_blocks_per_slot: 10, + punishment_epochs: 10, + liveness_threshold_lower_bound: 15, + liveness_threshold_upper_bound: 30, + min_committable_age: 10, + max_committable_age: 20, + congestion_control_parameters: CongestionControlParameters { + min_reference_mana_cost: 1, + increase: 10, + decrease: 10, + increase_threshold: 800000, + decrease_threshold: 500000, + scheduler_rate: 100000, + max_buffer_size: 1000, + max_validation_buffer_size: 100, + }, + version_signaling_parameters: VersionSignalingParameters { + window_size: 7, + window_target_ratio: 5, + activation_offset: 7, + }, + rewards_parameters: RewardsParameters { + profit_margin_exponent: 8, + // Derived + bootstrapping_duration: Default::default(), + reward_to_generation_ratio: 2, + // Derived + initial_target_rewards_rate: Default::default(), + // Derived + final_target_rewards_rate: Default::default(), + pool_coefficient_exponent: 11, + retention_period: 384, + }, + target_committee_size: 32, + chain_switching_threshold: 3, + } + .with_derived_values() + }) +} + +/// Returns Shimmer mainnet [`ProtocolParameters`] for testing purposes. +pub fn shimmer_mainnet_protocol_parameters() -> &'static ProtocolParameters { + static PARAMS: OnceLock = OnceLock::new(); + PARAMS.get_or_init(|| { + ProtocolParameters { + kind: 0, + version: PROTOCOL_VERSION, + network_name: String::from("shimmer-mainnet").try_into().unwrap(), + bech32_hrp: Hrp::from_str_unchecked("smr"), + storage_score_parameters: StorageScoreParameters { + storage_cost: 100, + factor_data: 1, + offset_output_overhead: 10, + offset_ed25519_block_issuer_key: 100, + offset_staking_feature: 100, + offset_delegation: 100, + }, + work_score_parameters: WorkScoreParameters { + data_byte: 0, + block: 1, + input: 0, + context_input: 0, + output: 0, + native_token: 0, + staking: 0, + block_issuer: 0, + allotment: 0, + signature_ed25519: 0, + }, + token_supply: 1_813_620_509_061_365, + genesis_slot: 0, + #[cfg(not(target_family = "wasm"))] + genesis_unix_timestamp: time::OffsetDateTime::now_utc().unix_timestamp() as _, + #[cfg(target_family = "wasm")] + genesis_unix_timestamp: instant::SystemTime::now() + .duration_since(instant::SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), + slot_duration_in_seconds: 10, + epoch_nearing_threshold: 60, + slots_per_epoch_exponent: 13, + mana_parameters: ManaParameters { + bits_count: 63, + generation_rate: 1, + generation_rate_exponent: 17, + // Derived + decay_factors: Default::default(), + decay_factors_exponent: 32, + // Derived + decay_factor_epochs_sum: Default::default(), + decay_factor_epochs_sum_exponent: 21, + annual_decay_factor_percentage: 70, + }, + staking_unbonding_period: 10, + validation_blocks_per_slot: 10, + punishment_epochs: 10, + liveness_threshold_lower_bound: 15, + liveness_threshold_upper_bound: 30, + min_committable_age: 10, + max_committable_age: 20, + congestion_control_parameters: CongestionControlParameters { + min_reference_mana_cost: 1, + increase: 10, + decrease: 10, + increase_threshold: 800000, + decrease_threshold: 500000, + scheduler_rate: 100000, + max_buffer_size: 1000, + max_validation_buffer_size: 100, + }, + version_signaling_parameters: VersionSignalingParameters { + window_size: 7, + window_target_ratio: 5, + activation_offset: 7, + }, + rewards_parameters: RewardsParameters { + profit_margin_exponent: 8, + // Derived + bootstrapping_duration: Default::default(), + reward_to_generation_ratio: 2, + // Derived + initial_target_rewards_rate: Default::default(), + // Derived + final_target_rewards_rate: Default::default(), + pool_coefficient_exponent: 11, + retention_period: 384, + }, + target_committee_size: 32, + chain_switching_threshold: 3, + } + .with_derived_values() + }) +} + +impl ProtocolParameters { + pub(crate) fn with_derived_values(mut self) -> Self { + self.derive_mana_decay_factors(); + self.derive_mana_decay_factors_epochs_sum(); + self.derive_bootstrapping_duration(); + self.derive_target_rewards_rates(); + self + } + + pub(crate) fn derive_mana_decay_factors(&mut self) { + self.mana_parameters.decay_factors = { + let epochs_in_table = (u16::MAX as usize).min(self.epochs_per_year().floor() as usize); + let decay_per_epoch = self.decay_per_epoch(); + (1..=epochs_in_table) + .map(|epoch| { + (decay_per_epoch.powi(epoch as _) * 2f64.powi(self.mana_parameters().decay_factors_exponent() as _)) + .floor() as u32 + }) + .collect::>() + } + .try_into() + .unwrap(); + } + + pub(crate) fn derive_mana_decay_factors_epochs_sum(&mut self) { + self.mana_parameters.decay_factor_epochs_sum = { + let delta = self.epochs_per_year().recip(); + let annual_decay_factor = self.mana_parameters().annual_decay_factor(); + (annual_decay_factor.powf(delta) / (1.0 - annual_decay_factor.powf(delta)) + * (2f64.powi(self.mana_parameters().decay_factor_epochs_sum_exponent() as _))) + .floor() as _ + }; + } + + pub(crate) fn derive_bootstrapping_duration(&mut self) { + self.rewards_parameters.bootstrapping_duration = + (self.epochs_per_year() / -self.mana_parameters().annual_decay_factor().ln()).floor() as _; + } + + pub(crate) fn derive_target_rewards_rates(&mut self) { + self.rewards_parameters.final_target_rewards_rate = (self.token_supply() + * self.rewards_parameters().reward_to_generation_ratio() as u64 + * self.mana_parameters().generation_rate() as u64) + >> self.mana_parameters().generation_rate_exponent() - self.slots_per_epoch_exponent(); + let bootstrapping_duration_years = + self.rewards_parameters().bootstrapping_duration() as f64 * self.epochs_per_year().exp(); + self.rewards_parameters.initial_target_rewards_rate = (self.rewards_parameters.final_target_rewards_rate as f64 + * (self.mana_parameters().annual_decay_factor() * bootstrapping_duration_years).exp()) + .floor() as _; + } +} diff --git a/sdk/src/types/block/protocol/work_score.rs b/sdk/src/types/block/protocol/work_score.rs index fc96021a64..7010774cf2 100644 --- a/sdk/src/types/block/protocol/work_score.rs +++ b/sdk/src/types/block/protocol/work_score.rs @@ -16,42 +16,25 @@ use crate::types::block::Error; #[getset(get_copy = "pub")] pub struct WorkScoreParameters { /// Accounts for the network traffic per byte. - data_byte: u32, + pub(crate) data_byte: u32, /// Accounts for work done to process a block in the node software. - block: u32, + pub(crate) block: u32, /// Accounts for loading the UTXO from the database and performing the mana balance check. - input: u32, + pub(crate) input: u32, /// Accounts for loading and checking the context input. - context_input: u32, + pub(crate) context_input: u32, /// Accounts for storing the UTXO in the database. - output: u32, + pub(crate) output: u32, /// Accounts for native token balance checks which use big integers. - native_token: u32, + pub(crate) native_token: u32, /// Accounts for the cost of updating the staking vector when a staking feature is present. - staking: u32, + pub(crate) staking: u32, /// Accounts for the cost of updating the block issuer keys when a block issuer feature is present. - block_issuer: u32, + pub(crate) block_issuer: u32, /// Accounts for accessing the account based ledger to transform the allotted mana to block issuance credits. - allotment: u32, + pub(crate) allotment: u32, /// Accounts for an Ed25519 signature check. - signature_ed25519: u32, -} - -impl Default for WorkScoreParameters { - fn default() -> Self { - Self { - data_byte: 0, - block: 100, - input: 20, - context_input: 20, - output: 20, - native_token: 20, - staking: 100, - block_issuer: 100, - allotment: 100, - signature_ed25519: 200, - } - } + pub(crate) signature_ed25519: u32, } /// A trait to facilitate the computation of the work score of a block, which is central to mana cost calculation. diff --git a/sdk/src/types/block/signature/ed25519.rs b/sdk/src/types/block/signature/ed25519.rs index b27a628416..a0135b04d6 100644 --- a/sdk/src/types/block/signature/ed25519.rs +++ b/sdk/src/types/block/signature/ed25519.rs @@ -152,12 +152,12 @@ impl Packable for Ed25519Signature { Ok(()) } - fn unpack( + fn unpack( unpacker: &mut U, - visitor: &Self::UnpackVisitor, + visitor: Option<&Self::UnpackVisitor>, ) -> Result> { - let public_key = <[u8; Self::PUBLIC_KEY_LENGTH]>::unpack::<_, VERIFY>(unpacker, visitor).coerce()?; - let signature = <[u8; Self::SIGNATURE_LENGTH]>::unpack::<_, VERIFY>(unpacker, visitor).coerce()?; + let public_key = <[u8; Self::PUBLIC_KEY_LENGTH]>::unpack(unpacker, visitor).coerce()?; + let signature = <[u8; Self::SIGNATURE_LENGTH]>::unpack(unpacker, visitor).coerce()?; Ok(Self::from_bytes(public_key, signature)) } diff --git a/sdk/src/types/block/slot/epoch.rs b/sdk/src/types/block/slot/epoch.rs index 8fa9427457..d50d7988cb 100644 --- a/sdk/src/types/block/slot/epoch.rs +++ b/sdk/src/types/block/slot/epoch.rs @@ -141,20 +141,17 @@ impl core::ops::SubAssign for EpochIndex { } } -#[cfg(test)] +#[cfg(all(test, feature = "protocol_parameters_samples"))] mod test { use pretty_assertions::assert_eq; use super::*; - use crate::types::block::protocol::ProtocolParameters; + use crate::types::block::protocol::iota_mainnet_protocol_parameters; #[test] fn epoch_index_to_from_slot() { - let params = ProtocolParameters { - version: 3, - slots_per_epoch_exponent: 10, - ..Default::default() - }; + let mut params = iota_mainnet_protocol_parameters().clone(); + params.slots_per_epoch_exponent = 10; let slot_index = SlotIndex(3000); let epoch_index = EpochIndex::from_slot_index(slot_index, params.genesis_slot, params.slots_per_epoch_exponent()); diff --git a/sdk/src/types/block/slot/index.rs b/sdk/src/types/block/slot/index.rs index ad4c7ce496..5b705abe4e 100644 --- a/sdk/src/types/block/slot/index.rs +++ b/sdk/src/types/block/slot/index.rs @@ -124,15 +124,15 @@ impl From for u32 { } } -#[cfg(test)] +#[cfg(all(test, feature = "protocol_parameters_samples"))] mod test { use pretty_assertions::assert_eq; - use crate::types::block::protocol::ProtocolParameters; + use crate::types::block::protocol::iota_mainnet_protocol_parameters; #[test] fn to_from_timestamp() { - let protocol_params = ProtocolParameters::default(); + let protocol_params = iota_mainnet_protocol_parameters(); // Timestamp before the genesis let timestamp = protocol_params.genesis_unix_timestamp() - 100; diff --git a/sdk/src/types/block/unlock/mod.rs b/sdk/src/types/block/unlock/mod.rs index 7e5f791ba9..eaefc34fe2 100644 --- a/sdk/src/types/block/unlock/mod.rs +++ b/sdk/src/types/block/unlock/mod.rs @@ -132,7 +132,7 @@ impl Unlocks { let unlocks: BoxedSlicePrefix = unlocks.into().try_into().map_err(Error::InvalidUnlockCount)?; - verify_unlocks::(&unlocks)?; + verify_unlocks(&unlocks)?; Ok(Self(unlocks)) } @@ -192,19 +192,17 @@ fn verify_non_multi_unlock<'a>( Ok(()) } -fn verify_unlocks(unlocks: &[Unlock]) -> Result<(), Error> { - if VERIFY { - let mut seen_signatures = HashSet::new(); +fn verify_unlocks(unlocks: &[Unlock]) -> Result<(), Error> { + let mut seen_signatures = HashSet::new(); - for (index, unlock) in (0u16..).zip(unlocks.iter()) { - match unlock { - Unlock::Multi(multi) => { - for unlock in multi.unlocks() { - verify_non_multi_unlock(unlocks, unlock, index, &mut seen_signatures)? - } + for (index, unlock) in (0u16..).zip(unlocks.iter()) { + match unlock { + Unlock::Multi(multi) => { + for unlock in multi.unlocks() { + verify_non_multi_unlock(unlocks, unlock, index, &mut seen_signatures)? } - _ => verify_non_multi_unlock(unlocks, unlock, index, &mut seen_signatures)?, } + _ => verify_non_multi_unlock(unlocks, unlock, index, &mut seen_signatures)?, } } diff --git a/sdk/src/types/block/unlock/multi.rs b/sdk/src/types/block/unlock/multi.rs index 9d47ca22ce..4f455fec0b 100644 --- a/sdk/src/types/block/unlock/multi.rs +++ b/sdk/src/types/block/unlock/multi.rs @@ -29,7 +29,7 @@ impl MultiUnlock { pub fn new(unlocks: impl IntoIterator) -> Result { let unlocks = unlocks.into_iter().collect::>(); - verify_unlocks::(&unlocks)?; + verify_unlocks(&unlocks)?; Ok(Self( BoxedSlicePrefix::::try_from(unlocks).map_err(Error::InvalidMultiUnlockCount)?, @@ -49,8 +49,8 @@ impl WorkScore for MultiUnlock { } } -fn verify_unlocks(unlocks: &[Unlock]) -> Result<(), Error> { - if VERIFY && unlocks.iter().any(Unlock::is_multi) { +fn verify_unlocks(unlocks: &[Unlock]) -> Result<(), Error> { + if unlocks.iter().any(Unlock::is_multi) { Err(Error::MultiUnlockRecursion) } else { Ok(()) diff --git a/sdk/src/types/fuzz/Cargo.toml b/sdk/src/types/fuzz/Cargo.toml index 1d084a0ec6..7c538a8487 100644 --- a/sdk/src/types/fuzz/Cargo.toml +++ b/sdk/src/types/fuzz/Cargo.toml @@ -12,7 +12,9 @@ cargo-fuzz = true iota-types = { path = "..", default-features = false } libfuzzer-sys = { version = "0.4.7", default-features = false } -packable = { version = "0.10.1", default-features = false } +packable = { version = "0.11.0", default-features = false, features = [ + "primitive-types", +] } # Prevent this from interfering with workspaces [workspace] diff --git a/sdk/src/wallet/core/builder.rs b/sdk/src/wallet/core/builder.rs index 7ad9f10fc6..4d32e19c00 100644 --- a/sdk/src/wallet/core/builder.rs +++ b/sdk/src/wallet/core/builder.rs @@ -284,7 +284,7 @@ where let wallet_ledger = WalletLedger::default(); let wallet = Wallet { - // Panic: it's invalid to build a wallet without an address. + // Unwrap: The address is always set above (or we already returned) address: Arc::new(RwLock::new(self.address.unwrap())), bip_path: Arc::new(RwLock::new(self.bip_path)), alias: Arc::new(RwLock::new(self.alias)), diff --git a/sdk/src/wallet/core/mod.rs b/sdk/src/wallet/core/mod.rs index 30414fb3da..5720fe33fe 100644 --- a/sdk/src/wallet/core/mod.rs +++ b/sdk/src/wallet/core/mod.rs @@ -559,7 +559,7 @@ impl From<&WalletLedger> for WalletLedgerDto { } } -#[cfg(test)] +#[cfg(all(test, feature = "protocol_parameters_samples"))] mod test { use core::str::FromStr; @@ -570,9 +570,9 @@ mod test { types::block::{ address::{Address, Ed25519Address}, input::{Input, UtxoInput}, - output::{AddressUnlockCondition, BasicOutput, Output, StorageScoreParameters}, + output::{AddressUnlockCondition, BasicOutput, Output}, payload::signed_transaction::{SignedTransactionPayload, Transaction, TransactionId}, - protocol::ProtocolParameters, + protocol::iota_mainnet_protocol_parameters, rand::mana::rand_mana_allotment, signature::{Ed25519Signature, Signature}, unlock::{ReferenceUnlock, SignatureUnlock, Unlock, Unlocks}, @@ -587,17 +587,7 @@ mod test { #[test] fn serialize() { - let protocol_parameters = ProtocolParameters::new( - 2, - "testnet", - "rms", - StorageScoreParameters::new(500, 1, 10, 1, 1, 1), - 1_813_620_509_061_365, - 1582328545, - 10, - 20, - ) - .unwrap(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); @@ -614,8 +604,8 @@ mod test { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs([input1, input2]) .add_output(output) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters) + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters) .unwrap(); let pub_key_bytes = prefix_hex::decode(ED25519_PUBLIC_KEY).unwrap(); diff --git a/sdk/src/wallet/core/operations/client.rs b/sdk/src/wallet/core/operations/client.rs index 2f6d513b10..02ebe7a56b 100644 --- a/sdk/src/wallet/core/operations/client.rs +++ b/sdk/src/wallet/core/operations/client.rs @@ -13,7 +13,7 @@ use crate::{ node::{Node, NodeAuth, NodeDto}, }, secret::SecretManage, - Client, ClientBuilder, + Client, ClientBuilder, NetworkInfo, }, wallet::{Wallet, WalletBuilder}, }; @@ -39,7 +39,7 @@ where node_manager_builder, #[cfg(feature = "mqtt")] broker_options, - mut network_info, + protocol_parameters, api_timeout, #[cfg(not(target_family = "wasm"))] max_parallel_api_requests, @@ -60,12 +60,19 @@ where } if change_in_node_manager { - // Update the protocol of the network_info to not have the default data, which can be wrong - // Ignore errors, because there might be no node at all and then it should still not error if let Ok(info) = self.client.get_info().await { - network_info.protocol_parameters = info.node_info.latest_protocol_parameters().parameters.clone(); + let params = &info.node_info.latest_protocol_parameters().parameters; + + *self.client.network_info.write().await = NetworkInfo { + protocol_parameters: params.clone(), + tangle_time: info.node_info.status.relative_accepted_tangle_time, + }; + } else if let Some(protocol_parameters) = protocol_parameters { + *self.client.network_info.write().await = NetworkInfo { + protocol_parameters, + tangle_time: None, + }; } - *self.client.network_info.write().await = network_info; self.update_address_hrp().await?; } diff --git a/sdk/src/wallet/operations/transaction/mod.rs b/sdk/src/wallet/operations/transaction/mod.rs index 57688f25f2..36adc8e521 100644 --- a/sdk/src/wallet/operations/transaction/mod.rs +++ b/sdk/src/wallet/operations/transaction/mod.rs @@ -11,6 +11,8 @@ mod sign_transaction; pub(crate) mod submit_transaction; pub use self::options::{RemainderValueStrategy, TransactionOptions}; +#[cfg(feature = "storage")] +use crate::wallet::core::WalletLedgerDto; use crate::{ client::{ api::{verify_semantic, PreparedTransactionData, SignedTransactionData}, @@ -22,7 +24,6 @@ use crate::{ block::{output::Output, payload::signed_transaction::SignedTransactionPayload}, }, wallet::{ - core::WalletLedgerDto, types::{InclusionState, TransactionWithMetadata}, Wallet, }, diff --git a/sdk/src/wallet/types/balance.rs b/sdk/src/wallet/types/balance.rs index facdc4e150..3a7ffe686f 100644 --- a/sdk/src/wallet/types/balance.rs +++ b/sdk/src/wallet/types/balance.rs @@ -139,14 +139,14 @@ impl std::ops::AddAssign for NativeTokensBalance { } } -#[cfg(feature = "rand")] +#[cfg(all(feature = "rand", feature = "protocol_parameters_samples"))] impl Balance { pub fn rand() -> Self { use rand::Rng; use crate::types::block::rand::bytes::rand_bytes_array; - let token_supply = crate::types::block::protocol::protocol_parameters().token_supply(); + let token_supply = crate::types::block::protocol::iota_mainnet_protocol_parameters().token_supply(); let total = rand::thread_rng().gen_range(128..token_supply / 1000000); let mut generator = 0u8; diff --git a/sdk/src/wallet/update.rs b/sdk/src/wallet/update.rs index 7ea338e679..cdcb0b55f0 100644 --- a/sdk/src/wallet/update.rs +++ b/sdk/src/wallet/update.rs @@ -3,6 +3,8 @@ use std::collections::HashMap; +#[cfg(feature = "storage")] +use crate::wallet::core::WalletLedgerDto; use crate::{ client::secret::SecretManage, types::block::{ @@ -10,7 +12,6 @@ use crate::{ payload::signed_transaction::TransactionId, }, wallet::{ - core::WalletLedgerDto, types::{InclusionState, OutputData, TransactionWithMetadata}, Wallet, }, diff --git a/sdk/tests/client/addresses.rs b/sdk/tests/client/addresses.rs index 33515fe33d..bba7ad2540 100644 --- a/sdk/tests/client/addresses.rs +++ b/sdk/tests/client/addresses.rs @@ -13,7 +13,10 @@ use iota_sdk::{ secret::{GenerateAddressOptions, SecretManager}, Client, Result, }, - types::block::address::{Address, Hrp}, + types::block::{ + address::{Address, Hrp}, + protocol::iota_mainnet_protocol_parameters, + }, }; use pretty_assertions::assert_eq; use serde::{Deserialize, Serialize}; @@ -62,7 +65,11 @@ async fn evm_addresses() { #[tokio::test] async fn public_key_to_address() { - let client = Client::builder().finish().await.unwrap(); + let client = Client::builder() + .with_protocol_parameters(iota_mainnet_protocol_parameters().clone()) + .finish() + .await + .unwrap(); let hex_public_key = "0x2baaf3bca8ace9f862e60184bd3e79df25ff230f7eaaa4c7f03daa9833ba854a"; let public_key_address = client @@ -252,7 +259,11 @@ async fn address_generation() { #[tokio::test] async fn search_address() -> Result<()> { - let client = Client::builder().finish().await.unwrap(); + let client = Client::builder() + .with_protocol_parameters(iota_mainnet_protocol_parameters().clone()) + .finish() + .await + .unwrap(); let secret_manager = SecretManager::try_from_mnemonic(generate_mnemonic()?)?; diff --git a/sdk/tests/client/client_builder.rs b/sdk/tests/client/client_builder.rs index b5f7853e87..c92f8795f4 100644 --- a/sdk/tests/client/client_builder.rs +++ b/sdk/tests/client/client_builder.rs @@ -3,7 +3,7 @@ use iota_sdk::{ client::{Client, ClientBuilder}, - types::block::protocol::ProtocolParameters, + types::block::protocol::iota_mainnet_protocol_parameters, }; #[tokio::test] @@ -36,7 +36,7 @@ async fn client_builder() { "minQuorumSize": 3, "quorumThreshold": 66, "userAgent": "iota-client/2.0.1-rc.3", - "protocolParameters": ProtocolParameters::default(), + "protocolParameters": iota_mainnet_protocol_parameters(), "apiTimeout": { "secs": 15, "nanos": 0 diff --git a/sdk/tests/client/input_selection/account_outputs.rs b/sdk/tests/client/input_selection/account_outputs.rs index fbaa444e85..56cce3ee6e 100644 --- a/sdk/tests/client/input_selection/account_outputs.rs +++ b/sdk/tests/client/input_selection/account_outputs.rs @@ -15,14 +15,14 @@ use iota_sdk::{ feature::SenderFeature, unlock_condition::AddressUnlockCondition, AccountId, AccountOutputBuilder, BasicOutputBuilder, Output, }, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::output::{rand_output_id_with_slot_index, rand_output_metadata_with_id}, }, }; use pretty_assertions::{assert_eq, assert_ne}; use crate::client::{ - build_inputs, build_outputs, is_remainder_or_return, unsorted_eq, + assert_remainder_or_return, build_inputs, build_outputs, unsorted_eq, Build::{Account, Basic}, ACCOUNT_ID_0, ACCOUNT_ID_1, ACCOUNT_ID_2, BECH32_ADDRESS_ACCOUNT_1, BECH32_ADDRESS_ED25519_0, BECH32_ADDRESS_ED25519_1, BECH32_ADDRESS_NFT_1, SLOT_COMMITMENT_ID, SLOT_INDEX, @@ -30,7 +30,7 @@ use crate::client::{ #[test] fn input_account_eq_output_account() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -71,7 +71,7 @@ fn input_account_eq_output_account() { #[test] fn transition_account_id_zero() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( @@ -113,7 +113,7 @@ fn transition_account_id_zero() { // #[test] // fn input_amount_lt_output_amount() { -// let protocol_parameters = protocol_parameters(); +// let protocol_parameters = iota_mainnet_protocol_parameters().clone(); // let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); // let inputs = build_inputs([Account( @@ -158,7 +158,7 @@ fn transition_account_id_zero() { // #[test] // fn input_amount_lt_output_amount_2() { -// let protocol_parameters = protocol_parameters(); +// let protocol_parameters = iota_mainnet_protocol_parameters().clone(); // let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); // let inputs = build_inputs([ @@ -206,7 +206,7 @@ fn transition_account_id_zero() { // #[test] // fn basic_output_with_account_input() { -// let protocol_parameters = protocol_parameters(); +// let protocol_parameters = iota_mainnet_protocol_parameters().clone(); // let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); // let inputs = build_inputs([Account( @@ -247,7 +247,7 @@ fn transition_account_id_zero() { #[test] fn create_account() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( @@ -299,7 +299,7 @@ fn create_account() { #[test] fn burn_account() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -343,7 +343,7 @@ fn burn_account() { // #[test] // fn not_enough_storage_deposit_for_remainder() { -// let protocol_parameters = protocol_parameters(); +// let protocol_parameters = iota_mainnet_protocol_parameters().clone(); // let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); // let inputs = build_inputs([Account( @@ -388,7 +388,7 @@ fn burn_account() { #[test] fn missing_input_for_account_output() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -432,7 +432,7 @@ fn missing_input_for_account_output() { #[test] fn missing_input_for_account_output_2() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); @@ -489,7 +489,7 @@ fn missing_input_for_account_output_2() { #[test] fn missing_input_for_account_output_but_created() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( @@ -530,7 +530,7 @@ fn missing_input_for_account_output_but_created() { #[test] fn account_in_output_and_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -591,7 +591,7 @@ fn account_in_output_and_sender() { #[test] fn missing_ed25519_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -633,7 +633,7 @@ fn missing_ed25519_sender() { #[test] fn missing_ed25519_issuer_created() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( @@ -677,7 +677,7 @@ fn missing_ed25519_issuer_created() { #[test] fn missing_ed25519_issuer_transition() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -716,7 +716,7 @@ fn missing_ed25519_issuer_transition() { #[test] fn missing_account_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -758,7 +758,7 @@ fn missing_account_sender() { #[test] fn missing_account_issuer_created() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( @@ -802,7 +802,7 @@ fn missing_account_issuer_created() { #[test] fn missing_account_issuer_transition() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -841,7 +841,7 @@ fn missing_account_issuer_transition() { #[test] fn missing_nft_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -883,7 +883,7 @@ fn missing_nft_sender() { #[test] fn missing_nft_issuer_created() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( @@ -927,7 +927,7 @@ fn missing_nft_issuer_created() { #[test] fn missing_nft_issuer_transition() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -966,7 +966,7 @@ fn missing_nft_issuer_transition() { #[test] fn increase_account_amount() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1021,7 +1021,7 @@ fn increase_account_amount() { #[test] fn decrease_account_amount() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1076,19 +1076,19 @@ fn decrease_account_amount() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ); } }); } #[test] fn prefer_basic_to_account() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1146,7 +1146,7 @@ fn prefer_basic_to_account() { #[test] fn take_amount_from_account_to_fund_basic() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1218,7 +1218,7 @@ fn take_amount_from_account_to_fund_basic() { #[test] fn account_burn_should_validate_account_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1276,19 +1276,19 @@ fn account_burn_should_validate_account_sender() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ) } }); } #[test] fn account_burn_should_validate_account_address() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1346,19 +1346,19 @@ fn account_burn_should_validate_account_address() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ) } }); } #[test] fn transitioned_zero_account_id_no_longer_is_zero() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( @@ -1416,7 +1416,7 @@ fn transitioned_zero_account_id_no_longer_is_zero() { #[test] fn two_accounts_required() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); @@ -1495,7 +1495,7 @@ fn two_accounts_required() { #[test] fn state_controller_sender_required() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1539,7 +1539,7 @@ fn state_controller_sender_required() { #[test] fn state_controller_sender_required_already_selected() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1592,7 +1592,7 @@ fn state_controller_sender_required_already_selected() { #[test] fn state_transition_and_required() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1634,7 +1634,7 @@ fn state_transition_and_required() { #[test] fn remainder_address_in_state_controller() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1674,23 +1674,24 @@ fn remainder_address_in_state_controller() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ) } }); } #[test] fn min_allot_account_mana() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let mut inputs = Vec::new(); let mana_input_amount = 1_000_000; + let required_allotment = 7864; let account_output = AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) .add_unlock_condition(AddressUnlockCondition::new( @@ -1723,7 +1724,7 @@ fn min_allot_account_mana() { SLOT_COMMITMENT_ID, protocol_parameters, ) - .with_min_mana_allotment(account_id_1, 500) + .with_min_mana_allotment(account_id_1, 2) .select() .unwrap(); @@ -1731,26 +1732,25 @@ fn min_allot_account_mana() { assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); assert_eq!(selected.transaction.allotments().len(), 1); - let mana_cost = 230_000; assert_eq!( selected.transaction.allotments()[0], - ManaAllotment::new(account_id_1, mana_cost).unwrap() + ManaAllotment::new(account_id_1, required_allotment).unwrap() ); assert_eq!( selected.transaction.outputs()[1].as_account().mana(), - mana_input_amount - mana_cost + mana_input_amount - required_allotment ); } #[test] fn min_allot_account_mana_additional() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); - let additional_allotment = 1000; - let txn_required_mana_allotment = 240_000; + let provided_allotment = 1000; + let required_allotment = 7968; // The account does not have enough to cover the requirement - let account_mana = txn_required_mana_allotment - 100; + let account_mana = required_allotment - 100; // But there is additional available mana elsewhere let additional_available_mana = 111; @@ -1797,8 +1797,8 @@ fn min_allot_account_mana_additional() { SLOT_COMMITMENT_ID, protocol_parameters, ) - .with_min_mana_allotment(account_id_1, 500) - .with_mana_allotments(Some((account_id_1, additional_allotment))) + .with_min_mana_allotment(account_id_1, 2) + .with_mana_allotments(Some((account_id_1, provided_allotment))) .select() .unwrap(); @@ -1809,84 +1809,86 @@ fn min_allot_account_mana_additional() { assert_eq!(selected.transaction.allotments().len(), 1); assert_eq!( selected.transaction.allotments()[0], - ManaAllotment::new(account_id_1, txn_required_mana_allotment).unwrap() + ManaAllotment::new(account_id_1, required_allotment).unwrap() ); assert_eq!( selected.transaction.outputs().iter().map(|o| o.mana()).sum::(), - account_mana + additional_available_mana - txn_required_mana_allotment + account_mana + additional_available_mana - required_allotment ); } -#[test] -fn min_allot_account_mana_cannot_select_additional() { - let protocol_parameters = protocol_parameters(); - let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); - let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); - - let additional_allotment = 1000; - let txn_required_mana_allotment = 271_000; - // The account does not have enough to cover the requirement - let account_mana = txn_required_mana_allotment - 100; - // But there is additional available mana elsewhere - let additional_available_mana = additional_allotment + 111; +// #[test] +// fn min_allot_account_mana_cannot_select_additional() { +// let protocol_parameters = iota_mainnet_protocol_parameters().clone(); +// let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); +// let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); - let inputs = [ - AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) - .add_unlock_condition(AddressUnlockCondition::new( - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - )) - .with_mana(account_mana) - .finish_output() - .unwrap(), - BasicOutputBuilder::new_with_minimum_amount(protocol_parameters.storage_score_parameters()) - .with_mana(additional_available_mana) - .add_unlock_condition(AddressUnlockCondition::new( - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - )) - .finish_output() - .unwrap(), - ]; - let inputs = inputs - .into_iter() - .map(|input| InputSigningData { - output: input, - output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), - chain: None, - }) - .collect::>(); +// let provided_allotment = 1000; +// let required_allotment = 7968; +// // The account does not have enough to cover the requirement +// let account_mana = required_allotment - 100; +// // But there is additional available mana elsewhere +// let additional_available_mana = 111; + +// let inputs = [ +// AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) +// .add_unlock_condition(AddressUnlockCondition::new( +// Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), +// )) +// .with_mana(account_mana) +// .finish_output() +// .unwrap(), +// BasicOutputBuilder::new_with_minimum_amount(protocol_parameters.storage_score_parameters()) +// .add_unlock_condition(AddressUnlockCondition::new( +// Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), +// )) +// .with_mana(additional_available_mana) +// .finish_output() +// .unwrap(), +// ]; +// let inputs = inputs +// .into_iter() +// .map(|input| InputSigningData { +// output: input, +// output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), +// chain: None, +// }) +// .collect::>(); - let selected = InputSelection::new( - inputs.clone(), - None, - [Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()], - SLOT_INDEX, - SLOT_COMMITMENT_ID, - protocol_parameters, - ) - .with_min_mana_allotment(account_id_1, 500) - .with_mana_allotments(Some((account_id_2, additional_allotment))) - .with_required_inputs([*inputs[0].output_id()]) - .disable_additional_input_selection() - .select() - .unwrap_err(); +// let selected = InputSelection::new( +// inputs.clone(), +// None, +// [Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()], +// SLOT_INDEX, +// SLOT_COMMITMENT_ID, +// protocol_parameters, +// ) +// .with_min_mana_allotment(account_id_1, 2) +// .with_mana_allotments(Some((account_id_2, provided_allotment))) +// .with_required_inputs([*inputs[0].output_id()]) +// .disable_additional_input_selection() +// .select() +// .unwrap_err(); - assert!( - matches!(selected, Error::AdditionalInputsRequired(_)), - "expected AdditionalInputsRequired, found {selected:?}" - ); -} +// assert!( +// matches!(selected, Error::AdditionalInputsRequired(_)), +// "expected AdditionalInputsRequired, found {selected:?}" +// ); +// } #[test] fn min_allot_account_mana_requirement_twice() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); + let required_allotment = 7968; + let inputs = [ AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) - .with_mana(1000) + .with_mana(required_allotment) .finish_output() .unwrap(), BasicOutputBuilder::new_with_amount(1_000_000) @@ -1932,34 +1934,34 @@ fn min_allot_account_mana_requirement_twice() { assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); assert_eq!(selected.transaction.allotments().len(), 1); - let mana_cost = 960; assert_eq!( selected.transaction.allotments()[0], - ManaAllotment::new(account_id_1, mana_cost).unwrap() + ManaAllotment::new(account_id_1, required_allotment).unwrap() ); - assert_eq!(selected.transaction.outputs()[1].as_account().mana(), 140); + assert_eq!(selected.transaction.outputs()[1].as_account().mana(), 100); } #[test] fn min_allot_account_mana_requirement_covered() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); - let additional_allotment = 1100; + let additional_allotment = 100; + let required_allotment = 7968; let inputs = [ AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) - .with_mana(1000) + .with_mana(required_allotment - 100) .finish_output() .unwrap(), BasicOutputBuilder::new_with_amount(1_000_000) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) - .with_mana(100) + .with_mana(additional_allotment + 100) .finish_output() .unwrap(), ]; @@ -1991,7 +1993,7 @@ fn min_allot_account_mana_requirement_covered() { protocol_parameters, ) .with_min_mana_allotment(account_id_1, 2) - .with_mana_allotments(Some((account_id_1, additional_allotment))) + .with_mana_allotments(Some((account_id_1, required_allotment + additional_allotment))) .select() .unwrap(); @@ -2001,31 +2003,32 @@ fn min_allot_account_mana_requirement_covered() { assert_eq!(selected.transaction.allotments().len(), 1); assert_eq!( selected.transaction.allotments()[0], - ManaAllotment::new(account_id_1, additional_allotment).unwrap() + ManaAllotment::new(account_id_1, required_allotment + additional_allotment).unwrap() ); assert_eq!(selected.transaction.outputs()[1].as_account().mana(), 0); } #[test] fn min_allot_account_mana_requirement_covered_2() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); - let additional_allotment = 1100; + let additional_allotment = 100; + let required_allotment = 7968; let inputs = [ AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) - .with_mana(100) + .with_mana(additional_allotment + 100) .finish_output() .unwrap(), BasicOutputBuilder::new_with_amount(1_000_000) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) - .with_mana(1000) + .with_mana(required_allotment - 100) .finish_output() .unwrap(), ]; @@ -2057,7 +2060,7 @@ fn min_allot_account_mana_requirement_covered_2() { protocol_parameters, ) .with_min_mana_allotment(account_id_1, 2) - .with_mana_allotments(Some((account_id_1, additional_allotment))) + .with_mana_allotments(Some((account_id_1, required_allotment + additional_allotment))) .select() .unwrap(); @@ -2067,14 +2070,14 @@ fn min_allot_account_mana_requirement_covered_2() { assert_eq!(selected.transaction.allotments().len(), 1); assert_eq!( selected.transaction.allotments()[0], - ManaAllotment::new(account_id_1, additional_allotment).unwrap() + ManaAllotment::new(account_id_1, required_allotment + additional_allotment).unwrap() ); assert_eq!(selected.transaction.outputs()[1].as_account().mana(), 0); } #[test] fn implicit_account_transition() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = [BasicOutputBuilder::new_with_amount(1_000_000) @@ -2083,7 +2086,7 @@ fn implicit_account_transition() { **Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap().as_ed25519(), ), ))) - .with_mana(961) + .with_mana(7871) .finish_output() .unwrap()]; let inputs = inputs @@ -2125,7 +2128,7 @@ fn implicit_account_transition() { assert_eq!(selected.transaction.allotments().len(), 1); assert_eq!( selected.transaction.allotments()[0], - ManaAllotment::new(account_id_1, 960).unwrap() + ManaAllotment::new(account_id_1, 7870).unwrap() ); // One remainder Mana assert_eq!(selected.transaction.outputs()[0].mana(), 1); diff --git a/sdk/tests/client/input_selection/basic_outputs.rs b/sdk/tests/client/input_selection/basic_outputs.rs index 6958ee4b13..7b468b4786 100644 --- a/sdk/tests/client/input_selection/basic_outputs.rs +++ b/sdk/tests/client/input_selection/basic_outputs.rs @@ -12,14 +12,14 @@ use iota_sdk::{ address::{Address, AddressCapabilities, MultiAddress, RestrictedAddress, WeightedAddress}, mana::ManaAllotment, output::{unlock_condition::AddressUnlockCondition, AccountId, BasicOutputBuilder, NftId}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::output::{rand_output_id_with_slot_index, rand_output_metadata_with_id}, }, }; use pretty_assertions::assert_eq; use crate::client::{ - build_inputs, build_outputs, is_remainder_or_return, unsorted_eq, + assert_remainder_or_return, build_inputs, build_outputs, unsorted_eq, Build::{Account, Basic, Nft}, ACCOUNT_ID_0, ACCOUNT_ID_1, BECH32_ADDRESS_ACCOUNT_1, BECH32_ADDRESS_ED25519_0, BECH32_ADDRESS_ED25519_1, BECH32_ADDRESS_ED25519_2, BECH32_ADDRESS_NFT_1, BECH32_ADDRESS_REMAINDER, NFT_ID_0, NFT_ID_1, SLOT_COMMITMENT_ID, @@ -28,7 +28,7 @@ use crate::client::{ #[test] fn input_amount_equal_output_amount() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -72,7 +72,7 @@ fn input_amount_equal_output_amount() { #[test] fn input_amount_lower_than_output_amount() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -120,7 +120,7 @@ fn input_amount_lower_than_output_amount() { #[test] fn input_amount_lower_than_output_amount_2() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -182,7 +182,7 @@ fn input_amount_lower_than_output_amount_2() { #[test] fn input_amount_greater_than_output_amount() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -226,19 +226,19 @@ fn input_amount_greater_than_output_amount() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } }); } #[test] fn input_amount_greater_than_output_amount_with_remainder_address() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let remainder_address = Address::try_from_bech32(BECH32_ADDRESS_REMAINDER).unwrap(); let inputs = build_inputs( @@ -284,19 +284,19 @@ fn input_amount_greater_than_output_amount_with_remainder_address() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_500_000, Address::try_from_bech32(BECH32_ADDRESS_REMAINDER).unwrap(), None, - )); + ); } }); } #[test] fn two_same_inputs_one_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -355,19 +355,19 @@ fn two_same_inputs_one_needed() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } }); } #[test] fn two_inputs_one_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -425,7 +425,7 @@ fn two_inputs_one_needed() { #[test] fn two_inputs_one_needed_reversed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -483,7 +483,7 @@ fn two_inputs_one_needed_reversed() { #[test] fn two_inputs_both_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -541,7 +541,7 @@ fn two_inputs_both_needed() { #[test] fn two_inputs_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -599,12 +599,12 @@ fn two_inputs_remainder() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ); } }); } @@ -653,7 +653,7 @@ fn two_inputs_remainder() { #[test] fn ed25519_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let sender = Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(); let inputs = build_inputs( @@ -759,7 +759,7 @@ fn ed25519_sender() { #[test] fn missing_ed25519_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -804,7 +804,7 @@ fn missing_ed25519_sender() { #[test] fn account_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -906,7 +906,7 @@ fn account_sender() { #[test] fn account_sender_zero_id() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( @@ -971,7 +971,7 @@ fn account_sender_zero_id() { #[test] fn missing_account_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -1016,7 +1016,7 @@ fn missing_account_sender() { #[test] fn nft_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -1121,7 +1121,7 @@ fn nft_sender() { #[test] fn nft_sender_zero_id() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( @@ -1188,7 +1188,7 @@ fn nft_sender_zero_id() { #[test] fn missing_nft_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -1233,7 +1233,7 @@ fn missing_nft_sender() { #[test] fn simple_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -1276,12 +1276,12 @@ fn simple_remainder() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ); } }); } @@ -1368,7 +1368,7 @@ fn simple_remainder() { #[test] fn one_provided_one_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -1412,7 +1412,7 @@ fn one_provided_one_needed() { #[test] fn insufficient_amount() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -1460,7 +1460,7 @@ fn insufficient_amount() { #[test] fn two_inputs_remainder_2() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1518,19 +1518,19 @@ fn two_inputs_remainder_2() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ); } }); } #[test] fn two_inputs_remainder_3() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1587,12 +1587,12 @@ fn two_inputs_remainder_3() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_250_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ); } }); } @@ -1639,7 +1639,7 @@ fn two_inputs_remainder_3() { #[test] fn sender_already_selected() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -1687,7 +1687,7 @@ fn sender_already_selected() { #[test] fn single_mandatory_input() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -1735,7 +1735,7 @@ fn single_mandatory_input() { #[test] fn too_many_inputs() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); // 129 inputs that would be required for the amount, but that's above max inputs let inputs = build_inputs( @@ -1784,7 +1784,7 @@ fn too_many_inputs() { #[test] fn more_than_max_inputs_only_one_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); // 1000 inputs where 129 would be needed for the required amount which is above the max inputs let mut inputs = build_inputs( @@ -1850,7 +1850,7 @@ fn more_than_max_inputs_only_one_needed() { #[test] fn too_many_outputs() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -1898,7 +1898,7 @@ fn too_many_outputs() { #[test] fn too_many_outputs_with_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -1948,7 +1948,7 @@ fn too_many_outputs_with_remainder() { #[test] fn restricted_ed25519() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let address = Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(); let restricted = Address::from(RestrictedAddress::new(address.clone()).unwrap()); @@ -2045,7 +2045,7 @@ fn restricted_ed25519() { #[test] fn restricted_nft() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let nft_address = Address::from(nft_id_1); let restricted = Address::from(RestrictedAddress::new(nft_address.clone()).unwrap()); @@ -2107,7 +2107,7 @@ fn restricted_nft() { #[test] fn restricted_account() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let account_address = Address::from(account_id_1); let restricted = Address::from(RestrictedAddress::new(account_address.clone()).unwrap()); @@ -2167,7 +2167,7 @@ fn restricted_account() { #[test] fn restricted_ed25519_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let sender = Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(); let restricted_sender = Address::from(RestrictedAddress::new(sender.clone()).unwrap()); @@ -2274,7 +2274,7 @@ fn restricted_ed25519_sender() { #[test] fn multi_address_sender_already_fulfilled() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let sender_0 = Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(); let sender_1 = Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(); let sender_2 = Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(); @@ -2363,7 +2363,7 @@ fn multi_address_sender_already_fulfilled() { #[test] fn ed25519_backed_available_address() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let ed25519 = Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(); let restricted_address = Address::from( RestrictedAddress::new(ed25519.clone()) @@ -2440,14 +2440,14 @@ fn ed25519_backed_available_address() { #[test] fn automatic_allotment_provided_in_and_output() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = [BasicOutputBuilder::new_with_amount(1_000_000) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) - .with_mana(881) + .with_mana(7577) .finish_output() .unwrap()]; let inputs = inputs @@ -2485,7 +2485,7 @@ fn automatic_allotment_provided_in_and_output() { assert_eq!(selected.transaction.outputs().len(), 1); assert!(selected.transaction.outputs().contains(&outputs[0])); assert_eq!(selected.transaction.allotments().len(), 1); - let mana_cost = 880; + let mana_cost = 7576; assert_eq!( selected.transaction.allotments()[0], ManaAllotment::new(account_id_1, mana_cost).unwrap() diff --git a/sdk/tests/client/input_selection/burn.rs b/sdk/tests/client/input_selection/burn.rs index f79687905f..5616feaac3 100644 --- a/sdk/tests/client/input_selection/burn.rs +++ b/sdk/tests/client/input_selection/burn.rs @@ -11,13 +11,15 @@ use iota_sdk::{ types::block::{ address::Address, output::{AccountId, ChainId, NftId, SimpleTokenScheme, TokenId}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, }, }; use pretty_assertions::assert_eq; use crate::client::{ - build_inputs, build_outputs, is_remainder_or_return, unsorted_eq, + assert_remainder_or_return, build_inputs, build_outputs, + input_selection::native_tokens::nt_remainder_min_storage_deposit, + unsorted_eq, Build::{Account, Basic, Foundry, Nft}, ACCOUNT_ID_0, ACCOUNT_ID_1, ACCOUNT_ID_2, BECH32_ADDRESS_ED25519_0, NFT_ID_0, NFT_ID_1, NFT_ID_2, SLOT_COMMITMENT_ID, SLOT_INDEX, TOKEN_ID_1, TOKEN_ID_2, @@ -25,7 +27,7 @@ use crate::client::{ #[test] fn burn_account_present() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -84,7 +86,7 @@ fn burn_account_present() { #[test] fn burn_account_present_and_required() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -144,7 +146,7 @@ fn burn_account_present_and_required() { #[test] fn burn_account_id_zero() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( @@ -206,7 +208,7 @@ fn burn_account_id_zero() { #[test] fn burn_account_absent() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -253,7 +255,7 @@ fn burn_account_absent() { #[test] fn burn_accounts_present() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); @@ -322,7 +324,7 @@ fn burn_accounts_present() { #[test] fn burn_account_in_outputs() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -390,7 +392,7 @@ fn burn_account_in_outputs() { #[test] fn burn_nft_present() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -451,7 +453,7 @@ fn burn_nft_present() { #[test] fn burn_nft_present_and_required() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -513,7 +515,7 @@ fn burn_nft_present_and_required() { #[test] fn burn_nft_id_zero() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs( @@ -573,7 +575,7 @@ fn burn_nft_id_zero() { #[test] fn burn_nft_absent() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -620,7 +622,7 @@ fn burn_nft_absent() { #[test] fn burn_nfts_present() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); @@ -693,7 +695,7 @@ fn burn_nfts_present() { #[test] fn burn_nft_in_outputs() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -765,7 +767,7 @@ fn burn_nft_in_outputs() { #[test] fn burn_foundry_present() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -835,12 +837,12 @@ fn burn_foundry_present() { selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { if output.is_basic() { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } else if output.is_account() { assert_eq!(output.amount(), 1_000_000); assert_eq!(*output.as_account().account_id(), account_id_1); @@ -860,7 +862,7 @@ fn burn_foundry_present() { #[test] fn burn_foundry_absent() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let foundry_id_1 = build_inputs( [( @@ -935,7 +937,7 @@ fn burn_foundry_absent() { #[test] fn burn_foundries_present() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1019,7 +1021,7 @@ fn burn_foundries_present() { #[test] fn burn_foundry_in_outputs() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1088,7 +1090,7 @@ fn burn_foundry_in_outputs() { #[test] fn burn_native_tokens() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1120,6 +1122,8 @@ fn burn_native_tokens() { Some(SLOT_INDEX), ); + let nt_remainder_output_amount = nt_remainder_min_storage_deposit(&protocol_parameters); + let selected = InputSelection::new( inputs.clone(), None, @@ -1137,25 +1141,24 @@ fn burn_native_tokens() { assert!(unsorted_eq(&selected.inputs_data, &inputs)); assert_eq!(selected.transaction.outputs().len(), 2); - let nt_remainder_output_amount = 106000; - assert!( - is_remainder_or_return( - &selected.transaction.outputs()[0], - nt_remainder_output_amount, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 80)) - ) && is_remainder_or_return( - &selected.transaction.outputs()[1], - 2_000_000 - nt_remainder_output_amount, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 70)) - ) + + assert_remainder_or_return( + &selected.transaction.outputs()[0], + nt_remainder_output_amount, + Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + Some((TOKEN_ID_1, 80)), + ); + assert_remainder_or_return( + &selected.transaction.outputs()[1], + 2_000_000 - nt_remainder_output_amount, + Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + Some((TOKEN_ID_2, 70)), ); } #[test] fn burn_foundry_and_its_account() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -1229,12 +1232,12 @@ fn burn_foundry_and_its_account() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } }); } diff --git a/sdk/tests/client/input_selection/delegation_outputs.rs b/sdk/tests/client/input_selection/delegation_outputs.rs index f9d8e2420f..ad48472b28 100644 --- a/sdk/tests/client/input_selection/delegation_outputs.rs +++ b/sdk/tests/client/input_selection/delegation_outputs.rs @@ -12,12 +12,11 @@ use iota_sdk::{ unlock_condition::AddressUnlockCondition, BasicOutputBuilder, DelegationId, DelegationOutputBuilder, OutputId, }, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::{ address::rand_account_address, output::rand_output_metadata_with_id, transaction::rand_transaction_id_with_slot_index, }, - slot::SlotIndex, }, }; use pretty_assertions::assert_eq; @@ -26,7 +25,7 @@ use crate::client::{BECH32_ADDRESS_ED25519_0, SLOT_COMMITMENT_ID, SLOT_INDEX}; #[test] fn remainder_needed_for_mana() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let delegation_input = DelegationOutputBuilder::new_with_amount(1_000_000, DelegationId::null(), rand_account_address()) @@ -97,7 +96,11 @@ fn remainder_needed_for_mana() { .iter() .map(|i| i .output - .available_mana(&protocol_parameters, SlotIndex(0), SLOT_INDEX) + .available_mana( + &protocol_parameters, + i.output_id().transaction_id().slot_index(), + SLOT_INDEX + ) .unwrap()) .sum::(), selected.transaction.outputs().iter().map(|o| o.mana()).sum::() diff --git a/sdk/tests/client/input_selection/expiration.rs b/sdk/tests/client/input_selection/expiration.rs index a074f221d8..d79a8f9e7f 100644 --- a/sdk/tests/client/input_selection/expiration.rs +++ b/sdk/tests/client/input_selection/expiration.rs @@ -8,14 +8,14 @@ use iota_sdk::{ types::block::{ address::Address, output::{AccountId, NftId}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, slot::{SlotCommitmentHash, SlotIndex}, }, }; use pretty_assertions::assert_eq; use crate::client::{ - build_inputs, build_outputs, is_remainder_or_return, unsorted_eq, + assert_remainder_or_return, build_inputs, build_outputs, unsorted_eq, Build::{Account, Basic, Nft}, ACCOUNT_ID_1, BECH32_ADDRESS_ACCOUNT_1, BECH32_ADDRESS_ED25519_0, BECH32_ADDRESS_ED25519_1, BECH32_ADDRESS_ED25519_2, NFT_ID_1, @@ -23,7 +23,7 @@ use crate::client::{ #[test] fn one_output_expiration_not_expired() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -65,7 +65,7 @@ fn one_output_expiration_not_expired() { #[test] fn expiration_equal_timestamp() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -109,7 +109,7 @@ fn expiration_equal_timestamp() { #[test] fn one_output_expiration_expired() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -153,7 +153,7 @@ fn one_output_expiration_expired() { #[test] fn two_outputs_one_expiration_expired() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -212,7 +212,7 @@ fn two_outputs_one_expiration_expired() { #[test] fn two_outputs_one_unexpired_one_missing() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -271,7 +271,7 @@ fn two_outputs_one_unexpired_one_missing() { #[test] fn two_outputs_two_expired() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -342,7 +342,7 @@ fn two_outputs_two_expired() { #[test] fn two_outputs_two_expired_2() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -403,7 +403,7 @@ fn two_outputs_two_expired_2() { #[test] fn expiration_expired_with_sdr() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -447,7 +447,7 @@ fn expiration_expired_with_sdr() { #[test] fn expiration_expired_with_sdr_2() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -491,7 +491,7 @@ fn expiration_expired_with_sdr_2() { #[test] fn expiration_expired_with_sdr_and_timelock() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -535,7 +535,7 @@ fn expiration_expired_with_sdr_and_timelock() { #[test] fn expiration_expired_with_sdr_and_timelock_2() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -579,7 +579,7 @@ fn expiration_expired_with_sdr_and_timelock_2() { #[test] fn sender_in_expiration() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -677,7 +677,7 @@ fn sender_in_expiration() { #[test] fn sender_in_expiration_already_selected() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -725,7 +725,7 @@ fn sender_in_expiration_already_selected() { #[test] fn remainder_in_expiration() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -771,19 +771,19 @@ fn remainder_in_expiration() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None - )); + None, + ); } }); } #[test] fn expiration_expired_non_ed25519_in_address_unlock_condition() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -827,7 +827,7 @@ fn expiration_expired_non_ed25519_in_address_unlock_condition() { #[test] fn expiration_expired_only_account_addresses() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -885,7 +885,7 @@ fn expiration_expired_only_account_addresses() { #[test] fn one_nft_output_expiration_unexpired() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -930,7 +930,7 @@ fn one_nft_output_expiration_unexpired() { #[test] fn one_nft_output_expiration_expired() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( diff --git a/sdk/tests/client/input_selection/foundry_outputs.rs b/sdk/tests/client/input_selection/foundry_outputs.rs index 5c98a5568a..2f64dc8b17 100644 --- a/sdk/tests/client/input_selection/foundry_outputs.rs +++ b/sdk/tests/client/input_selection/foundry_outputs.rs @@ -14,21 +14,21 @@ use iota_sdk::{ unlock_condition::AddressUnlockCondition, AccountId, AccountOutputBuilder, FoundryId, Output, SimpleTokenScheme, TokenId, }, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::output::{rand_output_id_with_slot_index, rand_output_metadata_with_id}, }, }; use pretty_assertions::assert_eq; use crate::client::{ - build_inputs, build_outputs, is_remainder_or_return, unsorted_eq, + assert_remainder_or_return, build_inputs, build_outputs, unsorted_eq, Build::{Account, Basic, Foundry}, ACCOUNT_ID_1, ACCOUNT_ID_2, BECH32_ADDRESS_ED25519_0, SLOT_COMMITMENT_ID, SLOT_INDEX, }; #[test] fn missing_input_account_for_foundry() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -110,7 +110,7 @@ fn missing_input_account_for_foundry() { #[test] fn minted_native_tokens_in_new_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -173,7 +173,7 @@ fn minted_native_tokens_in_new_remainder() { #[test] fn minted_native_tokens_in_provided_output() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let foundry_id = FoundryId::build(&AccountAddress::from(account_id_2), 1, SimpleTokenScheme::KIND); let token_id = TokenId::from(foundry_id); @@ -244,7 +244,7 @@ fn minted_native_tokens_in_provided_output() { #[test] fn melt_native_tokens() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let mut inputs = build_inputs( @@ -322,7 +322,7 @@ fn melt_native_tokens() { #[test] fn destroy_foundry_with_account_state_transition() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -376,7 +376,7 @@ fn destroy_foundry_with_account_state_transition() { #[test] fn destroy_foundry_with_account_burn() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -435,19 +435,19 @@ fn destroy_foundry_with_account_burn() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } }); } #[test] fn prefer_basic_to_foundry() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -515,7 +515,7 @@ fn prefer_basic_to_foundry() { #[test] fn simple_foundry_transition_basic_not_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let mut inputs = build_inputs( @@ -600,7 +600,7 @@ fn simple_foundry_transition_basic_not_needed() { #[test] fn simple_foundry_transition_basic_not_needed_with_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let mut inputs = build_inputs( @@ -679,12 +679,12 @@ fn simple_foundry_transition_basic_not_needed_with_remainder() { Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap() ); } else if output.is_basic() { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } else { panic!("unexpected output type") } @@ -761,7 +761,7 @@ fn simple_foundry_transition_basic_not_needed_with_remainder() { #[test] fn mint_and_burn_at_the_same_time() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let foundry_id = FoundryId::build(&AccountAddress::from(account_id_1), 1, SimpleTokenScheme::KIND); let token_id = TokenId::from(foundry_id); @@ -819,7 +819,7 @@ fn mint_and_burn_at_the_same_time() { #[test] fn take_amount_from_account_and_foundry_to_fund_basic() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let foundry_id = FoundryId::build(&AccountAddress::from(account_id_1), 0, SimpleTokenScheme::KIND); let token_id = TokenId::from(foundry_id); @@ -902,7 +902,7 @@ fn take_amount_from_account_and_foundry_to_fund_basic() { #[test] fn create_native_token_but_burn_account() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let foundry_id = FoundryId::build(&AccountAddress::from(account_id_1), 1, SimpleTokenScheme::KIND); let token_id = TokenId::from(foundry_id); @@ -958,19 +958,19 @@ fn create_native_token_but_burn_account() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 2_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } }); } #[test] fn melted_tokens_not_provided() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let foundry_id = FoundryId::build(&AccountAddress::from(account_id_1), 1, SimpleTokenScheme::KIND); let token_id_1 = TokenId::from(foundry_id); @@ -1029,7 +1029,7 @@ fn melted_tokens_not_provided() { #[test] fn burned_tokens_not_provided() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let foundry_id = FoundryId::build(&AccountAddress::from(account_id_1), 0, SimpleTokenScheme::KIND); let token_id_1 = TokenId::from(foundry_id); @@ -1089,7 +1089,7 @@ fn burned_tokens_not_provided() { #[test] fn foundry_in_outputs_and_required() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let mut inputs = build_inputs( @@ -1149,7 +1149,7 @@ fn foundry_in_outputs_and_required() { #[test] fn melt_and_burn_native_tokens() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let foundry_id = FoundryId::build(&AccountAddress::from(account_id), 1, SimpleTokenScheme::KIND); let token_id = TokenId::from(foundry_id); diff --git a/sdk/tests/client/input_selection/native_tokens.rs b/sdk/tests/client/input_selection/native_tokens.rs index 2bd0267942..769c2bc3ea 100644 --- a/sdk/tests/client/input_selection/native_tokens.rs +++ b/sdk/tests/client/input_selection/native_tokens.rs @@ -5,19 +5,23 @@ use std::str::FromStr; use iota_sdk::{ client::api::input_selection::{Burn, Error, InputSelection}, - types::block::{address::Address, output::TokenId, protocol::protocol_parameters}, + types::block::{ + address::Address, + output::{unlock_condition::AddressUnlockCondition, BasicOutputBuilder, NativeToken, TokenId}, + protocol::{iota_mainnet_protocol_parameters, ProtocolParameters}, + }, }; use pretty_assertions::assert_eq; use primitive_types::U256; use crate::client::{ - build_inputs, build_outputs, is_remainder_or_return, unsorted_eq, Build::Basic, BECH32_ADDRESS_ED25519_0, + assert_remainder_or_return, build_inputs, build_outputs, unsorted_eq, Build::Basic, BECH32_ADDRESS_ED25519_0, SLOT_COMMITMENT_ID, SLOT_INDEX, TOKEN_ID_1, TOKEN_ID_2, }; #[test] fn two_native_tokens_one_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -76,7 +80,7 @@ fn two_native_tokens_one_needed() { #[test] fn two_native_tokens_both_needed_plus_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -144,19 +148,19 @@ fn two_native_tokens_both_needed_plus_remainder() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 2_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 50)) - )); + Some((TOKEN_ID_2, 50)), + ); } }); } #[test] fn three_inputs_two_needed_plus_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -225,19 +229,19 @@ fn three_inputs_two_needed_plus_remainder() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 80)) - )); + Some((TOKEN_ID_1, 80)), + ); } }); } #[test] fn three_inputs_two_needed_no_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -307,7 +311,7 @@ fn three_inputs_two_needed_no_remainder() { #[test] fn insufficient_native_tokens_one_input() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -355,7 +359,7 @@ fn insufficient_native_tokens_one_input() { #[test] fn insufficient_native_tokens_three_inputs() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -429,7 +433,7 @@ fn insufficient_native_tokens_three_inputs() { #[test] fn burn_and_send_at_the_same_time() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -491,19 +495,19 @@ fn burn_and_send_at_the_same_time() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 40)) - )); + Some((TOKEN_ID_1, 40)), + ); } }); } #[test] fn burn_one_input_no_output() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -535,17 +539,17 @@ fn burn_one_input_no_output() { assert!(unsorted_eq(&selected.inputs_data, &inputs)); assert_eq!(selected.transaction.outputs().len(), 1); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[0], 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 50)) - )); + Some((TOKEN_ID_1, 50)), + ); } #[test] fn multiple_native_tokens() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -604,7 +608,7 @@ fn multiple_native_tokens() { #[test] fn insufficient_native_tokens() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -652,7 +656,7 @@ fn insufficient_native_tokens() { #[test] fn insufficient_native_tokens_2() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -700,7 +704,7 @@ fn insufficient_native_tokens_2() { #[test] fn insufficient_amount_for_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -727,6 +731,8 @@ fn insufficient_amount_for_remainder() { expiration: None, }]); + let nt_remainder_min_storage_deposit = nt_remainder_min_storage_deposit(&protocol_parameters); + let selected = InputSelection::new( inputs, outputs, @@ -737,18 +743,18 @@ fn insufficient_amount_for_remainder() { ) .select(); - assert!(matches!( - selected, - Err(Error::InsufficientAmount { + assert_eq!( + selected.unwrap_err(), + Error::InsufficientAmount { found: 1_000_000, - required: 1_106_000, - }) - )); + required: 1_000_000 + nt_remainder_min_storage_deposit, + } + ); } #[test] fn single_output_native_token_no_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -792,7 +798,7 @@ fn single_output_native_token_no_remainder() { #[test] fn single_output_native_token_remainder_1() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -833,17 +839,17 @@ fn single_output_native_token_remainder_1() { assert!(unsorted_eq(&selected.inputs_data, &inputs)); assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[0], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 50)) - )); + Some((TOKEN_ID_1, 50)), + ); } #[test] fn single_output_native_token_remainder_2() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -884,17 +890,17 @@ fn single_output_native_token_remainder_2() { assert!(unsorted_eq(&selected.inputs_data, &inputs)); assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[1], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ); } #[test] fn two_basic_outputs_1() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -950,17 +956,17 @@ fn two_basic_outputs_1() { assert!(selected.inputs_data.contains(&inputs[0])); assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[1], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), Some((TOKEN_ID_1, 100)), - )); + ); } #[test] fn two_basic_outputs_2() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1016,17 +1022,17 @@ fn two_basic_outputs_2() { assert!(selected.inputs_data.contains(&inputs[0])); assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[1], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), Some((TOKEN_ID_1, 50)), - )); + ); } #[test] fn two_basic_outputs_3() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1082,17 +1088,17 @@ fn two_basic_outputs_3() { assert!(selected.inputs_data.contains(&inputs[0])); assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[1], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), Some((TOKEN_ID_1, 25)), - )); + ); } #[test] fn two_basic_outputs_4() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1148,17 +1154,17 @@ fn two_basic_outputs_4() { assert!(selected.inputs_data.contains(&inputs[0])); assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[1], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } #[test] fn two_basic_outputs_5() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1214,17 +1220,17 @@ fn two_basic_outputs_5() { assert!(selected.inputs_data.contains(&inputs[0])); assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[1], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } #[test] fn two_basic_outputs_6() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1279,17 +1285,17 @@ fn two_basic_outputs_6() { assert!(unsorted_eq(&selected.inputs_data, &inputs)); assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[1], 1_500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), Some((TOKEN_ID_1, 50)), - )); + ); } #[test] fn two_basic_outputs_7() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1344,17 +1350,17 @@ fn two_basic_outputs_7() { assert!(unsorted_eq(&selected.inputs_data, &inputs)); assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[1], 1_500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } #[test] fn two_basic_outputs_8() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1416,7 +1422,7 @@ fn two_basic_outputs_8() { #[test] fn two_basic_outputs_native_tokens_not_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1472,17 +1478,17 @@ fn two_basic_outputs_native_tokens_not_needed() { assert!(selected.inputs_data.contains(&inputs[1])); assert_eq!(selected.transaction.outputs().len(), 2); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[1], 500_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), None, - )); + ); } #[test] fn multiple_remainders() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -1547,6 +1553,8 @@ fn multiple_remainders() { expiration: None, }]); + let nt_remainder_min_storage_deposit = nt_remainder_min_storage_deposit(&protocol_parameters); + let selected = InputSelection::new( inputs.clone(), outputs.clone(), @@ -1561,26 +1569,39 @@ fn multiple_remainders() { assert_eq!(selected.inputs_data.len(), 4); assert_eq!(selected.transaction.outputs().len(), 3); assert!(selected.transaction.outputs().contains(&outputs[0])); - let nt_remainder_min_storage_deposit = 106000; + selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!( - is_remainder_or_return( + if output.native_token().unwrap().token_id().to_string() == TOKEN_ID_1 { + assert_remainder_or_return( output, nt_remainder_min_storage_deposit, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_1, 300)) - ) || is_remainder_or_return( + Some((TOKEN_ID_1, 300)), + ); + } else { + assert_remainder_or_return( output, 5_000_000 - nt_remainder_min_storage_deposit, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - Some((TOKEN_ID_2, 100)) - ) - ); + Some((TOKEN_ID_2, 100)), + ); + } } }); } +pub fn nt_remainder_min_storage_deposit(protocol_parameters: &ProtocolParameters) -> u64 { + BasicOutputBuilder::new_with_minimum_amount(protocol_parameters.storage_score_parameters()) + .add_unlock_condition(AddressUnlockCondition::from( + Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + )) + .with_native_token(NativeToken::new(TokenId::from_str(TOKEN_ID_1).unwrap(), 1).unwrap()) + .finish_output() + .unwrap() + .amount() +} + // #[test] // fn higher_nts_count_but_below_max_native_tokens() { // let protocol_parameters = protocol_parameters(); diff --git a/sdk/tests/client/input_selection/nft_outputs.rs b/sdk/tests/client/input_selection/nft_outputs.rs index 8ba0ab353c..5e3cc3f1ea 100644 --- a/sdk/tests/client/input_selection/nft_outputs.rs +++ b/sdk/tests/client/input_selection/nft_outputs.rs @@ -11,14 +11,14 @@ use iota_sdk::{ types::block::{ address::Address, output::{feature::MetadataFeature, unlock_condition::AddressUnlockCondition, NftId, NftOutputBuilder, Output}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::output::{rand_output_id_with_slot_index, rand_output_metadata_with_id}, }, }; use pretty_assertions::{assert_eq, assert_ne}; use crate::client::{ - build_inputs, build_outputs, is_remainder_or_return, unsorted_eq, + assert_remainder_or_return, build_inputs, build_outputs, unsorted_eq, Build::{Basic, Nft}, BECH32_ADDRESS_ACCOUNT_1, BECH32_ADDRESS_ED25519_0, BECH32_ADDRESS_ED25519_1, BECH32_ADDRESS_NFT_1, NFT_ID_0, NFT_ID_1, NFT_ID_2, SLOT_COMMITMENT_ID, SLOT_INDEX, @@ -26,7 +26,7 @@ use crate::client::{ #[test] fn input_nft_eq_output_nft() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( @@ -71,7 +71,7 @@ fn input_nft_eq_output_nft() { #[test] fn transition_nft_id_zero() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( @@ -205,7 +205,7 @@ fn transition_nft_id_zero() { #[test] fn mint_nft() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( @@ -259,7 +259,7 @@ fn mint_nft() { #[test] fn burn_nft() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( @@ -350,7 +350,7 @@ fn burn_nft() { #[test] fn missing_input_for_nft_output() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( @@ -396,7 +396,7 @@ fn missing_input_for_nft_output() { #[test] fn missing_input_for_nft_output_but_created() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( @@ -439,7 +439,7 @@ fn missing_input_for_nft_output_but_created() { #[test] fn nft_in_output_and_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -517,7 +517,7 @@ fn nft_in_output_and_sender() { #[test] fn missing_ed25519_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( @@ -563,7 +563,7 @@ fn missing_ed25519_sender() { #[test] fn missing_ed25519_issuer_created() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( @@ -609,7 +609,7 @@ fn missing_ed25519_issuer_created() { #[test] fn missing_ed25519_issuer_transition() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -652,7 +652,7 @@ fn missing_ed25519_issuer_transition() { #[test] fn missing_account_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( @@ -698,7 +698,7 @@ fn missing_account_sender() { #[test] fn missing_account_issuer_created() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( @@ -744,7 +744,7 @@ fn missing_account_issuer_created() { #[test] fn missing_account_issuer_transition() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( @@ -787,7 +787,7 @@ fn missing_account_issuer_transition() { #[test] fn missing_nft_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( @@ -833,7 +833,7 @@ fn missing_nft_sender() { #[test] fn missing_nft_issuer_created() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( @@ -879,7 +879,7 @@ fn missing_nft_issuer_created() { #[test] fn missing_nft_issuer_transition() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_2 = NftId::from_str(NFT_ID_2).unwrap(); let inputs = build_inputs( @@ -922,7 +922,7 @@ fn missing_nft_issuer_transition() { #[test] fn increase_nft_amount() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -981,7 +981,7 @@ fn increase_nft_amount() { #[test] fn decrease_nft_amount() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -1040,19 +1040,19 @@ fn decrease_nft_amount() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ); } }); } #[test] fn prefer_basic_to_nft() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -1112,7 +1112,7 @@ fn prefer_basic_to_nft() { #[test] fn take_amount_from_nft_to_fund_basic() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -1184,7 +1184,7 @@ fn take_amount_from_nft_to_fund_basic() { #[test] fn nft_burn_should_validate_nft_sender() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -1244,7 +1244,7 @@ fn nft_burn_should_validate_nft_sender() { #[test] fn nft_burn_should_validate_nft_address() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); let inputs = build_inputs( @@ -1304,7 +1304,7 @@ fn nft_burn_should_validate_nft_address() { #[test] fn transitioned_zero_nft_id_no_longer_is_zero() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_0 = NftId::from_str(NFT_ID_0).unwrap(); let inputs = build_inputs( @@ -1363,7 +1363,7 @@ fn transitioned_zero_nft_id_no_longer_is_zero() { #[test] fn changed_immutable_metadata() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id_1 = NftId::from_str(NFT_ID_1).unwrap(); #[cfg(feature = "irc_27")] diff --git a/sdk/tests/client/input_selection/outputs.rs b/sdk/tests/client/input_selection/outputs.rs index 1f15170983..4af1cd6ffc 100644 --- a/sdk/tests/client/input_selection/outputs.rs +++ b/sdk/tests/client/input_selection/outputs.rs @@ -11,21 +11,21 @@ use iota_sdk::{ types::block::{ address::Address, output::{unlock_condition::AddressUnlockCondition, AccountId, BasicOutputBuilder}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::output::{rand_output_id_with_slot_index, rand_output_metadata_with_id}, }, }; use pretty_assertions::assert_eq; use crate::client::{ - build_inputs, build_outputs, is_remainder_or_return, unsorted_eq, + assert_remainder_or_return, build_inputs, build_outputs, unsorted_eq, Build::{Account, Basic}, ACCOUNT_ID_1, ACCOUNT_ID_2, BECH32_ADDRESS_ED25519_0, BECH32_ADDRESS_ED25519_1, SLOT_COMMITMENT_ID, SLOT_INDEX, }; #[test] fn no_inputs() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = Vec::new(); let outputs = build_outputs([Basic { @@ -53,7 +53,7 @@ fn no_inputs() { #[test] fn no_outputs() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -87,7 +87,7 @@ fn no_outputs() { #[test] fn no_outputs_but_required_input() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -121,17 +121,17 @@ fn no_outputs_but_required_input() { assert_eq!(selected.inputs_data, inputs); // Just a remainder assert_eq!(selected.transaction.outputs().len(), 1); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[0], 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ); } #[test] fn no_outputs_but_burn() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs( @@ -163,17 +163,17 @@ fn no_outputs_but_burn() { assert_eq!(selected.inputs_data, inputs); assert_eq!(selected.transaction.outputs().len(), 1); - assert!(is_remainder_or_return( + assert_remainder_or_return( &selected.transaction.outputs()[0], 2_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ); } #[test] fn no_address_provided() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -215,7 +215,7 @@ fn no_address_provided() { #[test] fn no_matching_address_provided() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -257,7 +257,7 @@ fn no_matching_address_provided() { #[test] fn two_addresses_one_missing() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -319,7 +319,7 @@ fn two_addresses_one_missing() { #[test] fn two_addresses() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -380,34 +380,34 @@ fn two_addresses() { #[test] fn consolidate_with_min_allotment() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = [ BasicOutputBuilder::new_with_minimum_amount(protocol_parameters.storage_score_parameters()) - .with_mana(1000) + .with_mana(9860) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) .finish_output() .unwrap(), BasicOutputBuilder::new_with_minimum_amount(protocol_parameters.storage_score_parameters()) - .with_mana(2000) + .with_mana(9860) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) .finish_output() .unwrap(), BasicOutputBuilder::new_with_minimum_amount(protocol_parameters.storage_score_parameters()) - .with_mana(1000) + .with_mana(9860) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) .finish_output() .unwrap(), BasicOutputBuilder::new_with_minimum_amount(protocol_parameters.storage_score_parameters()) - .with_mana(1000) + .with_mana(9860) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) @@ -438,6 +438,6 @@ fn consolidate_with_min_allotment() { assert_eq!(selected.transaction.outputs().len(), 1); assert_eq!(selected.transaction.allotments().len(), 1); - assert_eq!(selected.transaction.allotments()[0].mana(), 5000); + assert_eq!(selected.transaction.allotments()[0].mana(), 39440); assert_eq!(selected.transaction.outputs().iter().map(|o| o.mana()).sum::(), 0); } diff --git a/sdk/tests/client/input_selection/storage_deposit_return.rs b/sdk/tests/client/input_selection/storage_deposit_return.rs index 52aeacc99b..40a8c7a29c 100644 --- a/sdk/tests/client/input_selection/storage_deposit_return.rs +++ b/sdk/tests/client/input_selection/storage_deposit_return.rs @@ -5,12 +5,12 @@ use std::str::FromStr; use iota_sdk::{ client::api::input_selection::{Error, InputSelection}, - types::block::{address::Address, output::AccountId, protocol::protocol_parameters}, + types::block::{address::Address, output::AccountId, protocol::iota_mainnet_protocol_parameters}, }; use pretty_assertions::assert_eq; use crate::client::{ - build_inputs, build_outputs, is_remainder_or_return, unsorted_eq, + assert_remainder_or_return, build_inputs, build_outputs, unsorted_eq, Build::{Account, Basic}, ACCOUNT_ID_1, BECH32_ADDRESS_ACCOUNT_1, BECH32_ADDRESS_ED25519_0, BECH32_ADDRESS_ED25519_1, BECH32_ADDRESS_ED25519_2, SLOT_COMMITMENT_ID, SLOT_INDEX, @@ -18,7 +18,7 @@ use crate::client::{ #[test] fn sdruc_output_not_provided_no_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -61,19 +61,19 @@ fn sdruc_output_not_provided_no_remainder() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None - )); + None, + ); } }); } #[test] fn sdruc_output_provided_no_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -128,7 +128,7 @@ fn sdruc_output_provided_no_remainder() { #[test] fn sdruc_output_provided_remainder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -171,19 +171,19 @@ fn sdruc_output_provided_remainder() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - None - )); + None, + ); } }); } #[test] fn two_sdrucs_to_the_same_address_both_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -240,19 +240,19 @@ fn two_sdrucs_to_the_same_address_both_needed() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 2_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None - )); + None, + ); } }); } #[test] fn two_sdrucs_to_the_same_address_one_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -310,19 +310,19 @@ fn two_sdrucs_to_the_same_address_one_needed() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None - )); + None, + ); } }); } #[test] fn two_sdrucs_to_different_addresses_both_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -377,27 +377,33 @@ fn two_sdrucs_to_different_addresses_both_needed() { assert!(unsorted_eq(&selected.inputs_data, &inputs)); assert_eq!(selected.transaction.outputs().len(), 3); assert!(selected.transaction.outputs().contains(&outputs[0])); - assert!(selected.transaction.outputs().iter().any(|output| { - is_remainder_or_return( - output, - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None, - ) - })); - assert!(selected.transaction.outputs().iter().any(|output| { - is_remainder_or_return( - output, - 1_000_000, - Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), - None, - ) - })); + assert_remainder_or_return( + selected + .transaction + .outputs() + .iter() + .find(|o| o.as_basic().address() == &Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap()) + .unwrap(), + 1_000_000, + Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), + None, + ); + assert_remainder_or_return( + selected + .transaction + .outputs() + .iter() + .find(|o| o.as_basic().address() == &Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap()) + .unwrap(), + 1_000_000, + Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), + None, + ); } #[test] fn two_sdrucs_to_different_addresses_one_needed() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -455,19 +461,19 @@ fn two_sdrucs_to_different_addresses_one_needed() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_1).unwrap(), - None - )); + None, + ); } }); } #[test] fn insufficient_amount_because_of_sdruc() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -515,7 +521,7 @@ fn insufficient_amount_because_of_sdruc() { #[test] fn useless_sdruc_required_for_sender_feature() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -575,19 +581,19 @@ fn useless_sdruc_required_for_sender_feature() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), - None - )); + None, + ); } }); } #[test] fn sdruc_required_non_ed25519_in_address_unlock() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( @@ -643,19 +649,19 @@ fn sdruc_required_non_ed25519_in_address_unlock() { assert!(selected.transaction.outputs().contains(&outputs[0])); selected.transaction.outputs().iter().for_each(|output| { if !outputs.contains(output) && !output.is_account() { - assert!(is_remainder_or_return( + assert_remainder_or_return( output, 1_000_000, Address::try_from_bech32(BECH32_ADDRESS_ED25519_2).unwrap(), - None - )); + None, + ); } }); } #[test] fn useless_sdruc_non_ed25519_in_address_unlock() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs( diff --git a/sdk/tests/client/input_selection/timelock.rs b/sdk/tests/client/input_selection/timelock.rs index 974e40accb..214a92f6df 100644 --- a/sdk/tests/client/input_selection/timelock.rs +++ b/sdk/tests/client/input_selection/timelock.rs @@ -5,7 +5,7 @@ use iota_sdk::{ client::api::input_selection::{Error, InputSelection}, types::block::{ address::Address, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, slot::{SlotCommitmentHash, SlotIndex}, }, }; @@ -17,7 +17,7 @@ use crate::client::{ #[test] fn one_output_timelock_not_expired() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -59,7 +59,7 @@ fn one_output_timelock_not_expired() { #[test] fn timelock_equal_timestamp() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( @@ -103,7 +103,7 @@ fn timelock_equal_timestamp() { #[test] fn two_outputs_one_timelock_expired() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -162,7 +162,7 @@ fn two_outputs_one_timelock_expired() { #[test] fn two_outputs_one_timelocked_one_missing() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [ @@ -221,7 +221,7 @@ fn two_outputs_one_timelocked_one_missing() { #[test] fn one_output_timelock_expired() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let inputs = build_inputs( [( diff --git a/sdk/tests/client/mod.rs b/sdk/tests/client/mod.rs index 00643214d6..ee47dc0575 100644 --- a/sdk/tests/client/mod.rs +++ b/sdk/tests/client/mod.rs @@ -39,6 +39,7 @@ use iota_sdk::{ slot::{SlotCommitmentHash, SlotCommitmentId, SlotIndex}, }, }; +use pretty_assertions::assert_ne; const ACCOUNT_ID_0: &str = "0x0000000000000000000000000000000000000000000000000000000000000000"; const ACCOUNT_ID_1: &str = "0x1111111111111111111111111111111111111111111111111111111111111111"; @@ -278,37 +279,26 @@ where count(a) == count(b) } -fn is_remainder_or_return(output: &Output, amount: u64, address: Address, native_token: Option<(&str, u64)>) -> bool { - if let Output::Basic(output) = output { - if output.amount() != amount { - return false; - } - - if let [UnlockCondition::Address(address_unlock_condition)] = output.unlock_conditions().as_ref() { - if address_unlock_condition.address() != &address { - return false; - } - } else { - return false; - } +fn assert_remainder_or_return(output: &Output, amount: u64, address: Address, native_token: Option<(&str, u64)>) { + let output = output.as_basic(); + assert_eq!(amount, output.amount()); - match output.features().as_ref() { - [] | [Feature::NativeToken(_)] => {} - _ => return false, - } + if let [UnlockCondition::Address(address_unlock_condition)] = output.unlock_conditions().as_ref() { + assert_eq!(&address, address_unlock_condition.address()); + } else { + panic!("no address unlock condition"); + } - if let Some((token_id, amount)) = native_token { - let native_token = NativeToken::new(TokenId::from_str(token_id).unwrap(), amount).unwrap(); + match output.features().as_ref() { + [] | [Feature::NativeToken(_)] => {} + _ => panic!("incorrect features"), + } - if output.native_token().unwrap() != &native_token { - return false; - } - } else if output.native_token().is_some() { - return false; - } + if let Some((token_id, amount)) = native_token { + let native_token = NativeToken::new(TokenId::from_str(token_id).unwrap(), amount).unwrap(); - true - } else { - false + assert_eq!(&native_token, output.native_token().unwrap()); + } else if output.native_token().is_some() { + panic!("no native token provided but native token exists on output"); } } diff --git a/sdk/tests/client/node_api/core.rs b/sdk/tests/client/node_api/core.rs index e508c91263..2cf9b7a2f6 100644 --- a/sdk/tests/client/node_api/core.rs +++ b/sdk/tests/client/node_api/core.rs @@ -157,7 +157,7 @@ async fn test_get_output_raw() { let output_id = OutputId::new(transaction_id, 0); let output = client.get_output(&output_id).await.unwrap(); - let output_raw = Output::unpack_verified( + let output_raw = Output::unpack_bytes_verified( client.get_output_raw(&output_id).await.unwrap(), &client.get_protocol_parameters().await.unwrap(), ) @@ -184,7 +184,7 @@ async fn test_get_included_block_raw() { let (_block_id, transaction_id) = setup_transaction_block(&client).await; let block = client.get_included_block(&transaction_id).await.unwrap(); - let block_raw = Block::unpack_verified( + let block_raw = Block::unpack_bytes_verified( client.get_included_block_raw(&transaction_id).await.unwrap(), &client.get_protocol_parameters().await.unwrap(), ) diff --git a/sdk/tests/client/signing/account.rs b/sdk/tests/client/signing/account.rs index f485646c99..9dcc6e045c 100644 --- a/sdk/tests/client/signing/account.rs +++ b/sdk/tests/client/signing/account.rs @@ -18,8 +18,11 @@ use iota_sdk::{ address::{AccountAddress, Address}, input::{Input, UtxoInput}, output::AccountId, - payload::{signed_transaction::Transaction, SignedTransactionPayload}, - protocol::protocol_parameters, + payload::{ + signed_transaction::{Transaction, TransactionCapabilityFlag}, + SignedTransactionPayload, + }, + protocol::iota_mainnet_protocol_parameters, slot::SlotIndex, unlock::{SignatureUnlock, Unlock}, }, @@ -46,7 +49,7 @@ async fn sign_account_state_transition() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id = AccountId::from_str(ACCOUNT_ID_1)?; let slot_index = SlotIndex::from(10); @@ -81,6 +84,7 @@ async fn sign_account_state_transition() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -129,7 +133,7 @@ async fn account_reference_unlocks() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id = AccountId::from_str(ACCOUNT_ID_1)?; let account_address = Address::Account(AccountAddress::new(account_id)); let slot_index = SlotIndex::from(10); @@ -202,6 +206,7 @@ async fn account_reference_unlocks() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { diff --git a/sdk/tests/client/signing/basic.rs b/sdk/tests/client/signing/basic.rs index 9fa7e3f3bb..887174a560 100644 --- a/sdk/tests/client/signing/basic.rs +++ b/sdk/tests/client/signing/basic.rs @@ -14,8 +14,11 @@ use iota_sdk::{ }, types::block::{ input::{Input, UtxoInput}, - payload::{signed_transaction::Transaction, SignedTransactionPayload}, - protocol::protocol_parameters, + payload::{ + signed_transaction::{Transaction, TransactionCapabilityFlag}, + SignedTransactionPayload, + }, + protocol::iota_mainnet_protocol_parameters, slot::SlotIndex, unlock::{SignatureUnlock, Unlock}, }, @@ -38,7 +41,7 @@ async fn single_ed25519_unlock() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_index = SlotIndex::from(10); let inputs = build_inputs( @@ -76,6 +79,7 @@ async fn single_ed25519_unlock() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -124,7 +128,7 @@ async fn ed25519_reference_unlocks() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_index = SlotIndex::from(10); let inputs = build_inputs( @@ -188,6 +192,7 @@ async fn ed25519_reference_unlocks() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -257,7 +262,7 @@ async fn two_signature_unlocks() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_index = SlotIndex::from(10); let inputs = build_inputs( @@ -309,6 +314,7 @@ async fn two_signature_unlocks() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { diff --git a/sdk/tests/client/signing/delegation.rs b/sdk/tests/client/signing/delegation.rs index 8fcb872c29..5adbbe804f 100644 --- a/sdk/tests/client/signing/delegation.rs +++ b/sdk/tests/client/signing/delegation.rs @@ -18,8 +18,11 @@ use iota_sdk::{ context_input::{CommitmentContextInput, RewardContextInput}, input::{Input, UtxoInput}, output::DelegationId, - payload::{signed_transaction::Transaction, SignedTransactionPayload}, - protocol::protocol_parameters, + payload::{ + signed_transaction::{Transaction, TransactionCapabilityFlag}, + SignedTransactionPayload, + }, + protocol::iota_mainnet_protocol_parameters, rand::{address::rand_account_address, output::rand_delegation_id, slot::rand_slot_commitment_id}, semantic::TransactionFailureReason, unlock::SignatureUnlock, @@ -46,7 +49,7 @@ async fn valid_creation() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id = rand_slot_commitment_id(); let slot_index = slot_commitment_id.slot_index(); @@ -86,6 +89,7 @@ async fn valid_creation() -> Result<()> { .with_outputs(outputs) .with_creation_slot(slot_index + 1) .with_context_inputs([CommitmentContextInput::new(slot_commitment_id).into()]) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -134,7 +138,7 @@ async fn creation_missing_commitment_input() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id = rand_slot_commitment_id(); let slot_index = slot_commitment_id.slot_index(); @@ -173,6 +177,7 @@ async fn creation_missing_commitment_input() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -222,7 +227,7 @@ async fn non_null_id_creation() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id = rand_slot_commitment_id(); let slot_index = slot_commitment_id.slot_index(); @@ -261,6 +266,7 @@ async fn non_null_id_creation() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -307,7 +313,7 @@ async fn mismatch_amount_creation() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id = rand_slot_commitment_id(); let slot_index = slot_commitment_id.slot_index(); @@ -346,6 +352,7 @@ async fn mismatch_amount_creation() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -392,7 +399,7 @@ async fn non_zero_end_epoch_creation() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id = rand_slot_commitment_id(); let slot_index = slot_commitment_id.slot_index(); @@ -431,6 +438,7 @@ async fn non_zero_end_epoch_creation() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -477,7 +485,7 @@ async fn invalid_start_epoch_creation() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id = rand_slot_commitment_id(); let slot_index = slot_commitment_id.slot_index(); @@ -516,6 +524,7 @@ async fn invalid_start_epoch_creation() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .with_context_inputs([CommitmentContextInput::new(slot_commitment_id).into()]) .finish_with_params(&protocol_parameters)?; @@ -563,7 +572,7 @@ async fn delay_not_null_id() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id_1 = rand_slot_commitment_id(); let slot_index_1 = slot_commitment_id_1.slot_index(); let slot_commitment_id_2 = rand_slot_commitment_id() @@ -614,6 +623,7 @@ async fn delay_not_null_id() -> Result<()> { CommitmentContextInput::new(slot_commitment_id_2).into(), RewardContextInput::new(0)?.into(), ]) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -663,7 +673,7 @@ async fn delay_modified_amount() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id_1 = rand_slot_commitment_id(); let slot_index_1 = slot_commitment_id_1.slot_index(); let slot_commitment_id_2 = rand_slot_commitment_id() @@ -714,6 +724,7 @@ async fn delay_modified_amount() -> Result<()> { CommitmentContextInput::new(slot_commitment_id_2).into(), RewardContextInput::new(0)?.into(), ]) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -760,7 +771,7 @@ async fn delay_modified_validator() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id_1 = rand_slot_commitment_id(); let slot_index_1 = slot_commitment_id_1.slot_index(); let slot_commitment_id_2 = rand_slot_commitment_id() @@ -811,6 +822,7 @@ async fn delay_modified_validator() -> Result<()> { CommitmentContextInput::new(slot_commitment_id_2).into(), RewardContextInput::new(0)?.into(), ]) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -857,7 +869,7 @@ async fn delay_modified_start_epoch() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id_1 = rand_slot_commitment_id(); let slot_index_1 = slot_commitment_id_1.slot_index(); let slot_commitment_id_2 = rand_slot_commitment_id() @@ -908,6 +920,7 @@ async fn delay_modified_start_epoch() -> Result<()> { CommitmentContextInput::new(slot_commitment_id_2).into(), RewardContextInput::new(0)?.into(), ]) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -954,7 +967,7 @@ async fn delay_pre_registration_slot_end_epoch() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id_1 = rand_slot_commitment_id(); let slot_index_1 = slot_commitment_id_1.slot_index(); let slot_commitment_id_2 = rand_slot_commitment_id() @@ -1005,6 +1018,7 @@ async fn delay_pre_registration_slot_end_epoch() -> Result<()> { CommitmentContextInput::new(slot_commitment_id_2).into(), RewardContextInput::new(0)?.into(), ]) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { @@ -1051,7 +1065,7 @@ async fn destroy_null_id() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id_1 = rand_slot_commitment_id(); let slot_index_1 = slot_commitment_id_1.slot_index(); let slot_commitment_id_2 = rand_slot_commitment_id() @@ -1100,6 +1114,7 @@ async fn destroy_null_id() -> Result<()> { CommitmentContextInput::new(slot_commitment_id_2).into(), RewardContextInput::new(0)?.into(), ]) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let mut mana_rewards = BTreeMap::default(); @@ -1151,7 +1166,7 @@ async fn destroy_reward_missing() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let slot_commitment_id_1 = rand_slot_commitment_id(); let slot_index_1 = slot_commitment_id_1.slot_index(); let slot_commitment_id_2 = rand_slot_commitment_id() @@ -1197,6 +1212,7 @@ async fn destroy_reward_missing() -> Result<()> { .with_outputs(outputs) .with_creation_slot(slot_index_2 + 1) .with_context_inputs([CommitmentContextInput::new(slot_commitment_id_2).into()]) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { diff --git a/sdk/tests/client/signing/mod.rs b/sdk/tests/client/signing/mod.rs index f08d6bfbe0..2a25165ad3 100644 --- a/sdk/tests/client/signing/mod.rs +++ b/sdk/tests/client/signing/mod.rs @@ -25,7 +25,7 @@ use iota_sdk::{ input::{Input, UtxoInput}, output::{AccountId, NftId}, payload::{signed_transaction::Transaction, SignedTransactionPayload}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, slot::{SlotCommitmentHash, SlotCommitmentId, SlotIndex}, unlock::{SignatureUnlock, Unlock}, }, @@ -45,7 +45,7 @@ async fn all_combined() -> Result<()> { "mirror add nothing long orphan hat this rough scare gallery fork twelve old shrug voyage job table obscure mimic holiday possible proud giraffe fan".to_owned(), )?; - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let ed25519_bech32_addresses = secret_manager .generate_ed25519_addresses( diff --git a/sdk/tests/client/signing/nft.rs b/sdk/tests/client/signing/nft.rs index b42c300f8e..1954198dc8 100644 --- a/sdk/tests/client/signing/nft.rs +++ b/sdk/tests/client/signing/nft.rs @@ -18,8 +18,11 @@ use iota_sdk::{ address::{Address, NftAddress}, input::{Input, UtxoInput}, output::NftId, - payload::{signed_transaction::Transaction, SignedTransactionPayload}, - protocol::protocol_parameters, + payload::{ + signed_transaction::{Transaction, TransactionCapabilityFlag}, + SignedTransactionPayload, + }, + protocol::iota_mainnet_protocol_parameters, slot::SlotIndex, unlock::{SignatureUnlock, Unlock}, }, @@ -46,7 +49,7 @@ async fn nft_reference_unlocks() -> Result<()> { .clone() .into_inner(); - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let nft_id = NftId::from_str(NFT_ID_1)?; let nft_address = Address::Nft(NftAddress::new(nft_id)); let slot_index = SlotIndex::from(10); @@ -123,6 +126,7 @@ async fn nft_reference_unlocks() -> Result<()> { ) .with_outputs(outputs) .with_creation_slot(slot_index + 1) + .with_capabilities([TransactionCapabilityFlag::BurnMana]) .finish_with_params(&protocol_parameters)?; let prepared_transaction_data = PreparedTransactionData { diff --git a/sdk/tests/mod.rs b/sdk/tests/mod.rs index 3007e18930..f13f5139e1 100644 --- a/sdk/tests/mod.rs +++ b/sdk/tests/mod.rs @@ -1,9 +1,9 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -#[cfg(feature = "client")] +#[cfg(all(feature = "protocol_parameters_samples", feature = "client"))] mod client; mod types; mod utils; -#[cfg(feature = "wallet")] +#[cfg(all(feature = "protocol_parameters_samples", feature = "wallet"))] mod wallet; diff --git a/sdk/tests/types/address/account.rs b/sdk/tests/types/address/account.rs index 916a065f60..cc777e4a15 100644 --- a/sdk/tests/types/address/account.rs +++ b/sdk/tests/types/address/account.rs @@ -167,7 +167,7 @@ fn pack_unpack() { assert_eq!( address, - PackableExt::unpack_verified(packed_address.as_slice(), &()).unwrap() + PackableExt::unpack_bytes_verified(packed_address.as_slice(), &()).unwrap() ); let address = Address::from(AccountAddress::from_str(ACCOUNT_ID).unwrap()); @@ -175,6 +175,6 @@ fn pack_unpack() { assert_eq!( address, - PackableExt::unpack_verified(packed_address.as_slice(), &()).unwrap() + PackableExt::unpack_bytes_verified(packed_address.as_slice(), &()).unwrap() ); } diff --git a/sdk/tests/types/address/bech32.rs b/sdk/tests/types/address/bech32.rs index 55ae7eb4ea..eeed8e9b49 100644 --- a/sdk/tests/types/address/bech32.rs +++ b/sdk/tests/types/address/bech32.rs @@ -56,14 +56,14 @@ fn hrp_pack_unpack() { let hrp = Hrp::from_str("rms").unwrap(); let packed_hrp = hrp.pack_to_vec(); - assert_eq!(hrp, Hrp::unpack_verified(packed_hrp.as_slice(), &()).unwrap()); + assert_eq!(hrp, Hrp::unpack_bytes_verified(packed_hrp.as_slice(), &()).unwrap()); } #[test] fn invalid_hrp_unpack() { let packed_hrp = vec![32, 32, 32]; // invalid HRP: " " - assert!(Hrp::unpack_verified(packed_hrp.as_slice(), &()).is_err()); + assert!(Hrp::unpack_bytes_verified(packed_hrp.as_slice(), &()).is_err()); } #[test] diff --git a/sdk/tests/types/address/ed25519.rs b/sdk/tests/types/address/ed25519.rs index 6ed989f224..0d6ddaa63c 100644 --- a/sdk/tests/types/address/ed25519.rs +++ b/sdk/tests/types/address/ed25519.rs @@ -156,7 +156,7 @@ fn pack_unpack() { assert_eq!( address, - Ed25519Address::unpack_verified(packed_address.as_slice(), &()).unwrap() + Ed25519Address::unpack_bytes_verified(packed_address.as_slice(), &()).unwrap() ); let address = Address::from(Ed25519Address::from_str(ED25519_ADDRESS).unwrap()); @@ -164,6 +164,6 @@ fn pack_unpack() { assert_eq!( address, - Address::unpack_verified(packed_address.as_slice(), &()).unwrap() + Address::unpack_bytes_verified(packed_address.as_slice(), &()).unwrap() ); } diff --git a/sdk/tests/types/address/multi.rs b/sdk/tests/types/address/multi.rs index c63a63633a..23978d04a7 100644 --- a/sdk/tests/types/address/multi.rs +++ b/sdk/tests/types/address/multi.rs @@ -21,7 +21,7 @@ fn ordered_by_packed_bytes() { let multi_1 = MultiAddress::new([weighted_1, weighted_2], 2).unwrap(); let bytes = multi_1.pack_to_vec(); - let multi_2 = MultiAddress::unpack_verified(bytes, &()).unwrap(); + let multi_2 = MultiAddress::unpack_bytes_verified(bytes, &()).unwrap(); assert!(multi_2.addresses()[0].address().is_ed25519()); assert!(multi_2.addresses()[1].address().is_account()); @@ -74,7 +74,7 @@ fn json_packable_bech32() { }); let multi_address = serde_json::from_value::
(multi_address_json).unwrap(); let multi_address_bytes = multi_address.pack_to_vec(); - let multi_address_unpacked = Address::unpack_verified(multi_address_bytes, &()).unwrap(); + let multi_address_unpacked = Address::unpack_bytes_verified(multi_address_bytes, &()).unwrap(); assert_eq!(multi_address, multi_address_unpacked); assert_eq!( diff --git a/sdk/tests/types/address/nft.rs b/sdk/tests/types/address/nft.rs index 45f5243a16..0606d342c9 100644 --- a/sdk/tests/types/address/nft.rs +++ b/sdk/tests/types/address/nft.rs @@ -167,7 +167,7 @@ fn pack_unpack() { assert_eq!( address, - PackableExt::unpack_verified(packed_address.as_slice(), &()).unwrap() + PackableExt::unpack_bytes_verified(packed_address.as_slice(), &()).unwrap() ); let address = Address::from(NftAddress::from_str(NFT_ID).unwrap()); @@ -175,6 +175,6 @@ fn pack_unpack() { assert_eq!( address, - PackableExt::unpack_verified(packed_address.as_slice(), &()).unwrap() + PackableExt::unpack_bytes_verified(packed_address.as_slice(), &()).unwrap() ); } diff --git a/sdk/tests/types/address/restricted.rs b/sdk/tests/types/address/restricted.rs index dc50f4c880..a28199a101 100644 --- a/sdk/tests/types/address/restricted.rs +++ b/sdk/tests/types/address/restricted.rs @@ -43,7 +43,7 @@ fn restricted_ed25519() { // Test from https://github.com/iotaledger/tips/blob/tip50/tips/TIP-0050/tip-0050.md#bech32-strings // Ed25519 Address (Plain) - let address = Address::unpack_verified( + let address = Address::unpack_bytes_verified( prefix_hex::decode::>("0x00efdc112efe262b304bcf379b26c31bad029f616ee3ec4aa6345a366e4c9e43a3").unwrap(), &(), ) @@ -103,7 +103,7 @@ fn restricted_account() { // Test from https://github.com/iotaledger/tips/blob/tip50/tips/TIP-0050/tip-0050.md#bech32-strings // Account Address (Plain) - let address = Address::unpack_verified( + let address = Address::unpack_bytes_verified( prefix_hex::decode::>("0x0860441c013b400f402c317833366f48730610296a09243636343e7b1b7e115409").unwrap(), &(), ) @@ -163,7 +163,7 @@ fn restricted_nft() { // Test from https://github.com/iotaledger/tips/blob/tip50/tips/TIP-0050/tip-0050.md#bech32-strings // NFT Address (Plain) - let address = Address::unpack_verified( + let address = Address::unpack_bytes_verified( prefix_hex::decode::>("0x10140f39267a343f0d650a751250445e40600d133522085d210a2b5f3f69445139").unwrap(), &(), ) diff --git a/sdk/tests/types/api/core.rs b/sdk/tests/types/api/core.rs index ea03e1f84e..85f7057ddc 100644 --- a/sdk/tests/types/api/core.rs +++ b/sdk/tests/types/api/core.rs @@ -44,9 +44,9 @@ fn binary_response( let file = std::fs::read_to_string(format!("./tests/types/api/fixtures/{path}")).unwrap(); let bytes = hex::decode(file).unwrap(); let mut unpacker = SliceUnpacker::new(bytes.as_slice()); - let res = T::unpack::<_, true>(&mut unpacker, visitor); + let res = T::unpack_verified(&mut unpacker, visitor); - assert!(u8::unpack::<_, true>(&mut unpacker, &()).is_err()); + assert!(u8::unpack_verified(&mut unpacker, &()).is_err()); res } diff --git a/sdk/tests/types/block.rs b/sdk/tests/types/block.rs index 47d536265f..705c4cd2a7 100644 --- a/sdk/tests/types/block.rs +++ b/sdk/tests/types/block.rs @@ -5,7 +5,7 @@ use iota_sdk::types::{ block::{ helper::network_name_to_id, payload::Payload, - protocol::{protocol_parameters, ProtocolParameters}, + protocol::iota_mainnet_protocol_parameters, rand::{ block::{rand_basic_block_body_builder_with_strong_parents, rand_block, rand_block_with_block_body}, parents::rand_strong_parents, @@ -92,20 +92,20 @@ use pretty_assertions::assert_eq; // Validate that a `unpack` ∘ `pack` round-trip results in the original block. #[test] fn pack_unpack_valid() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let block = rand_block(protocol_parameters.clone()); let packed_block = block.pack_to_vec(); assert_eq!(packed_block.len(), block.packed_len()); assert_eq!( block, - PackableExt::unpack_verified(packed_block.as_slice(), &protocol_parameters).unwrap() + PackableExt::unpack_bytes_verified(packed_block.as_slice(), protocol_parameters).unwrap() ); } #[test] fn getters() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let parents = rand_strong_parents(); let payload = Payload::from(rand_tagged_data_payload()); @@ -122,7 +122,7 @@ fn getters() { #[test] fn dto_mismatch_version() { - let protocol_parameters = ProtocolParameters::default(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let protocol_parameters_hash = protocol_parameters.hash(); let slot_index = 11_u64; let issuing_time = protocol_parameters.genesis_unix_timestamp() @@ -166,7 +166,7 @@ fn dto_mismatch_version() { #[test] fn dto_mismatch_network_id() { - let protocol_parameters = ProtocolParameters::default(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let protocol_parameters_hash = protocol_parameters.hash(); let slot_index = 11_u64; let issuing_time = protocol_parameters.genesis_unix_timestamp() diff --git a/sdk/tests/types/block_id.rs b/sdk/tests/types/block_id.rs index 60e9dc6e3f..8d497e428b 100644 --- a/sdk/tests/types/block_id.rs +++ b/sdk/tests/types/block_id.rs @@ -53,7 +53,7 @@ fn pack_unpack_valid() { assert_eq!(packed_block_id.len(), block_id.packed_len()); assert_eq!( block_id, - PackableExt::unpack_verified(packed_block_id.as_slice(), &()).unwrap() + PackableExt::unpack_bytes_verified(packed_block_id.as_slice(), &()).unwrap() ); } diff --git a/sdk/tests/types/ed25519_signature.rs b/sdk/tests/types/ed25519_signature.rs index 4adc27d077..7d4212f79b 100644 --- a/sdk/tests/types/ed25519_signature.rs +++ b/sdk/tests/types/ed25519_signature.rs @@ -30,5 +30,8 @@ fn pack_unpack_valid() { let sig = Ed25519Signature::from_bytes(pub_key_bytes, sig_bytes); let sig_packed = sig.pack_to_vec(); - assert_eq!(sig, PackableExt::unpack_verified(sig_packed.as_slice(), &()).unwrap()); + assert_eq!( + sig, + PackableExt::unpack_bytes_verified(sig_packed.as_slice(), &()).unwrap() + ); } diff --git a/sdk/tests/types/input/utxo.rs b/sdk/tests/types/input/utxo.rs index e097db2bb0..0cd2b4e238 100644 --- a/sdk/tests/types/input/utxo.rs +++ b/sdk/tests/types/input/utxo.rs @@ -96,11 +96,14 @@ fn pack_unpack() { assert_eq!( utxo_input, - UtxoInput::unpack_verified(packed_input.as_slice(), &()).unwrap() + UtxoInput::unpack_bytes_verified(packed_input.as_slice(), &()).unwrap() ); let input = Input::from(utxo_input); let packed_input = input.pack_to_vec(); - assert_eq!(input, Input::unpack_verified(packed_input.as_slice(), &()).unwrap()); + assert_eq!( + input, + Input::unpack_bytes_verified(packed_input.as_slice(), &()).unwrap() + ); } diff --git a/sdk/tests/types/mod.rs b/sdk/tests/types/mod.rs index fd58dfba92..e4a8c1a5bd 100644 --- a/sdk/tests/types/mod.rs +++ b/sdk/tests/types/mod.rs @@ -3,20 +3,25 @@ mod address; mod api; +#[cfg(feature = "protocol_parameters_samples")] mod block; mod block_id; mod ed25519_signature; mod foundry_id; mod input; +#[cfg(feature = "protocol_parameters_samples")] mod output; mod output_id; mod parents; +#[cfg(feature = "protocol_parameters_samples")] mod payload; mod protocol_parameters; +#[cfg(feature = "protocol_parameters_samples")] mod signed_transaction_payload; mod slot; mod storage_score; mod tagged_data_payload; +#[cfg(feature = "protocol_parameters_samples")] mod transaction; mod transaction_id; mod unlock; diff --git a/sdk/tests/types/output/account.rs b/sdk/tests/types/output/account.rs index 57f5b2474c..d5ee080729 100644 --- a/sdk/tests/types/output/account.rs +++ b/sdk/tests/types/output/account.rs @@ -3,7 +3,7 @@ use iota_sdk::types::block::{ output::{AccountOutput, Feature, MinimumOutputAmount}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::output::{ feature::{rand_issuer_feature, rand_metadata_feature, rand_sender_feature}, rand_account_id, rand_account_output, @@ -15,7 +15,7 @@ use pretty_assertions::assert_eq; #[test] fn builder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let account_id = rand_account_id(); let address_1 = rand_address_unlock_condition_different_from_account_id(&account_id); let address_2 = rand_address_unlock_condition_different_from_account_id(&account_id); @@ -70,10 +70,10 @@ fn builder() { #[test] fn pack_unpack() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let output = rand_account_output(protocol_parameters.token_supply()); let bytes = output.pack_to_vec(); - let output_unpacked = AccountOutput::unpack_verified(bytes, &protocol_parameters).unwrap(); + let output_unpacked = AccountOutput::unpack_bytes_verified(bytes, &protocol_parameters).unwrap(); assert_eq!(output, output_unpacked); } diff --git a/sdk/tests/types/output/basic.rs b/sdk/tests/types/output/basic.rs index 42268b7afe..8ce4baf1b1 100644 --- a/sdk/tests/types/output/basic.rs +++ b/sdk/tests/types/output/basic.rs @@ -3,7 +3,7 @@ use iota_sdk::types::block::{ output::{BasicOutput, Feature, FoundryId, MinimumOutputAmount, NativeToken, SimpleTokenScheme, TokenId}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::{ address::rand_account_address, output::{ @@ -18,7 +18,7 @@ use pretty_assertions::assert_eq; #[test] fn builder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let foundry_id = FoundryId::build(&rand_account_address(), 0, SimpleTokenScheme::KIND); let address_1 = rand_address_unlock_condition(); let address_2 = rand_address_unlock_condition(); @@ -64,10 +64,10 @@ fn builder() { #[test] fn pack_unpack() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let output = rand_basic_output(protocol_parameters.token_supply()); let bytes = output.pack_to_vec(); - let output_unpacked = BasicOutput::unpack_verified(bytes, &protocol_parameters).unwrap(); + let output_unpacked = BasicOutput::unpack_bytes_verified(bytes, &protocol_parameters).unwrap(); assert_eq!(output, output_unpacked); } diff --git a/sdk/tests/types/output/feature/metadata.rs b/sdk/tests/types/output/feature/metadata.rs index 491e33b506..3cca821857 100644 --- a/sdk/tests/types/output/feature/metadata.rs +++ b/sdk/tests/types/output/feature/metadata.rs @@ -46,7 +46,7 @@ fn serde_roundtrip() { #[test] fn unpack_invalid_order() { assert!(matches!( - MetadataFeature::unpack_verified([3, 1, 99, 0, 0, 1, 98, 0, 0, 1, 97, 0, 0], &()), + MetadataFeature::unpack_bytes_verified([3, 1, 99, 0, 0, 1, 98, 0, 0, 1, 97, 0, 0], &()), Err(UnpackError::Packable(Error::InvalidMetadataFeature(error_msg))) if &error_msg == "unordered map" )); } @@ -54,7 +54,7 @@ fn unpack_invalid_order() { #[test] fn unpack_invalid_length() { assert!(matches!( - MetadataFeature::unpack_verified([vec![1, 1, 33, 0, 32], vec![0u8; 8192]].concat(), &()), + MetadataFeature::unpack_bytes_verified([vec![1, 1, 33, 0, 32], vec![0u8; 8192]].concat(), &()), Err(UnpackError::Packable(Error::InvalidMetadataFeature(len))) if &len == "Out of bounds byte length: 8197" )); } diff --git a/sdk/tests/types/output/foundry.rs b/sdk/tests/types/output/foundry.rs index 8a6b39822c..1057a4bf5c 100644 --- a/sdk/tests/types/output/foundry.rs +++ b/sdk/tests/types/output/foundry.rs @@ -6,7 +6,7 @@ use iota_sdk::types::block::{ unlock_condition::ImmutableAccountAddressUnlockCondition, FoundryId, FoundryOutput, MinimumOutputAmount, NativeToken, SimpleTokenScheme, TokenId, }, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::{ address::rand_account_address, output::{feature::rand_metadata_feature, rand_foundry_output, rand_token_scheme}, @@ -17,7 +17,7 @@ use pretty_assertions::assert_eq; #[test] fn builder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let foundry_id = FoundryId::build(&rand_account_address(), 0, SimpleTokenScheme::KIND); let account_1 = ImmutableAccountAddressUnlockCondition::new(rand_account_address()); let account_2 = ImmutableAccountAddressUnlockCondition::new(rand_account_address()); @@ -65,10 +65,10 @@ fn builder() { #[test] fn pack_unpack() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let output = rand_foundry_output(protocol_parameters.token_supply()); let bytes = output.pack_to_vec(); - let output_unpacked = FoundryOutput::unpack_verified(bytes, &protocol_parameters).unwrap(); + let output_unpacked = FoundryOutput::unpack_bytes_verified(bytes, &protocol_parameters).unwrap(); assert_eq!(output, output_unpacked); } diff --git a/sdk/tests/types/output/nft.rs b/sdk/tests/types/output/nft.rs index 5eb4322ecf..2214df96fd 100644 --- a/sdk/tests/types/output/nft.rs +++ b/sdk/tests/types/output/nft.rs @@ -3,7 +3,7 @@ use iota_sdk::types::block::{ output::{MinimumOutputAmount, NftId, NftOutput}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::output::{ feature::{rand_issuer_feature, rand_sender_feature}, rand_nft_output, @@ -15,7 +15,7 @@ use pretty_assertions::assert_eq; #[test] fn builder() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let address_1 = rand_address_unlock_condition(); let address_2 = rand_address_unlock_condition(); let sender_1 = rand_sender_feature(); @@ -61,10 +61,10 @@ fn builder() { #[test] fn pack_unpack() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let output = rand_nft_output(protocol_parameters.token_supply()); let bytes = output.pack_to_vec(); - let output_unpacked = NftOutput::unpack_verified(bytes, &protocol_parameters).unwrap(); + let output_unpacked = NftOutput::unpack_bytes_verified(bytes, &protocol_parameters).unwrap(); assert_eq!(output, output_unpacked); } diff --git a/sdk/tests/types/output_id.rs b/sdk/tests/types/output_id.rs index 38394a6fab..862aff5ec2 100644 --- a/sdk/tests/types/output_id.rs +++ b/sdk/tests/types/output_id.rs @@ -98,7 +98,7 @@ fn packed_len() { #[test] fn pack_unpack() { let output_id_1 = OutputId::from_str(OUTPUT_ID).unwrap(); - let output_id_2 = OutputId::unpack_verified(output_id_1.pack_to_vec().as_slice(), &()).unwrap(); + let output_id_2 = OutputId::unpack_bytes_verified(output_id_1.pack_to_vec().as_slice(), &()).unwrap(); assert_eq!(output_id_1, output_id_2); } diff --git a/sdk/tests/types/parents.rs b/sdk/tests/types/parents.rs index 8e229e7d2f..cc62b54cc3 100644 --- a/sdk/tests/types/parents.rs +++ b/sdk/tests/types/parents.rs @@ -99,7 +99,7 @@ fn packed_len() { #[test] fn pack_unpack_valid() { let parents_1 = basic::StrongParents::from_vec(rand_block_ids(8)).unwrap(); - let parents_2 = basic::StrongParents::unpack_verified(parents_1.pack_to_vec().as_slice(), &()).unwrap(); + let parents_2 = basic::StrongParents::unpack_bytes_verified(parents_1.pack_to_vec().as_slice(), &()).unwrap(); assert_eq!(parents_1, parents_2); } @@ -120,7 +120,7 @@ fn pack_unpack_invalid_less_than_min() { // ))) // )); assert!(matches!( - basic::StrongParents::unpack_verified(bytes.as_slice(), &()), + basic::StrongParents::unpack_bytes_verified(bytes.as_slice(), &()), Err(UnpackError::Packable(Error::InvalidParentCount)) )); } @@ -141,7 +141,7 @@ fn pack_unpack_invalid_more_than_max() { // ))) // )); assert!(matches!( - basic::StrongParents::unpack_verified(bytes.as_slice(), &()), + basic::StrongParents::unpack_bytes_verified(bytes.as_slice(), &()), Err(UnpackError::Packable(Error::InvalidParentCount)) )); } @@ -153,7 +153,7 @@ fn unpack_invalid_not_sorted() { let inner = VecPrefix::<_, u8>::try_from(inner).unwrap(); let packed = inner.pack_to_vec(); - let parents = basic::StrongParents::unpack_verified(packed.as_slice(), &()); + let parents = basic::StrongParents::unpack_bytes_verified(packed.as_slice(), &()); assert!(matches!( parents, @@ -168,7 +168,7 @@ fn unpack_invalid_not_unique() { let inner = VecPrefix::<_, u8>::try_from(inner).unwrap(); let packed = inner.pack_to_vec(); - let parents = basic::StrongParents::unpack_verified(packed.as_slice(), &()); + let parents = basic::StrongParents::unpack_bytes_verified(packed.as_slice(), &()); assert!(matches!( parents, diff --git a/sdk/tests/types/payload.rs b/sdk/tests/types/payload.rs index 5e1929ce11..82cd4f4706 100644 --- a/sdk/tests/types/payload.rs +++ b/sdk/tests/types/payload.rs @@ -9,7 +9,7 @@ use iota_sdk::types::block::{ signed_transaction::{SignedTransactionPayload, Transaction, TransactionId}, Payload, TaggedDataPayload, }, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::{bytes::rand_bytes, mana::rand_mana_allotment}, signature::{Ed25519Signature, Signature}, unlock::{ReferenceUnlock, SignatureUnlock, Unlock, Unlocks}, @@ -24,7 +24,7 @@ const ED25519_SIGNATURE: &str = "0xc6a40edf9a089f42c18f4ebccb35fe4b578d93b879e99 #[test] fn transaction() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -41,7 +41,7 @@ fn transaction() { .with_inputs(vec![input1, input2]) .add_output(output) .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters) + .finish_with_params(protocol_parameters) .unwrap(); let pub_key_bytes = prefix_hex::decode(ED25519_PUBLIC_KEY).unwrap(); @@ -61,7 +61,7 @@ fn transaction() { assert!(matches!(payload, Payload::SignedTransaction(_))); assert_eq!( payload, - PackableExt::unpack_verified(packed.as_slice(), &protocol_parameters).unwrap() + PackableExt::unpack_bytes_verified(packed.as_slice(), protocol_parameters).unwrap() ); } diff --git a/sdk/tests/types/signed_transaction_payload.rs b/sdk/tests/types/signed_transaction_payload.rs index f624285eca..1b1d24110d 100644 --- a/sdk/tests/types/signed_transaction_payload.rs +++ b/sdk/tests/types/signed_transaction_payload.rs @@ -6,7 +6,7 @@ use iota_sdk::types::block::{ input::{Input, UtxoInput}, output::{unlock_condition::AddressUnlockCondition, BasicOutput, Output}, payload::signed_transaction::{SignedTransactionPayload, Transaction, TransactionId}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::mana::rand_mana_allotment, signature::{Ed25519Signature, Signature}, unlock::{ReferenceUnlock, SignatureUnlock, Unlock, Unlocks}, @@ -28,7 +28,7 @@ fn kind() { // Validate that attempting to construct a `SignedTransactionPayload` with too few unlocks is an error. #[test] fn builder_too_few_unlocks() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); // Construct a transaction with two inputs and one output. let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); @@ -46,7 +46,7 @@ fn builder_too_few_unlocks() { .with_inputs([input1, input2]) .add_output(output) .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters) + .finish_with_params(protocol_parameters) .unwrap(); // Construct a list with a single unlock, whereas we have 2 tx inputs. @@ -65,7 +65,7 @@ fn builder_too_few_unlocks() { // Validate that attempting to construct a `SignedTransactionPayload` with too many unlocks is an error. #[test] fn builder_too_many_unlocks() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); // Construct a transaction with one input and one output. let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); @@ -82,7 +82,7 @@ fn builder_too_many_unlocks() { .add_input(input1) .add_output(output) .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters) + .finish_with_params(protocol_parameters) .unwrap(); // Construct a list of two unlocks, whereas we only have 1 tx input. @@ -104,7 +104,7 @@ fn builder_too_many_unlocks() { #[test] fn pack_unpack_valid() { // Construct a transaction with two inputs and one output. - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -121,7 +121,7 @@ fn pack_unpack_valid() { .with_inputs([input1, input2]) .add_output(output) .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters) + .finish_with_params(protocol_parameters) .unwrap(); // Construct a list of two unlocks, whereas we only have 1 tx input. @@ -138,13 +138,13 @@ fn pack_unpack_valid() { assert_eq!(packed_tx_payload.len(), tx_payload.packed_len()); assert_eq!( tx_payload, - PackableExt::unpack_verified(packed_tx_payload.as_slice(), &protocol_parameters).unwrap() + PackableExt::unpack_bytes_verified(packed_tx_payload.as_slice(), protocol_parameters).unwrap() ); } #[test] fn getters() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); // Construct a transaction with two inputs and one output. let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); @@ -162,7 +162,7 @@ fn getters() { .with_inputs([input1, input2]) .add_output(output) .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters) + .finish_with_params(protocol_parameters) .unwrap(); // Construct a list of two unlocks, whereas we only have 1 tx input. diff --git a/sdk/tests/types/slot.rs b/sdk/tests/types/slot.rs index 711824baea..da2f009c42 100644 --- a/sdk/tests/types/slot.rs +++ b/sdk/tests/types/slot.rs @@ -26,7 +26,7 @@ fn slot_commitment_id_index() { assert_eq!(prefix_hex::encode(&commitment_bytes), fixture.bytes); assert_eq!( fixture.commitment, - SlotCommitment::unpack_verified(commitment_bytes, &()).unwrap() + SlotCommitment::unpack_bytes_verified(commitment_bytes, &()).unwrap() ); assert_eq!(commitment_id, fixture.id); assert_eq!(commitment_id.slot_index(), fixture.commitment.slot()); diff --git a/sdk/tests/types/tagged_data_payload.rs b/sdk/tests/types/tagged_data_payload.rs index e02934f949..b5c84ab489 100644 --- a/sdk/tests/types/tagged_data_payload.rs +++ b/sdk/tests/types/tagged_data_payload.rs @@ -84,7 +84,7 @@ fn packed_len() { fn pack_unpack_valid() { let tagged_data_1 = TaggedDataPayload::new(rand_bytes(32), [0x42, 0xff, 0x84, 0xa2, 0x42, 0xff, 0x84, 0xa2]).unwrap(); - let tagged_data_2 = TaggedDataPayload::unpack_verified(tagged_data_1.pack_to_vec().as_slice(), &()).unwrap(); + let tagged_data_2 = TaggedDataPayload::unpack_bytes_verified(tagged_data_1.pack_to_vec().as_slice(), &()).unwrap(); assert_eq!(tagged_data_1.tag(), tagged_data_2.tag()); assert_eq!(tagged_data_1.data(), tagged_data_2.data()); @@ -92,7 +92,8 @@ fn pack_unpack_valid() { #[test] fn unpack_valid_tag_length_min() { - let payload = TaggedDataPayload::unpack_verified([0x00, 0x00, 0x00, 0x00, 0x00, 0x00].as_slice(), &()).unwrap(); + let payload = + TaggedDataPayload::unpack_bytes_verified([0x00, 0x00, 0x00, 0x00, 0x00, 0x00].as_slice(), &()).unwrap(); assert!(payload.tag().is_empty()); } @@ -100,7 +101,7 @@ fn unpack_valid_tag_length_min() { #[test] fn unpack_invalid_tag_length_more_than_max() { assert!(matches!( - TaggedDataPayload::unpack_verified( + TaggedDataPayload::unpack_bytes_verified( [ 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -119,7 +120,7 @@ fn unpack_invalid_tag_length_more_than_max() { #[test] fn unpack_invalid_data_length_more_than_max() { assert!(matches!( - TaggedDataPayload::unpack_verified([0x02, 0x00, 0x00, 0x35, 0x82, 0x00, 0x00], &()), + TaggedDataPayload::unpack_bytes_verified([0x02, 0x00, 0x00, 0x35, 0x82, 0x00, 0x00], &()), Err(UnpackError::Packable(Error::InvalidTaggedDataLength( TryIntoBoundedU32Error::Invalid(33333) ))) diff --git a/sdk/tests/types/transaction.rs b/sdk/tests/types/transaction.rs index e32da6a7a2..be39e9d931 100644 --- a/sdk/tests/types/transaction.rs +++ b/sdk/tests/types/transaction.rs @@ -17,7 +17,7 @@ use iota_sdk::types::block::{ }, Payload, }, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::{mana::rand_mana_allotment, payload::rand_tagged_data_payload}, signature::{Ed25519Signature, Signature}, unlock::{ReferenceUnlock, SignatureUnlock, Unlock, Unlocks}, @@ -34,7 +34,7 @@ const ED25519_SIGNATURE: &str = "0xc6a40edf9a089f42c18f4ebccb35fe4b578d93b879e99 #[test] fn build_valid() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -50,15 +50,15 @@ fn build_valid() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs([input1, input2]) .add_output(output) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(transaction.is_ok()); } #[test] fn build_valid_with_payload() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -75,15 +75,15 @@ fn build_valid_with_payload() { .with_inputs([input1, input2]) .add_output(output) .with_payload(rand_tagged_data_payload()) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(transaction.is_ok()); } #[test] fn build_valid_add_inputs_outputs() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -99,15 +99,15 @@ fn build_valid_add_inputs_outputs() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs([input1, input2]) .add_output(output) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(transaction.is_ok()); } #[test] fn build_invalid_payload_kind() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); // Construct a transaction with two inputs and one output. let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); @@ -123,8 +123,8 @@ fn build_invalid_payload_kind() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs([input1.clone(), input2.clone()]) .add_output(output.clone()) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters) + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters) .unwrap(); // Construct a list of two unlocks, whereas we only have 1 tx input. @@ -141,15 +141,15 @@ fn build_invalid_payload_kind() { .with_inputs(vec![input1, input2]) .add_output(output) .with_payload(tx_payload) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(matches!(transaction, Err(Error::InvalidPayloadKind(1)))); } #[test] fn build_invalid_input_count_low() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let address = Address::from(Ed25519Address::from_str(ED25519_ADDRESS_1).unwrap()); let amount = 1_000_000; let output = Output::Basic( @@ -161,8 +161,8 @@ fn build_invalid_input_count_low() { let transaction = Transaction::builder(protocol_parameters.network_id()) .add_output(output) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(matches!( transaction, @@ -172,7 +172,7 @@ fn build_invalid_input_count_low() { #[test] fn build_invalid_input_count_high() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input = Input::Utxo(UtxoInput::new(transaction_id, 0)); let address = Address::from(Ed25519Address::from_str(ED25519_ADDRESS_1).unwrap()); @@ -187,8 +187,8 @@ fn build_invalid_input_count_high() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs(vec![input; 129]) .add_output(output) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(matches!( transaction, @@ -198,14 +198,14 @@ fn build_invalid_input_count_high() { #[test] fn build_invalid_output_count_low() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input = Input::Utxo(UtxoInput::new(transaction_id, 0)); let transaction = Transaction::builder(protocol_parameters.network_id()) .add_input(input) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(matches!( transaction, @@ -215,7 +215,7 @@ fn build_invalid_output_count_low() { #[test] fn build_invalid_output_count_high() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input = Input::Utxo(UtxoInput::new(transaction_id, 0)); let address = Address::from(Ed25519Address::from_str(ED25519_ADDRESS_1).unwrap()); @@ -230,8 +230,8 @@ fn build_invalid_output_count_high() { let transaction = Transaction::builder(protocol_parameters.network_id()) .add_input(input) .with_outputs(vec![output; 129]) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(matches!( transaction, @@ -241,7 +241,7 @@ fn build_invalid_output_count_high() { #[test] fn build_invalid_duplicate_utxo() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input = Input::Utxo(UtxoInput::new(transaction_id, 0)); let address = Address::from(Ed25519Address::from_str(ED25519_ADDRESS_1).unwrap()); @@ -256,15 +256,15 @@ fn build_invalid_duplicate_utxo() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs(vec![input; 2]) .add_output(output) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(matches!(transaction, Err(Error::DuplicateUtxo(_)))); } #[test] fn build_invalid_accumulated_output() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input = Input::Utxo(UtxoInput::new(transaction_id, 0)); @@ -291,15 +291,15 @@ fn build_invalid_accumulated_output() { let transaction = Transaction::builder(protocol_parameters.network_id()) .add_input(input) .with_outputs([output1, output2]) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(matches!(transaction, Err(Error::InvalidTransactionAmountSum(_)))); } #[test] fn getters() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -317,8 +317,8 @@ fn getters() { .with_inputs([input1, input2]) .with_outputs(outputs.clone()) .with_payload(payload.clone()) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters) + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters) .unwrap(); assert_eq!(transaction.outputs(), outputs.as_slice()); @@ -327,7 +327,7 @@ fn getters() { #[test] fn duplicate_output_nft() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -346,8 +346,8 @@ fn duplicate_output_nft() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs([input1, input2]) .with_outputs([basic, nft.clone(), nft]) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(matches!( transaction, @@ -357,7 +357,7 @@ fn duplicate_output_nft() { #[test] fn duplicate_output_nft_null() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -376,15 +376,15 @@ fn duplicate_output_nft_null() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs([input1, input2]) .with_outputs([basic, nft.clone(), nft]) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(transaction.is_ok()); } #[test] fn duplicate_output_account() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -403,8 +403,8 @@ fn duplicate_output_account() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs([input1, input2]) .with_outputs([basic, account.clone(), account]) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(matches!( transaction, @@ -414,7 +414,7 @@ fn duplicate_output_account() { #[test] fn duplicate_output_foundry() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -439,8 +439,8 @@ fn duplicate_output_foundry() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs([input1, input2]) .with_outputs([basic, foundry.clone(), foundry]) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters); + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters); assert!(matches!( transaction, @@ -450,7 +450,7 @@ fn duplicate_output_foundry() { #[test] fn transactions_capabilities() { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -465,8 +465,8 @@ fn transactions_capabilities() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs(vec![input1, input2]) .add_output(output) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters) + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters) .unwrap(); let mut capabilities = transaction.capabilities().clone(); diff --git a/sdk/tests/types/transaction_id.rs b/sdk/tests/types/transaction_id.rs index 4ac3265b21..87eb82784b 100644 --- a/sdk/tests/types/transaction_id.rs +++ b/sdk/tests/types/transaction_id.rs @@ -45,7 +45,7 @@ fn pack_unpack_valid() { assert_eq!( transaction_id, - PackableExt::unpack_verified(packed_transaction_id.as_slice(), &()).unwrap() + PackableExt::unpack_bytes_verified(packed_transaction_id.as_slice(), &()).unwrap() ); } diff --git a/sdk/tests/types/unlock/account.rs b/sdk/tests/types/unlock/account.rs index 083660c18a..84abf650f5 100644 --- a/sdk/tests/types/unlock/account.rs +++ b/sdk/tests/types/unlock/account.rs @@ -52,7 +52,7 @@ fn packed_len() { #[test] fn pack_unpack_valid() { let unlock_1 = AccountUnlock::new(42).unwrap(); - let unlock_2 = AccountUnlock::unpack_verified(unlock_1.pack_to_vec().as_slice(), &()).unwrap(); + let unlock_2 = AccountUnlock::unpack_bytes_verified(unlock_1.pack_to_vec().as_slice(), &()).unwrap(); assert_eq!(unlock_1, unlock_2); } diff --git a/sdk/tests/types/unlock/nft.rs b/sdk/tests/types/unlock/nft.rs index 70204ae4ca..707bbf66c0 100644 --- a/sdk/tests/types/unlock/nft.rs +++ b/sdk/tests/types/unlock/nft.rs @@ -52,7 +52,7 @@ fn packed_len() { #[test] fn pack_unpack_valid() { let unlock_1 = NftUnlock::new(42).unwrap(); - let unlock_2 = NftUnlock::unpack_verified(unlock_1.pack_to_vec().as_slice(), &()).unwrap(); + let unlock_2 = NftUnlock::unpack_bytes_verified(unlock_1.pack_to_vec().as_slice(), &()).unwrap(); assert_eq!(unlock_1, unlock_2); } diff --git a/sdk/tests/types/unlock/reference.rs b/sdk/tests/types/unlock/reference.rs index 6938d60b12..1f887a80df 100644 --- a/sdk/tests/types/unlock/reference.rs +++ b/sdk/tests/types/unlock/reference.rs @@ -52,7 +52,7 @@ fn packed_len() { #[test] fn pack_unpack_valid() { let reference_1 = ReferenceUnlock::try_from(42).unwrap(); - let reference_2 = ReferenceUnlock::unpack_verified(reference_1.pack_to_vec().as_slice(), &()).unwrap(); + let reference_2 = ReferenceUnlock::unpack_bytes_verified(reference_1.pack_to_vec().as_slice(), &()).unwrap(); assert_eq!(reference_1, reference_2); } @@ -60,7 +60,7 @@ fn pack_unpack_valid() { #[test] fn pack_unpack_invalid_index() { assert!(matches!( - ReferenceUnlock::unpack_verified([0x2a, 0x2a], &()), + ReferenceUnlock::unpack_bytes_verified([0x2a, 0x2a], &()), Err(UnpackError::Packable(Error::InvalidReferenceIndex(InvalidBoundedU16( 10794 )))) diff --git a/sdk/tests/types/unlock/signature.rs b/sdk/tests/types/unlock/signature.rs index 0833a13616..64dddd006b 100644 --- a/sdk/tests/types/unlock/signature.rs +++ b/sdk/tests/types/unlock/signature.rs @@ -27,7 +27,7 @@ fn packed_len() { fn pack_unpack_valid_ed25519() { let signature_1 = SignatureUnlock::from(rand_signature()); let signature_bytes = signature_1.pack_to_vec(); - let signature_2 = SignatureUnlock::unpack_verified(signature_bytes.as_slice(), &()).unwrap(); + let signature_2 = SignatureUnlock::unpack_bytes_verified(signature_bytes.as_slice(), &()).unwrap(); assert_eq!(signature_bytes[0], 0); assert_eq!(signature_1, signature_2); @@ -36,7 +36,7 @@ fn pack_unpack_valid_ed25519() { #[test] fn pack_unpack_invalid_kind() { assert!(matches!( - SignatureUnlock::unpack_verified( + SignatureUnlock::unpack_bytes_verified( [ 1, 111, 225, 221, 28, 247, 253, 234, 110, 187, 52, 129, 153, 130, 84, 26, 7, 226, 27, 212, 145, 96, 151, 196, 124, 135, 176, 31, 48, 0, 213, 200, 82, 227, 169, 21, 179, 253, 115, 184, 209, 107, 138, 0, diff --git a/sdk/tests/wallet/address_generation.rs b/sdk/tests/wallet/address_generation.rs index 51fa73587c..ea2dc0c775 100644 --- a/sdk/tests/wallet/address_generation.rs +++ b/sdk/tests/wallet/address_generation.rs @@ -15,7 +15,7 @@ use iota_sdk::{ constants::IOTA_COIN_TYPE, secret::{mnemonic::MnemonicSecretManager, SecretManager}, }, - types::block::address::ToBech32Ext, + types::block::{address::ToBech32Ext, protocol::iota_mainnet_protocol_parameters}, wallet::{ClientOptions, Result, Wallet}, }; use pretty_assertions::assert_eq; @@ -27,7 +27,9 @@ async fn wallet_address_generation_mnemonic() -> Result<()> { let storage_path = "test-storage/wallet_address_generation_mnemonic"; setup(storage_path)?; - let client_options = ClientOptions::new().with_node(NODE_LOCAL)?; + let client_options = ClientOptions::new() + .with_node(NODE_LOCAL)? + .with_protocol_parameters(iota_mainnet_protocol_parameters().clone()); let secret_manager = MnemonicSecretManager::try_from_mnemonic(DEFAULT_MNEMONIC.to_owned())?; #[allow(unused_mut)] @@ -68,7 +70,9 @@ async fn wallet_address_generation_stronghold() -> Result<()> { .store_mnemonic(Mnemonic::from(DEFAULT_MNEMONIC.to_string())) .await?; - let client_options = ClientOptions::new().with_node(NODE_LOCAL)?; + let client_options = ClientOptions::new() + .with_node(NODE_LOCAL)? + .with_protocol_parameters(iota_mainnet_protocol_parameters().clone()); #[allow(unused_mut)] let mut wallet_builder = Wallet::builder() .with_secret_manager(SecretManager::Stronghold(secret_manager)) diff --git a/sdk/tests/wallet/balance.rs b/sdk/tests/wallet/balance.rs index 8e10ed9773..ad39dbb4a6 100644 --- a/sdk/tests/wallet/balance.rs +++ b/sdk/tests/wallet/balance.rs @@ -13,6 +13,7 @@ use pretty_assertions::assert_eq; use crate::wallet::common::{make_wallet, request_funds, setup, tear_down}; +#[cfg(all(feature = "rand", feature = "protocol_parameters_samples"))] #[test] fn rand_balance_add_assign() { use iota_sdk::U256; diff --git a/sdk/tests/wallet/common/mod.rs b/sdk/tests/wallet/common/mod.rs index 7575c6a6c0..f431be61b8 100644 --- a/sdk/tests/wallet/common/mod.rs +++ b/sdk/tests/wallet/common/mod.rs @@ -11,6 +11,7 @@ use iota_sdk::{ secret::{mnemonic::MnemonicSecretManager, SecretManager}, Client, }, + types::block::protocol::iota_mainnet_protocol_parameters, wallet::{ClientOptions, Result, Wallet}, }; @@ -34,7 +35,9 @@ pub(crate) async fn make_wallet( mnemonic: impl Into>, node: Option<&str>, ) -> Result { - let client_options = ClientOptions::new().with_node(node.unwrap_or(NODE_LOCAL))?; + let client_options = ClientOptions::new() + .with_node(node.unwrap_or(NODE_LOCAL))? + .with_protocol_parameters(iota_mainnet_protocol_parameters().clone()); let secret_manager = MnemonicSecretManager::try_from_mnemonic( mnemonic.into().unwrap_or_else(|| Client::generate_mnemonic().unwrap()), )?; diff --git a/sdk/tests/wallet/core.rs b/sdk/tests/wallet/core.rs index b651655747..9d2315a8f3 100644 --- a/sdk/tests/wallet/core.rs +++ b/sdk/tests/wallet/core.rs @@ -14,10 +14,11 @@ use iota_sdk::{ secret::{mnemonic::MnemonicSecretManager, SecretManager}, }, crypto::keys::bip44::Bip44, - types::block::address::Bech32Address, + types::block::{address::Bech32Address, protocol::iota_mainnet_protocol_parameters}, wallet::{ClientOptions, Result, Wallet}, }; use pretty_assertions::assert_eq; +#[cfg(feature = "storage")] use url::Url; #[cfg(feature = "storage")] @@ -97,14 +98,12 @@ async fn changed_bip_path() -> Result<()> { .finish() .await; - let _mismatch_err: Result = Err(Error::BipPathMismatch { - new_bip_path: Some(Bip44::new(IOTA_COIN_TYPE)), - old_bip_path: Some(Bip44::new(SHIMMER_COIN_TYPE)), - }); - // Building the wallet with another coin type needs to return an error, because a different coin type was used in // the existing account - assert!(matches!(result, _mismatch_err)); + assert!(matches!(result, Err(Error::BipPathMismatch { + new_bip_path: Some(new_bip_path), + old_bip_path: Some(old_bip_path), + }) if new_bip_path == Bip44::new(IOTA_COIN_TYPE) && old_bip_path == Bip44::new(SHIMMER_COIN_TYPE))); // Building the wallet with the same coin type still works assert!( @@ -143,7 +142,9 @@ async fn iota_coin_type() -> Result<()> { let storage_path = "test-storage/iota_coin_type"; setup(storage_path)?; - let client_options = ClientOptions::new().with_node(NODE_LOCAL)?; + let client_options = ClientOptions::new() + .with_node(NODE_LOCAL)? + .with_protocol_parameters(iota_mainnet_protocol_parameters().clone()); let secret_manager = MnemonicSecretManager::try_from_mnemonic(DEFAULT_MNEMONIC.to_owned())?; #[allow(unused_mut)] diff --git a/sdk/tests/wallet/events.rs b/sdk/tests/wallet/events.rs index 30ddb04ee7..e3460d2b3b 100644 --- a/sdk/tests/wallet/events.rs +++ b/sdk/tests/wallet/events.rs @@ -11,7 +11,7 @@ use iota_sdk::{ OutputIdProof, }, payload::signed_transaction::{Transaction, TransactionHash, TransactionId}, - protocol::protocol_parameters, + protocol::iota_mainnet_protocol_parameters, rand::{ mana::rand_mana_allotment, output::{rand_basic_output, rand_output_metadata}, @@ -90,7 +90,7 @@ fn wallet_events_serde() { )); { - let protocol_parameters = protocol_parameters(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let transaction_id = TransactionId::new(prefix_hex::decode(TRANSACTION_ID).unwrap()); let input1 = Input::Utxo(UtxoInput::new(transaction_id, 0)); let input2 = Input::Utxo(UtxoInput::new(transaction_id, 1)); @@ -106,8 +106,8 @@ fn wallet_events_serde() { let transaction = Transaction::builder(protocol_parameters.network_id()) .with_inputs(vec![input1, input2]) .add_output(output) - .add_mana_allotment(rand_mana_allotment(&protocol_parameters)) - .finish_with_params(&protocol_parameters) + .add_mana_allotment(rand_mana_allotment(protocol_parameters)) + .finish_with_params(protocol_parameters) .unwrap(); assert_serde_eq(WalletEvent::TransactionProgress( diff --git a/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs b/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs index 1bd1747ecb..526d305de3 100644 --- a/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs +++ b/sdk/tests/wallet/migrate_stronghold_snapshot_v2_to_v3.rs @@ -13,6 +13,7 @@ use iota_sdk::{ Error as ClientError, }, crypto::keys::bip44::Bip44, + types::block::protocol::iota_mainnet_protocol_parameters, wallet::{ClientOptions, Error as WalletError, Wallet}, }; use pretty_assertions::assert_eq; @@ -25,6 +26,7 @@ const PBKDF_ITER: u32 = 100; #[tokio::test] async fn stronghold_snapshot_v2_v3_migration() { iota_stronghold::engine::snapshot::try_set_encrypt_work_factor(0).unwrap(); + let protocol_parameters = iota_mainnet_protocol_parameters(); let storage_path = "test-storage/stronghold_snapshot_v2_v3_migration"; setup(storage_path).unwrap(); @@ -87,7 +89,12 @@ async fn stronghold_snapshot_v2_v3_migration() { let restore_manager = Wallet::builder() .with_storage_path("test-storage/stronghold_snapshot_v2_v3_migration") .with_secret_manager(stronghold_secret_manager) - .with_client_options(ClientOptions::new().with_node(NODE_LOCAL).unwrap()) + .with_client_options( + ClientOptions::new() + .with_node(NODE_LOCAL) + .unwrap() + .with_protocol_parameters(protocol_parameters.clone()), + ) // Build with a different coin type, to check if it gets replaced by the one from the backup .with_bip_path(Bip44::new(IOTA_COIN_TYPE)) .finish() From b4daa5307fad64fd8a7db5fbce8fe92cd8d2f25e Mon Sep 17 00:00:00 2001 From: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Date: Fri, 23 Feb 2024 11:00:53 +0100 Subject: [PATCH 3/9] Python: rework OutputId so it works in deserialization (#2048) * Python: rework OutputId so it works in deserialization * Validate that output id has valid hex chars --------- Co-authored-by: Thibault Martinez --- .../iota_sdk/client/_node_indexer_api.py | 10 +-- bindings/python/iota_sdk/client/responses.py | 2 +- bindings/python/iota_sdk/types/output_id.py | 68 ++++++++++--------- bindings/python/iota_sdk/utils.py | 2 +- bindings/python/tests/test_api_responses.py | 20 +++--- bindings/python/tests/test_offline.py | 36 ++++++---- 6 files changed, 74 insertions(+), 64 deletions(-) diff --git a/bindings/python/iota_sdk/client/_node_indexer_api.py b/bindings/python/iota_sdk/client/_node_indexer_api.py index ef93bfb1c8..6b9f04c7cd 100644 --- a/bindings/python/iota_sdk/client/_node_indexer_api.py +++ b/bindings/python/iota_sdk/client/_node_indexer_api.py @@ -279,7 +279,7 @@ def account_output_id(self, account_id: HexStr) -> OutputId: Returns: The output ID of the account output. """ - return OutputId.from_string(self._call_method('accountOutputId', { + return OutputId(self._call_method('accountOutputId', { 'accountId': account_id })) @@ -302,7 +302,7 @@ def anchor_output_id(self, anchor_id: HexStr) -> OutputId: Returns: The output ID of the anchor output. """ - return OutputId.from_string(self._call_method('anchorOutputId', { + return OutputId(self._call_method('anchorOutputId', { 'anchorId': anchor_id })) @@ -325,7 +325,7 @@ def delegation_output_id(self, delegation_id: HexStr) -> OutputId: Returns: The output ID of the delegation output. """ - return OutputId.from_string(self._call_method('delegationOutputId', { + return OutputId(self._call_method('delegationOutputId', { 'delegationId': delegation_id })) @@ -348,7 +348,7 @@ def foundry_output_id(self, foundry_id: HexStr) -> OutputId: Returns: The output ID of the foundry output. """ - return OutputId.from_string(self._call_method('foundryOutputId', { + return OutputId(self._call_method('foundryOutputId', { 'foundryId': foundry_id })) @@ -371,6 +371,6 @@ def nft_output_id(self, nft_id: HexStr) -> OutputId: Returns: The output ID of the NFT output. """ - return OutputId.from_string(self._call_method('nftOutputId', { + return OutputId(self._call_method('nftOutputId', { 'nftId': nft_id })) diff --git a/bindings/python/iota_sdk/client/responses.py b/bindings/python/iota_sdk/client/responses.py index fbf3a76802..bf7c7fc581 100644 --- a/bindings/python/iota_sdk/client/responses.py +++ b/bindings/python/iota_sdk/client/responses.py @@ -35,7 +35,7 @@ def __init__(self, output_dict: Dict): self.committed_slot = output_dict["committedSlot"] self.page_size = output_dict["pageSize"] self.cursor = output_dict["cursor"] - self.items = [OutputId.from_string( + self.items = [OutputId( output_id) for output_id in output_dict["items"]] diff --git a/bindings/python/iota_sdk/types/output_id.py b/bindings/python/iota_sdk/types/output_id.py index 81a49cf512..1f9c57c7c4 100644 --- a/bindings/python/iota_sdk/types/output_id.py +++ b/bindings/python/iota_sdk/types/output_id.py @@ -2,64 +2,68 @@ # SPDX-License-Identifier: Apache-2.0 from dataclasses import dataclass - -from iota_sdk.types.common import HexStr, json +from iota_sdk.types.common import json from iota_sdk.types.output import Output from iota_sdk.types.transaction_id import TransactionId -class OutputId(dict): +class OutputId(str): """Represents an output ID. Attributes: output_id: The unique id of an output. - transaction_id: The transaction id associated with the output. - output_index: The index of the output within a transaction. - """ - def __init__(self, transaction_id: TransactionId, output_index: int): + def __new__(cls, output_id: str): """Initialize OutputId """ - if len(transaction_id) != 74: + if len(output_id) != 78: raise ValueError( - 'transaction_id length must be 74 characters with 0x prefix') - if not transaction_id.startswith('0x'): - raise ValueError('transaction_id must start with 0x') + 'output_id length must be 78 characters with 0x prefix') + if not output_id.startswith('0x'): + raise ValueError('output_id must start with 0x') # Validate that it has only valid hex characters - int(transaction_id[2:], 16) - output_index_hex = (output_index).to_bytes(2, "little").hex() - self.output_id = transaction_id + output_index_hex - self.transaction_id = transaction_id - self.output_index = output_index + int(output_id[2:], 16) + instance = super().__new__(cls, output_id) + return instance @classmethod - def from_string(cls, output_id: HexStr): - """Creates an `OutputId` instance from a `HexStr`. + def from_transaction_id_and_output_index(cls, transaction_id: TransactionId, output_index: int): + """Creates an `OutputId` instance from its transaction id and output index. Args: - output_id: The unique id of an output as a hex string. + transaction_id: The transaction id associated with the output. + output_index: The index of the output within a transaction. Returns: OutputId: The unique id of an output. """ - obj = cls.__new__(cls) - super(OutputId, obj).__init__() - if len(output_id) != 78: + if len(transaction_id) != 74: raise ValueError( - 'output_id length must be 78 characters with 0x prefix') - if not output_id.startswith('0x'): + 'transaction_id length must be 74 characters with 0x prefix') + if not transaction_id.startswith('0x'): raise ValueError('transaction_id must start with 0x') # Validate that it has only valid hex characters - int(output_id[2:], 16) - obj.output_id = output_id - obj.transaction_id = TransactionId(output_id[:74]) - obj.output_index = int.from_bytes( - bytes.fromhex(output_id[74:]), 'little') - return obj + int(transaction_id[2:], 16) + output_index_hex = (output_index).to_bytes(2, "little").hex() + return OutputId(transaction_id + output_index_hex) - def __repr__(self): - return self.output_id + def transaction_id(self) -> TransactionId: + """Returns the TransactionId of an OutputId. + """ + return TransactionId(self[:74]) + + def output_index(self) -> int: + """Returns the output index of an OutputId. + """ + return int.from_bytes( + bytes.fromhex(self[74:]), 'little') + + @classmethod + def from_dict(cls, output_id_dict: dict): + """Init an OutputId from a dict. + """ + return OutputId(output_id_dict) @json diff --git a/bindings/python/iota_sdk/utils.py b/bindings/python/iota_sdk/utils.py index 7154a37a82..cd6eb6bef6 100644 --- a/bindings/python/iota_sdk/utils.py +++ b/bindings/python/iota_sdk/utils.py @@ -160,7 +160,7 @@ def compute_output_id(transaction_id: TransactionId, index: int) -> OutputId: """Compute the output id from transaction id and output index. """ - return OutputId.from_string(_call_method('computeOutputId', { + return OutputId(_call_method('computeOutputId', { 'id': transaction_id, 'index': index, })) diff --git a/bindings/python/tests/test_api_responses.py b/bindings/python/tests/test_api_responses.py index 3b5fab3a18..359fad7db7 100644 --- a/bindings/python/tests/test_api_responses.py +++ b/bindings/python/tests/test_api_responses.py @@ -3,7 +3,7 @@ from typing import Generic, TypeVar from json import load, loads, dumps -from iota_sdk import RoutesResponse, CongestionResponse, ManaRewardsResponse, ValidatorResponse, CommitteeResponse, IssuanceBlockHeaderResponse, Block, OutputResponse, SlotCommitment +from iota_sdk import RoutesResponse, CongestionResponse, ManaRewardsResponse, ValidatorResponse, CommitteeResponse, IssuanceBlockHeaderResponse, Block, OutputMetadata, OutputResponse, SlotCommitment, UtxoChangesResponse, UtxoChangesFullResponse base_path = '../../sdk/tests/types/api/fixtures/' @@ -69,11 +69,10 @@ def test_api_response(cls_type: Generic[T], path: str): test_api_response( OutputResponse, "get-outputs-by-id-response-example.json") # GET /api/core/v3/outputs/{outputId}/metadata - # TODO: enable when https://github.com/iotaledger/iota-sdk/issues/2020 is fixed - # test_api_response( - # OutputMetadata, "get-output-metadata-by-id-response-unspent-example.json") - # test_api_response( - # OutputMetadata, "get-output-metadata-by-id-response-spent-example.json") + test_api_response( + OutputMetadata, "get-output-metadata-by-id-response-unspent-example.json") + test_api_response( + OutputMetadata, "get-output-metadata-by-id-response-spent-example.json") # GET /api/core/v3/outputs/{outputId}/full # TODO: enable when OutputWithMetadata is updated with OutputIdProof https://github.com/iotaledger/iota-sdk/issues/2021 # test_api_response(OutputWithMetadata, @@ -85,9 +84,8 @@ def test_api_response(cls_type: Generic[T], path: str): # GET /api/core/v3/commitments/{commitmentId} test_api_response(SlotCommitment, "get-commitment-response-example.json") # GET /api/core/v3/commitments/{commitmentId}/utxo-changes - # TODO: enable when https://github.com/iotaledger/iota-sdk/issues/2020 is fixed - # test_api_response(UtxoChangesResponse, - # "get-utxo-changes-response-example.json") + test_api_response(UtxoChangesResponse, + "get-utxo-changes-response-example.json") # GET /api/core/v3/commitments/{commitmentId}/utxo-changes/full - # test_api_response(UtxoChangesFullResponse, - # "get-utxo-changes-full-response-example.json") + test_api_response(UtxoChangesFullResponse, + "get-utxo-changes-full-response-example.json") diff --git a/bindings/python/tests/test_offline.py b/bindings/python/tests/test_offline.py index 5678b7b60e..b1c393f08e 100644 --- a/bindings/python/tests/test_offline.py +++ b/bindings/python/tests/test_offline.py @@ -60,35 +60,43 @@ def test_output_id(self): transaction_id = TransactionId( '0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64900000000') output_index = 42 - output_id = OutputId(transaction_id, output_index) - assert repr( - output_id) == '0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649000000002a00' + output_id = OutputId.from_transaction_id_and_output_index( + transaction_id, output_index) + assert str(output_id + ) == "0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649000000002a00" - new_output_id = OutputId.from_string( + new_output_id = OutputId( '0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649000000002a00') - assert repr( - new_output_id) == '0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649000000002a00' - assert new_output_id.transaction_id == transaction_id - assert new_output_id.output_index == output_index + assert str(new_output_id + ) == '0x52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649000000002a00' + assert new_output_id.transaction_id() == transaction_id + assert new_output_id.output_index() == output_index + + output_id_invalid_hex_char = '0xz2fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649000000002a00' + with self.assertRaises(ValueError): + OutputId(output_id_invalid_hex_char) transaction_id_missing_0x_prefix = '52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64900000000' with self.assertRaises(ValueError): - OutputId(transaction_id_missing_0x_prefix, output_index) + OutputId.from_transaction_id_and_output_index( + transaction_id_missing_0x_prefix, output_index) transaction_id__invalid_hex_prefix = '0052fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64900000000' with self.assertRaises(ValueError): - OutputId(transaction_id__invalid_hex_prefix, output_index) + OutputId.from_transaction_id_and_output_index( + transaction_id__invalid_hex_prefix, output_index) transaction_id_invalid_hex_char = '0xz2fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64900000000' with self.assertRaises(ValueError): - OutputId(transaction_id_invalid_hex_char, output_index) + OutputId.from_transaction_id_and_output_index( + transaction_id_invalid_hex_char, output_index) output_id_missing_0x_prefix = '52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c6492a000000000000' with self.assertRaises(ValueError): - OutputId.from_string(output_id_missing_0x_prefix) + OutputId(output_id_missing_0x_prefix) output_id_invalid_hex_char = '0xz2fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c6492a000000000000' with self.assertRaises(ValueError): - OutputId.from_string(output_id_invalid_hex_char) + OutputId(output_id_invalid_hex_char) output_id_invalid_hex_prefix = '0052fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c6492a000000000000' with self.assertRaises(ValueError): - OutputId.from_string(output_id_invalid_hex_prefix) + OutputId(output_id_invalid_hex_prefix) def test_hex_utf8(): From 8abaebf3773614130e0ba597cbd24400816c1f87 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Fri, 23 Feb 2024 14:51:00 +0100 Subject: [PATCH 4/9] Replace creation slot with commitment slot in more places (#2056) --- .../api/block_builder/input_selection/mod.rs | 2 +- .../input_selection/requirement/amount.rs | 23 ++++++++++++------- .../input_selection/requirement/mana.rs | 2 +- .../operations/transaction/input_selection.rs | 4 ++-- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/sdk/src/client/api/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index b00e5dbd4e..f6a30bb72a 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -284,7 +284,7 @@ impl InputSelection { let inputs_data = Self::sort_input_signing_data( self.selected_inputs, - self.creation_slot, + self.latest_slot_commitment_id.slot_index(), self.protocol_parameters.committable_age_range(), )?; diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs b/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs index 9a45039fb6..801e962951 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs @@ -45,7 +45,8 @@ impl InputSelection { for selected_input in &self.selected_inputs { inputs_sum += selected_input.output.amount(); - if let Some(sdruc) = sdruc_not_expired(&selected_input.output, self.creation_slot) { + if let Some(sdruc) = sdruc_not_expired(&selected_input.output, self.latest_slot_commitment_id.slot_index()) + { *inputs_sdr.entry(sdruc.return_address().clone()).or_default() += sdruc.amount(); } } @@ -139,7 +140,9 @@ impl AmountSelection { continue; } - if let Some(sdruc) = sdruc_not_expired(&input.output, input_selection.creation_slot) { + if let Some(sdruc) = + sdruc_not_expired(&input.output, input_selection.latest_slot_commitment_id.slot_index()) + { // Skip if no additional amount is made available if input.output.amount() == sdruc.amount() { continue; @@ -201,9 +204,11 @@ impl InputSelection { base_inputs: impl Iterator + Clone, amount_selection: &mut AmountSelection, ) -> Result { + let slot_index = self.latest_slot_commitment_id.slot_index(); + // No native token, expired SDRUC. let inputs = base_inputs.clone().filter(|input| { - input.output.native_token().is_none() && sdruc_not_expired(&input.output, self.creation_slot).is_none() + input.output.native_token().is_none() && sdruc_not_expired(&input.output, slot_index).is_none() }); if amount_selection.fulfil(self, inputs)? { @@ -212,7 +217,7 @@ impl InputSelection { // No native token, unexpired SDRUC. let inputs = base_inputs.clone().filter(|input| { - input.output.native_token().is_none() && sdruc_not_expired(&input.output, self.creation_slot).is_some() + input.output.native_token().is_none() && sdruc_not_expired(&input.output, slot_index).is_some() }); if amount_selection.fulfil(self, inputs)? { @@ -221,7 +226,7 @@ impl InputSelection { // Native token, expired SDRUC. let inputs = base_inputs.clone().filter(|input| { - input.output.native_token().is_some() && sdruc_not_expired(&input.output, self.creation_slot).is_none() + input.output.native_token().is_some() && sdruc_not_expired(&input.output, slot_index).is_none() }); if amount_selection.fulfil(self, inputs)? { @@ -230,7 +235,7 @@ impl InputSelection { // Native token, unexpired SDRUC. let inputs = base_inputs.clone().filter(|input| { - input.output.native_token().is_some() && sdruc_not_expired(&input.output, self.creation_slot).is_some() + input.output.native_token().is_some() && sdruc_not_expired(&input.output, slot_index).is_some() }); if amount_selection.fulfil(self, inputs)? { @@ -364,13 +369,15 @@ impl InputSelection { &mut self, amount_selection: &mut AmountSelection, ) -> Result>, Error> { + let slot_index = self.latest_slot_commitment_id.slot_index(); + let basic_ed25519_inputs = self.available_inputs.iter().filter(|input| { if let Output::Basic(output) = &input.output { output .unlock_conditions() .locked_address( output.address(), - self.creation_slot, + slot_index, self.protocol_parameters.committable_age_range(), ) .expect("slot index was provided") @@ -391,7 +398,7 @@ impl InputSelection { .unlock_conditions() .locked_address( output.address(), - self.creation_slot, + slot_index, self.protocol_parameters.committable_age_range(), ) .expect("slot index was provided") diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/mana.rs b/sdk/src/client/api/block_builder/input_selection/requirement/mana.rs index 646954d0af..2b50961b96 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/mana.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/mana.rs @@ -38,7 +38,7 @@ impl InputSelection { if !self.selected_inputs.is_empty() && self.all_outputs().next().is_some() { self.selected_inputs = Self::sort_input_signing_data( std::mem::take(&mut self.selected_inputs), - self.creation_slot, + self.latest_slot_commitment_id.slot_index(), self.protocol_parameters.committable_age_range(), )?; diff --git a/sdk/src/wallet/operations/transaction/input_selection.rs b/sdk/src/wallet/operations/transaction/input_selection.rs index 6a42a2cb6f..3f3022f368 100644 --- a/sdk/src/wallet/operations/transaction/input_selection.rs +++ b/sdk/src/wallet/operations/transaction/input_selection.rs @@ -86,7 +86,7 @@ where &self.address().await, self.bip_path().await, wallet_ledger.unspent_outputs.values(), - creation_slot, + slot_commitment_id.slot_index(), protocol_parameters.committable_age_range(), &options.required_inputs, )?; @@ -125,7 +125,7 @@ where mana_rewards.insert( *output_id, self.client() - .get_output_mana_rewards(output_id, creation_slot) + .get_output_mana_rewards(output_id, slot_commitment_id.slot_index()) .await? .rewards, ); From 3f54908417fa2abc13252b828f99cbe6230e8767 Mon Sep 17 00:00:00 2001 From: DaughterOfMars Date: Fri, 23 Feb 2024 09:13:08 -0500 Subject: [PATCH 5/9] fix the getValidator return type (#2059) --- bindings/nodejs/lib/client/client.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bindings/nodejs/lib/client/client.ts b/bindings/nodejs/lib/client/client.ts index f98f54b005..df52e54444 100644 --- a/bindings/nodejs/lib/client/client.ts +++ b/bindings/nodejs/lib/client/client.ts @@ -72,7 +72,10 @@ import { import { plainToInstance } from 'class-transformer'; import { ManaRewardsResponse } from '../types/models/api/mana-rewards-response'; -import { ValidatorsResponse } from '../types/models/api/validators-response'; +import { + ValidatorResponse, + ValidatorsResponse, +} from '../types/models/api/validators-response'; /** The Client to interact with nodes. */ export class Client { @@ -176,7 +179,7 @@ export class Client { /** * Return information about a validator. */ - async getValidator(accountId: AccountId): Promise { + async getValidator(accountId: AccountId): Promise { const response = await this.methodHandler.callMethod({ name: 'getValidator', data: { From 2ea8e748c9d9f6b51d06579d28de91518ac73930 Mon Sep 17 00:00:00 2001 From: DaughterOfMars Date: Fri, 23 Feb 2024 09:55:45 -0500 Subject: [PATCH 6/9] Do not clone ledger in balance (#2053) * don't clone or hold ledger lock in balance * just lock it * block on client calls --------- Co-authored-by: Thibault Martinez --- sdk/src/wallet/operations/balance.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sdk/src/wallet/operations/balance.rs b/sdk/src/wallet/operations/balance.rs index 400eacd08a..6ec70ef30e 100644 --- a/sdk/src/wallet/operations/balance.rs +++ b/sdk/src/wallet/operations/balance.rs @@ -28,7 +28,7 @@ where let slot_index = self.client().get_slot_index().await?; let wallet_address = self.address().await; - let wallet_ledger = self.ledger().await.clone(); + let wallet_ledger = self.ledger().await; let network_id = protocol_parameters.network_id(); let storage_score_params = protocol_parameters.storage_score_parameters(); @@ -72,7 +72,11 @@ where slot_index, )?; // Add mana rewards - if let Ok(response) = self.client().get_output_mana_rewards(output_id, slot_index).await { + // NOTE: Block here because we really don't want to yield to the executor while we are holding the + // ledger lock + if let Ok(response) = tokio::runtime::Handle::current() + .block_on(self.client().get_output_mana_rewards(output_id, slot_index)) + { balance.mana.rewards += response.rewards; } @@ -105,7 +109,11 @@ where // Add amount balance.base_coin.total += delegation.amount(); // Add mana rewards - if let Ok(response) = self.client().get_output_mana_rewards(output_id, slot_index).await { + // NOTE: Block here because we really don't want to yield to the executor while we are holding the + // ledger lock + if let Ok(response) = tokio::runtime::Handle::current() + .block_on(self.client().get_output_mana_rewards(output_id, slot_index)) + { balance.mana.rewards += response.rewards; } // Add storage deposit From 8712869b93bc6196b0b5237cf8fe343ed4020b75 Mon Sep 17 00:00:00 2001 From: DaughterOfMars Date: Fri, 23 Feb 2024 10:12:47 -0500 Subject: [PATCH 7/9] Allotment touchups (#2036) * Add flag that enables allotting from account outputs by reducing the resulting output mana * move checks and improve test * default values * oops all commas * comment --- bindings/core/src/method/wallet.rs | 8 +- bindings/core/src/method_handler/wallet.rs | 9 +- .../lib/types/wallet/transaction-options.ts | 5 + .../iota_sdk/types/transaction_options.py | 3 + cli/src/wallet_cli/mod.rs | 64 ++++- .../api/block_builder/input_selection/mod.rs | 40 ++- .../input_selection/requirement/mana.rs | 53 ++-- .../input_selection/transition.rs | 2 +- sdk/src/types/block/output/account.rs | 38 ++- sdk/src/types/block/output/anchor.rs | 38 ++- sdk/src/types/block/output/basic.rs | 38 ++- sdk/src/types/block/output/delegation.rs | 37 ++- sdk/src/types/block/output/foundry.rs | 38 ++- sdk/src/types/block/output/mod.rs | 27 +-- sdk/src/types/block/output/nft.rs | 39 ++- .../burning_melting/melt_native_token.rs | 43 ++-- .../high_level/minting/create_native_token.rs | 20 +- .../high_level/minting/mint_native_token.rs | 29 +-- .../transaction/high_level/staking/end.rs | 22 +- .../transaction/high_level/staking/extend.rs | 12 +- .../operations/transaction/input_selection.rs | 6 +- .../wallet/operations/transaction/options.rs | 4 + .../client/input_selection/account_outputs.rs | 227 +++++++++--------- .../client/input_selection/basic_outputs.rs | 2 +- sdk/tests/client/input_selection/outputs.rs | 2 +- 25 files changed, 558 insertions(+), 248 deletions(-) diff --git a/bindings/core/src/method/wallet.rs b/bindings/core/src/method/wallet.rs index efd3dd13d3..4395278b54 100644 --- a/bindings/core/src/method/wallet.rs +++ b/bindings/core/src/method/wallet.rs @@ -357,11 +357,17 @@ pub enum WalletMethod { PrepareExtendStaking { account_id: AccountId, additional_epochs: u32, + #[serde(default)] + options: Option, }, /// Prepare to end staking. /// Expected response: [`PreparedTransaction`](crate::Response::PreparedTransaction) #[serde(rename_all = "camelCase")] - PrepareEndStaking { account_id: AccountId }, + PrepareEndStaking { + account_id: AccountId, + #[serde(default)] + options: Option, + }, /// Announce candidacy for an account. /// Expected response: [`BlockId`](crate::Response::BlockId) #[serde(rename_all = "camelCase")] diff --git a/bindings/core/src/method_handler/wallet.rs b/bindings/core/src/method_handler/wallet.rs index bc53e77ff4..b51d49b2bd 100644 --- a/bindings/core/src/method_handler/wallet.rs +++ b/bindings/core/src/method_handler/wallet.rs @@ -340,12 +340,15 @@ pub(crate) async fn call_wallet_method_internal(wallet: &Wallet, method: WalletM WalletMethod::PrepareExtendStaking { account_id, additional_epochs, + options, } => { - let data = wallet.prepare_extend_staking(account_id, additional_epochs).await?; + let data = wallet + .prepare_extend_staking(account_id, additional_epochs, options) + .await?; Response::PreparedTransaction(data) } - WalletMethod::PrepareEndStaking { account_id } => { - let data = wallet.prepare_end_staking(account_id).await?; + WalletMethod::PrepareEndStaking { account_id, options } => { + let data = wallet.prepare_end_staking(account_id, options).await?; Response::PreparedTransaction(data) } WalletMethod::AnnounceCandidacy { account_id } => { diff --git a/bindings/nodejs/lib/types/wallet/transaction-options.ts b/bindings/nodejs/lib/types/wallet/transaction-options.ts index cbe3f7385b..100cde30f9 100644 --- a/bindings/nodejs/lib/types/wallet/transaction-options.ts +++ b/bindings/nodejs/lib/types/wallet/transaction-options.ts @@ -31,6 +31,11 @@ export interface TransactionOptions { allowMicroAmount?: boolean; /** Whether to allow the selection of additional inputs for this transaction. */ allowAdditionalInputSelection?: boolean; + /** + * Whether to allow allotting automatically calculated mana from the issuer account. + * If this flag is disabled, additional inputs will be selected to cover the amount. + */ + allowAllottingFromAccountMana?: boolean; /** Transaction capabilities. */ capabilities?: HexEncodedString; /** Mana allotments for the transaction. */ diff --git a/bindings/python/iota_sdk/types/transaction_options.py b/bindings/python/iota_sdk/types/transaction_options.py index 8aedbc7283..4223298f6e 100644 --- a/bindings/python/iota_sdk/types/transaction_options.py +++ b/bindings/python/iota_sdk/types/transaction_options.py @@ -55,6 +55,8 @@ class TransactionOptions: note: A string attached to the transaction. allow_micro_amount: Whether to allow sending a micro amount. allow_additional_input_selection: Whether to allow the selection of additional inputs for this transaction. + allow_allotting_from_account_mana: Whether to allow allotting automatically calculated mana from the issuer account. + If this flag is disabled, additional inputs will be selected to cover the amount. capabilities: Transaction capabilities. mana_allotments: Mana allotments for the transaction. issuer_id: Optional block issuer to which the transaction will have required mana allotted. @@ -68,6 +70,7 @@ class TransactionOptions: note: Optional[str] = None allow_micro_amount: Optional[bool] = None allow_additional_input_selection: Optional[bool] = None + allow_allotting_from_account_mana: Optional[bool] = None capabilities: Optional[HexStr] = None mana_allotments: Optional[dict[HexStr, int]] = None issuer_id: Optional[HexStr] = None diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index c9e5bbdfba..d343e78d1f 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -79,6 +79,9 @@ pub enum WalletCommand { fixed_cost: u64, /// The staking period (in epochs). Will default to the staking unbonding period. staking_period: Option, + /// Whether to allot mana from the account output. + #[arg(long, default_value_t = true)] + allot_from_account: bool, }, /// Burn an amount of native token. BurnNativeToken { @@ -164,6 +167,9 @@ pub enum WalletCommand { EndStaking { /// The Account ID of the staking account. account_id: AccountId, + /// Whether to allot mana from the account output. + #[arg(long, default_value_t = true)] + allot_from_account: bool, }, /// Exit the CLI wallet. Exit, @@ -173,6 +179,9 @@ pub enum WalletCommand { account_id: AccountId, /// The number of additional epochs to add to the staking period. additional_epochs: u32, + /// Whether to allot mana from the account output. + #[arg(long, default_value_t = true)] + allot_from_account: bool, }, /// Request funds from the faucet. Faucet { @@ -482,6 +491,7 @@ pub async fn begin_staking_command( staked_amount: u64, fixed_cost: u64, staking_period: Option, + allot_from_account: bool, ) -> Result<(), Error> { println_log_info!("Begin staking for {account_id}."); @@ -493,7 +503,10 @@ pub async fn begin_staking_command( fixed_cost, staking_period, }, - None, + TransactionOptions { + allow_allotting_from_account_mana: allot_from_account, + ..Default::default() + }, ) .await?; @@ -803,10 +816,22 @@ pub async fn destroy_foundry_command(wallet: &Wallet, foundry_id: FoundryId) -> } // `end-staking` command -pub async fn end_staking_command(wallet: &Wallet, account_id: AccountId) -> Result<(), Error> { +pub async fn end_staking_command( + wallet: &Wallet, + account_id: AccountId, + allot_from_account: bool, +) -> Result<(), Error> { println_log_info!("Ending staking for {account_id}."); - let transaction = wallet.end_staking(account_id).await?; + let transaction = wallet + .end_staking( + account_id, + TransactionOptions { + allow_allotting_from_account_mana: allot_from_account, + ..Default::default() + }, + ) + .await?; println_log_info!( "End staking transaction sent:\n{:?}\n{:?}", @@ -822,10 +847,20 @@ pub async fn extend_staking_command( wallet: &Wallet, account_id: AccountId, additional_epochs: u32, + allot_from_account: bool, ) -> Result<(), Error> { println_log_info!("Extending staking for {account_id} by {additional_epochs} epochs."); - let transaction = wallet.extend_staking(account_id, additional_epochs).await?; + let transaction = wallet + .extend_staking( + account_id, + additional_epochs, + TransactionOptions { + allow_allotting_from_account_mana: allot_from_account, + ..Default::default() + }, + ) + .await?; println_log_info!( "Extend staking transaction sent:\n{:?}\n{:?}", @@ -1437,9 +1472,18 @@ pub async fn prompt_internal( staked_amount, fixed_cost, staking_period, + allot_from_account, } => { ensure_password(wallet).await?; - begin_staking_command(wallet, account_id, staked_amount, fixed_cost, staking_period).await + begin_staking_command( + wallet, + account_id, + staked_amount, + fixed_cost, + staking_period, + allot_from_account, + ) + .await } WalletCommand::BurnNativeToken { token_id, amount } => { ensure_password(wallet).await?; @@ -1511,9 +1555,12 @@ pub async fn prompt_internal( ensure_password(wallet).await?; destroy_foundry_command(wallet, foundry_id).await } - WalletCommand::EndStaking { account_id } => { + WalletCommand::EndStaking { + account_id, + allot_from_account, + } => { ensure_password(wallet).await?; - end_staking_command(wallet, account_id).await + end_staking_command(wallet, account_id, allot_from_account).await } WalletCommand::Exit => { return Ok(PromptResponse::Done); @@ -1521,9 +1568,10 @@ pub async fn prompt_internal( WalletCommand::ExtendStaking { account_id, additional_epochs, + allot_from_account, } => { ensure_password(wallet).await?; - extend_staking_command(wallet, account_id, additional_epochs).await + extend_staking_command(wallet, account_id, additional_epochs, allot_from_account).await } WalletCommand::Faucet { address, url } => faucet_command(wallet, address, url).await, WalletCommand::ImplicitAccountCreationAddress => { diff --git a/sdk/src/client/api/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index f6a30bb72a..1e5248ec49 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -69,6 +69,7 @@ pub struct InputSelection { #[derive(Copy, Clone, Debug)] pub(crate) struct MinManaAllotment { issuer_id: AccountId, + allow_allotting_from_account_mana: bool, reference_mana_cost: u64, allotment_debt: u64, } @@ -180,7 +181,7 @@ impl InputSelection { let input = self.available_inputs.swap_remove(index); // Selects required input. - self.select_input(input)? + self.select_input(input)?; } None => return Err(Error::RequiredInputIsNotAvailable(required_input)), } @@ -203,7 +204,7 @@ impl InputSelection { // If burn or mana allotments are provided, outputs will be added later, in the other cases it will just // create remainder outputs. if !self.provided_outputs.is_empty() - || self.burn.is_none() && self.mana_allotments.is_empty() && self.required_inputs.is_empty() + || (self.burn.is_none() && self.mana_allotments.is_empty() && self.required_inputs.is_empty()) { return Err(Error::InvalidOutputCount(self.provided_outputs.len())); } @@ -233,6 +234,15 @@ impl InputSelection { } } + let (input_mana, output_mana) = self.mana_sums(false)?; + + if input_mana < output_mana { + return Err(Error::InsufficientMana { + found: input_mana, + required: output_mana, + }); + } + // If there is no min allotment calculation, then we should update the remainders as the last step if self.min_mana_allotment.is_none() { self.update_remainders()?; @@ -324,9 +334,10 @@ impl InputSelection { }) } - fn select_input(&mut self, input: InputSigningData) -> Result<(), Error> { + fn select_input(&mut self, input: InputSigningData) -> Result, Error> { log::debug!("Selecting input {:?}", input.output_id()); + let mut added_output = None; if let Some(output) = self.transition_input(&input)? { // No need to check for `outputs_requirements` because // - the sender feature doesn't need to be verified as it has been removed @@ -334,6 +345,7 @@ impl InputSelection { // - input doesn't need to be checked for as we just transitioned it // - foundry account requirement should have been met already by a prior `required_account_nft_addresses` self.added_outputs.push(output); + added_output = self.added_outputs.last(); } if let Some(requirement) = self.required_account_nft_addresses(&input)? { @@ -348,7 +360,7 @@ impl InputSelection { self.requirements.push(Requirement::ContextInputs); } - Ok(()) + Ok(added_output) } /// Sets the required inputs of an [`InputSelection`]. @@ -406,9 +418,15 @@ impl InputSelection { } /// Specifies an account to which the minimum required mana allotment will be added. - pub fn with_min_mana_allotment(mut self, account_id: AccountId, reference_mana_cost: u64) -> Self { + pub fn with_min_mana_allotment( + mut self, + account_id: AccountId, + reference_mana_cost: u64, + allow_allotting_from_account_mana: bool, + ) -> Self { self.min_mana_allotment.replace(MinManaAllotment { issuer_id: account_id, + allow_allotting_from_account_mana, reference_mana_cost, allotment_debt: 0, }); @@ -431,15 +449,21 @@ impl InputSelection { } pub(crate) fn all_outputs(&self) -> impl Iterator { - self.non_remainder_outputs() - .chain(self.remainders.data.iter().map(|r| &r.output)) - .chain(&self.remainders.storage_deposit_returns) + self.non_remainder_outputs().chain(self.remainder_outputs()) } pub(crate) fn non_remainder_outputs(&self) -> impl Iterator { self.provided_outputs.iter().chain(&self.added_outputs) } + pub(crate) fn remainder_outputs(&self) -> impl Iterator { + self.remainders + .data + .iter() + .map(|r| &r.output) + .chain(&self.remainders.storage_deposit_returns) + } + fn required_account_nft_addresses(&self, input: &InputSigningData) -> Result, Error> { let required_address = input .output diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/mana.rs b/sdk/src/client/api/block_builder/input_selection/requirement/mana.rs index 2b50961b96..d6d8286a34 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/mana.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/mana.rs @@ -32,7 +32,8 @@ impl InputSelection { }) = self.min_mana_allotment else { // If there is no min allotment calculation needed, just check mana - return self.get_inputs_for_mana_balance(); + self.get_inputs_for_mana_balance()?; + return Ok(Vec::new()); }; if !self.selected_inputs.is_empty() && self.all_outputs().next().is_some() { @@ -80,6 +81,7 @@ impl InputSelection { let MinManaAllotment { issuer_id, allotment_debt, + allow_allotting_from_account_mana, .. } = self .min_mana_allotment @@ -89,7 +91,7 @@ impl InputSelection { // Add the required allotment to the issuing allotment if required_allotment_mana > self.mana_allotments[issuer_id] { log::debug!("Allotting at least {required_allotment_mana} mana to account ID {issuer_id}"); - let additional_allotment = required_allotment_mana - self.mana_allotments[&issuer_id]; + let additional_allotment = required_allotment_mana - self.mana_allotments[issuer_id]; log::debug!("{additional_allotment} additional mana required to meet minimum allotment"); // Unwrap: safe because we always add the record above *self.mana_allotments.get_mut(issuer_id).unwrap() = required_allotment_mana; @@ -100,7 +102,9 @@ impl InputSelection { *allotment_debt = self.mana_allotments[issuer_id]; } - self.reduce_account_output()?; + if *allow_allotting_from_account_mana { + self.reduce_account_output()?; + } } else if !self.requirements.contains(&Requirement::Mana) { self.requirements.push(Requirement::Mana); } @@ -114,17 +118,16 @@ impl InputSelection { let additional_inputs = self.get_inputs_for_mana_balance()?; // If we needed more inputs to cover the additional allotment mana // then update remainders and re-run this requirement - if !additional_inputs.is_empty() { + if additional_inputs { if !self.requirements.contains(&Requirement::Mana) { self.requirements.push(Requirement::Mana); } - return Ok(additional_inputs); } Ok(Vec::new()) } - pub(crate) fn reduce_account_output(&mut self) -> Result<(), Error> { + fn reduce_account_output(&mut self) -> Result<(), Error> { let MinManaAllotment { issuer_id, allotment_debt, @@ -233,43 +236,43 @@ impl InputSelection { Ok(Unlocks::new(blocks)?) } - pub(crate) fn get_inputs_for_mana_balance(&mut self) -> Result, Error> { - let (mut selected_mana, required_mana) = self.mana_sums(true)?; + pub(crate) fn get_inputs_for_mana_balance(&mut self) -> Result { + let (mut selected_mana, mut required_mana) = self.mana_sums(true)?; log::debug!("Mana requirement selected mana: {selected_mana}, required mana: {required_mana}"); + let mut added_inputs = false; if selected_mana >= required_mana { log::debug!("Mana requirement already fulfilled"); - Ok(Vec::new()) } else { - let mut inputs = Vec::new(); - + if !self.allow_additional_input_selection { + return Err(Error::AdditionalInputsRequired(Requirement::Mana)); + } // TODO we should do as for the amount and have preferences on which inputs to pick. while let Some(input) = self.available_inputs.pop() { selected_mana += self.total_mana(&input)?; - inputs.push(input); + if let Some(output) = self.select_input(input)? { + required_mana += output.mana(); + } + added_inputs = true; if selected_mana >= required_mana { break; } } - if selected_mana < required_mana { - return Err(Error::InsufficientMana { - found: selected_mana, - required: required_mana, - }); - } - - Ok(inputs) } + Ok(added_inputs) } pub(crate) fn mana_sums(&self, include_remainders: bool) -> Result<(u64, u64), Error> { - let required_mana = if include_remainders { - self.all_outputs().map(|o| o.mana()).sum::() + self.remainders.added_mana - } else { - self.non_remainder_outputs().map(|o| o.mana()).sum::() - } + self.mana_allotments.values().sum::(); + let mut required_mana = + self.non_remainder_outputs().map(|o| o.mana()).sum::() + self.mana_allotments.values().sum::(); + if include_remainders { + // Add the remainder outputs mana as well as the excess mana we've allocated to add to existing outputs + // later. + required_mana += self.remainder_outputs().map(|o| o.mana()).sum::() + self.remainders.added_mana; + } + let mut selected_mana = 0; for input in &self.selected_inputs { diff --git a/sdk/src/client/api/block_builder/input_selection/transition.rs b/sdk/src/client/api/block_builder/input_selection/transition.rs index 39089dcb48..58beed6813 100644 --- a/sdk/src/client/api/block_builder/input_selection/transition.rs +++ b/sdk/src/client/api/block_builder/input_selection/transition.rs @@ -60,7 +60,7 @@ impl InputSelection { .with_features(features); if input.is_block_issuer() { - builder = builder.with_mana(Output::from(input.clone()).available_mana( + builder = builder.with_mana(input.available_mana( &self.protocol_parameters, output_id.transaction_id().slot_index(), self.creation_slot, diff --git a/sdk/src/types/block/output/account.rs b/sdk/src/types/block/output/account.rs index 1651b7fd0b..40f174656d 100644 --- a/sdk/src/types/block/output/account.rs +++ b/sdk/src/types/block/output/account.rs @@ -19,10 +19,12 @@ use crate::types::block::{ verify_allowed_unlock_conditions, verify_restricted_addresses, UnlockCondition, UnlockConditionFlags, UnlockConditions, }, - ChainId, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StorageScore, StorageScoreParameters, + ChainId, DecayedMana, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StorageScore, + StorageScoreParameters, }, protocol::{ProtocolParameters, WorkScore, WorkScoreParameters}, semantic::TransactionFailureReason, + slot::SlotIndex, Error, }; @@ -395,6 +397,40 @@ impl AccountOutput { self.features().staking().is_some() && next_state.map_or(true, |o| o.features().staking().is_none()) } + /// Returns all the mana held by the output, which is potential + stored, all decayed. + pub fn available_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let decayed_mana = self.decayed_mana(protocol_parameters, creation_index, target_index)?; + + decayed_mana + .stored + .checked_add(decayed_mana.potential) + .ok_or(Error::ConsumedManaOverflow) + } + + /// Returns the decayed stored and potential mana of the output. + pub fn decayed_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let min_deposit = self.minimum_amount(protocol_parameters.storage_score_parameters()); + let generation_amount = self.amount().saturating_sub(min_deposit); + let stored_mana = protocol_parameters.mana_with_decay(self.mana(), creation_index, target_index)?; + let potential_mana = + protocol_parameters.generate_mana_with_decay(generation_amount, creation_index, target_index)?; + + Ok(DecayedMana { + stored: stored_mana, + potential: potential_mana, + }) + } + // Transition, just without full SemanticValidationContext pub(crate) fn transition_inner( current_state: &Self, diff --git a/sdk/src/types/block/output/anchor.rs b/sdk/src/types/block/output/anchor.rs index 1739933b95..7f94894b86 100644 --- a/sdk/src/types/block/output/anchor.rs +++ b/sdk/src/types/block/output/anchor.rs @@ -19,10 +19,12 @@ use crate::types::block::{ verify_allowed_unlock_conditions, verify_restricted_addresses, UnlockCondition, UnlockConditionFlags, UnlockConditions, }, - ChainId, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StorageScore, StorageScoreParameters, + ChainId, DecayedMana, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StorageScore, + StorageScoreParameters, }, protocol::{ProtocolParameters, WorkScore, WorkScoreParameters}, semantic::{SemanticValidationContext, TransactionFailureReason}, + slot::SlotIndex, unlock::Unlock, Error, }; @@ -451,6 +453,40 @@ impl AnchorOutput { Ok(()) } + /// Returns all the mana held by the output, which is potential + stored, all decayed. + pub fn available_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let decayed_mana = self.decayed_mana(protocol_parameters, creation_index, target_index)?; + + decayed_mana + .stored + .checked_add(decayed_mana.potential) + .ok_or(Error::ConsumedManaOverflow) + } + + /// Returns the decayed stored and potential mana of the output. + pub fn decayed_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let min_deposit = self.minimum_amount(protocol_parameters.storage_score_parameters()); + let generation_amount = self.amount().saturating_sub(min_deposit); + let stored_mana = protocol_parameters.mana_with_decay(self.mana(), creation_index, target_index)?; + let potential_mana = + protocol_parameters.generate_mana_with_decay(generation_amount, creation_index, target_index)?; + + Ok(DecayedMana { + stored: stored_mana, + potential: potential_mana, + }) + } + // Transition, just without full ValidationContext pub(crate) fn transition_inner( current_state: &Self, diff --git a/sdk/src/types/block/output/basic.rs b/sdk/src/types/block/output/basic.rs index afa6b3e62d..4b5de1a79e 100644 --- a/sdk/src/types/block/output/basic.rs +++ b/sdk/src/types/block/output/basic.rs @@ -13,9 +13,11 @@ use crate::types::block::{ verify_allowed_unlock_conditions, verify_restricted_addresses, AddressUnlockCondition, StorageDepositReturnUnlockCondition, UnlockCondition, UnlockConditionFlags, UnlockConditions, }, - MinimumOutputAmount, NativeToken, Output, OutputBuilderAmount, StorageScore, StorageScoreParameters, + DecayedMana, MinimumOutputAmount, NativeToken, Output, OutputBuilderAmount, StorageScore, + StorageScoreParameters, }, protocol::{ProtocolParameters, WorkScore, WorkScoreParameters}, + slot::SlotIndex, Error, }; @@ -348,6 +350,40 @@ impl BasicOutput { .unwrap() .amount() } + + /// Returns all the mana held by the output, which is potential + stored, all decayed. + pub fn available_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let decayed_mana = self.decayed_mana(protocol_parameters, creation_index, target_index)?; + + decayed_mana + .stored + .checked_add(decayed_mana.potential) + .ok_or(Error::ConsumedManaOverflow) + } + + /// Returns the decayed stored and potential mana of the output. + pub fn decayed_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let min_deposit = self.minimum_amount(protocol_parameters.storage_score_parameters()); + let generation_amount = self.amount().saturating_sub(min_deposit); + let stored_mana = protocol_parameters.mana_with_decay(self.mana(), creation_index, target_index)?; + let potential_mana = + protocol_parameters.generate_mana_with_decay(generation_amount, creation_index, target_index)?; + + Ok(DecayedMana { + stored: stored_mana, + potential: potential_mana, + }) + } } impl StorageScore for BasicOutput { diff --git a/sdk/src/types/block/output/delegation.rs b/sdk/src/types/block/output/delegation.rs index c6415a8927..26bfea1274 100644 --- a/sdk/src/types/block/output/delegation.rs +++ b/sdk/src/types/block/output/delegation.rs @@ -13,11 +13,11 @@ use crate::types::block::{ verify_allowed_unlock_conditions, verify_restricted_addresses, UnlockCondition, UnlockConditionFlags, UnlockConditions, }, - MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StorageScore, StorageScoreParameters, + DecayedMana, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StorageScore, StorageScoreParameters, }, protocol::{ProtocolParameters, WorkScore, WorkScoreParameters}, semantic::TransactionFailureReason, - slot::EpochIndex, + slot::{EpochIndex, SlotIndex}, Error, }; @@ -331,6 +331,39 @@ impl DelegationOutput { ChainId::Delegation(self.delegation_id) } + /// Returns all the mana held by the output, which is potential + stored, all decayed. + pub fn available_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let decayed_mana = self.decayed_mana(protocol_parameters, creation_index, target_index)?; + + decayed_mana + .stored + .checked_add(decayed_mana.potential) + .ok_or(Error::ConsumedManaOverflow) + } + + /// Returns the decayed stored and potential mana of the output. + pub fn decayed_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let min_deposit = self.minimum_amount(protocol_parameters.storage_score_parameters()); + let generation_amount = self.amount().saturating_sub(min_deposit); + let potential_mana = + protocol_parameters.generate_mana_with_decay(generation_amount, creation_index, target_index)?; + + Ok(DecayedMana { + stored: 0, + potential: potential_mana, + }) + } + // Transition, just without full SemanticValidationContext. pub(crate) fn transition_inner(current_state: &Self, next_state: &Self) -> Result<(), TransactionFailureReason> { if !current_state.delegation_id.is_null() || next_state.delegation_id.is_null() { diff --git a/sdk/src/types/block/output/foundry.rs b/sdk/src/types/block/output/foundry.rs index 02ac4fac6b..cb72eb4fda 100644 --- a/sdk/src/types/block/output/foundry.rs +++ b/sdk/src/types/block/output/foundry.rs @@ -18,12 +18,13 @@ use crate::types::block::{ account::AccountId, feature::{verify_allowed_features, Feature, FeatureFlags, Features, NativeTokenFeature}, unlock_condition::{verify_allowed_unlock_conditions, UnlockCondition, UnlockConditionFlags, UnlockConditions}, - ChainId, MinimumOutputAmount, NativeToken, Output, OutputBuilderAmount, StorageScore, StorageScoreParameters, - TokenId, TokenScheme, + ChainId, DecayedMana, MinimumOutputAmount, NativeToken, Output, OutputBuilderAmount, StorageScore, + StorageScoreParameters, TokenId, TokenScheme, }, payload::signed_transaction::{TransactionCapabilities, TransactionCapabilityFlag}, protocol::{ProtocolParameters, WorkScore, WorkScoreParameters}, semantic::TransactionFailureReason, + slot::SlotIndex, Error, }; @@ -401,6 +402,39 @@ impl FoundryOutput { ChainId::Foundry(self.id()) } + /// Returns all the mana held by the output, which is potential + stored, all decayed. + pub fn available_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let decayed_mana = self.decayed_mana(protocol_parameters, creation_index, target_index)?; + + decayed_mana + .stored + .checked_add(decayed_mana.potential) + .ok_or(Error::ConsumedManaOverflow) + } + + /// Returns the decayed stored and potential mana of the output. + pub fn decayed_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let min_deposit = self.minimum_amount(protocol_parameters.storage_score_parameters()); + let generation_amount = self.amount().saturating_sub(min_deposit); + let potential_mana = + protocol_parameters.generate_mana_with_decay(generation_amount, creation_index, target_index)?; + + Ok(DecayedMana { + stored: 0, + potential: potential_mana, + }) + } + // Transition, just without full SemanticValidationContext pub(crate) fn transition_inner( current_state: &Self, diff --git a/sdk/src/types/block/output/mod.rs b/sdk/src/types/block/output/mod.rs index 6737e268fe..d550e983e9 100644 --- a/sdk/src/types/block/output/mod.rs +++ b/sdk/src/types/block/output/mod.rs @@ -242,25 +242,14 @@ impl Output { creation_index: SlotIndex, target_index: SlotIndex, ) -> Result { - let (amount, mana) = match self { - Self::Basic(output) => (output.amount(), output.mana()), - Self::Account(output) => (output.amount(), output.mana()), - Self::Anchor(output) => (output.amount(), output.mana()), - Self::Foundry(output) => (output.amount(), 0), - Self::Nft(output) => (output.amount(), output.mana()), - Self::Delegation(output) => (output.amount(), 0), - }; - - let min_deposit = self.minimum_amount(protocol_parameters.storage_score_parameters()); - let generation_amount = amount.saturating_sub(min_deposit); - let stored_mana = protocol_parameters.mana_with_decay(mana, creation_index, target_index)?; - let potential_mana = - protocol_parameters.generate_mana_with_decay(generation_amount, creation_index, target_index)?; - - Ok(DecayedMana { - stored: stored_mana, - potential: potential_mana, - }) + match self { + Self::Basic(output) => output.decayed_mana(protocol_parameters, creation_index, target_index), + Self::Account(output) => output.decayed_mana(protocol_parameters, creation_index, target_index), + Self::Anchor(output) => output.decayed_mana(protocol_parameters, creation_index, target_index), + Self::Foundry(output) => output.decayed_mana(protocol_parameters, creation_index, target_index), + Self::Nft(output) => output.decayed_mana(protocol_parameters, creation_index, target_index), + Self::Delegation(output) => output.decayed_mana(protocol_parameters, creation_index, target_index), + } } /// Returns the unlock conditions of an [`Output`], if any. diff --git a/sdk/src/types/block/output/nft.rs b/sdk/src/types/block/output/nft.rs index ec83f5fbf5..2bf6e318e1 100644 --- a/sdk/src/types/block/output/nft.rs +++ b/sdk/src/types/block/output/nft.rs @@ -18,11 +18,12 @@ use crate::types::block::{ verify_allowed_unlock_conditions, verify_restricted_addresses, AddressUnlockCondition, StorageDepositReturnUnlockCondition, UnlockCondition, UnlockConditionFlags, UnlockConditions, }, - BasicOutputBuilder, ChainId, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StorageScore, - StorageScoreParameters, + BasicOutputBuilder, ChainId, DecayedMana, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, + StorageScore, StorageScoreParameters, }, protocol::{ProtocolParameters, WorkScore, WorkScoreParameters}, semantic::TransactionFailureReason, + slot::SlotIndex, Error, }; @@ -406,6 +407,40 @@ impl NftOutput { NftAddress::new(self.nft_id_non_null(output_id)) } + /// Returns all the mana held by the output, which is potential + stored, all decayed. + pub fn available_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let decayed_mana = self.decayed_mana(protocol_parameters, creation_index, target_index)?; + + decayed_mana + .stored + .checked_add(decayed_mana.potential) + .ok_or(Error::ConsumedManaOverflow) + } + + /// Returns the decayed stored and potential mana of the output. + pub fn decayed_mana( + &self, + protocol_parameters: &ProtocolParameters, + creation_index: SlotIndex, + target_index: SlotIndex, + ) -> Result { + let min_deposit = self.minimum_amount(protocol_parameters.storage_score_parameters()); + let generation_amount = self.amount().saturating_sub(min_deposit); + let stored_mana = protocol_parameters.mana_with_decay(self.mana(), creation_index, target_index)?; + let potential_mana = + protocol_parameters.generate_mana_with_decay(generation_amount, creation_index, target_index)?; + + Ok(DecayedMana { + stored: stored_mana, + potential: potential_mana, + }) + } + // Transition, just without full SemanticValidationContext pub(crate) fn transition_inner(current_state: &Self, next_state: &Self) -> Result<(), TransactionFailureReason> { if current_state.immutable_features != next_state.immutable_features { diff --git a/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs b/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs index 3bdbe8f11b..29e4d5cdbf 100644 --- a/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs +++ b/sdk/src/wallet/operations/transaction/high_level/burning_melting/melt_native_token.rs @@ -6,8 +6,7 @@ use primitive_types::U256; use crate::{ client::{api::PreparedTransactionData, secret::SecretManage}, types::block::output::{ - AccountId, AccountOutputBuilder, FoundryId, FoundryOutputBuilder, Output, SimpleTokenScheme, TokenId, - TokenScheme, + AccountId, FoundryId, FoundryOutputBuilder, Output, SimpleTokenScheme, TokenId, TokenScheme, }, wallet::{ operations::transaction::TransactionOptions, @@ -59,29 +58,27 @@ where Output::Foundry(foundry_output) => (account_data, foundry_output), _ => unreachable!("We already checked it's a foundry output"), })?; - - if let Output::Account(account_output) = &existing_account_output_data.output { - // Create the new account output with updated amount. - let account_output = AccountOutputBuilder::from(account_output) - .with_account_id(account_id) - .finish_output()?; - - let TokenScheme::Simple(token_scheme) = existing_foundry_output.token_scheme(); - let outputs = [ - account_output, - FoundryOutputBuilder::from(&existing_foundry_output) - .with_token_scheme(TokenScheme::Simple(SimpleTokenScheme::new( - token_scheme.minted_tokens(), - token_scheme.melted_tokens() + melt_amount, - token_scheme.maximum_supply(), - )?)) - .finish_output()?, - ]; - // Input selection will detect that we're melting native tokens and add the required inputs if available - self.prepare_transaction(outputs, options).await + let account_output_id = existing_account_output_data.output_id; + let mut options = options.into(); + if let Some(options) = options.as_mut() { + options.required_inputs.insert(account_output_id); } else { - unreachable!("We checked if it's an account output before") + options.replace(TransactionOptions { + required_inputs: [account_output_id].into(), + ..Default::default() + }); } + + let TokenScheme::Simple(token_scheme) = existing_foundry_output.token_scheme(); + let outputs = [FoundryOutputBuilder::from(&existing_foundry_output) + .with_token_scheme(TokenScheme::Simple(SimpleTokenScheme::new( + token_scheme.minted_tokens(), + token_scheme.melted_tokens() + melt_amount, + token_scheme.maximum_supply(), + )?)) + .finish_output()?]; + // Input selection will detect that we're melting native tokens and add the required inputs if available + self.prepare_transaction(outputs, options).await } /// Find and return unspent `OutputData` for given `account_id` and `foundry_id` diff --git a/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs b/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs index 3839f68a62..5cbbadb460 100644 --- a/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs +++ b/sdk/src/wallet/operations/transaction/high_level/minting/create_native_token.rs @@ -9,8 +9,8 @@ use crate::{ types::block::{ address::AccountAddress, output::{ - feature::MetadataFeature, unlock_condition::ImmutableAccountAddressUnlockCondition, AccountId, - AccountOutputBuilder, FoundryId, FoundryOutputBuilder, Output, SimpleTokenScheme, TokenId, TokenScheme, + feature::MetadataFeature, unlock_condition::ImmutableAccountAddressUnlockCondition, AccountId, FoundryId, + FoundryOutputBuilder, Output, SimpleTokenScheme, TokenId, TokenScheme, }, }, wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Wallet}, @@ -101,12 +101,17 @@ where .await .ok_or_else(|| crate::wallet::Error::MintingFailed("Missing account output".to_string()))?; - if let Output::Account(account_output) = &account_output_data.output { - // Create the new account output with the same features, just updated mana and foundry_counter. - let new_account_output_builder = AccountOutputBuilder::from(account_output) - .with_account_id(account_id) - .with_foundry_counter(account_output.foundry_counter() + 1); + let mut options = options.into(); + if let Some(options) = options.as_mut() { + options.required_inputs.insert(account_output_data.output_id); + } else { + options.replace(TransactionOptions { + required_inputs: [account_output_data.output_id].into(), + ..Default::default() + }); + } + if let Output::Account(account_output) = &account_output_data.output { // create foundry output with minted native tokens let foundry_id = FoundryId::build( &AccountAddress::new(account_id), @@ -116,7 +121,6 @@ where let token_id = TokenId::from(foundry_id); let outputs = [ - new_account_output_builder.finish_output()?, { let mut foundry_builder = FoundryOutputBuilder::new_with_minimum_amount( storage_score_params, diff --git a/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs b/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs index 99b3a23df0..21c75a4484 100644 --- a/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs +++ b/sdk/src/wallet/operations/transaction/high_level/minting/mint_native_token.rs @@ -5,9 +5,7 @@ use primitive_types::U256; use crate::{ client::{api::PreparedTransactionData, secret::SecretManage}, - types::block::output::{ - AccountOutputBuilder, FoundryOutputBuilder, Output, SimpleTokenScheme, TokenId, TokenScheme, - }, + types::block::output::{FoundryOutputBuilder, Output, SimpleTokenScheme, TokenId, TokenScheme}, wallet::{operations::transaction::TransactionOptions, types::TransactionWithMetadata, Error, Wallet}, }; @@ -96,19 +94,17 @@ where drop(wallet_ledger); - let account_output = if let Output::Account(account_output) = existing_account_output.output { - account_output - } else { - unreachable!("We checked if it's an account output before") - }; - let foundry_output = if let Output::Foundry(foundry_output) = existing_foundry_output.output { - foundry_output - } else { - unreachable!("We checked if it's an foundry output before") - }; + let foundry_output = existing_foundry_output.output.as_foundry(); - // Create the next account output with the same data. - let new_account_output_builder = AccountOutputBuilder::from(&account_output); + let mut options = options.into(); + if let Some(options) = options.as_mut() { + options.required_inputs.insert(existing_account_output.output_id); + } else { + options.replace(TransactionOptions { + required_inputs: [existing_account_output.output_id].into(), + ..Default::default() + }); + } // Create next foundry output with minted native tokens @@ -121,10 +117,9 @@ where )?); let new_foundry_output_builder = - FoundryOutputBuilder::from(&foundry_output).with_token_scheme(updated_token_scheme); + FoundryOutputBuilder::from(foundry_output).with_token_scheme(updated_token_scheme); let outputs = [ - new_account_output_builder.finish_output()?, new_foundry_output_builder.finish_output()?, // Native Tokens will be added automatically in the remainder output in try_select_inputs() ]; diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/end.rs b/sdk/src/wallet/operations/transaction/high_level/staking/end.rs index 115d1a6efb..fc84dbbc4a 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/end.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/end.rs @@ -12,14 +12,23 @@ where crate::wallet::Error: From, crate::client::Error: From, { - pub async fn end_staking(&self, account_id: AccountId) -> crate::wallet::Result { - let prepared = self.prepare_end_staking(account_id).await?; + pub async fn end_staking( + &self, + account_id: AccountId, + options: impl Into> + Send, + ) -> crate::wallet::Result { + let options = options.into(); + let prepared = self.prepare_end_staking(account_id, options.clone()).await?; - self.sign_and_submit_transaction(prepared, None).await + self.sign_and_submit_transaction(prepared, options).await } /// Prepares the transaction for [Wallet::end_staking()]. - pub async fn prepare_end_staking(&self, account_id: AccountId) -> crate::wallet::Result { + pub async fn prepare_end_staking( + &self, + account_id: AccountId, + options: impl Into> + Send, + ) -> crate::wallet::Result { log::debug!("[TRANSACTION] prepare_end_staking"); let account_output_data = self @@ -61,11 +70,6 @@ where .with_features(features) .finish_output()?; - let options = TransactionOptions { - required_inputs: [account_output_data.output_id].into(), - ..Default::default() - }; - let transaction = self.prepare_transaction([output], options).await?; Ok(transaction) diff --git a/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs b/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs index 3797811d2c..e2b8b6efbe 100644 --- a/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs +++ b/sdk/src/wallet/operations/transaction/high_level/staking/extend.rs @@ -16,10 +16,14 @@ where &self, account_id: AccountId, additional_epochs: u32, + options: impl Into> + Send, ) -> crate::wallet::Result { - let prepared = self.prepare_extend_staking(account_id, additional_epochs).await?; + let options = options.into(); + let prepared = self + .prepare_extend_staking(account_id, additional_epochs, options.clone()) + .await?; - self.sign_and_submit_transaction(prepared, None).await + self.sign_and_submit_transaction(prepared, options).await } /// Prepares the transaction for [Wallet::extend_staking()]. @@ -27,6 +31,7 @@ where &self, account_id: AccountId, additional_epochs: u32, + options: impl Into> + Send, ) -> crate::wallet::Result { log::debug!("[TRANSACTION] prepare_extend_staking"); @@ -52,8 +57,6 @@ where let mut output_builder = AccountOutputBuilder::from(account_output_data.output.as_account()).with_account_id(account_id); - let mut options = TransactionOptions::default(); - // Just extend the end epoch if it's still possible if future_bounded_epoch <= staking_feature.end_epoch() { output_builder = output_builder.replace_feature(StakingFeature::new( @@ -78,7 +81,6 @@ where past_bounded_epoch, end_epoch, )); - options.required_inputs = [account_output_data.output_id].into(); } let output = output_builder.finish_output()?; diff --git a/sdk/src/wallet/operations/transaction/input_selection.rs b/sdk/src/wallet/operations/transaction/input_selection.rs index 3f3022f368..2c49c5418e 100644 --- a/sdk/src/wallet/operations/transaction/input_selection.rs +++ b/sdk/src/wallet/operations/transaction/input_selection.rs @@ -151,7 +151,11 @@ where .with_burn(options.burn); if let (Some(account_id), Some(reference_mana_cost)) = (options.issuer_id, reference_mana_cost) { - input_selection = input_selection.with_min_mana_allotment(account_id, reference_mana_cost); + input_selection = input_selection.with_min_mana_allotment( + account_id, + reference_mana_cost, + options.allow_allotting_from_account_mana, + ); } if !options.allow_additional_input_selection { diff --git a/sdk/src/wallet/operations/transaction/options.rs b/sdk/src/wallet/operations/transaction/options.rs index f3bc9bcde4..76f7ccbb3f 100644 --- a/sdk/src/wallet/operations/transaction/options.rs +++ b/sdk/src/wallet/operations/transaction/options.rs @@ -36,6 +36,9 @@ pub struct TransactionOptions { pub allow_micro_amount: bool, /// Whether to allow the selection of additional inputs for this transaction. pub allow_additional_input_selection: bool, + /// Whether to allow allotting automatically calculated mana from the issuer account. + /// If this flag is disabled, additional inputs will be selected to cover the amount. + pub allow_allotting_from_account_mana: bool, /// Transaction capabilities. pub capabilities: Option, /// Mana allotments for the transaction. @@ -55,6 +58,7 @@ impl Default for TransactionOptions { note: Default::default(), allow_micro_amount: false, allow_additional_input_selection: true, + allow_allotting_from_account_mana: false, capabilities: Default::default(), mana_allotments: Default::default(), issuer_id: Default::default(), diff --git a/sdk/tests/client/input_selection/account_outputs.rs b/sdk/tests/client/input_selection/account_outputs.rs index 56cce3ee6e..a18126ccbd 100644 --- a/sdk/tests/client/input_selection/account_outputs.rs +++ b/sdk/tests/client/input_selection/account_outputs.rs @@ -12,8 +12,7 @@ use iota_sdk::{ address::{Address, ImplicitAccountCreationAddress}, mana::ManaAllotment, output::{ - feature::SenderFeature, unlock_condition::AddressUnlockCondition, AccountId, AccountOutputBuilder, - BasicOutputBuilder, Output, + unlock_condition::AddressUnlockCondition, AccountId, AccountOutputBuilder, BasicOutputBuilder, Output, }, protocol::iota_mainnet_protocol_parameters, rand::output::{rand_output_id_with_slot_index, rand_output_metadata_with_id}, @@ -1724,7 +1723,7 @@ fn min_allot_account_mana() { SLOT_COMMITMENT_ID, protocol_parameters, ) - .with_min_mana_allotment(account_id_1, 2) + .with_min_mana_allotment(account_id_1, 2, true) .select() .unwrap(); @@ -1748,7 +1747,7 @@ fn min_allot_account_mana_additional() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let provided_allotment = 1000; - let required_allotment = 7968; + let required_allotment = 7900; // The account does not have enough to cover the requirement let account_mana = required_allotment - 100; // But there is additional available mana elsewhere @@ -1783,9 +1782,6 @@ fn min_allot_account_mana_additional() { .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) - .add_feature(SenderFeature::new( - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - )) .finish_output() .unwrap()]; @@ -1797,7 +1793,7 @@ fn min_allot_account_mana_additional() { SLOT_COMMITMENT_ID, protocol_parameters, ) - .with_min_mana_allotment(account_id_1, 2) + .with_min_mana_allotment(account_id_1, 2, true) .with_mana_allotments(Some((account_id_1, provided_allotment))) .select() .unwrap(); @@ -1817,71 +1813,71 @@ fn min_allot_account_mana_additional() { ); } -// #[test] -// fn min_allot_account_mana_cannot_select_additional() { -// let protocol_parameters = iota_mainnet_protocol_parameters().clone(); -// let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); -// let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); +#[test] +fn min_allot_account_mana_cannot_select_additional() { + let protocol_parameters = iota_mainnet_protocol_parameters().clone(); + let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); + let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); -// let provided_allotment = 1000; -// let required_allotment = 7968; -// // The account does not have enough to cover the requirement -// let account_mana = required_allotment - 100; -// // But there is additional available mana elsewhere -// let additional_available_mana = 111; - -// let inputs = [ -// AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) -// .add_unlock_condition(AddressUnlockCondition::new( -// Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), -// )) -// .with_mana(account_mana) -// .finish_output() -// .unwrap(), -// BasicOutputBuilder::new_with_minimum_amount(protocol_parameters.storage_score_parameters()) -// .add_unlock_condition(AddressUnlockCondition::new( -// Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), -// )) -// .with_mana(additional_available_mana) -// .finish_output() -// .unwrap(), -// ]; -// let inputs = inputs -// .into_iter() -// .map(|input| InputSigningData { -// output: input, -// output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), -// chain: None, -// }) -// .collect::>(); + let provided_allotment = 1000; + let required_allotment = 7900; + // The account does not have enough to cover the requirement + let account_mana = required_allotment - 100; + // But there is additional available mana elsewhere + let additional_available_mana = 111; -// let selected = InputSelection::new( -// inputs.clone(), -// None, -// [Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()], -// SLOT_INDEX, -// SLOT_COMMITMENT_ID, -// protocol_parameters, -// ) -// .with_min_mana_allotment(account_id_1, 2) -// .with_mana_allotments(Some((account_id_2, provided_allotment))) -// .with_required_inputs([*inputs[0].output_id()]) -// .disable_additional_input_selection() -// .select() -// .unwrap_err(); + let inputs = [ + AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) + .add_unlock_condition(AddressUnlockCondition::new( + Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + )) + .with_mana(account_mana) + .finish_output() + .unwrap(), + BasicOutputBuilder::new_with_minimum_amount(protocol_parameters.storage_score_parameters()) + .add_unlock_condition(AddressUnlockCondition::new( + Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + )) + .with_mana(additional_available_mana) + .finish_output() + .unwrap(), + ]; + let inputs = inputs + .into_iter() + .map(|input| InputSigningData { + output: input, + output_metadata: rand_output_metadata_with_id(rand_output_id_with_slot_index(SLOT_INDEX)), + chain: None, + }) + .collect::>(); -// assert!( -// matches!(selected, Error::AdditionalInputsRequired(_)), -// "expected AdditionalInputsRequired, found {selected:?}" -// ); -// } + let selected = InputSelection::new( + inputs.clone(), + None, + [Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()], + SLOT_INDEX, + SLOT_COMMITMENT_ID, + protocol_parameters, + ) + .with_min_mana_allotment(account_id_1, 2, true) + .with_mana_allotments(Some((account_id_2, provided_allotment))) + .with_required_inputs([*inputs[0].output_id()]) + .disable_additional_input_selection() + .select() + .unwrap_err(); + + assert!( + matches!(selected, Error::AdditionalInputsRequired(_)), + "expected AdditionalInputsRequired, found {selected:?}" + ); +} #[test] fn min_allot_account_mana_requirement_twice() { let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); - let required_allotment = 7968; + let required_allotment = 7900; let inputs = [ AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) @@ -1908,37 +1904,34 @@ fn min_allot_account_mana_requirement_twice() { }) .collect::>(); - let outputs = build_outputs([Basic { - amount: 1_000_000, - address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - native_token: None, - sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()), - sdruc: None, - timelock: None, - expiration: None, - }]); - let selected = InputSelection::new( inputs.clone(), - outputs.clone(), + None, [Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()], SLOT_INDEX, SLOT_COMMITMENT_ID, protocol_parameters, ) - .with_min_mana_allotment(account_id_1, 2) + .with_min_mana_allotment(account_id_1, 2, true) + .with_required_inputs([*inputs[1].output_id()]) .select() .unwrap(); assert!(unsorted_eq(&selected.inputs_data, &inputs)); assert_eq!(selected.transaction.outputs().len(), 2); - assert!(selected.transaction.outputs().contains(&outputs[0])); + let account_output = selected + .transaction + .outputs() + .iter() + .filter_map(Output::as_account_opt) + .find(|o| o.account_id() == &account_id_1) + .unwrap(); assert_eq!(selected.transaction.allotments().len(), 1); assert_eq!( selected.transaction.allotments()[0], ManaAllotment::new(account_id_1, required_allotment).unwrap() ); - assert_eq!(selected.transaction.outputs()[1].as_account().mana(), 100); + assert_eq!(account_output.mana(), 100); } #[test] @@ -1946,22 +1939,29 @@ fn min_allot_account_mana_requirement_covered() { let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); - let additional_allotment = 100; - let required_allotment = 7968; + let provided_allotment = 7900; + + let account_input = AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) + .add_unlock_condition(AddressUnlockCondition::new( + Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + )) + .with_mana(provided_allotment - 100) + .finish_output() + .unwrap(); + + // Must manually add account output with mana reduced for the manual allotment + let account_output = AccountOutputBuilder::from(account_input.as_account()) + .with_mana(0) + .finish_output() + .unwrap(); let inputs = [ - AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) - .add_unlock_condition(AddressUnlockCondition::new( - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - )) - .with_mana(required_allotment - 100) - .finish_output() - .unwrap(), + account_input, BasicOutputBuilder::new_with_amount(1_000_000) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) - .with_mana(additional_allotment + 100) + .with_mana(100) .finish_output() .unwrap(), ]; @@ -1974,15 +1974,16 @@ fn min_allot_account_mana_requirement_covered() { }) .collect::>(); - let outputs = build_outputs([Basic { + let mut outputs = build_outputs([Basic { amount: 1_000_000, address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), native_token: None, - sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()), + sender: None, sdruc: None, timelock: None, expiration: None, }]); + outputs.push(account_output); let selected = InputSelection::new( inputs.clone(), @@ -1992,8 +1993,8 @@ fn min_allot_account_mana_requirement_covered() { SLOT_COMMITMENT_ID, protocol_parameters, ) - .with_min_mana_allotment(account_id_1, 2) - .with_mana_allotments(Some((account_id_1, required_allotment + additional_allotment))) + .with_min_mana_allotment(account_id_1, 2, true) + .with_mana_allotments(Some((account_id_1, provided_allotment))) .select() .unwrap(); @@ -2003,7 +2004,7 @@ fn min_allot_account_mana_requirement_covered() { assert_eq!(selected.transaction.allotments().len(), 1); assert_eq!( selected.transaction.allotments()[0], - ManaAllotment::new(account_id_1, required_allotment + additional_allotment).unwrap() + ManaAllotment::new(account_id_1, provided_allotment).unwrap() ); assert_eq!(selected.transaction.outputs()[1].as_account().mana(), 0); } @@ -2013,22 +2014,29 @@ fn min_allot_account_mana_requirement_covered_2() { let protocol_parameters = iota_mainnet_protocol_parameters().clone(); let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); - let additional_allotment = 100; - let required_allotment = 7968; + let provided_allotment = 7900; + + let account_input = AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) + .add_unlock_condition(AddressUnlockCondition::new( + Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), + )) + .with_mana(100) + .finish_output() + .unwrap(); + + // Must manually add account output with mana reduced for the manual allotment + let account_output = AccountOutputBuilder::from(account_input.as_account()) + .with_mana(0) + .finish_output() + .unwrap(); let inputs = [ - AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) - .add_unlock_condition(AddressUnlockCondition::new( - Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), - )) - .with_mana(additional_allotment + 100) - .finish_output() - .unwrap(), + account_input, BasicOutputBuilder::new_with_amount(1_000_000) .add_unlock_condition(AddressUnlockCondition::new( Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), )) - .with_mana(required_allotment - 100) + .with_mana(provided_allotment - 100) .finish_output() .unwrap(), ]; @@ -2041,15 +2049,16 @@ fn min_allot_account_mana_requirement_covered_2() { }) .collect::>(); - let outputs = build_outputs([Basic { + let mut outputs = build_outputs([Basic { amount: 1_000_000, address: Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap(), native_token: None, - sender: Some(Address::try_from_bech32(BECH32_ADDRESS_ED25519_0).unwrap()), + sender: None, sdruc: None, timelock: None, expiration: None, }]); + outputs.push(account_output); let selected = InputSelection::new( inputs.clone(), @@ -2059,8 +2068,8 @@ fn min_allot_account_mana_requirement_covered_2() { SLOT_COMMITMENT_ID, protocol_parameters, ) - .with_min_mana_allotment(account_id_1, 2) - .with_mana_allotments(Some((account_id_1, required_allotment + additional_allotment))) + .with_min_mana_allotment(account_id_1, 2, true) + .with_mana_allotments(Some((account_id_1, provided_allotment))) .select() .unwrap(); @@ -2070,7 +2079,7 @@ fn min_allot_account_mana_requirement_covered_2() { assert_eq!(selected.transaction.allotments().len(), 1); assert_eq!( selected.transaction.allotments()[0], - ManaAllotment::new(account_id_1, required_allotment + additional_allotment).unwrap() + ManaAllotment::new(account_id_1, provided_allotment).unwrap() ); assert_eq!(selected.transaction.outputs()[1].as_account().mana(), 0); } @@ -2118,7 +2127,7 @@ fn implicit_account_transition() { protocol_parameters, ) .with_required_inputs(vec![input_output_id]) - .with_min_mana_allotment(account_id_1, 2) + .with_min_mana_allotment(account_id_1, 2, true) .select() .unwrap(); diff --git a/sdk/tests/client/input_selection/basic_outputs.rs b/sdk/tests/client/input_selection/basic_outputs.rs index 7b468b4786..306c54eee4 100644 --- a/sdk/tests/client/input_selection/basic_outputs.rs +++ b/sdk/tests/client/input_selection/basic_outputs.rs @@ -2477,7 +2477,7 @@ fn automatic_allotment_provided_in_and_output() { SLOT_COMMITMENT_ID, protocol_parameters, ) - .with_min_mana_allotment(account_id_1, 2) + .with_min_mana_allotment(account_id_1, 2, true) .select() .unwrap(); diff --git a/sdk/tests/client/input_selection/outputs.rs b/sdk/tests/client/input_selection/outputs.rs index 4af1cd6ffc..d92c814e08 100644 --- a/sdk/tests/client/input_selection/outputs.rs +++ b/sdk/tests/client/input_selection/outputs.rs @@ -431,7 +431,7 @@ fn consolidate_with_min_allotment() { SLOT_COMMITMENT_ID, protocol_parameters, ) - .with_min_mana_allotment(account_id_1, 10) + .with_min_mana_allotment(account_id_1, 10, true) .with_required_inputs(inputs.iter().map(|i| *i.output_id())) .select() .unwrap(); From 1849cc608e83a54c7061e1a8d772433cd38d5fb3 Mon Sep 17 00:00:00 2001 From: DaughterOfMars Date: Fri, 23 Feb 2024 11:46:37 -0500 Subject: [PATCH 8/9] Add output proof creation (#2014) * Add output proof creation * update type * no_std, packable, better serde, and tests * logic fix * no_std again * fix proofs * fix merge * better error handling --------- Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Co-authored-by: Thibault Martinez --- sdk/src/types/block/output/mod.rs | 2 +- sdk/src/types/block/output/output_id.rs | 31 +- sdk/src/types/block/output/output_id_proof.rs | 356 +++++++++++++++--- .../payload/signed_transaction/transaction.rs | 14 +- sdk/src/utils/merkle_hasher.rs | 6 +- .../fixtures/tip45_32_output_proof_idx0.json | 55 +++ .../fixtures/tip45_32_output_proof_idx28.json | 55 +++ .../fixtures/tip45_five_output_proof.json | 34 ++ .../fixtures/tip45_single_output_proof.json | 20 + sdk/tests/types/output/mod.rs | 1 + sdk/tests/types/output/proof.rs | 55 +++ sdk/tests/wallet/events.rs | 7 +- 12 files changed, 561 insertions(+), 75 deletions(-) create mode 100644 sdk/tests/types/fixtures/tip45_32_output_proof_idx0.json create mode 100644 sdk/tests/types/fixtures/tip45_32_output_proof_idx28.json create mode 100644 sdk/tests/types/fixtures/tip45_five_output_proof.json create mode 100644 sdk/tests/types/fixtures/tip45_single_output_proof.json create mode 100644 sdk/tests/types/output/proof.rs diff --git a/sdk/src/types/block/output/mod.rs b/sdk/src/types/block/output/mod.rs index d550e983e9..15c70edc7f 100644 --- a/sdk/src/types/block/output/mod.rs +++ b/sdk/src/types/block/output/mod.rs @@ -42,7 +42,7 @@ pub use self::{ native_token::{NativeToken, NativeTokens, NativeTokensBuilder, TokenId}, nft::{NftId, NftOutput, NftOutputBuilder}, output_id::OutputId, - output_id_proof::{HashableNode, LeafHash, OutputCommitmentProof, OutputIdProof, ValueHash}, + output_id_proof::{HashableNode, LeafHash, OutputCommitmentProof, OutputIdProof, ProofError, ValueHash}, storage_score::{StorageScore, StorageScoreParameters}, token_scheme::{SimpleTokenScheme, TokenScheme}, unlock_condition::{UnlockCondition, UnlockConditions}, diff --git a/sdk/src/types/block/output/output_id.rs b/sdk/src/types/block/output/output_id.rs index 57d9289257..1dd0629571 100644 --- a/sdk/src/types/block/output/output_id.rs +++ b/sdk/src/types/block/output/output_id.rs @@ -5,7 +5,7 @@ use alloc::string::ToString; use core::str::FromStr; use crypto::hashes::{blake2b::Blake2b256, Digest}; -use packable::{bounded::BoundedU16, PackableExt}; +use packable::bounded::BoundedU16; use crate::types::block::{output::OUTPUT_INDEX_RANGE, payload::signed_transaction::TransactionId, Error}; @@ -49,18 +49,33 @@ impl OutputId { /// Hash the [`OutputId`] with BLAKE2b-256. #[inline(always)] pub fn hash(&self) -> [u8; 32] { - Blake2b256::digest(self.pack_to_vec()).into() + Blake2b256::digest(self.to_bytes()).into() + } + + pub fn to_bytes(&self) -> [u8; Self::LENGTH] { + let mut buffer = [0u8; Self::LENGTH]; + let (transaction_id, index) = buffer.split_at_mut(TransactionId::LENGTH); + transaction_id.copy_from_slice(self.transaction_id.as_ref()); + index.copy_from_slice(&self.index().to_le_bytes()); + buffer } } #[cfg(feature = "serde")] crate::string_serde_impl!(OutputId); -#[allow(clippy::fallible_impl_from)] impl From<[u8; Self::LENGTH]> for OutputId { fn from(bytes: [u8; Self::LENGTH]) -> Self { - // Unwrap is fine because size is already known and valid. - Self::unpack_bytes_unverified(bytes).unwrap() + #[repr(C)] + #[allow(dead_code)] + struct Layout { + transaction_id: TransactionId, + index: [u8; 2], + } + unsafe { + let Layout { transaction_id, index } = core::mem::transmute(bytes); + Self::new(transaction_id, u16::from_le_bytes(index)) + } } } @@ -76,11 +91,7 @@ impl FromStr for OutputId { impl core::fmt::Display for OutputId { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let mut buffer = [0u8; Self::LENGTH]; - let (transaction_id, index) = buffer.split_at_mut(TransactionId::LENGTH); - transaction_id.copy_from_slice(self.transaction_id.as_ref()); - index.copy_from_slice(&self.index().to_le_bytes()); - write!(f, "{}", prefix_hex::encode(buffer)) + write!(f, "{}", prefix_hex::encode(self.to_bytes())) } } diff --git a/sdk/src/types/block/output/output_id_proof.rs b/sdk/src/types/block/output/output_id_proof.rs index 7f7bab6933..170a5fabeb 100644 --- a/sdk/src/types/block/output/output_id_proof.rs +++ b/sdk/src/types/block/output/output_id_proof.rs @@ -1,90 +1,336 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use alloc::{boxed::Box, string::String}; +use alloc::boxed::Box; +use core::convert::Infallible; + +use crypto::hashes::{blake2b::Blake2b256, Digest}; +use packable::{Packable, PackableExt}; #[cfg(feature = "serde")] -use {crate::utils::serde::prefix_hex_bytes, alloc::format, serde::de::Deserialize, serde_json::Value}; +use crate::utils::serde::prefix_hex_bytes; +use crate::{ + types::block::{output::Output, slot::SlotIndex}, + utils::merkle_hasher::{largest_power_of_two, LEAF_HASH_PREFIX, NODE_HASH_PREFIX}, +}; + +#[derive(Debug, derive_more::Display)] +pub enum ProofError { + #[display(fmt = "invalid output ID proof kind: {_0}")] + InvalidProofKind(u8), + #[display(fmt = "index {index} is out of range, outputs length {len}")] + IndexOutOfRange { index: u16, len: u16 }, + #[display(fmt = "no outputs provided")] + NoOutputs, +} -use crate::types::block::slot::SlotIndex; +#[cfg(feature = "std")] +impl std::error::Error for ProofError {} + +impl From for ProofError { + fn from(error: Infallible) -> Self { + match error {} + } +} /// The proof of the output identifier. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Packable)] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "camelCase") )] +#[packable(unpack_error = ProofError)] pub struct OutputIdProof { pub slot: SlotIndex, pub output_index: u16, - pub transaction_commitment: String, + #[cfg_attr(feature = "serde", serde(with = "prefix_hex_bytes"))] + pub transaction_commitment: [u8; 32], + #[packable(verify_with = verify_output_commitment_type)] pub output_commitment_proof: OutputCommitmentProof, } -#[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(untagged))] -pub enum OutputCommitmentProof { - HashableNode(HashableNode), - LeafHash(LeafHash), - ValueHash(ValueHash), +impl OutputCommitmentProof { + pub fn new(outputs: &[Output], index: u16) -> Result { + let num_outputs = outputs.len() as u16; + if num_outputs == 0 { + Err(ProofError::NoOutputs) + } else if index >= num_outputs { + Err(ProofError::IndexOutOfRange { + index, + len: num_outputs, + }) + } else { + Ok(Self::proof(outputs, index)) + } + } + + fn proof(outputs: &[Output], index: u16) -> Self { + if let [output] = outputs { + Self::value(&output.pack_to_vec()) + } else { + let num_outputs = outputs.len() as u16; + + // Select a `pivot` element to split `data` into two slices `left` and `right`. + let pivot = largest_power_of_two(num_outputs as _) as u16; + let (left, right) = outputs.split_at(pivot as _); + + if index < pivot { + // `value` is contained in the left subtree, and the `right` subtree can be hashed together. + Self::node(Self::proof(left, index), Self::hash(right)) + } else { + // `value` is contained in the right subtree, and the `left` subtree can be hashed together. + Self::node(Self::hash(left), Self::proof(right, index - pivot)) + } + } + } + + /// Get the merkle tree hash for a list of outputs + fn hash(outputs: &[Output]) -> LeafHash { + match outputs { + [] => LeafHash::empty(), + [output] => LeafHash::new(&output.pack_to_vec()), + _ => { + let pivot = largest_power_of_two(outputs.len() as _); + let (left, right) = outputs.split_at(pivot as _); + let left = Self::hash(left).0; + let right = Self::hash(right).0; + + let mut hasher = Blake2b256::default(); + + hasher.update([NODE_HASH_PREFIX]); + hasher.update(left); + hasher.update(right); + LeafHash(hasher.finalize().into()) + } + } + } + + fn node(left: impl Into, right: impl Into) -> Self { + Self::Node(HashableNode::new(left, right)) + } + + fn value(bytes: &[u8]) -> Self { + Self::Value(ValueHash::new(bytes)) + } } -#[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for OutputCommitmentProof { - fn deserialize>(d: D) -> Result { - let value = Value::deserialize(d)?; - Ok( - match value - .get("type") - .and_then(Value::as_u64) - .ok_or_else(|| serde::de::Error::custom("invalid output commitment proof type"))? - as u8 - { - 0 => Self::HashableNode( - serde_json::from_value::(value) - .map_err(|e| serde::de::Error::custom(format!("cannot deserialize hashable node: {e}")))?, - ), - 1 => Self::LeafHash( - serde_json::from_value::(value) - .map_err(|e| serde::de::Error::custom(format!("cannot deserialize leaf hash: {e}")))?, - ), - 2 => Self::ValueHash( - serde_json::from_value::(value) - .map_err(|e| serde::de::Error::custom(format!("cannot deserialize value hash: {e}")))?, - ), - _ => return Err(serde::de::Error::custom("invalid output commitment proof")), - }, - ) +fn verify_output_commitment_type(proof: &OutputCommitmentProof) -> Result<(), ProofError> { + match proof { + OutputCommitmentProof::Leaf(_) => Err(ProofError::InvalidProofKind(LeafHash::KIND)), + _ => Ok(()), } } +#[derive(Clone, Debug, Eq, PartialEq, derive_more::From, Packable)] +#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(untagged))] +#[packable(tag_type = u8, with_error = ProofError::InvalidProofKind)] +#[packable(unpack_error = ProofError)] +pub enum OutputCommitmentProof { + #[packable(tag = HashableNode::KIND)] + Node(HashableNode), + #[packable(tag = LeafHash::KIND)] + Leaf(LeafHash), + #[packable(tag = ValueHash::KIND)] + Value(ValueHash), +} + /// Node contains the hashes of the left and right children of a node in the tree. -#[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Eq, PartialEq, Packable)] +#[packable(unpack_visitor = ())] pub struct HashableNode { - #[cfg_attr(feature = "serde", serde(rename = "type"))] - pub kind: u8, pub l: Box, pub r: Box, } +impl HashableNode { + const KIND: u8 = 0; + + pub fn new(left: impl Into, right: impl Into) -> Self { + Self { + l: Box::new(left.into()), + r: Box::new(right.into()), + } + } +} + /// Leaf Hash contains the hash of a leaf in the tree. -#[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct LeafHash { - #[cfg_attr(feature = "serde", serde(rename = "type"))] - pub kind: u8, - #[cfg_attr(feature = "serde", serde(with = "prefix_hex_bytes"))] - pub hash: [u8; 32], +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct LeafHash(pub [u8; 32]); + +impl LeafHash { + const KIND: u8 = 1; + + pub fn new(bytes: &[u8]) -> Self { + let mut hasher = Blake2b256::default(); + + hasher.update([LEAF_HASH_PREFIX]); + hasher.update(bytes); + Self(hasher.finalize().into()) + } + + pub fn empty() -> Self { + Self(Blake2b256::digest([]).into()) + } +} + +impl Packable for LeafHash { + type UnpackError = Infallible; + type UnpackVisitor = (); + + fn pack(&self, packer: &mut P) -> Result<(), P::Error> { + 32_u8.pack(packer)?; + self.0.pack(packer)?; + Ok(()) + } + + fn unpack( + unpacker: &mut U, + visitor: Option<&Self::UnpackVisitor>, + ) -> Result> { + let _len = u8::unpack(unpacker, visitor)?; + let bytes = Packable::unpack(unpacker, visitor)?; + Ok(Self(bytes)) + } } /// Value Hash contains the hash of the value for which the proof is being computed. -#[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ValueHash { - #[cfg_attr(feature = "serde", serde(rename = "type"))] - pub kind: u8, - #[cfg_attr(feature = "serde", serde(with = "prefix_hex_bytes"))] - pub hash: [u8; 32], +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ValueHash(pub [u8; 32]); + +impl ValueHash { + const KIND: u8 = 2; + + pub fn new(bytes: &[u8]) -> Self { + let mut hasher = Blake2b256::default(); + + hasher.update([LEAF_HASH_PREFIX]); + hasher.update(bytes); + Self(hasher.finalize().into()) + } +} + +impl Packable for ValueHash { + type UnpackError = Infallible; + type UnpackVisitor = (); + + fn pack(&self, packer: &mut P) -> Result<(), P::Error> { + 32_u8.pack(packer)?; + self.0.pack(packer)?; + Ok(()) + } + + fn unpack( + unpacker: &mut U, + visitor: Option<&Self::UnpackVisitor>, + ) -> Result> { + let _len = u8::unpack(unpacker, visitor)?; + let bytes = Packable::unpack(unpacker, visitor)?; + Ok(Self(bytes)) + } +} + +#[cfg(feature = "serde")] +mod serialization { + use alloc::format; + + use serde::{Deserialize, Serialize}; + use serde_json::Value; + + use super::*; + use crate::{impl_serde_typed_dto, utils::serde::prefix_hex_bytes}; + + #[derive(Serialize, Deserialize)] + struct NodeDto { + #[serde(rename = "type")] + kind: u8, + l: Box, + r: Box, + } + + #[derive(Serialize, Deserialize)] + struct HashDto { + #[serde(rename = "type")] + kind: u8, + #[serde(with = "prefix_hex_bytes")] + hash: [u8; 32], + } + + impl From for HashableNode { + fn from(value: NodeDto) -> Self { + Self { l: value.l, r: value.r } + } + } + + impl From<&HashableNode> for NodeDto { + fn from(value: &HashableNode) -> Self { + Self { + kind: HashableNode::KIND, + l: value.l.clone(), + r: value.r.clone(), + } + } + } + + impl From for ValueHash { + fn from(value: HashDto) -> Self { + Self(value.hash) + } + } + + impl From<&ValueHash> for HashDto { + fn from(value: &ValueHash) -> Self { + Self { + kind: ValueHash::KIND, + hash: value.0, + } + } + } + + impl From for LeafHash { + fn from(value: HashDto) -> Self { + Self(value.hash) + } + } + + impl From<&LeafHash> for HashDto { + fn from(value: &LeafHash) -> Self { + Self { + kind: LeafHash::KIND, + hash: value.0, + } + } + } + + impl_serde_typed_dto!(HashableNode, NodeDto, "hashable node"); + impl_serde_typed_dto!(ValueHash, HashDto, "value hash"); + impl_serde_typed_dto!(LeafHash, HashDto, "leaf hash"); + + impl<'de> Deserialize<'de> for OutputCommitmentProof { + fn deserialize>(d: D) -> Result { + let value = Value::deserialize(d)?; + Ok( + match value + .get("type") + .and_then(Value::as_u64) + .ok_or_else(|| serde::de::Error::custom("invalid output commitment proof type"))? + as u8 + { + HashableNode::KIND => Self::Node( + serde_json::from_value::(value) + .map_err(|e| serde::de::Error::custom(format!("cannot deserialize hashable node: {e}")))?, + ), + LeafHash::KIND => Self::Leaf( + serde_json::from_value::(value) + .map_err(|e| serde::de::Error::custom(format!("cannot deserialize leaf hash: {e}")))?, + ), + ValueHash::KIND => Self::Value( + serde_json::from_value::(value) + .map_err(|e| serde::de::Error::custom(format!("cannot deserialize value hash: {e}")))?, + ), + _ => return Err(serde::de::Error::custom("invalid output commitment proof")), + }, + ) + } + } } diff --git a/sdk/src/types/block/payload/signed_transaction/transaction.rs b/sdk/src/types/block/payload/signed_transaction/transaction.rs index 4125ecbad7..e2629e7290 100644 --- a/sdk/src/types/block/payload/signed_transaction/transaction.rs +++ b/sdk/src/types/block/payload/signed_transaction/transaction.rs @@ -13,7 +13,7 @@ use crate::{ context_input::{ContextInput, ContextInputs}, input::{Input, INPUT_COUNT_RANGE}, mana::{verify_mana_allotments_sum, ManaAllotment, ManaAllotments}, - output::{Output, OUTPUT_COUNT_RANGE}, + output::{Output, OutputCommitmentProof, OutputIdProof, ProofError, OUTPUT_COUNT_RANGE}, payload::{ signed_transaction::{TransactionHash, TransactionId, TransactionSigningHash}, OptionalPayload, Payload, @@ -313,6 +313,18 @@ impl Transaction { merkle_hasher::MerkleHasher::digest::(&outputs_serialized).into() } + /// Returns a proof for the output in the transaction at the given index, + /// if the transaction has an output at that index. + pub fn output_id_proof(&self, index: u16) -> Result { + let output_commitment_proof = OutputCommitmentProof::new(&self.outputs, index)?; + Ok(OutputIdProof { + slot: self.creation_slot(), + output_index: index, + transaction_commitment: self.transaction_commitment(), + output_commitment_proof, + }) + } + /// Computes the identifier of a [`Transaction`]. pub fn id(&self) -> TransactionId { self.hash().into_transaction_id(self.creation_slot()) diff --git a/sdk/src/utils/merkle_hasher.rs b/sdk/src/utils/merkle_hasher.rs index c63e5ce41e..4e770617e6 100644 --- a/sdk/src/utils/merkle_hasher.rs +++ b/sdk/src/utils/merkle_hasher.rs @@ -4,9 +4,9 @@ use crypto::hashes::{Digest, Output}; /// Leaf domain separation prefix. -const LEAF_HASH_PREFIX: u8 = 0x00; +pub(crate) const LEAF_HASH_PREFIX: u8 = 0x00; /// Node domain separation prefix. -const NODE_HASH_PREFIX: u8 = 0x01; +pub(crate) const NODE_HASH_PREFIX: u8 = 0x01; /// A Merkle hasher based on a digest function. pub(crate) struct MerkleHasher; @@ -48,7 +48,7 @@ impl MerkleHasher { } /// Computes the largest power of two less than or equal to `n`. -fn largest_power_of_two(n: u32) -> usize { +pub(crate) fn largest_power_of_two(n: u32) -> usize { debug_assert!(n > 1, "invalid input to `largest_power_of_two`"); 1 << (32 - (n - 1).leading_zeros() - 1) } diff --git a/sdk/tests/types/fixtures/tip45_32_output_proof_idx0.json b/sdk/tests/types/fixtures/tip45_32_output_proof_idx0.json new file mode 100644 index 0000000000..02f28d5bb8 --- /dev/null +++ b/sdk/tests/types/fixtures/tip45_32_output_proof_idx0.json @@ -0,0 +1,55 @@ +{ + "transaction_bytes": "0x01fb5c44ef0d3ac8730b0000000000010000f09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed719520000000000000000013f0000000021000040420f0000000000000000000000000001000041b5fc0f730776b9d25dc9ffba236ce34bd9433f8a4bc8e286612e42654e0138000040420f00000000000000000000000000010000c5797137d27ceeb1d7a7f712b2dbbd2cb6b9e3fa39fe98a7751ea5913f00495d000040420f00000000000000000000000000010000c3d789866209202d21895e9a5a69ceb4b1fba08f53237c697e32cf6780a89a71000040420f000000000000000000000000000100008b1697f39c48f841e78e9e3fb2eae08d6af3463fc26fdfbf8ae23ad86ef5353d000040420f00000000000000000000000000010000145a6400ae4ce60e2192b6e538bb790a774db03070afaff1f0c83beedd15fa65000040420f00000000000000000000000000010000f25fbe26abe7ddc7b1ba9fc94a8f6c5a1ac025b0f8027fb7c5ec6047b7715271000040420f00000000000000000000000000010000ea2e3aa40282125d37373a7a51b94e806156f3d4d5a3e4a7679e9dac36ae5daa000040420f000000000000000000000000000100003475a41594b179a940fe311fddb2b8f0f68ff86fc88d50b085ed0af6dc916879000040420f00000000000000000000000000010000e7f9581f4105471c428dcba08f274986fbc084cbebbe77e0121f6486d7543dab000040420f00000000000000000000000000010000b2313d9e1e500c0105496d43459c33692af0d72c5412a6aa896c2d968aa09d0b000040420f0000000000000000000000000001000056db5b539ddeda7e1c81602669e26506d1a5b3119713d30090ba674cd837e567000040420f000000000000000000000000000100000f29bab850895afefbc2fcc2db1d60f1d86e275ef406b8d98c4e7ed6112c74e5000040420f00000000000000000000000000010000bda720e6d8bf203933dbf1dc4bd00e87e39e93fe514f6e64c9288ae8ce0ca84a000040420f000000000000000000000000000100009d3fd662ba96b4df02d578526090c1f9a580e1d93376380b302bc153b08c9bca000040420f00000000000000000000000000010000613fc72ee7c78035e0cc469a1f49629a98e5ad9c87ce441b9605baa249c42744000040420f000000000000000000000000000100004400a5ed5664a913bb87cb0af6b81bbe01b6a34824f92822cacf6d28f24c235e000040420f000000000000000000000000000100000b4cca1c8d620d650c8bf0f6b3575278732bb79b0156080557a72ffca84e4049000040420f00000000000000000000000000010000f8d2c1579c46b28987a0ed69f1d751b166c4dfd8c1701066aa9d3ad16761785a000040420f00000000000000000000000000010000cd682775e623f1b3f4a99f4d10509aae49a9e4fb2bb959c604d95b7f053fbd38000040420f000000000000000000000000000100006de2cd6d6b75cdf3ecdddcab903e6df6ca288d8ae3ea66c4281b7f86cf063e36000040420f000000000000000000000000000100002a207ba664da0a73f7722868af1396e35e94c96ceb32ddba28dfe862258ac8cb000040420f000000000000000000000000000100004e9807d3cfd5b26ad015b3a8c746d602234a8aeeb09a4f0b814ccf092170086c000040420f000000000000000000000000000100008c2150b4207ba52c8b75ebf13bcb9db776ca103c3ccd6fd25c065a4c91878751000040420f000000000000000000000000000100003293f372d83017fb62eddadf4dfe963c92b5aaa9a4b955da9e8c165318fe8e05000040420f00000000000000000000000000010000c439c102d9b01aab0c7dd33763fb9d376defb5b0d3238122835b9b0eb2def7c6000040420f00000000000000000000000000010000757a899de49f0b2a00dc90ef5bd901c3e24e4998d939cff0f0cf55e8e208e41d000040420f0000000000000000000000000001000032a40408819bfce14fc7101a42d4fc6cf02780c385fc2c3c07e38ddab307f57e000040420f000000000000000000000000000100003f010f28a30d3a5caf57b682ee1b29a89fe13847d761f751a2efef3079d20047000040420f00000000000000000000000000010000c1c3d93b0a50cae27cbfc53cf0195430cda86ce34a63471a59120a61cbc3f5ea000040420f0000000000000000000000000001000009ee1ed9707cec374bdc4977ed77fa237e9f788f6bd47ecbe65d5e3788ccc9b1000040420f00000000000000000000000000010000df40b4f6fe643a1ab1a4ecc7f2f1d2feb24aea9b8cfedb09d21d4dd1870f784e000040420f00000000000000000000000000010000f77ec745cf5fe977cd02905d866cb2ecce4631d02910f96ac49945db418966cb000040420f000000000000000000000000000100009d1879ca302277d00c6a00aa70a23caae1aadbc1232cd3026875ba9291cce11600010000002daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257accae4a03e1357e6ce71deb6f0de8ec9cf2c0f62cbcc0a54a7ea8db5c05257f2c538139739cc41aebd32ffee5f45d8b2c5004079d4d675189d3aa092cc673de704", + "proof": { + "slot": 11, + "outputIndex": 0, + "transactionCommitment": "0xe5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470", + "outputCommitmentProof": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 2, + "hash": "0xb750f19d60bdd576e8eb617d101ae54146b5511b76d41294b8b9a869f12ab13b" + }, + "r": { + "type": 1, + "hash": "0x6b9c6672c54f7dc2012fea833416a8425a3dc40a4855a63908e741568843ab72" + } + }, + "r": { + "type": 1, + "hash": "0xb125aad50138d88d8c43459345cbab04523c7e8fc4ea00a2c63bf9c792734775" + } + }, + "r": { + "type": 1, + "hash": "0x91ce0e100a30fed59e0ef34bc4fae37aa46811d48cc18f95b2cc02371fb7e7b8" + } + }, + "r": { + "type": 1, + "hash": "0x8211ee89080681552986e3321b231ff1cfdc114a952c1e3d3fc934283603df1f" + } + }, + "r": { + "type": 1, + "hash": "0x84fc02511dfc0326c9c82aa7081430cbfac7dc9d4e9144527374f66399e5c790" + } + }, + "r": { + "type": 1, + "hash": "0x4ad094e37e0ec880bb6a24f03f3bc3ca5fdb60af734606ba639bd413eb1a1e39" + } + } + }, + "proof_bytes": "0x0b0000000000e5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f4700000000000000220b750f19d60bdd576e8eb617d101ae54146b5511b76d41294b8b9a869f12ab13b01206b9c6672c54f7dc2012fea833416a8425a3dc40a4855a63908e741568843ab720120b125aad50138d88d8c43459345cbab04523c7e8fc4ea00a2c63bf9c792734775012091ce0e100a30fed59e0ef34bc4fae37aa46811d48cc18f95b2cc02371fb7e7b801208211ee89080681552986e3321b231ff1cfdc114a952c1e3d3fc934283603df1f012084fc02511dfc0326c9c82aa7081430cbfac7dc9d4e9144527374f66399e5c79001204ad094e37e0ec880bb6a24f03f3bc3ca5fdb60af734606ba639bd413eb1a1e39" +} diff --git a/sdk/tests/types/fixtures/tip45_32_output_proof_idx28.json b/sdk/tests/types/fixtures/tip45_32_output_proof_idx28.json new file mode 100644 index 0000000000..d57b824b45 --- /dev/null +++ b/sdk/tests/types/fixtures/tip45_32_output_proof_idx28.json @@ -0,0 +1,55 @@ +{ + "transaction_bytes": "0x01fb5c44ef0d3ac8730b0000000000010000f09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed719520000000000000000013f0000000021000040420f0000000000000000000000000001000041b5fc0f730776b9d25dc9ffba236ce34bd9433f8a4bc8e286612e42654e0138000040420f00000000000000000000000000010000c5797137d27ceeb1d7a7f712b2dbbd2cb6b9e3fa39fe98a7751ea5913f00495d000040420f00000000000000000000000000010000c3d789866209202d21895e9a5a69ceb4b1fba08f53237c697e32cf6780a89a71000040420f000000000000000000000000000100008b1697f39c48f841e78e9e3fb2eae08d6af3463fc26fdfbf8ae23ad86ef5353d000040420f00000000000000000000000000010000145a6400ae4ce60e2192b6e538bb790a774db03070afaff1f0c83beedd15fa65000040420f00000000000000000000000000010000f25fbe26abe7ddc7b1ba9fc94a8f6c5a1ac025b0f8027fb7c5ec6047b7715271000040420f00000000000000000000000000010000ea2e3aa40282125d37373a7a51b94e806156f3d4d5a3e4a7679e9dac36ae5daa000040420f000000000000000000000000000100003475a41594b179a940fe311fddb2b8f0f68ff86fc88d50b085ed0af6dc916879000040420f00000000000000000000000000010000e7f9581f4105471c428dcba08f274986fbc084cbebbe77e0121f6486d7543dab000040420f00000000000000000000000000010000b2313d9e1e500c0105496d43459c33692af0d72c5412a6aa896c2d968aa09d0b000040420f0000000000000000000000000001000056db5b539ddeda7e1c81602669e26506d1a5b3119713d30090ba674cd837e567000040420f000000000000000000000000000100000f29bab850895afefbc2fcc2db1d60f1d86e275ef406b8d98c4e7ed6112c74e5000040420f00000000000000000000000000010000bda720e6d8bf203933dbf1dc4bd00e87e39e93fe514f6e64c9288ae8ce0ca84a000040420f000000000000000000000000000100009d3fd662ba96b4df02d578526090c1f9a580e1d93376380b302bc153b08c9bca000040420f00000000000000000000000000010000613fc72ee7c78035e0cc469a1f49629a98e5ad9c87ce441b9605baa249c42744000040420f000000000000000000000000000100004400a5ed5664a913bb87cb0af6b81bbe01b6a34824f92822cacf6d28f24c235e000040420f000000000000000000000000000100000b4cca1c8d620d650c8bf0f6b3575278732bb79b0156080557a72ffca84e4049000040420f00000000000000000000000000010000f8d2c1579c46b28987a0ed69f1d751b166c4dfd8c1701066aa9d3ad16761785a000040420f00000000000000000000000000010000cd682775e623f1b3f4a99f4d10509aae49a9e4fb2bb959c604d95b7f053fbd38000040420f000000000000000000000000000100006de2cd6d6b75cdf3ecdddcab903e6df6ca288d8ae3ea66c4281b7f86cf063e36000040420f000000000000000000000000000100002a207ba664da0a73f7722868af1396e35e94c96ceb32ddba28dfe862258ac8cb000040420f000000000000000000000000000100004e9807d3cfd5b26ad015b3a8c746d602234a8aeeb09a4f0b814ccf092170086c000040420f000000000000000000000000000100008c2150b4207ba52c8b75ebf13bcb9db776ca103c3ccd6fd25c065a4c91878751000040420f000000000000000000000000000100003293f372d83017fb62eddadf4dfe963c92b5aaa9a4b955da9e8c165318fe8e05000040420f00000000000000000000000000010000c439c102d9b01aab0c7dd33763fb9d376defb5b0d3238122835b9b0eb2def7c6000040420f00000000000000000000000000010000757a899de49f0b2a00dc90ef5bd901c3e24e4998d939cff0f0cf55e8e208e41d000040420f0000000000000000000000000001000032a40408819bfce14fc7101a42d4fc6cf02780c385fc2c3c07e38ddab307f57e000040420f000000000000000000000000000100003f010f28a30d3a5caf57b682ee1b29a89fe13847d761f751a2efef3079d20047000040420f00000000000000000000000000010000c1c3d93b0a50cae27cbfc53cf0195430cda86ce34a63471a59120a61cbc3f5ea000040420f0000000000000000000000000001000009ee1ed9707cec374bdc4977ed77fa237e9f788f6bd47ecbe65d5e3788ccc9b1000040420f00000000000000000000000000010000df40b4f6fe643a1ab1a4ecc7f2f1d2feb24aea9b8cfedb09d21d4dd1870f784e000040420f00000000000000000000000000010000f77ec745cf5fe977cd02905d866cb2ecce4631d02910f96ac49945db418966cb000040420f000000000000000000000000000100009d1879ca302277d00c6a00aa70a23caae1aadbc1232cd3026875ba9291cce11600010000002daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257accae4a03e1357e6ce71deb6f0de8ec9cf2c0f62cbcc0a54a7ea8db5c05257f2c538139739cc41aebd32ffee5f45d8b2c5004079d4d675189d3aa092cc673de704", + "proof": { + "slot": 11, + "outputIndex": 28, + "transactionCommitment": "0xe5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470", + "outputCommitmentProof": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 1, + "hash": "0x7f564883c631d43a902ef144a674e6ac11ed7db1c9e88ecf7a664c19885de497" + }, + "r": { + "type": 0, + "l": { + "type": 1, + "hash": "0xaa70d7aab4560bcafda057bcffca504f4d6ca89bc5652d4cf60a33e85a39bc5f" + }, + "r": { + "type": 0, + "l": { + "type": 1, + "hash": "0xc6e9e11d1ae2b9479e778fed77d273ced27cfee60b8d9c2cb0fce4efe5b1d179" + }, + "r": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 2, + "hash": "0x56cf9617298303d80e0b0bc7a38e9807db5e6b5c1dbe32338ec54efa830f1d93" + }, + "r": { + "type": 1, + "hash": "0x45d50fb24eecc01fed1254b75e0ddc97c3d8825f02e68b75da3f16f14573cc53" + } + }, + "r": { + "type": 1, + "hash": "0x2e88c7335dcc28ef7cf618d77336b62f49c1d0c05d956e516eb9a37f556373e2" + } + } + } + } + }, + "r": { + "type": 1, + "hash": "0x4ad094e37e0ec880bb6a24f03f3bc3ca5fdb60af734606ba639bd413eb1a1e39" + } + } + }, + "proof_bytes": "0x0b0000001c00e5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470000001207f564883c631d43a902ef144a674e6ac11ed7db1c9e88ecf7a664c19885de497000120aa70d7aab4560bcafda057bcffca504f4d6ca89bc5652d4cf60a33e85a39bc5f000120c6e9e11d1ae2b9479e778fed77d273ced27cfee60b8d9c2cb0fce4efe5b1d1790000022056cf9617298303d80e0b0bc7a38e9807db5e6b5c1dbe32338ec54efa830f1d93012045d50fb24eecc01fed1254b75e0ddc97c3d8825f02e68b75da3f16f14573cc5301202e88c7335dcc28ef7cf618d77336b62f49c1d0c05d956e516eb9a37f556373e201204ad094e37e0ec880bb6a24f03f3bc3ca5fdb60af734606ba639bd413eb1a1e39" +} diff --git a/sdk/tests/types/fixtures/tip45_five_output_proof.json b/sdk/tests/types/fixtures/tip45_five_output_proof.json new file mode 100644 index 0000000000..69f05bb498 --- /dev/null +++ b/sdk/tests/types/fixtures/tip45_five_output_proof.json @@ -0,0 +1,34 @@ +{ + "transaction_bytes": "0x01fb5c44ef0d3ac8730b0000000000010000f09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed719520000000000000000013f0000000006000040420f0000000000000000000000000001000041b5fc0f730776b9d25dc9ffba236ce34bd9433f8a4bc8e286612e42654e0138000040420f00000000000000000000000000010000c5797137d27ceeb1d7a7f712b2dbbd2cb6b9e3fa39fe98a7751ea5913f00495d000040420f00000000000000000000000000010000c3d789866209202d21895e9a5a69ceb4b1fba08f53237c697e32cf6780a89a71000040420f000000000000000000000000000100008b1697f39c48f841e78e9e3fb2eae08d6af3463fc26fdfbf8ae23ad86ef5353d000040420f00000000000000000000000000010000145a6400ae4ce60e2192b6e538bb790a774db03070afaff1f0c83beedd15fa65000040420f00000000000000000000000000010000f25fbe26abe7ddc7b1ba9fc94a8f6c5a1ac025b0f8027fb7c5ec6047b771527100010000002daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257ac75b951fbf7c55b41b6323cd9b00fe5c444f3145d7bc75da7ae366756f01ee8a18a8e15c6321eb0972084d05422b6eb257869f6f5333ae17b763c0f111d65510e", + "proof": { + "slot": 11, + "outputIndex": 2, + "transactionCommitment": "0xe5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470", + "outputCommitmentProof": { + "type": 0, + "l": { + "type": 0, + "l": { + "type": 1, + "hash": "0xdb9fc09b2bdea181fd4f9775116a2ec3c27c93a7ce0ce8f5835fda73bfd09b49" + }, + "r": { + "type": 0, + "l": { + "type": 2, + "hash": "0xe6fc3cdc50433760d43adfe52426648597c092d8973a30529ad0058d6a03b55d" + }, + "r": { + "type": 1, + "hash": "0x7392fe9c9e518a0bc1b0f032e003dbf73096fb95a8bfdbfe05e05f67e0894038" + } + } + }, + "r": { + "type": 1, + "hash": "0xc00b8503cb3aa5473f1a4b4d68cdad468c52e628fdf8dc175caae2d8bec75297" + } + } + }, + "proof_bytes": "0x0b0000000200e5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f47000000120db9fc09b2bdea181fd4f9775116a2ec3c27c93a7ce0ce8f5835fda73bfd09b49000220e6fc3cdc50433760d43adfe52426648597c092d8973a30529ad0058d6a03b55d01207392fe9c9e518a0bc1b0f032e003dbf73096fb95a8bfdbfe05e05f67e08940380120c00b8503cb3aa5473f1a4b4d68cdad468c52e628fdf8dc175caae2d8bec75297" +} diff --git a/sdk/tests/types/fixtures/tip45_single_output_proof.json b/sdk/tests/types/fixtures/tip45_single_output_proof.json new file mode 100644 index 0000000000..4b8dc93491 --- /dev/null +++ b/sdk/tests/types/fixtures/tip45_single_output_proof.json @@ -0,0 +1,20 @@ +{ + "transaction_bytes": "0x01fb5c44ef0d3ac8730b0000000000010000f09d3cd648a7246c7c1b2ba2f9182465ae5742b78c592392b4b455ab8ed719520000000000000000013f0000000002000040420f0000000000000000000000000001000041b5fc0f730776b9d25dc9ffba236ce34bd9433f8a4bc8e286612e42654e0138000040420f00000000000000000000000000010000c5797137d27ceeb1d7a7f712b2dbbd2cb6b9e3fa39fe98a7751ea5913f00495d00010000002daefbcbadd044da470acd2f7fcf6fcb04b873cc801e7ee408018e1dfa0257acea95793c5a8aef7eeb0daa2a1632f0abf6eeb4c7ca19808f20f6101a6d22ea8f8b4d85dbbbd21d0ac521991a57536fbd37bccd85ab29254a3b5d2e534fda5506", + "proof": { + "slot": 11, + "outputIndex": 0, + "transactionCommitment": "0xe5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470", + "outputCommitmentProof": { + "type": 0, + "l": { + "type": 2, + "hash": "0xb750f19d60bdd576e8eb617d101ae54146b5511b76d41294b8b9a869f12ab13b" + }, + "r": { + "type": 1, + "hash": "0x6b9c6672c54f7dc2012fea833416a8425a3dc40a4855a63908e741568843ab72" + } + } + }, + "proof_bytes": "0x0b0000000000e5cd573b65e2e10f8811a5a5df5af36b385dc2d75bf13b7c731aa4660125f470000220b750f19d60bdd576e8eb617d101ae54146b5511b76d41294b8b9a869f12ab13b01206b9c6672c54f7dc2012fea833416a8425a3dc40a4855a63908e741568843ab72" +} diff --git a/sdk/tests/types/output/mod.rs b/sdk/tests/types/output/mod.rs index 986986ff7b..03173a9454 100644 --- a/sdk/tests/types/output/mod.rs +++ b/sdk/tests/types/output/mod.rs @@ -7,3 +7,4 @@ mod foundry; mod nft; mod feature; +mod proof; diff --git a/sdk/tests/types/output/proof.rs b/sdk/tests/types/output/proof.rs new file mode 100644 index 0000000000..35b6b465ec --- /dev/null +++ b/sdk/tests/types/output/proof.rs @@ -0,0 +1,55 @@ +// Copyright 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_sdk::{ + types::block::{output::OutputIdProof, payload::Payload}, + utils::serde::prefix_hex_bytes, +}; +use packable::PackableExt; +use pretty_assertions::assert_eq; +use serde::Deserialize; + +#[derive(Deserialize)] +struct ProofFixture { + #[serde(with = "prefix_hex_bytes")] + transaction_bytes: Vec, + proof: OutputIdProof, + proof_bytes: String, +} + +fn proof_fixture(filename: &str) -> Result> { + Ok(serde_json::from_value(serde_json::from_reader(std::fs::File::open( + format!("./tests/types/fixtures/{filename}"), + )?)?)?) +} + +#[test] +fn output_proofs() { + for filename in [ + // https://github.com/iotaledger/tips/blob/tip45/tips/TIP-0045/tip-0045.md#single-output + "tip45_single_output_proof.json", + // https://github.com/iotaledger/tips/blob/tip45/tips/TIP-0045/tip-0045.md#five-outputs + "tip45_five_output_proof.json", + // https://github.com/iotaledger/tips/blob/tip45/tips/TIP-0045/tip-0045.md#32-outputs + "tip45_32_output_proof_idx0.json", + "tip45_32_output_proof_idx28.json", + ] { + let fixture = proof_fixture(filename).unwrap_or_else(|e| panic!("failed to deserialize {filename}: {e}")); + + let payload = Payload::unpack_bytes_unverified(&fixture.transaction_bytes).unwrap(); + let transaction = payload.as_signed_transaction().transaction(); + assert_eq!( + transaction + .output_id_proof(fixture.proof.output_index) + .map(|p| serde_json::to_string_pretty(&p).unwrap()) + .unwrap(), + serde_json::to_string_pretty(&fixture.proof).unwrap(), + "proof mismatch for {filename}" + ); + assert_eq!( + prefix_hex::encode(fixture.proof.pack_to_vec()), + fixture.proof_bytes, + "byte mismatch for {filename}" + ); + } +} diff --git a/sdk/tests/wallet/events.rs b/sdk/tests/wallet/events.rs index e3460d2b3b..2293698ee1 100644 --- a/sdk/tests/wallet/events.rs +++ b/sdk/tests/wallet/events.rs @@ -53,11 +53,8 @@ fn wallet_events_serde() { output_id_proof: OutputIdProof { slot: SlotIndex(1), output_index: 0, - transaction_commitment: "0x".to_string(), - output_commitment_proof: OutputCommitmentProof::LeafHash(LeafHash { - kind: 1, - hash: [0u8; 32], - }), + transaction_commitment: [0u8; 32], + output_commitment_proof: OutputCommitmentProof::Leaf(LeafHash([0u8; 32])), }, network_id: 42, remainder: true, From 56b19d4c12c1bf23bc716b47c36018d37d5b3168 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Fri, 23 Feb 2024 20:50:30 +0100 Subject: [PATCH 9/9] Bump bech32 to 0.11 (#2064) --- Cargo.lock | 106 ++++++++++++++------------ sdk/Cargo.toml | 4 +- sdk/src/types/block/address/bech32.rs | 3 +- 3 files changed, 59 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d17d9b4709..c756a5ae9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -237,9 +237,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bech32" -version = "0.10.0-beta" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bincode" @@ -341,9 +341,9 @@ checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" [[package]] name = "bumpalo" -version = "3.15.2" +version = "3.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b1be7772ee4501dba05acbe66bb1e8760f6a6c474a36035631638e4415f130" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" [[package]] name = "byte-slice-cast" @@ -723,9 +723,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.6" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" dependencies = [ "darling_core", "darling_macro", @@ -733,9 +733,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.6" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" dependencies = [ "fnv", "ident_case", @@ -747,9 +747,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.6" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", @@ -1969,9 +1969,9 @@ dependencies = [ [[package]] name = "napi" -version = "2.15.2" +version = "2.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd92040344a83763379b122f4e714932ccaa700439e647f1e90481dd1999cb" +checksum = "72e0dc78e0524286630914db66e31bad70160e379705a9ce92e0161ce2389d89" dependencies = [ "bitflags 2.4.2", "ctor", @@ -2303,6 +2303,12 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + [[package]] name = "powerfmt" version = "0.2.0" @@ -2403,15 +2409,16 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a89dc7a5850d0e983be1ec2a463a171d20990487c3cfcd68b5363f1ee3d6fe0" +checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233" dependencies = [ "cfg-if", "indoc", "libc", "memoffset 0.9.0", "parking_lot", + "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", @@ -2420,9 +2427,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07426f0d8fe5a601f26293f300afd1a7b1ed5e78b2a705870c5f30893c5163be" +checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7" dependencies = [ "once_cell", "target-lexicon", @@ -2430,9 +2437,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb7dec17e17766b46bca4f1a4215a85006b4c2ecde122076c562dd058da6cf1" +checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa" dependencies = [ "libc", "pyo3-build-config", @@ -2440,9 +2447,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f738b4e40d50b5711957f142878cfa0f28e054aa0ebdfc3fd137a843f74ed3" +checksum = "7305c720fa01b8055ec95e484a6eca7a83c841267f0dd5280f0c8b8551d2c158" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -2452,12 +2459,13 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc910d4851847827daf9d6cdd4a823fbdaab5b8818325c5e97a86da79e8881f" +checksum = "7c7e9b68bb9c3149c5b0cade5d07f953d6d125eb4337723c4ccdb665f1f96185" dependencies = [ "heck", "proc-macro2", + "pyo3-build-config", "quote", "syn 2.0.50", ] @@ -3033,12 +3041,12 @@ checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3749,7 +3757,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.3", ] [[package]] @@ -3769,17 +3777,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.3", + "windows_aarch64_msvc 0.52.3", + "windows_i686_gnu 0.52.3", + "windows_i686_msvc 0.52.3", + "windows_x86_64_gnu 0.52.3", + "windows_x86_64_gnullvm 0.52.3", + "windows_x86_64_msvc 0.52.3", ] [[package]] @@ -3790,9 +3798,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" [[package]] name = "windows_aarch64_msvc" @@ -3808,9 +3816,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" [[package]] name = "windows_i686_gnu" @@ -3826,9 +3834,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" [[package]] name = "windows_i686_msvc" @@ -3844,9 +3852,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" [[package]] name = "windows_x86_64_gnu" @@ -3862,9 +3870,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" [[package]] name = "windows_x86_64_gnullvm" @@ -3874,9 +3882,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" [[package]] name = "windows_x86_64_msvc" @@ -3892,9 +3900,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" [[package]] name = "winnow" diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index dbadc57941..8a07bc99f2 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -18,9 +18,7 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] # Mandatory dependencies -bech32 = { version = "0.10.0-beta", default-features = false, features = [ - "alloc", -] } +bech32 = { version = "0.11.0", default-features = false, features = ["alloc"] } bitflags = { version = "2.4.2", default-features = false } derive_more = { version = "0.99.17", default-features = false, features = [ "from", diff --git a/sdk/src/types/block/address/bech32.rs b/sdk/src/types/block/address/bech32.rs index 92db719127..c802c09267 100644 --- a/sdk/src/types/block/address/bech32.rs +++ b/sdk/src/types/block/address/bech32.rs @@ -60,8 +60,7 @@ impl Packable for Hrp { #[inline] fn pack(&self, packer: &mut P) -> Result<(), P::Error> { (self.0.len() as u8).pack(packer)?; - // TODO revisit when/if bech32 adds a way to get the bytes without iteration to avoid collecting - packer.pack_bytes(&self.0.byte_iter().collect::>())?; + packer.pack_bytes(self.0.as_bytes())?; Ok(()) }