From e42c2cda990f81c9e82aa300d96126b4f124f972 Mon Sep 17 00:00:00 2001 From: Yiannis Marangos Date: Mon, 24 Jul 2023 17:45:40 +0300 Subject: [PATCH] WIP: Compile helios in a canister (#1) * Use stable Rust instead * Vendor `ic-http` from `bitcoin-canister` * config: Replace `reqwest` with `ic-http` * Replace most of `ethers` with `ethers-core` * consensus: replace `reqwest` with `ic-http` * client: replace `ethers` with `ethers-core` * client: Replace `gloo-timers` and `wasm-bindgen-futures` with `ic-cdk` * Remove tokio::task::spawn_blocking * remove ic-http/example_canister * use ic-cdk instead of wasm-timer --- Cargo.lock | 1263 +++++++++++-------------------- Cargo.toml | 2 +- cli/Cargo.toml | 3 - client/Cargo.toml | 7 +- client/src/client.rs | 21 +- client/src/node.rs | 6 +- client/src/rpc.rs | 2 +- common/Cargo.toml | 4 +- common/src/errors.rs | 15 +- common/src/http.rs | 9 + common/src/lib.rs | 1 + common/src/utils.rs | 2 +- config/Cargo.toml | 7 +- config/src/checkpoints.rs | 18 +- config/tests/checkpoints.rs | 2 +- consensus/Cargo.toml | 6 +- consensus/src/consensus.rs | 34 +- consensus/src/rpc/nimbus_rpc.rs | 71 +- consensus/src/types.rs | 2 +- examples/call.rs | 1 - execution/Cargo.toml | 4 +- execution/src/errors.rs | 2 +- execution/src/evm.rs | 14 +- execution/src/execution.rs | 16 +- execution/src/proof.rs | 6 +- execution/src/rpc/http_rpc.rs | 44 +- execution/src/rpc/mock_rpc.rs | 2 +- execution/src/rpc/mod.rs | 2 +- execution/src/types.rs | 5 +- execution/tests/execution.rs | 2 +- helios-ts/Cargo.toml | 2 +- ic-http/.gitignore | 12 + ic-http/Cargo.toml | 21 + ic-http/README.md | 122 +++ ic-http/src/http_request.rs | 31 + ic-http/src/lib.rs | 132 ++++ ic-http/src/mock.rs | 162 ++++ ic-http/src/request.rs | 109 +++ ic-http/src/response.rs | 55 ++ ic-http/src/storage.rs | 54 ++ ic-http/src/transform.rs | 122 +++ ic-http/tests/api.rs | 332 ++++++++ rust-toolchain | 1 - 43 files changed, 1762 insertions(+), 966 deletions(-) create mode 100644 common/src/http.rs create mode 100644 ic-http/.gitignore create mode 100644 ic-http/Cargo.toml create mode 100644 ic-http/README.md create mode 100644 ic-http/src/http_request.rs create mode 100644 ic-http/src/lib.rs create mode 100644 ic-http/src/mock.rs create mode 100644 ic-http/src/request.rs create mode 100644 ic-http/src/response.rs create mode 100644 ic-http/src/storage.rs create mode 100644 ic-http/src/transform.rs create mode 100644 ic-http/tests/api.rs delete mode 100644 rust-toolchain diff --git a/Cargo.lock b/Cargo.lock index 154d835b..1c8688e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,22 +13,19 @@ dependencies = [ ] [[package]] -name = "adler" -version = "1.0.2" +name = "addr2line" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] [[package]] -name = "aes" -version = "0.7.5" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher 0.3.0", - "cpufeatures", - "opaque-debug", -] +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" @@ -37,7 +34,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" dependencies = [ "cfg-if", - "cipher 0.4.4", + "cipher", "cpufeatures", ] @@ -54,9 +51,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -105,15 +102,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - [[package]] name = "async-lock" version = "2.7.0" @@ -131,7 +119,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] @@ -167,9 +155,9 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" dependencies = [ "proc-macro-error", "proc-macro2", @@ -183,6 +171,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide 0.7.1", + "object", + "rustc-demangle", +] + [[package]] name = "base16ct" version = "0.1.1" @@ -238,19 +241,27 @@ dependencies = [ ] [[package]] -name = "bit-set" -version = "0.5.3" +name = "binread" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f" dependencies = [ - "bit-vec", + "binread_derive", + "lazy_static", + "rustversion", ] [[package]] -name = "bit-vec" -version = "0.6.3" +name = "binread_derive" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" +dependencies = [ + "either", + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] name = "bitflags" @@ -309,9 +320,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", "serde", @@ -357,33 +368,51 @@ dependencies = [ ] [[package]] -name = "bzip2" -version = "0.4.4" +name = "camino" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" dependencies = [ - "bzip2-sys", - "libc", + "serde", ] [[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" +name = "candid" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "4df671c37a9c6168db0334f2b289dd4e02dea1bbefe1fb22c5d43b12d865aacd" dependencies = [ - "cc", - "libc", - "pkg-config", + "anyhow", + "binread", + "byteorder", + "candid_derive", + "codespan-reporting", + "crc32fast", + "data-encoding", + "hex", + "leb128", + "num-bigint", + "num-traits", + "num_enum 0.6.1", + "paste", + "pretty", + "serde", + "serde_bytes", + "sha2 0.10.6", + "stacker", + "thiserror", ] [[package]] -name = "camino" -version = "1.1.4" +name = "candid_derive" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +checksum = "810b3bd60244f282090652ffc7c30a9d23892e72dfe443e46ee55569044f7dd5" dependencies = [ - "serde", + "lazy_static", + "proc-macro2", + "quote", + "syn 2.0.26", ] [[package]] @@ -420,9 +449,6 @@ name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" -dependencies = [ - "jobserver", -] [[package]] name = "cfg-if" @@ -440,7 +466,7 @@ dependencies = [ "js-sys", "num-integer", "num-traits", - "time 0.1.45", + "time", "wasm-bindgen", "winapi", ] @@ -472,15 +498,6 @@ dependencies = [ "half", ] -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - [[package]] name = "cipher" version = "0.4.4" @@ -554,19 +571,19 @@ dependencies = [ "common", "config", "consensus", - "ethers", + "ethers-core", "execution", "eyre", "futures", - "gloo-timers", "hex", + "ic-cdk", + "ic-cdk-timers", "jsonrpsee", "log", "serde", "ssz-rs", "thiserror", "tokio", - "wasm-bindgen-futures", ] [[package]] @@ -600,7 +617,7 @@ dependencies = [ "digest 0.10.6", "getrandom 0.2.9", "hmac", - "k256 0.13.0", + "k256 0.13.1", "lazy_static", "serde", "sha2 0.10.6", @@ -609,21 +626,19 @@ dependencies = [ [[package]] name = "coins-bip39" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad2a68a46b9d8cc90484f0689adc0e4c890eb215bf698ae52e5235bb88f40be7" +checksum = "84f4d04ee18e58356accd644896aeb2094ddeafb6a713e056cef0c0a8e468c15" dependencies = [ "bitvec 0.17.4", "coins-bip32", "getrandom 0.2.9", - "hex", "hmac", "once_cell", "pbkdf2 0.12.1", "rand 0.8.5", "sha2 0.10.6", "thiserror", - "tracing", ] [[package]] @@ -656,9 +671,11 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" name = "common" version = "0.4.1" dependencies = [ - "ethers", + "ethers-core", "eyre", "hex", + "ic-cdk", + "ic-http", "serde", "ssz-rs", "thiserror", @@ -669,17 +686,17 @@ name = "config" version = "0.4.1" dependencies = [ "common", - "ethers", + "ethers-core", "eyre", "figment", "futures", "hex", "log", - "reqwest", "serde", + "serde_json", "serde_yaml", "ssz-rs", - "strum", + "strum 0.24.1", "thiserror", "tokio", ] @@ -693,14 +710,14 @@ dependencies = [ "chrono", "common", "config", - "ethers", + "ethers-core", "eyre", "futures", "hex", + "ic-cdk", "log", "milagro_bls", "openssl", - "reqwest", "serde", "serde_json", "ssz-rs", @@ -708,34 +725,6 @@ dependencies = [ "thiserror", "tokio", "toml 0.5.11", - "wasm-timer", -] - -[[package]] -name = "console" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "regex", - "terminal_size", - "unicode-width", - "winapi", -] - -[[package]] -name = "console" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "windows-sys 0.42.0", ] [[package]] @@ -760,21 +749,6 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation" version = "0.9.3" @@ -973,7 +947,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher 0.4.4", + "cipher", ] [[package]] @@ -1010,7 +984,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] @@ -1027,7 +1001,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] @@ -1065,6 +1039,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "data-encoding" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" + [[package]] name = "der" version = "0.6.1" @@ -1095,24 +1075,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "dialoguer" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9dd058f8b65922819fabb4a41e7d1964e56344042c26efbccd465202c23fa0c" -dependencies = [ - "console 0.14.1", - "lazy_static", - "tempfile", - "zeroize", -] - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - [[package]] name = "digest" version = "0.9.0" @@ -1228,7 +1190,7 @@ checksum = "106401dadc137d05cb0d4ab4d42be089746aefdfe8992df4d0edcf351c16ddca" dependencies = [ "der 0.7.3", "digest 0.10.6", - "elliptic-curve 0.13.3", + "elliptic-curve 0.13.5", "rfc6979 0.4.0", "signature 2.1.0", ] @@ -1260,9 +1222,9 @@ dependencies = [ [[package]] name = "elliptic-curve" -version = "0.13.3" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cdacd4d6ed3f9b98680b679c0e52a823b8a2c7a97358d508fe247f2180c282" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" dependencies = [ "base16ct 0.2.0", "crypto-bigint 0.5.1", @@ -1277,21 +1239,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ena" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" -dependencies = [ - "log", -] - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - [[package]] name = "encoding_rs" version = "0.8.32" @@ -1303,14 +1250,14 @@ dependencies = [ [[package]] name = "enr" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb4d5fbf6f56acecd38f5988eb2e4ae412008a2a30268c748c701ec6322f39d4" +checksum = "cf56acd72bb22d2824e66ae8e9e5ada4d0de17a69c7fd35569dde2ada8ec9116" dependencies = [ "base64 0.13.1", "bytes", "hex", - "k256 0.13.0", + "k256 0.13.1", "log", "rand 0.8.5", "rlp 0.5.2", @@ -1359,7 +1306,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" dependencies = [ - "aes 0.8.2", + "aes", "ctr", "digest 0.10.6", "hex", @@ -1452,9 +1399,9 @@ dependencies = [ [[package]] name = "ethers" -version = "2.0.2" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697aba1bec98cb86e7bebd69f9bb365218871464137af9e93e7a72bd6dc421d0" +checksum = "96b4026b97da8281276744741fac7eb385da905f6093c583331fa2953fdd4253" dependencies = [ "ethers-addressbook", "ethers-contract", @@ -1463,14 +1410,13 @@ dependencies = [ "ethers-middleware", "ethers-providers", "ethers-signers", - "ethers-solc", ] [[package]] name = "ethers-addressbook" -version = "2.0.2" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b603812e5e4d63521c691cbc1f34743879e96a1ee96c6594639d7fa0cf6fbc" +checksum = "edcb6ffefc230d8c42874c51b28dc11dbb8de50b27a8fdf92648439d6baa68dc" dependencies = [ "ethers-core", "once_cell", @@ -1480,14 +1426,15 @@ dependencies = [ [[package]] name = "ethers-contract" -version = "2.0.2" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4e8ed7c2b2a22e07b65ae0eb426c948a7448f1be15c66e4813e02c423751fc9" +checksum = "0d4719a44c3d37ab07c6dea99ab174068d8c35e441b60b6c20ce4e48357273e8" dependencies = [ "ethers-contract-abigen", "ethers-contract-derive", "ethers-core", "ethers-providers", + "ethers-signers", "futures-util", "hex", "once_cell", @@ -1499,72 +1446,66 @@ dependencies = [ [[package]] name = "ethers-contract-abigen" -version = "2.0.2" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf0984f4ec4e267fd27b7c9fa2f73e72c5c98491a73f777290654154d104f723" +checksum = "155ea1b84d169d231317ed86e307af6f2bed6b40dd17e5e94bc84da21cadb21c" dependencies = [ "Inflector", "dunce", "ethers-core", - "ethers-etherscan", "eyre", - "getrandom 0.2.9", "hex", "prettyplease", "proc-macro2", "quote", "regex", - "reqwest", "serde", "serde_json", - "syn 1.0.109", - "tokio", + "syn 2.0.26", "toml 0.7.3", - "url", "walkdir", ] [[package]] name = "ethers-contract-derive" -version = "2.0.2" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914e9211077a1b590af1ee6b8dfbd54515c808119546c95da69479908dc3d4de" +checksum = "8567ff196c4a37c1a8c90ec73bda0ad2062e191e4f0a6dc4d943e2ec4830fc88" dependencies = [ + "Inflector", "ethers-contract-abigen", "ethers-core", "hex", "proc-macro2", "quote", - "syn 1.0.109", + "serde_json", + "syn 2.0.26", ] [[package]] name = "ethers-core" -version = "2.0.2" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40bf114f1017ace0f622f1652f59c2c5e1abfe7d88891cca0c43da979b351de0" +checksum = "60ca2514feb98918a0a31de7e1983c29f2267ebf61b2dc5d4294f91e5b866623" dependencies = [ "arrayvec 0.7.2", "bytes", "cargo_metadata", "chrono", - "convert_case", - "elliptic-curve 0.13.3", + "elliptic-curve 0.13.5", "ethabi", "generic-array", - "getrandom 0.2.9", "hex", - "k256 0.13.0", - "num_enum", + "k256 0.13.1", + "num_enum 0.6.1", "once_cell", "open-fastrlp", - "proc-macro2", "rand 0.8.5", "rlp 0.5.2", "serde", "serde_json", - "strum", - "syn 1.0.109", + "strum 0.25.0", + "syn 2.0.26", "tempfile", "thiserror", "tiny-keccak 2.0.2", @@ -1573,13 +1514,11 @@ dependencies = [ [[package]] name = "ethers-etherscan" -version = "2.0.2" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8920b59cf81e357df2c8102d6a9dc81c2d68f7409543ff3b6868851ecf007807" +checksum = "22b3a8269d3df0ed6364bc05b4735b95f4bf830ce3aef87d5e760fb0e93e5b91" dependencies = [ "ethers-core", - "ethers-solc", - "getrandom 0.2.9", "reqwest", "semver 1.0.17", "serde", @@ -1590,9 +1529,9 @@ dependencies = [ [[package]] name = "ethers-middleware" -version = "2.0.2" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b30f67c1883ed68bd38aedbdd321831382c12e1b95089c8261c79bb85e4da" +checksum = "e0c339aad74ae5c451d27e0e49c7a3c7d22620b119b4f9291d7aa21f72d7f366" dependencies = [ "async-trait", "auto_impl", @@ -1617,9 +1556,9 @@ dependencies = [ [[package]] name = "ethers-providers" -version = "2.0.2" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2fa0857eaad0c1678f982a2f4cfbe33ebd51d273cc93de0182b7c693f2a84a1" +checksum = "b411b119f1cf0efb69e2190883dee731251882bb21270f893ee9513b3a697c48" dependencies = [ "async-trait", "auto_impl", @@ -1630,7 +1569,6 @@ dependencies = [ "futures-core", "futures-timer", "futures-util", - "getrandom 0.2.9", "hashers", "hex", "http", @@ -1642,7 +1580,6 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tokio-tungstenite", "tracing", "tracing-futures", "url", @@ -1654,14 +1591,14 @@ dependencies = [ [[package]] name = "ethers-signers" -version = "2.0.2" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5caa7cad4f444931d0ed45818e609847781582399eff0be5c089e8666475c7fb" +checksum = "4864d387456a9c09a1157fa10e1528b29d90f1d859443acf06a1b23365fb518c" dependencies = [ "async-trait", "coins-bip32", "coins-bip39", - "elliptic-curve 0.13.3", + "elliptic-curve 0.13.5", "eth-keystore", "ethers-core", "hex", @@ -1671,38 +1608,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "ethers-solc" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139542f51f4c405d0dd7e97c34232140a14e8744d1cf121777355567187259e4" -dependencies = [ - "cfg-if", - "dunce", - "ethers-core", - "getrandom 0.2.9", - "glob", - "hex", - "home", - "md-5", - "num_cpus", - "once_cell", - "path-slash", - "rayon", - "regex", - "semver 1.0.17", - "serde", - "serde_json", - "solang-parser", - "svm-rs", - "thiserror", - "tiny-keccak 2.0.2", - "tokio", - "tracing", - "walkdir", - "yansi", -] - [[package]] name = "event-listener" version = "2.5.3" @@ -1717,14 +1622,12 @@ dependencies = [ "bytes", "common", "consensus", - "ethers", + "ethers-core", "eyre", "futures", "hex", - "hyper", "log", "openssl", - "reqwest", "revm", "serde", "serde_json", @@ -1812,12 +1715,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" version = "1.0.25" @@ -1825,7 +1722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.6.2", ] [[package]] @@ -1910,16 +1807,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "funty" version = "2.0.0" @@ -1992,7 +1879,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] @@ -2090,16 +1977,16 @@ dependencies = [ ] [[package]] -name = "glob" -version = "0.3.1" +name = "gimli" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "globset" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df" dependencies = [ "aho-corasick", "bstr", @@ -2142,9 +2029,9 @@ dependencies = [ [[package]] name = "gloo-utils" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" +checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" dependencies = [ "js-sys", "serde", @@ -2323,15 +2210,6 @@ dependencies = [ "digest 0.10.6", ] -[[package]] -name = "home" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408" -dependencies = [ - "winapi", -] - [[package]] name = "http" version = "0.2.9" @@ -2412,19 +2290,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "iana-time-zone" version = "0.1.56" @@ -2450,24 +2315,83 @@ dependencies = [ ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "ic-cdk" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "08d4c0b932bf454d5d60e61e13c3c944972fcfd74dc82b9ed5c8b0a75979cf50" +dependencies = [ + "candid", + "ic-cdk-macros", + "ic0", + "serde", + "serde_bytes", +] [[package]] -name = "idna" -version = "0.3.0" +name = "ic-cdk-macros" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "b4587624e64b8db56224033ee74e5c246d39be15375d03d3df7c117d49d18487" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "candid", + "proc-macro2", + "quote", + "serde", + "serde_tokenstream", + "syn 1.0.109", ] [[package]] -name = "image" -version = "0.24.6" +name = "ic-cdk-timers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "198e55e4d9e069903fbea1dceae6fd28f7e0b38d5a4e1026ed2c772e1d55f5e0" +dependencies = [ + "futures", + "ic-cdk", + "ic0", + "serde", + "serde_bytes", + "slotmap", +] + +[[package]] +name = "ic-http" +version = "0.1.0" +dependencies = [ + "candid", + "futures", + "ic-cdk", + "ic-cdk-macros", + "serde_json", + "tokio", +] + +[[package]] +name = "ic0" +version = "0.18.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576c539151d4769fb4d1a0c25c4108dd18facd04c5695b02cf2d226ab4e43aa5" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" dependencies = [ @@ -2570,18 +2494,6 @@ dependencies = [ "hashbrown 0.12.3", ] -[[package]] -name = "indicatif" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" -dependencies = [ - "console 0.15.5", - "lazy_static", - "number_prefix", - "regex", -] - [[package]] name = "inlinable_string" version = "0.1.15" @@ -2623,18 +2535,6 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" 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" version = "0.10.5" @@ -2650,15 +2550,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" -[[package]] -name = "jobserver" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" -dependencies = [ - "libc", -] - [[package]] name = "jpeg-decoder" version = "0.3.0" @@ -2736,7 +2627,7 @@ dependencies = [ "hyper", "jsonrpsee-types", "lazy_static", - "parking_lot 0.12.1", + "parking_lot", "rand 0.8.5", "rustc-hash", "serde", @@ -2872,13 +2763,13 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955890845095ccf31ef83ad41a05aabb4d8cc23dc3cac5a9f5c89cf26dd0da75" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if", "ecdsa 0.16.4", - "elliptic-curve 0.13.3", + "elliptic-curve 0.13.5", "once_cell", "sha2 0.10.6", "signature 2.1.0", @@ -2904,38 +2795,6 @@ dependencies = [ "tiny-keccak 1.5.0", ] -[[package]] -name = "lalrpop" -version = "0.19.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34313ec00c2eb5c3c87ca6732ea02dcf3af99c3ff7a8fb622ffb99c9d860a87" -dependencies = [ - "ascii-canvas", - "bit-set", - "diff", - "ena", - "is-terminal", - "itertools", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak 2.0.2", - "unicode-xid", -] - -[[package]] -name = "lalrpop-util" -version = "0.19.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c1f7869c94d214466c5fd432dfed12c379fd87786768d36455892d46b18edd" -dependencies = [ - "regex", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -2945,11 +2804,17 @@ dependencies = [ "spin", ] +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "libc" -version = "0.2.141" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" @@ -3001,16 +2866,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", -] - -[[package]] -name = "md-5" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" -dependencies = [ - "digest 0.10.6", + "regex-automata 0.1.10", ] [[package]] @@ -3056,41 +2912,26 @@ dependencies = [ ] [[package]] -name = "mio" -version = "0.8.6" +name = "miniz_oxide" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ - "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "adler", ] [[package]] -name = "native-tls" -version = "0.2.11" +name = "mio" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ - "lazy_static", "libc", "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.45.0", ] -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - [[package]] name = "nix" version = "0.26.2" @@ -3136,6 +2977,7 @@ dependencies = [ "autocfg", "num-integer", "num-traits", + "serde", ] [[package]] @@ -3205,7 +3047,16 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ - "num_enum_derive", + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", ] [[package]] @@ -3221,10 +3072,25 @@ dependencies = [ ] [[package]] -name = "number_prefix" -version = "0.4.0" +name = "num_enum_derive" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.26", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] [[package]] name = "once_cell" @@ -3292,7 +3158,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] @@ -3373,17 +3239,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -3391,21 +3246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.7", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -3422,21 +3263,10 @@ dependencies = [ ] [[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "path-slash" -version = "0.2.1" +name = "paste" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pathfinder_geometry" @@ -3464,9 +3294,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ "digest 0.10.6", - "hmac", - "password-hash", - "sha2 0.10.6", ] [[package]] @@ -3499,7 +3326,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] @@ -3518,16 +3345,6 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "petgraph" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" -dependencies = [ - "fixedbitset", - "indexmap", -] - [[package]] name = "pharos" version = "0.5.3" @@ -3538,81 +3355,24 @@ dependencies = [ "rustc_version 0.4.0", ] -[[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" -dependencies = [ - "phf_macros", - "phf_shared 0.11.1", -] - -[[package]] -name = "phf_generator" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" -dependencies = [ - "phf_shared 0.11.1", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" -dependencies = [ - "phf_generator", - "phf_shared 0.11.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" -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" -version = "1.0.12" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.26", ] [[package]] @@ -3707,7 +3467,7 @@ dependencies = [ "bitflags", "crc32fast", "flate2", - "miniz_oxide", + "miniz_oxide 0.6.2", ] [[package]] @@ -3717,19 +3477,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] -name = "precomputed-hash" -version = "0.1.1" +name = "pretty" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +checksum = "563c9d701c3a31dfffaaf9ce23507ba09cbe0b9125ba176d15e629b0235e9acc" +dependencies = [ + "arrayvec 0.5.2", + "typed-arena", + "unicode-segmentation", +] [[package]] name = "prettyplease" -version = "0.1.25" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 1.0.109", + "syn 2.0.26", ] [[package]] @@ -3795,9 +3560,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -3810,16 +3575,25 @@ checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.26", "version_check", "yansi", ] +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + [[package]] name = "quote" -version = "1.0.26" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -3960,13 +3734,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.3" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-automata 0.3.3", + "regex-syntax 0.7.4", ] [[package]] @@ -3975,7 +3750,18 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.4", ] [[package]] @@ -3984,11 +3770,17 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + [[package]] name = "reqwest" -version = "0.11.16" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ "base64 0.21.0", "bytes", @@ -3999,30 +3791,22 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-rustls", - "hyper-tls", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-native-tls", - "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", "winreg", ] @@ -4037,7 +3821,7 @@ dependencies = [ "bytes", "hashbrown 0.13.2", "hex", - "num_enum", + "num_enum 0.5.11", "primitive-types 0.12.1", "revm_precompiles", "rlp 0.5.2", @@ -4139,6 +3923,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -4197,9 +3987,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -4209,9 +3999,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ "base64 0.21.0", ] @@ -4234,7 +4024,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" dependencies = [ - "cipher 0.4.4", + "cipher", ] [[package]] @@ -4272,11 +4062,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -4342,9 +4132,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.8.2" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ "bitflags", "core-foundation", @@ -4355,9 +4145,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" dependencies = [ "core-foundation-sys", "libc", @@ -4404,9 +4194,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.159" +version = "1.0.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "e91f70896d6720bc714a4a57d22fc91f1db634680e65c8efe13323f1fa38d53f" dependencies = [ "serde_derive", ] @@ -4422,22 +4212,31 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "serde_bytes" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "a6250dde8342e0232232be9ca3db7aa40aceb5a3e5dd9bddbc00d99a007cde49" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", @@ -4453,6 +4252,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_tokenstream" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "797ba1d80299b264f3aac68ab5d12e5825a561749db4df7cd7c8083900c5d4e9" +dependencies = [ + "proc-macro2", + "serde", + "syn 1.0.109", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4491,17 +4301,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.6", -] - [[package]] name = "sha2" version = "0.9.9" @@ -4574,12 +4373,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - [[package]] name = "slab" version = "0.4.8" @@ -4589,6 +4382,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "1.10.0" @@ -4620,19 +4422,6 @@ dependencies = [ "sha-1", ] -[[package]] -name = "solang-parser" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff87dae6cdccacdbf3b19e99b271083556e808de0f59c74a01482f64fdbc61fc" -dependencies = [ - "itertools", - "lalrpop", - "lalrpop-util", - "phf", - "unicode-xid", -] - [[package]] name = "spin" version = "0.5.2" @@ -4675,23 +4464,23 @@ dependencies = [ ] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "stacker" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "winapi", +] [[package]] -name = "string_cache" -version = "0.8.7" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot 0.12.1", - "phf_shared 0.10.0", - "precomputed-hash", -] +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" @@ -4705,7 +4494,16 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "strum_macros", + "strum_macros 0.24.3", +] + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros 0.25.1", ] [[package]] @@ -4721,6 +4519,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6069ca09d878a33f883cc06aaa9718ede171841d3832450354410b718b097232" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.26", +] + [[package]] name = "substrate-bn" version = "0.6.0" @@ -4754,37 +4565,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "svm-rs" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01afefe60c02f4a2271fb15d1965c37856712cebb338330b06649d12afec42df" -dependencies = [ - "anyhow", - "cfg-if", - "clap", - "console 0.14.1", - "dialoguer", - "fs2", - "hex", - "home", - "indicatif", - "itertools", - "once_cell", - "rand 0.8.5", - "reqwest", - "semver 1.0.17", - "serde", - "serde_json", - "sha2 0.9.9", - "tempfile", - "thiserror", - "tokio", - "tracing", - "url", - "zip", -] - [[package]] name = "syn" version = "1.0.109" @@ -4798,9 +4578,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -4826,17 +4606,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - [[package]] name = "termcolor" version = "1.2.0" @@ -4846,16 +4615,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "terminal_size" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "textwrap" version = "0.16.0" @@ -4879,7 +4638,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] @@ -4903,22 +4662,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "time" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" -dependencies = [ - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" - [[package]] name = "tiny-keccak" version = "1.5.0" @@ -4964,42 +4707,33 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.27.0" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", + "syn 2.0.26", ] [[package]] @@ -5015,31 +4749,15 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", "tokio", ] -[[package]] -name = "tokio-tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" -dependencies = [ - "futures-util", - "log", - "rustls", - "tokio", - "tokio-rustls", - "tungstenite", - "webpki", - "webpki-roots", -] - [[package]] name = "tokio-util" version = "0.7.7" @@ -5232,25 +4950,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" [[package]] -name = "tungstenite" -version = "0.18.0" +name = "typed-arena" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand 0.8.5", - "rustls", - "sha1", - "thiserror", - "url", - "utf-8", - "webpki", -] +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" @@ -5368,12 +5071,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "uuid" version = "0.8.2" @@ -5506,21 +5203,6 @@ version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "web-sys" version = "0.3.61" @@ -5596,21 +5278,6 @@ dependencies = [ "windows-targets 0.48.0", ] -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "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-sys" version = "0.45.0" @@ -5821,53 +5488,3 @@ name = "zeroize" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" - -[[package]] -name = "zip" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0445d0fbc924bb93539b4316c11afb121ea39296f99a3c4c9edad09e3658cdef" -dependencies = [ - "aes 0.7.5", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2 0.11.0", - "sha1", - "time 0.3.20", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" -dependencies = [ - "cc", - "libc", - "pkg-config", -] diff --git a/Cargo.toml b/Cargo.toml index 84940cc4..0854c96f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ dotenv = "0.15.0" tokio = { version = "1", features = ["full"] } eyre = "0.6.8" dirs = "4.0.0" -ethers = { version = "2.0.2", features = [ "abigen" ] } +ethers = { version = "2.0.8", default-features = false } env_logger = "0.9.0" log = "0.4.17" tracing-test = "0.2.4" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 53b717b3..cfbfc203 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,5 +1,3 @@ -cargo-features = ["different-binary-name"] - [package] name = "cli" version = "0.4.1" @@ -7,7 +5,6 @@ edition = "2021" [[bin]] name = "cli" -filename = "helios" path = "src/main.rs" [dependencies] diff --git a/client/Cargo.toml b/client/Cargo.toml index c310ab68..5150f7ec 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -8,7 +8,7 @@ eyre = "0.6.8" serde = { version = "1.0.143", features = ["derive"] } hex = "0.4.3" ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" } -ethers = "2.0.2" +ethers-core = { version = "2.0.8", default-features = false } futures = "0.3.23" log = "0.4.17" thiserror = "1.0.37" @@ -23,7 +23,6 @@ jsonrpsee = { version = "0.15.1", features = ["full"] } tokio = { version = "1", features = ["full"] } [target.'cfg(target_arch = "wasm32")'.dependencies] -gloo-timers = "0.2.6" -wasm-bindgen-futures = "0.4.33" +ic-cdk-timers = "0.4.0" +ic-cdk = "0.10.0" tokio = { version = "1", features = ["sync"] } - diff --git a/client/src/client.rs b/client/src/client.rs index 8ac5acf3..36fb5e14 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -3,9 +3,8 @@ use std::sync::Arc; use config::networks::Network; use consensus::errors::ConsensusError; -use ethers::prelude::{Address, U256}; -use ethers::types::{ - FeeHistory, Filter, Log, SyncingStatus, Transaction, TransactionReceipt, H256, +use ethers_core::types::{ + Address, FeeHistory, Filter, Log, SyncingStatus, Transaction, TransactionReceipt, H256, U256, }; use eyre::{eyre, Result}; @@ -24,9 +23,9 @@ use tokio::spawn; use tokio::time::sleep; #[cfg(target_arch = "wasm32")] -use gloo_timers::callback::Interval; +use ic_cdk::spawn; #[cfg(target_arch = "wasm32")] -use wasm_bindgen_futures::spawn_local; +use ic_cdk_timers::set_timer_interval; use crate::database::Database; use crate::errors::NodeError; @@ -249,6 +248,8 @@ impl Client { let config = Arc::new(config); let node = Node::new(config.clone())?; let node = Arc::new(RwLock::new(node)); + + #[cfg(not(target_arch = "wasm32"))] let mut rpc: Option = None; #[cfg(not(target_arch = "wasm32"))] @@ -331,17 +332,19 @@ impl Client { #[cfg(target_arch = "wasm32")] fn start_advance_thread(&self) { + use std::time::Duration; + let node = self.node.clone(); - Interval::new(12000, move || { + + set_timer_interval(Duration::from_secs(12), move || { let node = node.clone(); - spawn_local(async move { + spawn(async move { let res = node.write().await.advance().await; if let Err(err) = res { warn!("consensus error: {}", err); } }); - }) - .forget(); + }); } async fn boot_from_fallback(&self) -> eyre::Result<()> { diff --git a/client/src/node.rs b/client/src/node.rs index 75c299d8..0c22791e 100644 --- a/client/src/node.rs +++ b/client/src/node.rs @@ -2,9 +2,9 @@ use std::collections::BTreeMap; use std::sync::Arc; use std::time::Duration; -use ethers::prelude::{Address, U256}; -use ethers::types::{ - FeeHistory, Filter, Log, SyncProgress, SyncingStatus, Transaction, TransactionReceipt, H256, +use ethers_core::types::{ + Address, FeeHistory, Filter, Log, SyncProgress, SyncingStatus, Transaction, TransactionReceipt, + H256, U256, }; use eyre::{eyre, Result}; diff --git a/client/src/rpc.rs b/client/src/rpc.rs index 66e35e83..ad963b5f 100644 --- a/client/src/rpc.rs +++ b/client/src/rpc.rs @@ -1,4 +1,4 @@ -use ethers::{ +use ethers_core::{ abi::AbiEncode, types::{Address, Filter, Log, SyncingStatus, Transaction, TransactionReceipt, H256, U256}, }; diff --git a/common/Cargo.toml b/common/Cargo.toml index b92b88d1..5a616ec2 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -8,5 +8,7 @@ eyre = "0.6.8" serde = { version = "1.0.143", features = ["derive"] } hex = "0.4.3" ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" } -ethers = "2.0.2" +ethers-core = "2.0.8" thiserror = "1.0.37" +ic-cdk = "0.10.0" +ic-http = { path = "../ic-http" } diff --git a/common/src/errors.rs b/common/src/errors.rs index ad74d995..3eadd62f 100644 --- a/common/src/errors.rs +++ b/common/src/errors.rs @@ -1,4 +1,5 @@ -use ethers::types::H256; +use ethers_core::types::H256; +use ic_cdk::api::call::RejectionCode; use thiserror::Error; use crate::types::BlockTag; @@ -42,3 +43,15 @@ impl RpcError { } } } + +#[derive(Debug, Error)] +pub enum HttpError { + #[error("canister call error: rejection code: {0:?}, message: {1}")] + CanisterCall(RejectionCode, String), +} + +impl From<(RejectionCode, String)> for HttpError { + fn from(value: (RejectionCode, String)) -> Self { + HttpError::CanisterCall(value.0, value.1) + } +} diff --git a/common/src/http.rs b/common/src/http.rs new file mode 100644 index 00000000..628b6028 --- /dev/null +++ b/common/src/http.rs @@ -0,0 +1,9 @@ +use crate::errors::HttpError; +use ic_cdk::api::management_canister::http_request::HttpResponse; + +pub async fn http_get(url: &str) -> Result { + let req = ic_http::create_request().get(url).build(); + // TODO: should we pass cycles in http_get method or we should have a default one? + let resp = ic_http::http_request(req, 2_603_101_200).await?; + Ok(resp.0) +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 9040a8f7..3d55834a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,3 +1,4 @@ pub mod errors; +pub mod http; pub mod types; pub mod utils; diff --git a/common/src/utils.rs b/common/src/utils.rs index b041fe47..245eb73c 100644 --- a/common/src/utils.rs +++ b/common/src/utils.rs @@ -1,4 +1,4 @@ -use ethers::prelude::Address; +use ethers_core::types::Address; use eyre::Result; use ssz_rs::{Node, Vector}; diff --git a/config/Cargo.toml b/config/Cargo.toml index 426eb759..ed880eea 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -1,4 +1,3 @@ - [package] name = "config" version = "0.4.1" @@ -9,13 +8,13 @@ eyre = "0.6.8" serde = { version = "1.0.143", features = ["derive"] } hex = "0.4.3" ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" } -ethers = "2.0.2" +ethers-core = { version = "2.0.8", default-features = false } figment = { version = "0.10.7", features = ["toml", "env"] } thiserror = "1.0.37" log = "0.4.17" -reqwest = "0.11.13" serde_yaml = "0.9.14" -strum = "0.24.1" +serde_json = "1.0.103" +strum = { version = "0.24.1", features = ["derive"] } futures = "0.3.23" common = { path = "../common" } diff --git a/config/src/checkpoints.rs b/config/src/checkpoints.rs index 020641b5..454f5ed1 100644 --- a/config/src/checkpoints.rs +++ b/config/src/checkpoints.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; -use ethers::types::H256; +use common::http::http_get; +use ethers_core::types::H256; use serde::{Deserialize, Serialize}; use crate::networks; @@ -87,9 +88,8 @@ impl CheckpointFallback { /// The list is defined in [ethPandaOps/checkpoint-fallback-service](https://github.com/ethpandaops/checkpoint-sync-health-checks/blob/master/_data/endpoints.yaml). pub async fn build(mut self) -> eyre::Result { // Fetch the services - let client = reqwest::Client::new(); - let res = client.get(CHECKPOINT_SYNC_SERVICES_LIST).send().await?; - let yaml = res.text().await?; + let resp = http_get(CHECKPOINT_SYNC_SERVICES_LIST).await?; + let yaml = String::from_utf8(resp.body)?; // Parse the yaml content results. let list: serde_yaml::Value = serde_yaml::from_str(&yaml)?; @@ -122,10 +122,9 @@ impl CheckpointFallback { } async fn query_service(endpoint: &str) -> Option { - let client = reqwest::Client::new(); let constructed_url = Self::construct_url(endpoint); - let res = client.get(&constructed_url).send().await.ok()?; - let raw: RawSlotResponse = res.json().await.ok()?; + let resp = http_get(&constructed_url).await.ok()?; + let raw: RawSlotResponse = serde_json::from_slice(&resp.body).ok()?; Some(raw) } @@ -199,10 +198,9 @@ impl CheckpointFallback { /// service api url. pub async fn fetch_checkpoint_from_api(url: &str) -> eyre::Result { // Fetch the url - let client = reqwest::Client::new(); let constructed_url = Self::construct_url(url); - let res = client.get(constructed_url).send().await?; - let raw: RawSlotResponse = res.json().await?; + let resp = http_get(&constructed_url).await?; + let raw: RawSlotResponse = serde_json::from_slice(&resp.body)?; let slot = raw.data.slots[0].clone(); slot.block_root .ok_or_else(|| eyre::eyre!("Checkpoint not in returned slot")) diff --git a/config/tests/checkpoints.rs b/config/tests/checkpoints.rs index 1d50e616..a6cde30f 100644 --- a/config/tests/checkpoints.rs +++ b/config/tests/checkpoints.rs @@ -1,5 +1,5 @@ use config::networks; -use ethers::types::H256; +use ethers_core::types::H256; #[tokio::test] async fn test_checkpoint_fallback() { diff --git a/consensus/Cargo.toml b/consensus/Cargo.toml index 9ab1576d..fae59229 100644 --- a/consensus/Cargo.toml +++ b/consensus/Cargo.toml @@ -11,14 +11,13 @@ serde_json = "1.0.85" hex = "0.4.3" ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" } milagro_bls = { git = "https://github.com/Snowfork/milagro_bls" } -ethers = "2.0.2" +ethers-core = { version = "2.0.8", default-features = false } bytes = "1.2.1" toml = "0.5.9" async-trait = "0.1.57" log = "0.4.17" chrono = "0.4.23" thiserror = "1.0.37" -reqwest = { version = "0.11.13", features = ["json"] } superstruct = "0.7.0" common = { path = "../common" } @@ -29,5 +28,4 @@ openssl = { version = "0.10", features = ["vendored"] } tokio = { version = "1", features = ["full"] } [target.'cfg(target_arch = "wasm32")'.dependencies] -wasm-timer = "0.2.5" - +ic-cdk = "0.10.0" diff --git a/consensus/src/consensus.rs b/consensus/src/consensus.rs index 7a8e45f1..dfaf00e6 100644 --- a/consensus/src/consensus.rs +++ b/consensus/src/consensus.rs @@ -21,16 +21,6 @@ use super::rpc::ConsensusRpc; use super::types::*; use super::utils::*; -#[cfg(not(target_arch = "wasm32"))] -use std::time::SystemTime; -#[cfg(not(target_arch = "wasm32"))] -use std::time::UNIX_EPOCH; - -#[cfg(target_arch = "wasm32")] -use wasm_timer::SystemTime; -#[cfg(target_arch = "wasm32")] -use wasm_timer::UNIX_EPOCH; - // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md // does not implement force updates @@ -531,13 +521,13 @@ impl ConsensusClient { fn age(&self, slot: u64) -> Duration { let expected_time = self.slot_timestamp(slot); - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let now = duration_since_epoch(); let delay = now - std::time::Duration::from_secs(expected_time); chrono::Duration::from_std(delay).unwrap() } pub fn expected_current_slot(&self) -> u64 { - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let now = duration_since_epoch(); let genesis_time = self.config.chain.genesis_time; let since_genesis = now - std::time::Duration::from_secs(genesis_time); @@ -555,11 +545,7 @@ impl ConsensusClient { let next_slot = current_slot + 1; let next_slot_timestamp = self.slot_timestamp(next_slot); - let now = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - + let now = duration_since_epoch().as_secs(); let time_to_next_slot = next_slot_timestamp - now; let next_update = time_to_next_slot + 4; @@ -578,6 +564,20 @@ impl ConsensusClient { } } +fn duration_since_epoch() -> std::time::Duration { + #[cfg(not(target_arch = "wasm32"))] + { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + } + + #[cfg(target_arch = "wasm32")] + { + std::time::Duration::from_nanos(ic_cdk::api::time()) + } +} + fn get_participating_keys( committee: &SyncCommittee, bitfield: &Bitvector<512>, diff --git a/consensus/src/rpc/nimbus_rpc.rs b/consensus/src/rpc/nimbus_rpc.rs index 00f2ba6d..58e8fbfd 100644 --- a/consensus/src/rpc/nimbus_rpc.rs +++ b/consensus/src/rpc/nimbus_rpc.rs @@ -6,6 +6,7 @@ use super::ConsensusRpc; use crate::constants::MAX_REQUEST_LIGHT_CLIENT_UPDATES; use crate::types::*; use common::errors::RpcError; +use common::http::http_get; #[derive(Debug)] pub struct NimbusRpc { @@ -28,15 +29,7 @@ impl ConsensusRpc for NimbusRpc { self.rpc, root_hex ); - let client = reqwest::Client::new(); - let res = client - .get(req) - .send() - .await - .map_err(|e| RpcError::new("bootstrap", e))? - .json::() - .await - .map_err(|e| RpcError::new("bootstrap", e))?; + let res: BootstrapResponse = rpc_request("bootstrap", req).await?; Ok(res.data) } @@ -48,64 +41,32 @@ impl ConsensusRpc for NimbusRpc { self.rpc, period, count ); - let client = reqwest::Client::new(); - let res = client - .get(req) - .send() - .await - .map_err(|e| RpcError::new("updates", e))? - .json::() - .await - .map_err(|e| RpcError::new("updates", e))?; + let res: UpdateResponse = rpc_request("updates", req).await?; Ok(res.into_iter().map(|d| d.data).collect()) } async fn get_finality_update(&self) -> Result { let req = format!("{}/eth/v1/beacon/light_client/finality_update", self.rpc); - let res = reqwest::get(req) - .await - .map_err(|e| RpcError::new("finality_update", e))? - .json::() - .await - .map_err(|e| RpcError::new("finality_update", e))?; - + let res: FinalityUpdateResponse = rpc_request("finality_update", req).await?; Ok(res.data) } async fn get_optimistic_update(&self) -> Result { let req = format!("{}/eth/v1/beacon/light_client/optimistic_update", self.rpc); - let res = reqwest::get(req) - .await - .map_err(|e| RpcError::new("optimistic_update", e))? - .json::() - .await - .map_err(|e| RpcError::new("optimistic_update", e))?; - + let res: OptimisticUpdateResponse = rpc_request("optimistic_update", req).await?; Ok(res.data) } async fn get_block(&self, slot: u64) -> Result { let req = format!("{}/eth/v2/beacon/blocks/{}", self.rpc, slot); - let res = reqwest::get(req) - .await - .map_err(|e| RpcError::new("blocks", e))? - .json::() - .await - .map_err(|e| RpcError::new("blocks", e))?; - + let res: BeaconBlockResponse = rpc_request("blocks", req).await?; Ok(res.data.message) } async fn chain_id(&self) -> Result { let req = format!("{}/eth/v1/config/spec", self.rpc); - let res = reqwest::get(req) - .await - .map_err(|e| RpcError::new("spec", e))? - .json::() - .await - .map_err(|e| RpcError::new("spec", e))?; - + let res: SpecResponse = rpc_request("spec", req).await?; Ok(res.data.chain_id) } } @@ -152,3 +113,21 @@ struct Spec { #[serde(rename = "DEPOSIT_NETWORK_ID", deserialize_with = "u64_deserialize")] chain_id: u64, } + +async fn rpc_request(name: impl AsRef, url: impl AsRef) -> Result +where + T: serde::de::DeserializeOwned, +{ + let name = name.as_ref(); + let url = url.as_ref(); + let resp = http_get(url).await.map_err(|e| RpcError::new(name, e))?; + + if resp.status != 200 { + let e = format!("http response with status {}", resp.status); + Err(RpcError::new(name, e))?; + } + + let value = serde_json::from_slice(&resp.body).map_err(|e| RpcError::new(name, e))?; + + Ok(value) +} diff --git a/consensus/src/types.rs b/consensus/src/types.rs index ea0e4f80..7ebb354c 100644 --- a/consensus/src/types.rs +++ b/consensus/src/types.rs @@ -525,7 +525,7 @@ where D: serde::Deserializer<'de>, { let val: String = serde::Deserialize::deserialize(deserializer)?; - let x = ethers::types::U256::from_dec_str(&val).map_err(D::Error::custom)?; + let x = ethers_core::types::U256::from_dec_str(&val).map_err(D::Error::custom)?; let mut x_bytes = [0; 32]; x.to_little_endian(&mut x_bytes); Ok(U256::from_bytes_le(x_bytes)) diff --git a/examples/call.rs b/examples/call.rs index d404c6f7..2cb245c0 100644 --- a/examples/call.rs +++ b/examples/call.rs @@ -1,7 +1,6 @@ #![allow(deprecated)] use env_logger::Env; -use ethers::prelude::*; use std::{path::PathBuf, sync::Arc}; use helios::{ diff --git a/execution/Cargo.toml b/execution/Cargo.toml index bfea33eb..87b75a9f 100644 --- a/execution/Cargo.toml +++ b/execution/Cargo.toml @@ -4,14 +4,13 @@ version = "0.4.1" edition = "2021" [dependencies] -reqwest = { version = "0.11.13", features = ["json"] } eyre = "0.6.8" serde = { version = "1.0.143", features = ["derive"] } serde_json = "1.0.85" hex = "0.4.3" ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" } revm = { version = "2.3", default-features = false, features = ["std", "k256", "with-serde"] } -ethers = "2.0.2" +ethers-core = { version = "2.0.8", default-features = false } bytes = "1.2.1" futures = "0.3.23" toml = "0.5.9" @@ -19,7 +18,6 @@ triehash-ethereum = { git = "https://github.com/openethereum/parity-ethereum", r async-trait = "0.1.57" log = "0.4.17" thiserror = "1.0.37" -hyper = "0.14.23" common = { path = "../common" } consensus = { path = "../consensus" } diff --git a/execution/src/errors.rs b/execution/src/errors.rs index 58da3a6d..f9afeff4 100644 --- a/execution/src/errors.rs +++ b/execution/src/errors.rs @@ -1,5 +1,5 @@ use bytes::Bytes; -use ethers::{ +use ethers_core::{ abi::AbiDecode, types::{Address, H256, U256}, }; diff --git a/execution/src/evm.rs b/execution/src/evm.rs index 2c0076ca..20b8cf02 100644 --- a/execution/src/evm.rs +++ b/execution/src/evm.rs @@ -9,7 +9,7 @@ use common::{ errors::{BlockNotFoundError, SlotNotFoundError}, types::BlockTag, }; -use ethers::{ +use ethers_core::{ abi::ethereum_types::BigEndianHash, types::transaction::eip2930::AccessListItem, types::{Address, H160, H256, U256}, @@ -20,7 +20,6 @@ use log::trace; use revm::{AccountInfo, Bytecode, Database, Env, TransactOut, TransactTo, EVM}; use consensus::types::ExecutionPayload; -use tokio::task::spawn_blocking; use crate::{ constants::PARALLEL_QUERY_BATCH_SIZE, @@ -221,15 +220,24 @@ impl<'a, R: ExecutionRpc> ProofDB<'a, R> { } fn get_account(&mut self, address: Address, slots: &[H256]) -> Result { + /* let execution = self.execution.clone(); let payload = self.current_payload.clone(); let slots = slots.to_owned(); - let handle = spawn_blocking(move || { + let handle = tokio::task::spawn_blocking(move || { block_on(execution.get_account(&address, Some(&slots), &payload)) }); block_on(handle)? + */ + + // TODO: The above is the original implementation, but it can not be used + // in WASM environments. + // + // We are also not sure if this will ever be triggered since batch_fetch_accounts + // is pre-fetching the accounts. + panic!("not supported in wasm"); } } diff --git a/execution/src/execution.rs b/execution/src/execution.rs index 38768d94..0e23b8cf 100644 --- a/execution/src/execution.rs +++ b/execution/src/execution.rs @@ -1,11 +1,12 @@ use std::collections::{BTreeMap, HashMap}; use std::str::FromStr; -use ethers::abi::AbiEncode; -use ethers::prelude::{Address, U256}; -use ethers::types::{FeeHistory, Filter, Log, Transaction, TransactionReceipt, H256}; -use ethers::utils::keccak256; -use ethers::utils::rlp::{encode, Encodable, RlpStream}; +use ethers_core::abi::AbiEncode; +use ethers_core::types::{ + Address, FeeHistory, Filter, Log, Transaction, TransactionReceipt, H256, U256, +}; +use ethers_core::utils::keccak256; +use ethers_core::utils::rlp::{encode, Encodable, RlpStream}; use eyre::Result; use common::utils::hex_str_to_bytes; @@ -395,9 +396,8 @@ impl ExecutionClient { let execution_payload = payloads .get(&block_id) .ok_or(ExecutionError::EmptyExecutionPayload())?; - let converted_base_fee_per_gas = ethers::types::U256::from_little_endian( - &execution_payload.base_fee_per_gas().to_bytes_le(), - ); + let converted_base_fee_per_gas = + U256::from_little_endian(&execution_payload.base_fee_per_gas().to_bytes_le()); fee_history .base_fee_per_gas .push(converted_base_fee_per_gas); diff --git a/execution/src/proof.rs b/execution/src/proof.rs index 0d836ab5..55e849c2 100644 --- a/execution/src/proof.rs +++ b/execution/src/proof.rs @@ -1,6 +1,6 @@ -use ethers::types::{Bytes, EIP1186ProofResponse}; -use ethers::utils::keccak256; -use ethers::utils::rlp::{decode_list, RlpStream}; +use ethers_core::types::{Bytes, EIP1186ProofResponse}; +use ethers_core::utils::keccak256; +use ethers_core::utils::rlp::{decode_list, RlpStream}; pub fn verify_proof(proof: &Vec, root: &[u8], path: &Vec, value: &Vec) -> bool { let mut expected_hash = root.to_vec(); diff --git a/execution/src/rpc/http_rpc.rs b/execution/src/rpc/http_rpc.rs index 9c0f9b2f..2f483521 100644 --- a/execution/src/rpc/http_rpc.rs +++ b/execution/src/rpc/http_rpc.rs @@ -1,13 +1,11 @@ use std::str::FromStr; use async_trait::async_trait; -use ethers::prelude::{Address, Http}; -use ethers::providers::{HttpRateLimitRetryPolicy, Middleware, Provider, RetryClient}; -use ethers::types::transaction::eip2718::TypedTransaction; -use ethers::types::transaction::eip2930::AccessList; -use ethers::types::{ - BlockId, BlockNumber, Bytes, EIP1186ProofResponse, Eip1559TransactionRequest, FeeHistory, - Filter, Log, Transaction, TransactionReceipt, H256, U256, +use ethers_core::types::transaction::eip2718::TypedTransaction; +use ethers_core::types::transaction::eip2930::AccessList; +use ethers_core::types::{ + Address, BlockId, BlockNumber, Bytes, EIP1186ProofResponse, Eip1559TransactionRequest, + FeeHistory, Filter, Log, Transaction, TransactionReceipt, H256, U256, }; use eyre::Result; @@ -18,7 +16,7 @@ use super::ExecutionRpc; pub struct HttpRpc { url: String, - provider: Provider>, + //provider: Provider>, } impl Clone for HttpRpc { @@ -31,6 +29,7 @@ impl Clone for HttpRpc { #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl ExecutionRpc for HttpRpc { fn new(rpc: &str) -> Result { + /* let http = Http::from_str(rpc)?; let mut client = RetryClient::new(http, Box::new(HttpRateLimitRetryPolicy), 100, 50); client.set_compute_units(300); @@ -41,6 +40,8 @@ impl ExecutionRpc for HttpRpc { url: rpc.to_string(), provider, }) + */ + todo!() } async fn get_proof( @@ -49,6 +50,7 @@ impl ExecutionRpc for HttpRpc { slots: &[H256], block: u64, ) -> Result { + /* let block = Some(BlockId::from(block)); let proof_response = self .provider @@ -57,9 +59,12 @@ impl ExecutionRpc for HttpRpc { .map_err(|e| RpcError::new("get_proof", e))?; Ok(proof_response) + */ + todo!() } async fn create_access_list(&self, opts: &CallOpts, block: u64) -> Result { + /* let block = Some(BlockId::from(block)); let mut raw_tx = Eip1559TransactionRequest::new(); @@ -82,9 +87,12 @@ impl ExecutionRpc for HttpRpc { .map_err(|e| RpcError::new("create_access_list", e))?; Ok(list.access_list) + */ + todo!() } async fn get_code(&self, address: &Address, block: u64) -> Result> { + /* let block = Some(BlockId::from(block)); let code = self .provider @@ -93,9 +101,12 @@ impl ExecutionRpc for HttpRpc { .map_err(|e| RpcError::new("get_code", e))?; Ok(code.to_vec()) + */ + todo!() } async fn send_raw_transaction(&self, bytes: &[u8]) -> Result { + /* let bytes = Bytes::from(bytes.to_owned()); let tx = self .provider @@ -104,9 +115,12 @@ impl ExecutionRpc for HttpRpc { .map_err(|e| RpcError::new("send_raw_transaction", e))?; Ok(tx.tx_hash()) + */ + todo!() } async fn get_transaction_receipt(&self, tx_hash: &H256) -> Result> { + /* let receipt = self .provider .get_transaction_receipt(*tx_hash) @@ -114,31 +128,42 @@ impl ExecutionRpc for HttpRpc { .map_err(|e| RpcError::new("get_transaction_receipt", e))?; Ok(receipt) + */ + todo!() } async fn get_transaction(&self, tx_hash: &H256) -> Result> { + /* Ok(self .provider .get_transaction(*tx_hash) .await .map_err(|e| RpcError::new("get_transaction", e))?) + */ + todo!() } async fn get_logs(&self, filter: &Filter) -> Result> { + /* Ok(self .provider .get_logs(filter) .await .map_err(|e| RpcError::new("get_logs", e))?) + */ + todo!() } async fn chain_id(&self) -> Result { + /* Ok(self .provider .get_chainid() .await .map_err(|e| RpcError::new("chain_id", e))? .as_u64()) + */ + todo!() } async fn get_fee_history( @@ -147,11 +172,14 @@ impl ExecutionRpc for HttpRpc { last_block: u64, reward_percentiles: &[f64], ) -> Result { + /* let block = BlockNumber::from(last_block); Ok(self .provider .fee_history(block_count, block, reward_percentiles) .await .map_err(|e| RpcError::new("fee_history", e))?) + */ + todo!() } } diff --git a/execution/src/rpc/mock_rpc.rs b/execution/src/rpc/mock_rpc.rs index 42bec5ef..fac52e38 100644 --- a/execution/src/rpc/mock_rpc.rs +++ b/execution/src/rpc/mock_rpc.rs @@ -2,7 +2,7 @@ use std::{fs::read_to_string, path::PathBuf}; use async_trait::async_trait; use common::utils::hex_str_to_bytes; -use ethers::types::{ +use ethers_core::types::{ transaction::eip2930::AccessList, Address, EIP1186ProofResponse, FeeHistory, Filter, Log, Transaction, TransactionReceipt, H256, }; diff --git a/execution/src/rpc/mod.rs b/execution/src/rpc/mod.rs index d4dd8a58..6e301c54 100644 --- a/execution/src/rpc/mod.rs +++ b/execution/src/rpc/mod.rs @@ -1,5 +1,5 @@ use async_trait::async_trait; -use ethers::types::{ +use ethers_core::types::{ transaction::eip2930::AccessList, Address, EIP1186ProofResponse, FeeHistory, Filter, Log, Transaction, TransactionReceipt, H256, }; diff --git a/execution/src/types.rs b/execution/src/types.rs index eea31e4e..3e90c8d3 100644 --- a/execution/src/types.rs +++ b/execution/src/types.rs @@ -1,9 +1,6 @@ use std::{collections::HashMap, fmt}; -use ethers::{ - prelude::{Address, H256, U256}, - types::Transaction, -}; +use ethers_core::types::{Address, Transaction, H256, U256}; use eyre::Result; use serde::{ser::SerializeSeq, Deserialize, Serialize}; diff --git a/execution/tests/execution.rs b/execution/tests/execution.rs index f5c77cd3..da21e78a 100644 --- a/execution/tests/execution.rs +++ b/execution/tests/execution.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::str::FromStr; -use ethers::types::{Address, Filter, H256, U256}; +use ethers_core::types::{Address, Filter, H256, U256}; use ssz_rs::{List, Vector}; use common::utils::hex_str_to_bytes; diff --git a/helios-ts/Cargo.toml b/helios-ts/Cargo.toml index 67be4716..54c62a0a 100644 --- a/helios-ts/Cargo.toml +++ b/helios-ts/Cargo.toml @@ -14,7 +14,7 @@ wasm-bindgen-futures = "0.4.33" serde-wasm-bindgen = "0.4.5" console_error_panic_hook = "0.1.7" -ethers = "2.0.2" +ethers = { version = "2.0.8", default-features = false } hex = "0.4.3" serde = { version = "1.0.143", features = ["derive"] } serde_json = "1.0.85" diff --git a/ic-http/.gitignore b/ic-http/.gitignore new file mode 100644 index 00000000..92d82383 --- /dev/null +++ b/ic-http/.gitignore @@ -0,0 +1,12 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +.env diff --git a/ic-http/Cargo.toml b/ic-http/Cargo.toml new file mode 100644 index 00000000..8b7cdb3b --- /dev/null +++ b/ic-http/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "ic-http" +description = "Mocking HTTPS Outcalls on the Internet Computer" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +candid = "0.9.1" +ic-cdk = "0.10.0" +ic-cdk-macros = "0.7.0" + +# Added to use non-blocking sleep to mock delayed responses. +# Currently wasm32 does not support tokio, so we need to disable it for wasm32. +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tokio = "1.29.1" + +[dev-dependencies] +futures = "0.3.28" +serde_json = "1.0.103" diff --git a/ic-http/README.md b/ic-http/README.md new file mode 100644 index 00000000..5d17827a --- /dev/null +++ b/ic-http/README.md @@ -0,0 +1,122 @@ +# ic-http + +`ic-http` offers a simplified API to make HTTP outcalls on the Internet Computer with an extra convenience of mocking them in tests. + +## References + +- [Integrations](https://internetcomputer.org/docs/current/developer-docs/integrations/) +- [HTTPS Outcalls](https://internetcomputer.org/docs/current/developer-docs/integrations/http_requests/) +- [IC method http_request](https://internetcomputer.org/docs/current/references/ic-interface-spec#ic-http_request) +- [Transformation Function](https://internetcomputer.org/docs/current/developer-docs/integrations/http_requests/http_requests-how-it-works#transformation-function) + +## Getting Started + +Usage: +- Add `ic-http` to your `Cargo.toml` +- Create a canister +- Build a request using the `ic_http::create_request` + - If necessary, provide a transform function +- Make an HTTP request using `ic_http::http_request` +- Test with mock data by using `ic_http::mock::mock`, `ic_http::mock::mock_err`, etc. + +Canister: + +```rust +/// Apply a transform function to the HTTP response. +#[ic_cdk_macros::query] +fn transform(raw: TransformArgs) -> HttpResponse { + let mut response = HttpResponse { + status: raw.response.status.clone(), + ..Default::default() + }; + if response.status == 200 { + let original = parse_json(raw.response.body); + + // Extract the author from the JSON response. + print(&format!("Before transform: {:?}", original.to_string())); + let transformed = original.get("author").cloned().unwrap_or_default(); + print(&format!("After transform: {:?}", transformed.to_string())); + + response.body = transformed.to_string().into_bytes(); + } else { + print(&format!("Transform error: err = {:?}", raw)); + } + response +} + +/// Create a request to the dummyjson.com API. +fn build_request() -> CanisterHttpRequestArgument { + ic_http::create_request() + .get("https://dummyjson.com/quotes/1") + .header(HttpHeader { + name: "User-Agent".to_string(), + value: "ic-http-example-canister".to_string(), + }) + .transform_func(transform, vec![]) + .build() +} + +/// Fetch a quote from the dummyjson.com API. +#[ic_cdk_macros::update] +async fn fetch() -> String { + let request = build_request(); + let result = ic_http::http_request(request).await; + + match result { + Ok((response,)) => { + let body = String::from_utf8(response.body).unwrap(); + format!("Response: {:?}", body) + } + Err((code, msg)) => { + format!("Error: {:?} {:?}", code, msg) + } + } +} +``` + +Test: + +```rust +#[tokio::test] +async fn test_http_request_transform_body() { + // Arrange + let request = build_request(); + let mock_response = ic_http::create_response() + .status(200) + .body( + r#"{ + "id": 1, + "quote": "Life isn’t about getting and having, it’s about giving and being.", + "author": "Kevin Kruse" + }"#, + ) + .build(); + ic_http::mock::mock(request.clone(), mock_response); + + // Act + let (response,) = ic_http::http_request(request.clone()).await.unwrap(); + + // Assert + assert_eq!( + String::from_utf8(response.body).unwrap(), + r#""Kevin Kruse""#.to_string() + ); + assert_eq!(ic_http::mock::times_called(request), 1); +} +``` + +## Examples + +- Simple canister [here](./example_canister/) +- Some API tests [here](./tests/api.rs) + +## Testing + +```bash +# Crate tests. +$ cargo test + +# Example Canister tests. +$ cd example_canister +$ cargo test +``` diff --git a/ic-http/src/http_request.rs b/ic-http/src/http_request.rs new file mode 100644 index 00000000..04c2d4dd --- /dev/null +++ b/ic-http/src/http_request.rs @@ -0,0 +1,31 @@ +use ic_cdk::api::call::RejectionCode; +use ic_cdk::api::management_canister::http_request::{CanisterHttpRequestArgument, HttpResponse}; + +/// The result of a Call. +/// +/// Errors on the IC have two components; a Code and a message associated with it. +pub type CallResult = Result; + +/// Make a HTTP request to a given URL and return HTTP response, possibly after a transformation. +pub async fn http_request( + arg: CanisterHttpRequestArgument, + cycles: u128, +) -> CallResult<(HttpResponse,)> { + #[cfg(not(target_arch = "wasm32"))] + { + // Mocking cycles is not implemented at the moment. + let _ = cycles; + crate::mock::http_request(arg).await + } + + #[cfg(target_arch = "wasm32")] + { + ic_cdk::api::call::call_with_payment128( + candid::Principal::management_canister(), + "http_request", + (arg,), + cycles, + ) + .await + } +} diff --git a/ic-http/src/lib.rs b/ic-http/src/lib.rs new file mode 100644 index 00000000..f69990bb --- /dev/null +++ b/ic-http/src/lib.rs @@ -0,0 +1,132 @@ +//! +//! `ic-http` offers a simplified API to make HTTP outcalls on the Internet Computer with an extra convenience of mocking them in tests. +//! +//! # Getting Started +//! +//! Usage: +//! - Add `ic-http` to your `Cargo.toml` +//! - Create a canister +//! - Build a request using the `ic_http::create_request` +//! - If necessary, provide a transform function +//! - Make an HTTP request using `ic_http::http_request` +//! - Test with mock data by using `ic_http::mock::mock`, `ic_http::mock::mock_err`, etc. +//! +//! ## Canister +//! +//! ```rust +//! # use ic_cdk::api::management_canister::http_request::{ +//! # CanisterHttpRequestArgument, HttpHeader, HttpResponse, TransformArgs, +//! # }; +//! # +//! # pub fn print(msg: &str) { +//! # println!("{}", msg); +//! # } +//! # +//! # /// Parse the raw response body as JSON. +//! # fn parse_json(body: Vec) -> serde_json::Value { +//! # let json_str = String::from_utf8(body).expect("Raw response is not UTF-8 encoded."); +//! # serde_json::from_str(&json_str).expect("Failed to parse JSON from string") +//! # } +//! # +//! /// Apply a transform function to the HTTP response. +//! #[ic_cdk_macros::query] +//! fn transform(raw: TransformArgs) -> HttpResponse { +//! let mut response = HttpResponse { +//! status: raw.response.status.clone(), +//! ..Default::default() +//! }; +//! if response.status == 200 { +//! let original = parse_json(raw.response.body); +//! +//! // Extract the author from the JSON response. +//! print(&format!("Before transform: {:?}", original.to_string())); +//! let transformed = original.get("author").cloned().unwrap_or_default(); +//! print(&format!("After transform: {:?}", transformed.to_string())); +//! +//! response.body = transformed.to_string().into_bytes(); +//! } else { +//! print(&format!("Transform error: err = {:?}", raw)); +//! } +//! response +//! } +//! +//! /// Create a request to the dummyjson.com API. +//! fn build_request() -> CanisterHttpRequestArgument { +//! ic_http::create_request() +//! .get("https://dummyjson.com/quotes/1") +//! .header(HttpHeader { +//! name: "User-Agent".to_string(), +//! value: "ic-http-example-canister".to_string(), +//! }) +//! .transform_func("transform", transform, vec![]) +//! .build() +//! } +//! +//! /// Fetch a quote from the dummyjson.com API. +//! #[ic_cdk_macros::update] +//! async fn fetch() -> String { +//! let request = build_request(); +//! let cycles = 0; +//! let result = ic_http::http_request(request, cycles).await; +//! +//! match result { +//! Ok((response,)) => { +//! let body = String::from_utf8(response.body).unwrap(); +//! format!("Response: {:?}", body) +//! } +//! Err((code, msg)) => { +//! format!("Error: {:?} {:?}", code, msg) +//! } +//! } +//! } +//! ``` +//! +//! ## Test +//! +//! ```rust +//! #[tokio::test] +//! async fn test_http_request_transform_body() { +//! // Arrange +//! let request = build_request(); +//! let mock_response = ic_http::create_response() +//! .status(200) +//! .body( +//! r#"{ +//! "id": 1, +//! "quote": "Life isn’t about getting and having, it’s about giving and being.", +//! "author": "Kevin Kruse" +//! }"#, +//! ) +//! .build(); +//! ic_http::mock::mock(request.clone(), mock_response); +//! +//! // Act +//! let cycles = 0; +//! let (response,) = ic_http::http_request(request.clone(), cycles).await.unwrap(); +//! +//! // Assert +//! assert_eq!( +//! String::from_utf8(response.body).unwrap(), +//! r#""Kevin Kruse""#.to_string() +//! ); +//! assert_eq!(ic_http::mock::times_called(request), 1); +//! } +//! ``` +//! + +mod http_request; +mod request; +mod response; +mod transform; + +#[cfg(not(target_arch = "wasm32"))] +mod storage; + +// Export. +#[cfg(not(target_arch = "wasm32"))] +pub mod mock; + +// Re-export. +pub use crate::http_request::http_request; +pub use crate::request::create_request; +pub use crate::response::create_response; diff --git a/ic-http/src/mock.rs b/ic-http/src/mock.rs new file mode 100644 index 00000000..5e54ba66 --- /dev/null +++ b/ic-http/src/mock.rs @@ -0,0 +1,162 @@ +use ic_cdk::api::call::RejectionCode; +use ic_cdk::api::management_canister::http_request::{ + CanisterHttpRequestArgument, HttpResponse, TransformArgs, +}; +use std::time::Duration; + +/// Represents a mock HTTP request and its corresponding response. +#[derive(Clone)] +pub(crate) struct Mock { + pub(crate) request: CanisterHttpRequestArgument, + result: Option>, + delay: Duration, + times_called: u64, +} + +/// Adds a mock for a given HTTP request and response. The mock will be returned by +/// subsequent calls to `http_request` that match the same request. The response will be +/// returned immediately, without any delay. +pub fn mock(request: CanisterHttpRequestArgument, response: HttpResponse) { + mock_with_delay(request, response, Duration::from_secs(0)); +} + +/// Adds a mock for a given HTTP request and response. The mock will be returned by +/// subsequent calls to `http_request` that match the same request. The response will be +/// returned after a delay specified by the `delay` argument. +pub fn mock_with_delay( + request: CanisterHttpRequestArgument, + response: HttpResponse, + delay: Duration, +) { + crate::storage::mock_insert(Mock { + request, + result: Some(Ok(response)), + delay, + times_called: 0, + }); +} + +/// Adds a mock error for a given HTTP request and error. The mock will be returned by +/// subsequent calls to `http_request` that match the same request. The error will be +/// returned immediately, without any delay. +pub fn mock_error(request: CanisterHttpRequestArgument, error: (RejectionCode, String)) { + mock_error_with_delay(request, error, Duration::from_secs(0)); +} + +/// Adds a mock error for a given HTTP request and error. The mock will be returned by +/// subsequent calls to `http_request` that match the same request. The error will be +/// returned after a delay specified by the `delay` argument. +pub fn mock_error_with_delay( + request: CanisterHttpRequestArgument, + error: (RejectionCode, String), + delay: Duration, +) { + crate::storage::mock_insert(Mock { + request, + result: Some(Err(error)), + delay, + times_called: 0, + }); +} + +/// Calls the transform function if one is specified in the request. +pub fn call_transform_function( + request: CanisterHttpRequestArgument, + arg: TransformArgs, +) -> Option { + request + .transform + .and_then(|t| crate::storage::transform_function_call(t.function.0.method, arg)) +} + +/// Handles incoming HTTP requests by retrieving a mock response based +/// on the request, possibly delaying the response, transforming the response if necessary, +/// and returning it. If there is no mock found, it returns an error. +pub(crate) async fn http_request( + request: CanisterHttpRequestArgument, +) -> Result<(HttpResponse,), (RejectionCode, String)> { + let mut mock = crate::storage::mock_get(&request) + .ok_or((RejectionCode::CanisterReject, "No mock found".to_string()))?; + mock.times_called += 1; + crate::storage::mock_insert(mock.clone()); + + // Delay the response if necessary. + if mock.delay > Duration::from_secs(0) { + // TODO: Use a non-blocking sleep when the CDK supports it. + #[cfg(not(target_arch = "wasm32"))] + tokio::time::sleep(mock.delay).await; + } + + let mock_response = match mock.result { + None => panic!("Mock response is missing"), + // Return the error if one is specified. + Some(Err(error)) => return Err(error), + Some(Ok(response)) => response, + }; + + // Check if the response body exceeds the maximum allowed size. + if let Some(max_response_bytes) = mock.request.max_response_bytes { + if mock_response.body.len() as u64 > max_response_bytes { + return Err(( + RejectionCode::SysFatal, + format!( + "Value of 'Content-length' header exceeds http body size limit, {} > {}.", + mock_response.body.len(), + max_response_bytes + ), + )); + } + } + + // Apply the transform function if one is specified. + let transformed_response = call_transform_function( + mock.request, + TransformArgs { + response: mock_response.clone(), + context: vec![], + }, + ) + .unwrap_or(mock_response); + + Ok((transformed_response,)) +} + +/// Returns the number of times the given request has been called. +/// Returns 0 if no mock has been found for the request. +pub fn times_called(request: CanisterHttpRequestArgument) -> u64 { + crate::storage::mock_get(&request) + .map(|mock| mock.times_called) + .unwrap_or(0) +} + +/// Returns a sorted list of registered transform function names. +pub fn registered_transform_function_names() -> Vec { + crate::storage::transform_function_names() +} + +/// Create a hash from a `CanisterHttpRequestArgument`, which includes its URL, +/// method, headers, body, and optionally, its transform function name. +/// This is because `CanisterHttpRequestArgument` does not have `Hash` implemented. +pub(crate) fn hash(request: &CanisterHttpRequestArgument) -> String { + let mut hash = String::new(); + + hash.push_str(&request.url); + hash.push_str(&format!("{:?}", request.max_response_bytes)); + hash.push_str(&format!("{:?}", request.method)); + for header in request.headers.iter() { + hash.push_str(&header.name); + hash.push_str(&header.value); + } + let body = String::from_utf8(request.body.as_ref().unwrap_or(&vec![]).clone()) + .expect("Raw response is not UTF-8 encoded."); + hash.push_str(&body); + let function_name = request + .transform + .as_ref() + .map(|transform| transform.function.0.method.clone()); + if let Some(name) = function_name { + hash.push_str(&name); + } + + hash +} diff --git a/ic-http/src/request.rs b/ic-http/src/request.rs new file mode 100644 index 00000000..0705d150 --- /dev/null +++ b/ic-http/src/request.rs @@ -0,0 +1,109 @@ +use crate::transform::create_transform_context; +use ic_cdk::api::management_canister::http_request::{ + CanisterHttpRequestArgument, HttpHeader, HttpMethod, HttpResponse, TransformArgs, + TransformContext, +}; + +/// Creates a new `HttpRequestBuilder` to construct an HTTP request. +pub fn create_request() -> HttpRequestBuilder { + HttpRequestBuilder::new() +} + +/// Represents a builder for an HTTP request. +pub struct HttpRequestBuilder { + /// The requested URL. + pub url: String, + /// The maximal size of the response in bytes. If None, 2MiB will be the limit. + pub max_response_bytes: Option, + /// The method of HTTP request. + pub method: HttpMethod, + /// List of HTTP request headers and their corresponding values. + pub headers: Vec, + /// Optionally provide request body. + pub body: Option>, + /// Name of the transform function which is `func (transform_args) -> (http_response) query`. + pub transform: Option, +} + +impl HttpRequestBuilder { + pub fn new() -> Self { + Self { + url: String::new(), + max_response_bytes: None, + method: HttpMethod::GET, + headers: Vec::new(), + body: None, + transform: None, + } + } + + pub fn get(mut self, url: &str) -> Self { + self.url = url.to_string(); + self.method = HttpMethod::GET; + self + } + + pub fn url(mut self, url: &str) -> Self { + self.url = url.to_string(); + self + } + + pub fn max_response_bytes(mut self, max_response_bytes: u64) -> Self { + self.max_response_bytes = Some(max_response_bytes); + self + } + + pub fn method(mut self, method: HttpMethod) -> Self { + self.method = method; + self + } + + pub fn header(mut self, header: HttpHeader) -> Self { + self.headers.push(header); + self + } + + pub fn body(mut self, body: Vec) -> Self { + self.body = Some(body); + self + } + + pub fn transform_context(mut self, transform_context: TransformContext) -> Self { + self.transform = Some(transform_context); + self + } + + pub fn transform_func( + mut self, + candid_function_name: &str, + func: T, + context: Vec, + ) -> Self + where + T: Fn(TransformArgs) -> HttpResponse + 'static, + { + self.transform = Some(create_transform_context( + candid_function_name, + func, + context, + )); + self + } + + pub fn build(self) -> CanisterHttpRequestArgument { + CanisterHttpRequestArgument { + url: self.url, + max_response_bytes: self.max_response_bytes, + method: self.method, + headers: self.headers, + body: self.body, + transform: self.transform, + } + } +} + +impl Default for HttpRequestBuilder { + fn default() -> Self { + Self::new() + } +} diff --git a/ic-http/src/response.rs b/ic-http/src/response.rs new file mode 100644 index 00000000..0424abd9 --- /dev/null +++ b/ic-http/src/response.rs @@ -0,0 +1,55 @@ +use ic_cdk::api::management_canister::http_request::{HttpHeader, HttpResponse}; + +/// Creates a new `HttpResponseBuilder` to construct an HTTP response. +pub fn create_response() -> HttpResponseBuilder { + HttpResponseBuilder::new() +} + +/// Represents a builder for an HTTP response. +pub struct HttpResponseBuilder { + /// The response status (e.g., 200, 404). + pub status: candid::Nat, + /// List of HTTP response headers and their corresponding values. + pub headers: Vec, + /// The response’s body. + pub body: Vec, +} + +impl HttpResponseBuilder { + pub fn new() -> Self { + Self { + status: candid::Nat::from(200), + headers: Vec::new(), + body: Vec::new(), + } + } + + pub fn status(mut self, status: u64) -> Self { + self.status = candid::Nat::from(status); + self + } + + pub fn header(mut self, header: HttpHeader) -> Self { + self.headers.push(header); + self + } + + pub fn body(mut self, body: &str) -> Self { + self.body = body.as_bytes().to_vec(); + self + } + + pub fn build(self) -> HttpResponse { + HttpResponse { + status: self.status, + headers: self.headers, + body: self.body, + } + } +} + +impl Default for HttpResponseBuilder { + fn default() -> Self { + Self::new() + } +} diff --git a/ic-http/src/storage.rs b/ic-http/src/storage.rs new file mode 100644 index 00000000..1cb11ee5 --- /dev/null +++ b/ic-http/src/storage.rs @@ -0,0 +1,54 @@ +use crate::mock::{hash, Mock}; +use crate::transform::TransformFn; +use ic_cdk::api::management_canister::http_request::CanisterHttpRequestArgument; +use ic_cdk::api::management_canister::http_request::{HttpResponse, TransformArgs}; +use std::collections::HashMap; +use std::sync::RwLock; + +// A thread-local hashmap. +thread_local! { + /// A thread-local hashmap of mocks. + static MOCKS: RwLock> = RwLock::new(HashMap::new()); + + /// A thread-local hashmap of transform functions. + static TRANSFORM_FUNCTIONS: RwLock>> = RwLock::new(HashMap::new()); +} + +/// Inserts the provided mock into a thread-local hashmap. +pub(crate) fn mock_insert(mock: Mock) { + MOCKS.with(|cell| { + cell.write().unwrap().insert(hash(&mock.request), mock); + }); +} + +/// Returns a cloned mock from the thread-local hashmap that corresponds to the provided request. +pub(crate) fn mock_get(request: &CanisterHttpRequestArgument) -> Option { + MOCKS.with(|cell| cell.read().unwrap().get(&hash(request)).cloned()) +} + +/// Inserts the provided transform function into a thread-local hashmap. +/// If a transform function with the same name already exists, it is not inserted. +pub(crate) fn transform_function_insert(name: String, func: Box) { + TRANSFORM_FUNCTIONS.with(|cell| { + // This is a workaround to prevent the transform function from being + // overridden while it is being executed. + if cell.read().unwrap().get(&name).is_none() { + cell.write().unwrap().insert(name, func); + } + }); +} + +/// Executes the transform function that corresponds to the provided name. +pub(crate) fn transform_function_call(name: String, arg: TransformArgs) -> Option { + TRANSFORM_FUNCTIONS.with(|cell| cell.read().unwrap().get(&name).map(|f| f(arg))) +} + +/// Returns a sorted list of transform function names. +/// This is used for testing. +pub(crate) fn transform_function_names() -> Vec { + TRANSFORM_FUNCTIONS.with(|cell| { + let mut names: Vec = cell.read().unwrap().keys().cloned().collect(); + names.sort(); + names + }) +} diff --git a/ic-http/src/transform.rs b/ic-http/src/transform.rs new file mode 100644 index 00000000..e6732d05 --- /dev/null +++ b/ic-http/src/transform.rs @@ -0,0 +1,122 @@ +use ic_cdk::api::management_canister::http_request::{ + HttpResponse, TransformArgs, TransformContext, +}; + +#[cfg(not(target_arch = "wasm32"))] +use {candid::Principal, ic_cdk::api::management_canister::http_request::TransformFunc}; + +#[cfg(not(target_arch = "wasm32"))] +pub type TransformFn = dyn Fn(TransformArgs) -> HttpResponse + 'static; + +/// Creates a `TransformContext` from a transform function and a context. +pub(crate) fn create_transform_context( + candid_function_name: &str, + func: T, + context: Vec, +) -> TransformContext +where + T: Fn(TransformArgs) -> HttpResponse + 'static, +{ + #[cfg(target_arch = "wasm32")] + { + TransformContext::from_name(candid_function_name.to_string(), context) + } + + #[cfg(not(target_arch = "wasm32"))] + { + let method = candid_function_name.to_string(); + super::storage::transform_function_insert(method.clone(), Box::new(func)); + + // crate::id() can not be called outside of canister, that's why for testing + // it is replaced with Principal::management_canister(). + let principal = Principal::management_canister(); + TransformContext { + function: TransformFunc(candid::Func { principal, method }), + context, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use ic_cdk::api::management_canister::http_request::CanisterHttpRequestArgument; + + /// A test transform function. + fn transform_function_1(arg: TransformArgs) -> HttpResponse { + arg.response + } + + /// A test transform function. + fn transform_function_2(arg: TransformArgs) -> HttpResponse { + arg.response + } + + /// Inserts the provided transform function into a thread-local hashmap. + fn insert(name: &str, f: T) + where + T: Fn(TransformArgs) -> HttpResponse + 'static, + { + crate::storage::transform_function_insert(name.to_string(), Box::new(f)); + } + + /// This test makes sure that transform function names are preserved + /// when passing to the function. + #[test] + fn test_transform_function_names() { + // Arrange. + insert("transform_function_1", transform_function_1); + insert("transform_function_2", transform_function_2); + + // Act. + let names = crate::mock::registered_transform_function_names(); + + // Assert. + assert_eq!(names, vec!["transform_function_1", "transform_function_2"]); + } + + /// Transform function which intentionally creates a new request passing + /// itself as the target transform function. + fn transform_function_with_overwrite(arg: TransformArgs) -> HttpResponse { + create_request_with_transform(); + arg.response + } + + /// Creates a request with a transform function which overwrites itself. + fn create_request_with_transform() -> CanisterHttpRequestArgument { + crate::request::create_request() + .url("https://www.example.com") + .transform_func( + "transform_function_with_overwrite", + transform_function_with_overwrite, + vec![], + ) + .build() + } + + // IMPORTANT: If this test hangs check the implementation of inserting + // transform function to the thread-local storage. + // + // This test simulates the case when transform function tries to + // rewrite itself in a thread-local storage while it is being executed. + // This may lead to a hang if the insertion to the thread-local storage + // is not written properly. + #[tokio::test] + async fn test_transform_function_call_without_a_hang() { + // Arrange + let request = create_request_with_transform(); + let mock_response = crate::response::create_response().build(); + crate::mock::mock(request.clone(), mock_response); + + // Act + let (response,) = crate::mock::http_request(request.clone()).await.unwrap(); + + // Assert + assert_eq!(response.status, 200); + assert_eq!(crate::mock::times_called(request), 1); + assert_eq!( + crate::mock::registered_transform_function_names(), + vec!["transform_function_with_overwrite"] + ); + } +} diff --git a/ic-http/tests/api.rs b/ic-http/tests/api.rs new file mode 100644 index 00000000..23249710 --- /dev/null +++ b/ic-http/tests/api.rs @@ -0,0 +1,332 @@ +use ic_cdk::api::call::RejectionCode; +use ic_cdk::api::management_canister::http_request::{HttpResponse, TransformArgs}; +use std::time::{Duration, Instant}; + +const STATUS_CODE_OK: u64 = 200; +const STATUS_CODE_NOT_FOUND: u64 = 404; +const ZERO_CYCLES: u128 = 0; + +#[tokio::test] +async fn test_http_request_no_transform() { + // Arrange + let body = "some text"; + let request = ic_http::create_request().get("https://example.com").build(); + let mock_response = ic_http::create_response() + .status(STATUS_CODE_OK) + .body(body) + .build(); + ic_http::mock::mock(request.clone(), mock_response); + + // Act + let (response,) = ic_http::http_request(request.clone(), ZERO_CYCLES) + .await + .unwrap(); + + // Assert + assert_eq!(response.status, candid::Nat::from(STATUS_CODE_OK)); + assert_eq!(response.body, body.to_string().as_bytes().to_vec()); + assert_eq!(ic_http::mock::times_called(request), 1); +} + +#[tokio::test] +async fn test_http_request_called_several_times() { + // Arrange + let calls = 3; + let body = "some text"; + let request = ic_http::create_request().get("https://example.com").build(); + let mock_response = ic_http::create_response() + .status(STATUS_CODE_OK) + .body(body) + .build(); + ic_http::mock::mock(request.clone(), mock_response); + + // Act + for _ in 0..calls { + let (response,) = ic_http::http_request(request.clone(), ZERO_CYCLES) + .await + .unwrap(); + assert_eq!(response.status, candid::Nat::from(STATUS_CODE_OK)); + assert_eq!(response.body, body.to_string().as_bytes().to_vec()); + } + + // Assert + assert_eq!(ic_http::mock::times_called(request), calls); +} + +#[tokio::test] +async fn test_http_request_transform_status() { + // Arrange + fn transform(_arg: TransformArgs) -> HttpResponse { + ic_http::create_response() + .status(STATUS_CODE_NOT_FOUND) + .build() + } + let request = ic_http::create_request() + .get("https://example.com") + .transform_func("transform", transform, vec![]) + .build(); + let mock_response = ic_http::create_response() + .status(STATUS_CODE_OK) + .body("some text") + .build(); + ic_http::mock::mock(request.clone(), mock_response); + + // Act + let (response,) = ic_http::http_request(request.clone(), ZERO_CYCLES) + .await + .unwrap(); + + // Assert + assert_ne!(response.status, candid::Nat::from(STATUS_CODE_OK)); + assert_eq!(response.status, candid::Nat::from(STATUS_CODE_NOT_FOUND)); + assert_eq!(ic_http::mock::times_called(request), 1); +} + +#[tokio::test] +async fn test_http_request_transform_body() { + // Arrange + const ORIGINAL_BODY: &str = "original body"; + const TRANSFORMED_BODY: &str = "transformed body"; + fn transform(_arg: TransformArgs) -> HttpResponse { + ic_http::create_response().body(TRANSFORMED_BODY).build() + } + let request = ic_http::create_request() + .get("https://dummyjson.com/todos/1") + .transform_func("transform", transform, vec![]) + .build(); + let mock_response = ic_http::create_response() + .status(STATUS_CODE_OK) + .body(ORIGINAL_BODY) + .build(); + ic_http::mock::mock(request.clone(), mock_response); + + // Act + let (response,) = ic_http::http_request(request.clone(), ZERO_CYCLES) + .await + .unwrap(); + + // Assert + assert_ne!(response.body, ORIGINAL_BODY.as_bytes().to_vec()); + assert_eq!(response.body, TRANSFORMED_BODY.as_bytes().to_vec()); + assert_eq!(ic_http::mock::times_called(request), 1); +} + +#[tokio::test] +async fn test_http_request_transform_both_status_and_body() { + // Arrange + const ORIGINAL_BODY: &str = "original body"; + const TRANSFORMED_BODY: &str = "transformed body"; + + fn transform_status(arg: TransformArgs) -> HttpResponse { + let mut response = arg.response; + response.status = candid::Nat::from(STATUS_CODE_NOT_FOUND); + response + } + + fn transform_body(arg: TransformArgs) -> HttpResponse { + let mut response = arg.response; + response.body = TRANSFORMED_BODY.as_bytes().to_vec(); + response + } + + let request_1 = ic_http::create_request() + .get("https://dummyjson.com/todos/1") + .transform_func("transform_status", transform_status, vec![]) + .build(); + let mock_response_1 = ic_http::create_response() + .status(STATUS_CODE_NOT_FOUND) + .body(ORIGINAL_BODY) + .build(); + ic_http::mock::mock(request_1.clone(), mock_response_1); + + let request_2 = ic_http::create_request() + .get("https://dummyjson.com/todos/2") + .transform_func("transform_body", transform_body, vec![]) + .build(); + let mock_response_2 = ic_http::create_response() + .status(STATUS_CODE_OK) + .body(TRANSFORMED_BODY) + .build(); + ic_http::mock::mock(request_2.clone(), mock_response_2); + + // Act + let futures = vec![ + ic_http::http_request(request_1.clone(), ZERO_CYCLES), + ic_http::http_request(request_2.clone(), ZERO_CYCLES), + ]; + let results = futures::future::join_all(futures).await; + let responses: Vec<_> = results + .into_iter() + .filter(|result| result.is_ok()) + .map(|result| result.unwrap().0) + .collect(); + + // Assert + assert_eq!( + ic_http::mock::registered_transform_function_names(), + vec!["transform_body", "transform_status"] + ); + assert_eq!(responses.len(), 2); + assert_eq!( + responses[0].status, + candid::Nat::from(STATUS_CODE_NOT_FOUND) + ); + assert_eq!(responses[0].body, ORIGINAL_BODY.as_bytes().to_vec()); + assert_eq!(responses[1].status, candid::Nat::from(STATUS_CODE_OK)); + assert_eq!(responses[1].body, TRANSFORMED_BODY.as_bytes().to_vec()); + assert_eq!(ic_http::mock::times_called(request_1), 1); + assert_eq!(ic_http::mock::times_called(request_2), 1); +} + +#[tokio::test] +async fn test_http_request_max_response_bytes_ok() { + // Arrange + let max_response_bytes = 3; + let body_small_enough = "123"; + let request = ic_http::create_request() + .get("https://example.com") + .max_response_bytes(max_response_bytes) + .build(); + let mock_response = ic_http::create_response() + .status(STATUS_CODE_OK) + .body(body_small_enough) + .build(); + ic_http::mock::mock(request.clone(), mock_response); + + // Act + let result = ic_http::http_request(request.clone(), ZERO_CYCLES).await; + + // Assert + assert!(result.is_ok()); + assert_eq!(ic_http::mock::times_called(request), 1); +} + +#[tokio::test] +async fn test_http_request_max_response_bytes_error() { + // Arrange + let max_response_bytes = 3; + let body_too_big = "1234"; + let request = ic_http::create_request() + .get("https://example.com") + .max_response_bytes(max_response_bytes) + .build(); + let mock_response = ic_http::create_response() + .status(STATUS_CODE_OK) + .body(body_too_big) + .build(); + ic_http::mock::mock(request.clone(), mock_response); + + // Act + let result = ic_http::http_request(request.clone(), ZERO_CYCLES).await; + + // Assert + assert!(result.is_err()); + assert_eq!(ic_http::mock::times_called(request), 1); +} + +#[tokio::test] +async fn test_http_request_sequentially() { + // Arrange + let request_a = ic_http::create_request().get("a").build(); + let request_b = ic_http::create_request().get("b").build(); + let request_c = ic_http::create_request().get("c").build(); + let mock_response = ic_http::create_response().status(STATUS_CODE_OK).build(); + ic_http::mock::mock_with_delay( + request_a.clone(), + mock_response.clone(), + Duration::from_millis(100), + ); + ic_http::mock::mock_with_delay( + request_b.clone(), + mock_response.clone(), + Duration::from_millis(200), + ); + ic_http::mock::mock_with_delay(request_c.clone(), mock_response, Duration::from_millis(300)); + + // Act + let start = Instant::now(); + let _ = ic_http::http_request(request_a.clone(), ZERO_CYCLES).await; + let _ = ic_http::http_request(request_b.clone(), ZERO_CYCLES).await; + let _ = ic_http::http_request(request_c.clone(), ZERO_CYCLES).await; + println!("All finished after {} s", start.elapsed().as_secs_f32()); + + // Assert + assert!(start.elapsed() > Duration::from_millis(500)); + assert_eq!(ic_http::mock::times_called(request_a), 1); + assert_eq!(ic_http::mock::times_called(request_b), 1); + assert_eq!(ic_http::mock::times_called(request_c), 1); +} + +#[tokio::test] +async fn test_http_request_concurrently() { + // Arrange + let request_a = ic_http::create_request().get("a").build(); + let request_b = ic_http::create_request().get("b").build(); + let request_c = ic_http::create_request().get("c").build(); + let mock_response = ic_http::create_response().status(STATUS_CODE_OK).build(); + ic_http::mock::mock_with_delay( + request_a.clone(), + mock_response.clone(), + Duration::from_millis(100), + ); + ic_http::mock::mock_with_delay( + request_b.clone(), + mock_response.clone(), + Duration::from_millis(200), + ); + ic_http::mock::mock_with_delay(request_c.clone(), mock_response, Duration::from_millis(300)); + + // Act + let start = Instant::now(); + let futures = vec![ + ic_http::http_request(request_a.clone(), ZERO_CYCLES), + ic_http::http_request(request_b.clone(), ZERO_CYCLES), + ic_http::http_request(request_c.clone(), ZERO_CYCLES), + ]; + futures::future::join_all(futures).await; + println!("All finished after {} s", start.elapsed().as_secs_f32()); + + // Assert + assert!(start.elapsed() < Duration::from_millis(500)); + assert_eq!(ic_http::mock::times_called(request_a), 1); + assert_eq!(ic_http::mock::times_called(request_b), 1); + assert_eq!(ic_http::mock::times_called(request_c), 1); +} + +#[tokio::test] +async fn test_http_request_error() { + // Arrange + let request = ic_http::create_request().get("https://example.com").build(); + let mock_error = (RejectionCode::SysFatal, "system fatal error".to_string()); + ic_http::mock::mock_error(request.clone(), mock_error); + + // Act + let result = ic_http::http_request(request.clone(), ZERO_CYCLES).await; + + // Assert + assert_eq!( + result, + Err((RejectionCode::SysFatal, "system fatal error".to_string())) + ); + assert_eq!(ic_http::mock::times_called(request), 1); +} + +#[tokio::test] +async fn test_http_request_error_with_delay() { + // Arrange + let request = ic_http::create_request().get("https://example.com").build(); + let mock_error = (RejectionCode::SysFatal, "system fatal error".to_string()); + ic_http::mock::mock_error_with_delay(request.clone(), mock_error, Duration::from_millis(200)); + + // Act + let start = Instant::now(); + let result = ic_http::http_request(request.clone(), ZERO_CYCLES).await; + + // Assert + assert!(start.elapsed() > Duration::from_millis(100)); + assert_eq!( + result, + Err((RejectionCode::SysFatal, "system fatal error".to_string())) + ); + assert_eq!(ic_http::mock::times_called(request), 1); +} diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index fe03a4d0..00000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly-2023-01-23