From af7dab7961cd091427e7b6f2174000e6213dcc96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Tue, 11 Jul 2023 12:35:06 +0200 Subject: [PATCH] [feature] #3468: implement server-side cursor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- Cargo.lock | 888 ++++++++++-------- cli/Cargo.toml | 1 + cli/src/stream.rs | 2 +- cli/src/torii/cursor.rs | 79 ++ cli/src/torii/mod.rs | 53 +- cli/src/torii/pagination.rs | 97 +- cli/src/torii/routing.rs | 110 ++- cli/src/torii/utils.rs | 2 +- client/benches/torii.rs | 21 +- client/src/client.rs | 410 ++++---- client/src/http.rs | 12 +- client/src/http_default.rs | 12 +- client/tests/integration/asset.rs | 43 +- client/tests/integration/asset_propagation.rs | 6 +- .../integration/multiple_blocks_created.rs | 6 +- .../integration/multisignature_account.rs | 6 +- .../integration/multisignature_transaction.rs | 11 +- client/tests/integration/non_mintable.rs | 14 +- client/tests/integration/offline_peers.rs | 6 +- client/tests/integration/pagination.rs | 16 +- client/tests/integration/permissions.rs | 4 +- client/tests/integration/queries/account.rs | 6 +- client/tests/integration/queries/role.rs | 21 +- client/tests/integration/restart_peer.rs | 28 +- client/tests/integration/roles.rs | 14 +- client/tests/integration/set_parameter.rs | 11 +- client/tests/integration/sorting.rs | 114 ++- client/tests/integration/transfer_asset.rs | 6 +- .../integration/triggers/time_trigger.rs | 6 +- client/tests/integration/tx_history.rs | 17 +- client/tests/integration/tx_rollback.rs | 8 +- client/tests/integration/unregister_peer.rs | 6 +- client/tests/integration/unstable_network.rs | 6 +- client/tests/integration/upgrade.rs | 2 +- config/Cargo.toml | 1 + config/src/torii.rs | 18 +- configs/peer/config.json | 4 +- configs/peer/validator.wasm | Bin 377766 -> 379964 bytes core/benches/apply_blocks/apply_blocks.rs | 2 +- core/src/queue.rs | 4 +- core/src/smartcontracts/isi/account.rs | 28 +- core/src/smartcontracts/isi/asset.rs | 52 +- core/src/smartcontracts/isi/block.rs | 11 +- core/src/smartcontracts/isi/domain.rs | 23 +- core/src/smartcontracts/isi/query.rs | 12 +- core/src/smartcontracts/isi/triggers/mod.rs | 26 +- core/src/smartcontracts/isi/triggers/set.rs | 76 +- core/src/smartcontracts/isi/tx.rs | 19 +- core/src/smartcontracts/isi/world.rs | 27 +- core/src/smartcontracts/mod.rs | 6 +- core/src/smartcontracts/wasm.rs | 6 +- core/src/sumeragi/main_loop.rs | 1 - core/src/wsv.rs | 11 +- core/test_network/Cargo.toml | 1 + core/test_network/src/lib.rs | 112 +-- data_model/cbindgen.toml | 3 + .../transparent_api_private_item.stderr | 2 +- data_model/src/lib.rs | 15 +- data_model/src/numeric.rs | 2 +- data_model/src/pagination.rs | 122 --- data_model/src/predicate.rs | 30 +- data_model/src/query/cursor.rs | 57 ++ data_model/src/{query.rs => query/mod.rs} | 138 ++- data_model/src/query/pagination.rs | 60 ++ data_model/src/{ => query}/sorting.rs | 17 +- data_model/src/transaction.rs | 20 +- data_model/src/visit.rs | 2 + docs/source/references/config.md | 26 +- docs/source/references/schema.json | 96 +- lints.toml | 11 - macro/derive/src/lib.rs | 4 +- macro/utils/src/lib.rs | 4 +- schema/gen/src/lib.rs | 10 +- version/derive/src/lib.rs | 43 +- version/src/lib.rs | 4 +- wasm/src/lib.rs | 7 +- wasm/validator/derive/src/validate.rs | 4 +- 77 files changed, 1807 insertions(+), 1354 deletions(-) create mode 100644 cli/src/torii/cursor.rs create mode 100644 data_model/cbindgen.toml delete mode 100644 data_model/src/pagination.rs create mode 100644 data_model/src/query/cursor.rs rename data_model/src/{query.rs => query/mod.rs} (94%) create mode 100644 data_model/src/query/pagination.rs rename data_model/src/{ => query}/sorting.rs (77%) diff --git a/Cargo.lock b/Cargo.lock index 0f19e0b3c7f..4b23a94c854 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,11 +13,11 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ - "gimli 0.27.2", + "gimli 0.27.3", ] [[package]] @@ -203,9 +203,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" [[package]] name = "arc-swap" @@ -221,9 +221,9 @@ checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "async-stream" @@ -244,18 +244,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -301,9 +301,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" +checksum = "a6a1de45611fdb535bfde7b7de4fd54f4fd2b17b1737c0a59b69bf9b92074b8c" dependencies = [ "async-trait", "axum-core", @@ -346,16 +346,16 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ - "addr2line 0.19.0", + "addr2line 0.20.0", "cc", "cfg-if", "libc", - "miniz_oxide 0.6.2", - "object 0.30.4", + "miniz_oxide", + "object 0.31.1", "rustc-demangle", ] @@ -373,9 +373,9 @@ checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "basic-toml" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1" +checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" dependencies = [ "serde", ] @@ -412,9 +412,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" [[package]] name = "bitvec" @@ -497,13 +497,12 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bstr" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", - "once_cell", - "regex-automata", + "regex-automata 0.3.3", "serde", ] @@ -654,7 +653,7 @@ dependencies = [ "bitflags 1.3.2", "clap_derive 3.2.25", "clap_lex 0.2.4", - "indexmap", + "indexmap 1.9.3", "once_cell", "strsim", "termcolor", @@ -663,20 +662,20 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.11" +version = "4.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" +checksum = "8f644d0dac522c8b05ddc39aaaccc5b136d5dc4ff216610c5641e3be5becf56c" dependencies = [ "clap_builder", - "clap_derive 4.3.2", + "clap_derive 4.3.12", "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.11" +version = "4.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" +checksum = "af410122b9778e024f9e0fb35682cc09cc3f85cad5e8d3ba8f47a9702df6e73d" dependencies = [ "anstream", "anstyle", @@ -700,14 +699,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.2" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -776,13 +775,13 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.0.0" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ - "atty", + "is-terminal", "lazy_static", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -812,9 +811,9 @@ dependencies = [ [[package]] name = "console-subscriber" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ab2224a0311582eb03adba4caaf18644f7b1f10a760803a803b9b605187fc7" +checksum = "d4cf42660ac07fcebed809cfe561dd8730bcd35b075215e6479c516bcd0d11cb" dependencies = [ "console-api", "crossbeam-channel", @@ -867,9 +866,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -1058,14 +1057,14 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg 1.1.0", "cfg-if", "crossbeam-utils", - "memoffset 0.8.0", + "memoffset 0.9.0", "scopeguard", ] @@ -1081,9 +1080,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -1106,9 +1105,9 @@ dependencies = [ [[package]] name = "crossterm_winapi" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] @@ -1200,9 +1199,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.97" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88abab2f5abbe4c56e8f1fb431b784d710b709888f35755a160e62e33fe38e8" +checksum = "5032837c1384de3708043de9d4e97bb91290faca6c16529a28aa340592a78166" dependencies = [ "cc", "cxxbridge-flags", @@ -1212,9 +1211,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.97" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0c11acd0e63bae27dcd2afced407063312771212b7a823b4fd72d633be30fb" +checksum = "51368b3d0dbf356e10fcbfd455a038503a105ee556f7ee79b6bb8c53a7247456" dependencies = [ "cc", "codespan-reporting", @@ -1222,31 +1221,31 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "cxxbridge-flags" -version = "1.0.97" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3816ed957c008ccd4728485511e3d9aaf7db419aa321e3d2c5a2f3411e36c8" +checksum = "0d9062157072e4aafc8e56ceaf8325ce850c5ae37578c852a0d4de2cecdded13" [[package]] name = "cxxbridge-macro" -version = "1.0.97" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26acccf6f445af85ea056362561a24ef56cdc15fcc685f03aec50b9c702cb6d" +checksum = "cf01e8a540f5a4e0f284595834f81cf88572f244b768f051724537afa99a2545" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "darling" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ "darling_core", "darling_macro", @@ -1254,37 +1253,37 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "darling_macro" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "dashmap" -version = "5.4.0" +version = "5.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown 0.14.0", "lock_api", "once_cell", "parking_lot_core", @@ -1377,14 +1376,14 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "dissimilar" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "210ec60ae7d710bed8683e333e9d2855a8a56a3e9892b38bad3bb0d4d29b0d5e" +checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "duct" @@ -1406,9 +1405,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "dyn-clone" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" +checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" [[package]] name = "ecdsa" @@ -1495,11 +1494,17 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "erased-serde" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2b0c2380453a92ea8b6c8e5f64ecaafccddde8ceab55ff7a8ac1029f894569" +checksum = "da96524cc884f6558f1769b6c46686af2fe8e8b4cd253bd5a3cdba8181b8e070" dependencies = [ "serde", ] @@ -1593,6 +1598,12 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + [[package]] name = "ff" version = "0.10.1" @@ -1652,7 +1663,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", - "miniz_oxide 0.7.1", + "miniz_oxide", ] [[package]] @@ -1747,7 +1758,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -1871,24 +1882,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" dependencies = [ "fallible-iterator", - "indexmap", + "indexmap 1.9.3", "stable_deref_trait", ] [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "gix" -version = "0.44.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf41b61f7df395284f7a579c0fa1a7e012c5aede655174d4e91299ef1cac643" +checksum = "c1e74cea676de7f53a79f3c0365812b11f6814b81e671b8ee4abae6ca09c7881" dependencies = [ "gix-actor", "gix-attributes", + "gix-commitgraph", "gix-config", "gix-credentials", "gix-date", @@ -1903,6 +1915,7 @@ dependencies = [ "gix-index", "gix-lock", "gix-mailmap", + "gix-negotiate", "gix-object", "gix-odb", "gix-pack", @@ -1913,6 +1926,7 @@ dependencies = [ "gix-revision", "gix-sec", "gix-tempfile", + "gix-trace", "gix-traverse", "gix-url", "gix-utils", @@ -1928,9 +1942,9 @@ dependencies = [ [[package]] name = "gix-actor" -version = "0.20.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848efa0f1210cea8638f95691c82a46f98a74b9e3524f01d4955ebc25a8f84f3" +checksum = "1969b77b9ee4cc1755c841987ec6f7622aaca95e952bcafb76973ae59d1b8716" dependencies = [ "bstr", "btoi", @@ -1942,9 +1956,9 @@ dependencies = [ [[package]] name = "gix-attributes" -version = "0.12.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3015baa01ad2122fbcaab7863c857a603eb7b7ec12ac8141207c42c6439805e2" +checksum = "e3772b0129dcd1fc73e985bbd08a1482d082097d2915cb1ee31ce8092b8e4434" dependencies = [ "bstr", "gix-glob", @@ -1959,36 +1973,50 @@ dependencies = [ [[package]] name = "gix-bitmap" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc02feb20ad313d52a450852f2005c2205d24f851e74d82b7807cbe12c371667" +checksum = "311e2fa997be6560c564b070c5da2d56d038b645a94e1e5796d5d85a350da33c" dependencies = [ "thiserror", ] [[package]] name = "gix-chunk" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7acf3bc6c4b91e8fb260086daf5e105ea3a6d913f5fd3318137f7e309d6e540" +checksum = "39db5ed0fc0a2e9b1b8265993f7efdbc30379dec268f3b91b7af0c2de4672fdd" dependencies = [ "thiserror", ] [[package]] name = "gix-command" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6141b70cfb21255223e42f3379855037cbbe8673b58dd8318d2f09b516fad1" +checksum = "bb49ab557a37b0abb2415bca2b10e541277dff0565deb5bd5e99fd95f93f51eb" dependencies = [ "bstr", ] +[[package]] +name = "gix-commitgraph" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed42baa50075d41c1a0931074ce1a97c5797c7c6fe7591d9f1f2dcd448532c26" +dependencies = [ + "bstr", + "gix-chunk", + "gix-features", + "gix-hash", + "memmap2", + "thiserror", +] + [[package]] name = "gix-config" -version = "0.22.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d252a0eddb6df74600d3d8872dc9fe98835a7da43110411d705b682f49d4ac1" +checksum = "817688c7005a716d9363e267913526adea402dabd947f4ba63842d10cc5132af" dependencies = [ "bstr", "gix-config-value", @@ -2008,11 +2036,11 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f216df1c33e6e1555923eff0096858a879e8aaadd35b5d788641e4e8064c892" +checksum = "83960be5e99266bcf55dae5a24731bbd39f643bfb68f27e939d6b06836b5b87d" dependencies = [ - "bitflags 2.3.1", + "bitflags 2.3.3", "bstr", "gix-path", "libc", @@ -2021,9 +2049,9 @@ dependencies = [ [[package]] name = "gix-credentials" -version = "0.14.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4874a4fc11ffa844a3c2b87a66957bda30a73b577ef1acf15ac34df5745de5ff" +checksum = "75a75565e0e6e7f80cfa4eb1b05cc448c6846ddd48dcf413a28875fbc11ee9af" dependencies = [ "bstr", "gix-command", @@ -2037,21 +2065,21 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc164145670e9130a60a21670d9b6f0f4f8de04e5dd256c51fa5a0340c625902" +checksum = "8e9a04a1d2387c955ec91059d56b673000dd24f3c07cad08ed253e36381782bf" dependencies = [ "bstr", "itoa", "thiserror", - "time 0.3.22", + "time 0.3.23", ] [[package]] name = "gix-diff" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644a0f2768bc42d7a69289ada80c9e15c589caefc6a315d2307202df83ed1186" +checksum = "aaf5d9b9b521b284ebe53ee69eee33341835ec70edc314f36b2100ea81396121" dependencies = [ "gix-hash", "gix-object", @@ -2061,9 +2089,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.18.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a6b61363e63e7cdaa3e6f96acb0257ebdb3d8883e21eba5930c99f07f0a5fc0" +checksum = "272aad20dc63dedba76615373dd8885fb5aebe4795e5b5b0aa2a24e63c82085c" dependencies = [ "bstr", "dunce", @@ -2076,13 +2104,14 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf69b0f5c701cc3ae22d3204b671907668f6437ca88862d355eaf9bc47a4f897" +checksum = "06142d8cff5d17509399b04052b64d2f9b3a311d5cff0b1a32b220f62cd0d595" dependencies = [ "crc32fast", "flate2", "gix-hash", + "gix-trace", "libc", "once_cell", "prodash", @@ -2093,20 +2122,20 @@ dependencies = [ [[package]] name = "gix-fs" -version = "0.1.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b37a1832f691fdc09910bd267f9a2e413737c1f9ec68c6e31f9e802616278a9" +checksum = "bb15956bc0256594c62a2399fcf6958a02a11724217eddfdc2b49b21b6292496" dependencies = [ "gix-features", ] [[package]] name = "gix-glob" -version = "0.7.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07c98204529ac3f24b34754540a852593d2a4c7349008df389240266627a72a" +checksum = "c18bdff83143d61e7d60da6183b87542a870d026b2a2d0b30170b8e9c0cd321a" dependencies = [ - "bitflags 2.3.1", + "bitflags 2.3.3", "bstr", "gix-features", "gix-path", @@ -2114,9 +2143,9 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee181c85d3955f54c4426e6bfaeeada4428692e1a39b8788c2ac7785fc301dd8" +checksum = "a0dd58cdbe7ffa4032fc111864c80d5f8cecd9a2c9736c97ae7e5be834188272" dependencies = [ "hex", "thiserror", @@ -2124,20 +2153,20 @@ dependencies = [ [[package]] name = "gix-hashtable" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd259bd0d96e6153e357a8cdaca76c48e103fd34208b6c0ce77b1ad995834bd2" +checksum = "9e133bc56d938eaec1c675af7c681a51de9662b0ada779f45607b967a10da77a" dependencies = [ "gix-hash", - "hashbrown 0.13.2", + "hashbrown 0.14.0", "parking_lot", ] [[package]] name = "gix-ignore" -version = "0.2.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba205b6df563e2906768bb22834c82eb46c5fdfcd86ba2c347270bc8309a05b2" +checksum = "ca801f2d0535210f77b33e2c067d565aedecacc82f1b3dbce26da1388ebc4634" dependencies = [ "bstr", "gix-glob", @@ -2147,11 +2176,11 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.16.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f39c1ccc8f1912cbbd5191efc28dbc5f0d0598042aa56bc09427b7c34efab3ba" +checksum = "68099abdf6ee50ae3c897e8b05de96871cbe54d52a37cdf559101f911b883562" dependencies = [ - "bitflags 2.3.1", + "bitflags 2.3.3", "bstr", "btoi", "filetime", @@ -2169,9 +2198,9 @@ dependencies = [ [[package]] name = "gix-lock" -version = "5.0.1" +version = "7.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c693d7f05730fa74a7c467150adc7cea393518410c65f0672f80226b8111555" +checksum = "714bcb13627995ac33716e9c5e4d25612b19947845395f64d2a9cbe6007728e4" dependencies = [ "gix-tempfile", "gix-utils", @@ -2180,24 +2209,42 @@ dependencies = [ [[package]] name = "gix-mailmap" -version = "0.12.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8856cec3bdc3610c06970d28b6cb20a0c6621621cf9a8ec48cbd23f2630f362" +checksum = "1787e3c37fc43b1f7c0e3be6196c6837b3ba5f869190dfeaa444b816f0a7f34b" dependencies = [ "bstr", "gix-actor", + "gix-date", + "thiserror", +] + +[[package]] +name = "gix-negotiate" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7bce64d4452dd609f44d04b14b29da2e0ad2c45fcdf4ce1472a5f5f8ec21c2" +dependencies = [ + "bitflags 2.3.3", + "gix-commitgraph", + "gix-date", + "gix-hash", + "gix-object", + "gix-revwalk", + "smallvec", "thiserror", ] [[package]] name = "gix-object" -version = "0.29.2" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d96bd620fd08accdd37f70b2183cfa0b001b4f1c6ade8b7f6e15cb3d9e261ce" +checksum = "a953f3d7ffad16734aa3ab1d05807972c80e339d1bd9dde03e0198716b99e2a6" dependencies = [ "bstr", "btoi", "gix-actor", + "gix-date", "gix-features", "gix-hash", "gix-validate", @@ -2210,11 +2257,12 @@ dependencies = [ [[package]] name = "gix-odb" -version = "0.45.0" +version = "0.49.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2f324aa67672b6d0f2c0fa93f96eb6a7029d260e4c1df5dce3c015f5e5add" +checksum = "f6418cff00ecc2713b58c8e04bff30dda808fbba1a080e7248b299d069894a01" dependencies = [ "arc-swap", + "gix-date", "gix-features", "gix-hash", "gix-object", @@ -2228,9 +2276,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.35.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164a515900a83257ae4aa80e741655bee7a2e39113fb535d7a5ac623b445ff20" +checksum = "414935138d90043ea5898de7a93f02c2558e52652492719470e203ef26a8fd0a" dependencies = [ "clru", "gix-chunk", @@ -2250,11 +2298,12 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1226f2e50adeb4d76c754c1856c06f13a24cad1624801653fbf09b869e5b808" +checksum = "dfca182d2575ded2ed38280f1ebf75cd5d3790b77e0872de07854cf085821fbe" dependencies = [ "bstr", + "gix-trace", "home", "once_cell", "thiserror", @@ -2262,22 +2311,22 @@ dependencies = [ [[package]] name = "gix-prompt" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e15fe57fa48572b7d3bf465d6a2a0351cd3c55cba74fd5f0b9c23689f9c1a31e" +checksum = "8dfd363fd89a40c1e7bff9c9c1b136cd2002480f724b0c627c1bc771cd5480ec" dependencies = [ "gix-command", "gix-config-value", "parking_lot", - "rustix 0.37.19", + "rustix 0.37.23", "thiserror", ] [[package]] name = "gix-quote" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d59489bff95b06dcdabe763b7266d3dc0a628cac1ac1caf65a7ca0a43eeae0" +checksum = "3874de636c2526de26a3405b8024b23ef1a327bebf4845d770d00d48700b6a40" dependencies = [ "bstr", "btoi", @@ -2286,11 +2335,12 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.29.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e03989e9d49954368e1b526578230fc7189d1634acdfbe79e9ba1de717e15d5" +checksum = "39453f4e5f23cddc2e6e4cca2ba20adfdbec29379e3ca829714dfe98ae068ccd" dependencies = [ "gix-actor", + "gix-date", "gix-features", "gix-fs", "gix-hash", @@ -2306,9 +2356,9 @@ dependencies = [ [[package]] name = "gix-refspec" -version = "0.10.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6ea733820df67e4cd7797deb12727905824d8f5b7c59d943c456d314475892" +checksum = "b8e76ff1f82fba295a121e31ab02f69642994e532c45c0c899aa393f4b740302" dependencies = [ "bstr", "gix-hash", @@ -2320,25 +2370,41 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.13.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "810f35e9afeccca999d5d348b239f9c162353127d2e13ff3240e31b919e35476" +checksum = "237428a7d3978e8572964e1e45d984027c2acc94df47e594baa6c4b0da7c9922" dependencies = [ "bstr", "gix-date", "gix-hash", "gix-hashtable", "gix-object", + "gix-revwalk", + "thiserror", +] + +[[package]] +name = "gix-revwalk" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028d50fcaf8326a8f79a359490d9ca9fb4e2b51ac9ac86503560d0bcc888d2eb" +dependencies = [ + "gix-commitgraph", + "gix-date", + "gix-hash", + "gix-hashtable", + "gix-object", + "smallvec", "thiserror", ] [[package]] name = "gix-sec" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b7b38b766eb95dcc5350a9c450030b69892c0902fa35f4a6d0809273bd9dae" +checksum = "ede298863db2a0574a14070991710551e76d1f47c9783b62d4fcbca17f56371c" dependencies = [ - "bitflags 2.3.1", + "bitflags 2.3.3", "gix-path", "libc", "windows", @@ -2346,9 +2412,9 @@ dependencies = [ [[package]] name = "gix-tempfile" -version = "5.0.3" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71a0d32f34e71e86586124225caefd78dabc605d0486de580d717653addf182" +checksum = "4fac8310c17406ea619af72f42ee46dac795110f68f41b4f4fa231b69889c6a2" dependencies = [ "gix-fs", "libc", @@ -2359,23 +2425,33 @@ dependencies = [ "tempfile", ] +[[package]] +name = "gix-trace" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "103eac621617be3ebe0605c9065ca51a223279a23218aaf67d10daa6e452f663" + [[package]] name = "gix-traverse" -version = "0.25.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5be1e807f288c33bb005075111886cceb43ed8a167b3182a0f62c186e2a0dd1" +checksum = "e3cdfd54598db4fae57d5ae6f52958422b2d13382d2745796bfe5c8015ffa86e" dependencies = [ + "gix-commitgraph", + "gix-date", "gix-hash", "gix-hashtable", "gix-object", + "gix-revwalk", + "smallvec", "thiserror", ] [[package]] name = "gix-url" -version = "0.18.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc77f89054297cc81491e31f1bab4027e554b5ef742a44bd7035db9a0f78b76" +checksum = "beaede6dbc83f408b19adfd95bb52f1dbf01fb8862c3faf6c6243e2e67fcdfa1" dependencies = [ "bstr", "gix-features", @@ -2387,18 +2463,18 @@ dependencies = [ [[package]] name = "gix-utils" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbcfcb150c7ef553d76988467d223254045bdcad0dc6724890f32fbe96415da5" +checksum = "7058c94f4164fcf5b8457d35f6d8f6e1007f9f7f938c9c7684a7e01d23c6ddde" dependencies = [ - "fastrand", + "fastrand 2.0.0", ] [[package]] name = "gix-validate" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ea5845b506c7728b9d89f4227cc369a5fc5a1d5b26c3add0f0d323413a3a60" +checksum = "8d092b594c8af00a3a31fe526d363ee8a51a6f29d8496cdb991ed2f01ec0ec13" dependencies = [ "bstr", "thiserror", @@ -2406,9 +2482,9 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.17.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69eaff0ae973a9d37c40f02ae5ae50fa726c8fc2fd3ab79d0a19eb61975aafa" +checksum = "c1363b9aa66b9e14412ac04e1f759827203f491729d92172535a8ce6cde02efa" dependencies = [ "bstr", "filetime", @@ -2444,9 +2520,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -2454,7 +2530,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -2484,9 +2560,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" [[package]] name = "hdrhistogram" @@ -2543,18 +2619,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -2642,9 +2709,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -2759,6 +2826,16 @@ dependencies = [ "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "inquire" version = "0.6.2" @@ -2812,7 +2889,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.2", "libc", "windows-sys 0.48.0", ] @@ -2823,6 +2900,7 @@ version = "2.0.0-pre-rc.16" dependencies = [ "async-trait", "color-eyre", + "dashmap", "displaydoc", "eyre", "futures", @@ -2938,6 +3016,7 @@ dependencies = [ "iroha_data_model", "iroha_primitives", "json5", + "once_cell", "path-absolutize", "proptest", "serde", @@ -3395,13 +3474,12 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes 1.0.11", - "rustix 0.37.19", + "hermit-abi 0.3.2", + "rustix 0.38.4", "windows-sys 0.48.0", ] @@ -3422,9 +3500,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "ittapi-rs" @@ -3446,9 +3524,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -3480,7 +3558,7 @@ dependencies = [ name = "kagami" version = "2.0.0-pre-rc.16" dependencies = [ - "clap 4.3.11", + "clap 4.3.15", "color-eyre", "derive_more", "duct", @@ -3529,7 +3607,7 @@ dependencies = [ name = "kura_inspector" version = "2.0.0-pre-rc.16" dependencies = [ - "clap 4.3.11", + "clap 4.3.15", "iroha_core", "iroha_data_model", "iroha_version", @@ -3549,9 +3627,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.146" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libm" @@ -3561,9 +3639,9 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "link-cplusplus" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" dependencies = [ "cc", ] @@ -3580,6 +3658,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + [[package]] name = "lock_api" version = "0.4.10" @@ -3592,9 +3676,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "mach" @@ -3611,7 +3695,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] @@ -3632,14 +3716,14 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" dependencies = [ - "rustix 0.37.19", + "rustix 0.37.23", ] [[package]] name = "memmap2" -version = "0.5.10" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6" dependencies = [ "libc", ] @@ -3655,9 +3739,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg 1.1.0", ] @@ -3684,15 +3768,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -3803,11 +3878,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.2", "libc", ] @@ -3828,15 +3903,15 @@ checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" dependencies = [ "crc32fast", "hashbrown 0.11.2", - "indexmap", + "indexmap 1.9.3", "memchr", ] [[package]] name = "object" -version = "0.30.4" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] @@ -3867,9 +3942,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.54" +version = "0.10.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -3888,7 +3963,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -3908,9 +3983,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.88" +version = "0.9.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" dependencies = [ "cc", "libc", @@ -3931,9 +4006,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.0" +version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" +checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" [[package]] name = "overload" @@ -3952,9 +4027,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.5.0" +version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ddb756ca205bd108aee3c62c6d3c994e1df84a59b9d6d4a5ea42ee1fd5a9a28" +checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" dependencies = [ "arrayvec", "bitvec", @@ -3966,9 +4041,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.4" +version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3980,7 +4055,7 @@ dependencies = [ name = "parity_scale_decoder" version = "2.0.0-pre-rc.16" dependencies = [ - "clap 4.3.11", + "clap 4.3.15", "colored", "eyre", "iroha_crypto", @@ -4018,14 +4093,14 @@ dependencies = [ "redox_syscall 0.3.5", "smallvec", "thread-id", - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "path-absolutize" @@ -4059,9 +4134,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e68e84bfb01f0507134eac1e9b410a12ba379d064eab48c50ba4ce329a527b70" +checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5" dependencies = [ "thiserror", "ucd-trie", @@ -4069,9 +4144,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b79d4c71c865a25a4322296122e3924d30bc8ee0834c8bfc8b95f7f054afbfb" +checksum = "5f94bca7e7a599d89dea5dfa309e217e7906c3c007fb9c3299c40b10d6a315d3" dependencies = [ "pest", "pest_generator", @@ -4079,26 +4154,26 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c435bf1076437b851ebc8edc3a18442796b30f1728ffea6262d59bbe28b077e" +checksum = "99d490fe7e8556575ff6911e45567ab95e71617f43781e5c05490dc8d75c965c" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "pest_meta" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745a452f8eb71e39ffd8ee32b3c5f51d03845f99786fa9b68db6ff509c505411" +checksum = "2674c66ebb4b4d9036012091b537aae5878970d6999f81a265034d85b136b341" dependencies = [ "once_cell", "pest", - "sha2 0.10.6", + "sha2 0.10.7", ] [[package]] @@ -4108,34 +4183,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.3", ] [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -4161,9 +4236,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "plotters" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ "num-traits", "plotters-backend", @@ -4174,15 +4249,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" [[package]] name = "plotters-svg" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" dependencies = [ "plotters-backend", ] @@ -4250,18 +4325,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "prodash" -version = "23.1.2" +version = "25.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d" +checksum = "c236e70b7f9b9ea00d33c69f63ec1ae6e9ae96118923cd37bd4e9c7396f0b107" [[package]] name = "prometheus" @@ -4346,9 +4421,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.28" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -4595,13 +4670,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.2", + "regex-automata 0.3.3", + "regex-syntax 0.7.4", ] [[package]] @@ -4613,6 +4689,17 @@ dependencies = [ "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.4", +] + [[package]] name = "regex-syntax" version = "0.6.29" @@ -4621,9 +4708,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "region" @@ -4651,9 +4738,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.35.13" +version = "0.35.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" +checksum = "6380889b07a03b5ecf1d44dc9ede6fd2145d84b502a2a9ca0b03c48e0cc3220f" dependencies = [ "bitflags 1.3.2", "errno 0.2.8", @@ -4665,9 +4752,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags 1.3.2", "errno 0.3.1", @@ -4677,20 +4764,33 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rustix" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +dependencies = [ + "bitflags 2.3.3", + "errno 0.3.1", + "libc", + "linux-raw-sys 0.4.3", + "windows-sys 0.48.0", +] + [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ "base64 0.21.2", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "rusty-fork" @@ -4706,9 +4806,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "same-file" @@ -4721,11 +4821,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -4736,15 +4836,15 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scratch" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" [[package]] name = "sealed" @@ -4755,7 +4855,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -4803,18 +4903,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.163" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.9" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] @@ -4831,20 +4931,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", @@ -4882,16 +4982,16 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "serde_yaml" -version = "0.9.21" +version = "0.9.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" +checksum = "bd5f51e3fdb5b9cdd1577e1cb7a733474191b1aca6a72c2e50913241632c1180" dependencies = [ - "indexmap", + "indexmap 2.0.0", "itoa", "ryu", "serde", @@ -4980,9 +5080,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -4991,12 +5091,15 @@ dependencies = [ [[package]] name = "sha256" -version = "1.1.4" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a975c1bc0941703000eaf232c4d8ce188d8d5408d6344b6b2c8c6262772828" +checksum = "f894f93906f2a96d3a75a60362f790e71247c588d9f87e97796db1e94bcb808e" dependencies = [ + "async-trait", + "bytes", "hex", - "sha2 0.10.6", + "sha2 0.10.7", + "tokio", ] [[package]] @@ -5051,9 +5154,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "signal-hook" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +checksum = "b824b6e687aff278cdbf3b36f07aa52d4bd4099699324d5da86a2ebce3aa00b3" dependencies = [ "libc", "signal-hook-registry", @@ -5116,9 +5219,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" dependencies = [ "serde", ] @@ -5256,9 +5359,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.23" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -5291,9 +5394,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.7" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" +checksum = "df8e77cb757a61f51b947ec4a7e3646efd825b73561db1c232a8ccb639e611a0" [[package]] name = "tempfile" @@ -5303,9 +5406,9 @@ checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ "autocfg 1.1.0", "cfg-if", - "fastrand", + "fastrand 1.9.0", "redox_syscall 0.3.5", - "rustix 0.37.19", + "rustix 0.37.23", "windows-sys 0.48.0", ] @@ -5328,6 +5431,7 @@ dependencies = [ "iroha_client", "iroha_config", "iroha_core", + "iroha_crypto", "iroha_data_model", "iroha_genesis", "iroha_logger", @@ -5356,22 +5460,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -5414,9 +5518,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" dependencies = [ "itoa", "libc", @@ -5434,9 +5538,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" dependencies = [ "time-core", ] @@ -5468,11 +5572,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg 1.1.0", + "backtrace", "bytes", "libc", "mio", @@ -5503,7 +5608,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -5590,17 +5695,17 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap", + "indexmap 2.0.0", "toml_datetime", "winnow", ] @@ -5641,7 +5746,7 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 1.9.3", "pin-project", "pin-project-lite", "rand 0.8.5", @@ -5680,27 +5785,27 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] name = "tracing-bunyan-formatter" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a348912d4e90923cb93343691d3be97e3409607363706c400fc935bb032fb0" +checksum = "464ce79ea7f689ca56d90a9c5563e803a4b61b2695e789205644ed8e8101e6bf" dependencies = [ "ahash 0.8.3", "gethostname", "log", "serde", "serde_json", - "time 0.3.22", + "time 0.3.23", "tracing", "tracing-core", "tracing-log", @@ -5784,9 +5889,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "trybuild" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501dbdbb99861e4ab6b60eb6a7493956a9defb644fd034bc4a5ef27c693c8a3a" +checksum = "04366e99ff743345622cd00af2af01d711dc2d1ef59250d7347698d21b546729" dependencies = [ "basic-toml", "glob", @@ -5863,9 +5968,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unarray" @@ -5896,9 +6001,9 @@ checksum = "98e90c70c9f0d4d1ee6d0a7d04aa06cb9bbd53d8cfbdd62a0269a7c2eb640552" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -5948,9 +6053,9 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" [[package]] name = "url" @@ -6035,14 +6140,14 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "8.2.1" +version = "8.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3c89c2c7e50f33e4d35527e5bf9c11d6d132226dbbd1753f0fbe9f19ef88c6" +checksum = "bbc5ad0d9d26b2c49a5ab7da76c3e79d3ee37e7821799f8223fcb8f2f391a2e7" dependencies = [ "anyhow", "gix", "rustversion", - "time 0.3.22", + "time 0.3.23", ] [[package]] @@ -6072,11 +6177,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -6131,9 +6235,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -6141,24 +6245,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6166,28 +6270,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-encoder" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c41dbd92eaebf3612a39be316540b8377c871cb9bde6b064af962984912881" +checksum = "06a3d1b4a575ffb873679402b2aedb3117555eb65c27b1b86c8a91e574bc2a2a" dependencies = [ "leb128", ] @@ -6238,7 +6342,7 @@ version = "0.86.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bcbfe95447da2aa7ff171857fc8427513eb57c75a729bb190e974dc695e8f5c" dependencies = [ - "indexmap", + "indexmap 1.9.3", ] [[package]] @@ -6252,7 +6356,7 @@ dependencies = [ "backtrace", "bincode", "cfg-if", - "indexmap", + "indexmap 1.9.3", "lazy_static", "libc", "log", @@ -6287,7 +6391,7 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix 0.35.13", + "rustix 0.35.14", "serde", "sha2 0.9.9", "toml", @@ -6326,7 +6430,7 @@ dependencies = [ "anyhow", "cranelift-entity", "gimli 0.26.2", - "indexmap", + "indexmap 1.9.3", "log", "more-asserts", "object 0.28.4", @@ -6345,7 +6449,7 @@ checksum = "2f6aba0b317746e8213d1f36a4c51974e66e69c1f05bfc09ed29b4d4bda290eb" dependencies = [ "cc", "cfg-if", - "rustix 0.35.13", + "rustix 0.35.14", "windows-sys 0.36.1", ] @@ -6366,7 +6470,7 @@ dependencies = [ "object 0.28.4", "region", "rustc-demangle", - "rustix 0.35.13", + "rustix 0.35.14", "serde", "target-lexicon", "thiserror", @@ -6384,7 +6488,7 @@ checksum = "55e23273fddce8cab149a0743c46932bf4910268641397ed86b46854b089f38f" dependencies = [ "lazy_static", "object 0.28.4", - "rustix 0.35.13", + "rustix 0.35.14", ] [[package]] @@ -6397,7 +6501,7 @@ dependencies = [ "backtrace", "cc", "cfg-if", - "indexmap", + "indexmap 1.9.3", "libc", "log", "mach", @@ -6406,7 +6510,7 @@ dependencies = [ "more-asserts", "rand 0.8.5", "region", - "rustix 0.35.13", + "rustix 0.35.14", "thiserror", "wasmtime-environ", "wasmtime-fiber", @@ -6428,9 +6532,9 @@ dependencies = [ [[package]] name = "wast" -version = "60.0.0" +version = "62.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd06cc744b536e30387e72a48fdd492105b9c938bb4f415c39c616a7a0a697ad" +checksum = "c7f7ee878019d69436895f019b65f62c33da63595d8e857cbdc87c13ecb29a32" dependencies = [ "leb128", "memchr", @@ -6440,18 +6544,18 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5abe520f0ab205366e9ac7d3e6b2fc71de44e32a2b58f2ec871b6b575bdcea3b" +checksum = "295572bf24aa5b685a971a83ad3e8b6e684aaad8a9be24bc7bf59bed84cc1c08" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -6510,7 +6614,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -6556,7 +6660,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -6576,9 +6680,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm 0.48.0", "windows_aarch64_msvc 0.48.0", @@ -6705,9 +6809,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" dependencies = [ "memchr", ] @@ -6749,7 +6853,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index fc07c845864..328ebcae528 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -67,6 +67,7 @@ thiserror = { workspace = true } displaydoc = { workspace = true } tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "rt-multi-thread", "macros", "fs", "signal"] } warp = { workspace = true, features = ["multipart", "websocket"] } +dashmap = "5.4.0" serial_test = "0.8.0" once_cell = { workspace = true } owo-colors = { workspace = true, features = ["supports-colors"] } diff --git a/cli/src/stream.rs b/cli/src/stream.rs index ade044472b7..340923c9426 100644 --- a/cli/src/stream.rs +++ b/cli/src/stream.rs @@ -13,7 +13,7 @@ const TIMEOUT: Duration = Duration::from_millis(10_000); const TIMEOUT: Duration = Duration::from_millis(1000); /// Error type with generic for actual Stream/Sink error type -#[derive(thiserror::Error, displaydoc::Display, Debug)] +#[derive(Debug, displaydoc::Display, thiserror::Error)] #[ignore_extra_doc_attributes] pub enum Error where diff --git a/cli/src/torii/cursor.rs b/cli/src/torii/cursor.rs new file mode 100644 index 00000000000..aae3713314c --- /dev/null +++ b/cli/src/torii/cursor.rs @@ -0,0 +1,79 @@ +use std::num::NonZeroUsize; + +use iroha_data_model::query::ForwardCursor; + +use crate::torii::{Error, Result}; + +pub trait Batch: IntoIterator + Sized { + fn batched(self, fetch_size: NonZeroUsize) -> Batched; +} + +impl Batch for I { + fn batched(self, batch_size: NonZeroUsize) -> Batched { + Batched { + iter: self.into_iter(), + batch_size, + cursor: ForwardCursor::default(), + } + } +} + +/// Paginated [`Iterator`]. +/// Not recommended to use directly, only use in iterator chains. +#[derive(Debug)] +pub struct Batched { + iter: I::IntoIter, + batch_size: NonZeroUsize, + cursor: ForwardCursor, +} + +impl> Batched { + pub(crate) fn next_batch(&mut self, cursor: ForwardCursor) -> Result<(I, ForwardCursor)> { + if cursor != self.cursor { + return Err(Error::UnknownCursor); + } + + let mut batch_size = 0; + let batch: I = self + .iter + .by_ref() + .inspect(|_| batch_size += 1) + .take(self.batch_size.get()) + .collect(); + + self.cursor.cursor = if let Some(cursor) = self.cursor.cursor { + if batch_size >= self.batch_size.get() { + let batch_size = self + .batch_size + .get() + .try_into() + .expect("usize should fit in u64"); + Some( + cursor + .checked_add(batch_size) + .expect("Cursor size should never reach the platform limit"), + ) + } else { + None + } + } else if batch_size >= self.batch_size.get() { + Some(self.batch_size.try_into().expect("usize should fit in u64")) + } else { + None + }; + + Ok((batch, self.cursor)) + } + + pub fn is_depleted(&self) -> bool { + self.cursor.cursor.is_none() + } +} + +impl Iterator for Batched { + type Item = I::Item; + + fn next(&mut self) -> Option { + self.iter.next() + } +} diff --git a/cli/src/torii/mod.rs b/cli/src/torii/mod.rs index 5490a31cf75..c98ba158b1d 100644 --- a/cli/src/torii/mod.rs +++ b/cli/src/torii/mod.rs @@ -7,8 +7,10 @@ use std::{ fmt::{Debug, Write as _}, net::ToSocketAddrs, sync::Arc, + time::{Duration, Instant}, }; +use dashmap::DashMap; use futures::{stream::FuturesUnordered, StreamExt}; use iroha_core::{ kura::Kura, @@ -17,8 +19,8 @@ use iroha_core::{ sumeragi::SumeragiHandle, EventsSender, }; -use thiserror::Error; -use tokio::sync::Notify; +use iroha_data_model::Value; +use tokio::{sync::Notify, time::sleep}; use utils::*; use warp::{ http::StatusCode, @@ -27,10 +29,44 @@ use warp::{ Filter as _, Reply, }; +use self::cursor::Batched; + #[macro_use] pub(crate) mod utils; +mod cursor; mod pagination; -pub mod routing; +mod routing; + +type LiveQuery = Batched>; + +#[derive(Default)] +struct LiveQueryStore { + queries: DashMap, (LiveQuery, Instant)>, +} + +impl LiveQueryStore { + fn insert(&self, request: Vec, live_query: LiveQuery) { + self.queries.insert(request, (live_query, Instant::now())); + } + + fn remove(&self, request: &Vec) -> Option<(Vec, LiveQuery)> { + self.queries + .remove(request) + .map(|(query_id, (query, _))| (query_id, query)) + } + + // TODO: Add notifier channel to enable graceful shutdown + fn expired_query_cleanup(self: Arc, idle_time: Duration) -> tokio::task::JoinHandle<()> { + tokio::task::spawn(async move { + loop { + sleep(idle_time).await; + + self.queries + .retain(|_, (_, last_access_time)| last_access_time.elapsed() <= idle_time); + } + }) + } +} /// Main network handler and the only entrypoint of the Iroha. pub struct Torii { @@ -39,11 +75,12 @@ pub struct Torii { events: EventsSender, notify_shutdown: Arc, sumeragi: SumeragiHandle, + query_store: Arc, kura: Arc, } /// Torii errors. -#[derive(Debug, Error, displaydoc::Display)] +#[derive(Debug, thiserror::Error, displaydoc::Display)] pub enum Error { /// Failed to execute or validate query Query(#[from] iroha_data_model::ValidationFail), @@ -58,10 +95,12 @@ pub enum Error { #[cfg(feature = "telemetry")] /// Error while getting Prometheus metrics Prometheus(#[source] eyre::Report), + /// Error while resuming cursor + UnknownCursor, } /// Status code for query error response. -pub(crate) fn query_status_code(validation_error: &iroha_data_model::ValidationFail) -> StatusCode { +fn query_status_code(validation_error: &iroha_data_model::ValidationFail) -> StatusCode { use iroha_data_model::{ isi::error::InstructionExecutionError, query::error::QueryExecutionFail::*, ValidationFail::*, @@ -104,7 +143,9 @@ impl Error { use Error::*; match self { Query(e) => query_status_code(e), - AcceptTransaction(_) | ConfigurationReload(_) => StatusCode::BAD_REQUEST, + AcceptTransaction(_) | ConfigurationReload(_) | UnknownCursor => { + StatusCode::BAD_REQUEST + } Config(_) => StatusCode::NOT_FOUND, PushIntoQueue(err) => match **err { queue::Error::Full => StatusCode::INTERNAL_SERVER_ERROR, diff --git a/cli/src/torii/pagination.rs b/cli/src/torii/pagination.rs index 2a20556a686..e305edbaec1 100644 --- a/cli/src/torii/pagination.rs +++ b/cli/src/torii/pagination.rs @@ -1,4 +1,4 @@ -use iroha_data_model::prelude::*; +use iroha_data_model::query::Pagination; /// Describes a collection to which pagination can be applied. /// Implemented for the [`Iterator`] implementors. @@ -7,53 +7,46 @@ pub trait Paginate: Iterator + Sized { fn paginate(self, pagination: Pagination) -> Paginated; } -impl Paginate for I { +impl Paginate for I { fn paginate(self, pagination: Pagination) -> Paginated { - Paginated { - pagination, - iter: self, - } + Paginated::new(pagination, self) } } /// Paginated [`Iterator`]. /// Not recommended to use directly, only use in iterator chains. #[derive(Debug)] -pub struct Paginated { - pagination: Pagination, - iter: I, +pub struct Paginated(core::iter::Take>); + +impl Paginated { + fn new(pagination: Pagination, iter: I) -> Self { + Self( + iter.skip(pagination.start.map_or_else( + || 0, + |start| start.get().try_into().expect("U64 should fit into usize"), + )) + .take(pagination.limit.map_or_else( + || usize::MAX, + |limit| limit.get().try_into().expect("U32 should fit into usize"), + )), + ) + } } impl Iterator for Paginated { type Item = I::Item; fn next(&mut self) -> Option { - if let Some(limit) = self.pagination.limit.as_mut() { - if *limit == 0 { - return None; - } - - *limit -= 1 - } - - #[allow(clippy::option_if_let_else)] - // Required because of E0524. 2 closures with unique refs to self - if let Some(start) = self.pagination.start.take() { - self.iter - .nth(start.try_into().expect("u32 should always fit in usize")) - } else { - self.iter.next() - } + self.0.next() } } -/// Filter for warp which extracts pagination -pub fn paginate() -> impl warp::Filter + Copy { - warp::query() -} - #[cfg(test)] mod tests { + use std::num::{NonZeroU32, NonZeroU64}; + + use iroha_data_model::query::pagination::Pagination; + use super::*; #[test] @@ -61,7 +54,10 @@ mod tests { assert_eq!( vec![1_i32, 2_i32, 3_i32] .into_iter() - .paginate(Pagination::new(None, None)) + .paginate(Pagination { + limit: None, + start: None + }) .collect::>(), vec![1_i32, 2_i32, 3_i32] ) @@ -72,21 +68,20 @@ mod tests { assert_eq!( vec![1_i32, 2_i32, 3_i32] .into_iter() - .paginate(Pagination::new(Some(0), None)) - .collect::>(), - vec![1_i32, 2_i32, 3_i32] - ); - assert_eq!( - vec![1_i32, 2_i32, 3_i32] - .into_iter() - .paginate(Pagination::new(Some(1), None)) + .paginate(Pagination { + limit: None, + start: NonZeroU64::new(1) + }) .collect::>(), vec![2_i32, 3_i32] ); assert_eq!( vec![1_i32, 2_i32, 3_i32] .into_iter() - .paginate(Pagination::new(Some(3), None)) + .paginate(Pagination { + limit: None, + start: NonZeroU64::new(3) + }) .collect::>(), Vec::::new() ); @@ -97,21 +92,20 @@ mod tests { assert_eq!( vec![1_i32, 2_i32, 3_i32] .into_iter() - .paginate(Pagination::new(None, Some(0))) - .collect::>(), - Vec::::new() - ); - assert_eq!( - vec![1_i32, 2_i32, 3_i32] - .into_iter() - .paginate(Pagination::new(None, Some(2))) + .paginate(Pagination { + limit: NonZeroU32::new(2), + start: None + }) .collect::>(), vec![1_i32, 2_i32] ); assert_eq!( vec![1_i32, 2_i32, 3_i32] .into_iter() - .paginate(Pagination::new(None, Some(4))) + .paginate(Pagination { + limit: NonZeroU32::new(4), + start: None + }) .collect::>(), vec![1_i32, 2_i32, 3_i32] ); @@ -122,7 +116,10 @@ mod tests { assert_eq!( vec![1_i32, 2_i32, 3_i32] .into_iter() - .paginate(Pagination::new(Some(1), Some(1))) + .paginate(Pagination { + limit: NonZeroU32::new(1), + start: NonZeroU64::new(1), + }) .collect::>(), vec![2_i32] ) diff --git a/cli/src/torii/routing.rs b/cli/src/torii/routing.rs index 63a6d2b5d33..01003c30360 100644 --- a/cli/src/torii/routing.rs +++ b/cli/src/torii/routing.rs @@ -5,8 +5,9 @@ // FIXME: This can't be fixed, because one trait in `warp` is private. #![allow(opaque_hidden_inferred_bound)] -use std::cmp::Ordering; +use std::{cmp::Ordering, num::NonZeroUsize}; +use cursor::Batch; use eyre::WrapErr; use futures::TryStreamExt; use iroha_config::{ @@ -28,22 +29,34 @@ use iroha_data_model::{ VersionedCommittedBlock, }, prelude::*, + query::{ForwardCursor, Pagination, Sorting}, }; #[cfg(feature = "telemetry")] use iroha_telemetry::metrics::Status; -use pagination::{paginate, Paginate}; +use pagination::Paginate; +use parity_scale_codec::Encode; use tokio::task; use super::*; use crate::stream::{Sink, Stream}; /// Filter for warp which extracts sorting -pub fn sorting() -> impl warp::Filter + Copy { +fn sorting() -> impl warp::Filter + Copy { + warp::query() +} + +/// Filter for warp which extracts cursor +fn cursor() -> impl warp::Filter + Copy { + warp::query() +} + +/// Filter for warp which extracts pagination +fn paginate() -> impl warp::Filter + Copy { warp::query() } #[iroha_futures::telemetry_future] -pub(crate) async fn handle_instructions( +async fn handle_instructions( queue: Arc, sumeragi: SumeragiHandle, transaction: VersionedSignedTransaction, @@ -67,30 +80,52 @@ pub(crate) async fn handle_instructions( } #[iroha_futures::telemetry_future] -pub(crate) async fn handle_queries( +async fn handle_queries( sumeragi: SumeragiHandle, - pagination: Pagination, - sorting: Sorting, + query_store: Arc, + fetch_size: NonZeroUsize, + request: VersionedSignedQuery, -) -> Result> { - let mut wsv = sumeragi.wsv_clone(); + sorting: Sorting, + pagination: Pagination, - let valid_request = ValidQueryRequest::validate(request, &mut wsv)?; - let result = valid_request.execute(&wsv).map_err(ValidationFail::from)?; + cursor: ForwardCursor, +) -> Result> { + let (query_id, mut live_query) = if cursor.cursor.is_some() { + let query_id = (&request, &sorting, &pagination).encode(); + query_store.remove(&query_id).ok_or(Error::UnknownCursor)? + } else { + let mut wsv = sumeragi.wsv_clone(); - let result = match result { - LazyValue::Value(value) => value, - LazyValue::Iter(iter) => { - Value::Vec(apply_sorting_and_pagination(iter, &sorting, pagination)) + let valid_request = ValidQueryRequest::validate(request, &mut wsv)?; + let res = valid_request.execute(&wsv).map_err(ValidationFail::from)?; + + match res { + LazyValue::Value(result) => { + let cursor = ForwardCursor::default(); + let result = QueryResponse { result, cursor }; + return Ok(Scale(result.into())); + } + LazyValue::Iter(iter) => { + let query_id = (&valid_request, &sorting, &pagination).encode(); + let query = apply_sorting_and_pagination(iter, &sorting, pagination); + (query_id, query.batched(fetch_size)) + } } }; - let paginated_result = QueryResult { - result, - pagination, - sorting, + let (batch, next_cursor) = live_query.next_batch(cursor)?; + + if !live_query.is_depleted() { + query_store.insert(query_id, live_query); + } + + let query_response = QueryResponse { + result: Value::Vec(batch), + cursor: next_cursor, }; - Ok(Scale(paginated_result.into())) + + Ok(Scale(query_response.into())) } fn apply_sorting_and_pagination( @@ -155,6 +190,7 @@ async fn handle_pending_transactions( sumeragi: SumeragiHandle, pagination: Pagination, ) -> Result>> { + // TODO: Don't clone wsv here let wsv = sumeragi.wsv_clone(); Ok(Scale( queue @@ -162,6 +198,9 @@ async fn handle_pending_transactions( .map(Into::into) .paginate(pagination) .collect::>(), + // TODO: + // NOTE: batching is done after collecting the result of pagination + //.batched(fetch_size) )) } @@ -292,7 +331,10 @@ mod subscription { /// There should be a [`warp::filters::ws::Message::close()`] /// message to end subscription #[iroha_futures::telemetry_future] - pub async fn handle_subscription(events: EventsSender, stream: WebSocket) -> eyre::Result<()> { + pub(crate) async fn handle_subscription( + events: EventsSender, + stream: WebSocket, + ) -> eyre::Result<()> { let mut consumer = event::Consumer::new(stream).await?; match subscribe_forever(events, &mut consumer).await { @@ -404,6 +446,7 @@ impl Torii { queue, notify_shutdown, sumeragi, + query_store: Arc::default(), kura, } } @@ -443,9 +486,7 @@ impl Torii { } /// Helper function to create router. This router can tested without starting up an HTTP server - pub(crate) fn create_api_router( - &self, - ) -> impl warp::Filter + Clone + Send { + fn create_api_router(&self) -> impl warp::Filter + Clone + Send { let health_route = warp::get() .and(warp::path(uri::HEALTH)) .and_then(|| async { Ok::<_, Infallible>(handle_health()) }); @@ -480,13 +521,19 @@ impl Torii { )) .and(body::versioned()), ) - .or(endpoint4( + .or(endpoint7( handle_queries, warp::path(uri::QUERY) - .and(add_state!(self.sumeragi)) - .and(paginate()) + .and(add_state!( + self.sumeragi, + self.query_store, + NonZeroUsize::try_from(self.iroha_cfg.torii.fetch_size) + .expect("u64 should always fit into usize"), + )) + .and(body::versioned()) .and(sorting()) - .and(body::versioned()), + .and(paginate()) + .and(cursor()), )) .or(endpoint2( handle_post_configuration, @@ -612,13 +659,16 @@ impl Torii { /// # Errors /// Can fail due to listening to network or if http server fails #[iroha_futures::telemetry_future] - pub async fn start(self) -> eyre::Result<()> { - let mut handles = vec![]; + pub(crate) async fn start(self) -> eyre::Result<()> { + let query_idle_time = Duration::from_millis(self.iroha_cfg.torii.query_idle_time_ms.get()); let torii = Arc::new(self); + let mut handles = vec![]; + #[cfg(feature = "telemetry")] handles.extend(Arc::clone(&torii).start_telemetry()?); handles.extend(Arc::clone(&torii).start_api()?); + handles.push(Arc::clone(&torii.query_store).expired_query_cleanup(query_idle_time)); handles .into_iter() diff --git a/cli/src/torii/utils.rs b/cli/src/torii/utils.rs index 80c0d0028ab..77d31319c06 100644 --- a/cli/src/torii/utils.rs +++ b/cli/src/torii/utils.rs @@ -66,4 +66,4 @@ impl Reply for WarpResult { } } -iroha_cli_derive::generate_endpoints!(2, 3, 4, 5); +iroha_cli_derive::generate_endpoints!(2, 3, 4, 5, 7); diff --git a/client/benches/torii.rs b/client/benches/torii.rs index eb280c0496f..99fc7df5e5c 100644 --- a/client/benches/torii.rs +++ b/client/benches/torii.rs @@ -87,14 +87,19 @@ fn query_requests(criterion: &mut Criterion) { let mut failures_count = 0; let _dropable = group.throughput(Throughput::Bytes(request.encode().len() as u64)); let _dropable2 = group.bench_function("query", |b| { - b.iter(|| match iroha_client.request(request.clone()) { - Ok(assets) => { - assert!(!assets.is_empty()); - success_count += 1; - } - Err(e) => { - eprintln!("Query failed: {e}"); - failures_count += 1; + b.iter(|| { + match iroha_client + .request(request.clone()) + .and_then(|iter| iter.collect::, _>>()) + { + Ok(assets) => { + assert!(!assets.is_empty()); + success_count += 1; + } + Err(e) => { + eprintln!("Query failed: {e}"); + failures_count += 1; + } } }); }); diff --git a/client/src/client.rs b/client/src/client.rs index 69ed298aa77..71ab833c919 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -21,8 +21,13 @@ use http_default::{AsyncWebSocketStream, WebSocketStream}; use iroha_config::{client::Configuration, torii::uri, GetConfiguration, PostConfiguration}; use iroha_crypto::{HashOf, KeyPair}; use iroha_data_model::{ - block::VersionedCommittedBlock, isi::Instruction, predicate::PredicateBox, prelude::*, - transaction::TransactionPayload, ValidationFail, + block::VersionedCommittedBlock, + isi::Instruction, + predicate::PredicateBox, + prelude::*, + query::{ForwardCursor, Pagination, Query, Sorting}, + transaction::TransactionPayload, + ValidationFail, }; use iroha_logger::prelude::*; use iroha_telemetry::metrics::Status; @@ -40,28 +45,25 @@ use crate::{ const APPLICATION_JSON: &str = "application/json"; -/// General trait for all response handlers -pub trait ResponseHandler> { - /// What is the output of the handler - type Output; - - /// Handles HTTP response - fn handle(self, response: Response) -> Self::Output; -} - /// Phantom struct that handles responses of Query API. /// Depending on input query struct, transforms a response into appropriate output. -#[derive(Clone, Copy)] -pub struct QueryResponseHandler(PhantomData); +#[derive(Debug, Clone, serde::Serialize)] +pub struct QueryResponseHandler { + query_request: QueryRequest, + _output_type: PhantomData, +} -impl Default for QueryResponseHandler { - fn default() -> Self { - Self(PhantomData) +impl QueryResponseHandler { + fn new(query_request: QueryRequest) -> Self { + Self { + query_request, + _output_type: PhantomData, + } } } /// `Result` with [`ClientQueryError`] as an error -pub type QueryHandlerResult = core::result::Result; +pub type QueryResult = core::result::Result; /// Trait for signing transactions pub trait Sign { @@ -94,21 +96,18 @@ impl Sign for VersionedSignedTransaction { } } -impl ResponseHandler for QueryResponseHandler +impl QueryResponseHandler where - R: Query + Debug, - >::Error: Into, + >::Error: Into, { - type Output = QueryHandlerResult>; - - fn handle(self, resp: Response>) -> Self::Output { + fn handle(&mut self, resp: &Response>) -> QueryResult { // Separate-compilation friendly response handling fn _handle_query_response_base( resp: &Response>, - ) -> QueryHandlerResult { + ) -> QueryResult { match resp.status() { StatusCode::OK => { - let res = VersionedQueryResult::decode_all_versioned(resp.body()); + let res = VersionedQueryResponse::decode_all_versioned(resp.body()); res.wrap_err( "Failed to decode response from Iroha. \ You are likely using a version of the client library \ @@ -143,9 +142,15 @@ where } } - _handle_query_response_base(&resp).and_then(|VersionedQueryResult::V1(result)| { - ClientQueryRequest::try_from(result).map_err(Into::into) - }) + let response = _handle_query_response_base(resp) + .map(|VersionedQueryResponse::V1(response)| response)?; + + let value = R::try_from(response.result) + .map_err(Into::into) + .wrap_err("Unexpected type")?; + + self.query_request.server_cursor = response.cursor; + Ok(value) } } @@ -167,17 +172,15 @@ impl From for ClientQueryError { /// Phantom struct that handles Transaction API HTTP response #[derive(Clone, Copy)] -pub struct TransactionResponseHandler; - -impl ResponseHandler for TransactionResponseHandler { - type Output = Result<()>; +struct TransactionResponseHandler; - fn handle(self, resp: Response>) -> Self::Output { +impl TransactionResponseHandler { + fn handle(resp: &Response>) -> Result<()> { if resp.status() == StatusCode::OK { Ok(()) } else { Err( - ResponseReport::with_msg("Unexpected transaction response", &resp) + ResponseReport::with_msg("Unexpected transaction response", resp) .unwrap_or_else(core::convert::identity) .into(), ) @@ -189,16 +192,12 @@ impl ResponseHandler for TransactionResponseHandler { #[derive(Clone, Copy)] pub struct StatusResponseHandler; -impl ResponseHandler for StatusResponseHandler { - type Output = Result; - - fn handle(self, resp: Response>) -> Self::Output { +impl StatusResponseHandler { + fn handle(resp: &Response>) -> Result { if resp.status() != StatusCode::OK { - return Err( - ResponseReport::with_msg("Unexpected status response", &resp) - .unwrap_or_else(core::convert::identity) - .into(), - ); + return Err(ResponseReport::with_msg("Unexpected status response", resp) + .unwrap_or_else(core::convert::identity) + .into()); } serde_json::from_slice(resp.body()).wrap_err("Failed to decode body") } @@ -212,10 +211,7 @@ impl ResponseReport { /// /// # Errors /// If response body isn't a valid utf-8 string - fn with_msg(msg: S, response: &Response>) -> Result - where - S: AsRef, - { + fn with_msg>(msg: S, response: &Response>) -> Result { let status = response.status(); let body = std::str::from_utf8(response.body()); let msg = msg.as_ref(); @@ -236,60 +232,99 @@ impl From for eyre::Report { } } -/// More convenient version of [`iroha_data_model::prelude::QueryResult`]. -/// The only difference is that this struct has `output` field extracted from the result -/// accordingly to the source query. -#[derive(Clone, Debug)] -pub struct ClientQueryRequest -where - R: Query + Debug, - >::Error: Into, -{ - /// Query output - pub output: R::Output, - /// See [`iroha_data_model::prelude::QueryResult`] - pub pagination: Pagination, - /// See [`iroha_data_model::prelude::QueryResult`] - pub sorting: Sorting, +/// Output of a query +pub trait QueryOutput: Into + TryFrom { + /// Type of the query output + type Target: Clone; + + /// Construct query output from query response + fn new(value: Self, query_request: QueryResponseHandler) -> Self::Target; +} + +/// Iterable query output +#[derive(Debug, Clone, serde::Serialize)] +pub struct ResultSet { + query_handler: QueryResponseHandler>, + + iter: Vec, + client_cursor: usize, } -impl ClientQueryRequest +impl Iterator for ResultSet where - R: Query + Debug, - >::Error: Into, + Vec: QueryOutput, + as TryFrom>::Error: Into, { - /// Extracts output as is - pub fn only_output(self) -> R::Output { - self.output + type Item = QueryResult; + + fn next(&mut self) -> Option { + if self.client_cursor >= self.iter.len() { + self.query_handler.query_request.server_cursor.get()?; + + let request = match self.query_handler.query_request.clone().assemble().build() { + Err(err) => return Some(Err(ClientQueryError::Other(err))), + Ok(ok) => ok, + }; + + let response = match request.send() { + Err(err) => return Some(Err(ClientQueryError::Other(err))), + Ok(ok) => ok, + }; + let value = match self.query_handler.handle(&response) { + Err(err) => return Some(Err(err)), + Ok(ok) => ok, + }; + self.iter = value; + self.client_cursor = 0; + } + + let item = Ok(self.iter.get(self.client_cursor).cloned()); + self.client_cursor += 1; + item.transpose() } } -impl TryFrom for ClientQueryRequest +impl QueryOutput for Vec where - R: Query + Debug, - >::Error: Into, + Self: Into + TryFrom, { - type Error = eyre::Report; - - fn try_from( - QueryResult { - result, - pagination, - sorting, - }: QueryResult, - ) -> Result { - let output = R::Output::try_from(result) - .map_err(Into::into) - .wrap_err("Unexpected type")?; + type Target = ResultSet; - Ok(Self { - output, - pagination, - sorting, - }) + fn new(value: Self, query_handler: QueryResponseHandler) -> Self::Target { + ResultSet { + query_handler, + iter: value, + client_cursor: 0, + } } } +macro_rules! impl_query_result { + ( $($ident:ty),+ $(,)? ) => { $( + impl QueryOutput for $ident { + type Target = Self; + + fn new(value: Self, _query_handler: QueryResponseHandler) -> Self::Target { + value + } + } )+ + }; +} +impl_query_result! { + bool, + iroha_data_model::Value, + iroha_data_model::numeric::NumericValue, + iroha_data_model::role::Role, + iroha_data_model::asset::Asset, + iroha_data_model::asset::AssetDefinition, + iroha_data_model::account::Account, + iroha_data_model::domain::Domain, + iroha_data_model::block::BlockHeader, + iroha_data_model::query::MetadataValue, + iroha_data_model::query::TransactionQueryOutput, + iroha_data_model::trigger::Trigger, +} + /// Iroha client #[derive(Clone, DebugCustom, Display)] #[debug( @@ -317,6 +352,42 @@ pub struct Client { add_transaction_nonce: bool, } +/// Query request +#[derive(Debug, Clone, serde::Serialize)] +pub struct QueryRequest { + torii_url: Url, + headers: HashMap, + request: Vec, + sorting: Sorting, + pagination: Pagination, + server_cursor: ForwardCursor, +} + +impl QueryRequest { + #[cfg(test)] + fn dummy() -> Self { + Self { + torii_url: uri::QUERY.parse().unwrap(), + headers: HashMap::new(), + request: Vec::new(), + sorting: Sorting::default(), + pagination: Pagination::default(), + server_cursor: ForwardCursor::default(), + } + } + fn assemble(self) -> DefaultRequestBuilder { + DefaultRequestBuilder::new( + HttpMethod::POST, + self.torii_url.join(uri::QUERY).expect("Valid URI"), + ) + .headers(self.headers) + .params(Vec::from(self.sorting)) + .params(Vec::from(self.pagination)) + .params(Vec::from(self.server_cursor)) + .body(self.request) + } +} + /// Representation of `Iroha` client. impl Client { /// Constructor for client from configuration @@ -411,7 +482,7 @@ impl Client { /// /// # Errors /// Fails if signature generation fails - pub fn sign_query(&self, query: QueryBuilder) -> Result { + pub fn sign_query(&self, query: QueryBuilder) -> Result { query .sign(self.key_pair.clone()) .wrap_err("Failed to sign query") @@ -422,10 +493,7 @@ impl Client { /// /// # Errors /// Fails if sending transaction to peer fails or if it response with error - pub fn submit( - &self, - instruction: impl Instruction + Debug, - ) -> Result> { + pub fn submit(&self, instruction: impl Instruction) -> Result> { let isi = instruction.into(); self.submit_all([isi]) } @@ -480,13 +548,12 @@ impl Client { transaction: &VersionedSignedTransaction, ) -> Result> { iroha_logger::trace!(tx=?transaction, "Submitting"); - let (req, hash, resp_handler) = - self.prepare_transaction_request::(transaction); + let (req, hash) = self.prepare_transaction_request::(transaction); let response = req .build()? .send() .wrap_err_with(|| format!("Failed to send transaction with hash {hash:?}"))?; - resp_handler.handle(response)?; + TransactionResponseHandler::handle(&response)?; Ok(hash) } @@ -589,10 +656,10 @@ impl Client { /// it is better to use a response handler anyway. It allows to abstract from implementation details. /// /// For general usage example see [`Client::prepare_query_request`]. - pub fn prepare_transaction_request( + fn prepare_transaction_request( &self, transaction: &VersionedSignedTransaction, - ) -> (B, HashOf, TransactionResponseHandler) { + ) -> (B, HashOf) { let transaction_bytes: Vec = transaction.encode_versioned(); ( @@ -603,7 +670,6 @@ impl Client { .headers(self.headers.clone()) .body(transaction_bytes), transaction.payload().hash(), - TransactionResponseHandler, ) } @@ -670,7 +736,7 @@ impl Client { /// ```ignore /// use eyre::Result; /// use iroha_client::{ - /// client::{Client, ResponseHandler}, + /// client::Client, /// http::{RequestBuilder, Response, Method}, /// }; /// use iroha_data_model::{predicate::PredicateBox, prelude::{Account, FindAllAccounts, Pagination}}; @@ -717,36 +783,34 @@ impl Client { /// // Handle response with the handler and get typed result /// let accounts = resp_handler.handle(resp)?; /// - /// Ok(accounts.only_output()) + /// Ok(accounts.output()) /// } /// ``` - pub fn prepare_query_request( + fn prepare_query_request( &self, request: R, filter: PredicateBox, pagination: Pagination, sorting: Sorting, - ) -> Result<(B, QueryResponseHandler)> + ) -> Result<(DefaultRequestBuilder, QueryResponseHandler)> where - R: Query + Debug, >::Error: Into, - B: RequestBuilder, { - let pagination: Vec<_> = pagination.into(); - let sorting: Vec<_> = sorting.into(); - let request = QueryBuilder::new(request, self.account_id.clone()).with_filter(filter); - let request: VersionedSignedQuery = self.sign_query(request)?.into(); + let query_builder = QueryBuilder::new(request, self.account_id.clone()).with_filter(filter); + let request = self.sign_query(query_builder)?.encode_versioned(); + + let query_request = QueryRequest { + torii_url: self.torii_url.clone(), + headers: self.headers.clone(), + request, + sorting, + pagination, + server_cursor: ForwardCursor::default(), + }; Ok(( - B::new( - HttpMethod::POST, - self.torii_url.join(uri::QUERY).expect("Valid URI"), - ) - .params(pagination) - .params(sorting) - .headers(self.headers.clone()) - .body(request.encode_versioned()), - QueryResponseHandler::default(), + query_request.clone().assemble(), + QueryResponseHandler::new(query_request), )) } @@ -754,37 +818,42 @@ impl Client { /// /// # Errors /// Fails if sending request fails - pub fn request_with_filter_and_pagination_and_sorting( + pub fn request_with_filter_and_pagination_and_sorting( &self, request: R, pagination: Pagination, sorting: Sorting, filter: PredicateBox, - ) -> QueryHandlerResult> + ) -> QueryResult<::Target> where - R: Query + Debug, - >::Error: Into, // Seems redundant + R::Output: QueryOutput, + >::Error: Into, { iroha_logger::trace!(?request, %pagination, ?sorting, ?filter); - let (req, resp_handler) = self.prepare_query_request::( - request, filter, pagination, sorting, - )?; - let response = req.build()?.send()?; - resp_handler.handle(response) + let (req, mut resp_handler) = + self.prepare_query_request::(request, filter, pagination, sorting)?; + + let kita = req.build()?; + //println!("Request: {kita:?}"); + let response = kita.send()?; + let value = resp_handler.handle(&response)?; + let output = QueryOutput::new(value, resp_handler); + + Ok(output) } /// Create a request with pagination and sorting. /// /// # Errors /// Fails if sending request fails - pub fn request_with_pagination_and_sorting( + pub fn request_with_pagination_and_sorting( &self, request: R, pagination: Pagination, sorting: Sorting, - ) -> QueryHandlerResult> + ) -> QueryResult<::Target> where - R: Query + Debug, + R::Output: QueryOutput, >::Error: Into, { self.request_with_filter_and_pagination_and_sorting( @@ -799,15 +868,15 @@ impl Client { /// /// # Errors /// Fails if sending request fails - pub fn request_with_filter_and_pagination( + pub fn request_with_filter_and_pagination( &self, request: R, pagination: Pagination, filter: PredicateBox, - ) -> QueryHandlerResult> + ) -> QueryResult<::Target> where - R: Query + Debug, - >::Error: Into, // Seems redundant + R::Output: QueryOutput, + >::Error: Into, { self.request_with_filter_and_pagination_and_sorting( request, @@ -821,15 +890,15 @@ impl Client { /// /// # Errors /// Fails if sending request fails - pub fn request_with_filter_and_sorting( + pub fn request_with_filter_and_sorting( &self, request: R, sorting: Sorting, filter: PredicateBox, - ) -> QueryHandlerResult> + ) -> QueryResult<::Target> where - R: Query + Debug, - >::Error: Into, // Seems redundant + R::Output: QueryOutput, + >::Error: Into, { self.request_with_filter_and_pagination_and_sorting( request, @@ -846,13 +915,13 @@ impl Client { /// /// # Errors /// Fails if sending request fails - pub fn request_with_filter( + pub fn request_with_filter( &self, request: R, filter: PredicateBox, - ) -> QueryHandlerResult> + ) -> QueryResult<::Target> where - R: Query + Debug, + R::Output: QueryOutput, >::Error: Into, { self.request_with_filter_and_pagination(request, Pagination::default(), filter) @@ -865,13 +934,13 @@ impl Client { /// /// # Errors /// Fails if sending request fails - pub fn request_with_pagination( + pub fn request_with_pagination( &self, request: R, pagination: Pagination, - ) -> QueryHandlerResult> + ) -> QueryResult<::Target> where - R: Query + Debug, + R::Output: QueryOutput, >::Error: Into, { self.request_with_filter_and_pagination(request, pagination, PredicateBox::default()) @@ -881,13 +950,13 @@ impl Client { /// /// # Errors /// Fails if sending request fails - pub fn request_with_sorting( + pub fn request_with_sorting( &self, request: R, sorting: Sorting, - ) -> QueryHandlerResult> + ) -> QueryResult<::Target> where - R: Query + Debug, + R::Output: QueryOutput, >::Error: Into, { self.request_with_pagination_and_sorting(request, Pagination::default(), sorting) @@ -897,13 +966,15 @@ impl Client { /// /// # Errors /// Fails if sending request fails - pub fn request(&self, request: R) -> QueryHandlerResult + pub fn request( + &self, + request: R, + ) -> QueryResult<::Target> where - R: Query + Debug, + R::Output: QueryOutput, >::Error: Into, { self.request_with_pagination(request, Pagination::default()) - .map(ClientQueryRequest::only_output) } /// Connect (through `WebSocket`) to listen for `Iroha` `pipeline` and `data` events. @@ -1131,9 +1202,9 @@ impl Client { /// # Errors /// Fails if sending request or decoding fails pub fn get_status(&self) -> Result { - let (req, resp_handler) = self.prepare_status_request::(); + let req = self.prepare_status_request::(); let resp = req.build()?.send()?; - resp_handler.handle(resp) + StatusResponseHandler::handle(&resp) } /// Prepares http-request to implement [`Self::get_status`] on your own. @@ -1142,18 +1213,12 @@ impl Client { /// /// # Errors /// Fails if request build fails - pub fn prepare_status_request(&self) -> (B, StatusResponseHandler) - where - B: RequestBuilder, - { - ( - B::new( - HttpMethod::GET, - self.telemetry_url.join(uri::STATUS).expect("Valid URI"), - ) - .headers(self.headers.clone()), - StatusResponseHandler, + pub fn prepare_status_request(&self) -> B { + B::new( + HttpMethod::GET, + self.telemetry_url.join(uri::STATUS).expect("Valid URI"), ) + .headers(self.headers.clone()) } } @@ -1256,11 +1321,10 @@ pub mod stream_api { /// - Sending failed /// - Message not received in stream during connection or subscription /// - Message is an error - pub async fn new(handler: I) -> Result> - where - I: Init + Send, - I::Next: Send, - { + #[allow(clippy::future_not_send)] + pub async fn new>( + handler: I, + ) -> Result> { trace!("Creating `AsyncStream`"); let InitData { first_message, @@ -1770,13 +1834,13 @@ mod tests { #[cfg(test)] mod query_errors_handling { use http::Response; - use iroha_data_model::{query::error::QueryExecutionFail, ValidationFail}; + use iroha_data_model::{asset::Asset, query::error::QueryExecutionFail, ValidationFail}; use super::*; #[test] fn certain_errors() -> Result<()> { - let sut = QueryResponseHandler::::default(); + let mut sut = QueryResponseHandler::>::new(QueryRequest::dummy()); let responses = vec![ ( StatusCode::UNAUTHORIZED, @@ -1796,7 +1860,7 @@ mod tests { for (status_code, err) in responses { let resp = Response::builder().status(status_code).body(err.encode())?; - match sut.handle(resp) { + match sut.handle(&resp) { Err(ClientQueryError::Validation(actual)) => { // PartialEq isn't implemented, so asserting by encoded repr assert_eq!(actual.encode(), err.encode()); @@ -1810,12 +1874,12 @@ mod tests { #[test] fn indeterminate() -> Result<()> { - let sut = QueryResponseHandler::::default(); + let mut sut = QueryResponseHandler::>::new(QueryRequest::dummy()); let response = Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) .body(Vec::::new())?; - match sut.handle(response) { + match sut.handle(&response) { Err(ClientQueryError::Other(_)) => Ok(()), x => Err(eyre!("Expected indeterminate, found: {:?}", x)), } diff --git a/client/src/http.rs b/client/src/http.rs index f1396f61a65..1a70a381c07 100644 --- a/client/src/http.rs +++ b/client/src/http.rs @@ -28,14 +28,14 @@ pub trait RequestBuilder { { for pair in params { let (k, v) = pair.borrow(); - self = self.param(k, v.to_string()); + self = self.param(k, v); } self } /// Add a single query param #[must_use] - fn param(self, key: K, value: V) -> Self + fn param(self, key: K, value: &V) -> Self where K: AsRef, V: ToString; @@ -52,14 +52,14 @@ pub trait RequestBuilder { { for pair in headers { let (k, v) = pair.borrow(); - self = self.header(k, v.to_string()); + self = self.header(k, v); } self } /// Add a single header #[must_use] - fn header(self, name: N, value: V) -> Self + fn header(self, name: N, value: &V) -> Self where N: AsRef, V: ToString; @@ -166,11 +166,11 @@ pub mod ws { /// todo!() /// } /// - /// fn param, V: ToString>(self, _: K, _: V) -> Self { + /// fn param, V: ?Sized + ToString>(self, _: K, _: &V) -> Self { /// todo!() /// } /// - /// fn header, V: ToString>(self, _: N, _: V) -> Self { + /// fn header, V: ?Sized + ToString>(self, _: N, _: &V) -> Self { /// todo!() /// } /// diff --git a/client/src/http_default.rs b/client/src/http_default.rs index 46530a9b45a..2147c9b61ce 100644 --- a/client/src/http_default.rs +++ b/client/src/http_default.rs @@ -25,6 +25,7 @@ fn header_name_from_str(str: &str) -> Result { } /// Default request builder implemented on top of `attohttpc` crate. +#[derive(Debug)] pub struct DefaultRequestBuilder { inner: Result, body: Option>, @@ -50,6 +51,7 @@ impl DefaultRequestBuilder { } /// Request built by [`DefaultRequestBuilder`]. +#[derive(Debug)] pub struct DefaultRequest(AttoHttpRequestBuilderWithBytes); impl DefaultRequest { @@ -80,7 +82,7 @@ impl RequestBuilder for DefaultRequestBuilder { } } - fn header(self, key: K, value: V) -> Self + fn header(self, key: K, value: &V) -> Self where K: AsRef, V: ToString, @@ -90,12 +92,12 @@ impl RequestBuilder for DefaultRequestBuilder { }) } - fn param(self, key: K, value: V) -> Self + fn param(self, key: K, value: &V) -> Self where K: AsRef, V: ToString, { - self.and_then(|b| Ok(b.param(key, value))) + self.and_then(|b| Ok(b.param(key, value.to_string()))) } fn body(self, data: Vec) -> Self { @@ -150,11 +152,11 @@ impl RequestBuilder for DefaultWebSocketRequestBuilder { .uri(url.as_ref()))) } - fn param(self, _key: K, _val: V) -> Self { + fn param(self, _key: K, _val: &V) -> Self { Self(self.0.and(Err(eyre!("No params expected")))) } - fn header(self, name: N, value: V) -> Self + fn header(self, name: N, value: &V) -> Self where N: AsRef, V: ToString, diff --git a/client/tests/integration/asset.rs b/client/tests/integration/asset.rs index 29d9955d0f6..4495bfb1111 100644 --- a/client/tests/integration/asset.rs +++ b/client/tests/integration/asset.rs @@ -3,7 +3,7 @@ use std::{str::FromStr as _, thread}; use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_crypto::{KeyPair, PublicKey}; use iroha_data_model::prelude::*; use iroha_primitives::fixed::Fixed; @@ -31,7 +31,9 @@ fn client_register_asset_should_add_asset_once_but_not_twice() -> Result<()> { // Registering an asset to an account which doesn't have one // should result in asset being created test_client.poll_request(client::asset::by_account_id(account_id), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Quantity(0) }) @@ -61,7 +63,9 @@ fn unregister_asset_should_remove_asset_from_account() -> Result<()> { // Wait for asset to be registered test_client.poll_request(client::asset::by_account_id(account_id.clone()), |result| { - result + let assets = result.collect::>>().expect("Valid"); + + assets .iter() .any(|asset| asset.id().definition_id == asset_definition_id) })?; @@ -70,7 +74,9 @@ fn unregister_asset_should_remove_asset_from_account() -> Result<()> { // ... and check that it is removed after Unregister test_client.poll_request(client::asset::by_account_id(account_id), |result| { - result + let assets = result.collect::>>().expect("Valid"); + + assets .iter() .all(|asset| asset.id().definition_id != asset_definition_id) })?; @@ -101,7 +107,9 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount() -> let tx = test_client.build_transaction(instructions, metadata)?; test_client.submit_transaction(&tx)?; test_client.poll_request(client::asset::by_account_id(account_id), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Quantity(quantity) }) @@ -132,7 +140,9 @@ fn client_add_big_asset_quantity_to_existing_asset_should_increase_asset_amount( let tx = test_client.build_transaction(instructions, metadata)?; test_client.submit_transaction(&tx)?; test_client.poll_request(client::asset::by_account_id(account_id), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::BigQuantity(quantity) }) @@ -165,7 +175,9 @@ fn client_add_asset_with_decimal_should_increase_asset_amount() -> Result<()> { let tx = test_client.build_transaction(instructions, metadata)?; test_client.submit_transaction(&tx)?; test_client.poll_request(client::asset::by_account_id(account_id.clone()), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Fixed(quantity) }) @@ -185,7 +197,9 @@ fn client_add_asset_with_decimal_should_increase_asset_amount() -> Result<()> { .checked_add(quantity2) .map_err(|e| eyre::eyre!("{}", e))?; test_client.submit_till(mint, client::asset::by_account_id(account_id), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Fixed(sum) }) @@ -218,19 +232,22 @@ fn client_add_asset_with_name_length_more_than_limit_should_not_commit_transacti iroha_logger::info!("Creating another asset"); thread::sleep(pipeline_time * 4); - let asset_definition_ids = test_client + let mut asset_definition_ids = test_client .request(client::asset::all_definitions()) .expect("Failed to execute request.") + .collect::>>() + .expect("Failed to execute request.") .into_iter() - .map(|asset| asset.id().clone()) - .collect::>(); + .map(|asset| asset.id().clone()); iroha_logger::debug!( "Collected asset definitions ID's: {:?}", &asset_definition_ids ); - assert!(asset_definition_ids.contains(&normal_asset_definition_id)); - assert!(!asset_definition_ids.contains(&incorrect_asset_definition_id)); + assert!(asset_definition_ids + .any(|asset_definition_id| asset_definition_id == normal_asset_definition_id)); + assert!(!asset_definition_ids + .any(|asset_definition_id| asset_definition_id == incorrect_asset_definition_id)); Ok(()) } diff --git a/client/tests/integration/asset_propagation.rs b/client/tests/integration/asset_propagation.rs index 4160de579e9..ddd34ee81b3 100644 --- a/client/tests/integration/asset_propagation.rs +++ b/client/tests/integration/asset_propagation.rs @@ -3,7 +3,7 @@ use std::{str::FromStr as _, thread}; use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_crypto::KeyPair; use iroha_data_model::{ parameter::{default::MAX_TRANSACTIONS_IN_BLOCK, ParametersBuilder}, @@ -51,7 +51,9 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount_on_a client::Client::test(&peer.api_address, &peer.telemetry_address).poll_request( client::asset::by_account_id(account_id), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Quantity(quantity) }) diff --git a/client/tests/integration/multiple_blocks_created.rs b/client/tests/integration/multiple_blocks_created.rs index d00c10e14f1..0cbb55fdffc 100644 --- a/client/tests/integration/multiple_blocks_created.rs +++ b/client/tests/integration/multiple_blocks_created.rs @@ -3,7 +3,7 @@ use std::thread; use eyre::Result; -use iroha_client::client::{self, Client}; +use iroha_client::client::{self, Client, QueryResult}; use iroha_crypto::KeyPair; use iroha_data_model::{ parameter::{default::MAX_TRANSACTIONS_IN_BLOCK, ParametersBuilder}, @@ -63,7 +63,9 @@ fn long_multiple_blocks_created() -> Result<()> { Client::test(&peer.api_address, &peer.telemetry_address).poll_request( client::asset::by_account_id(account_id), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Quantity(account_has_quantity) }) diff --git a/client/tests/integration/multisignature_account.rs b/client/tests/integration/multisignature_account.rs index 84aea34170b..dd5f1454328 100644 --- a/client/tests/integration/multisignature_account.rs +++ b/client/tests/integration/multisignature_account.rs @@ -3,7 +3,7 @@ use std::thread; use eyre::Result; -use iroha_client::client::{self, Client}; +use iroha_client::client::{self, Client, QueryResult}; use iroha_crypto::KeyPair; use iroha_data_model::prelude::*; use test_network::*; @@ -42,7 +42,9 @@ fn transaction_signed_by_new_signatory_of_account_should_pass() -> Result<()> { mint_asset, client::asset::by_account_id(account_id), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Quantity(quantity) }) diff --git a/client/tests/integration/multisignature_transaction.rs b/client/tests/integration/multisignature_transaction.rs index 01ae20e47e9..cb2abe8ad8a 100644 --- a/client/tests/integration/multisignature_transaction.rs +++ b/client/tests/integration/multisignature_transaction.rs @@ -3,7 +3,7 @@ use std::{str::FromStr as _, thread, time::Duration}; use eyre::Result; -use iroha_client::client::{self, Client}; +use iroha_client::client::{self, Client, QueryResult}; use iroha_config::client::Configuration as ClientConfiguration; use iroha_crypto::KeyPair; use iroha_data_model::{ @@ -79,8 +79,11 @@ fn multisignature_transactions_should_wait_for_all_signatures() -> Result<()> { .unwrap(); let client_1 = Client::new(&client_configuration).expect("Invalid client configuration"); let request = client::asset::by_account_id(alice_id); + let assets = client_1 + .request(request.clone())? + .collect::>>()?; assert_eq!( - client_1.request(request.clone())?.len(), + assets.len(), 2 // Alice has roses and cabbage from Genesis ); let (public_key2, private_key2) = key_pair_2.into(); @@ -94,7 +97,9 @@ fn multisignature_transactions_should_wait_for_all_signatures() -> Result<()> { .expect("Found no pending transaction for this account."); client_2.submit_transaction(&client_2.sign_transaction(transaction)?)?; thread::sleep(pipeline_time); - let assets = client_1.request(request)?; + let assets = client_1 + .request(request)? + .collect::>>()?; assert!(!assets.is_empty()); let camomile_asset = assets .iter() diff --git a/client/tests/integration/non_mintable.rs b/client/tests/integration/non_mintable.rs index 6371c25d08d..404ad8d3192 100644 --- a/client/tests/integration/non_mintable.rs +++ b/client/tests/integration/non_mintable.rs @@ -3,7 +3,7 @@ use std::str::FromStr as _; use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_data_model::{metadata::UnlimitedMetadata, prelude::*}; use test_network::*; @@ -34,7 +34,8 @@ fn non_mintable_asset_can_be_minted_once_but_not_twice() -> Result<()> { // We can register and mint the non-mintable token test_client.submit_transaction(&tx)?; test_client.poll_request(client::asset::by_account_id(account_id.clone()), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Quantity(200_u32) }) @@ -46,7 +47,8 @@ fn non_mintable_asset_can_be_minted_once_but_not_twice() -> Result<()> { // However, this will fail assert!(test_client .poll_request(client::asset::by_account_id(account_id), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Quantity(400_u32) }) @@ -72,7 +74,8 @@ fn non_mintable_asset_cannot_be_minted_if_registered_with_non_zero_value() -> Re // We can register the non-mintable token test_client.submit_all([create_asset, register_asset.clone()])?; test_client.poll_request(client::asset::by_account_id(account_id), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Quantity(1_u32) }) @@ -108,7 +111,8 @@ fn non_mintable_asset_can_be_minted_if_registered_with_zero_value() -> Result<() [create_asset.into(), register_asset.into(), mint.into()]; test_client.submit_all(instructions)?; test_client.poll_request(client::asset::by_account_id(account_id), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Quantity(1_u32) }) diff --git a/client/tests/integration/offline_peers.rs b/client/tests/integration/offline_peers.rs index 13ed021b960..ee20b58ca4e 100644 --- a/client/tests/integration/offline_peers.rs +++ b/client/tests/integration/offline_peers.rs @@ -1,7 +1,7 @@ #![allow(clippy::restriction)] use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_data_model::{ parameter::{default::MAX_TRANSACTIONS_IN_BLOCK, ParametersBuilder}, prelude::*, @@ -33,7 +33,9 @@ fn genesis_block_is_committed_with_some_offline_peers() -> Result<()> { let alice_has_roses = 13; //Then - let assets = client.request(client::asset::by_account_id(alice_id))?; + let assets = client + .request(client::asset::by_account_id(alice_id))? + .collect::>>()?; let asset = assets .iter() .find(|asset| asset.id().definition_id == roses) diff --git a/client/tests/integration/pagination.rs b/client/tests/integration/pagination.rs index afa827a511e..e50251eb980 100644 --- a/client/tests/integration/pagination.rs +++ b/client/tests/integration/pagination.rs @@ -1,8 +1,10 @@ #![allow(clippy::restriction)] +use std::num::{NonZeroU32, NonZeroU64}; + use eyre::Result; -use iroha_client::client::asset; -use iroha_data_model::prelude::*; +use iroha_client::client::{asset, QueryResult}; +use iroha_data_model::{asset::AssetDefinition, prelude::*, query::Pagination}; use test_network::*; #[test] @@ -20,8 +22,14 @@ fn client_add_asset_quantity_to_existing_asset_should_increase_asset_amount() -> client.submit_all_blocking(register)?; let vec = client - .request_with_pagination(asset::all_definitions(), Pagination::new(Some(5), Some(5)))? - .only_output(); + .request_with_pagination( + asset::all_definitions(), + Pagination { + limit: NonZeroU32::new(5), + start: NonZeroU64::new(5), + }, + )? + .collect::>>()?; assert_eq!(vec.len(), 5); Ok(()) } diff --git a/client/tests/integration/permissions.rs b/client/tests/integration/permissions.rs index 903a63e7e17..1909820c08e 100644 --- a/client/tests/integration/permissions.rs +++ b/client/tests/integration/permissions.rs @@ -3,7 +3,7 @@ use std::{str::FromStr as _, thread}; use eyre::Result; -use iroha_client::client::{self, Client}; +use iroha_client::client::{self, Client, QueryResult}; use iroha_data_model::prelude::*; use test_network::{PeerBuilder, *}; @@ -13,6 +13,8 @@ fn get_assets(iroha_client: &mut Client, id: &::Id) -> iroha_client .request(client::asset::by_account_id(id.clone())) .expect("Failed to execute request.") + .collect::>>() + .expect("Failed to execute request.") } #[ignore = "ignore, more in #2851"] diff --git a/client/tests/integration/queries/account.rs b/client/tests/integration/queries/account.rs index 5e839d24e00..f9a07b84560 100644 --- a/client/tests/integration/queries/account.rs +++ b/client/tests/integration/queries/account.rs @@ -3,7 +3,7 @@ use std::{collections::HashSet, str::FromStr as _}; use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_data_model::prelude::*; use test_network::*; @@ -65,7 +65,9 @@ fn find_accounts_with_asset() -> Result<()> { AssetValueType::Quantity ); - let found_accounts = test_client.request(client::account::all_with_asset(definition_id))?; + let found_accounts = test_client + .request(client::account::all_with_asset(definition_id))? + .collect::>>()?; let found_ids = found_accounts .into_iter() .map(|account| account.id().clone()) diff --git a/client/tests/integration/queries/role.rs b/client/tests/integration/queries/role.rs index 5c893679f5a..1c8a2087071 100644 --- a/client/tests/integration/queries/role.rs +++ b/client/tests/integration/queries/role.rs @@ -3,7 +3,7 @@ use std::collections::HashSet; use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_data_model::{prelude::*, query::error::QueryExecutionFail}; use test_network::*; @@ -37,11 +37,14 @@ fn find_roles() -> Result<()> { // Checking results let found_role_ids = test_client .request(client::role::all())? - .into_iter() - .map(|role| role.id().clone()) - .collect::>(); + .collect::>>()? + .into_iter(); - assert!(role_ids.is_subset(&found_role_ids)); + assert!(role_ids.is_subset( + &found_role_ids + .map(|role| role.id().clone()) + .collect::>() + )); Ok(()) } @@ -64,7 +67,9 @@ fn find_role_ids() -> Result<()> { let role_ids = HashSet::from(role_ids); // Checking results - let found_role_ids = test_client.request(client::role::all_ids())?; + let found_role_ids = test_client + .request(client::role::all_ids())? + .collect::>>()?; let found_role_ids = found_role_ids.into_iter().collect::>(); assert!(role_ids.is_subset(&found_role_ids)); @@ -143,7 +148,9 @@ fn find_roles_by_account_id() -> Result<()> { let role_ids = HashSet::from(role_ids); // Checking results - let found_role_ids = test_client.request(client::role::by_account_id(alice_id))?; + let found_role_ids = test_client + .request(client::role::by_account_id(alice_id))? + .collect::>>()?; let found_role_ids = found_role_ids.into_iter().collect::>(); assert!(role_ids.is_subset(&found_role_ids)); diff --git a/client/tests/integration/restart_peer.rs b/client/tests/integration/restart_peer.rs index 02bc937841c..dbc4f2cd082 100644 --- a/client/tests/integration/restart_peer.rs +++ b/client/tests/integration/restart_peer.rs @@ -3,7 +3,7 @@ use std::{str::FromStr, sync::Arc}; use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_data_model::prelude::*; use tempfile::TempDir; use test_network::*; @@ -46,8 +46,10 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { ); iroha_client.submit_blocking(mint_asset)?; - let asset = iroha_client + let assets = iroha_client .request(client::asset::by_account_id(account_id.clone()))? + .collect::>>()?; + let asset = assets .into_iter() .find(|asset| asset.id().definition_id == asset_definition_id) .expect("Asset not found"); @@ -65,19 +67,17 @@ fn restarted_peer_should_have_the_same_asset_amount() -> Result<()> { ); wait_for_genesis_committed(&vec![iroha_client.clone()], 0); - let account_asset = iroha_client - .poll_request(client::asset::by_account_id(account_id), |assets| { - iroha_logger::error!(?assets); - assets - .iter() - .any(|asset| asset.id().definition_id == asset_definition_id) - }) - .expect("Valid") - .into_iter() - .find(|asset| asset.id().definition_id == asset_definition_id) - .expect("Asset not found"); + iroha_client.poll_request(client::asset::by_account_id(account_id), |result| { + let assets = result.collect::>>().expect("Valid"); + iroha_logger::error!(?assets); + + let account_asset = assets + .into_iter() + .find(|asset| asset.id().definition_id == asset_definition_id) + .expect("Asset not found"); - assert_eq!(AssetValue::Quantity(quantity), *account_asset.value()); + AssetValue::Quantity(quantity) == *account_asset.value() + })? } Ok(()) } diff --git a/client/tests/integration/roles.rs b/client/tests/integration/roles.rs index aa9db1a4873..2c0a84d64a2 100644 --- a/client/tests/integration/roles.rs +++ b/client/tests/integration/roles.rs @@ -3,7 +3,7 @@ use std::str::FromStr as _; use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_data_model::prelude::*; use test_network::*; @@ -88,7 +88,9 @@ fn register_and_grant_role_for_metadata_access() -> Result<()> { test_client.submit_blocking(set_key_value)?; // Making request to find Alice's roles - let found_role_ids = test_client.request(client::role::by_account_id(alice_id))?; + let found_role_ids = test_client + .request(client::role::by_account_id(alice_id))? + .collect::>>()?; assert!(found_role_ids.contains(&role_id)); Ok(()) @@ -118,7 +120,9 @@ fn unregistered_role_removed_from_account() -> Result<()> { test_client.submit_blocking(grant_role)?; // Check that Mouse has root role - let found_mouse_roles = test_client.request(client::role::by_account_id(mouse_id.clone()))?; + let found_mouse_roles = test_client + .request(client::role::by_account_id(mouse_id.clone()))? + .collect::>>()?; assert!(found_mouse_roles.contains(&role_id)); // Unregister root role @@ -126,7 +130,9 @@ fn unregistered_role_removed_from_account() -> Result<()> { test_client.submit_blocking(unregister_role)?; // Check that Mouse doesn't have the root role - let found_mouse_roles = test_client.request(client::role::by_account_id(mouse_id))?; + let found_mouse_roles = test_client + .request(client::role::by_account_id(mouse_id))? + .collect::>>()?; assert!(!found_mouse_roles.contains(&role_id)); Ok(()) diff --git a/client/tests/integration/set_parameter.rs b/client/tests/integration/set_parameter.rs index 24963610265..a9533f5f541 100644 --- a/client/tests/integration/set_parameter.rs +++ b/client/tests/integration/set_parameter.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_data_model::prelude::*; use test_network::*; @@ -16,7 +16,9 @@ fn can_change_parameter_value() -> Result<()> { let parameter_id = ParameterId::from_str("BlockTime")?; let param_box = SetParameterBox::new(parameter); - let old_params = test_client.request(client::parameter::all())?; + let old_params = test_client + .request(client::parameter::all())? + .collect::>>()?; let param_val_old = old_params .iter() .find(|param| param.id() == ¶meter_id) @@ -25,8 +27,9 @@ fn can_change_parameter_value() -> Result<()> { test_client.submit_blocking(param_box)?; - let new_params = test_client.request(client::parameter::all())?; - + let new_params = test_client + .request(client::parameter::all())? + .collect::>>()?; let param_val_new = new_params .iter() .find(|param| param.id() == ¶meter_id) diff --git a/client/tests/integration/sorting.rs b/client/tests/integration/sorting.rs index ae59bb2e643..bed460847a9 100644 --- a/client/tests/integration/sorting.rs +++ b/client/tests/integration/sorting.rs @@ -1,12 +1,18 @@ #![allow(clippy::restriction, clippy::pedantic)] -use std::{collections::HashSet, str::FromStr as _}; +use std::{ + collections::HashSet, + num::{NonZeroU32, NonZeroU64}, + str::FromStr as _, +}; use eyre::{Result, WrapErr as _}; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_data_model::{ + account::Account, predicate::{string, value, PredicateBox}, prelude::*, + query::{Pagination, Sorting}, }; use test_network::*; @@ -21,7 +27,7 @@ fn correct_pagination_assets_after_creating_new_one() { let mut assets = vec![]; let mut instructions = vec![]; - for i in 0..10_u128 { + for i in 0..20_u128 { let asset_definition_id = AssetDefinitionId::from_str(&format!("xor{i}#wonderland")).expect("Valid"); let asset_definition = AssetDefinition::store(asset_definition_id.clone()); @@ -56,30 +62,31 @@ fn correct_pagination_assets_after_creating_new_one() { let res = test_client .request_with_pagination_and_sorting( client::asset::by_account_id(account_id.clone()), - Pagination::new(None, Some(5)), + Pagination { + limit: NonZeroU32::new(5), + start: None, + }, sorting.clone(), ) + .expect("Valid") + .collect::>>() .expect("Valid"); - assert_eq!( - res.output - .iter() - .map(|asset| asset.id().definition_id.name.clone()) - .collect::>(), - assets + assert!(res + .iter() + .map(|asset| &asset.id().definition_id.name) + .eq(assets .iter() .take(5) - .map(|asset| asset.id().definition_id.name.clone()) - .collect::>() - ); + .map(|asset| &asset.id().definition_id.name))); - let new_asset_definition_id = AssetDefinitionId::from_str("xor10#wonderland").expect("Valid"); + let new_asset_definition_id = AssetDefinitionId::from_str("xor20#wonderland").expect("Valid"); let new_asset_definition = AssetDefinition::store(new_asset_definition_id.clone()); let mut new_asset_metadata = Metadata::new(); new_asset_metadata .insert_with_limits( sort_by_metadata_key, - 10_u128.to_value(), + 20_u128.to_value(), MetadataLimits::new(10, 23), ) .expect("Valid"); @@ -98,25 +105,24 @@ fn correct_pagination_assets_after_creating_new_one() { let res = test_client .request_with_pagination_and_sorting( client::asset::by_account_id(account_id), - Pagination::new(Some(5), Some(6)), + Pagination { + limit: NonZeroU32::new(13), + start: NonZeroU64::new(8), + }, sorting, ) + .expect("Valid") + .collect::>>() .expect("Valid"); - let mut right = assets.into_iter().skip(5).take(5).collect::>(); - - right.push(new_asset); - - assert_eq!( - res.output - .into_iter() - .map(|asset| asset.id().definition_id.name.clone()) - .collect::>(), - right - .into_iter() - .map(|asset| asset.id().definition_id.name.clone()) - .collect::>() - ); + assert!(res + .iter() + .map(|asset| &asset.id().definition_id.name) + .eq(assets + .iter() + .skip(8) + .chain(core::iter::once(&new_asset)) + .map(|asset| &asset.id().definition_id.name))); } #[test] @@ -164,15 +170,15 @@ fn correct_sorting_of_entities() { string::StringPredicate::starts_with("xor_"), )), ) + .expect("Valid") + .collect::>>() .expect("Valid"); assert!(res - .output .iter() .map(Identifiable::id) .eq(asset_definitions.iter().rev())); assert!(res - .output .iter() .map(|asset_definition| asset_definition.metadata()) .eq(assets_metadata.iter().rev())); @@ -215,15 +221,12 @@ fn correct_sorting_of_entities() { string::StringPredicate::starts_with("charlie"), )), ) + .expect("Valid") + .collect::>>() .expect("Valid"); + assert!(res.iter().map(Identifiable::id).eq(accounts.iter().rev())); assert!(res - .output - .iter() - .map(Identifiable::id) - .eq(accounts.iter().rev())); - assert!(res - .output .iter() .map(|account| account.metadata()) .eq(accounts_metadata.iter().rev())); @@ -266,15 +269,12 @@ fn correct_sorting_of_entities() { string::StringPredicate::starts_with("neverland"), )), ) + .expect("Valid") + .collect::>>() .expect("Valid"); + assert!(res.iter().map(Identifiable::id).eq(domains.iter().rev())); assert!(res - .output - .iter() - .map(Identifiable::id) - .eq(domains.iter().rev())); - assert!(res - .output .iter() .map(|domain| domain.metadata()) .eq(domains_metadata.iter().rev())); @@ -316,14 +316,16 @@ fn correct_sorting_of_entities() { Sorting::by_metadata_key(sort_by_metadata_key), filter, ) + .expect("Valid") + .collect::>>() .expect("Valid"); - assert_eq!(res.output[0].id(), &domains[1]); - assert_eq!(res.output[1].id(), &domains[0]); - assert_eq!(res.output[2].id(), &domains[2]); - assert_eq!(res.output[0].metadata(), &domains_metadata[1]); - assert_eq!(res.output[1].metadata(), &domains_metadata[0]); - assert_eq!(res.output[2].metadata(), &domains_metadata[2]); + assert_eq!(res[0].id(), &domains[1]); + assert_eq!(res[1].id(), &domains[0]); + assert_eq!(res[2].id(), &domains[2]); + assert_eq!(res[0].metadata(), &domains_metadata[1]); + assert_eq!(res[1].metadata(), &domains_metadata[0]); + assert_eq!(res[2].metadata(), &domains_metadata[2]); } #[test] @@ -377,15 +379,11 @@ fn sort_only_elements_which_have_sorting_key() -> Result<()> { string::StringPredicate::starts_with("charlie"), )), ) - .wrap_err("Failed to submit request")?; + .wrap_err("Failed to submit request")? + .collect::>>()?; - let accounts = accounts_a.into_iter().rev().chain(accounts_b.into_iter()); - assert!(res - .output - .iter() - .map(Identifiable::id) - .cloned() - .eq(accounts)); + let accounts = accounts_a.iter().rev().chain(accounts_b.iter()); + assert!(res.iter().map(Identifiable::id).eq(accounts)); Ok(()) } diff --git a/client/tests/integration/transfer_asset.rs b/client/tests/integration/transfer_asset.rs index b7d8022b048..674a1fa405e 100644 --- a/client/tests/integration/transfer_asset.rs +++ b/client/tests/integration/transfer_asset.rs @@ -1,6 +1,6 @@ #![allow(clippy::restriction, clippy::pedantic)] -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_crypto::KeyPair; use iroha_data_model::{prelude::*, Registered}; use iroha_primitives::fixed::Fixed; @@ -90,7 +90,9 @@ fn simulate_transfer< transfer_asset, client::asset::by_account_id(mouse_id.clone()), |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == amount_to_transfer.clone().into() && asset.id().account_id == mouse_id diff --git a/client/tests/integration/triggers/time_trigger.rs b/client/tests/integration/triggers/time_trigger.rs index 0543f4a7361..b2f77b8a600 100644 --- a/client/tests/integration/triggers/time_trigger.rs +++ b/client/tests/integration/triggers/time_trigger.rs @@ -3,7 +3,7 @@ use std::{str::FromStr as _, time::Duration}; use eyre::Result; -use iroha_client::client::{self, Client}; +use iroha_client::client::{self, Client, QueryResult}; use iroha_config::sumeragi::default::DEFAULT_CONSENSUS_ESTIMATION_MS; use iroha_data_model::{prelude::*, transaction::WasmSmartContract}; use iroha_logger::info; @@ -246,7 +246,9 @@ fn mint_nft_for_every_user_every_1_sec() -> Result<()> { for account_id in accounts { let start_pattern = "nft_number_"; let end_pattern = format!("_for_{}#{}", account_id.name, account_id.domain_id); - let assets = test_client.request(client::asset::by_account_id(account_id.clone()))?; + let assets = test_client + .request(client::asset::by_account_id(account_id.clone()))? + .collect::>>()?; let count: u64 = assets .into_iter() .filter(|asset| { diff --git a/client/tests/integration/tx_history.rs b/client/tests/integration/tx_history.rs index 45ea0a8eb26..af47084ca8f 100644 --- a/client/tests/integration/tx_history.rs +++ b/client/tests/integration/tx_history.rs @@ -1,10 +1,14 @@ #![allow(clippy::restriction)] -use std::{str::FromStr as _, thread}; +use std::{ + num::{NonZeroU32, NonZeroU64}, + str::FromStr as _, + thread, +}; use eyre::Result; -use iroha_client::client::transaction; -use iroha_data_model::prelude::*; +use iroha_client::client::{transaction, QueryResult}; +use iroha_data_model::{prelude::*, query::Pagination}; use test_network::*; use super::Configuration; @@ -52,9 +56,12 @@ fn client_has_rejected_and_acepted_txs_should_return_tx_history() -> Result<()> let transactions = client .request_with_pagination( transaction::by_account_id(account_id.clone()), - Pagination::new(Some(1), Some(50)), + Pagination { + limit: NonZeroU32::new(50), + start: NonZeroU64::new(1), + }, )? - .only_output(); + .collect::>>()?; assert_eq!(transactions.len(), 50); let mut prev_creation_time = core::time::Duration::from_millis(0); diff --git a/client/tests/integration/tx_rollback.rs b/client/tests/integration/tx_rollback.rs index 7d366f3f8bb..e65037e9d7d 100644 --- a/client/tests/integration/tx_rollback.rs +++ b/client/tests/integration/tx_rollback.rs @@ -3,7 +3,7 @@ use std::str::FromStr as _; use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_data_model::prelude::*; use test_network::*; @@ -30,11 +30,13 @@ fn client_sends_transaction_with_invalid_instruction_should_not_see_any_changes( //Then let request = client::asset::by_account_id(account_id); - let query_result = client.request(request)?; + let query_result = client.request(request)?.collect::>>()?; assert!(query_result .iter() .all(|asset| asset.id().definition_id != wrong_asset_definition_id)); - let definition_query_result = client.request(client::asset::all_definitions())?; + let definition_query_result = client + .request(client::asset::all_definitions())? + .collect::>>()?; assert!(definition_query_result .iter() .all(|asset| *asset.id() != wrong_asset_definition_id)); diff --git a/client/tests/integration/unregister_peer.rs b/client/tests/integration/unregister_peer.rs index e46a421a9cf..817e90ded4e 100644 --- a/client/tests/integration/unregister_peer.rs +++ b/client/tests/integration/unregister_peer.rs @@ -2,7 +2,7 @@ use std::thread; use eyre::Result; -use iroha_client::client; +use iroha_client::client::{self, QueryResult}; use iroha_crypto::KeyPair; use iroha_data_model::{ parameter::{default::MAX_TRANSACTIONS_IN_BLOCK, ParametersBuilder}, @@ -64,7 +64,9 @@ fn check_assets( Configuration::block_sync_gossip_time(), 15, |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == *asset_definition_id && *asset.value() == AssetValue::Quantity(quantity) }) diff --git a/client/tests/integration/unstable_network.rs b/client/tests/integration/unstable_network.rs index 79579f26c78..b14522b2f9b 100644 --- a/client/tests/integration/unstable_network.rs +++ b/client/tests/integration/unstable_network.rs @@ -3,7 +3,7 @@ use core::sync::atomic::Ordering; use std::thread; -use iroha_client::client::{self, Client}; +use iroha_client::client::{self, Client, QueryResult}; use iroha_data_model::prelude::*; use iroha_logger::Level; use rand::seq::SliceRandom; @@ -122,7 +122,9 @@ fn unstable_network( Configuration::pipeline_time(), 4, |result| { - result.iter().any(|asset| { + let assets = result.collect::>>().expect("Valid"); + + assets.iter().any(|asset| { asset.id().definition_id == asset_definition_id && *asset.value() == AssetValue::Quantity(account_has_quantity) }) diff --git a/client/tests/integration/upgrade.rs b/client/tests/integration/upgrade.rs index 03a61bc9027..3d667503ef0 100644 --- a/client/tests/integration/upgrade.rs +++ b/client/tests/integration/upgrade.rs @@ -3,7 +3,7 @@ use std::path::Path; use eyre::Result; -use iroha_client::client::Client; +use iroha_client::client::{Client, QueryResult}; use iroha_crypto::KeyPair; use iroha_data_model::{prelude::*, query::permission::FindPermissionTokenSchema}; use iroha_logger::info; diff --git a/config/Cargo.toml b/config/Cargo.toml index 13879d1cab7..93dccade084 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -27,6 +27,7 @@ displaydoc = { workspace = true } derive_more = { workspace = true } cfg-if = { workspace = true } path-absolutize = { workspace = true } +once_cell = "1.16.0" [dev-dependencies] proptest = { workspace = true } diff --git a/config/src/torii.rs b/config/src/torii.rs index 81ad7d67701..1797d8e7e07 100644 --- a/config/src/torii.rs +++ b/config/src/torii.rs @@ -1,5 +1,7 @@ //! `Torii` configuration as well as the default values for the URLs used for the main endpoints: `p2p`, `telemetry`, but not `api`. #![allow(clippy::std_instead_of_core, clippy::arithmetic_side_effects)] +use std::num::NonZeroU64; + use iroha_config_base::derive::{Documented, Proxy}; use iroha_primitives::addr::{socket_addr, SocketAddr}; use serde::{Deserialize, Serialize}; @@ -12,6 +14,12 @@ pub const DEFAULT_TORII_TELEMETRY_ADDR: SocketAddr = socket_addr!(127.0.0.1:8180 pub const DEFAULT_TORII_MAX_TRANSACTION_SIZE: u32 = 2_u32.pow(15); /// Default upper bound on `content-length` specified in the HTTP request header pub const DEFAULT_TORII_MAX_CONTENT_LENGTH: u32 = 2_u32.pow(12) * 4000; +/// Default max size of a single batch of results from a query +pub static DEFAULT_TORII_FETCH_SIZE: once_cell::sync::Lazy = + once_cell::sync::Lazy::new(|| NonZeroU64::new(10).unwrap()); +/// Default max time a query can remain in the store unaccessed +pub static DEFAULT_TORII_QUERY_IDLE_TIME_MS: once_cell::sync::Lazy = + once_cell::sync::Lazy::new(|| NonZeroU64::new(30_000).unwrap()); /// Structure that defines the configuration parameters of `Torii` which is the routing module. /// For example the `p2p_addr`, which is used for consensus and block-synchronisation purposes, @@ -33,6 +41,10 @@ pub struct Configuration { pub max_transaction_size: u32, /// Maximum number of bytes in raw message. Used to prevent from DOS attacks. pub max_content_len: u32, + /// How many query results are returned in one batch + pub fetch_size: NonZeroU64, + /// Time query can remain in the store if unaccessed + pub query_idle_time_ms: NonZeroU64, } impl Default for ConfigurationProxy { @@ -43,6 +55,8 @@ impl Default for ConfigurationProxy { telemetry_url: None, max_transaction_size: Some(DEFAULT_TORII_MAX_TRANSACTION_SIZE), max_content_len: Some(DEFAULT_TORII_MAX_CONTENT_LENGTH), + fetch_size: Some(*DEFAULT_TORII_FETCH_SIZE), + query_idle_time_ms: Some(*DEFAULT_TORII_QUERY_IDLE_TIME_MS), } } } @@ -96,9 +110,11 @@ pub mod tests { telemetry_url in prop::option::of(Just(DEFAULT_TORII_TELEMETRY_ADDR)), max_transaction_size in prop::option::of(Just(DEFAULT_TORII_MAX_TRANSACTION_SIZE)), max_content_len in prop::option::of(Just(DEFAULT_TORII_MAX_CONTENT_LENGTH)), + fetch_size in prop::option::of(Just(*DEFAULT_TORII_FETCH_SIZE)), + query_idle_time_ms in prop::option::of(Just(*DEFAULT_TORII_QUERY_IDLE_TIME_MS)), ) -> ConfigurationProxy { - ConfigurationProxy { p2p_addr, api_url, telemetry_url, max_transaction_size, max_content_len } + ConfigurationProxy { p2p_addr, api_url, telemetry_url, max_transaction_size, max_content_len, fetch_size, query_idle_time_ms } } } } diff --git a/configs/peer/config.json b/configs/peer/config.json index 1737604b1b3..56c74756874 100644 --- a/configs/peer/config.json +++ b/configs/peer/config.json @@ -25,7 +25,9 @@ "API_URL": null, "TELEMETRY_URL": null, "MAX_TRANSACTION_SIZE": 32768, - "MAX_CONTENT_LEN": 16384000 + "MAX_CONTENT_LEN": 16384000, + "FETCH_SIZE": 10, + "QUERY_IDLE_TIME_MS": 30000 }, "BLOCK_SYNC": { "GOSSIP_PERIOD_MS": 10000, diff --git a/configs/peer/validator.wasm b/configs/peer/validator.wasm index 13165644aa3b6da78c02abfd14eab0366d42e345..9009c58bd944b36ea3bc88b7fc227cf0f9ba25be 100644 GIT binary patch literal 379964 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≫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

(Bo$&(G6b=* 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 li1v#_@4qLU~2Jz$HH>2lUqez5ZKUpp{ln zs1J-@dvC8fNWiEFQ9+}iMu`vwG)feNAVIN4MU5I>iV`47kbvQ#jS%Jk{f)WS-fKUS zoDky0&%Z>^UXS@0bG+x6W6tHB`o@3pJn&*m3Zr0c@Vr+Rjcl?F2lFllW56X`Oj+dfbQO^b||f$^_P}- z#6>-?s~_r*mTvP$RG_69T`%mG3N>qoJFbD#`VkN|MCz#{d#FLEAvI@Z0gzI`5}x^b zQc*!K_}@|VnloPa>QhJG@TSww_}7z9ebeGszwV6JEdEz7cF*Uy=dXMHX=j|e_%*M4 z?a7N@ck-K0J^eMWI(6}BMVaZRz2&rjeAD97PJYd6-?;dUH~pi^d7i5uzUm+T+4J4? za8b_M^t|x;f$Ii>!1n|G1VM$LKL7c8r~fGDSK=XlrdfISbhm#!zgDSMf{I7$6+iav zKdyZkCG^6u;`yFmtyXIl_{OhzpZ&l?{0ywOqdpQq-l{9k?gmB8~V6|YvKZvYtZx#$aX`EkYlXXPkO zBgKCPq~}eiqx?TV1oXhG#PkG?Dt_IM=v?=7IR}(gK-_>IQ00$5eQw@4_$&S^T^5gg z|A6)-7!!-|9|*VqM6$j5uU(;i)!l$KUi8rYvUFc60$KDzKc%Oovi7p`zVDrCms%)Y z_AR~_4`clY1$X_Q2qt!R{~7s;TYeq8LfIe~@*?Z_S)Lb9i!1Y@L#lo{RIqRHONB;L zk`nPJ6#F{13J{-N|EDshC*Y|{B)#Cp)wnWXe=3z~HF~z-qwyS0AmUR0bF5Lmv?8=Y zldaN4xf*b|_wbaHhOjy~7*rWtR6R7QBuR+&sQRz>C&S4w3Vm-{d~mqL&n73=d-Ww= z_Tc&(?RUF=t1J9!{4b~d%j?eg*T5S)*%WS}MPGNu$>`R9dCeQ&=(Ovi(_VY>8~^du zr~S*R-t!OcDcVxKub-B``=6M-lTSVU^w<5PciF)7^21l1<{qye7(Dr8^!2GHpZ3~U zg?|0ylV5$>sjolzA5MMaX<;z%1Qf{p`jf#I2G$Nt{LsHPxV`cj|2_WA{<>g&aAWZ0 z;QC-~_`}Mbl@CN$`#-MSQTeyK{I3KTMK=W>_dgtcEc#UR)!@o#L-eKKtIv-t1o3_<^x5FH_?Gxf(T(wz%Ddtp zR4xggh|Y^w#OFnu{LjS~#_x&06o22pG`b-EUi9Jk#^}uISK@b6 hWU0OY>`sH|S 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�*8N@#ip#Nv08OyD^iAuVlZ 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 DJVvLX diff --git a/core/benches/apply_blocks/apply_blocks.rs b/core/benches/apply_blocks/apply_blocks.rs index 7c434066a69..917d29dee22 100644 --- a/core/benches/apply_blocks/apply_blocks.rs +++ b/core/benches/apply_blocks/apply_blocks.rs @@ -51,7 +51,7 @@ fn create_block( let pending_block = PendingBlock { header, transactions: vec![TransactionValue { - tx: transaction, + value: transaction, error: None, }], event_recommendations: Vec::new(), diff --git a/core/src/queue.rs b/core/src/queue.rs index ba80068cb1f..681a899bb3c 100644 --- a/core/src/queue.rs +++ b/core/src/queue.rs @@ -170,8 +170,8 @@ impl Queue { } /// Returns all pending transactions. - pub fn all_transactions<'q: 'wsv, 'wsv>( - &'q self, + pub fn all_transactions<'wsv>( + &'wsv self, wsv: &'wsv WorldStateView, ) -> impl Iterator + 'wsv { self.txs.iter().filter_map(|tx| { diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index 3e4c17c6463..6550e6b37f7 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -466,18 +466,20 @@ pub mod query { use eyre::{Result, WrapErr}; use iroha_data_model::{ - evaluate::ExpressionEvaluator, query::error::QueryExecutionFail as Error, + account::Account, + evaluate::ExpressionEvaluator, + permission::PermissionToken, + query::{error::QueryExecutionFail as Error, MetadataValue}, }; use super::*; - use crate::smartcontracts::query::Lazy; impl ValidQuery for FindRolesByAccountId { #[metrics(+"find_roles_by_account_id")] fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { let account_id = wsv .evaluate(&self.id) .wrap_err("Failed to evaluate account id") @@ -496,7 +498,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { let account_id = wsv .evaluate(&self.id) .wrap_err("Failed to evaluate account id") @@ -513,7 +515,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { Ok(Box::new( wsv.domains() .values() @@ -525,10 +527,7 @@ pub mod query { impl ValidQuery for FindAccountById { #[metrics(+"find_account_by_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get id") @@ -543,7 +542,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { let name = wsv .evaluate(&self.name) .wrap_err("Failed to get account name") @@ -570,7 +569,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { let id = wsv .evaluate(&self.domain_id) .wrap_err("Failed to get domain id") @@ -583,10 +582,7 @@ pub mod query { impl ValidQuery for FindAccountKeyValueByIdAndKey { #[metrics(+"find_account_key_value_by_id_and_key")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get account id") @@ -607,7 +603,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { let asset_definition_id = wsv .evaluate(&self.asset_definition_id) .wrap_err("Failed to get asset id") diff --git a/core/src/smartcontracts/isi/asset.rs b/core/src/smartcontracts/isi/asset.rs index 36b58bb8571..62554ffdd38 100644 --- a/core/src/smartcontracts/isi/asset.rs +++ b/core/src/smartcontracts/isi/asset.rs @@ -436,19 +436,19 @@ pub mod isi { /// Asset-related query implementations. pub mod query { use eyre::{Result, WrapErr as _}; - use iroha_data_model::query::{ - asset::IsAssetDefinitionOwner, error::QueryExecutionFail as Error, + use iroha_data_model::{ + asset::{Asset, AssetDefinition}, + query::{asset::IsAssetDefinitionOwner, error::QueryExecutionFail as Error, MetadataValue}, }; use super::*; - use crate::smartcontracts::query::Lazy; impl ValidQuery for FindAllAssets { #[metrics(+"find_all_assets")] fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { Ok(Box::new( wsv.domains() .values() @@ -468,7 +468,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { Ok(Box::new( wsv.domains() .values() @@ -480,10 +480,7 @@ pub mod query { impl ValidQuery for FindAssetById { #[metrics(+"find_asset_by_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset id") @@ -501,10 +498,7 @@ pub mod query { impl ValidQuery for FindAssetDefinitionById { #[metrics(+"find_asset_defintion_by_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset definition id") @@ -521,7 +515,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { let name = wsv .evaluate(&self.name) .wrap_err("Failed to get asset name") @@ -552,13 +546,13 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { let id = wsv .evaluate(&self.account_id) .wrap_err("Failed to get account id") .map_err(|e| Error::Evaluate(e.to_string()))?; iroha_logger::trace!(%id); - Ok(Box::new(wsv.account_assets(&id)?)) + Ok(Box::new(wsv.account_assets(&id)?.cloned())) } } @@ -567,7 +561,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { let id = wsv .evaluate(&self.asset_definition_id) .wrap_err("Failed to get asset definition id") @@ -598,7 +592,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { let id = wsv .evaluate(&self.domain_id) .wrap_err("Failed to get domain id") @@ -619,7 +613,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { let domain_id = wsv .evaluate(&self.domain_id) .wrap_err("Failed to get domain id") @@ -654,10 +648,7 @@ pub mod query { impl ValidQuery for FindAssetQuantityById { #[metrics(+"find_asset_quantity_by_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset id") @@ -681,10 +672,7 @@ pub mod query { impl ValidQuery for FindTotalAssetQuantityByAssetDefinitionId { #[metrics(+"find_total_asset_quantity_by_asset_definition_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset definition id") @@ -697,10 +685,7 @@ pub mod query { impl ValidQuery for FindAssetKeyValueByIdAndKey { #[metrics(+"find_asset_key_value_by_id_and_key")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset id") @@ -732,10 +717,7 @@ pub mod query { impl ValidQuery for IsAssetDefinitionOwner { #[metrics("is_asset_definition_owner")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let asset_definition_id = wsv .evaluate(&self.asset_definition_id) .wrap_err("Failed to get asset definition id") diff --git a/core/src/smartcontracts/isi/block.rs b/core/src/smartcontracts/isi/block.rs index 43ffd893a17..017f03a4a6d 100644 --- a/core/src/smartcontracts/isi/block.rs +++ b/core/src/smartcontracts/isi/block.rs @@ -1,6 +1,7 @@ //! This module contains trait implementations related to block queries use eyre::{Result, WrapErr}; use iroha_data_model::{ + block::{BlockHeader, VersionedCommittedBlock}, evaluate::ExpressionEvaluator, query::{ block::FindBlockHeaderByHash, @@ -10,14 +11,13 @@ use iroha_data_model::{ use iroha_telemetry::metrics; use super::*; -use crate::smartcontracts::query::Lazy; impl ValidQuery for FindAllBlocks { #[metrics(+"find_all_blocks")] fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { + ) -> Result + 'wsv>, QueryExecutionFail> { Ok(Box::new( wsv.all_blocks().rev().map(|block| Clone::clone(&*block)), )) @@ -29,7 +29,7 @@ impl ValidQuery for FindAllBlockHeaders { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { + ) -> Result + 'wsv>, QueryExecutionFail> { Ok(Box::new( wsv.all_blocks() .rev() @@ -40,10 +40,7 @@ impl ValidQuery for FindAllBlockHeaders { impl ValidQuery for FindBlockHeaderByHash { #[metrics(+"find_block_header")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { + fn execute(&self, wsv: &WorldStateView) -> Result { let hash = wsv .evaluate(&self.hash) .wrap_err("Failed to evaluate hash") diff --git a/core/src/smartcontracts/isi/domain.rs b/core/src/smartcontracts/isi/domain.rs index e208457a9dc..2f82fec7c3c 100644 --- a/core/src/smartcontracts/isi/domain.rs +++ b/core/src/smartcontracts/isi/domain.rs @@ -288,27 +288,26 @@ pub mod isi { /// Query module provides [`Query`] Domain related implementations. pub mod query { use eyre::{Result, WrapErr}; - use iroha_data_model::query::error::QueryExecutionFail as Error; + use iroha_data_model::{ + domain::Domain, + query::{error::QueryExecutionFail as Error, MetadataValue}, + }; use super::*; - use crate::smartcontracts::query::Lazy; impl ValidQuery for FindAllDomains { #[metrics(+"find_all_domains")] fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { Ok(Box::new(wsv.domains().values().cloned())) } } impl ValidQuery for FindDomainById { #[metrics(+"find_domain_by_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get domain id") @@ -320,10 +319,7 @@ pub mod query { impl ValidQuery for FindDomainKeyValueByIdAndKey { #[metrics(+"find_domain_key_value_by_id_and_key")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get domain id") @@ -341,10 +337,7 @@ pub mod query { impl ValidQuery for FindAssetDefinitionKeyValueByIdAndKey { #[metrics(+"find_asset_definition_key_value_by_id_and_key")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset definition id") diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 44929fec817..452f77bef98 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -42,7 +42,7 @@ macro_rules! impl_lazy { } impl_lazy! { bool, - NumericValue, + iroha_data_model::numeric::NumericValue, iroha_data_model::role::Role, iroha_data_model::asset::Asset, iroha_data_model::asset::AssetDefinition, @@ -50,12 +50,13 @@ impl_lazy! { iroha_data_model::domain::Domain, iroha_data_model::block::BlockHeader, iroha_data_model::query::MetadataValue, - iroha_data_model::query::TransactionQueryResult, + iroha_data_model::query::TransactionQueryOutput, iroha_data_model::trigger::Trigger, } /// Query Request statefully validated on the Iroha node side. #[derive(Debug, Decode, Encode)] +#[repr(transparent)] pub struct ValidQueryRequest(VersionedSignedQuery); impl ValidQueryRequest { @@ -110,10 +111,7 @@ impl ValidQueryRequest { } impl ValidQuery for QueryBox { - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute<'wsv>(&self, wsv: &'wsv WorldStateView) -> Result, Error> { iroha_logger::debug!(query=%self, "Executing"); macro_rules! match_all { @@ -474,7 +472,7 @@ mod tests { if found_accepted.transaction.error.is_none() { assert_eq!( va_tx.hash().transmute(), - found_accepted.transaction.tx.hash() + found_accepted.transaction.value.hash() ) } Ok(()) diff --git a/core/src/smartcontracts/isi/triggers/mod.rs b/core/src/smartcontracts/isi/triggers/mod.rs index d45693ce5c1..f2397a4a60a 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -195,27 +195,31 @@ pub mod isi { pub mod query { //! Queries associated to triggers. - use iroha_data_model::query::error::QueryExecutionFail as Error; + use iroha_data_model::{ + events::FilterBox, + query::{error::QueryExecutionFail as Error, MetadataValue}, + trigger::{OptimizedExecutable, Trigger, TriggerId}, + }; use super::*; - use crate::{prelude::*, smartcontracts::query::Lazy}; + use crate::prelude::*; impl ValidQuery for FindAllActiveTriggerIds { #[metrics(+"find_all_active_triggers")] fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { Ok(Box::new(wsv.triggers().ids().cloned())) } } impl ValidQuery for FindTriggerById { #[metrics(+"find_trigger_by_id")] - fn execute<'wsv>( + fn execute( &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + wsv: &WorldStateView, + ) -> Result, Error> { let id = wsv .evaluate(&self.id) .map_err(|e| Error::Evaluate(format!("Failed to evaluate trigger id. {e}")))?; @@ -243,10 +247,7 @@ pub mod query { impl ValidQuery for FindTriggerKeyValueByIdAndKey { #[metrics(+"find_trigger_key_value_by_id_and_key")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .map_err(|e| Error::Evaluate(format!("Failed to evaluate trigger id. {e}")))?; @@ -272,7 +273,10 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> eyre::Result<::Lazy<'wsv>, Error> { + ) -> eyre::Result< + Box> + 'wsv>, + Error, + > { let domain_id = wsv .evaluate(&self.domain_id) .map_err(|e| Error::Evaluate(format!("Failed to evaluate domain id. {e}")))?; diff --git a/core/src/smartcontracts/isi/triggers/set.rs b/core/src/smartcontracts/isi/triggers/set.rs index a3bffebae01..396975b3418 100644 --- a/core/src/smartcontracts/isi/triggers/set.rs +++ b/core/src/smartcontracts/isi/triggers/set.rs @@ -208,54 +208,48 @@ impl Set { /// Apply `f` to triggers that belong to the given [`DomainId`] /// /// Return an empty list if [`Set`] doesn't contain any triggers belonging to [`DomainId`]. - pub fn inspect_by_domain_id( - &self, + pub fn inspect_by_domain_id<'a, F: 'a, R>( + &'a self, domain_id: &DomainId, f: F, - ) -> impl ExactSizeIterator + ) -> impl Iterator + '_ where F: Fn(&TriggerId, &dyn ActionTrait) -> R, { - self.ids - .iter() - .filter_map(|(id, event_type)| { - let trigger_domain_id = id.domain_id.as_ref()?; + let domain_id = domain_id.clone(); - if trigger_domain_id != domain_id { - return None; - } + self.ids.iter().filter_map(move |(id, event_type)| { + let trigger_domain_id = id.domain_id.as_ref()?; - let result = match event_type { - EventType::Data => self - .data_triggers - .get(id) - .map(|trigger| f(id, trigger)) - .expect("`Set::data_triggers` doesn't contain required id. This is a bug"), - EventType::Pipeline => self - .pipeline_triggers - .get(id) - .map(|trigger| f(id, trigger)) - .expect( - "`Set::pipeline_triggers` doesn't contain required id. This is a bug", - ), - EventType::Time => self - .time_triggers - .get(id) - .map(|trigger| f(id, trigger)) - .expect("`Set::time_triggers` doesn't contain required id. This is a bug"), - EventType::ExecuteTrigger => self - .by_call_triggers - .get(id) - .map(|trigger| f(id, trigger)) - .expect( - "`Set::by_call_triggers` doesn't contain required id. This is a bug", - ), - }; - - Some(result) - }) - .collect::>() - .into_iter() + if *trigger_domain_id != domain_id { + return None; + } + + let result = match event_type { + EventType::Data => self + .data_triggers + .get(id) + .map(|trigger| f(id, trigger)) + .expect("`Set::data_triggers` doesn't contain required id. This is a bug"), + EventType::Pipeline => self + .pipeline_triggers + .get(id) + .map(|trigger| f(id, trigger)) + .expect("`Set::pipeline_triggers` doesn't contain required id. This is a bug"), + EventType::Time => self + .time_triggers + .get(id) + .map(|trigger| f(id, trigger)) + .expect("`Set::time_triggers` doesn't contain required id. This is a bug"), + EventType::ExecuteTrigger => self + .by_call_triggers + .get(id) + .map(|trigger| f(id, trigger)) + .expect("`Set::by_call_triggers` doesn't contain required id. This is a bug"), + }; + + Some(result) + }) } /// Apply `f` to the trigger identified by `id`. diff --git a/core/src/smartcontracts/isi/tx.rs b/core/src/smartcontracts/isi/tx.rs index 2c87fa781cb..894c965333e 100644 --- a/core/src/smartcontracts/isi/tx.rs +++ b/core/src/smartcontracts/isi/tx.rs @@ -10,13 +10,13 @@ use iroha_data_model::{ prelude::*, query::{ error::{FindError, QueryExecutionFail}, - TransactionQueryResult, + TransactionQueryOutput, }, transaction::TransactionValue, }; use iroha_telemetry::metrics; -use super::{query::Lazy, *}; +use super::*; pub(crate) struct BlockTransactionIter(Arc, usize); pub(crate) struct BlockTransactionRef(Arc, usize); @@ -61,11 +61,11 @@ impl ValidQuery for FindAllTransactions { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { + ) -> Result + 'wsv>, QueryExecutionFail> { Ok(Box::new( wsv.all_blocks() .flat_map(BlockTransactionIter::new) - .map(|tx| TransactionQueryResult { + .map(|tx| TransactionQueryOutput { block_hash: tx.block_hash(), transaction: tx.value(), }), @@ -78,7 +78,7 @@ impl ValidQuery for FindTransactionsByAccountId { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { + ) -> Result + 'wsv>, QueryExecutionFail> { let account_id = wsv .evaluate(&self.account_id) .wrap_err("Failed to get account id") @@ -88,7 +88,7 @@ impl ValidQuery for FindTransactionsByAccountId { wsv.all_blocks() .flat_map(BlockTransactionIter::new) .filter(move |tx| *tx.authority() == account_id) - .map(|tx| TransactionQueryResult { + .map(|tx| TransactionQueryOutput { block_hash: tx.block_hash(), transaction: tx.value(), }), @@ -98,10 +98,7 @@ impl ValidQuery for FindTransactionsByAccountId { impl ValidQuery for FindTransactionByHash { #[metrics(+"find_transaction_by_hash")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { + fn execute(&self, wsv: &WorldStateView) -> Result { let tx_hash = wsv .evaluate(&self.hash) .wrap_err("Failed to get hash") @@ -122,7 +119,7 @@ impl ValidQuery for FindTransactionByHash { .iter() .find(|transaction| transaction.value.hash() == tx_hash) .cloned() - .map(|transaction| TransactionQueryResult { + .map(|transaction| TransactionQueryOutput { block_hash, transaction, }) diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index fee5d884986..34cbe4ea3cc 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -269,7 +269,7 @@ pub mod isi { for account_id in account_ids { accounts_with_token.insert( account_id.clone(), - wsv.account_inherent_permission_tokens(account_id)? + wsv.account_inherent_permission_tokens(account_id) .filter(|token| token.definition_id == *target_definition_id) .cloned() .collect::>(), @@ -405,22 +405,25 @@ pub mod isi { pub mod query { use eyre::Result; use iroha_data_model::{ + parameter::Parameter, + peer::Peer, + permission::PermissionTokenDefinition, prelude::*, query::{ error::{FindError, QueryExecutionFail as Error}, permission::DoesAccountHavePermissionToken, }, + role::{Role, RoleId}, }; use super::*; - use crate::smartcontracts::query::Lazy; impl ValidQuery for FindAllRoles { #[metrics(+"find_all_roles")] fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { Ok(Box::new(wsv.world.roles.values().cloned())) } } @@ -430,7 +433,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { Ok(Box::new(wsv .world .roles @@ -443,10 +446,7 @@ pub mod query { impl ValidQuery for FindRoleByRoleId { #[metrics(+"find_role_by_role_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let role_id = wsv .evaluate(&self.id) .map_err(|e| Error::Evaluate(e.to_string()))?; @@ -464,7 +464,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { Ok(Box::new(wsv.peers().cloned().map(Peer::new))) } } @@ -474,7 +474,7 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { Ok(Box::new( wsv.permission_token_definitions().cloned(), )) @@ -486,17 +486,14 @@ pub mod query { fn execute<'wsv>( &self, wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + ) -> Result + 'wsv>, Error> { Ok(Box::new(wsv.parameters().cloned())) } } impl ValidQuery for DoesAccountHavePermissionToken { #[metrics("does_account_have_permission_token")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let authority = wsv .evaluate(&self.account_id) .map_err(|e| Error::Evaluate(e.to_string()))?; diff --git a/core/src/smartcontracts/mod.rs b/core/src/smartcontracts/mod.rs index ebab9f86afe..056dc8a6ab8 100644 --- a/core/src/smartcontracts/mod.rs +++ b/core/src/smartcontracts/mod.rs @@ -28,7 +28,7 @@ pub trait Execute { } /// This trait should be implemented for all Iroha Queries. -pub trait ValidQuery: Query +pub trait ValidQuery: iroha_data_model::query::Query where Self::Output: Lazy, { @@ -76,8 +76,8 @@ impl iroha_data_model::evaluate::Context for Context<'_> { .execute(self.wsv) .map(|value| match value { LazyValue::Value(value) => value, - // NOTE: This will only be executed from the validator/executor. - // Handing out references to the host system is a security risk + // NOTE: This will only be executed when evaluating an expression for an + // instruction, i.e. it will only be executed from the validator/executor. LazyValue::Iter(iter) => Value::Vec(iter.collect()), }) .map_err(Into::into) diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 2c02206195b..6c650c3ed36 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -686,8 +686,7 @@ impl<'wrld, S: state::GetCommon<'wrld>, R: DefaultExecute> ExecuteOperations<'wr .map_err(Into::into) .map(|lazy_value| match lazy_value { LazyValue::Value(value) => value, - // NOTE: Returning references to the host system is a security risk - LazyValue::Iter(iter) => Value::Vec(iter.collect::>()), + LazyValue::Iter(iter) => Value::Vec(iter.collect()), }) } @@ -869,8 +868,7 @@ impl<'wrld> ExecuteOperations<'wrld, state::Validator<'wrld>> for Runtime value, - // NOTE: Returning references to the host system is a security risk - LazyValue::Iter(iter) => Value::Vec(iter.collect::>()), + LazyValue::Iter(iter) => Value::Vec(iter.collect()), }) } diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index ec2835fb9d8..c2536ec3598 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -384,7 +384,6 @@ impl Sumeragi { // https://github.com/hyperledger/iroha/issues/3396 // Kura should store the block only upon successful application to the internal WSV to avoid storing a corrupted block. // Public-facing WSV update should happen after that and be followed by `BlockCommited` event to prevent client access to uncommitted data. - // TODO: Redundant clone Strategy::kura_store_block(&self.kura, committed_block); // Update WSV copy that is public facing diff --git a/core/src/wsv.rs b/core/src/wsv.rs index 233317aa93c..d5b8cfa57ee 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -160,8 +160,8 @@ impl WorldStateView { pub fn account_assets( &self, id: &AccountId, - ) -> Result + '_, QueryExecutionFail> { - self.map_account(id, |account| account.assets.values().cloned()) + ) -> Result, QueryExecutionFail> { + self.map_account(id, |account| account.assets.values()) } /// Return a set of all permission tokens granted to this account. @@ -176,7 +176,7 @@ impl WorldStateView { let account = self.account(account_id)?; let mut tokens = self - .account_inherent_permission_tokens(account_id)? + .account_inherent_permission_tokens(account_id) .collect::>(); for role_id in &account.roles { @@ -196,12 +196,11 @@ impl WorldStateView { pub fn account_inherent_permission_tokens( &self, account_id: &AccountId, - ) -> Result, FindError> { + ) -> impl ExactSizeIterator { self.world .account_permission_tokens .get(account_id) - .ok_or_else(|| FindError::Account(account_id.clone())) - .map(std::collections::BTreeSet::iter) + .map_or_else(Default::default, std::collections::BTreeSet::iter) } /// Return `true` if [`Account`] contains a permission token not associated with any role. diff --git a/core/test_network/Cargo.toml b/core/test_network/Cargo.toml index e323c350257..7d57da53f9c 100644 --- a/core/test_network/Cargo.toml +++ b/core/test_network/Cargo.toml @@ -9,6 +9,7 @@ license.workspace = true [dependencies] iroha = { workspace = true, features = ["test-network"] } +iroha_crypto = { workspace = true } iroha_client = { workspace = true } iroha_core = { workspace = true } iroha_config = { workspace = true } diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 62deea8daaf..0a5747874ad 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -9,10 +9,10 @@ use std::{ thread, }; -use eyre::{Error, Result}; +use eyre::Result; use futures::{prelude::*, stream::FuturesUnordered}; use iroha::Iroha; -use iroha_client::client::Client; +use iroha_client::client::{Client, QueryOutput}; use iroha_config::{ base::proxy::{LoadFromEnv, Override}, client::Configuration as ClientConfiguration, @@ -20,8 +20,8 @@ use iroha_config::{ sumeragi::Configuration as SumeragiConfiguration, torii::Configuration as ToriiConfiguration, }; -use iroha_core::{prelude::*, smartcontracts::query::Lazy}; -use iroha_data_model::{isi::Instruction, peer::Peer as DataModelPeer, prelude::*}; +use iroha_crypto::prelude::*; +use iroha_data_model::{isi::Instruction, peer::Peer as DataModelPeer, prelude::*, query::Query}; use iroha_genesis::{GenesisNetwork, RawGenesisBlock}; use iroha_logger::{Configuration as LoggerConfiguration, InstrumentFutures}; use iroha_primitives::addr::{socket_addr, SocketAddr}; @@ -650,7 +650,7 @@ impl PeerBuilder { type PeerWithRuntimeAndClient = (Runtime, Peer, Client); fn local_unique_port() -> Result { - Ok(socket_addr!(127.0.0.1: unique_port::get_unique_free_port().map_err(Error::msg)?)) + Ok(socket_addr!(127.0.0.1: unique_port::get_unique_free_port().map_err(eyre::Error::msg)?)) } /// Runtime used for testing. @@ -698,61 +698,61 @@ pub trait TestClient: Sized { /// /// # Errors /// If predicate is not satisfied, after maximum retries. - fn submit_till( + fn submit_till( &mut self, - instruction: impl Instruction + Debug, + instruction: impl Instruction + Debug + Clone, request: R, - f: impl Fn(&R::Output) -> bool, - ) -> eyre::Result + f: impl Fn(::Target) -> bool, + ) -> eyre::Result<()> where - R: ValidQuery + Into + Debug + Clone, - >::Error: Into, - R::Output: Lazy + Clone + Debug; + R::Output: QueryOutput, + ::Target: core::fmt::Debug, + >::Error: Into; /// Submits instructions with polling /// /// # Errors /// If predicate is not satisfied, after maximum retries. - fn submit_all_till( + fn submit_all_till( &mut self, instructions: Vec, request: R, - f: impl Fn(&R::Output) -> bool, - ) -> eyre::Result + f: impl Fn(::Target) -> bool, + ) -> eyre::Result<()> where - R: ValidQuery + Into + Debug + Clone, - >::Error: Into, - R::Output: Lazy + Clone + Debug; + R::Output: QueryOutput, + ::Target: core::fmt::Debug, + >::Error: Into; /// Polls request till predicate `f` is satisfied, with default period and max attempts. /// /// # Errors /// If predicate is not satisfied after maximum retries. - fn poll_request( + fn poll_request( &mut self, request: R, - f: impl Fn(&R::Output) -> bool, - ) -> eyre::Result + f: impl Fn(::Target) -> bool, + ) -> eyre::Result<()> where - R: ValidQuery + Into + Debug + Clone, - >::Error: Into, - R::Output: Lazy + Clone + Debug; + R::Output: QueryOutput, + ::Target: core::fmt::Debug, + >::Error: Into; /// Polls request till predicate `f` is satisfied with `period` and `max_attempts` supplied. /// /// # Errors /// If predicate is not satisfied after maximum retries. - fn poll_request_with_period( + fn poll_request_with_period( &mut self, request: R, period: Duration, max_attempts: u32, - f: impl Fn(&R::Output) -> bool, - ) -> eyre::Result + f: impl Fn(::Target) -> bool, + ) -> eyre::Result<()> where - R: ValidQuery + Into + Debug + Clone, - >::Error: Into, - R::Output: Lazy + Clone + Debug; + R::Output: QueryOutput, + ::Target: core::fmt::Debug, + >::Error: Into; } impl TestRuntime for Runtime { @@ -838,54 +838,54 @@ impl TestClient for Client { } } - fn submit_till( + fn submit_till( &mut self, - instruction: impl Instruction + Debug, + instruction: impl Instruction + Debug + Clone, request: R, - f: impl Fn(&R::Output) -> bool, - ) -> eyre::Result + f: impl Fn(::Target) -> bool, + ) -> eyre::Result<()> where - R: ValidQuery + Into + Debug + Clone, - >::Error: Into, - R::Output: Lazy + Clone + Debug, + R::Output: QueryOutput, + ::Target: core::fmt::Debug, + >::Error: Into, { self.submit(instruction) .expect("Failed to submit instruction."); self.poll_request(request, f) } - fn submit_all_till( + fn submit_all_till( &mut self, instructions: Vec, request: R, - f: impl Fn(&R::Output) -> bool, - ) -> eyre::Result + f: impl Fn(::Target) -> bool, + ) -> eyre::Result<()> where - R: ValidQuery + Into + Debug + Clone, - >::Error: Into, - R::Output: Lazy + Clone + Debug, + R::Output: QueryOutput, + ::Target: core::fmt::Debug, + >::Error: Into, { self.submit_all(instructions) .expect("Failed to submit instruction."); self.poll_request(request, f) } - fn poll_request_with_period( + fn poll_request_with_period( &mut self, request: R, period: Duration, max_attempts: u32, - f: impl Fn(&R::Output) -> bool, - ) -> eyre::Result + f: impl Fn(::Target) -> bool, + ) -> eyre::Result<()> where - R: ValidQuery + Into + Debug + Clone, - >::Error: Into, - R::Output: Lazy + Clone + Debug, + R::Output: QueryOutput, + ::Target: core::fmt::Debug, + >::Error: Into, { let mut query_result = None; for _ in 0..max_attempts { query_result = match self.request(request.clone()) { - Ok(result) if f(&result) => return Ok(result), + Ok(result) if f(result.clone()) => return Ok(()), result => Some(result), }; thread::sleep(period); @@ -893,15 +893,15 @@ impl TestClient for Client { Err(eyre::eyre!("Failed to wait for query request completion that would satisfy specified closure. Got this query result instead: {:?}", &query_result)) } - fn poll_request( + fn poll_request( &mut self, request: R, - f: impl Fn(&R::Output) -> bool, - ) -> eyre::Result + f: impl Fn(::Target) -> bool, + ) -> eyre::Result<()> where - R: ValidQuery + Into + Debug + Clone, - >::Error: Into, - R::Output: Lazy + Clone + Debug, + R::Output: QueryOutput, + ::Target: core::fmt::Debug, + >::Error: Into, { self.poll_request_with_period(request, Configuration::pipeline_time() / 2, 10, f) } diff --git a/data_model/cbindgen.toml b/data_model/cbindgen.toml new file mode 100644 index 00000000000..5d6b21a6ac3 --- /dev/null +++ b/data_model/cbindgen.toml @@ -0,0 +1,3 @@ +[parse.expand] +crates = ["iroha_data_model"] +features = ["ffi_export"] diff --git a/data_model/derive/tests/ui_fail/transparent_api_private_item.stderr b/data_model/derive/tests/ui_fail/transparent_api_private_item.stderr index 2ff8feb4121..74adf898403 100644 --- a/data_model/derive/tests/ui_fail/transparent_api_private_item.stderr +++ b/data_model/derive/tests/ui_fail/transparent_api_private_item.stderr @@ -5,7 +5,7 @@ error[E0603]: struct `QueryPayload` is private | ^^^^^^^^^^^^ private struct | note: the struct `QueryPayload` is defined here - --> $WORKSPACE/data_model/src/query.rs + --> $WORKSPACE/data_model/src/query/mod.rs | | pub use self::model::*; | ^^^^^^^^^^^ diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index c813a88e5ba..9dd3ae8db34 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -38,7 +38,6 @@ use evaluate::Evaluate; use events::FilterBox; use getset::Getters; use iroha_crypto::{HashOf, PublicKey}; -pub use iroha_crypto::{SignatureOf, SignaturesOf}; use iroha_data_model_derive::{ model, IdEqOrdHash, PartiallyTaggedDeserialize, PartiallyTaggedSerialize, }; @@ -50,7 +49,7 @@ use iroha_primitives::{ use iroha_schema::IntoSchema; pub use numeric::model::NumericValue; use parity_scale_codec::{Decode, Encode}; -use prelude::{Executable, TransactionQueryResult, VersionedSignedTransaction}; +use prelude::{Executable, TransactionQueryOutput, VersionedSignedTransaction}; use serde::{Deserialize, Serialize}; use serde_with::{DeserializeFromStr, SerializeDisplay}; @@ -69,16 +68,12 @@ pub mod isi; pub mod metadata; pub mod name; pub mod numeric; -#[cfg(feature = "http")] -pub mod pagination; pub mod peer; pub mod permission; #[cfg(feature = "http")] pub mod predicate; pub mod query; pub mod role; -#[cfg(feature = "http")] -pub mod sorting; pub mod transaction; pub mod trigger; pub mod validator; @@ -778,7 +773,7 @@ pub mod model { Identifiable(IdentifiableBox), PublicKey(PublicKey), SignatureCheckCondition(SignatureCheckCondition), - TransactionQueryResult(TransactionQueryResult), + TransactionQueryOutput(TransactionQueryOutput), PermissionToken(permission::PermissionToken), PermissionTokenSchema(permission::PermissionTokenSchema), Hash(HashValue), @@ -1063,7 +1058,7 @@ impl fmt::Display for Value { Value::Identifiable(v) => fmt::Display::fmt(&v, f), Value::PublicKey(v) => fmt::Display::fmt(&v, f), Value::SignatureCheckCondition(v) => fmt::Display::fmt(&v, f), - Value::TransactionQueryResult(_) => write!(f, "TransactionQueryResult"), + Value::TransactionQueryOutput(_) => write!(f, "TransactionQueryOutput"), Value::PermissionToken(v) => fmt::Display::fmt(&v, f), Value::PermissionTokenSchema(v) => fmt::Display::fmt(&v, f), Value::Hash(v) => fmt::Display::fmt(&v, f), @@ -1093,7 +1088,7 @@ impl Value { | Identifiable(_) | String(_) | Name(_) - | TransactionQueryResult(_) + | TransactionQueryOutput(_) | PermissionToken(_) | PermissionTokenSchema(_) | Hash(_) @@ -1878,6 +1873,4 @@ pub mod prelude { LengthLimits, NumericValue, PredicateTrait, RegistrableBox, ToValue, TriggerBox, TryAsMut, TryAsRef, TryToValue, UpgradableBox, ValidationFail, ValidatorDeny, Value, }; - #[cfg(feature = "http")] - pub use super::{pagination::prelude::*, sorting::prelude::*}; } diff --git a/data_model/src/numeric.rs b/data_model/src/numeric.rs index 8164d5a8c34..f85a7131eb1 100644 --- a/data_model/src/numeric.rs +++ b/data_model/src/numeric.rs @@ -17,7 +17,7 @@ use serde::{ Deserializer, }; -use self::model::NumericValue; +pub use self::model::*; use super::{ DebugCustom, Decode, Deserialize, Display, Encode, FromVariant, IntoSchema, Serialize, }; diff --git a/data_model/src/pagination.rs b/data_model/src/pagination.rs deleted file mode 100644 index 44dfdaf831f..00000000000 --- a/data_model/src/pagination.rs +++ /dev/null @@ -1,122 +0,0 @@ -//! Structures and traits related to pagination. - -#[cfg(not(feature = "std"))] -use alloc::{ - borrow::ToOwned as _, - collections::btree_map, - format, - string::{String, ToString as _}, - vec, - vec::Vec, -}; -#[cfg(feature = "std")] -use std::collections::btree_map; - -use derive_more::{Constructor, Display}; -use iroha_data_model_derive::model; -use iroha_schema::IntoSchema; -use iroha_version::{Decode, Encode}; -use serde::{Deserialize, Serialize}; -use warp::{ - http::StatusCode, - reply::{self, Response}, - Reply, -}; - -pub use self::model::*; - -const PAGINATION_START: &str = "start"; -const PAGINATION_LIMIT: &str = "limit"; - -#[model] -pub mod model { - use super::*; - - /// Structure for pagination requests - #[derive( - Debug, - Display, - Clone, - Copy, - PartialEq, - Eq, - Default, - Constructor, - Deserialize, - Serialize, - Decode, - Encode, - IntoSchema, - )] - #[display( - fmt = "{}--{}", - "start.unwrap_or(0)", - "limit.map_or(\".inf\".to_owned(), |n| n.to_string())" - )] - pub struct Pagination { - /// start of indexing - pub start: Option, - /// limit of indexing - pub limit: Option, - } -} - -/// Error for pagination -#[derive(Debug, Display, Clone, Eq, PartialEq)] -#[display(fmt = "Failed to decode pagination. Error: {_0}")] -pub struct PaginateError(pub core::num::ParseIntError); - -#[cfg(feature = "std")] -impl std::error::Error for PaginateError {} - -impl Reply for PaginateError { - fn into_response(self) -> Response { - reply::with_status(self.to_string(), StatusCode::BAD_REQUEST).into_response() - } -} - -impl From for btree_map::BTreeMap { - fn from(pagination: Pagination) -> Self { - let mut query_params = Self::new(); - if let Some(start) = pagination.start { - query_params.insert(String::from(PAGINATION_START), start.to_string()); - } - if let Some(limit) = pagination.limit { - query_params.insert(String::from(PAGINATION_LIMIT), limit.to_string()); - } - query_params - } -} - -impl From for Vec<(&'static str, usize)> { - fn from(pagination: Pagination) -> Self { - match (pagination.start, pagination.limit) { - (Some(start), Some(limit)) => { - vec![ - ( - PAGINATION_START, - start.try_into().expect("u32 should always fit in usize"), - ), - ( - PAGINATION_LIMIT, - limit.try_into().expect("u32 should always fit in usize"), - ), - ] - } - (Some(start), None) => vec![( - PAGINATION_START, - start.try_into().expect("u32 should always fit in usize"), - )], - (None, Some(limit)) => vec![( - PAGINATION_LIMIT, - limit.try_into().expect("u32 should always fit in usize"), - )], - (None, None) => Vec::new(), - } - } -} - -pub mod prelude { - //! Prelude: re-export most commonly used traits, structs and macros from this module. - pub use super::*; -} diff --git a/data_model/src/predicate.rs b/data_model/src/predicate.rs index 4e7d7d021ab..ff4b5d5764a 100644 --- a/data_model/src/predicate.rs +++ b/data_model/src/predicate.rs @@ -10,7 +10,7 @@ use crate::{IdBox, Name, Value}; mod nontrivial { use super::*; /// Struct representing a sequence with at least three elements. - #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct NonTrivial(Vec); impl NonTrivial { @@ -73,7 +73,7 @@ macro_rules! nontrivial { } /// Predicate combinator enum. -#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] +#[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] // Ideally we would enforce `P: PredicateTrait` here, but I // couldn't find a way to do it without polluting everything // downstream with explicit lifetimes, since we would need to @@ -282,7 +282,7 @@ pub mod string { use super::*; /// Predicate useful for processing [`String`]s and [`Name`]s. - #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum StringPredicate { /// Forward to [`str::contains()`] Contains(String), @@ -559,7 +559,7 @@ pub mod numerical { use super::*; /// A lower-inclusive range predicate. - #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct SemiInterval { /// The start of the range (inclusive) start: T, @@ -583,7 +583,7 @@ pub mod numerical { impl Copy for SemiInterval {} /// A both-inclusive range predicate - #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct Interval { /// The start of the range (inclusive) start: T, @@ -624,7 +624,7 @@ pub mod numerical { /// [`Self`] only applies to `Values` that are variants of /// compatible types. If the [`Range`] variant and the [`Value`] /// variant don't match defaults to `false`. - #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum SemiRange { /// 32-bit U32(SemiInterval), @@ -642,7 +642,7 @@ pub mod numerical { /// [`Self`] only applies to `Values` that are variants of /// compatible types. If the [`Range`] variant and the [`Value`] /// variant don't match defaults to `false`. - #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] + #[derive(Debug, Clone, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum Range { /// 32-bit U32(Interval), @@ -971,7 +971,7 @@ pub mod value { use super::*; /// A predicate designed for general processing of `Value`. - #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum ValuePredicate { /// Apply predicate to the [`Identifiable::Id`] and/or [`IdBox`]. Identifiable(string::StringPredicate), @@ -1107,14 +1107,14 @@ pub mod value { } /// A predicate that targets the particular `index` of a collection. - #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct AtIndex { index: u32, predicate: Box, } /// A predicate that targets the particular `key` of a collection. - #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct ValueOfKey { key: Name, predicate: Box, @@ -1124,7 +1124,7 @@ pub mod value { /// working with containers. Currently only /// [`Metadata`](crate::metadata::Metadata) and [`Vec`] are /// supported. - #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, IntoSchema)] + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum Container { /// Forward to [`Iterator::any`] Any(Box), @@ -1267,7 +1267,9 @@ pub mod ip_addr { /// A Predicate containing independent octuplet masks to be /// applied to all elements of an IP version 4 address. - #[derive(Debug, Clone, Copy, Encode, Decode, IntoSchema, Serialize, Deserialize)] + #[derive( + Debug, Clone, Copy, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema, + )] pub struct Ipv4Predicate([Mask; 4]); impl PredicateTrait for Ipv4Predicate { @@ -1302,7 +1304,9 @@ pub mod ip_addr { /// A Predicate containing independent _hexadecuplets_ (u16 /// groups) masks to be applied to all elements of an IP version 6 /// address. - #[derive(Debug, Clone, Copy, Encode, Decode, IntoSchema, Serialize, Deserialize)] + #[derive( + Debug, Clone, Copy, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema, + )] pub struct Ipv6Predicate([Mask; 8]); impl PredicateTrait for Ipv6Predicate { diff --git a/data_model/src/query/cursor.rs b/data_model/src/query/cursor.rs new file mode 100644 index 00000000000..331adb73701 --- /dev/null +++ b/data_model/src/query/cursor.rs @@ -0,0 +1,57 @@ +//! Structures and traits related to server-side cursor. + +use core::num::{NonZeroU64, NonZeroUsize}; + +use iroha_data_model_derive::model; +use iroha_schema::IntoSchema; +use parity_scale_codec::{Decode, Encode}; +use serde::{Deserialize, Serialize}; + +pub use self::model::*; + +const CURSOR: &str = "cursor"; + +#[model] +pub mod model { + use super::*; + + /// Forward-only (a.k.a non-scrollable) cursor + #[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + Default, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + )] + pub struct ForwardCursor { + pub cursor: Option, + } +} + +impl ForwardCursor { + /// Get cursor position + pub fn get(self) -> Option { + self.cursor + } +} + +impl From for Vec<(&'static str, NonZeroU64)> { + fn from(cursor: ForwardCursor) -> Self { + if let Some(cursor) = cursor.cursor { + return vec![(CURSOR, cursor)]; + } + + Vec::new() + } +} + +pub mod prelude { + //! Prelude: re-export most commonly used traits, structs and macros from this module. + pub use super::*; +} diff --git a/data_model/src/query.rs b/data_model/src/query/mod.rs similarity index 94% rename from data_model/src/query.rs rename to data_model/src/query/mod.rs index bc0f5def759..336620f3aad 100644 --- a/data_model/src/query.rs +++ b/data_model/src/query/mod.rs @@ -6,14 +6,20 @@ use alloc::{boxed::Box, format, string::String, vec::Vec}; use core::cmp::Ordering; +#[cfg(feature = "http")] +pub use cursor::ForwardCursor; use derive_more::Display; -use iroha_crypto::SignatureOf; +use iroha_crypto::{PublicKey, SignatureOf}; use iroha_data_model_derive::model; use iroha_macro::FromVariant; use iroha_schema::IntoSchema; use iroha_version::prelude::*; +#[cfg(feature = "http")] +pub use pagination::Pagination; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; +#[cfg(feature = "http")] +pub use sorting::Sorting; pub use self::model::*; use self::{ @@ -28,6 +34,13 @@ use crate::{ Identifiable, Value, }; +#[cfg(feature = "http")] +pub mod cursor; +#[cfg(feature = "http")] +pub mod pagination; +#[cfg(feature = "http")] +pub mod sorting; + macro_rules! queries { ($($($meta:meta)* $item:item)+) => { pub use self::model::*; @@ -130,24 +143,40 @@ pub mod model { )] #[getset(get = "pub")] #[ffi_type] - pub struct TransactionQueryResult { + pub struct TransactionQueryOutput { /// Transaction pub transaction: TransactionValue, /// The hash of the block to which `tx` belongs to pub block_hash: HashOf, } -} -/// Type returned from [`Metadata`] queries -pub struct MetadataValue(Value); + /// Type returned from [`Metadata`] queries + #[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + )] + #[ffi_type] + pub struct MetadataValue(pub Value); +} impl From for Value { + #[inline] fn from(source: MetadataValue) -> Self { source.0 } } impl From for MetadataValue { + #[inline] fn from(source: Value) -> Self { Self(source) } @@ -157,7 +186,7 @@ impl Query for QueryBox { type Output = Value; } -impl TransactionQueryResult { +impl TransactionQueryOutput { #[inline] /// Return payload of the transaction pub fn payload(&self) -> &TransactionPayload { @@ -165,14 +194,14 @@ impl TransactionQueryResult { } } -impl PartialOrd for TransactionQueryResult { +impl PartialOrd for TransactionQueryOutput { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for TransactionQueryResult { +impl Ord for TransactionQueryOutput { #[inline] fn cmp(&self, other: &Self) -> Ordering { self.payload() @@ -189,6 +218,7 @@ pub mod role { use derive_more::Display; + use super::Query; use crate::prelude::*; queries! { @@ -275,6 +305,7 @@ pub mod permission { use derive_more::Display; + use super::Query; use crate::{ permission::{self, PermissionTokenSchema}, prelude::*, @@ -361,7 +392,7 @@ pub mod account { use derive_more::Display; - use super::MetadataValue; + use super::{MetadataValue, Query}; use crate::prelude::*; queries! { @@ -523,7 +554,7 @@ pub mod asset { use iroha_data_model_derive::model; pub use self::model::*; - use super::MetadataValue; + use super::{MetadataValue, Query}; use crate::prelude::*; queries! { @@ -872,7 +903,7 @@ pub mod domain { use derive_more::Display; - use super::MetadataValue; + use super::{MetadataValue, Query}; use crate::prelude::*; queries! { @@ -1113,7 +1144,7 @@ pub mod transaction { use derive_more::Display; use iroha_crypto::HashOf; - use super::{Query, TransactionQueryResult}; + use super::{Query, TransactionQueryOutput}; use crate::{ account::AccountId, expression::EvaluatesTo, prelude::Account, transaction::VersionedSignedTransaction, @@ -1152,15 +1183,15 @@ pub mod transaction { } impl Query for FindAllTransactions { - type Output = Vec; + type Output = Vec; } impl Query for FindTransactionsByAccountId { - type Output = Vec; + type Output = Vec; } impl Query for FindTransactionByHash { - type Output = TransactionQueryResult; + type Output = TransactionQueryOutput; } impl FindTransactionsByAccountId { @@ -1258,19 +1289,23 @@ pub mod block { pub mod http { //! Structures related to sending queries over HTTP + use getset::Getters; use iroha_data_model_derive::model; pub use self::model::*; use super::*; - use crate::{ - account::AccountId, pagination::prelude::*, predicate::PredicateBox, sorting::prelude::*, - }; + use crate::{account::AccountId, predicate::PredicateBox}; + + // TODO: Could we make a variant of `Value` that holds only query results? + type QueryResult = Value; declare_versioned_with_scale!(VersionedSignedQuery 1..2, Debug, Clone, iroha_macro::FromVariant, IntoSchema); - declare_versioned_with_scale!(VersionedQueryResult 1..2, Debug, Clone, iroha_macro::FromVariant, IntoSchema); + declare_versioned_with_scale!(VersionedQueryResponse 1..2, Debug, Clone, iroha_macro::FromVariant, IntoSchema); #[model] pub mod model { + use core::num::NonZeroU64; + use super::*; /// I/O ready structure to send queries. @@ -1283,15 +1318,17 @@ pub mod http { } /// Payload of a query. - #[derive(Debug, Clone, Decode, Encode, Deserialize, Serialize, IntoSchema)] + #[derive( + Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema, + )] pub(crate) struct QueryPayload { /// Timestamp of the query creation. #[codec(compact)] pub timestamp_ms: u128, - /// Query definition. - pub query: QueryBox, /// Account id of the user who will sign this query. pub authority: AccountId, + /// Query definition. + pub query: QueryBox, /// The filter applied to the result on the server-side. pub filter: PredicateBox, } @@ -1300,10 +1337,23 @@ pub mod http { #[derive(Debug, Clone, Encode, Serialize, IntoSchema)] #[version_with_scale(n = 1, versioned = "VersionedSignedQuery")] pub struct SignedQuery { - /// Payload - pub payload: QueryPayload, /// Signature of the client who sends this query. pub signature: SignatureOf, + /// Payload + pub payload: QueryPayload, + } + + /// [`SignedQuery`] response + #[derive(Debug, Clone, Getters, Decode, Encode, Deserialize, Serialize, IntoSchema)] + #[version_with_scale(n = 1, versioned = "VersionedQueryResponse")] + #[getset(get = "pub")] + pub struct QueryResponse { + /// The result of the query execution. + #[getset(skip)] + pub result: QueryResult, + /// Index of the next element in the result set. Client will use this value + /// in the next request to continue fetching results of the original query + pub cursor: cursor::ForwardCursor, } } @@ -1314,8 +1364,8 @@ pub mod http { #[derive(Decode, Deserialize)] struct SignedQueryCandidate { - payload: QueryPayload, signature: SignatureOf, + payload: QueryPayload, } impl SignedQueryCandidate { @@ -1331,6 +1381,7 @@ pub mod http { }) } } + impl Decode for SignedQuery { fn decode(input: &mut I) -> Result { SignedQueryCandidate::decode(input)? @@ -1338,6 +1389,7 @@ pub mod http { .map_err(Into::into) } } + impl<'de> Deserialize<'de> for SignedQuery { fn deserialize(deserializer: D) -> Result where @@ -1376,19 +1428,6 @@ pub mod http { } } - /// Paginated Query Result - // TODO: This is the only structure whose inner fields are exposed. Wrap it in model macro? - #[derive(Debug, Clone, Decode, Encode, Deserialize, Serialize, IntoSchema)] - #[version_with_scale(n = 1, versioned = "VersionedQueryResult")] - pub struct QueryResult { - /// The result of the query execution. - pub result: Value, - /// pagination - pub pagination: Pagination, - /// sorting - pub sorting: Sorting, - } - impl QueryBuilder { /// Construct a new request with the `query`. pub fn new(query: impl Into, authority: AccountId) -> Self { @@ -1419,11 +1458,20 @@ pub mod http { pub fn sign( self, key_pair: iroha_crypto::KeyPair, - ) -> Result { - SignatureOf::new(key_pair, &self.payload).map(|signature| SignedQuery { - payload: self.payload, - signature, - }) + ) -> Result { + SignatureOf::new(key_pair, &self.payload) + .map(|signature| SignedQuery { + payload: self.payload, + signature, + }) + .map(Into::into) + } + } + + impl From for Value { + #[inline] + fn from(source: QueryResponse) -> Self { + source.result } } @@ -1431,7 +1479,7 @@ pub mod http { //! The prelude re-exports most commonly used traits, structs and macros from this crate. pub use super::{ - QueryBuilder, QueryResult, SignedQuery, VersionedQueryResult, VersionedSignedQuery, + QueryBuilder, QueryResponse, SignedQuery, VersionedQueryResponse, VersionedSignedQuery, }; } } @@ -1553,6 +1601,6 @@ pub mod prelude { pub use super::{ account::prelude::*, asset::prelude::*, block::prelude::*, domain::prelude::*, peer::prelude::*, permission::prelude::*, role::prelude::*, transaction::*, - trigger::prelude::*, Query, QueryBox, TransactionQueryResult, + trigger::prelude::*, QueryBox, TransactionQueryOutput, }; } diff --git a/data_model/src/query/pagination.rs b/data_model/src/query/pagination.rs new file mode 100644 index 00000000000..71a12d95f8c --- /dev/null +++ b/data_model/src/query/pagination.rs @@ -0,0 +1,60 @@ +//! Structures and traits related to pagination. + +#[cfg(not(feature = "std"))] +use alloc::{ + borrow::ToOwned as _, + collections::btree_map, + format, + string::{String, ToString as _}, + vec, + vec::Vec, +}; +use core::num::{NonZeroU32, NonZeroU64, NonZeroUsize}; +#[cfg(feature = "std")] +use std::collections::btree_map; + +use derive_more::{Constructor, Display}; +use iroha_data_model_derive::model; +use parity_scale_codec::{Decode, Encode}; +use serde::{Deserialize, Serialize}; +use warp::{ + http::StatusCode, + reply::{self, Response}, + Reply, +}; + +const PAGINATION_START: &str = "start"; +const PAGINATION_LIMIT: &str = "limit"; + +/// Structure for pagination requests +#[derive(Debug, Display, Clone, Copy, Default, Decode, Encode, Deserialize, Serialize)] +#[display( + fmt = "{}--{}", + "start.map(NonZeroU64::get).unwrap_or(0)", + "limit.map_or(\".inf\".to_owned(), |n| n.to_string())" +)] +pub struct Pagination { + /// limit of indexing + pub limit: Option, + /// start of indexing + // TODO: Rename to offset + pub start: Option, +} + +impl From for Vec<(&'static str, NonZeroU64)> { + fn from(pagination: Pagination) -> Self { + match (pagination.start, pagination.limit) { + (Some(start), Some(limit)) => { + vec![(PAGINATION_LIMIT, limit.into()), (PAGINATION_START, start)] + } + (Some(start), None) => vec![(PAGINATION_START, start)], + (None, Some(limit)) => vec![(PAGINATION_LIMIT, limit.into())], + (None, None) => Vec::new(), + } + } +} + +pub mod prelude { + //! Prelude: re-export most commonly used traits, structs and macros from this module. + pub use super::*; +} diff --git a/data_model/src/sorting.rs b/data_model/src/query/sorting.rs similarity index 77% rename from data_model/src/sorting.rs rename to data_model/src/query/sorting.rs index 0ceac5a86e2..9ccbc83c610 100644 --- a/data_model/src/sorting.rs +++ b/data_model/src/query/sorting.rs @@ -8,12 +8,11 @@ use alloc::{ }; use iroha_data_model_derive::model; -use iroha_schema::IntoSchema; -use iroha_version::{Decode, Encode}; +use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; pub use self::model::*; -use crate::prelude::*; +use crate::{name::Name, prelude::*}; const SORT_BY_KEY: &str = "sort_by_metadata_key"; @@ -21,8 +20,8 @@ const SORT_BY_KEY: &str = "sort_by_metadata_key"; pub mod model { use super::*; - /// Enum for sorting requests - #[derive(Debug, Clone, Default, Decode, Encode, Deserialize, Serialize, IntoSchema)] + /// Struct for sorting requests + #[derive(Debug, Clone, Default, Decode, Encode, Deserialize, Serialize)] pub struct Sorting { /// Sort query result using [`Name`] of the key in [`Asset`]'s metadata. pub sort_by_metadata_key: Option, @@ -38,13 +37,13 @@ impl Sorting { } } -impl From for Vec<(&'static str, String)> { +impl From for Vec<(&'static str, Name)> { fn from(sorting: Sorting) -> Self { - let mut vec = Vec::new(); if let Some(key) = sorting.sort_by_metadata_key { - vec.push((SORT_BY_KEY, key.to_string())); + return vec![(SORT_BY_KEY, key)]; } - vec + + Vec::new() } } diff --git a/data_model/src/transaction.rs b/data_model/src/transaction.rs index 482051477e5..43551f1b44f 100644 --- a/data_model/src/transaction.rs +++ b/data_model/src/transaction.rs @@ -102,20 +102,20 @@ pub mod model { #[getset(get = "pub")] #[ffi_type] pub struct TransactionPayload { - /// Account ID of transaction creator. - pub authority: AccountId, /// Creation timestamp (unix time in milliseconds). #[getset(skip)] pub creation_time_ms: u64, + /// Account ID of transaction creator. + pub authority: AccountId, + /// ISI or a `WebAssembly` smartcontract. + pub instructions: Executable, + /// If transaction is not committed by this time it will be dropped. + #[getset(skip)] + pub time_to_live_ms: Option, /// Random value to make different hashes for transactions which occur repeatedly and simultaneously. // TODO: Only temporary #[getset(skip)] pub nonce: Option, - /// If transaction is not committed by this time it will be dropped. - #[getset(skip)] - pub time_to_live_ms: Option, - /// ISI or a `WebAssembly` smartcontract. - pub instructions: Executable, /// Store for additional information. #[getset(skip)] pub metadata: UnlimitedMetadata, @@ -163,10 +163,10 @@ pub mod model { #[ffi_type] // TODO: All fields in this struct should be private pub struct SignedTransaction { - /// [`Transaction`] payload. - pub payload: TransactionPayload, /// [`iroha_crypto::SignatureOf`]<[`TransactionPayload`]>. pub signatures: SignaturesOf, + /// [`Transaction`] payload. + pub payload: TransactionPayload, } /// Transaction Value used in Instructions and Queries @@ -374,8 +374,8 @@ mod candidate { #[derive(Decode, Deserialize)] struct SignedTransactionCandidate { - payload: TransactionPayload, signatures: SignaturesOf, + payload: TransactionPayload, } impl SignedTransactionCandidate { diff --git a/data_model/src/visit.rs b/data_model/src/visit.rs index f07bbb58a89..c56bd363575 100644 --- a/data_model/src/visit.rs +++ b/data_model/src/visit.rs @@ -4,6 +4,8 @@ #[cfg(not(feature = "std"))] use alloc::format; +use iroha_crypto::PublicKey; + use crate::{evaluate::ExpressionEvaluator, prelude::*, NumericValue}; macro_rules! delegate { diff --git a/docs/source/references/config.md b/docs/source/references/config.md index 4b781ccfbde..463433b3a81 100644 --- a/docs/source/references/config.md +++ b/docs/source/references/config.md @@ -56,7 +56,9 @@ The following is the default configuration used by Iroha. "API_URL": null, "TELEMETRY_URL": null, "MAX_TRANSACTION_SIZE": 32768, - "MAX_CONTENT_LEN": 16384000 + "MAX_CONTENT_LEN": 16384000, + "FETCH_SIZE": 10, + "QUERY_IDLE_TIME_MS": 30000 }, "BLOCK_SYNC": { "GOSSIP_PERIOD_MS": 10000, @@ -624,9 +626,11 @@ Has type `Option`[^1]. Can be configured via environm ```json { "API_URL": null, + "FETCH_SIZE": 10, "MAX_CONTENT_LEN": 16384000, "MAX_TRANSACTION_SIZE": 32768, "P2P_ADDR": null, + "QUERY_IDLE_TIME_MS": 30000, "TELEMETRY_URL": null } ``` @@ -641,6 +645,16 @@ Has type `Option`[^1]. Can be configured via environment variable `T null ``` +### `torii.fetch_size` + +How many query results are returned in one batch + +Has type `Option`[^1]. Can be configured via environment variable `TORII_FETCH_SIZE` + +```json +10 +``` + ### `torii.max_content_len` Maximum number of bytes in raw message. Used to prevent from DOS attacks. @@ -671,6 +685,16 @@ Has type `Option`[^1]. Can be configured via environment variable `T null ``` +### `torii.query_idle_time_ms` + +Time query can remain in the store if unaccessed + +Has type `Option`[^1]. Can be configured via environment variable `TORII_QUERY_IDLE_TIME_MS` + +```json +30000 +``` + ### `torii.telemetry_url` Torii address for reporting internal status and metrics for administration. diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index d72a618b326..e94899ac8d4 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -2070,6 +2070,14 @@ "decimal_places": 9 } }, + "ForwardCursor": { + "Struct": [ + { + "name": "cursor", + "type": "Option>" + } + ] + }, "GenericPredicateBox": { "Enum": [ { @@ -2996,9 +3004,6 @@ "Option": { "Option": "IpfsPath" }, - "Option": { - "Option": "Name" - }, "Option>": { "Option": "NonZero" }, @@ -3017,9 +3022,6 @@ "Option": { "Option": "TransactionRejectionReason" }, - "Option": { - "Option": "u32" - }, "Or": { "Struct": [ { @@ -3039,18 +3041,6 @@ "OriginFilter": "PeerId", "OriginFilter": "RoleId", "OriginFilter": "TriggerId", - "Pagination": { - "Struct": [ - { - "name": "start", - "type": "Option" - }, - { - "name": "limit", - "type": "Option" - } - ] - }, "Pair": { "Struct": [ { @@ -3540,33 +3530,29 @@ "name": "timestamp_ms", "type": "Compact" }, - { - "name": "query", - "type": "QueryBox" - }, { "name": "authority", "type": "AccountId" }, + { + "name": "query", + "type": "QueryBox" + }, { "name": "filter", "type": "GenericPredicateBox" } ] }, - "QueryResult": { + "QueryResponse": { "Struct": [ { "name": "result", "type": "Value" }, { - "name": "pagination", - "type": "Pagination" - }, - { - "name": "sorting", - "type": "Sorting" + "name": "cursor", + "type": "ForwardCursor" } ] }, @@ -3890,25 +3876,25 @@ }, "SignedQuery": { "Struct": [ - { - "name": "payload", - "type": "QueryPayload" - }, { "name": "signature", "type": "SignatureOf" + }, + { + "name": "payload", + "type": "QueryPayload" } ] }, "SignedTransaction": { "Struct": [ - { - "name": "payload", - "type": "TransactionPayload" - }, { "name": "signatures", "type": "SignaturesOf" + }, + { + "name": "payload", + "type": "TransactionPayload" } ] }, @@ -4030,14 +4016,6 @@ "SortedVec>": { "Vec": "SignatureOf" }, - "Sorting": { - "Struct": [ - { - "name": "sort_by_metadata_key", - "type": "Option" - } - ] - }, "String": "String", "StringPredicate": { "Enum": [ @@ -4122,25 +4100,25 @@ }, "TransactionPayload": { "Struct": [ - { - "name": "authority", - "type": "AccountId" - }, { "name": "creation_time_ms", "type": "u64" }, { - "name": "nonce", - "type": "Option>" + "name": "authority", + "type": "AccountId" + }, + { + "name": "instructions", + "type": "Executable" }, { "name": "time_to_live_ms", "type": "Option>" }, { - "name": "instructions", - "type": "Executable" + "name": "nonce", + "type": "Option>" }, { "name": "metadata", @@ -4148,7 +4126,7 @@ } ] }, - "TransactionQueryResult": { + "TransactionQueryOutput": { "Struct": [ { "name": "transaction", @@ -4200,7 +4178,7 @@ "TransactionValue": { "Struct": [ { - "name": "tx", + "name": "value", "type": "VersionedSignedTransaction" }, { @@ -4507,9 +4485,9 @@ "type": "SignatureCheckCondition" }, { - "tag": "TransactionQueryResult", + "tag": "TransactionQueryOutput", "discriminant": 12, - "type": "TransactionQueryResult" + "type": "TransactionQueryOutput" }, { "tag": "PermissionToken", @@ -4685,12 +4663,12 @@ } ] }, - "VersionedQueryResult": { + "VersionedQueryResponse": { "Enum": [ { "tag": "V1", "discriminant": 1, - "type": "QueryResult" + "type": "QueryResponse" } ] }, diff --git a/lints.toml b/lints.toml index 6548fba5b6a..b36eb51c845 100644 --- a/lints.toml +++ b/lints.toml @@ -59,16 +59,8 @@ allow = [ 'clippy::let_underscore_must_use', 'clippy::match_wildcard_for_single_variants', 'clippy::missing_docs_in_private_items', - # Not all public items should be inline. We only inline **trivial** functions. - 'clippy::missing_inline_in_public_items', 'clippy::module_name_repetitions', - 'clippy::must_use_candidate', 'clippy::pattern_type_mismatch', - 'clippy::semicolon_if_nothing_returned', - 'clippy::non-ascii-literal', - 'clippy::wildcard_enum_match_arm', - 'clippy::wildcard_imports', - 'clippy::pub_use', 'clippy::shadow_reuse', 'clippy::shadow_same', @@ -76,14 +68,11 @@ allow = [ 'clippy::unwrap_in_result', 'clippy::expect_used', 'clippy::unreachable', - 'clippy::use_self', 'clippy::wildcard_enum_match_arm', 'clippy::wildcard_imports', - 'elided_lifetimes_in_paths', # Our preferred style. 'clippy::non-ascii-literal', 'clippy::std_instead_of_core', - 'clippy::uninlined_format_args', # This lint could be useful in theory. The trade-off of making # refactoring away from references difficult isn't worth it in all diff --git a/macro/derive/src/lib.rs b/macro/derive/src/lib.rs index 54f548203b1..acc2406b009 100644 --- a/macro/derive/src/lib.rs +++ b/macro/derive/src/lib.rs @@ -176,9 +176,9 @@ fn try_into_variant( quote! { impl #impl_generics TryFrom<#enum_ty #ty_generics> for #variant_ty #where_clause { - type Error = iroha_macro::error::ErrorTryFromEnum<#enum_ty, Self>; + type Error = iroha_macro::error::ErrorTryFromEnum<#enum_ty #ty_generics, Self>; - fn try_from(origin: #enum_ty) -> core::result::Result { + fn try_from(origin: #enum_ty #ty_generics) -> core::result::Result { if let #enum_ty :: #variant(variant) = origin { Ok(variant) } else { diff --git a/macro/utils/src/lib.rs b/macro/utils/src/lib.rs index 6cf0d0eda78..9fdfd48e247 100644 --- a/macro/utils/src/lib.rs +++ b/macro/utils/src/lib.rs @@ -1,9 +1,7 @@ //! Module for various functions and structs to build macros in iroha. -use syn::parse::Parse; - /// Trait for attribute parsing generalization -pub trait AttrParser { +pub trait AttrParser { /// Attribute identifier `#[IDENT...]` const IDENT: &'static str; diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index 09cb96b6e0d..79014f1223b 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -47,7 +47,7 @@ pub fn build_schemas() -> MetaMap { VersionedBlockSubscriptionRequest, VersionedEventMessage, VersionedEventSubscriptionRequest, - VersionedQueryResult, + VersionedQueryResponse, VersionedSignedQuery, // Never referenced, but present in type signature. Like `PhantomData` @@ -281,8 +281,7 @@ types!( OriginFilter, OriginFilter, OriginFilter, - QueryResult, - Pagination, + QueryResponse, Pair, Parameter, ParameterId, @@ -335,7 +334,6 @@ types!( SignaturesOf, SignedQuery, SignedTransaction, - Sorting, String, StringPredicate, Subtract, @@ -346,7 +344,7 @@ types!( TransactionLimitError, TransactionLimits, TransactionPayload, - TransactionQueryResult, + TransactionQueryOutput, TransactionRejectionReason, TransactionValue, TransferBox, @@ -375,7 +373,7 @@ types!( VersionedCommittedBlockWrapper, VersionedEventMessage, VersionedEventSubscriptionRequest, - VersionedQueryResult, + VersionedQueryResponse, VersionedSignedQuery, VersionedSignedTransaction, WasmExecutionFail, diff --git a/version/derive/src/lib.rs b/version/derive/src/lib.rs index eacafabf91f..91d7867260b 100644 --- a/version/derive/src/lib.rs +++ b/version/derive/src/lib.rs @@ -112,13 +112,18 @@ pub fn declare_versioned_with_json(input: TokenStream) -> TokenStream { } fn impl_version(args: Vec, item: TokenStream) -> TokenStream2 { - let (item, struct_name) = if let Ok(item_struct) = syn::parse::(item.clone()) { - (quote!(#item_struct), item_struct.ident) - } else if let Ok(item_enum) = syn::parse::(item) { - (quote!(#item_enum), item_enum.ident) - } else { - abort_call_site!("The attribute should be attached to either struct or enum."); - }; + let (item, struct_name, generics) = + if let Ok(item_struct) = syn::parse::(item.clone()) { + ( + quote!(#item_struct), + item_struct.ident, + item_struct.generics, + ) + } else if let Ok(item_enum) = syn::parse::(item) { + (quote!(#item_enum), item_enum.ident, item_enum.generics) + } else { + abort_call_site!("The attribute should be attached to either struct or enum."); + }; let args_map: FxHashMap<_, _> = args .into_iter() .filter_map(|meta| { @@ -173,10 +178,12 @@ fn impl_version(args: Vec, item: TokenStream) -> TokenStream2 { ) }; let alias_type_name = format_ident!("_{}V{}", versioned_struct_name, version_number); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + quote!( /// Autogenerated alias type to link versioned item to its container. #[allow(clippy::redundant_pub_crate)] - pub(crate) type #alias_type_name = #struct_name; + pub(crate) type #alias_type_name #impl_generics = #struct_name #ty_generics #where_clause; #item ) @@ -236,10 +243,24 @@ impl Parse for DeclareVersionedArgs { } fn impl_decode_versioned(enum_name: &Ident, generics: &syn::Generics) -> proc_macro2::TokenStream { - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let mut decode_where_clause = generics + .where_clause + .clone() + .unwrap_or_else(|| syn::parse_quote!(where)); + decode_where_clause + .predicates + .push(syn::parse_quote!(Self: parity_scale_codec::DecodeAll)); + let mut encode_where_clause = generics + .where_clause + .clone() + .unwrap_or_else(|| syn::parse_quote!(where)); + encode_where_clause + .predicates + .push(syn::parse_quote!(Self: parity_scale_codec::Encode)); + let (impl_generics, ty_generics, _) = generics.split_for_impl(); quote! ( - impl #impl_generics iroha_version::scale::DecodeVersioned for #enum_name #ty_generics #where_clause { + impl #impl_generics iroha_version::scale::DecodeVersioned for #enum_name #ty_generics #decode_where_clause { fn decode_all_versioned(input: &[u8]) -> iroha_version::error::Result { use iroha_version::{error::Error, Version, UnsupportedVersion, RawVersioned}; use parity_scale_codec::DecodeAll; @@ -260,7 +281,7 @@ fn impl_decode_versioned(enum_name: &Ident, generics: &syn::Generics) -> proc_ma } } - impl #impl_generics iroha_version::scale::EncodeVersioned for #enum_name #ty_generics #where_clause { + impl #impl_generics iroha_version::scale::EncodeVersioned for #enum_name #ty_generics #encode_where_clause { fn encode_versioned(&self) -> Vec { use parity_scale_codec::Encode; diff --git a/version/src/lib.rs b/version/src/lib.rs index 8299e01a9e9..841197968f8 100644 --- a/version/src/lib.rs +++ b/version/src/lib.rs @@ -197,12 +197,12 @@ pub mod scale { #[cfg(not(feature = "std"))] use alloc::vec::Vec; - use parity_scale_codec::{Decode, Encode}; + use parity_scale_codec::{DecodeAll, Encode}; use super::{error::Result, Version}; /// [`Decode`] versioned analog. - pub trait DecodeVersioned: Decode + Version { + pub trait DecodeVersioned: DecodeAll + Version { /// Use this function for versioned objects instead of `decode_all`. /// /// # Errors diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 90cd38f8a7d..bff69aa365d 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -14,7 +14,12 @@ extern crate alloc; use alloc::{boxed::Box, collections::BTreeMap, format, vec::Vec}; use core::ops::RangeFrom; -use data_model::{isi::Instruction, prelude::*, query::QueryBox, validator::NeedsValidationBox}; +use data_model::{ + isi::Instruction, + prelude::*, + query::{Query, QueryBox}, + validator::NeedsValidationBox, +}; use debug::DebugExpectExt as _; pub use iroha_data_model as data_model; pub use iroha_wasm_derive::main; diff --git a/wasm/validator/derive/src/validate.rs b/wasm/validator/derive/src/validate.rs index 72e37caa27a..68caa131486 100644 --- a/wasm/validator/derive/src/validate.rs +++ b/wasm/validator/derive/src/validate.rs @@ -58,7 +58,9 @@ impl ValidateAttribute { continue; } - let Some(proc_macro2::TokenTree::Group(group))= attribute.tokens.clone().into_iter().next() else { + let Some(proc_macro2::TokenTree::Group(group)) = + attribute.tokens.clone().into_iter().next() + else { panic!("Expected parentheses group"); }; assert!(