From ee15afe5c91cfa0dfb75015c8369ce122cf20999 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 21 Mar 2023 15:34:27 -0700 Subject: [PATCH 01/30] Update tempfile (#413) --- Cargo.lock | 104 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 88 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81de3978..9302015a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,7 +86,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -564,6 +564,27 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "fastrand" version = "1.8.0" @@ -764,6 +785,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" @@ -1050,6 +1077,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-lifetimes" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "ipnet" version = "2.5.0" @@ -1152,6 +1190,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "lock_api" version = "0.4.9" @@ -1317,7 +1361,7 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", ] @@ -1746,15 +1790,6 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "reqwest" version = "0.11.12" @@ -1830,6 +1865,20 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "rustix" +version = "0.36.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + [[package]] name = "rustls" version = "0.20.6" @@ -2183,16 +2232,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" dependencies = [ "cfg-if", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys 0.42.0", ] [[package]] @@ -2660,6 +2708,30 @@ dependencies = [ "windows_x86_64_msvc 0.42.1", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.1" From 3992f6e34de47b55d27b775ba4146e086eb36662 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Fri, 24 Mar 2023 16:58:00 -0700 Subject: [PATCH 02/30] feat: wasm-bindgen support (#414) This PR makes ic-agent and ic-utils available in the browser through wasm-bindgen. Fixes #360. --- .github/workflows/lint.yml | 3 + .github/workflows/test.yml | 11 + CHANGELOG.md | 2 + Cargo.lock | 925 ++++++++++-------- ic-agent/Cargo.toml | 41 +- ic-agent/http_mock_service_worker.js | 75 ++ ic-agent/src/agent/agent_test.rs | 458 +++++---- .../agent/http_transport/reqwest_transport.rs | 16 +- ic-agent/src/agent/mod.rs | 46 +- ic-agent/src/lib.rs | 3 + ic-utils/Cargo.toml | 3 + ic-utils/src/call.rs | 18 +- .../management_canister/builders.rs | 9 +- ic-utils/src/interfaces/wallet.rs | 3 +- icx-cert/src/pprint.rs | 11 +- 15 files changed, 1007 insertions(+), 617 deletions(-) create mode 100644 ic-agent/http_mock_service_worker.js diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0b15ba09..59ed332c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,10 +27,13 @@ jobs: rustup update ${{ matrix.rust }} --no-self-update rustup component add clippy rustup default ${{ matrix.rust }} + rustup target add wasm32-unknown-unknown - name: Run Lint run: cargo clippy --verbose --tests --benches -- -D clippy::all env: RUST_BACKTRACE: 1 + - name: Run Lint (WASM) + run: CARGO_TARGET_DIR=target/wasm cargo clippy --target wasm32-unknown-unknown -p ic-agent -p ic-utils --verbose -- -D clippy::all aggregate: name: lint:required runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 46edd60e..df380b29 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,6 +29,12 @@ jobs: run: | rustup update ${{ matrix.rust }} --no-self-update rustup default ${{ matrix.rust }} + rustup target add wasm32-unknown-unknown + + - name: Install wasm-pack + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Run Tests shell: bash @@ -42,6 +48,11 @@ jobs: done env: RUST_BACKTRACE: 1 + + - name: Run Tests (WASM) + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + CARGO_TARGET_DIR=../target/wasm wasm-pack test --chrome --headless ic-agent - name: Purge for OSX if: matrix.os == 'macos-latest' diff --git a/CHANGELOG.md b/CHANGELOG.md index 6250ef58..141a8446 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +* Support WASM targets in the browser via `wasm-bindgen` + ## [0.23.2] - 2023-04-21 * Expose the root key to clients through `read_root_key` diff --git a/Cargo.lock b/Cargo.lock index 9302015a..38b18297 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.17.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ "gimli", ] @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "0.7.19" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -37,9 +37,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.65" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" dependencies = [ "backtrace", ] @@ -71,13 +71,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.57" +version = "0.1.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" +checksum = "86ea188f25f0255d8f92797797c97ebf5631fa88178beb1a46fdf5622c9a00e4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.6", ] [[package]] @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" dependencies = [ "addr2line", "cc", @@ -137,15 +137,21 @@ checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "base64ct" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2b2456fd614d856680dcd9fcc660a51a820fa09daef2e49772b56a193c8474" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beef" @@ -173,7 +179,7 @@ dependencies = [ "either", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -208,18 +214,18 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "bls12_381" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62250ece575fa9b22068b3a8d59586f01d426dd7785522efd97632959e71c986" +checksum = "a3c196a77437e7cc2fb515ce413a6401291578b5afc8ecb29a3c7ab957f05941" dependencies = [ "digest 0.9.0", "ff", @@ -243,15 +249,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.2.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "candid" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e72fa59e129f61105902051ab41bfd81118d2cce90d0054d2dee353492a3f9" +checksum = "244005a1917bb7614cd775ca8a5d59efeb5ac74397bb14ba29a19347ebd78591" dependencies = [ "anyhow", "binread", @@ -285,14 +291,14 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "cc" -version = "1.0.73" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -302,24 +308,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.22" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ "iana-time-zone", "js-sys", "num-integer", "num-traits", - "time 0.1.44", + "time 0.1.45", "wasm-bindgen", "winapi", ] [[package]] name = "clap" -version = "3.2.22" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", "bitflags", @@ -342,7 +348,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -375,11 +381,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "const-oid" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "722e23542a15cea1f65d4a1419c4cfd7a26706c70871a13a04238ca3f40f1661" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "core-foundation" @@ -423,9 +439,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2b443d17d49dad5ef0ede301c3179cc923b8822f3393b4d2c28c269dd4a122" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array", "rand_core", @@ -443,17 +459,61 @@ dependencies = [ "typenum", ] +[[package]] +name = "cxx" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c00419335c41018365ddf7e4d5f1c12ee3659ddcf3e01974650ba1de73d038" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8307ad413a98fff033c8545ecf133e3257747b3bae935e7602aab8aa92d4ca" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.6", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc52e2eb08915cb12596d29d55f0b5384f00d697a646dbd269b6ecb0fbd9d31" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.6", +] + [[package]] name = "data-encoding" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" [[package]] name = "der" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ "const-oid", "pem-rfc7468", @@ -477,11 +537,11 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer 0.10.3", + "block-buffer 0.10.4", "crypto-common", "subtle", ] @@ -521,9 +581,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" @@ -534,7 +594,7 @@ dependencies = [ "base16ct", "crypto-bigint", "der", - "digest 0.10.5", + "digest 0.10.6", "ff", "generic-array", "group", @@ -548,18 +608,18 @@ dependencies = [ [[package]] name = "ena" -version = "0.14.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" dependencies = [ "log", ] [[package]] name = "encoding_rs" -version = "0.8.31" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if", ] @@ -587,18 +647,18 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] [[package]] name = "ff" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df689201f395c6b90dfe87127685f8dbfc083a5e779e613575d8bd7314300c3e" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ "rand_core", "subtle", @@ -640,59 +700,88 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" -version = "0.3.24" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" +checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" dependencies = [ "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.24" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" + +[[package]] +name = "futures-executor" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" +checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] [[package]] name = "futures-io" -version = "0.3.24" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" +checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" [[package]] name = "futures-macro" -version = "0.3.24" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" +checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "futures-sink" -version = "0.3.24" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" +checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" [[package]] name = "futures-task" -version = "0.3.24" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" +checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" [[package]] name = "futures-util" -version = "0.3.24" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" +checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", + "futures-sink", "futures-task", "memchr", "pin-project-lite", @@ -712,28 +801,29 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.26.2" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "group" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7391856def869c1c81063a03457c676fbcd419709c3dfb33d8d319de484b154d" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "byteorder", "ff", "rand_core", "subtle", @@ -741,9 +831,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.14" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" +checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" dependencies = [ "bytes", "fnv", @@ -772,9 +862,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -785,6 +875,15 @@ dependencies = [ "libc", ] +[[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" @@ -803,14 +902,14 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.5", + "digest 0.10.6", ] [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -848,9 +947,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.20" +version = "0.14.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" dependencies = [ "bytes", "futures-channel", @@ -872,9 +971,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", @@ -901,15 +1000,26 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.50" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd911b35d940d2bd0bea0f9100068e5b97b51a1cbe13d13382f132e0365257a0" +checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" dependencies = [ "android_system_properties", "core-foundation-sys", + "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", ] [[package]] @@ -919,10 +1029,11 @@ dependencies = [ "async-trait", "backoff", "base32", - "base64", + "base64 0.13.1", "byteorder", "candid", "futures-util", + "getrandom", "hex", "http", "http-body", @@ -930,13 +1041,13 @@ dependencies = [ "hyper-rustls", "ic-certification", "ic-verify-bls-signature", + "js-sys", "k256", "leb128", "mime", "mockito", "pem", "pkcs8", - "proptest", "rand", "reqwest", "ring", @@ -949,8 +1060,13 @@ dependencies = [ "sha2 0.10.6", "simple_asn1", "thiserror", + "time 0.3.20", "tokio", "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test", + "web-sys", ] [[package]] @@ -1034,7 +1150,7 @@ name = "icx-cert" version = "0.23.2" dependencies = [ "anyhow", - "base64", + "base64 0.13.1", "chrono", "clap", "hex", @@ -1060,9 +1176,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", @@ -1075,6 +1191,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -1090,9 +1209,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "itertools" @@ -1105,15 +1224,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -1176,9 +1295,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.134" +version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" [[package]] name = "libloading" @@ -1190,6 +1309,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -1235,7 +1363,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax", - "syn", + "syn 1.0.109", ] [[package]] @@ -1246,40 +1374,41 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.5.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.36.1", + "windows-sys 0.45.0", ] [[package]] name = "mockito" -version = "0.31.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "401edc088069634afaa5f4a29617b36dba683c0c16fe4435a86debad23fa2f1a" +checksum = "8c1eecc3baf782e3c8d6803cc8780268da1f32df6eb88c016c1d80b0df7944cf" dependencies = [ "assert-json-diff", "colored", - "httparse", + "futures", + "hyper", "lazy_static", "log", "rand", @@ -1287,13 +1416,14 @@ dependencies = [ "serde_json", "serde_urlencoded", "similar", + "tokio", ] [[package]] name = "native-tls" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" dependencies = [ "lazy_static", "libc", @@ -1357,58 +1487,49 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi 0.2.6", "libc", ] [[package]] name = "num_enum" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", + "syn 1.0.109", ] [[package]] name = "object" -version = "0.29.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.15.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "opaque-debug" @@ -1418,9 +1539,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.42" +version = "0.10.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" +checksum = "d8b277f87dacc05a6b709965d1cbafac4649d6ce9f3ce9ceb88508b5666dfec9" dependencies = [ "bitflags", "cfg-if", @@ -1439,7 +1560,7 @@ checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1450,9 +1571,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.76" +version = "0.9.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5230151e44c0f05157effb743e8d517472843121cf9243e8b81393edb5acd9ce" +checksum = "a95792af3c4e0153c3914df2261bedd30a98476f94dc892b67dfe1d89d433a04" dependencies = [ "autocfg", "cc", @@ -1463,9 +1584,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.3.0" +version = "6.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" [[package]] name = "pairing" @@ -1488,30 +1609,30 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.36.1", + "windows-sys 0.45.0", ] [[package]] name = "paste" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "pem" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ - "base64", + "base64 0.13.1", ] [[package]] @@ -1531,9 +1652,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "petgraph" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", "indexmap", @@ -1588,15 +1709,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "precomputed-hash" @@ -1616,13 +1737,12 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "thiserror", - "toml", + "toml_edit", ] [[package]] @@ -1634,7 +1754,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -1651,50 +1771,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.46" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" dependencies = [ "unicode-ident", ] -[[package]] -name = "proptest" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5" -dependencies = [ - "bit-set", - "bitflags", - "byteorder", - "lazy_static", - "num-traits", - "quick-error 2.0.1", - "rand", - "rand_chacha", - "rand_xorshift", - "regex-syntax", - "rusty-fork", - "tempfile", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - [[package]] name = "quote" -version = "1.0.21" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -1729,15 +1817,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] - [[package]] name = "redox_syscall" version = "0.2.16" @@ -1775,9 +1854,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c" dependencies = [ "aho-corasick", "memchr", @@ -1786,17 +1865,17 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "reqwest" -version = "0.11.12" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" +checksum = "0ba30cc2c0cd02af1222ed216ba659cdb2f879dfe3181852fe7c50b1d0005949" dependencies = [ - "base64", + "base64 0.21.0", "bytes", "encoding_rs", "futures-core", @@ -1828,6 +1907,7 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots", "winreg", @@ -1835,9 +1915,9 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c86280f057430a52f4861551b092a01b419b8eacefc7c995eacb9dc132fe32" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ "crypto-bigint", "hmac", @@ -1881,9 +1961,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.6" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -1905,53 +1985,52 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64", + "base64 0.21.0", ] [[package]] name = "rustversion" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" - -[[package]] -name = "rusty-fork" -version = "0.3.0" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" -dependencies = [ - "fnv", - "quick-error 1.2.3", - "tempfile", - "wait-timeout", -] +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "schannel" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" + [[package]] name = "sct" version = "0.7.0" @@ -1978,9 +2057,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags", "core-foundation", @@ -1991,9 +2070,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys", "libc", @@ -2001,15 +2080,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.154" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cdd151213925e7f1ab45a9bbfb129316bd00799784b174b7cc7bcd16961c49e" +checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" dependencies = [ "serde_derive", ] @@ -2035,20 +2114,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.154" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc80d722935453bcafdc2c9a73cd6fac4dc1938f0346035d84bf99fa9e33217" +checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.6", ] [[package]] name = "serde_json" -version = "1.0.85" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" dependencies = [ "itoa", "ryu", @@ -2088,33 +2167,33 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.5", + "digest 0.10.6", ] [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] [[package]] name = "signature" -version = "1.6.3" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb766570a2825fa972bceff0d195727876a9cdf2460ab2e52d455dc2de47fd9" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ - "digest 0.10.5", + "digest 0.10.6", "rand_core", ] [[package]] name = "similar" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803" +checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" [[package]] name = "simple_asn1" @@ -2125,7 +2204,7 @@ dependencies = [ "num-bigint 0.4.3", "num-traits", "thiserror", - "time 0.3.15", + "time 0.3.20", ] [[package]] @@ -2136,9 +2215,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -2151,9 +2230,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -2177,9 +2256,9 @@ dependencies = [ [[package]] name = "string_cache" -version = "0.8.4" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", @@ -2210,7 +2289,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 1.0.109", ] [[package]] @@ -2230,6 +2309,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece519cfaf36269ea69d16c363fa1d59ceba8296bbfbfc003c3176d01f2816ee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tempfile" version = "3.4.0" @@ -2256,44 +2346,44 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "textwrap" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.6", ] [[package]] name = "time" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", @@ -2302,21 +2392,31 @@ dependencies = [ [[package]] name = "time" -version = "0.3.15" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "itoa", - "libc", - "num_threads", + "js-sys", + "serde", + "time-core", "time-macros", ] +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + [[package]] name = "time-macros" -version = "0.2.4" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +dependencies = [ + "time-core", +] [[package]] name = "tiny-keccak" @@ -2338,15 +2438,15 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.24.2" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb" +checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" dependencies = [ "autocfg", "bytes", @@ -2359,25 +2459,25 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] name = "tokio-macros" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "tokio-native-tls" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", "tokio", @@ -2396,9 +2496,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ "bytes", "futures-core", @@ -2409,12 +2509,20 @@ dependencies = [ ] [[package]] -name = "toml" -version = "0.5.9" +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" + +[[package]] +name = "toml_edit" +version = "0.19.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "dc18466501acd8ac6a3f615dd29a3438f8ca6bb3b19537138b3106e575621274" dependencies = [ - "serde", + "indexmap", + "toml_datetime", + "winnow", ] [[package]] @@ -2425,9 +2533,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.36" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", @@ -2436,42 +2544,42 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", ] [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "typed-arena" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" @@ -2523,15 +2631,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "wait-timeout" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -dependencies = [ - "libc", -] - [[package]] name = "want" version = "0.3.0" @@ -2556,9 +2655,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2566,24 +2665,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -2593,9 +2692,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2603,28 +2702,65 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db36fc0f9fb209e88fb3642590ae0205bb5a56216dabd963ba15879fe53a30b" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0734759ae6b3b1717d661fe4f016efcfb9828f5edb4520c18eaee05af3b43be9" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wasm-streams" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -2642,9 +2778,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.5" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ "webpki", ] @@ -2681,16 +2817,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.36.1" +name = "windows" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", + "windows-targets", ] [[package]] @@ -2700,12 +2832,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.1", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.1", + "windows_x86_64_msvc", ] [[package]] @@ -2719,90 +2851,69 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.1", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.1", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" +name = "winnow" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "23d020b441f92996c80d94ae9166e8501e59c7bb56121189dc9eab3bd8216966" +dependencies = [ + "memchr", +] [[package]] name = "winreg" diff --git a/ic-agent/Cargo.toml b/ic-agent/Cargo.toml index a3d53113..b87ea7b1 100644 --- a/ic-agent/Cargo.toml +++ b/ic-agent/Cargo.toml @@ -25,16 +25,11 @@ futures-util = "0.3.21" hex = { workspace = true } http = "0.2.6" http-body = "0.4.5" -hyper-rustls = { version = "0.23.0", features = [ - "webpki-roots", - "http2", -], optional = true } ic-verify-bls-signature = "0.1" k256 = { version = "0.11", features = ["pem"] } leb128 = "0.2.5" mime = "0.3.16" rand = "0.8.5" -rustls = "0.20.4" ring = { workspace = true, features = ["std"] } serde = { workspace = true, features = ["derive"] } serde_bytes = { workspace = true } @@ -42,7 +37,6 @@ serde_cbor = "0.11.2" sha2 = { workspace = true } simple_asn1 = "0.6.1" thiserror = { workspace = true } -tokio = { version = "1.24.2", features = ["time"] } url = "2.1.0" pkcs8 = { version = "0.9", features = ["std"] } sec1 = { version = "0.3", features = ["pem"] } @@ -63,11 +57,39 @@ optional = true version = "1.0" optional = true +[target.'cfg(not(target_family = "wasm"))'.dependencies] +hyper-rustls = { version = "0.23.0", features = [ + "webpki-roots", + "http2", +], optional = true } +tokio = { version = "1.24.2", features = ["time"] } +rustls = "0.20.4" + +[target.'cfg(target_family = "wasm")'.dependencies] +backoff = { version = "0.4", features = ["wasm-bindgen"] } +getrandom = { version = "0.2", features = ["js"] } +js-sys = "0.3" +wasm-bindgen = "0.2" +wasm-bindgen-futures = "0.4" +web-sys = { version = "0.3", features = ["Window"] } +time = { version = "0.3", features = ["wasm-bindgen"] } + [dev-dependencies] -mockito = "0.31.0" -proptest = "1.0.0" serde_json = "1.0.79" + +[target.'cfg(not(target_family = "wasm"))'.dev-dependencies] tokio = { version = "1.24.2", features = ["full"] } +mockito = "1" + +[target.'cfg(target_family = "wasm")'.dev-dependencies] +wasm-bindgen-test = "0.3.34" +web-sys = { version = "0.3", features = [ + "Navigator", + "ServiceWorkerContainer", + "ServiceWorker", + "ServiceWorkerRegistration", + "ServiceWorkerState", +] } [features] default = ["pem", "reqwest"] @@ -76,3 +98,6 @@ hyper = ["dep:hyper", "dep:hyper-rustls"] ic_ref_tests = [ "default", ] # Used to separate integration tests for ic-ref which need a server running. + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] diff --git a/ic-agent/http_mock_service_worker.js b/ic-agent/http_mock_service_worker.js new file mode 100644 index 00000000..ac1e33d0 --- /dev/null +++ b/ic-agent/http_mock_service_worker.js @@ -0,0 +1,75 @@ +let db = null; + +async function getDb() { + if (db) { + return db; + } else { + return await new Promise((rs, rj) => { + const req = indexedDB.open("http_mock", 1); + req.onsuccess = (event) => rs(event.target.result); + req.onerror = rj; + req.onupgradeneeded = (event) => { + db = event.target.result; + db.createObjectStore("mocks", { keyPath: "nonce" }); + }; + }) + } +} + +async function setMock(mock) { + const db = await getDb(); + await new Promise((rs, rj) => { + const transaction = db.transaction("mocks", "readwrite"); + transaction.oncomplete = rs; + transaction.onerror = rj; + const store = transaction.objectStore("mocks"); + store.put(mock); + }) +} + +async function getMock(nonce) { + const db = await getDb(); + return await new Promise((rs, rj) => { + const req = db.transaction("mocks") + .objectStore("mocks") + .get(nonce); + req.onsuccess = (event) => rs(event.target.result); + req.onerror = rj; + }); +} + +self.addEventListener("fetch", (event) => { + event.respondWith((async () => { + try { + const request = event.request; + const url = new URL(request.url); + if (url.host === "mock_configure") { + const { method, path, status_code, nonce, body, headers } = await request.json(); + await setMock({ method, path, status_code, nonce, body, headers, hits: 0 }); + return new Response(null, { status: 204 }); + } else if (url.host === "mock_assert") { + const nonce = url.pathname.substring(1); + const { hits } = await getMock(nonce); + return new Response(hits, { status: 200 }); + } else { + const nonce = url.host.split('_')[1]; + const { method, path, status_code, body, headers, hits } = await getMock(nonce); + if (request.method !== method) { + return new Response(`expected ${method}, got ${request.method}`, { status: 405 }); + } + if (url.pathname !== path) { + return new Response(`expcted ${path}, got ${url.pathname}`, { status: 404 }); + } + await setMock({ method, path, status_code, nonce, body, headers, hits: hits + 1 }); + return new Response(Uint8Array.from(body), { status: status_code, headers }); + } + } catch (e) { + return new Response(e.toString(), { status: 503 }); + } + })()) +}); + +self.addEventListener("activate", (event) => { + skipWaiting(); + event.waitUntil(clients.claim()); +}); diff --git a/ic-agent/src/agent/agent_test.rs b/ic-agent/src/agent/agent_test.rs index 6850b25c..8c60c325 100644 --- a/ic-agent/src/agent/agent_test.rs +++ b/ic-agent/src/agent/agent_test.rs @@ -1,6 +1,7 @@ // Disable these tests without the reqwest feature. #![cfg(feature = "reqwest")] +use self::mock::{assert_mock, mock}; use crate::{ agent::{ http_transport::ReqwestHttpReplicaV2Transport, @@ -11,111 +12,108 @@ use crate::{ Agent, AgentError, }; use ic_certification::Label; -use mockito::mock; use std::collections::BTreeMap; +#[cfg(target_family = "wasm")] +use wasm_bindgen_test::wasm_bindgen_test; -#[test] -fn query() -> Result<(), AgentError> { +#[cfg(target_family = "wasm")] +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] +async fn query() -> Result<(), AgentError> { let blob = Vec::from("Hello World"); let response = QueryResponse::Replied { reply: CallReply { arg: blob.clone() }, }; - let query_mock = mock("POST", "/api/v2/canister/aaaaa-aa/query") - .with_status(200) - .with_header("content-type", "application/cbor") - .with_body(serde_cbor::to_vec(&response)?) - .create(); + let (query_mock, url) = mock( + "POST", + "/api/v2/canister/aaaaa-aa/query", + 200, + serde_cbor::to_vec(&response)?, + Some("application/cbor"), + ) + .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create( - &mockito::server_url(), - )?) + .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) .build()?; - let runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime"); - let result = runtime.block_on(async { - agent - .query_raw( - &Principal::management_canister(), - Principal::management_canister(), - "main", - &[], - None, - ) - .await - }); - - query_mock.assert(); + let result = agent + .query_raw( + &Principal::management_canister(), + Principal::management_canister(), + "main", + &[], + None, + ) + .await; + + assert_mock(query_mock).await; assert_eq!(result?, blob); Ok(()) } -#[test] -fn query_error() -> Result<(), AgentError> { - let query_mock = mock("POST", "/api/v2/canister/aaaaa-aa/query") - .with_status(500) - .create(); +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] +async fn query_error() -> Result<(), AgentError> { + let (query_mock, url) = + mock("POST", "/api/v2/canister/aaaaa-aa/query", 500, vec![], None).await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create( - &mockito::server_url(), - )?) + .with_transport(ReqwestHttpReplicaV2Transport::create(url)?) .build()?; - let runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime"); - - let result = runtime.block_on(async { - agent - .query_raw( - &Principal::management_canister(), - Principal::management_canister(), - "greet", - &[], - None, - ) - .await - }); - query_mock.assert(); + let result = agent + .query_raw( + &Principal::management_canister(), + Principal::management_canister(), + "greet", + &[], + None, + ) + .await; + + assert_mock(query_mock).await; assert!(result.is_err()); Ok(()) } -#[test] -fn query_rejected() -> Result<(), AgentError> { +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] +async fn query_rejected() -> Result<(), AgentError> { let response: QueryResponse = QueryResponse::Rejected { reject_code: 1234, reject_message: "Rejected Message".to_string(), }; - let query_mock = mock("POST", "/api/v2/canister/aaaaa-aa/query") - .with_status(200) - .with_header("content-type", "application/cbor") - .with_body(serde_cbor::to_vec(&response)?) - .create(); + let (query_mock, url) = mock( + "POST", + "/api/v2/canister/aaaaa-aa/query", + 200, + serde_cbor::to_vec(&response)?, + Some("application/cbor"), + ) + .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create( - &mockito::server_url(), - )?) + .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) .build()?; - let runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime"); - - let result = runtime.block_on(async { - agent - .query_raw( - &Principal::management_canister(), - Principal::management_canister(), - "greet", - &[], - None, - ) - .await - }); - query_mock.assert(); + let result = agent + .query_raw( + &Principal::management_canister(), + Principal::management_canister(), + "greet", + &[], + None, + ) + .await; + + assert_mock(query_mock).await; match result { Err(AgentError::ReplicaError { @@ -131,36 +129,31 @@ fn query_rejected() -> Result<(), AgentError> { Ok(()) } -#[test] -fn call_error() -> Result<(), AgentError> { - let call_mock = mock("POST", "/api/v2/canister/aaaaa-aa/call") - .with_status(500) - .create(); +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] +async fn call_error() -> Result<(), AgentError> { + let (call_mock, url) = mock("POST", "/api/v2/canister/aaaaa-aa/call", 500, vec![], None).await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create( - &mockito::server_url(), - )?) + .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) .build()?; - let runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime"); - let result = runtime.block_on(async { - agent - .update(&Principal::management_canister(), "greet") - .with_arg([]) - .call() - .await - }); + let result = agent + .update(&Principal::management_canister(), "greet") + .with_arg([]) + .call() + .await; - call_mock.assert(); + assert_mock(call_mock).await; assert!(result.is_err()); Ok(()) } -#[test] -fn status() -> Result<(), AgentError> { +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] +async fn status() -> Result<(), AgentError> { let ic_api_version = "1.2.3".to_string(); let mut map = BTreeMap::new(); map.insert( @@ -168,70 +161,71 @@ fn status() -> Result<(), AgentError> { serde_cbor::Value::Text(ic_api_version.clone()), ); let response = serde_cbor::Value::Map(map); - let read_mock = mock("GET", "/api/v2/status") - .with_status(200) - .with_body(serde_cbor::to_vec(&response)?) - .create(); + let (read_mock, url) = mock( + "GET", + "/api/v2/status", + 200, + serde_cbor::to_vec(&response)?, + Some("application/cbor"), + ) + .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create( - &mockito::server_url(), - )?) + .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) .build()?; - let runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime"); - let result = runtime.block_on(async { agent.status().await }); + let result = agent.status().await; - read_mock.assert(); + assert_mock(read_mock).await; assert!(matches!(result, Ok(Status { ic_api_version: v, .. }) if v == ic_api_version)); Ok(()) } -#[test] -fn status_okay() -> Result<(), AgentError> { +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] +async fn status_okay() -> Result<(), AgentError> { let mut map = BTreeMap::new(); map.insert( serde_cbor::Value::Text("ic_api_version".to_owned()), serde_cbor::Value::Text("1.2.3".to_owned()), ); let response = serde_cbor::Value::Map(map); - let read_mock = mock("GET", "/api/v2/status") - .with_status(200) - .with_body(serde_cbor::to_vec(&response)?) - .create(); + let (read_mock, url) = mock( + "GET", + "/api/v2/status", + 200, + serde_cbor::to_vec(&response)?, + Some("application/cbor"), + ) + .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create( - &mockito::server_url(), - )?) + .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) .build()?; - let runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime"); - let result = runtime.block_on(agent.status()); + let result = agent.status().await; - read_mock.assert(); + assert_mock(read_mock).await; assert!(result.is_ok()); Ok(()) } -#[test] +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] // test that the agent (re)tries to reach the server. // We spawn an agent that waits 400ms between requests, and times out after 600ms. The agent is // expected to hit the server at ~ 0ms and ~ 400 ms, and then shut down at 600ms, so we check that // the server got two requests. -fn status_error() -> Result<(), AgentError> { +async fn status_error() -> Result<(), AgentError> { // This mock is never asserted as we don't know (nor do we need to know) how many times // it is called. - let _read_mock = mock("GET", "/api/v2/status").with_status(500).create(); + let (_read_mock, url) = mock("GET", "/api/v2/status", 500, vec![], None).await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create( - &mockito::server_url(), - )?) + .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) .build()?; - let runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime"); - let result = runtime.block_on(async { agent.status().await }); + let result = agent.status().await; assert!(result.is_err()); @@ -357,98 +351,206 @@ const PRUNED_SUBNET: [u8; 1064] = [ 178, 247, 106, 100, 101, 108, 101, 103, 97, 116, 105, 111, 110, 246, ]; -#[test] +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] // asserts that a delegated certificate with correct /subnet//canister_ranges // passes the certificate verification -fn check_subnet_range_with_valid_range() { - let _read_mock = mock( +async fn check_subnet_range_with_valid_range() { + let (_read_mock, url) = mock( "POST", "/api/v2/canister/ivg37-qiaaa-aaaab-aaaga-cai/read_state", + 200, + REQ_WITH_DELEGATED_CERT_RESPONSE.into(), + Some("application/cbor"), ) - .with_status(200) - .with_body(REQ_WITH_DELEGATED_CERT_RESPONSE) - .create(); + .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&mockito::server_url()).unwrap()) + .with_transport(ReqwestHttpReplicaV2Transport::create(&url).unwrap()) .build() .unwrap(); - let runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime"); - let _result = runtime - .block_on(async { - agent - .read_state_raw( - vec![REQ_WITH_DELEGATED_CERT_PATH - .iter() - .map(Label::from) - .collect()], - Principal::from_text(REQ_WITH_DELEGATED_CERT_CANISTER).unwrap(), - ) - .await - }) + let _result = agent + .read_state_raw( + vec![REQ_WITH_DELEGATED_CERT_PATH + .iter() + .map(Label::from) + .collect()], + Principal::from_text(REQ_WITH_DELEGATED_CERT_CANISTER).unwrap(), + ) + .await .expect("read state failed"); } -#[test] +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] // asserts that a delegated certificate with /subnet//canister_ranges that don't include // the canister gets rejected by the cert verification because the subnet is not authorized to // respond to requests for this canister. We do this by using a correct response but serving it // for the wrong canister, which a malicious node might do. -fn check_subnet_range_with_unauthorized_range() { +async fn check_subnet_range_with_unauthorized_range() { let wrong_canister = Principal::from_text("ryjl3-tyaaa-aaaaa-aaaba-cai").unwrap(); - let _read_mock = mock( + let (_read_mock, url) = mock( "POST", "/api/v2/canister/ryjl3-tyaaa-aaaaa-aaaba-cai/read_state", + 200, + REQ_WITH_DELEGATED_CERT_RESPONSE.into(), + Some("application/cbor"), ) - .with_status(200) - .with_body(REQ_WITH_DELEGATED_CERT_RESPONSE) - .create(); + .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&mockito::server_url()).unwrap()) + .with_transport(ReqwestHttpReplicaV2Transport::create(&url).unwrap()) .build() .unwrap(); - let runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime"); - let result = runtime.block_on(async { - agent - .read_state_raw( - vec![REQ_WITH_DELEGATED_CERT_PATH - .iter() - .map(Label::from) - .collect()], - wrong_canister, - ) - .await - }); + let result = agent + .read_state_raw( + vec![REQ_WITH_DELEGATED_CERT_PATH + .iter() + .map(Label::from) + .collect()], + wrong_canister, + ) + .await; assert_eq!(result, Err(AgentError::CertificateNotAuthorized())); } -#[test] +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] // asserts that a delegated certificate with pruned/removed /subnet//canister_ranges // gets rejected by the cert verification. We do this by using a correct response that has // the leaf manually pruned -fn check_subnet_range_with_pruned_range() { +async fn check_subnet_range_with_pruned_range() { let canister = Principal::from_text("ivg37-qiaaa-aaaab-aaaga-cai").unwrap(); - let _read_mock = mock( + let (_read_mock, url) = mock( "POST", "/api/v2/canister/ivg37-qiaaa-aaaab-aaaga-cai/read_state", + 200, + PRUNED_SUBNET.into(), + Some("application/cbor"), ) - .with_status(200) - .with_body(PRUNED_SUBNET) - .create(); + .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&mockito::server_url()).unwrap()) + .with_transport(ReqwestHttpReplicaV2Transport::create(&url).unwrap()) .build() .unwrap(); - let runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime"); - let result = runtime.block_on(async { - agent - .read_state_raw( - vec![REQ_WITH_DELEGATED_CERT_PATH - .iter() - .map(Label::from) - .collect()], - canister, - ) - .await - }); + let result = agent + .read_state_raw( + vec![REQ_WITH_DELEGATED_CERT_PATH + .iter() + .map(Label::from) + .collect()], + canister, + ) + .await; assert!(result.is_err()); } + +#[cfg(not(target_family = "wasm"))] +mod mock { + + use mockito::{Mock, Server, ServerGuard}; + + pub async fn mock( + method: &str, + path: &str, + status_code: u16, + body: Vec, + content_type: Option<&str>, + ) -> ((ServerGuard, Mock), String) { + let mut server = Server::new_async().await; + let mut mock = server + .mock(method, path) + .with_status(status_code as _) + .with_body(body); + if let Some(content_type) = content_type { + mock = mock.with_header("Content-Type", content_type); + } + let mock = mock.create_async().await; + let url = server.url(); + ((server, mock), url) + } + + pub async fn assert_mock((_, mock): (ServerGuard, Mock)) { + mock.assert_async().await; + } +} + +#[cfg(target_family = "wasm")] +mod mock { + use js_sys::*; + use reqwest::Client; + use serde::Serialize; + use std::collections::HashMap; + use wasm_bindgen::{prelude::*, JsCast}; + use wasm_bindgen_futures::JsFuture; + use web_sys::*; + + #[wasm_bindgen(module = "/http_mock_service_worker.js")] + extern "C" {} + + #[derive(Debug, Serialize)] + struct MockConfig { + pub kind: String, + pub method: String, + pub path: String, + pub nonce: String, + pub status_code: u16, + pub headers: Option>, + pub body: Vec, + } + + pub async fn mock( + method: &str, + path: &str, + status_code: u16, + body: Vec, + content_type: Option<&str>, + ) -> (String, String) { + let swc = window().unwrap().navigator().service_worker(); + let registration: ServiceWorkerRegistration = + JsFuture::from(swc.register("/http_mock_service_worker.js")) + .await + .unwrap() + .unchecked_into(); + JsFuture::from(swc.ready().unwrap()).await.unwrap(); + let sw = registration.active().unwrap(); + let mut nonce = [0; 16]; + getrandom::getrandom(&mut nonce).unwrap(); + let nonce = hex::encode(nonce); + let config = MockConfig { + kind: "config".into(), + nonce: nonce.clone(), + method: method.into(), + path: path.into(), + status_code, + body, + headers: content_type.map(|c| HashMap::from([("Content-Type".into(), c.into())])), + }; + if sw.state() == ServiceWorkerState::Activating { + JsFuture::from(Promise::new(&mut |rs, _| sw.set_onstatechange(Some(&rs)))) + .await + .unwrap(); + } + Client::new() + .post("http://mock_configure") + .json(&config) + .send() + .await + .unwrap() + .error_for_status() + .unwrap(); + (nonce.clone(), format!("http://mock_{}/", nonce)) + } + + pub async fn assert_mock(nonce: String) { + let hits = Client::new() + .get(&format!("http://mock_assert/{}", nonce)) + .send() + .await + .unwrap() + .error_for_status() + .unwrap() + .text() + .await + .unwrap(); + assert!(hits.parse::().unwrap() >= 1); + } +} diff --git a/ic-agent/src/agent/http_transport/reqwest_transport.rs b/ic-agent/src/agent/http_transport/reqwest_transport.rs index a7bc853d..b63330f8 100644 --- a/ic-agent/src/agent/http_transport/reqwest_transport.rs +++ b/ic-agent/src/agent/http_transport/reqwest_transport.rs @@ -6,6 +6,7 @@ pub use reqwest; use std::sync::Arc; use futures_util::StreamExt; +#[cfg(not(target_family = "wasm"))] use hyper_rustls::ConfigBuilderExt; use reqwest::{ header::{HeaderMap, AUTHORIZATION, CONTENT_TYPE}, @@ -62,6 +63,7 @@ pub struct ReqwestHttpReplicaV2Transport { impl ReqwestHttpReplicaV2Transport { /// Creates a replica transport from a HTTP URL. + #[cfg(not(target_family = "wasm"))] pub fn create>(url: U) -> Result { let mut tls_config = rustls::ClientConfig::builder() .with_safe_defaults() @@ -80,6 +82,12 @@ impl ReqwestHttpReplicaV2Transport { ) } + /// Creates a replica transport from a HTTP URL. + #[cfg(target_family = "wasm")] + pub fn create>(url: U) -> Result { + Self::create_with_client(url, Client::new()) + } + /// Creates a replica transport from a HTTP URL and a [`reqwest::Client`]. pub fn create_with_client>(url: U, client: Client) -> Result { let url = url.into(); @@ -280,9 +288,15 @@ impl ReplicaV2Transport for ReqwestHttpReplicaV2Transport { #[cfg(test)] mod test { + #[cfg(target_family = "wasm")] + use wasm_bindgen_test::wasm_bindgen_test; + #[cfg(target_family = "wasm")] + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + use super::ReqwestHttpReplicaV2Transport; - #[test] + #[cfg_attr(not(target_family = "wasm"), test)] + #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] fn redirect() { fn test(base: &str, result: &str) { let t = ReqwestHttpReplicaV2Transport::create(base).unwrap(); diff --git a/ic-agent/src/agent/mod.rs b/ic-agent/src/agent/mod.rs index 9b2f1cd1..638dd46f 100644 --- a/ic-agent/src/agent/mod.rs +++ b/ic-agent/src/agent/mod.rs @@ -51,8 +51,12 @@ const IC_STATE_ROOT_DOMAIN_SEPARATOR: &[u8; 14] = b"\x0Dic-state-root"; const IC_ROOT_KEY: &[u8; 133] = b"\x30\x81\x82\x30\x1d\x06\x0d\x2b\x06\x01\x04\x01\x82\xdc\x7c\x05\x03\x01\x02\x01\x06\x0c\x2b\x06\x01\x04\x01\x82\xdc\x7c\x05\x03\x02\x01\x03\x61\x00\x81\x4c\x0e\x6e\xc7\x1f\xab\x58\x3b\x08\xbd\x81\x37\x3c\x25\x5c\x3c\x37\x1b\x2e\x84\x86\x3c\x98\xa4\xf1\xe0\x8b\x74\x23\x5d\x14\xfb\x5d\x9c\x0c\xd5\x46\xd9\x68\x5f\x91\x3a\x0c\x0b\x2c\xc5\x34\x15\x83\xbf\x4b\x43\x92\xe4\x67\xdb\x96\xd6\x5b\x9b\xb4\xcb\x71\x71\x12\xf8\x47\x2e\x0d\x5a\x4d\x14\x50\x5f\xfd\x74\x84\xb0\x12\x91\x09\x1c\x5f\x87\xb9\x88\x83\x46\x3f\x98\x09\x1a\x0b\xaa\xae"; +#[cfg(not(target_family = "wasm"))] type AgentFuture<'a, V> = Pin> + Send + 'a>>; +#[cfg(target_family = "wasm")] +type AgentFuture<'a, V> = Pin> + 'a>>; + /// A facade that connects to a Replica and does requests. These requests can be of any type /// (does not have to be HTTP). This trait is to inverse the control from the Agent over its /// connection code, and to resolve any direct dependencies to tokio or HTTP code from this @@ -335,14 +339,20 @@ impl Agent { let permitted_drift = Duration::from_secs(60); (self .ingress_expiry_duration - .as_nanos() - .saturating_add( - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .expect("Time wrapped around.") - .as_nanos(), - ) - .saturating_sub(permitted_drift.as_nanos())) as u64 + .saturating_add({ + #[cfg(not(target_family = "wasm"))] + { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .expect("Time wrapped around.") + } + #[cfg(target_family = "wasm")] + { + Duration::from_nanos((js_sys::Date::now() * 1_000_000.) as _) + } + }) + .saturating_sub(permitted_drift)) + .as_nanos() as u64 } /// Return the principal of the identity. @@ -574,7 +584,25 @@ impl Agent { }; match retry_policy.next_backoff() { + #[cfg(not(target_family = "wasm"))] Some(duration) => tokio::time::sleep(duration).await, + #[cfg(target_family = "wasm")] + Some(duration) => { + wasm_bindgen_futures::JsFuture::from(js_sys::Promise::new(&mut |rs, rj| { + if let Err(e) = web_sys::window() + .expect("global window unavailable") + .set_timeout_with_callback_and_timeout_and_arguments_0( + &rs, + duration.as_millis() as _, + ) + { + use wasm_bindgen::UnwrapThrowExt; + rj.call1(&rj, &e).unwrap_throw(); + } + })) + .await + .expect("unable to setTimeout"); + } None => return Err(AgentError::TimeoutWaitingForResponse()), } } @@ -1104,7 +1132,7 @@ impl<'agent> QueryBuilder<'agent> { /// An in-flight canister update call. Useful primarily as a `Future`. pub struct UpdateCall<'agent> { agent: &'agent Agent, - request_id: Pin> + Send + 'agent>>, + request_id: AgentFuture<'agent, RequestId>, effective_canister_id: Principal, } diff --git a/ic-agent/src/lib.rs b/ic-agent/src/lib.rs index a3ffa732..35631940 100644 --- a/ic-agent/src/lib.rs +++ b/ic-agent/src/lib.rs @@ -111,6 +111,9 @@ rustdoc::private_intra_doc_links )] +#[cfg(all(feature = "hyper", target_family = "wasm"))] +compile_error!("Feature `hyper` cannot be used from WASM."); + #[macro_use] mod macros; diff --git a/ic-utils/Cargo.toml b/ic-utils/Cargo.toml index 5406e167..15644fad 100644 --- a/ic-utils/Cargo.toml +++ b/ic-utils/Cargo.toml @@ -38,3 +38,6 @@ tokio = { version = "1.24.2", features = ["full"] } [features] raw = [] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] diff --git a/ic-utils/src/call.rs b/ic-utils/src/call.rs index 4bd8d219..ac5ed725 100644 --- a/ic-utils/src/call.rs +++ b/ic-utils/src/call.rs @@ -9,7 +9,8 @@ mod expiry; pub use expiry::Expiry; /// A type that implements synchronous calls (ie. 'query' calls). -#[async_trait] +#[cfg_attr(target_family = "wasm", async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait)] pub trait SyncCall where O: for<'de> ArgumentDecoder<'de> + Send, @@ -32,7 +33,8 @@ where /// /// The return type must be a tuple type that represents all the values the return /// call should be returning. -#[async_trait] +#[cfg_attr(target_family = "wasm", async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait)] pub trait AsyncCall where Out: for<'de> ArgumentDecoder<'de> + Send, @@ -166,7 +168,8 @@ where } } -#[async_trait] +#[cfg_attr(target_family = "wasm", async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait)] impl<'agent, Out> SyncCall for SyncCaller<'agent, Out> where Self: Sized, @@ -247,7 +250,8 @@ where } } -#[async_trait] +#[cfg_attr(target_family = "wasm", async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait)] impl<'agent, Out> AsyncCall for AsyncCaller<'agent, Out> where Out: for<'de> ArgumentDecoder<'de> + Send, @@ -348,7 +352,8 @@ where } } -#[async_trait] +#[cfg_attr(target_family = "wasm", async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait)] impl AsyncCall for AndThenAsyncCaller where @@ -449,7 +454,8 @@ where } } -#[async_trait] +#[cfg_attr(target_family = "wasm", async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait)] impl AsyncCall for MappedAsyncCaller where Out: for<'de> ArgumentDecoder<'de> + Send, diff --git a/ic-utils/src/interfaces/management_canister/builders.rs b/ic-utils/src/interfaces/management_canister/builders.rs index 801b6a32..759282cf 100644 --- a/ic-utils/src/interfaces/management_canister/builders.rs +++ b/ic-utils/src/interfaces/management_canister/builders.rs @@ -302,7 +302,8 @@ impl<'agent, 'canister: 'agent> CreateCanisterBuilder<'agent, 'canister> { } } -#[async_trait] +#[cfg_attr(target_family = "wasm", async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait)] impl<'agent, 'canister: 'agent> AsyncCall<(Principal,)> for CreateCanisterBuilder<'agent, 'canister> { @@ -436,7 +437,8 @@ impl<'agent, 'canister: 'agent> InstallCodeBuilder<'agent, 'canister> { } } -#[async_trait] +#[cfg_attr(target_family = "wasm", async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait)] impl<'agent, 'canister: 'agent> AsyncCall<()> for InstallCodeBuilder<'agent, 'canister> { async fn call(self) -> Result { self.build()?.call().await @@ -642,7 +644,8 @@ impl<'agent, 'canister: 'agent> UpdateCanisterBuilder<'agent, 'canister> { } } -#[async_trait] +#[cfg_attr(target_family = "wasm", async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait)] impl<'agent, 'canister: 'agent> AsyncCall<()> for UpdateCanisterBuilder<'agent, 'canister> { async fn call(self) -> Result { self.build()?.call().await diff --git a/ic-utils/src/interfaces/wallet.rs b/ic-utils/src/interfaces/wallet.rs index b11dbb9c..675566ed 100644 --- a/ic-utils/src/interfaces/wallet.rs +++ b/ic-utils/src/interfaces/wallet.rs @@ -121,7 +121,8 @@ where } } -#[async_trait] +#[cfg_attr(target_family = "wasm", async_trait(?Send))] +#[cfg_attr(not(target_family = "wasm"), async_trait)] impl<'agent, 'canister: 'agent, Out> AsyncCall for CallForwarder<'agent, 'canister, Out> where Out: for<'de> ArgumentDecoder<'de> + Send + Sync, diff --git a/icx-cert/src/pprint.rs b/icx-cert/src/pprint.rs index 941f5332..ea8ae0ef 100644 --- a/icx-cert/src/pprint.rs +++ b/icx-cert/src/pprint.rs @@ -122,10 +122,13 @@ pub fn pprint(url: String, accept_encodings: Option>) -> Result<()> .with_context(|| "failed to decode certificate time as LEB128")?; const NANOS_PER_SEC: u64 = 1_000_000_000; - let dt = chrono::Utc.timestamp( - (timestamp_nanos / NANOS_PER_SEC) as i64, - (timestamp_nanos % NANOS_PER_SEC) as u32, - ); + let dt = chrono::Utc + .timestamp_opt( + (timestamp_nanos / NANOS_PER_SEC) as i64, + (timestamp_nanos % NANOS_PER_SEC) as u32, + ) + .single() + .context("timestamp out of range")?; println!("CERTIFICATE TIME: {}", dt.to_rfc3339()); } println!("CERTIFICATE TREE: {:#?}", cert.tree); From 42d96459852b6793bb9c44c297ed41f30b35b86a Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Thu, 30 Mar 2023 11:05:10 -0700 Subject: [PATCH 03/30] chore: rename Transport and implementors (#416) There are a few unnecessarily large names which make the documentation feel slightly daunting while referencing an undocumented and inaccessible V1, namely `ReplicaV2Transport`, `ReqwestHttpReplicaV2Transport`, and `HyperReplicaV2Transport`. This renames these to `Transport`, `ReqwestTransport`, and `HyperTransport`, as well as un-deprecating `AgentBuilder::with_url`. However, the old names are left up as `pub use`s under `#[doc(hidden)]` to avoid making this a breaking change; they can be `#[deprecate]`d in the next release and removed in the one after that. Additionally, in the interest of friendlier documentation, many `pub use`s have been marked `#[doc(inline)]`. --- ic-agent/src/agent/agent_config.rs | 4 +-- ic-agent/src/agent/agent_test.rs | 22 ++++++++-------- ic-agent/src/agent/builder.rs | 11 ++++---- .../agent/http_transport/hyper_transport.rs | 25 +++++++++++-------- ic-agent/src/agent/http_transport/mod.rs | 14 ++++++++--- .../agent/http_transport/reqwest_transport.rs | 23 +++++++++-------- ic-agent/src/agent/mod.rs | 15 ++++++----- ic-agent/src/export.rs | 1 + ic-agent/src/identity/mod.rs | 6 ++--- ic-agent/src/lib.rs | 3 +++ ic-agent/src/request_id/error.rs | 1 + ic-agent/src/request_id/mod.rs | 1 + ic-identity-hsm/src/lib.rs | 4 +-- ic-utils/src/canister.rs | 4 +-- icx/src/main.rs | 2 +- ref-tests/src/utils.rs | 6 ++--- 16 files changed, 81 insertions(+), 61 deletions(-) diff --git a/ic-agent/src/agent/agent_config.rs b/ic-agent/src/agent/agent_config.rs index accb242f..3ef9fde7 100644 --- a/ic-agent/src/agent/agent_config.rs +++ b/ic-agent/src/agent/agent_config.rs @@ -1,5 +1,5 @@ use crate::{ - agent::{NonceFactory, NonceGenerator, ReplicaV2Transport}, + agent::{NonceFactory, NonceGenerator, Transport}, identity::{anonymous::AnonymousIdentity, Identity}, }; use std::{sync::Arc, time::Duration}; @@ -14,7 +14,7 @@ pub struct AgentConfig { /// See [`with_ingress_expiry`](super::AgentBuilder::with_ingress_expiry). pub ingress_expiry_duration: Option, /// The [`with_transport`](super::AgentBuilder::with_transport). - pub transport: Option>, + pub transport: Option>, } impl Default for AgentConfig { diff --git a/ic-agent/src/agent/agent_test.rs b/ic-agent/src/agent/agent_test.rs index 8c60c325..8b66620b 100644 --- a/ic-agent/src/agent/agent_test.rs +++ b/ic-agent/src/agent/agent_test.rs @@ -4,7 +4,7 @@ use self::mock::{assert_mock, mock}; use crate::{ agent::{ - http_transport::ReqwestHttpReplicaV2Transport, + http_transport::ReqwestTransport, replica_api::{CallReply, QueryResponse}, Status, }, @@ -37,7 +37,7 @@ async fn query() -> Result<(), AgentError> { .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) + .with_transport(ReqwestTransport::create(&url)?) .build()?; let result = agent .query_raw( @@ -62,7 +62,7 @@ async fn query_error() -> Result<(), AgentError> { let (query_mock, url) = mock("POST", "/api/v2/canister/aaaaa-aa/query", 500, vec![], None).await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(url)?) + .with_transport(ReqwestTransport::create(url)?) .build()?; let result = agent @@ -100,7 +100,7 @@ async fn query_rejected() -> Result<(), AgentError> { .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) + .with_transport(ReqwestTransport::create(&url)?) .build()?; let result = agent @@ -135,7 +135,7 @@ async fn call_error() -> Result<(), AgentError> { let (call_mock, url) = mock("POST", "/api/v2/canister/aaaaa-aa/call", 500, vec![], None).await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) + .with_transport(ReqwestTransport::create(&url)?) .build()?; let result = agent @@ -171,7 +171,7 @@ async fn status() -> Result<(), AgentError> { .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) + .with_transport(ReqwestTransport::create(&url)?) .build()?; let result = agent.status().await; @@ -200,7 +200,7 @@ async fn status_okay() -> Result<(), AgentError> { .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) + .with_transport(ReqwestTransport::create(&url)?) .build()?; let result = agent.status().await; @@ -223,7 +223,7 @@ async fn status_error() -> Result<(), AgentError> { let (_read_mock, url) = mock("GET", "/api/v2/status", 500, vec![], None).await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&url)?) + .with_transport(ReqwestTransport::create(&url)?) .build()?; let result = agent.status().await; @@ -365,7 +365,7 @@ async fn check_subnet_range_with_valid_range() { ) .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&url).unwrap()) + .with_transport(ReqwestTransport::create(&url).unwrap()) .build() .unwrap(); let _result = agent @@ -397,7 +397,7 @@ async fn check_subnet_range_with_unauthorized_range() { ) .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&url).unwrap()) + .with_transport(ReqwestTransport::create(&url).unwrap()) .build() .unwrap(); let result = agent @@ -428,7 +428,7 @@ async fn check_subnet_range_with_pruned_range() { ) .await; let agent = Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create(&url).unwrap()) + .with_transport(ReqwestTransport::create(&url).unwrap()) .build() .unwrap(); let result = agent diff --git a/ic-agent/src/agent/builder.rs b/ic-agent/src/agent/builder.rs index 17ffa641..9bdd6e1f 100644 --- a/ic-agent/src/agent/builder.rs +++ b/ic-agent/src/agent/builder.rs @@ -1,5 +1,5 @@ use crate::{ - agent::{agent_config::AgentConfig, Agent, ReplicaV2Transport}, + agent::{agent_config::AgentConfig, Agent, Transport}, AgentError, Identity, NonceFactory, NonceGenerator, }; use std::sync::Arc; @@ -18,21 +18,20 @@ impl AgentBuilder { /// Set the URL of the [Agent]. #[cfg(feature = "reqwest")] - #[deprecated(since = "0.3.0", note = "Prefer using with_transport().")] pub fn with_url>(self, url: S) -> Self { - use crate::agent::http_transport::ReqwestHttpReplicaV2Transport; + use crate::agent::http_transport::ReqwestTransport; - self.with_transport(ReqwestHttpReplicaV2Transport::create(url).unwrap()) + self.with_transport(ReqwestTransport::create(url).unwrap()) } /// Set a Replica transport to talk to serve as the replica interface. - pub fn with_transport(self, transport: T) -> Self { + pub fn with_transport(self, transport: T) -> Self { self.with_arc_transport(Arc::new(transport)) } /// Same as [Self::with_transport], but provides a `Arc` boxed implementation instead /// of a direct type. - pub fn with_arc_transport(mut self, transport: Arc) -> Self { + pub fn with_arc_transport(mut self, transport: Arc) -> Self { self.config.transport = Some(transport); self } diff --git a/ic-agent/src/agent/http_transport/hyper_transport.rs b/ic-agent/src/agent/http_transport/hyper_transport.rs index f8419573..66e697ac 100644 --- a/ic-agent/src/agent/http_transport/hyper_transport.rs +++ b/ic-agent/src/agent/http_transport/hyper_transport.rs @@ -1,4 +1,4 @@ -//! A [ReplicaV2Transport] that connects using a hyper client. +//! A [`Transport`] that connects using a [`hyper`] client. #![cfg(any(feature = "hyper"))] pub use hyper; @@ -20,22 +20,25 @@ use crate::{ agent::{ agent_error::HttpErrorPayload, http_transport::{IC0_DOMAIN, IC0_SUB_DOMAIN}, - AgentFuture, ReplicaV2Transport, + AgentFuture, Transport, }, export::Principal, AgentError, RequestId, }; -/// A [ReplicaV2Transport] using [hyper] to make HTTP calls to the internet computer. +/// A [`Transport`] using [`hyper`] to make HTTP calls to the Internet Computer. #[derive(Debug)] -pub struct HyperReplicaV2Transport, B1>> { +pub struct HyperTransport, B1>> { _marker: PhantomData>, url: Uri, max_response_body_size: Option, service: S, } -/// Trait representing the contraints on [`HttpBody`] that [`HyperReplicaV2Transport`] requires +#[doc(hidden)] +pub use HyperTransport as HyperReplicaV2Transport; // deprecate after 0.24 + +/// Trait representing the contraints on [`HttpBody`] that [`HyperTransport`] requires pub trait HyperBody: HttpBody + Send + From> + 'static { @@ -55,7 +58,7 @@ where type BodyError = B::Error; } -/// Trait representing the contraints on [`Service`] that [`HyperReplicaV2Transport`] requires. +/// Trait representing the contraints on [`Service`] that [`HyperTransport`] requires. pub trait HyperService: Send + Sync @@ -84,7 +87,7 @@ where type ServiceFuture = S::Future; } -impl HyperReplicaV2Transport { +impl HyperTransport { /// Creates a replica transport from a HTTP URL. pub fn create>(url: U) -> Result { let connector = HttpsConnectorBuilder::new() @@ -97,7 +100,7 @@ impl HyperReplicaV2Transport { } } -impl HyperReplicaV2Transport +impl HyperTransport where B1: HyperBody, S: HyperService, @@ -230,7 +233,7 @@ where } } -impl ReplicaV2Transport for HyperReplicaV2Transport +impl Transport for HyperTransport where B1: HyperBody, S: HyperService, @@ -276,7 +279,7 @@ where #[cfg(test)] mod test { - use super::HyperReplicaV2Transport; + use super::HyperTransport; use hyper::{Client, Uri}; #[test] @@ -284,7 +287,7 @@ mod test { fn test(base: &str, result: &str) { let client: Client<_> = Client::builder().build_http(); let uri: Uri = base.parse().unwrap(); - let t = HyperReplicaV2Transport::create_with_service(uri, client).unwrap(); + let t = HyperTransport::create_with_service(uri, client).unwrap(); assert_eq!(t.url, result, "{}", base); } diff --git a/ic-agent/src/agent/http_transport/mod.rs b/ic-agent/src/agent/http_transport/mod.rs index f6e1d2da..d39c3f30 100644 --- a/ic-agent/src/agent/http_transport/mod.rs +++ b/ic-agent/src/agent/http_transport/mod.rs @@ -1,16 +1,24 @@ -//! [super::ReplicaV2Transport] implementations. +//! [`Transport`](super::Transport) implementations. #[cfg(feature = "reqwest")] pub mod reqwest_transport; #[cfg(feature = "reqwest")] -pub use reqwest_transport::*; +#[doc(inline)] +pub use reqwest_transport::ReqwestTransport; +#[cfg(feature = "reqwest")] +#[doc(hidden)] +pub use reqwest_transport::*; // deprecate after 0.24 #[cfg(feature = "hyper")] pub mod hyper_transport; #[cfg(feature = "hyper")] -pub use hyper_transport::*; +#[doc(inline)] +pub use hyper_transport::HyperTransport; +#[cfg(feature = "hyper")] +#[doc(hidden)] +pub use hyper_transport::*; // deprecate after 0.24 #[allow(dead_code)] const IC0_DOMAIN: &str = "ic0.app"; diff --git a/ic-agent/src/agent/http_transport/reqwest_transport.rs b/ic-agent/src/agent/http_transport/reqwest_transport.rs index b63330f8..3c8003ee 100644 --- a/ic-agent/src/agent/http_transport/reqwest_transport.rs +++ b/ic-agent/src/agent/http_transport/reqwest_transport.rs @@ -1,4 +1,4 @@ -//! A [ReplicaV2Transport] that connects using a reqwest client. +//! A [`Transport`] that connects using a [`reqwest`] client. #![cfg(feature = "reqwest")] pub use reqwest; @@ -17,7 +17,7 @@ use crate::{ agent::{ agent_error::HttpErrorPayload, http_transport::{IC0_DOMAIN, IC0_SUB_DOMAIN}, - AgentFuture, ReplicaV2Transport, + AgentFuture, Transport, }, export::Principal, AgentError, RequestId, @@ -52,16 +52,19 @@ impl dyn PasswordManager { impl_debug_empty!(dyn PasswordManager); -/// A [ReplicaV2Transport] using [reqwest] to make HTTP calls to the internet computer. +/// A [`Transport`] using [`reqwest`] to make HTTP calls to the Internet Computer. #[derive(Debug)] -pub struct ReqwestHttpReplicaV2Transport { +pub struct ReqwestTransport { url: Url, client: Client, password_manager: Option>, max_response_body_size: Option, } -impl ReqwestHttpReplicaV2Transport { +#[doc(hidden)] +pub use ReqwestTransport as ReqwestHttpReplicaV2Transport; // deprecate after 0.24 + +impl ReqwestTransport { /// Creates a replica transport from a HTTP URL. #[cfg(not(target_family = "wasm"))] pub fn create>(url: U) -> Result { @@ -116,7 +119,7 @@ impl ReqwestHttpReplicaV2Transport { /// Same as [`Self::with_password_manager`], but providing the Arc so one does not have to be created. pub fn with_arc_password_manager(self, password_manager: Arc) -> Self { - ReqwestHttpReplicaV2Transport { + ReqwestTransport { password_manager: Some(password_manager), ..self } @@ -124,7 +127,7 @@ impl ReqwestHttpReplicaV2Transport { /// Sets a max response body size limit pub fn with_max_response_body_size(self, max_response_body_size: usize) -> Self { - ReqwestHttpReplicaV2Transport { + ReqwestTransport { max_response_body_size: Some(max_response_body_size), ..self } @@ -248,7 +251,7 @@ impl ReqwestHttpReplicaV2Transport { } } -impl ReplicaV2Transport for ReqwestHttpReplicaV2Transport { +impl Transport for ReqwestTransport { fn call( &self, effective_canister_id: Principal, @@ -293,13 +296,13 @@ mod test { #[cfg(target_family = "wasm")] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); - use super::ReqwestHttpReplicaV2Transport; + use super::ReqwestTransport; #[cfg_attr(not(target_family = "wasm"), test)] #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] fn redirect() { fn test(base: &str, result: &str) { - let t = ReqwestHttpReplicaV2Transport::create(base).unwrap(); + let t = ReqwestTransport::create(base).unwrap(); assert_eq!(t.url.as_str(), result, "{}", base); } diff --git a/ic-agent/src/agent/mod.rs b/ic-agent/src/agent/mod.rs index 638dd46f..b8f77b56 100644 --- a/ic-agent/src/agent/mod.rs +++ b/ic-agent/src/agent/mod.rs @@ -66,7 +66,7 @@ type AgentFuture<'a, V> = Pin> + ' /// feature flag `reqwest`. This might be deprecated in the future. /// /// Any error returned by these methods will bubble up to the code that called the [Agent]. -pub trait ReplicaV2Transport: Send + Sync { +pub trait Transport: Send + Sync { /// Sends an asynchronous request to a Replica. The Request ID is non-mutable and /// depends on the content of the envelope. /// @@ -100,9 +100,12 @@ pub trait ReplicaV2Transport: Send + Sync { fn status(&self) -> AgentFuture>; } -impl_debug_empty!(dyn ReplicaV2Transport); +#[doc(hidden)] +pub use Transport as ReplicaV2Transport; // deprecate after 0.24 -impl ReplicaV2Transport for Box { +impl_debug_empty!(dyn Transport); + +impl Transport for Box { fn call( &self, effective_canister_id: Principal, @@ -125,7 +128,7 @@ impl ReplicaV2Transport for Box { (**self).status() } } -impl ReplicaV2Transport for Arc { +impl Transport for Arc { fn call( &self, effective_canister_id: Principal, @@ -237,7 +240,7 @@ pub struct Agent { identity: Arc, ingress_expiry_duration: Duration, root_key: Arc>>>, - transport: Arc, + transport: Arc, } impl fmt::Debug for Agent { @@ -271,7 +274,7 @@ impl Agent { } /// Set the transport of the [`Agent`]. - pub fn set_transport(&mut self, transport: F) { + pub fn set_transport(&mut self, transport: F) { self.transport = Arc::new(transport); } diff --git a/ic-agent/src/export.rs b/ic-agent/src/export.rs index 21e5201f..fd285e29 100644 --- a/ic-agent/src/export.rs +++ b/ic-agent/src/export.rs @@ -1,2 +1,3 @@ //! A module to re-export types that are visible through the ic-agent API. +#[doc(inline)] pub use candid::types::principal::{Principal, PrincipalError}; diff --git a/ic-agent/src/identity/mod.rs b/ic-agent/src/identity/mod.rs index d15dec53..895030bd 100644 --- a/ic-agent/src/identity/mod.rs +++ b/ic-agent/src/identity/mod.rs @@ -24,11 +24,11 @@ pub struct Signature { pub signature: Option>, } -/// An Identity takes a request id and returns the [Signature]. Since it -/// also knows about the Principal of the sender. +/// An Identity takes a request id and returns the [Signature]. It knows or +/// represents the Principal of the sender. /// /// Agents are assigned a single Identity object, but there can be multiple -/// identities used +/// identities used. pub trait Identity: Send + Sync { /// Returns a sender, ie. the Principal ID that is used to sign a request. /// Only one sender can be used per request. diff --git a/ic-agent/src/lib.rs b/ic-agent/src/lib.rs index 35631940..ce68e133 100644 --- a/ic-agent/src/lib.rs +++ b/ic-agent/src/lib.rs @@ -122,11 +122,14 @@ pub mod export; pub mod identity; pub mod request_id; +#[doc(inline)] pub use agent::{ agent_error, agent_error::AgentError, response_authentication::lookup_value, Agent, NonceFactory, NonceGenerator, }; +#[doc(inline)] pub use identity::{Identity, Signature}; +#[doc(inline)] pub use request_id::{to_request_id, RequestId, RequestIdError}; // Re-export from ic_certification for backward compatibility. diff --git a/ic-agent/src/request_id/error.rs b/ic-agent/src/request_id/error.rs index b45212e7..8954545b 100644 --- a/ic-agent/src/request_id/error.rs +++ b/ic-agent/src/request_id/error.rs @@ -15,6 +15,7 @@ pub enum RequestIdFromStringError { } /// An error during the calculation of the RequestId. +/// /// Since we use serde for serializing a data type into a hash, this has to support traits that /// serde expects, such as Display #[derive(Error, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] diff --git a/ic-agent/src/request_id/mod.rs b/ic-agent/src/request_id/mod.rs index 63a09e42..943292d4 100644 --- a/ic-agent/src/request_id/mod.rs +++ b/ic-agent/src/request_id/mod.rs @@ -12,6 +12,7 @@ use sha2::{Digest, Sha256}; use std::{collections::BTreeMap, iter::Extend, str::FromStr}; pub mod error; +#[doc(inline)] pub use error::RequestIdError; /// Type alias for a sha256 result (ie. a u256). diff --git a/ic-identity-hsm/src/lib.rs b/ic-identity-hsm/src/lib.rs index e7f4a22d..51d25203 100644 --- a/ic-identity-hsm/src/lib.rs +++ b/ic-identity-hsm/src/lib.rs @@ -5,7 +5,7 @@ //! # Example //! //! ```rust,no_run -//! use ic_agent::agent::{Agent, http_transport::ReqwestHttpReplicaV2Transport}; +//! use ic_agent::agent::{Agent, http_transport::ReqwestTransport}; //! use ic_identity_hsm::HardwareIdentity; //! # fn main() -> Result<(), Box> { //! # let replica_url = ""; @@ -13,7 +13,7 @@ //! # let slot_index = 0; //! # let key_id = ""; //! let agent = Agent::builder() -//! .with_transport(ReqwestHttpReplicaV2Transport::create(replica_url)?) +//! .with_transport(ReqwestTransport::create(replica_url)?) //! .with_identity(HardwareIdentity::new(lib_path, slot_index, key_id, || Ok("hunter2".to_string()))?) //! .build(); //! # Ok(()) diff --git a/ic-utils/src/canister.rs b/ic-utils/src/canister.rs index ac363112..d603b354 100644 --- a/ic-utils/src/canister.rs +++ b/ic-utils/src/canister.rs @@ -399,7 +399,7 @@ impl<'agent, 'canister: 'agent> AsyncCallBuilder<'agent, 'canister> { mod tests { use super::super::interfaces::ManagementCanister; use crate::call::AsyncCall; - use ic_agent::agent::http_transport::ReqwestHttpReplicaV2Transport; + use ic_agent::agent::http_transport::ReqwestTransport; use ic_agent::identity::BasicIdentity; #[ignore] @@ -417,7 +417,7 @@ mod tests { ); let agent = ic_agent::Agent::builder() - .with_transport(ReqwestHttpReplicaV2Transport::create("http://localhost:8001").unwrap()) + .with_transport(ReqwestTransport::create("http://localhost:8001").unwrap()) .with_identity(identity) .build() .unwrap(); diff --git a/icx/src/main.rs b/icx/src/main.rs index 691ebcd2..ad4b47b9 100644 --- a/icx/src/main.rs +++ b/icx/src/main.rs @@ -341,7 +341,7 @@ async fn main() -> Result<()> { let agent = Agent::builder() .with_transport( - agent::http_transport::ReqwestHttpReplicaV2Transport::create(opts.replica.clone()) + agent::http_transport::ReqwestTransport::create(opts.replica.clone()) .context("Failed to create Transport for Agent")?, ) .with_boxed_identity(Box::new(create_identity(opts.pem))) diff --git a/ref-tests/src/utils.rs b/ref-tests/src/utils.rs index 4ab6e6f5..6bf29b68 100644 --- a/ref-tests/src/utils.rs +++ b/ref-tests/src/utils.rs @@ -1,4 +1,4 @@ -use ic_agent::agent::http_transport::ReqwestHttpReplicaV2Transport; +use ic_agent::agent::http_transport::ReqwestTransport; use ic_agent::identity::Secp256k1Identity; use ic_agent::{export::Principal, identity::BasicIdentity, Agent, Identity}; use ic_identity_hsm::HardwareIdentity; @@ -85,9 +85,7 @@ pub async fn create_agent(identity: Box) -> Result .expect("Could not parse the IC_REF_PORT environment variable as an integer."); Agent::builder() - .with_transport( - ReqwestHttpReplicaV2Transport::create(format!("http://127.0.0.1:{}", port)).unwrap(), - ) + .with_transport(ReqwestTransport::create(format!("http://127.0.0.1:{}", port)).unwrap()) .with_boxed_identity(identity) .build() .map_err(|e| format!("{:?}", e)) From 2f4ab23d28cef882ced80507c5276428b4e19302 Mon Sep 17 00:00:00 2001 From: Daniel Sharifi <40335219+DSharifi@users.noreply.github.com> Date: Fri, 21 Apr 2023 15:24:21 +0200 Subject: [PATCH 04/30] fix: Fixed bug in conventional commits file (#424) * Copied conventional commits file * Updated the changelog --- .github/workflows/conventional-commits.yml | 25 +++++++++++++++------- CHANGELOG.md | 1 + 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml index 34fd7c68..7d85b696 100644 --- a/.github/workflows/conventional-commits.yml +++ b/.github/workflows/conventional-commits.yml @@ -9,13 +9,22 @@ on: jobs: check: + name: conventional-pr-title:required runs-on: ubuntu-latest steps: - - uses: dfinity/conventional-pr-title-action@v2.2.3 - with: - success-state: Title follows the specification. - failure-state: Title does not follow the specification. - context-name: conventional-pr-title - preset: conventional-changelog-angular@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Conventional commit patterns: + # verb: description + # verb!: description of breaking change + # verb(scope): Description of change to $scope + # verb(scope)!: Description of breaking change to $scope + # verb: feat, fix, ... + # scope: refers to the part of code being changed. E.g. " (accounts)" or " (accounts,canisters)" + # !: Indicates that the PR contains a breaking change. + - run: | + if [[ "${{ github.event.pull_request.title }}" =~ ^(feat|fix|chore|build|ci|docs|style|refactor|perf|test)(\([-a-zA-Z0-9,]+\))?\!?\: ]]; then + echo pass + else + echo "PR title does not match conventions" + echo "PR title: ${{ github.event.pull_request.title }}" + exit 1 + fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 141a8446..41a33bd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +* Fix the conventional-commits job to allow `!` suffix for PRs introducing breaking changes. * Support WASM targets in the browser via `wasm-bindgen` ## [0.23.2] - 2023-04-21 From 28936b2fdd423966c12e31e3550a0c8c7afe9e1a Mon Sep 17 00:00:00 2001 From: Eric Swanson <64809312+ericswanson-dfinity@users.noreply.github.com> Date: Fri, 21 Apr 2023 11:37:45 -0700 Subject: [PATCH 05/30] ci: run conventional commits workflow from pull request (#425) --- .github/workflows/conventional-commits.yml | 2 +- CHANGELOG.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml index 7d85b696..37f1e327 100644 --- a/.github/workflows/conventional-commits.yml +++ b/.github/workflows/conventional-commits.yml @@ -1,6 +1,6 @@ name: Check PR title on: - pull_request_target: + pull_request: types: - opened - reopened diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a33bd5..141a8446 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -* Fix the conventional-commits job to allow `!` suffix for PRs introducing breaking changes. * Support WASM targets in the browser via `wasm-bindgen` ## [0.23.2] - 2023-04-21 From c14c10390dcac7846bb6ff8aaae3ef646c0d6d03 Mon Sep 17 00:00:00 2001 From: Daniel Sharifi <40335219+DSharifi@users.noreply.github.com> Date: Fri, 21 Apr 2023 23:27:20 +0200 Subject: [PATCH 06/30] feat!: Handle rejected update calls after IC spec change. (#422) --- CHANGELOG.md | 3 + Cargo.lock | 12 ++ ic-agent/Cargo.toml | 1 + ic-agent/src/agent/agent_error.rs | 24 ++-- ic-agent/src/agent/agent_test.rs | 95 ++++++++++++-- .../agent/http_transport/reqwest_transport.rs | 15 ++- ic-agent/src/agent/mod.rs | 30 ++--- ic-agent/src/agent/replica_api.rs | 56 ++++++++- ic-agent/src/agent/response.rs | 9 +- ic-agent/src/agent/response_authentication.rs | 12 +- ic-utils/src/interfaces/wallet.rs | 16 +-- icx/src/main.rs | 12 +- ref-tests/tests/ic-ref.rs | 116 ++++++++++++------ ref-tests/tests/integration.rs | 11 +- 14 files changed, 304 insertions(+), 108 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 141a8446..ba52b1a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +* Breaking Change: Enum variant `AgentError::ReplicaError` is now a tuple struct containing `RejectResponse`. +* Handling rejected update calls where status code is 200. See IC-1462 +* Reject code type is changed from `u64` to enum `RejectCode`. * Support WASM targets in the browser via `wasm-bindgen` diff --git a/Cargo.lock b/Cargo.lock index 38b18297..8d34b11e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1057,6 +1057,7 @@ dependencies = [ "serde_bytes", "serde_cbor", "serde_json", + "serde_repr", "sha2 0.10.6", "simple_asn1", "thiserror", @@ -2134,6 +2135,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.6", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" diff --git a/ic-agent/Cargo.toml b/ic-agent/Cargo.toml index b87ea7b1..1f1d1e1a 100644 --- a/ic-agent/Cargo.toml +++ b/ic-agent/Cargo.toml @@ -34,6 +34,7 @@ ring = { workspace = true, features = ["std"] } serde = { workspace = true, features = ["derive"] } serde_bytes = { workspace = true } serde_cbor = "0.11.2" +serde_repr = "0.1.12" sha2 = { workspace = true } simple_asn1 = "0.6.1" thiserror = { workspace = true } diff --git a/ic-agent/src/agent/agent_error.rs b/ic-agent/src/agent/agent_error.rs index 524ffc03..fcd106b4 100644 --- a/ic-agent/src/agent/agent_error.rs +++ b/ic-agent/src/agent/agent_error.rs @@ -1,6 +1,10 @@ //! Errors that can occur when using the replica agent. -use crate::{agent::status::Status, RequestIdError}; +use crate::{ + agent::{replica_api::RejectResponse, status::Status}, + RequestIdError, +}; +// use crate::{agent::status::Status, RequestIdError}; use ic_certification::Label; use leb128::read; use std::{ @@ -49,13 +53,8 @@ pub enum AgentError { PrincipalError(#[from] crate::export::PrincipalError), /// The replica rejected the message. - #[error(r#"The Replica returned an error: code {reject_code}, message: "{reject_message}""#)] - ReplicaError { - /// The [reject code](https://smartcontracts.org/docs/interface-spec/index.html#reject-codes) returned by the replica. - reject_code: u64, - /// The rejection message. - reject_message: String, - }, + #[error("The replica returned a replica error: {0}")] + ReplicaError(RejectResponse), /// The replica returned an HTTP error. #[error("The replica returned an HTTP Error: {0}")] @@ -193,6 +192,15 @@ impl PartialEq for AgentError { } } +impl Display for RejectResponse { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + f.write_fmt(format_args!( + "Replica Error: reject code {:?}, reject message {}, error code {:?}", + self.reject_code, self.reject_message, self.error_code, + )) + } +} + /// A HTTP error from the replica. pub struct HttpErrorPayload { /// The HTTP status code. diff --git a/ic-agent/src/agent/agent_test.rs b/ic-agent/src/agent/agent_test.rs index 8b66620b..d11b6098 100644 --- a/ic-agent/src/agent/agent_test.rs +++ b/ic-agent/src/agent/agent_test.rs @@ -5,7 +5,7 @@ use self::mock::{assert_mock, mock}; use crate::{ agent::{ http_transport::ReqwestTransport, - replica_api::{CallReply, QueryResponse}, + replica_api::{CallReply, QueryResponse, RejectCode, RejectResponse}, Status, }, export::Principal, @@ -85,10 +85,11 @@ async fn query_error() -> Result<(), AgentError> { #[cfg_attr(not(target_family = "wasm"), tokio::test)] #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] async fn query_rejected() -> Result<(), AgentError> { - let response: QueryResponse = QueryResponse::Rejected { - reject_code: 1234, + let response: QueryResponse = QueryResponse::Rejected(RejectResponse { + reject_code: RejectCode::DestinationInvalid, reject_message: "Rejected Message".to_string(), - }; + error_code: Some("Error code".to_string()), + }); let (query_mock, url) = mock( "POST", @@ -116,12 +117,10 @@ async fn query_rejected() -> Result<(), AgentError> { assert_mock(query_mock).await; match result { - Err(AgentError::ReplicaError { - reject_code: code, - reject_message: msg, - }) => { - assert_eq!(code, 1234); - assert_eq!(msg, "Rejected Message"); + Err(AgentError::ReplicaError(replica_error)) => { + assert_eq!(replica_error.reject_code, RejectCode::DestinationInvalid); + assert_eq!(replica_error.reject_message, "Rejected Message"); + assert_eq!(replica_error.error_code, Some("Error code".to_string())); } result => unreachable!("{:?}", result), } @@ -151,6 +150,82 @@ async fn call_error() -> Result<(), AgentError> { Ok(()) } +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] +async fn call_rejected() -> Result<(), AgentError> { + let reject_body = RejectResponse { + reject_code: RejectCode::SysTransient, + reject_message: "Test reject message".to_string(), + error_code: Some("Test error code".to_string()), + }; + + let body = serde_cbor::to_vec(&reject_body).unwrap(); + + let (call_mock, url) = mock( + "POST", + "/api/v2/canister/aaaaa-aa/call", + 200, + body, + Some("application/cbor"), + ) + .await; + + let agent = Agent::builder() + .with_transport(ReqwestTransport::create(&url)?) + .build()?; + + let result = agent + .update(&Principal::management_canister(), "greet") + .with_arg([]) + .call() + .await; + + assert_mock(call_mock).await; + + let expected_response = Err(AgentError::ReplicaError(reject_body)); + assert_eq!(expected_response, result); + + Ok(()) +} + +#[cfg_attr(not(target_family = "wasm"), tokio::test)] +#[cfg_attr(target_family = "wasm", wasm_bindgen_test)] +async fn call_rejected_without_error_code() -> Result<(), AgentError> { + let reject_body = RejectResponse { + reject_code: RejectCode::SysTransient, + reject_message: "Test reject message".to_string(), + error_code: None, + }; + + let body = serde_cbor::to_vec(&reject_body).unwrap(); + + let (call_mock, url) = mock( + "POST", + "/api/v2/canister/aaaaa-aa/call", + 200, + body, + Some("application/cbor"), + ) + .await; + + let agent = Agent::builder() + .with_transport(ReqwestTransport::create(&url)?) + .build()?; + + let result = agent + .update(&Principal::management_canister(), "greet") + .with_arg([]) + .call() + .await; + + assert_mock(call_mock).await; + + let expected_response = Err(AgentError::ReplicaError(reject_body)); + assert_eq!(expected_response, result); + + Ok(()) +} + #[cfg_attr(not(target_family = "wasm"), tokio::test)] #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] async fn status() -> Result<(), AgentError> { diff --git a/ic-agent/src/agent/http_transport/reqwest_transport.rs b/ic-agent/src/agent/http_transport/reqwest_transport.rs index 3c8003ee..841d3301 100644 --- a/ic-agent/src/agent/http_transport/reqwest_transport.rs +++ b/ic-agent/src/agent/http_transport/reqwest_transport.rs @@ -17,6 +17,7 @@ use crate::{ agent::{ agent_error::HttpErrorPayload, http_transport::{IC0_DOMAIN, IC0_SUB_DOMAIN}, + replica_api::RejectResponse, AgentFuture, Transport, }, export::Principal, @@ -236,7 +237,19 @@ impl ReqwestTransport { } } - if status.is_client_error() || status.is_server_error() { + // status == OK means we have an error message for call requests + // see https://internetcomputer.org/docs/current/references/ic-interface-spec#http-call + if status == StatusCode::OK && endpoint.ends_with("call") { + let cbor_decoded_body: Result = + serde_cbor::from_slice(&body); + + let agent_error = match cbor_decoded_body { + Ok(replica_error) => AgentError::ReplicaError(replica_error), + Err(cbor_error) => AgentError::InvalidCborData(cbor_error), + }; + + Err(agent_error) + } else if status.is_client_error() || status.is_server_error() { Err(AgentError::HttpError(HttpErrorPayload { status: status.into(), content_type: headers diff --git a/ic-agent/src/agent/mod.rs b/ic-agent/src/agent/mod.rs index b8f77b56..35ebd694 100644 --- a/ic-agent/src/agent/mod.rs +++ b/ic-agent/src/agent/mod.rs @@ -15,6 +15,7 @@ pub use agent_error::AgentError; use backoff::{backoff::Backoff, ExponentialBackoffBuilder}; pub use builder::AgentBuilder; pub use nonce::{NonceFactory, NonceGenerator}; +pub use replica_api::{RejectCode, RejectResponse}; pub use response::{Replied, RequestStatusResponse}; #[cfg(test)] @@ -421,13 +422,9 @@ impl Agent { .await .and_then(|response| match response { replica_api::QueryResponse::Replied { reply } => Ok(reply.arg), - replica_api::QueryResponse::Rejected { - reject_code, - reject_message, - } => Err(AgentError::ReplicaError { - reject_code, - reject_message, - }), + replica_api::QueryResponse::Rejected(response) => { + Err(AgentError::ReplicaError(response)) + } }) } @@ -445,13 +442,9 @@ impl Agent { .await .and_then(|response| match response { replica_api::QueryResponse::Replied { reply } => Ok(reply.arg), - replica_api::QueryResponse::Rejected { - reject_code, - reject_message, - } => Err(AgentError::ReplicaError { - reject_code, - reject_message, - }), + replica_api::QueryResponse::Rejected(response) => { + Err(AgentError::ReplicaError(response)) + } }) } @@ -542,13 +535,8 @@ impl Agent { reply: Replied::CallReplied(arg), } => Ok(PollResult::Completed(arg)), - RequestStatusResponse::Rejected { - reject_code, - reject_message, - } => Err(AgentError::ReplicaError { - reject_code, - reject_message, - }), + RequestStatusResponse::Rejected(response) => Err(AgentError::ReplicaError(response)), + RequestStatusResponse::Done => Err(AgentError::RequestStatusDoneNoReply(String::from( *request_id, ))), diff --git a/ic-agent/src/agent/replica_api.rs b/ic-agent/src/agent/replica_api.rs index 552ecab1..505186e4 100644 --- a/ic-agent/src/agent/replica_api.rs +++ b/ic-agent/src/agent/replica_api.rs @@ -1,8 +1,9 @@ -use crate::export::Principal; +use crate::{export::Principal, AgentError}; use ic_certification::Label; use serde::{Deserialize, Serialize}; pub use ic_certification::{Certificate, Delegation}; +use serde_repr::{Deserialize_repr, Serialize_repr}; #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] @@ -146,8 +147,53 @@ pub enum QueryResponse { #[serde(rename = "replied")] Replied { reply: CallReply }, #[serde(rename = "rejected")] - Rejected { - reject_code: u64, - reject_message: String, - }, + Rejected(RejectResponse), +} + +/// An IC execution error received from the replica. +#[derive(Debug, Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq)] +pub struct RejectResponse { + /// The [reject code](https://smartcontracts.org/docs/interface-spec/index.html#reject-codes) returned by the replica. + pub reject_code: RejectCode, + /// The rejection message. + pub reject_message: String, + /// The optional [error code](https://smartcontracts.org/docs/interface-spec/index.html#error-codes) returned by the replica. + #[serde(default)] + pub error_code: Option, +} + +/// See the [interface spec](https://smartcontracts.org/docs/interface-spec/index.html#reject-codes). +#[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr, Ord, PartialOrd, +)] +#[repr(u8)] +pub enum RejectCode { + /// Fatal system error, retry unlikely to be useful + SysFatal = 1, + /// Transient system error, retry might be possible. + SysTransient = 2, + /// Invalid destination (e.g. canister/account does not exist) + DestinationInvalid = 3, + /// Explicit reject by the canister. + CanisterReject = 4, + /// Canister error (e.g., trap, no response) + CanisterError = 5, +} + +impl TryFrom for RejectCode { + type Error = AgentError; + + fn try_from(value: u64) -> Result { + match value { + 1 => Ok(RejectCode::SysFatal), + 2 => Ok(RejectCode::SysTransient), + 3 => Ok(RejectCode::DestinationInvalid), + 4 => Ok(RejectCode::CanisterReject), + 5 => Ok(RejectCode::CanisterError), + _ => Err(AgentError::MessageError(format!( + "Received an invalid reject code {}", + value + ))), + } + } } diff --git a/ic-agent/src/agent/response.rs b/ic-agent/src/agent/response.rs index f154a967..f0e18b39 100644 --- a/ic-agent/src/agent/response.rs +++ b/ic-agent/src/agent/response.rs @@ -1,3 +1,5 @@ +use super::replica_api::RejectResponse; + /// The response of /api/v2/canister//read_state with "request_status" request type. /// /// See [the HTTP interface specification](https://smartcontracts.org/docs/interface-spec/index.html#http-call-overview) for more details. @@ -15,12 +17,7 @@ pub enum RequestStatusResponse { reply: Replied, }, /// The request has been rejected. - Rejected { - /// The [reject code](https://smartcontracts.org/docs/interface-spec/index.html#reject-codes) from the replica. - reject_code: u64, - /// The rejection message. - reject_message: String, - }, + Rejected(RejectResponse), /// The call has been completed, and it has been long enough that the reply/reject data has been purged, but the call has not expired yet. Done, } diff --git a/ic-agent/src/agent/response_authentication.rs b/ic-agent/src/agent/response_authentication.rs index 4cbacab1..4090461a 100644 --- a/ic-agent/src/agent/response_authentication.rs +++ b/ic-agent/src/agent/response_authentication.rs @@ -3,6 +3,8 @@ use crate::{export::Principal, AgentError, RequestId}; use ic_certification::{Certificate, Label, LookupResult}; use std::str::from_utf8; +use super::replica_api::{RejectCode, RejectResponse}; + const DER_PREFIX: &[u8; 37] = b"\x30\x81\x82\x30\x1d\x06\x0d\x2b\x06\x01\x04\x01\x82\xdc\x7c\x05\x03\x01\x02\x01\x06\x0c\x2b\x06\x01\x04\x01\x82\xdc\x7c\x05\x03\x02\x01\x03\x61\x00"; const KEY_LENGTH: usize = 96; @@ -82,16 +84,17 @@ pub(crate) fn lookup_rejection( let reject_code = lookup_reject_code(certificate, request_id)?; let reject_message = lookup_reject_message(certificate, request_id)?; - Ok(RequestStatusResponse::Rejected { + Ok(RequestStatusResponse::Rejected(RejectResponse { reject_code, reject_message, - }) + error_code: None, + })) } pub(crate) fn lookup_reject_code( certificate: &Certificate, request_id: &RequestId, -) -> Result { +) -> Result { let path = [ "request_status".into(), request_id.to_vec().into(), @@ -99,7 +102,8 @@ pub(crate) fn lookup_reject_code( ]; let code = lookup_value(certificate, path)?; let mut readable = code; - Ok(leb128::read::unsigned(&mut readable)?) + let code_digit = leb128::read::unsigned(&mut readable)?; + RejectCode::try_from(code_digit) } pub(crate) fn lookup_reject_message( diff --git a/ic-utils/src/interfaces/wallet.rs b/ic-utils/src/interfaces/wallet.rs index 675566ed..6eaaad7c 100644 --- a/ic-utils/src/interfaces/wallet.rs +++ b/ic-utils/src/interfaces/wallet.rs @@ -15,7 +15,7 @@ use crate::{ }; use async_trait::async_trait; use candid::{decode_args, utils::ArgumentDecoder, CandidType, Deserialize, Nat}; -use ic_agent::{export::Principal, Agent, AgentError, RequestId}; +use ic_agent::{agent::RejectCode, export::Principal, Agent, AgentError, RequestId}; use once_cell::sync::Lazy; use semver::{Version, VersionReq}; @@ -427,12 +427,14 @@ impl<'agent> WalletCanister<'agent> { let version: Result<(String,), _> = canister.query_("wallet_api_version").build().call().await; let version = match version { - Err(AgentError::ReplicaError { - reject_code, - reject_message, - }) if reject_code == 3 - && (reject_message.contains(REPLICA_ERROR_NO_SUCH_QUERY_METHOD) - || reject_message.contains(IC_REF_ERROR_NO_SUCH_QUERY_METHOD)) => + Err(AgentError::ReplicaError(replica_error)) + if replica_error.reject_code == RejectCode::DestinationInvalid + && (replica_error + .reject_message + .contains(REPLICA_ERROR_NO_SUCH_QUERY_METHOD) + || replica_error + .reject_message + .contains(IC_REF_ERROR_NO_SUCH_QUERY_METHOD)) => { DEFAULT_VERSION.clone() } diff --git a/icx/src/main.rs b/icx/src/main.rs index ad4b47b9..6283f365 100644 --- a/icx/src/main.rs +++ b/icx/src/main.rs @@ -567,14 +567,12 @@ async fn main() -> Result<()> { print_idl_blob(&blob, &ArgType::Idl, &None) .context("Failed to print request_status result")?; } - agent::RequestStatusResponse::Rejected { - reject_code, - reject_message, - } => { + agent::RequestStatusResponse::Rejected(replica_error) => { bail!( - r#"The Replica returned an error: code {}, message: "{}""#, - reject_code, - reject_message + r#"The Replica returned an error. reject code: {:?}, reject message: "{}", error code: {}"#, + replica_error.reject_code, + replica_error.reject_message, + replica_error.error_code.unwrap_or_default() ); } _ => bail!("Can't get valid status of the request.",), diff --git a/ref-tests/tests/ic-ref.rs b/ref-tests/tests/ic-ref.rs index 168057eb..e4a6b939 100644 --- a/ref-tests/tests/ic-ref.rs +++ b/ref-tests/tests/ic-ref.rs @@ -38,7 +38,11 @@ fn spec_compliance_claimed() { mod management_canister { use candid::CandidType; - use ic_agent::{export::Principal, AgentError}; + use ic_agent::{ + agent::{RejectCode, RejectResponse}, + export::Principal, + AgentError, + }; use ic_utils::{ call::AsyncCall, interfaces::{ @@ -322,12 +326,18 @@ mod management_canister { // Only that controller can get canister status let result = ic00.canister_status(&canister_id).call_and_wait().await; - assert_err_or_reject(result, vec![3, 5]); + assert_err_or_reject( + result, + vec![RejectCode::DestinationInvalid, RejectCode::CanisterError], + ); let result = other_ic00 .canister_status(&canister_id) .call_and_wait() .await; - assert_err_or_reject(result, vec![3, 5]); + assert_err_or_reject( + result, + vec![RejectCode::DestinationInvalid, RejectCode::CanisterError], + ); let result = secp256k1_ic00 .canister_status(&canister_id) @@ -340,16 +350,21 @@ mod management_canister { }) } - fn assert_err_or_reject(result: Result, allowed_reject_codes: Vec) { + fn assert_err_or_reject( + result: Result, + allowed_reject_codes: Vec, + ) { for expected_rc in &allowed_reject_codes { - if matches!(result, Err(AgentError::ReplicaError { - reject_code: actual_rc, - reject_message: _, - }) if actual_rc == *expected_rc) + if matches!(result, + Err(AgentError::ReplicaError(RejectResponse { + reject_code, + .. + })) if reject_code == *expected_rc) { return; } } + assert!( matches!(result, Err(AgentError::HttpError(_))), "expect an HttpError, or a ReplicaError with reject_code in {:?}", @@ -392,17 +407,23 @@ mod management_canister { // Can't call update on a stopped canister let result = agent.update(&canister_id, "update").call_and_wait().await; - assert!(matches!(result, Err(AgentError::ReplicaError { - reject_code: 5, + assert!( + matches!(result, Err(AgentError::ReplicaError(RejectResponse{ + reject_code: RejectCode::CanisterError, reject_message, - }) if reject_message == "canister is not running")); + .. + })) if reject_message == "canister is not running") + ); // Can't call query on a stopped canister let result = agent.query(&canister_id, "query").with_arg([]).call().await; - assert!(matches!(result, Err(AgentError::ReplicaError { - reject_code: 5, - reject_message, - }) if reject_message == "canister is stopped")); + assert!( + matches!(result, Err(AgentError::ReplicaError(RejectResponse{ + reject_code: RejectCode::CanisterError, + reject_message, + .. + })) if reject_message == "canister is stopped") + ); // Upgrade should succeed ic00.install_code(&canister_id, &canister_wasm) @@ -419,17 +440,23 @@ mod management_canister { // Can call update let result = agent.update(&canister_id, "update").call_and_wait().await; - assert!(matches!(result, Err(AgentError::ReplicaError { - reject_code: 3, - reject_message, - }) if reject_message == "method does not exist: update")); + assert!( + matches!(result, Err(AgentError::ReplicaError(RejectResponse{ + reject_code: RejectCode::DestinationInvalid, + reject_message, + .. + })) if reject_message == "method does not exist: update") + ); // Can call query let result = agent.query(&canister_id, "query").with_arg([]).call().await; - assert!(matches!(result, Err(AgentError::ReplicaError { - reject_code: 3, - reject_message, - }) if reject_message == "query method does not exist")); + assert!( + matches!(result, Err(AgentError::ReplicaError(RejectResponse{ + reject_code: RejectCode::DestinationInvalid, + reject_message, + .. + })) if reject_message == "query method does not exist") + ); // Another start is a noop ic00.start_canister(&canister_id).call_and_wait().await?; @@ -452,11 +479,14 @@ mod management_canister { // Cannot call query let result = agent.query(&canister_id, "query").with_arg([]).call().await; - assert!(matches!(result, Err(AgentError::ReplicaError { - reject_code: 3, - reject_message, - }) if reject_message - == format!("canister no longer exists: {}", canister_id.to_text()))); + assert!( + matches!(result, Err(AgentError::ReplicaError(RejectResponse{ + reject_code: RejectCode::DestinationInvalid, + reject_message, + .. + })) if reject_message + == format!("canister no longer exists: {}", canister_id.to_text())) + ); // Cannot query canister status let result = ic00.canister_status(&canister_id).call_and_wait().await; @@ -674,7 +704,10 @@ mod management_canister { mod simple_calls { use crate::universal_canister::payload; - use ic_agent::AgentError; + use ic_agent::{ + agent::{RejectCode, RejectResponse}, + AgentError, + }; use ref_tests::with_universal_canister; #[ignore] @@ -722,7 +755,10 @@ mod simple_calls { assert!(matches!( result, - Err(AgentError::ReplicaError { reject_code: 3, .. }) + Err(AgentError::ReplicaError(RejectResponse { + reject_code: RejectCode::DestinationInvalid, + .. + })) )); Ok(()) }) @@ -741,7 +777,10 @@ mod simple_calls { assert!(matches!( result, - Err(AgentError::ReplicaError { reject_code: 3, .. }) + Err(AgentError::ReplicaError(RejectResponse { + reject_code: RejectCode::DestinationInvalid, + .. + })) )); Ok(()) }) @@ -750,7 +789,11 @@ mod simple_calls { mod extras { use candid::Nat; - use ic_agent::{export::Principal, AgentError}; + use ic_agent::{ + agent::{RejectCode, RejectResponse}, + export::Principal, + AgentError, + }; use ic_utils::{ call::AsyncCall, interfaces::{management_canister::builders::ComputeAllocation, ManagementCanister}, @@ -880,10 +923,13 @@ mod extras { .with_effective_canister_id(get_effective_canister_id()) .call_and_wait() .await; - assert!(matches!(result, Err(AgentError::ReplicaError { - reject_code: 3, + + assert!(matches!(result, + Err(AgentError::ReplicaError(RejectResponse { + reject_code: RejectCode::DestinationInvalid, reject_message, - }) if reject_message == "The specified_id of the created canister is already in use.")); + .. + })) if reject_message == "The specified_id of the created canister is already in use.")); Ok(()) }) diff --git a/ref-tests/tests/integration.rs b/ref-tests/tests/integration.rs index 493d6860..5a9abdf5 100644 --- a/ref-tests/tests/integration.rs +++ b/ref-tests/tests/integration.rs @@ -18,6 +18,8 @@ use ref_tests::{ with_wallet_canister, }; +use ic_agent::agent::{RejectCode, RejectResponse}; + #[ignore] #[test] fn basic_expiry() { @@ -98,10 +100,11 @@ fn canister_reject_call() { assert_eq!( result, - Err(AgentError::ReplicaError { - reject_code: 3, - reject_message: "method does not exist: wallet_send".to_string() - }) + Err(AgentError::ReplicaError(RejectResponse { + reject_code: RejectCode::DestinationInvalid, + reject_message: "method does not exist: wallet_send".to_string(), + error_code: None + })) ); Ok(()) From f0f502dfd217fbc0f5c7a656f2b7b3918ed2c3c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Apr 2023 15:08:41 -0700 Subject: [PATCH 07/30] chore(deps): bump openssl from 0.10.47 to 0.10.51 (#427) Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.47 to 0.10.51. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.47...openssl-v0.10.51) --- updated-dependencies: - dependency-name: openssl dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d34b11e..16b7471f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1540,9 +1540,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.47" +version = "0.10.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b277f87dacc05a6b709965d1cbafac4649d6ce9f3ce9ceb88508b5666dfec9" +checksum = "97ea2d98598bf9ada7ea6ee8a30fb74f9156b63bbe495d64ec2b87c269d2dda3" dependencies = [ "bitflags", "cfg-if", @@ -1572,11 +1572,10 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.82" +version = "0.9.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a95792af3c4e0153c3914df2261bedd30a98476f94dc892b67dfe1d89d433a04" +checksum = "992bac49bdbab4423199c654a5515bd2a6c6a23bf03f2dd3bdb7e5ae6259bc69" dependencies = [ - "autocfg", "cc", "libc", "pkg-config", From 60fccdf42b3b23f3a4c0dee926a5f4078645eb77 Mon Sep 17 00:00:00 2001 From: Daniel Sharifi <40335219+DSharifi@users.noreply.github.com> Date: Mon, 24 Apr 2023 16:01:16 +0200 Subject: [PATCH 08/30] chore: Clean up imports introduced in PR #422 (#429) --- ic-agent/src/agent/agent_error.rs | 1 - ic-agent/src/agent/response.rs | 2 +- ic-agent/src/agent/response_authentication.rs | 4 +--- ref-tests/tests/integration.rs | 8 +++++--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ic-agent/src/agent/agent_error.rs b/ic-agent/src/agent/agent_error.rs index fcd106b4..d49da6a7 100644 --- a/ic-agent/src/agent/agent_error.rs +++ b/ic-agent/src/agent/agent_error.rs @@ -4,7 +4,6 @@ use crate::{ agent::{replica_api::RejectResponse, status::Status}, RequestIdError, }; -// use crate::{agent::status::Status, RequestIdError}; use ic_certification::Label; use leb128::read; use std::{ diff --git a/ic-agent/src/agent/response.rs b/ic-agent/src/agent/response.rs index f0e18b39..4ee469d6 100644 --- a/ic-agent/src/agent/response.rs +++ b/ic-agent/src/agent/response.rs @@ -1,4 +1,4 @@ -use super::replica_api::RejectResponse; +use crate::agent::replica_api::RejectResponse; /// The response of /api/v2/canister//read_state with "request_status" request type. /// diff --git a/ic-agent/src/agent/response_authentication.rs b/ic-agent/src/agent/response_authentication.rs index 4090461a..ceb32e4a 100644 --- a/ic-agent/src/agent/response_authentication.rs +++ b/ic-agent/src/agent/response_authentication.rs @@ -1,10 +1,8 @@ -use crate::agent::{Replied, RequestStatusResponse}; +use crate::agent::{RejectCode, RejectResponse, Replied, RequestStatusResponse}; use crate::{export::Principal, AgentError, RequestId}; use ic_certification::{Certificate, Label, LookupResult}; use std::str::from_utf8; -use super::replica_api::{RejectCode, RejectResponse}; - const DER_PREFIX: &[u8; 37] = b"\x30\x81\x82\x30\x1d\x06\x0d\x2b\x06\x01\x04\x01\x82\xdc\x7c\x05\x03\x01\x02\x01\x06\x0c\x2b\x06\x01\x04\x01\x82\xdc\x7c\x05\x03\x02\x01\x03\x61\x00"; const KEY_LENGTH: usize = 96; diff --git a/ref-tests/tests/integration.rs b/ref-tests/tests/integration.rs index 5a9abdf5..f880b3f5 100644 --- a/ref-tests/tests/integration.rs +++ b/ref-tests/tests/integration.rs @@ -3,7 +3,11 @@ //! Contrary to ic-ref.rs, these tests are not meant to match any other tests. They're //! integration tests with a running IC-Ref. use candid::CandidType; -use ic_agent::{agent::agent_error::HttpErrorPayload, export::Principal, AgentError}; +use ic_agent::{ + agent::{agent_error::HttpErrorPayload, RejectCode, RejectResponse}, + export::Principal, + AgentError, +}; use ic_utils::{ call::{AsyncCall, SyncCall}, interfaces::{ @@ -18,8 +22,6 @@ use ref_tests::{ with_wallet_canister, }; -use ic_agent::agent::{RejectCode, RejectResponse}; - #[ignore] #[test] fn basic_expiry() { From fdec776f7aed8bc6788c738ec5116aace501e2a6 Mon Sep 17 00:00:00 2001 From: Ioannis Mourginakis Date: Mon, 24 Apr 2023 10:29:17 -0700 Subject: [PATCH 09/30] fix: update `icx-cert` reqwest call to include a user agent (#419) --- CHANGELOG.md | 3 +++ icx-cert/src/pprint.rs | 1 + 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba52b1a2..dd8bb4b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Support WASM targets in the browser via `wasm-bindgen` +### icx-cert +* Fixed issue where a missing request header caused the canister to not respond with an `ic-certificate` header. + ## [0.23.2] - 2023-04-21 * Expose the root key to clients through `read_root_key` diff --git a/icx-cert/src/pprint.rs b/icx-cert/src/pprint.rs index ea8ae0ef..99aa7436 100644 --- a/icx-cert/src/pprint.rs +++ b/icx-cert/src/pprint.rs @@ -77,6 +77,7 @@ pub fn pprint(url: String, accept_encodings: Option>) -> Result<()> client }; client + .user_agent("icx-cert") .build()? .get(url) .send() From eaee7373d7c26b395d3291e53c1eb3fd656acb56 Mon Sep 17 00:00:00 2001 From: Nathan Mc Grath Date: Tue, 25 Apr 2023 00:06:22 -0700 Subject: [PATCH 10/30] fix: do not send certificate_version on http update requests (#417) --- CHANGELOG.md | 1 + ic-utils/src/interfaces/http_request.rs | 27 +++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd8bb4b7..fe830cb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Reject code type is changed from `u64` to enum `RejectCode`. * Support WASM targets in the browser via `wasm-bindgen` +* Do not send `certificate_version` on HTTP Update requests ### icx-cert * Fixed issue where a missing request header caused the canister to not respond with an `ic-certificate` header. diff --git a/ic-utils/src/interfaces/http_request.rs b/ic-utils/src/interfaces/http_request.rs index 93489198..45f2e501 100644 --- a/ic-utils/src/interfaces/http_request.rs +++ b/ic-utils/src/interfaces/http_request.rs @@ -51,6 +51,20 @@ struct HttpRequest<'a, H> { pub certificate_version: Option<&'a u128>, } +/// The important components of an HTTP update request. +/// This is the same as `HttpRequest`, excluding the `certificate_version` property. +#[derive(Debug, Clone, CandidType)] +struct HttpUpdateRequest<'a, H> { + /// The HTTP method string. + pub method: &'a str, + /// The URL that was visited. + pub url: &'a str, + /// The request headers. + pub headers: H, + /// The request body. + pub body: &'a [u8], +} + /// A wrapper around an iterator of headers #[derive(Debug, Clone)] pub struct Headers(H); @@ -443,15 +457,8 @@ impl<'agent> HttpRequestCanister<'agent> { url: impl AsRef, headers: impl 'agent + Send + Sync + Clone + ExactSizeIterator>, body: impl AsRef<[u8]>, - certificate_version: Option<&u128>, ) -> impl 'agent + AsyncCall<(HttpResponse,)> { - self.http_request_update_custom( - method.as_ref(), - url.as_ref(), - headers, - body.as_ref(), - certificate_version, - ) + self.http_request_update_custom(method.as_ref(), url.as_ref(), headers, body.as_ref()) } /// Performs a HTTP request over an update call. Unlike query calls, update calls must pass consensus @@ -463,7 +470,6 @@ impl<'agent> HttpRequestCanister<'agent> { url: &str, headers: H, body: &[u8], - certificate_version: Option<&u128>, ) -> impl 'agent + AsyncCall<(HttpResponse,)> where H: 'agent + Send + Sync + Clone + ExactSizeIterator>, @@ -471,12 +477,11 @@ impl<'agent> HttpRequestCanister<'agent> { C: 'agent + Send + Sync + CandidType + for<'de> Deserialize<'de>, { self.update_("http_request_update") - .with_arg(HttpRequest { + .with_arg(HttpUpdateRequest { method, url, headers: Headers(headers), body, - certificate_version, }) .build() } From e5ecfa201f696580d83a7d563fa0c9cf83946aee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 10:09:00 +0200 Subject: [PATCH 11/30] chore(deps): bump h2 from 0.3.16 to 0.3.18 (#426) Bumps [h2](https://github.com/hyperium/h2) from 0.3.16 to 0.3.18. - [Release notes](https://github.com/hyperium/h2/releases) - [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/h2/compare/v0.3.16...v0.3.18) --- updated-dependencies: - dependency-name: h2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eric Swanson <64809312+ericswanson-dfinity@users.noreply.github.com> Co-authored-by: Severin Siffert --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16b7471f..fdc88dc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -831,9 +831,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" dependencies = [ "bytes", "fnv", From 56b3e4b69f31b3694e2287a8852c12d2017e8e06 Mon Sep 17 00:00:00 2001 From: Nathan Mc Grath Date: Thu, 27 Apr 2023 18:13:06 -0700 Subject: [PATCH 12/30] fix: http_request not matching expected candid (#432) --- CHANGELOG.md | 1 + ic-utils/src/interfaces/http_request.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe830cb1..8f44377d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Support WASM targets in the browser via `wasm-bindgen` * Do not send `certificate_version` on HTTP Update requests +* Update `certificate_version` to `u16` instead of `u128`, fixes an issue where the asset canister always responds with v1 response verification ### icx-cert * Fixed issue where a missing request header caused the canister to not respond with an `ic-certificate` header. diff --git a/ic-utils/src/interfaces/http_request.rs b/ic-utils/src/interfaces/http_request.rs index 45f2e501..4e7fe37e 100644 --- a/ic-utils/src/interfaces/http_request.rs +++ b/ic-utils/src/interfaces/http_request.rs @@ -48,7 +48,7 @@ struct HttpRequest<'a, H> { /// The request body. pub body: &'a [u8], /// The certificate version. - pub certificate_version: Option<&'a u128>, + pub certificate_version: Option<&'a u16>, } /// The important components of an HTTP update request. @@ -412,7 +412,7 @@ impl<'agent> HttpRequestCanister<'agent> { IntoIter = impl 'agent + Send + Sync + Clone + ExactSizeIterator>, >, body: impl AsRef<[u8]>, - certificate_version: Option<&u128>, + certificate_version: Option<&u16>, ) -> impl 'agent + SyncCall<(HttpResponse,)> { self.http_request_custom( method.as_ref(), @@ -431,7 +431,7 @@ impl<'agent> HttpRequestCanister<'agent> { url: &str, headers: H, body: &[u8], - certificate_version: Option<&u128>, + certificate_version: Option<&u16>, ) -> impl 'agent + SyncCall<(HttpResponse,)> where H: 'agent + Send + Sync + Clone + ExactSizeIterator>, From 5881513cb98a70150882e27bcb544e8ddbfbaf1a Mon Sep 17 00:00:00 2001 From: Rostislav Rumenov Date: Fri, 28 Apr 2023 21:28:40 +0200 Subject: [PATCH 13/30] feat: remove the PasswordManager (#431) --- CHANGELOG.md | 1 + Cargo.lock | 109 ++++++++++++------ ic-agent/Cargo.toml | 11 +- ic-agent/src/agent/agent_error.rs | 16 --- .../agent/http_transport/reqwest_transport.rs | 97 +--------------- ic-agent/src/identity/basic.rs | 2 +- ic-agent/src/identity/secp256k1.rs | 8 +- ic-agent/src/lib.rs | 3 +- 8 files changed, 88 insertions(+), 159 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f44377d..4367e822 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +* Breaking Change: removing the PasswordManager * Breaking Change: Enum variant `AgentError::ReplicaError` is now a tuple struct containing `RejectResponse`. * Handling rejected update calls where status code is 200. See IC-1462 * Reject code type is changed from `u64` to enum `RejectCode`. diff --git a/Cargo.lock b/Cargo.lock index fdc88dc4..c7432087 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "base16ct" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base32" @@ -228,8 +228,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3c196a77437e7cc2fb515ce413a6401291578b5afc8ecb29a3c7ab957f05941" dependencies = [ "digest 0.9.0", - "ff", - "group", + "ff 0.12.1", + "group 0.12.1", "pairing", "rand_core", "subtle", @@ -439,9 +439,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.4.9" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array", "rand_core", @@ -511,9 +511,9 @@ checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" [[package]] name = "der" -version = "0.6.1" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +checksum = "05e58dffcdcc8ee7b22f0c1f71a69243d7c2d9ad87b5a14361f2424a1565c219" dependencies = [ "const-oid", "pem-rfc7468", @@ -542,6 +542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] @@ -569,11 +570,12 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.14.8" +version = "0.16.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd" dependencies = [ "der", + "digest 0.10.6", "elliptic-curve", "rfc6979", "signature", @@ -587,17 +589,16 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" -version = "0.12.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7" dependencies = [ "base16ct", "crypto-bigint", - "der", "digest 0.10.6", - "ff", + "ff 0.13.0", "generic-array", - "group", + "group 0.13.0", "pem-rfc7468", "pkcs8", "rand_core", @@ -664,6 +665,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -791,12 +802,13 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -824,7 +836,18 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "ff", + "ff 0.12.1", + "rand_core", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", "rand_core", "subtle", ] @@ -1029,7 +1052,6 @@ dependencies = [ "async-trait", "backoff", "base32", - "base64 0.13.1", "byteorder", "candid", "futures-util", @@ -1046,7 +1068,7 @@ dependencies = [ "leb128", "mime", "mockito", - "pem", + "pem 2.0.1", "pkcs8", "rand", "reqwest", @@ -1138,7 +1160,7 @@ dependencies = [ "humantime", "ic-agent", "ic-utils", - "pem", + "pem 1.1.1", "ring", "serde", "serde_json", @@ -1240,14 +1262,16 @@ dependencies = [ [[package]] name = "k256" -version = "0.11.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", + "once_cell", "sha2 0.10.6", + "signature", ] [[package]] @@ -1594,7 +1618,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b" dependencies = [ - "group", + "group 0.12.1", ] [[package]] @@ -1635,11 +1659,21 @@ dependencies = [ "base64 0.13.1", ] +[[package]] +name = "pem" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b13fe415cdf3c8e44518e18a7c95a13431d9bdf6d15367d82b23c377fdd441a" +dependencies = [ + "base64 0.21.0", + "serde", +] + [[package]] name = "pem-rfc7468" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ "base64ct", ] @@ -1699,9 +1733,9 @@ dependencies = [ [[package]] name = "pkcs8" -version = "0.9.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "spki", @@ -1915,13 +1949,12 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "crypto-bigint", "hmac", - "zeroize", + "subtle", ] [[package]] @@ -2043,9 +2076,9 @@ dependencies = [ [[package]] name = "sec1" -version = "0.3.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" dependencies = [ "base16ct", "der", @@ -2192,9 +2225,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.6.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest 0.10.6", "rand_core", @@ -2257,9 +2290,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spki" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" dependencies = [ "base64ct", "der", diff --git a/ic-agent/Cargo.toml b/ic-agent/Cargo.toml index 1f1d1e1a..a268238a 100644 --- a/ic-agent/Cargo.toml +++ b/ic-agent/Cargo.toml @@ -18,17 +18,19 @@ include = ["src", "Cargo.toml", "../LICENSE", "README.md"] async-trait = "0.1.53" backoff = "0.4.0" base32 = "0.4.0" -base64 = "0.13.0" byteorder = "1.3.2" candid = { workspace = true } futures-util = "0.3.21" hex = { workspace = true } http = "0.2.6" http-body = "0.4.5" +ic-certification = { path = "../ic-certification", version = "0.23" } ic-verify-bls-signature = "0.1" -k256 = { version = "0.11", features = ["pem"] } +k256 = { version = "0.13.1", features = ["pem"] } leb128 = "0.2.5" mime = "0.3.16" +pkcs8 = { version = "0.10.2", features = ["std"] } +sec1 = { version = "0.7.2", features = ["pem"] } rand = "0.8.5" ring = { workspace = true, features = ["std"] } serde = { workspace = true, features = ["derive"] } @@ -39,9 +41,6 @@ sha2 = { workspace = true } simple_asn1 = "0.6.1" thiserror = { workspace = true } url = "2.1.0" -pkcs8 = { version = "0.9", features = ["std"] } -sec1 = { version = "0.3", features = ["pem"] } -ic-certification = { path = "../ic-certification", version = "0.23" } [dependencies.hyper] version = "0.14" @@ -55,7 +54,7 @@ features = ["blocking", "json", "rustls-tls", "stream"] optional = true [dependencies.pem] -version = "1.0" +version = "2.0.1" optional = true [target.'cfg(not(target_family = "wasm"))'.dependencies] diff --git a/ic-agent/src/agent/agent_error.rs b/ic-agent/src/agent/agent_error.rs index d49da6a7..11344034 100644 --- a/ic-agent/src/agent/agent_error.rs +++ b/ic-agent/src/agent/agent_error.rs @@ -59,14 +59,6 @@ pub enum AgentError { #[error("The replica returned an HTTP Error: {0}")] HttpError(HttpErrorPayload), - /// Attempted to use HTTP authentication in a non-secure URL (either HTTPS or localhost). - #[error("HTTP Authentication cannot be used in a non-secure URL (either HTTPS or localhost)")] - CannotUseAuthenticationOnNonSecureUrl(), - - /// The password manager returned an error. - #[error("Password Manager returned an error: {0}")] - AuthenticationError(String), - /// The status endpoint returned an invalid status. #[error("Status endpoint returned an invalid status.")] InvalidReplicaStatus, @@ -79,10 +71,6 @@ pub enum AgentError { #[error("A tool returned a string message error: {0}")] MessageError(String), - /// An error occurred in an external tool. - #[error("A tool returned a custom error: {0}")] - CustomError(#[from] Box), - /// There was an error reading a LEB128 value. #[error("Error reading LEB128 value: {0}")] Leb128ReadError(#[from] read::Error), @@ -143,10 +131,6 @@ pub enum AgentError { #[error("Could not read the root key")] CouldNotReadRootKey(), - /// Failed to initialize the BLS library. - #[error("Failed to initialize the BLS library")] - BlsInitializationFailure(), - /// The invocation to the wallet call forward method failed with an error. #[error("The invocation to the wallet call forward method failed with the error: {0}")] WalletCallFailed(String), diff --git a/ic-agent/src/agent/http_transport/reqwest_transport.rs b/ic-agent/src/agent/http_transport/reqwest_transport.rs index 841d3301..b978bdc5 100644 --- a/ic-agent/src/agent/http_transport/reqwest_transport.rs +++ b/ic-agent/src/agent/http_transport/reqwest_transport.rs @@ -3,13 +3,11 @@ pub use reqwest; -use std::sync::Arc; - use futures_util::StreamExt; #[cfg(not(target_family = "wasm"))] use hyper_rustls::ConfigBuilderExt; use reqwest::{ - header::{HeaderMap, AUTHORIZATION, CONTENT_TYPE}, + header::{HeaderMap, CONTENT_TYPE}, Body, Client, Method, Request, StatusCode, Url, }; @@ -24,41 +22,11 @@ use crate::{ AgentError, RequestId, }; -/// Implemented by the Agent environment to cache and update an HTTP Auth password. -/// It returns a tuple of `(username, password)`. -pub trait PasswordManager: Send + Sync { - /// Retrieve the cached value for a user. If no cache value exists for this URL, - /// the manager can return [`None`]. - fn cached(&self, url: &str) -> Result, String>; - - /// A call to the replica failed, so in order to succeed a username and password - /// is required. If one cannot be provided (for example, there's no terminal), - /// this should return an error. - /// If the username and password provided by this method does not work (the next - /// request still returns UNAUTHORIZED), this will be called and the request will - /// be retried in a loop. - fn required(&self, url: &str) -> Result<(String, String), String>; -} - -impl dyn PasswordManager { - fn get(&self, cached: bool, url: &str) -> Result, AgentError> { - if cached { - self.cached(url) - } else { - self.required(url).map(Some) - } - .map_err(AgentError::AuthenticationError) - } -} - -impl_debug_empty!(dyn PasswordManager); - /// A [`Transport`] using [`reqwest`] to make HTTP calls to the Internet Computer. #[derive(Debug)] pub struct ReqwestTransport { url: Url, client: Client, - password_manager: Option>, max_response_body_size: Option, } @@ -108,24 +76,10 @@ impl ReqwestTransport { }) .map_err(|_| AgentError::InvalidReplicaUrl(url.clone()))?, client, - password_manager: None, max_response_body_size: None, }) } - /// Sets a password manager to use with HTTP authentication. - pub fn with_password_manager(self, password_manager: P) -> Self { - self.with_arc_password_manager(Arc::new(password_manager)) - } - - /// Same as [`Self::with_password_manager`], but providing the Arc so one does not have to be created. - pub fn with_arc_password_manager(self, password_manager: Arc) -> Self { - ReqwestTransport { - password_manager: Some(password_manager), - ..self - } - } - /// Sets a max response body size limit pub fn with_max_response_body_size(self, max_response_body_size: usize) -> Self { ReqwestTransport { @@ -134,27 +88,6 @@ impl ReqwestTransport { } } - /// Gets the set password manager, if one exists. Otherwise returns None. - pub fn password_manager(&self) -> Option<&dyn PasswordManager> { - self.password_manager.as_deref() - } - - fn maybe_add_authorization( - &self, - http_request: &mut Request, - cached: bool, - ) -> Result<(), AgentError> { - if let Some(pm) = &self.password_manager { - if let Some((u, p)) = pm.get(cached, http_request.url().as_str())? { - let auth = base64::encode(&format!("{}:{}", u, p)); - http_request - .headers_mut() - .insert(AUTHORIZATION, format!("Basic {}", auth).parse().unwrap()); - } - } - Ok(()) - } - async fn request( &self, http_request: Request, @@ -210,32 +143,12 @@ impl ReqwestTransport { .headers_mut() .insert(CONTENT_TYPE, "application/cbor".parse().unwrap()); - self.maybe_add_authorization(&mut http_request, true)?; - *http_request.body_mut() = body.map(Body::from); - let mut status; - let mut headers; - let mut body; - loop { - let request_result = self.request(http_request.try_clone().unwrap()).await?; - status = request_result.0; - headers = request_result.1; - body = request_result.2; - - // If the server returned UNAUTHORIZED, and it is the first time we replay the call, - // check if we can get the username/password for the HTTP Auth. - if status == StatusCode::UNAUTHORIZED { - if self.url.scheme() == "https" || self.url.host_str() == Some("localhost") { - // If there is a password manager, get the username and password from it. - self.maybe_add_authorization(&mut http_request, false)?; - } else { - return Err(AgentError::CannotUseAuthenticationOnNonSecureUrl()); - } - } else { - break; - } - } + let request_result = self.request(http_request.try_clone().unwrap()).await?; + let status = request_result.0; + let headers = request_result.1; + let body = request_result.2; // status == OK means we have an error message for call requests // see https://internetcomputer.org/docs/current/references/ic-interface-spec#http-call diff --git a/ic-agent/src/identity/basic.rs b/ic-agent/src/identity/basic.rs index 6428cab4..d206f5f5 100644 --- a/ic-agent/src/identity/basic.rs +++ b/ic-agent/src/identity/basic.rs @@ -40,7 +40,7 @@ impl BasicIdentity { .collect::, std::io::Error>>()?; Ok(BasicIdentity::from_key_pair(Ed25519KeyPair::from_pkcs8( - pem::parse(&bytes)?.contents.as_slice(), + pem::parse(&bytes)?.contents(), )?)) } diff --git a/ic-agent/src/identity/secp256k1.rs b/ic-agent/src/identity/secp256k1.rs index 6ae15e79..db3d180a 100644 --- a/ic-agent/src/identity/secp256k1.rs +++ b/ic-agent/src/identity/secp256k1.rs @@ -39,15 +39,15 @@ impl Secp256k1Identity { let contents = pem_reader.bytes().collect::, io::Error>>()?; for pem in pem::parse_many(contents)? { - if pem.tag == EC_PARAMETERS && pem.contents != SECP256K1 { - return Err(PemError::UnsupportedKeyCurve(pem.contents)); + if pem.tag() == EC_PARAMETERS && pem.contents() != SECP256K1 { + return Err(PemError::UnsupportedKeyCurve(pem.contents().to_vec())); } - if pem.tag != EcPrivateKey::PEM_LABEL { + if pem.tag() != EcPrivateKey::PEM_LABEL { continue; } let private_key = - SecretKey::from_sec1_der(&pem.contents).map_err(|_| pkcs8::Error::KeyMalformed)?; + SecretKey::from_sec1_der(pem.contents()).map_err(|_| pkcs8::Error::KeyMalformed)?; return Ok(Self::from_private_key(private_key)); } Err(pem::PemError::MissingData.into()) diff --git a/ic-agent/src/lib.rs b/ic-agent/src/lib.rs index ce68e133..1f334b1a 100644 --- a/ic-agent/src/lib.rs +++ b/ic-agent/src/lib.rs @@ -133,5 +133,4 @@ pub use identity::{Identity, Signature}; pub use request_id::{to_request_id, RequestId, RequestIdError}; // Re-export from ic_certification for backward compatibility. -pub use ic_certification::hash_tree; -pub use ic_certification::Certificate; +pub use ic_certification::{hash_tree, Certificate}; From 71987142bb94a55ac0cb74a52396e01b6a142a16 Mon Sep 17 00:00:00 2001 From: Rostislav Rumenov Date: Mon, 1 May 2023 19:05:55 +0200 Subject: [PATCH 14/30] chore: remove deprecated code and fix style (#433) --- CHANGELOG.md | 1 + ic-agent/src/agent/agent_config.rs | 1 - ic-agent/src/agent/builder.rs | 2 +- ic-agent/src/agent/mod.rs | 24 ++++++++++-------------- ic-agent/src/agent/nonce.rs | 4 +--- ic-agent/src/agent/signed.rs | 2 +- ic-agent/src/identity/mod.rs | 2 -- ic-agent/src/lib.rs | 6 +----- ic-agent/src/macros.rs | 9 --------- ic-agent/src/request_id/error.rs | 24 ------------------------ ic-asset/README.md | 3 --- icx-asset/README.md | 3 --- 12 files changed, 15 insertions(+), 66 deletions(-) delete mode 100644 ic-agent/src/macros.rs delete mode 100644 ic-asset/README.md delete mode 100644 icx-asset/README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 4367e822..e88a80b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +* chore: remove deprecated code and fix style * Breaking Change: removing the PasswordManager * Breaking Change: Enum variant `AgentError::ReplicaError` is now a tuple struct containing `RejectResponse`. * Handling rejected update calls where status code is 200. See IC-1462 diff --git a/ic-agent/src/agent/agent_config.rs b/ic-agent/src/agent/agent_config.rs index 3ef9fde7..1a174bd3 100644 --- a/ic-agent/src/agent/agent_config.rs +++ b/ic-agent/src/agent/agent_config.rs @@ -5,7 +5,6 @@ use crate::{ use std::{sync::Arc, time::Duration}; /// A configuration for an agent. -#[derive(Debug)] pub struct AgentConfig { /// See [`with_nonce_factory`](super::AgentBuilder::with_nonce_factory). pub nonce_factory: Arc, diff --git a/ic-agent/src/agent/builder.rs b/ic-agent/src/agent/builder.rs index 9bdd6e1f..bfd9f1b1 100644 --- a/ic-agent/src/agent/builder.rs +++ b/ic-agent/src/agent/builder.rs @@ -5,7 +5,7 @@ use crate::{ use std::sync::Arc; /// A builder for an [`Agent`]. -#[derive(Debug, Default)] +#[derive(Default)] pub struct AgentBuilder { config: AgentConfig, } diff --git a/ic-agent/src/agent/mod.rs b/ic-agent/src/agent/mod.rs index 35ebd694..d43db911 100644 --- a/ic-agent/src/agent/mod.rs +++ b/ic-agent/src/agent/mod.rs @@ -7,12 +7,11 @@ pub(crate) mod nonce; pub(crate) mod replica_api; pub(crate) mod response; pub(crate) mod response_authentication; - pub mod signed; pub mod status; + pub use agent_config::AgentConfig; pub use agent_error::AgentError; -use backoff::{backoff::Backoff, ExponentialBackoffBuilder}; pub use builder::AgentBuilder; pub use nonce::{NonceFactory, NonceGenerator}; pub use replica_api::{RejectCode, RejectResponse}; @@ -22,21 +21,23 @@ pub use response::{Replied, RequestStatusResponse}; mod agent_test; use crate::{ - agent::replica_api::{ - CallRequestContent, Envelope, QueryContent, ReadStateContent, ReadStateResponse, + agent::{ + replica_api::{ + CallRequestContent, Envelope, QueryContent, ReadStateContent, ReadStateResponse, + }, + response_authentication::{ + extract_der, lookup_canister_info, lookup_canister_metadata, lookup_request_status, + lookup_value, + }, }, export::Principal, identity::Identity, to_request_id, RequestId, }; +use backoff::{backoff::Backoff, ExponentialBackoffBuilder}; use ic_certification::{Certificate, Delegation, Label}; use serde::Serialize; use status::Status; - -use crate::agent::response_authentication::{ - extract_der, lookup_canister_info, lookup_canister_metadata, lookup_request_status, - lookup_value, -}; use std::{ convert::TryFrom, fmt, @@ -101,11 +102,6 @@ pub trait Transport: Send + Sync { fn status(&self) -> AgentFuture>; } -#[doc(hidden)] -pub use Transport as ReplicaV2Transport; // deprecate after 0.24 - -impl_debug_empty!(dyn Transport); - impl Transport for Box { fn call( &self, diff --git a/ic-agent/src/agent/nonce.rs b/ic-agent/src/agent/nonce.rs index a83c2e0a..380d6d6c 100644 --- a/ic-agent/src/agent/nonce.rs +++ b/ic-agent/src/agent/nonce.rs @@ -5,7 +5,7 @@ use std::sync::{ }; /// A Factory for nonce blobs. -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct NonceFactory { inner: Arc, } @@ -57,8 +57,6 @@ pub trait NonceGenerator: Send + Sync { fn generate(&self) -> Option>; } -impl_debug_empty!(dyn NonceGenerator); - pub struct Func(pub T); impl Option>> NonceGenerator for Func { fn generate(&self) -> Option> { diff --git a/ic-agent/src/agent/signed.rs b/ic-agent/src/agent/signed.rs index 1fe5964c..ddcf6b75 100644 --- a/ic-agent/src/agent/signed.rs +++ b/ic-agent/src/agent/signed.rs @@ -1,4 +1,4 @@ -//! Types representing signed ingress messages. +//! Types representing signed messages. use crate::{export::Principal, RequestId}; diff --git a/ic-agent/src/identity/mod.rs b/ic-agent/src/identity/mod.rs index 895030bd..462ab00b 100644 --- a/ic-agent/src/identity/mod.rs +++ b/ic-agent/src/identity/mod.rs @@ -38,5 +38,3 @@ pub trait Identity: Send + Sync { /// creating the sender signature. fn sign(&self, blob: &[u8]) -> Result; } - -impl_debug_empty!(dyn Identity); diff --git a/ic-agent/src/lib.rs b/ic-agent/src/lib.rs index 1f334b1a..4c3ea873 100644 --- a/ic-agent/src/lib.rs +++ b/ic-agent/src/lib.rs @@ -1,5 +1,5 @@ //! The `ic-agent` is a simple-to-use library that enables you to -//! build applications and interact with the [Internet Computer](https://dfinity.org) +//! build applications and interact with the [Internet Computer](https://internetcomputer.org) //! in Rust. It serves as a Rust-based low-level backend for the //! DFINITY Canister Software Development Kit (SDK) and the //! [Canister SDK](https://sdk.dfinity.org) command-line execution environment @@ -106,7 +106,6 @@ #![deny( missing_docs, - missing_debug_implementations, rustdoc::broken_intra_doc_links, rustdoc::private_intra_doc_links )] @@ -114,9 +113,6 @@ #[cfg(all(feature = "hyper", target_family = "wasm"))] compile_error!("Feature `hyper` cannot be used from WASM."); -#[macro_use] -mod macros; - pub mod agent; pub mod export; pub mod identity; diff --git a/ic-agent/src/macros.rs b/ic-agent/src/macros.rs deleted file mode 100644 index 12a67ea1..00000000 --- a/ic-agent/src/macros.rs +++ /dev/null @@ -1,9 +0,0 @@ -macro_rules! impl_debug_empty { - ($name:ty) => { - impl std::fmt::Debug for $name { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(concat!("? ", stringify!($name))) - } - } - }; -} diff --git a/ic-agent/src/request_id/error.rs b/ic-agent/src/request_id/error.rs index 8954545b..a585ca23 100644 --- a/ic-agent/src/request_id/error.rs +++ b/ic-agent/src/request_id/error.rs @@ -35,21 +35,6 @@ pub enum RequestIdError { /// The serializer received a `bool`, which it does not support. #[error("Unsupported type: Bool")] UnsupportedTypeBool, - /// The serializer received a `u8`, which it does not support. - #[error("Unsupported type: U8")] - UnsupportedTypeU8, - /// The serializer received a `u16`, which it does not support. - #[error("Unsupported type: U16")] - UnsupportedTypeU16, - /// The serializer received a `u32`, which it does not support. - #[error("Unsupported type: U32")] - UnsupportedTypeU32, - /// The serializer received a `u64`, which it does not support. - #[error("Unsupported type: U64")] - UnsupportedTypeU64, - /// The serializer received a `u128`, which it does not support. - #[error("Unsupported type: U128")] - UnsupportedTypeU128, /// The serializer received a `i8`, which it does not support. #[error("Unsupported type: I8")] UnsupportedTypeI8, @@ -62,9 +47,6 @@ pub enum RequestIdError { /// The serializer received a `i64`, which it does not support. #[error("Unsupported type: I64")] UnsupportedTypeI64, - /// The serializer received a `i128`, which it does not support. - #[error("Unsupported type: I128")] - UnsupportedTypeI128, /// The serializer received a `f32`, which it does not support. #[error("Unsupported type: F32")] UnsupportedTypeF32, @@ -75,9 +57,6 @@ pub enum RequestIdError { #[error("Unsupported type: Char")] UnsupportedTypeChar, // UnsupportedTypeStr, // Supported - /// The serializer received a byte sequence, which it does not support. - #[error("Unsupported type: Bytes")] - UnsupportedTypeBytes, // UnsupportedTypeNone, // Supported // UnsupportedTypeSome, // Supported /// The serializer received a `()`, which it does not support. @@ -97,9 +76,6 @@ pub enum RequestIdError { /// The serializer received an enum newtype variant, which it does not support. #[error("Unsupported type: NewTypeVariant")] UnsupportedTypeNewTypeVariant, - /// The serializer received a sequence, which it does not support. - #[error("Unsupported type: Sequence")] - UnsupportedTypeSequence, /// The serializer received a tuple, which it does not support. #[error("Unsupported type: Tuple")] UnsupportedTypeTuple, diff --git a/ic-asset/README.md b/ic-asset/README.md deleted file mode 100644 index 49934f48..00000000 --- a/ic-asset/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Notice - -The `ic-asset` crate has been moved to the [sdk](https://github.com/dfinity/sdk) repo. diff --git a/icx-asset/README.md b/icx-asset/README.md deleted file mode 100644 index 4cb65793..00000000 --- a/icx-asset/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Notice - -The `icx-asset` crate has been moved to the [sdk](https://github.com/dfinity/sdk) repo. From 1ec2391d7bb84eec7ab6effe6a572c24d197d94c Mon Sep 17 00:00:00 2001 From: Rostislav Rumenov Date: Fri, 12 May 2023 21:07:18 +0200 Subject: [PATCH 15/30] fix: multiple fixes to the agent-rs, most notably having 5 min limit on the retry loop while polling (#434) --- .gitattributes | 2 + CHANGELOG.md | 1 + Cargo.lock | 415 +++++++++++++++++------------ Cargo.toml | 10 +- ic-agent/Cargo.toml | 6 +- ic-agent/src/agent/agent_config.rs | 4 +- ic-agent/src/agent/agent_error.rs | 4 - ic-agent/src/agent/builder.rs | 10 +- ic-agent/src/agent/mod.rs | 51 ++-- ic-agent/src/agent/replica_api.rs | 2 - ic-agent/src/lib.rs | 2 +- ic-utils/Cargo.toml | 4 +- icx/Cargo.toml | 4 +- ref-tests/Cargo.toml | 2 +- 14 files changed, 293 insertions(+), 224 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..dfe07704 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/CHANGELOG.md b/CHANGELOG.md index e88a80b7..6a69b989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +* fix: Adjust the default polling parameters to provide better UX. Remove the `CouldNotReadRootKey` error and panic on poisoned mutex. * chore: remove deprecated code and fix style * Breaking Change: removing the PasswordManager * Breaking Change: Enum variant `AgentError::ReplicaError` is now a tuple struct containing `RejectResponse`. diff --git a/Cargo.lock b/Cargo.lock index c7432087..3327e6f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" dependencies = [ "memchr", ] @@ -37,9 +37,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" dependencies = [ "backtrace", ] @@ -71,13 +71,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.67" +version = "0.1.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ea188f25f0255d8f92797797c97ebf5631fa88178beb1a46fdf5622c9a00e4" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.6", + "syn 2.0.15", ] [[package]] @@ -237,9 +237,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" [[package]] name = "byteorder" @@ -323,9 +323,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.23" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags", @@ -340,9 +340,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.2.18" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck", "proc-macro-error", @@ -409,15 +409,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" dependencies = [ "libc", ] @@ -461,9 +461,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c00419335c41018365ddf7e4d5f1c12ee3659ddcf3e01974650ba1de73d038" +checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" dependencies = [ "cc", "cxxbridge-flags", @@ -473,9 +473,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8307ad413a98fff033c8545ecf133e3257747b3bae935e7602aab8aa92d4ca" +checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" dependencies = [ "cc", "codespan-reporting", @@ -483,24 +483,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.6", + "syn 2.0.15", ] [[package]] name = "cxxbridge-flags" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc52e2eb08915cb12596d29d55f0b5384f00d697a646dbd269b6ecb0fbd9d31" +checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" [[package]] name = "cxxbridge-macro" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" +checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.6", + "syn 2.0.15", ] [[package]] @@ -627,13 +627,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -713,9 +713,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -728,9 +728,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -738,15 +738,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -755,38 +755,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.15", ] [[package]] name = "futures-sink" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -813,9 +813,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "js-sys", @@ -970,9 +970,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.25" +version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ "bytes", "futures-channel", @@ -1023,9 +1023,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.54" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1083,7 +1083,7 @@ dependencies = [ "sha2 0.10.6", "simple_asn1", "thiserror", - "time 0.3.20", + "time 0.3.21", "tokio", "url", "wasm-bindgen", @@ -1199,9 +1199,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", @@ -1221,20 +1221,32 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "ipnet" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] [[package]] name = "itertools" @@ -1276,21 +1288,20 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.19.8" +version = "0.19.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" +checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b" dependencies = [ "ascii-canvas", - "atty", "bit-set", "diff", "ena", + "is-terminal", "itertools", "lalrpop-util", "petgraph", - "pico-args", "regex", - "regex-syntax", + "regex-syntax 0.6.29", "string_cache", "term", "tiny-keccak", @@ -1299,9 +1310,9 @@ dependencies = [ [[package]] name = "lalrpop-util" -version = "0.19.8" +version = "0.19.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" +checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed" dependencies = [ "regex", ] @@ -1320,9 +1331,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "libloading" @@ -1345,9 +1356,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" [[package]] name = "lock_api" @@ -1387,7 +1398,7 @@ dependencies = [ "fnv", "proc-macro2", "quote", - "regex-syntax", + "regex-syntax 0.6.29", "syn 1.0.109", ] @@ -1426,9 +1437,9 @@ dependencies = [ [[package]] name = "mockito" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1eecc3baf782e3c8d6803cc8780268da1f32df6eb88c016c1d80b0df7944cf" +checksum = "ea57936ab3bf56156f135f20ee24b840e5a8ad97a8e1710eace33ac078f8f537" dependencies = [ "assert-json-diff", "colored", @@ -1564,9 +1575,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.51" +version = "0.10.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ea2d98598bf9ada7ea6ee8a30fb74f9156b63bbe495d64ec2b87c269d2dda3" +checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56" dependencies = [ "bitflags", "cfg-if", @@ -1579,13 +1590,13 @@ dependencies = [ [[package]] name = "openssl-macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.15", ] [[package]] @@ -1596,9 +1607,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.86" +version = "0.9.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992bac49bdbab4423199c654a5515bd2a6c6a23bf03f2dd3bdb7e5ae6259bc69" +checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e" dependencies = [ "cc", "libc", @@ -1639,7 +1650,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "windows-sys 0.45.0", ] @@ -1703,12 +1714,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pico-args" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" - [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1743,9 +1748,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "ppv-lite86" @@ -1805,18 +1810,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" dependencies = [ "proc-macro2", ] @@ -1860,6 +1865,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -1867,7 +1881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] @@ -1888,13 +1902,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.2" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.1", ] [[package]] @@ -1903,11 +1917,17 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +[[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" + [[package]] name = "reqwest" -version = "0.11.15" +version = "0.11.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ba30cc2c0cd02af1222ed216ba659cdb2f879dfe3181852fe7c50b1d0005949" +checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" dependencies = [ "base64 0.21.0", "bytes", @@ -1974,22 +1994,22 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.36.11" +version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2119,9 +2139,9 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.158" +version = "1.0.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" dependencies = [ "serde_derive", ] @@ -2147,20 +2167,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.158" +version = "1.0.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" +checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.6", + "syn 2.0.15", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -2175,7 +2195,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.6", + "syn 2.0.15", ] [[package]] @@ -2248,7 +2268,7 @@ dependencies = [ "num-bigint 0.4.3", "num-traits", "thiserror", - "time 0.3.20", + "time 0.3.21", ] [[package]] @@ -2290,9 +2310,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spki" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" dependencies = [ "base64ct", "der", @@ -2355,9 +2375,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.6" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece519cfaf36269ea69d16c363fa1d59ceba8296bbfbfc003c3176d01f2816ee" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", @@ -2366,15 +2386,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -2420,7 +2440,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.6", + "syn 2.0.15", ] [[package]] @@ -2436,9 +2456,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" dependencies = [ "itoa", "js-sys", @@ -2449,15 +2469,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" dependencies = [ "time-core", ] @@ -2488,14 +2508,13 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.26.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "parking_lot", @@ -2503,18 +2522,18 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.15", ] [[package]] @@ -2540,9 +2559,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", @@ -2560,9 +2579,9 @@ checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" [[package]] name = "toml_edit" -version = "0.19.7" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc18466501acd8ac6a3f615dd29a3438f8ca6bb3b19537138b3106e575621274" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ "indexmap", "toml_datetime", @@ -2862,11 +2881,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.46.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets", + "windows-targets 0.48.0", ] [[package]] @@ -2875,13 +2894,13 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -2890,7 +2909,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", ] [[package]] @@ -2899,13 +2927,28 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] @@ -2914,47 +2957,89 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "winnow" -version = "0.3.6" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d020b441f92996c80d94ae9166e8501e59c7bb56121189dc9eab3bd8216966" +checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" dependencies = [ "memchr", ] @@ -2970,6 +3055,6 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml index 4847020f..9b0f0335 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,12 +18,14 @@ rust-version = "1.65.0" license = "Apache-2.0" [workspace.dependencies] -candid = "0.8.0" +candid = "0.8.4" hex = "0.4.3" ring = "0.16.20" -serde = "1.0.154" +serde = "1.0.162" serde_bytes = "0.11.9" serde_cbor = "0.11.2" -serde_json = "1.0.94" +serde_json = "1.0.96" sha2 = "0.10.6" -thiserror = "1.0.39" +thiserror = "1.0.40" +tokio = "1.28.0" + diff --git a/ic-agent/Cargo.toml b/ic-agent/Cargo.toml index a268238a..d08bdc2a 100644 --- a/ic-agent/Cargo.toml +++ b/ic-agent/Cargo.toml @@ -15,7 +15,7 @@ keywords = ["internet-computer", "agent", "icp", "dfinity"] include = ["src", "Cargo.toml", "../LICENSE", "README.md"] [dependencies] -async-trait = "0.1.53" +async-trait = "0.1.68" backoff = "0.4.0" base32 = "0.4.0" byteorder = "1.3.2" @@ -35,7 +35,7 @@ rand = "0.8.5" ring = { workspace = true, features = ["std"] } serde = { workspace = true, features = ["derive"] } serde_bytes = { workspace = true } -serde_cbor = "0.11.2" +serde_cbor = { workspace = true } serde_repr = "0.1.12" sha2 = { workspace = true } simple_asn1 = "0.6.1" @@ -79,7 +79,7 @@ serde_json = "1.0.79" [target.'cfg(not(target_family = "wasm"))'.dev-dependencies] tokio = { version = "1.24.2", features = ["full"] } -mockito = "1" +mockito = "1.0.2" [target.'cfg(target_family = "wasm")'.dev-dependencies] wasm-bindgen-test = "0.3.34" diff --git a/ic-agent/src/agent/agent_config.rs b/ic-agent/src/agent/agent_config.rs index 1a174bd3..856f3cc8 100644 --- a/ic-agent/src/agent/agent_config.rs +++ b/ic-agent/src/agent/agent_config.rs @@ -11,7 +11,7 @@ pub struct AgentConfig { /// See [`with_identity`](super::AgentBuilder::with_identity). pub identity: Arc, /// See [`with_ingress_expiry`](super::AgentBuilder::with_ingress_expiry). - pub ingress_expiry_duration: Option, + pub ingress_expiry: Option, /// The [`with_transport`](super::AgentBuilder::with_transport). pub transport: Option>, } @@ -21,7 +21,7 @@ impl Default for AgentConfig { Self { nonce_factory: Arc::new(NonceFactory::random()), identity: Arc::new(AnonymousIdentity {}), - ingress_expiry_duration: None, + ingress_expiry: None, transport: None, } } diff --git a/ic-agent/src/agent/agent_error.rs b/ic-agent/src/agent/agent_error.rs index 11344034..8f64142f 100644 --- a/ic-agent/src/agent/agent_error.rs +++ b/ic-agent/src/agent/agent_error.rs @@ -127,10 +127,6 @@ pub enum AgentError { #[error("The status response did not contain a root key. Status: {0}")] NoRootKeyInStatus(Status), - /// Could not read the replica root key. - #[error("Could not read the root key")] - CouldNotReadRootKey(), - /// The invocation to the wallet call forward method failed with an error. #[error("The invocation to the wallet call forward method failed with the error: {0}")] WalletCallFailed(String), diff --git a/ic-agent/src/agent/builder.rs b/ic-agent/src/agent/builder.rs index bfd9f1b1..e8a8d788 100644 --- a/ic-agent/src/agent/builder.rs +++ b/ic-agent/src/agent/builder.rs @@ -83,12 +83,8 @@ impl AgentBuilder { /// Provides a _default_ ingress expiry. This is the delta that will be applied /// at the time an update or query is made. The default expiry cannot be a /// fixed system time. - pub fn with_ingress_expiry(self, duration: Option) -> Self { - AgentBuilder { - config: AgentConfig { - ingress_expiry_duration: duration, - ..self.config - }, - } + pub fn with_ingress_expiry(mut self, ingress_expiry: Option) -> Self { + self.config.ingress_expiry = ingress_expiry; + self } } diff --git a/ic-agent/src/agent/mod.rs b/ic-agent/src/agent/mod.rs index d43db911..21bc3b8b 100644 --- a/ic-agent/src/agent/mod.rs +++ b/ic-agent/src/agent/mod.rs @@ -204,7 +204,7 @@ pub enum PollResult { /// // Only do the following call when not contacting the IC main net (e.g. a local emulator). /// // This is important as the main net public key is static and a rogue network could return /// // a different key. -/// // If you know the root key ahead of time, you can use `agent.set_root_key(root_key)?;`. +/// // If you know the root key ahead of time, you can use `agent.set_root_key(root_key);`. /// agent.fetch_root_key().await?; /// let management_canister_id = Principal::from_text("aaaaa-aa")?; /// @@ -235,15 +235,15 @@ pub enum PollResult { pub struct Agent { nonce_factory: Arc, identity: Arc, - ingress_expiry_duration: Duration, - root_key: Arc>>>, + ingress_expiry: Duration, + root_key: Arc>>, transport: Arc, } impl fmt::Debug for Agent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { f.debug_struct("Agent") - .field("ingress_expiry_duration", &self.ingress_expiry_duration) + .field("ingress_expiry", &self.ingress_expiry) .finish_non_exhaustive() } } @@ -260,10 +260,10 @@ impl Agent { Ok(Agent { nonce_factory: config.nonce_factory, identity: config.identity, - ingress_expiry_duration: config - .ingress_expiry_duration + ingress_expiry: config + .ingress_expiry .unwrap_or_else(|| Duration::from_secs(300)), - root_key: Arc::new(RwLock::new(Some(IC_ROOT_KEY.to_vec()))), + root_key: Arc::new(RwLock::new(IC_ROOT_KEY.to_vec())), transport: config .transport .ok_or_else(AgentError::MissingReplicaTransport)?, @@ -296,49 +296,37 @@ impl Agent { /// *Only use this when you are _not_ talking to the main Internet Computer, otherwise /// you are prone to man-in-the-middle attacks! Do not call this function by default.* pub async fn fetch_root_key(&self) -> Result<(), AgentError> { - if let Ok(key) = self.read_root_key() { - if key != IC_ROOT_KEY.to_vec() { - // already fetched the root key - return Ok(()); - } + if self.read_root_key() != IC_ROOT_KEY.to_vec() { + // already fetched the root key + return Ok(()); } let status = self.status().await?; let root_key = status .root_key .clone() .ok_or(AgentError::NoRootKeyInStatus(status))?; - self.set_root_key(root_key) + self.set_root_key(root_key); + Ok(()) } /// By default, the agent is configured to talk to the main Internet Computer, and verifies /// responses using a hard-coded public key. /// /// Using this function you can set the root key to a known one if you know if beforehand. - pub fn set_root_key(&self, root_key: Vec) -> Result<(), AgentError> { - if let Ok(mut write_guard) = self.root_key.write() { - *write_guard = Some(root_key); - } - Ok(()) + pub fn set_root_key(&self, root_key: Vec) { + *self.root_key.write().unwrap() = root_key; } /// Return the root key currently in use. - pub fn read_root_key(&self) -> Result, AgentError> { - if let Ok(read_lock) = self.root_key.read() { - if let Some(root_key) = read_lock.clone() { - Ok(root_key) - } else { - Err(AgentError::CouldNotReadRootKey()) - } - } else { - Err(AgentError::CouldNotReadRootKey()) - } + pub fn read_root_key(&self) -> Vec { + self.root_key.read().unwrap().clone() } fn get_expiry_date(&self) -> u64 { // TODO(hansl): evaluate if we need this on the agent side (my hunch is we don't). let permitted_drift = Duration::from_secs(60); (self - .ingress_expiry_duration + .ingress_expiry .saturating_add({ #[cfg(not(target_family = "wasm"))] { @@ -546,9 +534,10 @@ impl Agent { effective_canister_id: Principal, ) -> Result, AgentError> { let mut retry_policy = ExponentialBackoffBuilder::new() - .with_initial_interval(Duration::from_millis(200)) + .with_initial_interval(Duration::from_millis(500)) .with_max_interval(Duration::from_secs(1)) .with_multiplier(1.4) + .with_max_elapsed_time(Some(Duration::from_secs(60 * 5))) .build(); let mut request_accepted = false; loop { @@ -648,7 +637,7 @@ impl Agent { effective_canister_id: Principal, ) -> Result, AgentError> { match delegation { - None => self.read_root_key(), + None => Ok(self.read_root_key()), Some(delegation) => { let cert: Certificate = serde_cbor::from_slice(&delegation.certificate) .map_err(AgentError::InvalidCborData)?; diff --git a/ic-agent/src/agent/replica_api.rs b/ic-agent/src/agent/replica_api.rs index 505186e4..73933076 100644 --- a/ic-agent/src/agent/replica_api.rs +++ b/ic-agent/src/agent/replica_api.rs @@ -1,8 +1,6 @@ use crate::{export::Principal, AgentError}; use ic_certification::Label; use serde::{Deserialize, Serialize}; - -pub use ic_certification::{Certificate, Delegation}; use serde_repr::{Deserialize_repr, Serialize_repr}; #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/ic-agent/src/lib.rs b/ic-agent/src/lib.rs index 4c3ea873..2b945100 100644 --- a/ic-agent/src/lib.rs +++ b/ic-agent/src/lib.rs @@ -64,7 +64,7 @@ //! // Only do the following call when not contacting the IC main net (e.g. a local emulator). //! // This is important as the main net public key is static and a rogue network could return //! // a different key. -//! // If you know the root key ahead of time, you can use `agent.set_root_key(root_key)?;`. +//! // If you know the root key ahead of time, you can use `agent.set_root_key(root_key);`. //! agent.fetch_root_key().await?; //! let management_canister_id = Principal::from_text("aaaaa-aa")?; //! diff --git a/ic-utils/Cargo.toml b/ic-utils/Cargo.toml index 15644fad..350aad72 100644 --- a/ic-utils/Cargo.toml +++ b/ic-utils/Cargo.toml @@ -17,7 +17,7 @@ include = ["src", "Cargo.toml", "../LICENSE", "README.md"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-trait = "0.1.40" +async-trait = "0.1.68" candid = { workspace = true } ic-agent = { path = "../ic-agent", version = "0.23", default-features = false } serde = { workspace = true } @@ -34,7 +34,7 @@ once_cell = "1.10.0" [dev-dependencies] ic-agent = { path = "../ic-agent", version = "0.23" } ring = { workspace = true } -tokio = { version = "1.24.2", features = ["full"] } +tokio = { workspace = true, features = ["full"] } [features] raw = [] diff --git a/icx/Cargo.toml b/icx/Cargo.toml index 86a9e49f..901755f6 100644 --- a/icx/Cargo.toml +++ b/icx/Cargo.toml @@ -29,6 +29,6 @@ ic-utils = { path = "../ic-utils", version = "0.23" } pem = "1.0" ring = { workspace = true } serde = { workspace = true } -serde_json = "1.0.57" -tokio = { version = "1.24.2", features = ["full"] } +serde_json = { workspace = true } +tokio = { workspace = true, features = ["full"] } thiserror = { workspace = true } diff --git a/ref-tests/Cargo.toml b/ref-tests/Cargo.toml index f083966d..358065e8 100644 --- a/ref-tests/Cargo.toml +++ b/ref-tests/Cargo.toml @@ -13,7 +13,7 @@ ic-utils = { path = "../ic-utils", features = ["raw"] } ring = { workspace = true } serde = { workspace = true, features = ["derive"] } sha2 = { workspace = true } -tokio = { version = "1.24.2", features = ["full"] } +tokio = { workspace = true, features = ["full"] } [dev-dependencies] serde_cbor = { workspace = true } From d6ffe9619024cbed483c0acb2fe986716f712189 Mon Sep 17 00:00:00 2001 From: Daniel Sharifi <40335219+DSharifi@users.noreply.github.com> Date: Tue, 16 May 2023 17:05:53 +0200 Subject: [PATCH 16/30] fix: put wasm-bindgen build target behind a feature. (#435) --- .github/workflows/lint.yml | 6 ++--- .github/workflows/test.yml | 10 ++++----- CHANGELOG.md | 2 +- ic-agent/Cargo.toml | 22 +++++++++++++------ ic-agent/src/agent/agent_test.rs | 6 ++--- .../agent/http_transport/reqwest_transport.rs | 6 ++--- ic-agent/src/agent/mod.rs | 4 ++-- 7 files changed, 32 insertions(+), 24 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 59ed332c..d7976a84 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,8 +8,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - rust: [ '1.65.0' ] - os: [ ubuntu-latest ] + rust: ["1.65.0"] + os: [ubuntu-latest] steps: - uses: actions/checkout@v2 @@ -33,7 +33,7 @@ jobs: env: RUST_BACKTRACE: 1 - name: Run Lint (WASM) - run: CARGO_TARGET_DIR=target/wasm cargo clippy --target wasm32-unknown-unknown -p ic-agent -p ic-utils --verbose -- -D clippy::all + run: CARGO_TARGET_DIR=target/wasm cargo clippy --target wasm32-unknown-unknown -p ic-agent --features wasm-bindgen -p ic-utils --verbose -- -D clippy::all aggregate: name: lint:required runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index df380b29..16c3e1e8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,8 +11,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - rust: [ '1.65.0' ] - os: [ ubuntu-latest, macos-latest, windows-latest ] + rust: ["1.65.0"] + os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@v2 @@ -30,7 +30,7 @@ jobs: rustup update ${{ matrix.rust }} --no-self-update rustup default ${{ matrix.rust }} rustup target add wasm32-unknown-unknown - + - name: Install wasm-pack if: ${{ matrix.os == 'ubuntu-latest' }} run: | @@ -48,11 +48,11 @@ jobs: done env: RUST_BACKTRACE: 1 - + - name: Run Tests (WASM) if: ${{ matrix.os == 'ubuntu-latest' }} run: | - CARGO_TARGET_DIR=../target/wasm wasm-pack test --chrome --headless ic-agent + CARGO_TARGET_DIR=../target/wasm wasm-pack test --chrome --headless ic-agent --features wasm-bindgen - name: Purge for OSX if: matrix.os == 'macos-latest' diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a69b989..33bb3544 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Handling rejected update calls where status code is 200. See IC-1462 * Reject code type is changed from `u64` to enum `RejectCode`. -* Support WASM targets in the browser via `wasm-bindgen` +* Support WASM targets in the browser via `wasm-bindgen`. Feature `wasm-bindgen` required. * Do not send `certificate_version` on HTTP Update requests * Update `certificate_version` to `u16` instead of `u128`, fixes an issue where the asset canister always responds with v1 response verification diff --git a/ic-agent/Cargo.toml b/ic-agent/Cargo.toml index d08bdc2a..e4743937 100644 --- a/ic-agent/Cargo.toml +++ b/ic-agent/Cargo.toml @@ -66,13 +66,12 @@ tokio = { version = "1.24.2", features = ["time"] } rustls = "0.20.4" [target.'cfg(target_family = "wasm")'.dependencies] -backoff = { version = "0.4", features = ["wasm-bindgen"] } -getrandom = { version = "0.2", features = ["js"] } -js-sys = "0.3" -wasm-bindgen = "0.2" -wasm-bindgen-futures = "0.4" -web-sys = { version = "0.3", features = ["Window"] } -time = { version = "0.3", features = ["wasm-bindgen"] } +getrandom = { version = "0.2", features = ["js"], optional = true } +js-sys = { version = "0.3", optional = true } +wasm-bindgen = { version = "0.2", optional = true } +wasm-bindgen-futures = { version = "0.4", optional = true } +web-sys = { version = "0.3", features = ["Window"], optional = true } +time = { version = "0.3", features = ["wasm-bindgen"], optional = true } [dev-dependencies] serde_json = "1.0.79" @@ -98,6 +97,15 @@ hyper = ["dep:hyper", "dep:hyper-rustls"] ic_ref_tests = [ "default", ] # Used to separate integration tests for ic-ref which need a server running. +wasm-bindgen = [ + "dep:js-sys", + "dep:wasm-bindgen", + "dep:wasm-bindgen-futures", + "dep:getrandom", + "dep:web-sys", + "dep:time", + "backoff/wasm-bindgen", +] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] diff --git a/ic-agent/src/agent/agent_test.rs b/ic-agent/src/agent/agent_test.rs index d11b6098..c5f0360b 100644 --- a/ic-agent/src/agent/agent_test.rs +++ b/ic-agent/src/agent/agent_test.rs @@ -13,10 +13,10 @@ use crate::{ }; use ic_certification::Label; use std::collections::BTreeMap; -#[cfg(target_family = "wasm")] +#[cfg(all(target_family = "wasm", feature = "wasm-bindgen"))] use wasm_bindgen_test::wasm_bindgen_test; -#[cfg(target_family = "wasm")] +#[cfg(all(target_family = "wasm", feature = "wasm-bindgen"))] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); #[cfg_attr(not(target_family = "wasm"), tokio::test)] @@ -548,7 +548,7 @@ mod mock { } } -#[cfg(target_family = "wasm")] +#[cfg(all(target_family = "wasm", feature = "wasm-bindgen"))] mod mock { use js_sys::*; use reqwest::Client; diff --git a/ic-agent/src/agent/http_transport/reqwest_transport.rs b/ic-agent/src/agent/http_transport/reqwest_transport.rs index b978bdc5..a8da9bf9 100644 --- a/ic-agent/src/agent/http_transport/reqwest_transport.rs +++ b/ic-agent/src/agent/http_transport/reqwest_transport.rs @@ -55,7 +55,7 @@ impl ReqwestTransport { } /// Creates a replica transport from a HTTP URL. - #[cfg(target_family = "wasm")] + #[cfg(all(target_family = "wasm", feature = "wasm-bindgen"))] pub fn create>(url: U) -> Result { Self::create_with_client(url, Client::new()) } @@ -217,9 +217,9 @@ impl Transport for ReqwestTransport { #[cfg(test)] mod test { - #[cfg(target_family = "wasm")] + #[cfg(all(target_family = "wasm", feature = "wasm-bindgen"))] use wasm_bindgen_test::wasm_bindgen_test; - #[cfg(target_family = "wasm")] + #[cfg(all(target_family = "wasm", feature = "wasm-bindgen"))] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); use super::ReqwestTransport; diff --git a/ic-agent/src/agent/mod.rs b/ic-agent/src/agent/mod.rs index 21bc3b8b..4cca1e72 100644 --- a/ic-agent/src/agent/mod.rs +++ b/ic-agent/src/agent/mod.rs @@ -334,7 +334,7 @@ impl Agent { .duration_since(std::time::UNIX_EPOCH) .expect("Time wrapped around.") } - #[cfg(target_family = "wasm")] + #[cfg(all(target_family = "wasm", feature = "wasm-bindgen"))] { Duration::from_nanos((js_sys::Date::now() * 1_000_000.) as _) } @@ -562,7 +562,7 @@ impl Agent { match retry_policy.next_backoff() { #[cfg(not(target_family = "wasm"))] Some(duration) => tokio::time::sleep(duration).await, - #[cfg(target_family = "wasm")] + #[cfg(all(target_family = "wasm", feature = "wasm-bindgen"))] Some(duration) => { wasm_bindgen_futures::JsFuture::from(js_sys::Promise::new(&mut |rs, rj| { if let Err(e) = web_sys::window() From e62a5a583b095fa90f2aa9a8459181a043cd0ee8 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 16 May 2023 14:39:15 -0700 Subject: [PATCH 17/30] chore: Document optional features (#436) --- ic-agent/Cargo.toml | 4 +- .../agent/http_transport/hyper_transport.rs | 2 - .../agent/http_transport/reqwest_transport.rs | 44 +++++++++---------- ic-agent/src/identity/error.rs | 2 - ic-agent/src/lib.rs | 1 + ic-certification/Cargo.toml | 3 ++ ic-certification/src/lib.rs | 2 + ic-identity-hsm/Cargo.toml | 4 +- ic-utils/Cargo.toml | 2 + ic-utils/src/call.rs | 42 +++++++++--------- ic-utils/src/canister.rs | 14 +++--- ic-utils/src/interfaces/wallet.rs | 2 +- ic-utils/src/lib.rs | 1 + 13 files changed, 66 insertions(+), 57 deletions(-) diff --git a/ic-agent/Cargo.toml b/ic-agent/Cargo.toml index e4743937..7758c359 100644 --- a/ic-agent/Cargo.toml +++ b/ic-agent/Cargo.toml @@ -35,7 +35,7 @@ rand = "0.8.5" ring = { workspace = true, features = ["std"] } serde = { workspace = true, features = ["derive"] } serde_bytes = { workspace = true } -serde_cbor = { workspace = true } +serde_cbor = { workspace = true } serde_repr = "0.1.12" sha2 = { workspace = true } simple_asn1 = "0.6.1" @@ -109,3 +109,5 @@ wasm-bindgen = [ [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] +rustdoc-args = ["--cfg=docsrs"] +features = ["hyper"] diff --git a/ic-agent/src/agent/http_transport/hyper_transport.rs b/ic-agent/src/agent/http_transport/hyper_transport.rs index 66e697ac..30035f01 100644 --- a/ic-agent/src/agent/http_transport/hyper_transport.rs +++ b/ic-agent/src/agent/http_transport/hyper_transport.rs @@ -1,6 +1,4 @@ //! A [`Transport`] that connects using a [`hyper`] client. -#![cfg(any(feature = "hyper"))] - pub use hyper; use std::{any, error::Error, future::Future, marker::PhantomData, sync::atomic::AtomicPtr}; diff --git a/ic-agent/src/agent/http_transport/reqwest_transport.rs b/ic-agent/src/agent/http_transport/reqwest_transport.rs index a8da9bf9..8289336b 100644 --- a/ic-agent/src/agent/http_transport/reqwest_transport.rs +++ b/ic-agent/src/agent/http_transport/reqwest_transport.rs @@ -35,29 +35,29 @@ pub use ReqwestTransport as ReqwestHttpReplicaV2Transport; // deprecate after 0. impl ReqwestTransport { /// Creates a replica transport from a HTTP URL. - #[cfg(not(target_family = "wasm"))] pub fn create>(url: U) -> Result { - let mut tls_config = rustls::ClientConfig::builder() - .with_safe_defaults() - .with_webpki_roots() - .with_no_client_auth(); - - // Advertise support for HTTP/2 - tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; - - Self::create_with_client( - url, - Client::builder() - .use_preconfigured_tls(tls_config) - .build() - .expect("Could not create HTTP client."), - ) - } - - /// Creates a replica transport from a HTTP URL. - #[cfg(all(target_family = "wasm", feature = "wasm-bindgen"))] - pub fn create>(url: U) -> Result { - Self::create_with_client(url, Client::new()) + #[cfg(not(target_family = "wasm"))] + { + let mut tls_config = rustls::ClientConfig::builder() + .with_safe_defaults() + .with_webpki_roots() + .with_no_client_auth(); + + // Advertise support for HTTP/2 + tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; + + Self::create_with_client( + url, + Client::builder() + .use_preconfigured_tls(tls_config) + .build() + .expect("Could not create HTTP client."), + ) + } + #[cfg(all(target_family = "wasm", feature = "wasm-bindgen"))] + { + Self::create_with_client(url, Client::new()) + } } /// Creates a replica transport from a HTTP URL and a [`reqwest::Client`]. diff --git a/ic-agent/src/identity/error.rs b/ic-agent/src/identity/error.rs index 8ce1b8d9..5fa46dbe 100644 --- a/ic-agent/src/identity/error.rs +++ b/ic-agent/src/identity/error.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "pem")] - use thiserror::Error; /// An error happened while reading a PEM file. diff --git a/ic-agent/src/lib.rs b/ic-agent/src/lib.rs index 2b945100..759ba9a5 100644 --- a/ic-agent/src/lib.rs +++ b/ic-agent/src/lib.rs @@ -109,6 +109,7 @@ rustdoc::broken_intra_doc_links, rustdoc::private_intra_doc_links )] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #[cfg(all(feature = "hyper", target_family = "wasm"))] compile_error!("Feature `hyper` cannot be used from WASM."); diff --git a/ic-certification/Cargo.toml b/ic-certification/Cargo.toml index a0a1222d..0f9ad453 100644 --- a/ic-certification/Cargo.toml +++ b/ic-certification/Cargo.toml @@ -33,3 +33,6 @@ optional = true [features] # Default features include serde support. default = ['serde', 'serde_bytes'] + +[package.metadata.docs.rs] +rustdoc-args = ["--cfg=docsrs"] diff --git a/ic-certification/src/lib.rs b/ic-certification/src/lib.rs index 2b168ac9..9785e8b0 100644 --- a/ic-certification/src/lib.rs +++ b/ic-certification/src/lib.rs @@ -3,6 +3,8 @@ //! If you need support for the serde library, you will need to use the `serde` feature //! (available by default). +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + pub mod hash_tree; #[doc(inline)] pub use hash_tree::{HashTree, Label, LookupResult, SubtreeLookupResult}; diff --git a/ic-identity-hsm/Cargo.toml b/ic-identity-hsm/Cargo.toml index d1a463bf..28f0870e 100644 --- a/ic-identity-hsm/Cargo.toml +++ b/ic-identity-hsm/Cargo.toml @@ -16,9 +16,7 @@ include = ["src", "Cargo.toml", "../LICENSE", "README.md"] [dependencies] hex = { workspace = true } -ic-agent = { path = "../ic-agent", version = "0.23", features = [ - "pem", -], default-features = false } +ic-agent = { path = "../ic-agent", version = "0.23", default-features = false } num-bigint = "0.4.3" pkcs11 = "0.5.0" sha2 = { workspace = true } diff --git a/ic-utils/Cargo.toml b/ic-utils/Cargo.toml index 350aad72..d852d5a5 100644 --- a/ic-utils/Cargo.toml +++ b/ic-utils/Cargo.toml @@ -41,3 +41,5 @@ raw = [] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"] +rustdoc-args = ["--cfg=docsrs"] +features = ["raw"] diff --git a/ic-utils/src/call.rs b/ic-utils/src/call.rs index ac5ed725..549b2ccc 100644 --- a/ic-utils/src/call.rs +++ b/ic-utils/src/call.rs @@ -43,34 +43,36 @@ where /// managed by the caller using the Agent directly. /// /// Since the return type is encoded in the trait itself, this can lead to types - /// that are not compatible to [O] when getting the result from the Request Id. - /// For example, you might hold a [AsyncCall], use `call()` and poll for + /// that are not compatible to `Out` when getting the result from the Request Id. + /// For example, you might hold a [`AsyncCall`], use `call()` and poll for /// the result, and try to deserialize it as a [String]. This would be caught by /// Rust type system, but in this case it will be checked at runtime (as Request /// Id does not have a type associated with it). async fn call(self) -> Result; - /// Execute the call, and wait for an answer using a [Waiter] strategy. The return + /// Execute the call, and wait for an answer using an exponential-backoff strategy. The return /// type is encoded in the trait. async fn call_and_wait(self) -> Result; /// Apply a transformation function after the call has been successful. The transformation /// is applied with the result. /// - /// ```ignored + /// ```ignore /// # // This test is ignored because it requires an ic to be running. We run these /// # // in the ic-ref workflow. - /// use ic_agent::{Agent, Principal}; - /// use ic_utils::{Canister, interfaces}; - /// use candid::{Encode, Decode, CandidType}; + /// use ic_agent::Agent; + /// # use ic_agent::identity::{Identity, BasicIdentity}; + /// use ic_utils::{Canister, interfaces, call::AsyncCall}; + /// use candid::{Encode, Decode, CandidType, Principal}; /// + /// async fn create_a_canister() -> Result> { /// # let canister_wasm = b"\0asm\x01\0\0\0"; - /// # fn create_identity() -> impl ic_agent::Identity { + /// # fn create_identity() -> impl Identity { /// # let rng = ring::rand::SystemRandom::new(); /// # let key_pair = ring::signature::Ed25519KeyPair::generate_pkcs8(&rng) /// # .expect("Could not generate a key pair."); /// # - /// # ic_agent::BasicIdentity::from_key_pair( + /// # BasicIdentity::from_key_pair( /// # ring::signature::Ed25519KeyPair::from_pkcs8(key_pair.as_ref()) /// # .expect("Could not read the key pair."), /// # ) @@ -78,34 +80,34 @@ where /// # /// # const URL: &'static str = concat!("http://localhost:", env!("IC_REF_PORT")); /// # - /// async fn create_a_canister() -> Result> { + /// # let effective_id = Principal::from_text("rwlgt-iiaaa-aaaaa-aaaaa-cai").unwrap(); /// let agent = Agent::builder() /// .with_url(URL) /// .with_identity(create_identity()) /// .build()?; - /// let management_canister = Canister::builder() - /// .with_agent(&agent) - /// .with_canister_id("aaaaa-aa") - /// .with_interface(interfaces::ManagementCanister) - /// .build()?; + /// agent.fetch_root_key().await?; + /// let management_canister = interfaces::ManagementCanister::create(&agent); + /// let management_canister = &management_canister; // needed for `async move` /// /// // Create a canister, then call the management canister to install a base canister /// // WASM. This is to show how this API would be used, but is probably not a good /// // real use case. - /// let canister_id = management_canister + /// let (canister_id,) = management_canister /// .create_canister() - /// .and_then(|(canister_id,)| async { + /// .as_provisional_create_with_amount(None) + /// .with_effective_canister_id(effective_id) + /// .and_then(|(canister_id,)| async move { /// management_canister /// .install_code(&canister_id, canister_wasm) /// .build() + /// .unwrap() /// .call_and_wait() - /// .await + /// .await?; + /// Ok((canister_id,)) /// }) /// .call_and_wait() /// .await?; /// - /// let result = Decode!(response.as_slice(), CreateCanisterResult)?; - /// let canister_id: Principal = Principal::from_text(&result.canister_id.to_text())?; /// Ok(canister_id) /// } /// diff --git a/ic-utils/src/canister.rs b/ic-utils/src/canister.rs index d603b354..1b9c384f 100644 --- a/ic-utils/src/canister.rs +++ b/ic-utils/src/canister.rs @@ -222,7 +222,7 @@ impl Argument { Default::default() } - /// Creates an argument from an arbitrary blob. Equivalent to [`set_raw_arg`]. + /// Creates an argument from an arbitrary blob. Equivalent to [`set_raw_arg`](Argument::set_raw_arg). pub fn from_raw(raw: Vec) -> Self { Self(Ok(ArgumentType::Raw(raw))) } @@ -273,7 +273,8 @@ impl<'agent, 'canister: 'agent> SyncCallBuilder<'agent, 'canister> { impl<'agent, 'canister: 'agent> SyncCallBuilder<'agent, 'canister> { /// Add an argument to the candid argument list. This requires Candid arguments, if - /// there is a raw argument set (using [with_arg_raw]), this will fail. + /// there is a raw argument set (using [`with_arg_raw`](SyncCallBuilder::with_arg_raw)), + /// this will fail. pub fn with_arg(mut self, arg: Argument) -> SyncCallBuilder<'agent, 'canister> where Argument: CandidType + Sync + Send, @@ -283,8 +284,9 @@ impl<'agent, 'canister: 'agent> SyncCallBuilder<'agent, 'canister> { } /// Add an argument to the candid argument list. This requires Candid arguments, if - /// there is a raw argument set (using [with_arg_raw]), this will fail. - /// TODO: make this method unnecessary https://github.com/dfinity/agent-rs/issues/132 + /// there is a raw argument set (using [`with_arg_raw`](SyncCallBuilder::with_arg_raw)), this will fail. + /// + /// TODO: make this method unnecessary ([#132](https://github.com/dfinity/agent-rs/issues/132)) pub fn with_value_arg(mut self, arg: IDLValue) -> SyncCallBuilder<'agent, 'canister> { self.arg.push_value_arg(arg); self @@ -306,7 +308,7 @@ impl<'agent, 'canister: 'agent> SyncCallBuilder<'agent, 'canister> { self } - /// Builds an [SyncCaller] from this builder's state. + /// Builds a [SyncCaller] from this builder's state. pub fn build(self) -> SyncCaller<'canister, Output> where Output: for<'de> ArgumentDecoder<'de> + Send + Sync, @@ -352,7 +354,7 @@ impl<'agent, 'canister: 'agent> AsyncCallBuilder<'agent, 'canister> { impl<'agent, 'canister: 'agent> AsyncCallBuilder<'agent, 'canister> { /// Add an argument to the candid argument list. This requires Candid arguments, if - /// there is a raw argument set (using [with_arg_raw]), this will fail. + /// there is a raw argument set (using [`with_arg_raw`](AsyncCallBuilder::with_arg_raw)), this will fail. pub fn with_arg(mut self, arg: Argument) -> AsyncCallBuilder<'agent, 'canister> where Argument: CandidType + Sync + Send, diff --git a/ic-utils/src/interfaces/wallet.rs b/ic-utils/src/interfaces/wallet.rs index 6eaaad7c..431f230c 100644 --- a/ic-utils/src/interfaces/wallet.rs +++ b/ic-utils/src/interfaces/wallet.rs @@ -57,7 +57,7 @@ where Out: for<'de> ArgumentDecoder<'de> + Send + Sync, { /// Add an argument to the candid argument list. This requires Candid arguments, if - /// there is a raw argument set (using [with_arg_raw]), this will fail. + /// there is a raw argument set (using [`with_arg_raw`](CallForwarder::with_arg_raw)), this will fail. pub fn with_arg(mut self, arg: Argument) -> Self where Argument: CandidType + Sync + Send, diff --git a/ic-utils/src/lib.rs b/ic-utils/src/lib.rs index b1edd1f2..43a19871 100644 --- a/ic-utils/src/lib.rs +++ b/ic-utils/src/lib.rs @@ -7,6 +7,7 @@ rustdoc::broken_intra_doc_links, rustdoc::private_intra_doc_links )] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] /// Utilities to encapsulate calls to a canister. pub mod call; From 1d5854aa8607581b6613e9d617b4dfa2054525e2 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Tue, 16 May 2023 16:28:38 -0700 Subject: [PATCH 18/30] Replace `chrono` with `time` (#437) --- Cargo.lock | 143 ++--------------------------------------- Cargo.toml | 2 +- ic-agent/Cargo.toml | 2 +- icx-cert/Cargo.toml | 2 +- icx-cert/src/pprint.rs | 13 +--- 5 files changed, 11 insertions(+), 151 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3327e6f5..ecb990f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,15 +26,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anyhow" version = "1.0.71" @@ -306,21 +297,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits", - "time 0.1.45", - "wasm-bindgen", - "winapi", -] - [[package]] name = "clap" version = "3.2.25" @@ -459,50 +435,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.15", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - [[package]] name = "data-encoding" version = "2.3.3" @@ -820,7 +752,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -1021,30 +953,6 @@ dependencies = [ "tokio-native-tls", ] -[[package]] -name = "iana-time-zone" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - [[package]] name = "ic-agent" version = "0.23.2" @@ -1083,7 +991,7 @@ dependencies = [ "sha2 0.10.6", "simple_asn1", "thiserror", - "time 0.3.21", + "time", "tokio", "url", "wasm-bindgen", @@ -1174,7 +1082,6 @@ version = "0.23.2" dependencies = [ "anyhow", "base64 0.13.1", - "chrono", "clap", "hex", "ic-agent", @@ -1185,6 +1092,7 @@ dependencies = [ "serde_bytes", "serde_cbor", "sha2 0.10.6", + "time", ] [[package]] @@ -1345,15 +1253,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "linux-raw-sys" version = "0.3.7" @@ -1431,7 +1330,7 @@ checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.45.0", ] @@ -2078,12 +1977,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - [[package]] name = "sct" version = "0.7.0" @@ -2268,7 +2161,7 @@ dependencies = [ "num-bigint 0.4.3", "num-traits", "thiserror", - "time 0.3.21", + "time", ] [[package]] @@ -2443,17 +2336,6 @@ dependencies = [ "syn 2.0.15", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - [[package]] name = "time" version = "0.3.21" @@ -2704,12 +2586,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2879,15 +2755,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.0", -] - [[package]] name = "windows-sys" version = "0.42.0" diff --git a/Cargo.toml b/Cargo.toml index 9b0f0335..f3478c32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,5 +27,5 @@ serde_cbor = "0.11.2" serde_json = "1.0.96" sha2 = "0.10.6" thiserror = "1.0.40" +time = "0.3" tokio = "1.28.0" - diff --git a/ic-agent/Cargo.toml b/ic-agent/Cargo.toml index 7758c359..f14d77f7 100644 --- a/ic-agent/Cargo.toml +++ b/ic-agent/Cargo.toml @@ -71,7 +71,7 @@ js-sys = { version = "0.3", optional = true } wasm-bindgen = { version = "0.2", optional = true } wasm-bindgen-futures = { version = "0.4", optional = true } web-sys = { version = "0.3", features = ["Window"], optional = true } -time = { version = "0.3", features = ["wasm-bindgen"], optional = true } +time = { workspace = true, features = ["wasm-bindgen"], optional = true } [dev-dependencies] serde_json = "1.0.79" diff --git a/icx-cert/Cargo.toml b/icx-cert/Cargo.toml index 30140c18..13fcd572 100644 --- a/icx-cert/Cargo.toml +++ b/icx-cert/Cargo.toml @@ -20,7 +20,6 @@ include = ["src", "Cargo.toml", "../LICENSE", "README.md"] anyhow = "1.0" base64 = "0.13" clap = { version = "3.1.8", features = ["derive", "cargo"] } -chrono = "0.4.19" hex = { workspace = true } ic-agent = { path = "../ic-agent", version = "0.23", default-features = false } leb128 = "0.2.4" @@ -29,4 +28,5 @@ sha2 = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_bytes = { workspace = true } serde_cbor = { workspace = true } +time = { workspace = true } ic-certification = { path = "../ic-certification", version = "0.23" } diff --git a/icx-cert/src/pprint.rs b/icx-cert/src/pprint.rs index 99aa7436..2b852bc4 100644 --- a/icx-cert/src/pprint.rs +++ b/icx-cert/src/pprint.rs @@ -1,9 +1,9 @@ use anyhow::{anyhow, Context, Result}; -use chrono::TimeZone; use ic_certification::{HashTree, LookupResult}; use reqwest::header; use serde::{de::DeserializeOwned, Deserialize}; use sha2::Digest; +use time::{format_description::well_known::Rfc3339, OffsetDateTime}; /// Structured contents of the IC-Certificate header. struct StructuredCertHeader<'a> { @@ -121,16 +121,9 @@ pub fn pprint(url: String, accept_encodings: Option>) -> Result<()> if let LookupResult::Found(mut date_bytes) = cert.tree.lookup_path(&["time".into()]) { let timestamp_nanos = leb128::read::unsigned(&mut date_bytes) .with_context(|| "failed to decode certificate time as LEB128")?; - const NANOS_PER_SEC: u64 = 1_000_000_000; - - let dt = chrono::Utc - .timestamp_opt( - (timestamp_nanos / NANOS_PER_SEC) as i64, - (timestamp_nanos % NANOS_PER_SEC) as u32, - ) - .single() + let dt = OffsetDateTime::from_unix_timestamp_nanos(timestamp_nanos as i128) .context("timestamp out of range")?; - println!("CERTIFICATE TIME: {}", dt.to_rfc3339()); + println!("CERTIFICATE TIME: {}", dt.format(&Rfc3339)?); } println!("CERTIFICATE TREE: {:#?}", cert.tree); println!("TREE: {:#?}", tree); From 824ecc9691ff9e35571016ebf60e22290c395555 Mon Sep 17 00:00:00 2001 From: Daniel Bloom <82895745+Daniel-Bloom-dfinity@users.noreply.github.com> Date: Thu, 18 May 2023 13:42:24 -0700 Subject: [PATCH 19/30] refactor: Remove the lifetimes from `ic-certification` (#438) --- CHANGELOG.md | 5 + ic-agent/src/agent/agent_test.rs | 6 +- ic-agent/src/agent/mod.rs | 22 +- ic-agent/src/agent/response_authentication.rs | 188 ++++-- ic-certification/src/certificate.rs | 273 +++++++- ic-certification/src/hash_tree/mod.rs | 605 +++++++++++------- ic-certification/src/hash_tree/tests.rs | 165 +++-- ic-certification/src/lib.rs | 105 ++- icx-cert/src/pprint.rs | 4 +- 9 files changed, 985 insertions(+), 388 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33bb3544..6e5125e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased + * fix: Adjust the default polling parameters to provide better UX. Remove the `CouldNotReadRootKey` error and panic on poisoned mutex. * chore: remove deprecated code and fix style * Breaking Change: removing the PasswordManager @@ -18,6 +19,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Do not send `certificate_version` on HTTP Update requests * Update `certificate_version` to `u16` instead of `u128`, fixes an issue where the asset canister always responds with v1 response verification +### ic-certification + +* Breaking change: Content and path storage has been changed from a `Cow<[u8]>` to a user-provided `T: AsRef`, removing the lifetime from various types. + ### icx-cert * Fixed issue where a missing request header caused the canister to not respond with an `ic-certificate` header. diff --git a/ic-agent/src/agent/agent_test.rs b/ic-agent/src/agent/agent_test.rs index c5f0360b..fdf01c26 100644 --- a/ic-agent/src/agent/agent_test.rs +++ b/ic-agent/src/agent/agent_test.rs @@ -446,7 +446,7 @@ async fn check_subnet_range_with_valid_range() { let _result = agent .read_state_raw( vec![REQ_WITH_DELEGATED_CERT_PATH - .iter() + .into_iter() .map(Label::from) .collect()], Principal::from_text(REQ_WITH_DELEGATED_CERT_CANISTER).unwrap(), @@ -478,7 +478,7 @@ async fn check_subnet_range_with_unauthorized_range() { let result = agent .read_state_raw( vec![REQ_WITH_DELEGATED_CERT_PATH - .iter() + .into_iter() .map(Label::from) .collect()], wrong_canister, @@ -509,7 +509,7 @@ async fn check_subnet_range_with_pruned_range() { let result = agent .read_state_raw( vec![REQ_WITH_DELEGATED_CERT_PATH - .iter() + .into_iter() .map(Label::from) .collect()], canister, diff --git a/ic-agent/src/agent/mod.rs b/ic-agent/src/agent/mod.rs index 4cca1e72..5cdee2b1 100644 --- a/ic-agent/src/agent/mod.rs +++ b/ic-agent/src/agent/mod.rs @@ -589,7 +589,7 @@ impl Agent { &self, paths: Vec>, effective_canister_id: Principal, - ) -> Result, AgentError> { + ) -> Result { let request = self.read_state_content(paths)?; let serialized_bytes = sign_request(&request, self.identity.clone())?; @@ -643,9 +643,9 @@ impl Agent { .map_err(AgentError::InvalidCborData)?; self.verify(&cert, effective_canister_id)?; let canister_range_lookup = [ - "subnet".into(), - delegation.subnet_id.clone().into(), - "canister_ranges".into(), + "subnet".as_bytes(), + delegation.subnet_id.as_ref(), + "canister_ranges".as_bytes(), ]; let canister_range = lookup_value(&cert, canister_range_lookup)?; let ranges: Vec<(Principal, Principal)> = @@ -656,9 +656,9 @@ impl Agent { } let public_key_path = [ - "subnet".into(), - delegation.subnet_id.clone().into(), - "public_key".into(), + "subnet".as_bytes(), + delegation.subnet_id.as_ref(), + "public_key".as_bytes(), ]; lookup_value(&cert, public_key_path).map(|pk| pk.to_vec()) } @@ -671,7 +671,11 @@ impl Agent { canister_id: Principal, path: &str, ) -> Result, AgentError> { - let paths: Vec> = vec![vec!["canister".into(), canister_id.into(), path.into()]]; + let paths: Vec> = vec![vec![ + "canister".into(), + Label::from_bytes(canister_id.as_slice()), + path.into(), + ]]; let cert = self.read_state_raw(paths, canister_id).await?; @@ -686,7 +690,7 @@ impl Agent { ) -> Result, AgentError> { let paths: Vec> = vec![vec![ "canister".into(), - canister_id.into(), + Label::from_bytes(canister_id.as_slice()), "metadata".into(), path.into(), ]]; diff --git a/ic-agent/src/agent/response_authentication.rs b/ic-agent/src/agent/response_authentication.rs index ceb32e4a..9ebdc966 100644 --- a/ic-agent/src/agent/response_authentication.rs +++ b/ic-agent/src/agent/response_authentication.rs @@ -1,6 +1,6 @@ use crate::agent::{RejectCode, RejectResponse, Replied, RequestStatusResponse}; use crate::{export::Principal, AgentError, RequestId}; -use ic_certification::{Certificate, Label, LookupResult}; +use ic_certification::{certificate::Certificate, hash_tree::Label, LookupResult}; use std::str::from_utf8; const DER_PREFIX: &[u8; 37] = b"\x30\x81\x82\x30\x1d\x06\x0d\x2b\x06\x01\x04\x01\x82\xdc\x7c\x05\x03\x01\x02\x01\x06\x0c\x2b\x06\x01\x04\x01\x82\xdc\x7c\x05\x03\x02\x01\x03\x61\x00"; @@ -27,31 +27,36 @@ pub fn extract_der(buf: Vec) -> Result, AgentError> { Ok(key.to_vec()) } -pub(crate) fn lookup_canister_info( - certificate: Certificate, +pub(crate) fn lookup_canister_info>( + certificate: Certificate, canister_id: Principal, path: &str, ) -> Result, AgentError> { - let path_canister = ["canister".into(), canister_id.into(), path.into()]; + let path_canister = [ + "canister".as_bytes(), + canister_id.as_slice(), + path.as_bytes(), + ]; lookup_value(&certificate, path_canister).map(<[u8]>::to_vec) } -pub(crate) fn lookup_canister_metadata( - certificate: Certificate, +pub(crate) fn lookup_canister_metadata>( + certificate: Certificate, canister_id: Principal, path: &str, ) -> Result, AgentError> { let path_canister = [ - "canister".into(), - canister_id.into(), - "metadata".into(), - path.into(), + "canister".as_bytes(), + canister_id.as_slice(), + "metadata".as_bytes(), + path.as_bytes(), ]; + lookup_value(&certificate, path_canister).map(<[u8]>::to_vec) } -pub(crate) fn lookup_request_status( - certificate: Certificate, +pub(crate) fn lookup_request_status>( + certificate: Certificate, request_id: &RequestId, ) -> Result { use AgentError::*; @@ -75,8 +80,8 @@ pub(crate) fn lookup_request_status( } } -pub(crate) fn lookup_rejection( - certificate: &Certificate, +pub(crate) fn lookup_rejection>( + certificate: &Certificate, request_id: &RequestId, ) -> Result { let reject_code = lookup_reject_code(certificate, request_id)?; @@ -89,14 +94,14 @@ pub(crate) fn lookup_rejection( })) } -pub(crate) fn lookup_reject_code( - certificate: &Certificate, +pub(crate) fn lookup_reject_code>( + certificate: &Certificate, request_id: &RequestId, ) -> Result { let path = [ - "request_status".into(), - request_id.to_vec().into(), - "reject_code".into(), + "request_status".as_bytes(), + request_id.as_slice(), + "reject_code".as_bytes(), ]; let code = lookup_value(certificate, path)?; let mut readable = code; @@ -104,49 +109,152 @@ pub(crate) fn lookup_reject_code( RejectCode::try_from(code_digit) } -pub(crate) fn lookup_reject_message( - certificate: &Certificate, +pub(crate) fn lookup_reject_message>( + certificate: &Certificate, request_id: &RequestId, ) -> Result { let path = [ - "request_status".into(), - request_id.to_vec().into(), - "reject_message".into(), + "request_status".as_bytes(), + request_id.as_slice(), + "reject_message".as_bytes(), ]; let msg = lookup_value(certificate, path)?; Ok(from_utf8(msg)?.to_string()) } -pub(crate) fn lookup_reply( - certificate: &Certificate, +pub(crate) fn lookup_reply>( + certificate: &Certificate, request_id: &RequestId, ) -> Result { let path = [ - "request_status".into(), - request_id.to_vec().into(), - "reply".into(), + "request_status".as_bytes(), + request_id.as_slice(), + "reply".as_bytes(), ]; let reply_data = lookup_value(certificate, path)?; let reply = Replied::CallReplied(Vec::from(reply_data)); Ok(RequestStatusResponse::Replied { reply }) } +/// The path to [`lookup_value`] +pub trait LookupPath { + type Item<'a>: AsRef<[u8]> + where + Self: 'a; + type Iter<'a>: Iterator> + where + Self: 'a; + fn iter(&self) -> Self::Iter<'_>; + fn into_vec(self) -> Vec>>; +} + +impl<'b, const N: usize> LookupPath for [&'b [u8]; N] { + type Item<'a> = &'a &'b [u8] where Self: 'a; + type Iter<'a> = std::slice::Iter<'a, &'b [u8]> where Self: 'a; + fn iter(&self) -> Self::Iter<'_> { + self.as_slice().iter() + } + fn into_vec(self) -> Vec>> { + self.map(Label::from_bytes).into() + } +} +impl<'b, 'c> LookupPath for &'c [&'b [u8]] { + type Item<'a> = &'a &'b [u8] where Self: 'a; + type Iter<'a> = std::slice::Iter<'a, &'b [u8]> where Self: 'a; + fn iter(&self) -> Self::Iter<'_> { + <[_]>::iter(self) + } + fn into_vec(self) -> Vec>> { + self.iter().map(|v| Label::from_bytes(v)).collect() + } +} +impl<'b> LookupPath for Vec<&'b [u8]> { + type Item<'a> = &'a &'b [u8] where Self: 'a; + type Iter<'a> = std::slice::Iter<'a, &'b [u8]> where Self: 'a; + fn iter(&self) -> Self::Iter<'_> { + <[_]>::iter(self.as_slice()) + } + fn into_vec(self) -> Vec>> { + self.into_iter().map(Label::from_bytes).collect() + } +} + +impl LookupPath for [Vec; N] { + type Item<'a> = &'a Vec where Self: 'a; + type Iter<'a> = std::slice::Iter<'a, Vec> where Self: 'a; + fn iter(&self) -> Self::Iter<'_> { + self.as_slice().iter() + } + fn into_vec(self) -> Vec>> { + self.map(Label::from).into() + } +} +impl<'c> LookupPath for &'c [Vec] { + type Item<'a> = &'a Vec where Self: 'a; + type Iter<'a> = std::slice::Iter<'a, Vec> where Self: 'a; + fn iter(&self) -> Self::Iter<'_> { + <[_]>::iter(self) + } + fn into_vec(self) -> Vec>> { + self.iter().map(|v| Label::from(v.clone())).collect() + } +} +impl LookupPath for Vec> { + type Item<'a> = &'a Vec where Self: 'a; + type Iter<'a> = std::slice::Iter<'a, Vec> where Self: 'a; + fn iter(&self) -> Self::Iter<'_> { + <[_]>::iter(self.as_slice()) + } + fn into_vec(self) -> Vec>> { + self.into_iter().map(Label::from).collect() + } +} + +impl + Into>, const N: usize> LookupPath for [Label; N] { + type Item<'a> = &'a Label where Self: 'a; + type Iter<'a> = std::slice::Iter<'a, Label> where Self: 'a; + fn iter(&self) -> Self::Iter<'_> { + self.as_slice().iter() + } + fn into_vec(self) -> Vec>> { + self.map(Label::from_label).into() + } +} +impl<'c, Storage: AsRef<[u8]> + Into>> LookupPath for &'c [Label] { + type Item<'a> = &'a Label where Self: 'a; + type Iter<'a> = std::slice::Iter<'a, Label> where Self: 'a; + fn iter(&self) -> Self::Iter<'_> { + <[_]>::iter(self) + } + fn into_vec(self) -> Vec>> { + self.iter() + .map(|v| Label::from_bytes(v.as_bytes())) + .collect() + } +} +impl LookupPath for Vec>> { + type Item<'a> = &'a Label> where Self: 'a; + type Iter<'a> = std::slice::Iter<'a, Label>> where Self: 'a; + fn iter(&self) -> Self::Iter<'_> { + <[_]>::iter(self.as_slice()) + } + fn into_vec(self) -> Vec>> { + self + } +} + /// Looks up a value in the certificate's tree at the specified hash. /// /// Returns the value if it was found; otherwise, errors with `LookupPathAbsent`, `LookupPathUnknown`, or `LookupPathError`. -pub fn lookup_value<'a, P>( - certificate: &'a Certificate<'a>, +pub fn lookup_value>( + certificate: &Certificate, path: P, -) -> Result<&'a [u8], AgentError> -where - for<'p> &'p P: IntoIterator, - P: Into>, -{ +) -> Result<&[u8], AgentError> { use AgentError::*; - match certificate.tree.lookup_path(&path) { - LookupResult::Absent => Err(LookupPathAbsent(path.into())), - LookupResult::Unknown => Err(LookupPathUnknown(path.into())), + match certificate.tree.lookup_path(path.iter()) { + LookupResult::Absent => Err(LookupPathAbsent(path.into_vec())), + LookupResult::Unknown => Err(LookupPathUnknown(path.into_vec())), LookupResult::Found(value) => Ok(value), - LookupResult::Error => Err(LookupPathError(path.into())), + LookupResult::Error => Err(LookupPathError(path.into_vec())), } } diff --git a/ic-certification/src/certificate.rs b/ic-certification/src/certificate.rs index 5dd054e7..f3aeceb8 100644 --- a/ic-certification/src/certificate.rs +++ b/ic-certification/src/certificate.rs @@ -1,30 +1,273 @@ -use crate::HashTree; +use crate::hash_tree::HashTree; /// A `Certificate` as defined in #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Certificate<'a> { +#[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[cfg_attr( + feature = "serde", + serde(bound(serialize = "Storage: serde_bytes::Serialize")) +)] +pub struct Certificate> { /// The hash tree. - pub tree: HashTree<'a>, + pub tree: HashTree, /// The signature of the root hash in `tree`. #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] - pub signature: Vec, + pub signature: Storage, /// A delegation from the root key to the key used to sign `signature`, if one exists. #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] - pub delegation: Option, + pub delegation: Option>, } /// A `Delegation` as defined in #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Delegation { +#[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[cfg_attr( + feature = "serde", + serde(bound(serialize = "Storage: serde_bytes::Serialize")) +)] +pub struct Delegation> { #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] - pub subnet_id: Vec, + pub subnet_id: Storage, #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] - pub certificate: Vec, + pub certificate: Storage, +} + +#[cfg(feature = "serde")] +mod serde_impl { + use super::{Certificate, Delegation}; + use crate::{hash_tree::HashTreeNode, serde_impl::*}; + + use std::{borrow::Cow, fmt, marker::PhantomData}; + + use serde::{ + de::{self, MapAccess, SeqAccess, Visitor}, + Deserialize, Deserializer, + }; + + #[derive(Deserialize)] + #[serde(field_identifier, rename_all = "snake_case")] + enum CertificateField { + Tree, + Signature, + Delegation, + } + struct CertificateVisitor(PhantomData); + + impl<'de, S: Storage> Visitor<'de> for CertificateVisitor + where + Delegation>: Deserialize<'de>, + HashTreeNode>: Deserialize<'de>, + { + type Value = Certificate>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct Delegation") + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: SeqAccess<'de>, + { + let tree = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + let signature = S::convert( + seq.next_element()? + .ok_or_else(|| de::Error::invalid_length(1, &self))?, + ); + let delegation = seq.next_element()?; + + Ok(Certificate { + tree, + signature, + delegation, + }) + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + let mut tree = None; + let mut signature = None; + let mut delegation = None; + while let Some(key) = map.next_key()? { + match key { + CertificateField::Tree => { + if tree.is_some() { + return Err(de::Error::duplicate_field("tree")); + } + tree = Some(map.next_value()?); + } + CertificateField::Signature => { + if signature.is_some() { + return Err(de::Error::duplicate_field("signature")); + } + signature = Some(map.next_value()?); + } + CertificateField::Delegation => { + if delegation.is_some() { + return Err(de::Error::duplicate_field("signature")); + } + delegation = Some(map.next_value()?); + } + } + } + let tree = tree.ok_or_else(|| de::Error::missing_field("tree"))?; + let signature = + S::convert(signature.ok_or_else(|| de::Error::missing_field("signature"))?); + Ok(Certificate { + tree, + signature, + delegation, + }) + } + } + + fn deserialize_certificate<'de, S: Storage, D>( + deserializer: D, + ) -> Result>, D::Error> + where + Delegation>: Deserialize<'de>, + HashTreeNode>: Deserialize<'de>, + D: Deserializer<'de>, + { + const FIELDS: &[&str] = &["tree", "signature", "delegation"]; + deserializer.deserialize_struct("Certificate", FIELDS, CertificateVisitor::(PhantomData)) + } + + impl<'de> Deserialize<'de> for Certificate> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserialize_certificate::(deserializer) + } + } + + impl<'de> Deserialize<'de> for Certificate<&'de [u8]> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserialize_certificate::(deserializer) + } + } + + impl<'de> Deserialize<'de> for Certificate> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserialize_certificate::(deserializer) + } + } + + #[derive(Deserialize)] + #[serde(field_identifier, rename_all = "snake_case")] + enum DelegationField { + SubnetId, + Certificate, + } + struct DelegationVisitor(PhantomData); + + impl<'de, S: Storage> Visitor<'de> for DelegationVisitor { + type Value = Delegation>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct Delegation") + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: SeqAccess<'de>, + { + let subnet_id = S::convert( + seq.next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?, + ); + let certificate = S::convert( + seq.next_element()? + .ok_or_else(|| de::Error::invalid_length(1, &self))?, + ); + Ok(Delegation { + subnet_id, + certificate, + }) + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + let mut subnet_id = None; + let mut certificate = None; + while let Some(key) = map.next_key()? { + match key { + DelegationField::SubnetId => { + if subnet_id.is_some() { + return Err(de::Error::duplicate_field("subnet_id")); + } + subnet_id = Some(map.next_value()?); + } + DelegationField::Certificate => { + if certificate.is_some() { + return Err(de::Error::duplicate_field("certificate")); + } + certificate = Some(map.next_value()?); + } + } + } + let subnet_id = + S::convert(subnet_id.ok_or_else(|| de::Error::missing_field("subnet_id"))?); + let certificate = + S::convert(certificate.ok_or_else(|| de::Error::missing_field("certificate"))?); + Ok(Delegation { + subnet_id, + certificate, + }) + } + } + + fn deserialize_delegation<'de, S: Storage, D>( + deserializer: D, + ) -> Result>, D::Error> + where + D: Deserializer<'de>, + { + const FIELDS: &[&str] = &["subnet_id", "certificate"]; + deserializer.deserialize_struct("Delegation", FIELDS, DelegationVisitor::(PhantomData)) + } + + impl<'de> Deserialize<'de> for Delegation> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserialize_delegation::(deserializer) + } + } + + impl<'de> Deserialize<'de> for Delegation<&'de [u8]> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserialize_delegation::(deserializer) + } + } + + impl<'de> Deserialize<'de> for Delegation> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserialize_delegation::(deserializer) + } + } } #[cfg(test)] @@ -33,19 +276,19 @@ mod tests { use super::*; use crate::hash_tree::{empty, fork, label, leaf}; - fn create_tree<'a>() -> HashTree<'a> { + fn create_tree() -> HashTree> { fork( fork( label( "a", fork( - fork(label("x", leaf(b"hello")), empty()), - label("y", leaf(b"world")), + fork(label("x", leaf(*b"hello")), empty()), + label("y", leaf(*b"world")), ), ), - label("b", leaf(b"good")), + label("b", leaf(*b"good")), ), - fork(label("c", empty()), label("d", leaf(b"morning"))), + fork(label("c", empty()), label("d", leaf(*b"morning"))), ) } diff --git a/ic-certification/src/hash_tree/mod.rs b/ic-certification/src/hash_tree/mod.rs index 64e5bd47..abf8d2e7 100644 --- a/ic-certification/src/hash_tree/mod.rs +++ b/ic-certification/src/hash_tree/mod.rs @@ -2,44 +2,112 @@ use hex::FromHexError; use sha2::Digest; -use std::borrow::Cow; +use std::{ + borrow::{Borrow, Cow}, + fmt, +}; /// Sha256 Digest: 32 bytes pub type Sha256Digest = [u8; 32]; #[derive(Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(from = "&serde_bytes::Bytes"))] -#[cfg_attr(feature = "serde", serde(into = "&serde_bytes::ByteBuf"))] /// For labeled [HashTreeNode] -pub struct Label(Vec); +pub struct Label>(Storage); + +impl> Label { + /// Create a label from bytes. + pub fn from_bytes<'a>(v: &'a [u8]) -> Self + where + &'a [u8]: Into, + { + Self(v.into()) + } + + /// Convert labels + pub fn from_label + Into>(s: Label) -> Self { + Self(s.0.into()) + } -impl Label { /// Returns this label as bytes. pub fn as_bytes(&self) -> &[u8] { self.0.as_ref() } + + /// The length of the output of [`Self::write_hex`] + fn hex_len(&self) -> usize { + self.as_bytes().len() * 2 + } + + /// Write out the hex + fn write_hex(&self, f: &mut impl fmt::Write) -> fmt::Result { + self.as_bytes() + .iter() + .try_for_each(|b| write!(f, "{:02X}", b)) + } } -#[cfg(feature = "serde")] -impl From