From a1a617869502f0d188460dd0076f7c54caf9e341 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 23 Jun 2023 15:31:51 +0300 Subject: [PATCH 01/36] Cargo update in prep for wasm build Signed-off-by: Alexandru Vasile --- Cargo.lock | 34 +- testing/wasm-tests/Cargo.lock | 1379 ++++++++++++++++++++++++++++++--- testing/wasm-tests/Cargo.toml | 4 +- 3 files changed, 1277 insertions(+), 140 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fddc207497..aec732d3b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,15 +141,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] @@ -701,9 +701,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.4" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed" +checksum = "2686c4115cb0810d9a984776e197823d08ec94f176549a89a9efded477c456dc" dependencies = [ "clap_builder", "clap_derive", @@ -712,9 +712,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.4" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636" +checksum = "2e53afce1efce6ed1f633cf0e57612fe51db54a1ee4fd8f8503d078fe02d69ae" dependencies = [ "anstream", "anstyle", @@ -3189,9 +3189,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b569c32c806ec3abdf3b5869fb8bf1e0d275a7c1c9b0b05603d9464632649edf" +checksum = "ad560913365790f17cbf12479491169f01b9d46d29cfc7422bf8c64bdc61b731" dependencies = [ "bitvec", "cfg-if", @@ -3203,9 +3203,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53012eae69e5aa5c14671942a5dd47de59d4cdcff8532a6dd0e081faf1119482" +checksum = "19df9bd9ace6cc2fe19387c96ce677e823e07d017ceed253e7bb3d1d1bd9c73b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4182,7 +4182,7 @@ dependencies = [ name = "subxt-cli" version = "0.29.0" dependencies = [ - "clap 4.3.4", + "clap 4.3.5", "color-eyre", "frame-metadata", "hex", @@ -4294,9 +4294,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" +checksum = "1b1c7f239eb94671427157bd93b3694320f3668d4e1eff08c7285366fd777fac" [[package]] name = "termcolor" @@ -4533,9 +4533,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8803eee176538f94ae9a14b55b2804eb7e1441f8210b1c31290b3bccdccff73b" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", diff --git a/testing/wasm-tests/Cargo.lock b/testing/wasm-tests/Cargo.lock index 492063fbed..e60c7aad6b 100644 --- a/testing/wasm-tests/Cargo.lock +++ b/testing/wasm-tests/Cargo.lock @@ -2,6 +2,52 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes-gcm" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc3be92e19a7ef47457b8e6f90707e12b6ac5d20c6f3866584fa3be0787d839f" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "anyhow" version = "1.0.71" @@ -16,9 +62,75 @@ checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +dependencies = [ + "nodrop", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-channel" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" +dependencies = [ + "async-lock", + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock", + "autocfg", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite", + "log", + "parking", + "polling", + "rustix", + "slab", + "socket2", + "waker-fn", +] [[package]] name = "async-lock" @@ -29,6 +141,42 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-net" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f" +dependencies = [ + "async-io", + "autocfg", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-process" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" +dependencies = [ + "async-io", + "async-lock", + "autocfg", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "signal-hook", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-task" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" + [[package]] name = "async-trait" version = "0.1.68" @@ -37,9 +185,21 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + +[[package]] +name = "atomic-waker" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" + [[package]] name = "autocfg" version = "1.1.0" @@ -60,9 +220,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "beef" @@ -73,6 +233,21 @@ dependencies = [ "serde", ] +[[package]] +name = "bip39" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +dependencies = [ + "bitcoin_hashes", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" + [[package]] name = "bitflags" version = "1.3.2" @@ -100,6 +275,16 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "blake2-rfc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" +dependencies = [ + "arrayvec 0.4.12", + "constant_time_eq 0.1.5", +] + [[package]] name = "blake2b_simd" version = "1.0.1" @@ -107,8 +292,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", - "arrayvec", - "constant_time_eq", + "arrayvec 0.7.4", + "constant_time_eq 0.2.6", ] [[package]] @@ -129,6 +314,30 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "log", +] + +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.13.0" @@ -165,6 +374,49 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "chacha20poly1305" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "concurrent-queue" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -177,9 +429,21 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.2.5" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" + +[[package]] +name = "convert_case" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" @@ -199,13 +463,32 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -222,6 +505,65 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +dependencies = [ + "cfg-if", + "fiat-crypto", + "packed_simd_2", + "platforms", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-ng" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.6.4", + "subtle-ng", + "zeroize", +] + [[package]] name = "darling" version = "0.14.4" @@ -267,7 +609,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -289,7 +631,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" dependencies = [ "darling_core 0.20.1", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -309,8 +651,10 @@ version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ + "convert_case", "proc-macro2", "quote", + "rustc_version", "syn 1.0.109", ] @@ -334,18 +678,74 @@ dependencies = [ "subtle", ] +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + [[package]] name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "event-listener" version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + [[package]] name = "fixed-hash" version = "0.8.0" @@ -418,6 +818,32 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + [[package]] name = "futures-sink" version = "0.3.28" @@ -449,6 +875,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -469,9 +896,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -480,6 +907,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gloo-net" version = "0.2.6" @@ -514,9 +951,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", @@ -549,6 +986,18 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "serde", +] [[package]] name = "heck" @@ -565,12 +1014,48 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + [[package]] name = "http" version = "0.2.9" @@ -687,7 +1172,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap-nostd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "intx" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f38a50a899dc47a6d0ed5508e7f601a2e34c3a85303514b5d137f3c10a0c75" + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", ] [[package]] @@ -698,9 +1224,9 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -816,35 +1342,195 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] -name = "log" -version = "0.4.17" +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" + +[[package]] +name = "libm" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ - "cfg-if", + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", ] +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "lru" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e" + [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi", - "windows-sys 0.45.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", ] [[package]] @@ -853,15 +1539,15 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opaque-debug" @@ -875,13 +1561,23 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if", + "libm 0.1.4", +] + [[package]] name = "parity-scale-codec" -version = "3.5.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ddb756ca205bd108aee3c62c6d3c994e1df84a59b9d6d4a5ea42ee1fd5a9a28" +checksum = "2287753623c76f953acd29d15d8100bcab84d29db78fb6f352adb3c53e83b967" dependencies = [ - "arrayvec", + "arrayvec 0.7.4", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", @@ -891,9 +1587,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.4" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +checksum = "2b6937b5e67bfba3351b87b040d48352a2fcb6ad72f81855412ce97b45c8f110" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -901,6 +1597,50 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "pbkdf2" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "pin-project" version = "1.1.0" @@ -918,7 +1658,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -928,10 +1668,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "poly1305" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] [[package]] name = "ppv-lite86" @@ -1018,7 +1803,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1028,9 +1813,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + [[package]] name = "rand_core" version = "0.6.4" @@ -1040,6 +1831,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "ring" version = "0.16.20" @@ -1049,7 +1849,7 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", + "spin 0.5.2", "untrusted", "web-sys", "winapi", @@ -1067,6 +1867,29 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustls" version = "0.20.8" @@ -1081,9 +1904,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", @@ -1097,7 +1920,18 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.21.1", + "base64 0.21.2", +] + +[[package]] +name = "ruzstd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc" +dependencies = [ + "byteorder", + "thiserror-core", + "twox-hash", ] [[package]] @@ -1175,9 +2009,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b569c32c806ec3abdf3b5869fb8bf1e0d275a7c1c9b0b05603d9464632649edf" +checksum = "ad560913365790f17cbf12479491169f01b9d46d29cfc7422bf8c64bdc61b731" dependencies = [ "bitvec", "cfg-if", @@ -1189,9 +2023,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53012eae69e5aa5c14671942a5dd47de59d4cdcff8532a6dd0e081faf1119482" +checksum = "19df9bd9ace6cc2fe19387c96ce677e823e07d017ceed253e7bb3d1d1bd9c73b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1228,12 +2062,34 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "schnorrkel" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "844b7645371e6ecdf61ff246ba1958c29e802881a749ae3fb1993675d210d28d" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "curve25519-dalek-ng", + "merlin", + "rand_core 0.6.4", + "sha2 0.9.9", + "subtle-ng", + "zeroize", +] + [[package]] name = "scoped-tls" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "sct" version = "0.7.0" @@ -1267,6 +2123,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + [[package]] name = "send_wrapper" version = "0.4.0" @@ -1290,7 +2152,7 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1319,9 +2181,22 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -1347,6 +2222,31 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "signal-hook" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[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" @@ -1362,6 +2262,120 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +[[package]] +name = "smol" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1" +dependencies = [ + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", +] + +[[package]] +name = "smoldot" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cce5e2881b30bad7ef89f383a816ad0b22c45915911f28499026de4a76d20ee" +dependencies = [ + "arrayvec 0.7.4", + "async-lock", + "atomic", + "base64 0.21.2", + "bip39", + "blake2-rfc", + "bs58", + "crossbeam-queue", + "derive_more", + "ed25519-zebra", + "either", + "event-listener", + "fnv", + "futures-channel", + "futures-util", + "hashbrown 0.14.0", + "hex", + "hmac 0.12.1", + "itertools", + "libsecp256k1", + "merlin", + "no-std-net", + "nom", + "num-bigint", + "num-rational", + "num-traits", + "pbkdf2", + "pin-project", + "rand", + "rand_chacha", + "ruzstd", + "schnorrkel", + "serde", + "serde_json", + "sha2 0.10.7", + "siphasher", + "slab", + "smallvec", + "smol", + "snow", + "soketto", + "tiny-keccak", + "twox-hash", + "wasmi", +] + +[[package]] +name = "smoldot-light" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2f7b4687b83ff244ef6137735ed5716ad37dcdf3ee16c4eb1a32fb9808fa47" +dependencies = [ + "async-lock", + "blake2-rfc", + "derive_more", + "either", + "event-listener", + "fnv", + "futures-channel", + "futures-util", + "hashbrown 0.14.0", + "hex", + "itertools", + "log", + "lru", + "parking_lot", + "rand", + "serde", + "serde_json", + "siphasher", + "slab", + "smol", + "smoldot", +] + +[[package]] +name = "snow" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" +dependencies = [ + "aes-gcm", + "blake2", + "chacha20poly1305", + "curve25519-dalek 4.0.0-rc.1", + "rand_core 0.6.4", + "rustc_version", + "sha2 0.10.7", + "subtle", +] + [[package]] name = "socket2" version = "0.4.9" @@ -1396,7 +2410,7 @@ dependencies = [ "blake2b_simd", "byteorder", "digest 0.10.7", - "sha2", + "sha2 0.10.7", "sha3", "sp-std", "twox-hash", @@ -1414,6 +2428,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1428,9 +2448,15 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "subtle-ng" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" [[package]] name = "subxt" @@ -1442,6 +2468,7 @@ dependencies = [ "either", "frame-metadata", "futures", + "futures-util", "getrandom", "hex", "impl-serde", @@ -1455,10 +2482,13 @@ dependencies = [ "scale-value", "serde", "serde_json", + "smoldot-light", "sp-core-hashing", "subxt-macro", "subxt-metadata", "thiserror", + "tokio", + "tokio-stream", "tracing", ] @@ -1475,7 +2505,7 @@ dependencies = [ "quote", "scale-info", "subxt-metadata", - "syn 2.0.16", + "syn 2.0.18", "thiserror", "tokio", ] @@ -1487,7 +2517,7 @@ dependencies = [ "darling 0.20.1", "proc-macro-error", "subxt-codegen", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1514,9 +2544,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.16" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -1538,6 +2568,26 @@ dependencies = [ "thiserror-impl", ] +[[package]] +name = "thiserror-core" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" +dependencies = [ + "thiserror-core-impl", +] + +[[package]] +name = "thiserror-core-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "thiserror-impl" version = "1.0.40" @@ -1546,7 +2596,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1559,11 +2609,35 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" -version = "1.28.1" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", @@ -1584,7 +2658,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1598,6 +2672,17 @@ dependencies = [ "webpki", ] +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.8" @@ -1650,13 +2735,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1728,9 +2813,19 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "universal-hash" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +dependencies = [ + "generic-array", + "subtle", +] [[package]] name = "untrusted" @@ -1744,13 +2839,18 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -1762,9 +2862,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1772,24 +2872,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -1799,9 +2899,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1809,28 +2909,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-bindgen-test" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e636f3a428ff62b3742ebc3c70e254dfe12b8c2b469d688ea59cdd4abcf502" +checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" dependencies = [ "console_error_panic_hook", "js-sys", @@ -1842,9 +2942,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f18c1fad2f7c4958e7bcce014fa212f59a65d5e3721d0f77e6c0b27ede936ba3" +checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" dependencies = [ "proc-macro2", "quote", @@ -1861,11 +2961,52 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "wasmi" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51fb5c61993e71158abf5bb863df2674ca3ec39ed6471c64f07aeaf751d67b4" +dependencies = [ + "intx", + "smallvec", + "spin 0.9.8", + "wasmi_arena", + "wasmi_core", + "wasmparser-nostd", +] + +[[package]] +name = "wasmi_arena" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "401c1f35e413fac1846d4843745589d9ec678977ab35a384db8ae7830525d468" + +[[package]] +name = "wasmi_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624e6333e861ef49095d2d678b76ebf30b06bf37effca845be7e5b87c90071b7" +dependencies = [ + "downcast-rs", + "libm 0.2.7", + "num-traits", + "paste", +] + +[[package]] +name = "wasmparser-nostd" +version = "0.100.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9157cab83003221bfd385833ab587a039f5d6fa7304854042ba358a3b09e0724" +dependencies = [ + "indexmap-nostd", +] + [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -1927,37 +3068,13 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -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", + "windows-targets", ] [[package]] @@ -2061,9 +3178,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" dependencies = [ "memchr", ] @@ -2082,3 +3199,23 @@ name = "yap" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2a7eb6d82a11e4d0b8e6bda8347169aff4ccd8235d039bba7c47482d977dcf7" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] diff --git a/testing/wasm-tests/Cargo.toml b/testing/wasm-tests/Cargo.toml index 5c0b13f3b2..973972e7d1 100644 --- a/testing/wasm-tests/Cargo.toml +++ b/testing/wasm-tests/Cargo.toml @@ -11,6 +11,6 @@ console_error_panic_hook = "0.1.7" serde_json = "1" # This crate is not a part of the workspace, because it -# requires the "jsonrpsee web" features to be enabled, which we don't +# requires the "jsonrpsee web unstable-light-client" features to be enabled, which we don't # want enabled for workspace builds in general. -subxt = { path = "../../subxt", default-features = false, features = ["web", "jsonrpsee"] } +subxt = { path = "../../subxt", default-features = false, features = ["web", "jsonrpsee", "unstable-light-client"] } From 4f0f69e204b3a62fe500247a612031bf68be52f5 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 23 Jun 2023 19:57:02 +0300 Subject: [PATCH 02/36] Add light client test Signed-off-by: Alexandru Vasile --- testing/wasm-tests/tests/wasm.rs | 44 ++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/testing/wasm-tests/tests/wasm.rs b/testing/wasm-tests/tests/wasm.rs index e91aaed0b9..33f5891303 100644 --- a/testing/wasm-tests/tests/wasm.rs +++ b/testing/wasm-tests/tests/wasm.rs @@ -1,6 +1,9 @@ #![cfg(target_arch = "wasm32")] -use subxt::config::PolkadotConfig; +use subxt::{config::PolkadotConfig, + client::{LightClient, OfflineClientT, LightClientBuilder}, +}; +use futures_util::StreamExt; use wasm_bindgen_test::*; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); @@ -11,7 +14,15 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); // wasm-pack test --firefox --headless` // ``` // -// You'll need to have a substrate/polkadot node running too with eg `substrate --dev`. +// You'll need to have a substrate/polkadot node running: +// +// ```bash +// # Polkadot does not accept by default WebSocket connections to the P2P network. +// # Ensure `--listen-addr` is provided with valid ws adddress endpoint. +// # The `--node-key` provides a deterministic p2p address for the node. +// ./polkadot --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws +// ``` +// #[wasm_bindgen_test] async fn wasm_ws_transport_works() { @@ -22,3 +33,32 @@ async fn wasm_ws_transport_works() { let chain = client.rpc().system_chain().await.unwrap(); assert_eq!(&chain, "Development"); } + +#[wasm_bindgen_test] +async fn light_client_works() { + console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); + + let api: LightClient = LightClientBuilder::new() + .bootnodes( + ["/ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp"] + .into_iter(), + ) + .build_from_url("ws://127.0.0.1:9944") + .await + .unwrap(); + + tracing::info!("Subscribe to latest finalized blocks: "); + + let mut blocks_sub = api.blocks().subscribe_finalized().await.expect("Cannot subscribe to finalized hashes").take(3); + // For each block, print a bunch of information about it: + while let Some(block) = blocks_sub.next().await { + let block = block.expect("Block not valid"); + + let block_number = block.header().number; + let block_hash = block.hash(); + + tracing::info!("Block #{block_number}:"); + tracing::info!(" Hash: {block_hash}"); + } +} From 467a4e828dffbd15c3eb462d93aeba6c48eeb7b4 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 23 Jun 2023 19:57:30 +0300 Subject: [PATCH 03/36] Implement low level socket Signed-off-by: Alexandru Vasile --- .../lightclient/platform/wasm_socket.rs | 228 ++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 subxt/src/client/lightclient/platform/wasm_socket.rs diff --git a/subxt/src/client/lightclient/platform/wasm_socket.rs b/subxt/src/client/lightclient/platform/wasm_socket.rs new file mode 100644 index 0000000000..0ac34d4e8b --- /dev/null +++ b/subxt/src/client/lightclient/platform/wasm_socket.rs @@ -0,0 +1,228 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +use futures::{io, prelude::*}; +use send_wrapper::SendWrapper; +use wasm_bindgen::{prelude::*, JsCast}; +use web_sys::{MessageEvent, WebSocket}; + +use std::{ + collections::VecDeque, + pin::Pin, + sync::{Arc, Mutex}, + task::Poll, + task::{Context, Waker}, +}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Failed to connect {0}")] + ConnectionError(String), +} + +/// Wasm websocket. +pub struct WasmSocket { + inner: Arc>, +} + +/// The state of the [`WasmSocket`]. +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum ConnectionState { + /// Initial state of the socket. + Connecting, + /// Socket is fully opened. + Opened, + /// Socket is closed. + Closed, + /// Error reported by callbacks. + Error, +} + +struct InnerWasmSocket { + state: ConnectionState, + /// This implements `Send` and panics if the value is accessed + /// or dropped from another thread. + /// + /// This is safe in wasm environments. + socket: SendWrapper, + data: VecDeque, + waker: Option, + callbacks: Option>, +} + +/// Registered callbacks of the [`WasmSocket`]. +struct Callbacks { + open: Closure, + message: Closure, + error: Closure, + close: Closure, +} + +impl WasmSocket { + /// Constructs a new [`WasmSocket`]. + pub fn new(addr: &str) -> Result { + let socket = match WebSocket::new(addr) { + Ok(socket) => socket, + Err(err) => return Err(Error::ConnectionError(format!("{:?}", err))), + }; + + socket.set_binary_type(web_sys::BinaryType::Arraybuffer); + + let inner = Arc::new(Mutex::new(InnerWasmSocket { + state: ConnectionState::Connecting, + socket: SendWrapper::new(socket.clone()), + data: VecDeque::with_capacity(16384), + waker: None, + callbacks: None, + })); + + let open = Closure::::new({ + let inner = inner.clone(); + move || { + let mut inner = inner.lock().expect("Mutex is poised; qed"); + inner.state = ConnectionState::Opened; + + if let Some(waker) = &inner.waker { + waker.wake_by_ref(); + } + } + }); + socket.set_onopen(Some(open.as_ref().unchecked_ref())); + + let message = Closure::::new({ + let inner = inner.clone(); + move |event: MessageEvent| { + let Ok(buffer) = event.data().dyn_into::() else { + panic!("Unexpected data format {:?}", event.data()); + }; + + let mut inner = inner.lock().expect("Mutex is poised; qed"); + let bytes = js_sys::Uint8Array::new(&buffer).to_vec(); + inner.data.extend(bytes.into_iter()); + + if let Some(waker) = &inner.waker { + waker.wake_by_ref(); + } + } + }); + socket.set_onmessage(Some(message.as_ref().unchecked_ref())); + + let error = Closure::::new({ + let inner = inner.clone(); + move |_| { + // Callback does not provide useful information, signal it back to the stream. + let mut inner = inner.lock().expect("Mutex is poised; qed"); + inner.state = ConnectionState::Error; + + if let Some(waker) = &inner.waker { + waker.wake_by_ref(); + } + } + }); + socket.set_onerror(Some(error.as_ref().unchecked_ref())); + + let close = Closure::::new({ + let inner = inner.clone(); + move |_| { + let mut inner = inner.lock().expect("Mutex is poised; qed"); + inner.state = ConnectionState::Closed; + + if let Some(waker) = &inner.waker { + waker.wake_by_ref(); + } + } + }); + socket.set_onclose(Some(close.as_ref().unchecked_ref())); + + let callbacks = SendWrapper::new(Callbacks { + open, + message, + error, + close, + }); + inner.lock().expect("Mutex poised; qed").callbacks = Some(callbacks); + + Ok(Self { inner }) + } + + /// The state of the [`WasmSocket`]. + pub fn state(&self) -> ConnectionState { + let inner = self.inner.lock().expect("Mutex is poised; qed"); + inner.state + } +} + +impl AsyncRead for WasmSocket { + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut [u8], + ) -> Poll> { + let mut inner = self.inner.lock().expect("Mutex is poised; qed"); + inner.waker = Some(cx.waker().clone()); + + match inner.state { + ConnectionState::Error => { + Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, "Socket error"))) + } + ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())), + ConnectionState::Connecting => Poll::Pending, + ConnectionState::Opened => { + if inner.data.is_empty() { + return Poll::Pending; + } + + let n = inner.data.len().min(buf.len()); + for k in buf.iter_mut().take(n) { + *k = inner.data.pop_front().unwrap(); + } + Poll::Ready(Ok(n)) + } + } + } +} + +impl AsyncWrite for WasmSocket { + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + let mut inner = self.inner.lock().expect("Mutex is poised; qed"); + inner.waker = Some(cx.waker().clone()); + + match inner.state { + ConnectionState::Error => { + Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, "Socket error"))) + } + ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())), + ConnectionState::Connecting => Poll::Pending, + ConnectionState::Opened => match inner.socket.send_with_u8_array(buf) { + Ok(()) => Poll::Ready(Ok(buf.len())), + Err(err) => Poll::Ready(Err(io::Error::new( + io::ErrorKind::Other, + format!("Write error: {err:?}"), + ))), + }, + } + } + + fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + Poll::Pending + } +} + +impl Drop for WasmSocket { + fn drop(&mut self) { + let inner = self.inner.lock().expect("Mutex is poised; qed"); + + if inner.state == ConnectionState::Opened { + let _ = inner.socket.close(); + } + } +} From 52ee64dc280d4a374920267904b47eeb1d6fe431 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 23 Jun 2023 19:58:33 +0300 Subject: [PATCH 04/36] Add native platform primitives Signed-off-by: Alexandru Vasile --- .../src/client/lightclient/platform/native.rs | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 subxt/src/client/lightclient/platform/native.rs diff --git a/subxt/src/client/lightclient/platform/native.rs b/subxt/src/client/lightclient/platform/native.rs new file mode 100644 index 0000000000..64006f026e --- /dev/null +++ b/subxt/src/client/lightclient/platform/native.rs @@ -0,0 +1,161 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +//! Native implementation for the light client's platform using +//! `tokio::net::TcpStream` for connections. + +use core::time::Duration; +use futures_util::{future, FutureExt}; +use smoldot::libp2p::{multiaddr::ProtocolRef, websocket}; +use smoldot_light::platform::{ConnectError, PlatformConnection}; +use std::{ + collections::VecDeque, + net::{IpAddr, SocketAddr}, +}; +use tokio::net::TcpStream; +use tokio_util::compat::{Compat, TokioAsyncReadCompatExt}; + +pub fn spawn(task: future::BoxFuture<'static, ()>) { + tokio::spawn(task); +} + +pub fn now_from_unix_epoch() -> Duration { + // Intentionally panic if the time is configured earlier than the UNIX EPOCH. + std::time::UNIX_EPOCH.elapsed().unwrap_or_else(|_| { + panic!("Invalid systime cannot be configured earlier than `UNIX_EPOCH`") + }) +} + +pub type Instant = std::time::Instant; + +pub fn now() -> Instant { + Instant::now() +} + +pub type Delay = future::BoxFuture<'static, ()>; + +pub fn sleep(duration: Duration) -> Delay { + tokio::time::sleep(duration).boxed() +} + +pub type CompatTcpStream = Compat; +pub type Socket = future::Either>; + +pub struct Stream { + pub socket: Socket, + /// Read and write buffers of the connection, or `None` if the socket has been reset. + pub buffers: Option<(StreamReadBuffer, StreamWriteBuffer)>, +} + +pub enum StreamReadBuffer { + Open { + buffer: Vec, + cursor: std::ops::Range, + }, + Closed, +} + +pub enum StreamWriteBuffer { + Open { + buffer: VecDeque, + must_flush: bool, + must_close: bool, + }, + Closed, +} + +pub async fn connect<'a>( + proto1: ProtocolRef<'a>, + proto2: ProtocolRef<'a>, + proto3: Option>, +) -> Result, ConnectError> { + // Ensure ahead of time that the multiaddress is supported. + let (addr, host_if_websocket) = match (&proto1, &proto2, &proto3) { + (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), None) => ( + either::Left(SocketAddr::new(IpAddr::V4((*ip).into()), *port)), + None, + ), + (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), None) => ( + either::Left(SocketAddr::new(IpAddr::V6((*ip).into()), *port)), + None, + ), + (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { + let addr = SocketAddr::new(IpAddr::V4((*ip).into()), *port); + (either::Left(addr), Some(addr.to_string())) + } + (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { + let addr = SocketAddr::new(IpAddr::V6((*ip).into()), *port); + (either::Left(addr), Some(addr.to_string())) + } + ( + ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), + ProtocolRef::Tcp(port), + None, + ) => (either::Right((addr.to_string(), *port)), None), + ( + ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), + ProtocolRef::Tcp(port), + Some(ProtocolRef::Ws), + ) => ( + either::Right((addr.to_string(), *port)), + Some(format!("{}:{}", addr, *port)), + ), + _ => { + return Err(ConnectError { + is_bad_addr: true, + message: "Unknown protocols combination".to_string(), + }) + } + }; + + tracing::debug!("Connecting to addr={addr:?}"); + + let tcp_socket = match addr { + either::Left(socket_addr) => tokio::net::TcpStream::connect(socket_addr).await, + either::Right((dns, port)) => tokio::net::TcpStream::connect((&dns[..], port)).await, + }; + + if let Ok(tcp_socket) = &tcp_socket { + let _ = tcp_socket.set_nodelay(true); + } + + let socket: Socket = match (tcp_socket, host_if_websocket) { + (Ok(tcp_socket), Some(host)) => future::Either::Right( + websocket::websocket_client_handshake(websocket::Config { + tcp_socket: tcp_socket.compat(), + host: &host, + url: "/", + }) + .await + .map_err(|err| ConnectError { + message: format!("Failed to negotiate WebSocket: {err}"), + is_bad_addr: false, + })?, + ), + (Ok(tcp_socket), None) => future::Either::Left(tcp_socket.compat()), + (Err(err), _) => { + return Err(ConnectError { + is_bad_addr: false, + message: format!("Failed to reach peer: {err}"), + }) + } + }; + + Ok(PlatformConnection::SingleStreamMultistreamSelectNoiseYamux( + Stream { + socket, + buffers: Some(( + StreamReadBuffer::Open { + buffer: vec![0; 16384], + cursor: 0..0, + }, + StreamWriteBuffer::Open { + buffer: VecDeque::with_capacity(16384), + must_close: false, + must_flush: false, + }, + )), + }, + )) +} From f2b3547e297e61cab7e0863753496698c15b56e0 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 23 Jun 2023 19:58:44 +0300 Subject: [PATCH 05/36] Add wasm platform primitives Signed-off-by: Alexandru Vasile --- subxt/src/client/lightclient/platform/wasm.rs | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 subxt/src/client/lightclient/platform/wasm.rs diff --git a/subxt/src/client/lightclient/platform/wasm.rs b/subxt/src/client/lightclient/platform/wasm.rs new file mode 100644 index 0000000000..0fd93ac910 --- /dev/null +++ b/subxt/src/client/lightclient/platform/wasm.rs @@ -0,0 +1,111 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +//! Wasm implementation for the light client's platform using +//! custom websockets. + +use core::time::Duration; +use futures_util::{future, FutureExt}; +use smoldot::libp2p::multiaddr::ProtocolRef; +use smoldot_light::platform::{ConnectError, PlatformConnection}; +use std::{ + collections::VecDeque, + net::{IpAddr, SocketAddr}, +}; + +use super::wasm_socket::WasmSocket; + +pub fn spawn(task: future::BoxFuture<'static, ()>) { + wasm_bindgen_futures::spawn_local(task); +} + +pub fn now_from_unix_epoch() -> Duration { + instant::SystemTime::now() + .duration_since(instant::SystemTime::UNIX_EPOCH) + .unwrap_or_else(|_| { + panic!("Invalid systime cannot be configured earlier than `UNIX_EPOCH`") + }) +} + +pub type Instant = instant::Instant; + +pub fn now() -> Instant { + instant::Instant::now() +} + +pub type Delay = future::BoxFuture<'static, ()>; + +pub fn sleep(duration: Duration) -> Delay { + futures_timer::Delay::new(duration).boxed() +} + +pub struct Stream { + pub socket: WasmSocket, + /// Read and write buffers of the connection, or `None` if the socket has been reset. + pub buffers: Option<(StreamReadBuffer, StreamWriteBuffer)>, +} + +pub enum StreamReadBuffer { + Open { + buffer: Vec, + cursor: std::ops::Range, + }, + Closed, +} + +pub enum StreamWriteBuffer { + Open { + buffer: VecDeque, + must_flush: bool, + must_close: bool, + }, + Closed, +} + +pub async fn connect<'a>( + proto1: ProtocolRef<'a>, + proto2: ProtocolRef<'a>, + proto3: Option>, +) -> Result, ConnectError> { + // Ensure ahead of time that the multiaddress is supported. + let addr = match (&proto1, &proto2, &proto3) { + (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { + SocketAddr::new(IpAddr::V4((*ip).into()), *port) + } + (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { + SocketAddr::new(IpAddr::V6((*ip).into()), *port) + } + _ => { + return Err(ConnectError { + is_bad_addr: true, + message: "Unknown protocols combination".to_string(), + }) + } + }; + + let addr = format!("ws://{}", addr.to_string()); + tracing::debug!("Connecting to addr={addr}"); + + let socket = WasmSocket::new(addr.as_str()).map_err(|err| ConnectError { + is_bad_addr: false, + message: format!("Failed to reach peer: {err}"), + })?; + + Ok(PlatformConnection::SingleStreamMultistreamSelectNoiseYamux( + Stream { + socket, + buffers: Some(( + StreamReadBuffer::Open { + buffer: vec![0; 16384], + cursor: 0..0, + }, + StreamWriteBuffer::Open { + buffer: VecDeque::with_capacity(16384), + must_close: false, + must_flush: false, + }, + )), + }, + )) +} From 9a52898383124eb895f2eb889072020bce4a5eb7 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 23 Jun 2023 19:58:56 +0300 Subject: [PATCH 06/36] Implement smoldot platform Signed-off-by: Alexandru Vasile --- .../client/lightclient/platform/default.rs | 300 ++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 subxt/src/client/lightclient/platform/default.rs diff --git a/subxt/src/client/lightclient/platform/default.rs b/subxt/src/client/lightclient/platform/default.rs new file mode 100644 index 0000000000..6703dc8282 --- /dev/null +++ b/subxt/src/client/lightclient/platform/default.rs @@ -0,0 +1,300 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +use core::time::Duration; +use futures::{prelude::*, task::Poll}; + +use smoldot::libp2p::multiaddr::Multiaddr; +use smoldot_light::platform::{ + ConnectError, PlatformConnection, PlatformRef, PlatformSubstreamDirection, ReadBuffer, +}; +use std::{io::IoSlice, pin::Pin}; + +#[cfg(not(feature = "unstable-light-client-wasm"))] +use super::native as platform_impl; +#[cfg(feature = "unstable-light-client-wasm")] +use super::wasm as platform_impl; + +use platform_impl::{StreamReadBuffer, StreamWriteBuffer}; + +/// Subxt plaform implementation for native and wasm. +/// +/// This implementation is a conversion of the implementation from the smoldot: +/// https://github.com/smol-dot/smoldot/blob/f49ce4ea6a325c444ab6ad37d3ab5558edf0d541/light-base/src/platform/default.rs#L52. +#[derive(Clone)] +pub struct SubxtPlatform {} + +impl SubxtPlatform { + pub fn new() -> Self { + SubxtPlatform {} + } +} + +impl PlatformRef for SubxtPlatform { + type Delay = platform_impl::Delay; + type Yield = future::Ready<()>; + type Instant = platform_impl::Instant; + type Connection = std::convert::Infallible; + type Stream = platform_impl::Stream; + type ConnectFuture = future::BoxFuture< + 'static, + Result, ConnectError>, + >; + type StreamUpdateFuture<'a> = future::BoxFuture<'a, ()>; + type NextSubstreamFuture<'a> = + future::Pending>; + + fn now_from_unix_epoch(&self) -> Duration { + platform_impl::now_from_unix_epoch() + } + + fn now(&self) -> Self::Instant { + platform_impl::now() + } + + fn sleep(&self, duration: Duration) -> Self::Delay { + platform_impl::sleep(duration) + } + + fn sleep_until(&self, when: Self::Instant) -> Self::Delay { + self.sleep(when.saturating_duration_since(self.now())) + } + + fn yield_after_cpu_intensive(&self) -> Self::Yield { + // No-op. + future::ready(()) + } + + fn connect(&self, multiaddr: &str) -> Self::ConnectFuture { + // We simply copy the address to own it. We could be more zero-cost here, but doing so + // would considerably complicate the implementation. + let multiaddr = multiaddr.to_owned(); + + tracing::debug!("Connecting to multiaddress={:?}", multiaddr); + + Box::pin(async move { + let addr = multiaddr.parse::().map_err(|_| ConnectError { + is_bad_addr: true, + message: "Failed to parse address".to_string(), + })?; + + let mut iter = addr.iter().fuse(); + let proto1 = iter.next().ok_or(ConnectError { + is_bad_addr: true, + message: "Unknown protocols combination".to_string(), + })?; + let proto2 = iter.next().ok_or(ConnectError { + is_bad_addr: true, + message: "Unknown protocols combination".to_string(), + })?; + let proto3 = iter.next(); + + if iter.next().is_some() { + return Err(ConnectError { + is_bad_addr: true, + message: "Unknown protocols combination".to_string(), + }); + } + + platform_impl::connect(proto1, proto2, proto3).await + }) + } + + fn open_out_substream(&self, c: &mut Self::Connection) { + // This function can only be called with so-called "multi-stream" connections. We never + // open such connection. + match *c {} + } + + fn next_substream<'a>(&self, c: &'a mut Self::Connection) -> Self::NextSubstreamFuture<'a> { + // This function can only be called with so-called "multi-stream" connections. We never + // open such connection. + match *c {} + } + + fn update_stream<'a>(&self, stream: &'a mut Self::Stream) -> Self::StreamUpdateFuture<'a> { + Box::pin(future::poll_fn(|cx| { + let Some((read_buffer, write_buffer)) = stream.buffers.as_mut() else { return Poll::Pending }; + + // Whether the future returned by `update_stream` should return `Ready` or `Pending`. + let mut update_stream_future_ready = false; + + if let StreamReadBuffer::Open { + buffer: ref mut buf, + ref mut cursor, + } = read_buffer + { + // When reading data from the socket, `poll_read` might return "EOF". In that + // situation, we transition to the `Closed` state, which would discard the data + // currently in the buffer. For this reason, we only try to read if there is no + // data left in the buffer. + if cursor.start == cursor.end { + if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_read(cx, buf) { + update_stream_future_ready = true; + match result { + Err(_) => { + // End the stream. + stream.buffers = None; + return Poll::Ready(()); + } + Ok(0) => { + // EOF. + *read_buffer = StreamReadBuffer::Closed; + } + Ok(bytes) => { + *cursor = 0..bytes; + } + } + } + } + } + + if let StreamWriteBuffer::Open { + buffer: ref mut buf, + must_flush, + must_close, + } = write_buffer + { + while !buf.is_empty() { + let write_queue_slices = buf.as_slices(); + if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_write_vectored( + cx, + &[ + IoSlice::new(write_queue_slices.0), + IoSlice::new(write_queue_slices.1), + ], + ) { + if !*must_close { + // In the situation where the API user wants to close the writing + // side, simply sending the buffered data isn't enough to justify + // making the future ready. + update_stream_future_ready = true; + } + + match result { + Err(_) => { + // End the stream. + stream.buffers = None; + return Poll::Ready(()); + } + Ok(bytes) => { + *must_flush = true; + for _ in 0..bytes { + buf.pop_front(); + } + } + } + } else { + break; + } + } + + if buf.is_empty() && *must_close { + if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_close(cx) { + update_stream_future_ready = true; + match result { + Err(_) => { + // End the stream. + stream.buffers = None; + return Poll::Ready(()); + } + Ok(()) => { + *write_buffer = StreamWriteBuffer::Closed; + } + } + } + } else if *must_flush { + if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_flush(cx) { + update_stream_future_ready = true; + match result { + Err(_) => { + // End the stream. + stream.buffers = None; + return Poll::Ready(()); + } + Ok(()) => { + *must_flush = false; + } + } + } + } + } + + if update_stream_future_ready { + Poll::Ready(()) + } else { + Poll::Pending + } + })) + } + + fn read_buffer<'a>(&self, stream: &'a mut Self::Stream) -> ReadBuffer<'a> { + match stream.buffers.as_ref().map(|(r, _)| r) { + None => ReadBuffer::Reset, + Some(StreamReadBuffer::Closed) => ReadBuffer::Closed, + Some(StreamReadBuffer::Open { buffer, cursor }) => { + ReadBuffer::Open(&buffer[cursor.clone()]) + } + } + } + + fn advance_read_cursor(&self, stream: &mut Self::Stream, extra_bytes: usize) { + let Some(StreamReadBuffer::Open { ref mut cursor, .. }) = + stream.buffers.as_mut().map(|(r, _)| r) + else { + assert_eq!(extra_bytes, 0); + return + }; + + assert!(cursor.start + extra_bytes <= cursor.end); + cursor.start += extra_bytes; + } + + fn writable_bytes(&self, stream: &mut Self::Stream) -> usize { + let Some(StreamWriteBuffer::Open { ref mut buffer, must_close: false, ..}) = + stream.buffers.as_mut().map(|(_, w)| w) else { return 0 }; + buffer.capacity() - buffer.len() + } + + fn send(&self, stream: &mut Self::Stream, data: &[u8]) { + debug_assert!(!data.is_empty()); + + // Because `writable_bytes` returns 0 if the writing side is closed, and because `data` + // must always have a size inferior or equal to `writable_bytes`, we know for sure that + // the writing side isn't closed. + let Some(StreamWriteBuffer::Open { ref mut buffer, .. } )= + stream.buffers.as_mut().map(|(_, w)| w) else { panic!() }; + buffer.reserve(data.len()); + buffer.extend(data.iter().copied()); + } + + fn close_send(&self, stream: &mut Self::Stream) { + // It is not illegal to call this on an already-reset stream. + let Some((_, write_buffer)) = stream.buffers.as_mut() else { return }; + + match write_buffer { + StreamWriteBuffer::Open { + must_close: must_close @ false, + .. + } => *must_close = true, + _ => { + // However, it is illegal to call this on a stream that was already close + // attempted. + panic!() + } + } + } + + fn spawn_task(&self, _: std::borrow::Cow, task: future::BoxFuture<'static, ()>) { + platform_impl::spawn(task); + } + + fn client_name(&self) -> std::borrow::Cow { + "subxt-light-client".into() + } + + fn client_version(&self) -> std::borrow::Cow { + env!("CARGO_PKG_VERSION").into() + } +} From ebb0ba89610c4ce36f9485122dc0e23cd81beffc Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 23 Jun 2023 19:59:14 +0300 Subject: [PATCH 07/36] Adjust code to use custom platform Signed-off-by: Alexandru Vasile --- Cargo.lock | 20 +- Cargo.toml | 13 +- codegen/src/utils/fetch_metadata.rs | 2 +- subxt/Cargo.toml | 33 +- subxt/src/client/lightclient/background.rs | 9 +- subxt/src/client/lightclient/builder.rs | 81 +++-- subxt/src/client/lightclient/mod.rs | 1 + subxt/src/client/lightclient/platform/mod.rs | 13 + subxt/src/client/lightclient/rpc.rs | 19 +- subxt/src/client/mod.rs | 10 +- subxt/src/error/mod.rs | 10 +- testing/wasm-tests/Cargo.lock | 363 +------------------ testing/wasm-tests/Cargo.toml | 4 +- 13 files changed, 190 insertions(+), 388 deletions(-) create mode 100644 subxt/src/client/lightclient/platform/mod.rs diff --git a/Cargo.lock b/Cargo.lock index aec732d3b7..5c10fd10de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1481,7 +1481,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" dependencies = [ "gloo-timers", - "send_wrapper", + "send_wrapper 0.4.0", ] [[package]] @@ -1938,6 +1938,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -3366,6 +3369,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "serde" version = "1.0.164" @@ -4148,10 +4157,13 @@ dependencies = [ "either", "frame-metadata", "futures", + "futures-timer", "futures-util", "getrandom 0.2.10", "hex", "impl-serde", + "instant", + "js-sys", "jsonrpsee", "parity-scale-codec", "primitive-types", @@ -4160,8 +4172,10 @@ dependencies = [ "scale-encode", "scale-info", "scale-value", + "send_wrapper 0.6.0", "serde", "serde_json", + "smoldot", "smoldot-light", "sp-core", "sp-core-hashing", @@ -4174,8 +4188,12 @@ dependencies = [ "thiserror", "tokio", "tokio-stream", + "tokio-util", "tracing", "tracing-subscriber 0.3.17", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fba1684d33..c4d3c2f074 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ serde = { version = "1.0.164" } serde_json = { version = "1.0.97" } syn = { version = "2.0.15", features = ["full", "extra-traits"] } thiserror = "1.0.40" -tokio = { version = "1.28", features = ["macros", "time", "rt-multi-thread"] } +tokio = { version = "1.28", default-features = false } tracing = "0.1.34" tracing-wasm = "0.2.1" tracing-subscriber = "0.3.17" @@ -77,10 +77,21 @@ wasm-bindgen-test = "0.3.24" which = "4.4.0" # Light client support: +smoldot = { version = "0.8.0", default-features = false } smoldot-light = { version = "0.6.0", default-features = false } tokio-stream = "0.1.14" futures-util = "0.3.28" +# Light client wasm: +web-sys = { version = "0.3.61", features = [ "BinaryType", "CloseEvent", "MessageEvent", "WebSocket"] } +wasm-bindgen = "0.2.84" +send_wrapper = "0.6.0" +js-sys = "0.3.61" +wasm-bindgen-futures = "0.4.19" +futures-timer = "3" +instant = { version = "0.1.12", default-features = false } +tokio-util = "0.7.8" + # Substrate crates: sp-core = { version = "21.0.0", default-features = false } sp-core-hashing = "9.0.0" diff --git a/codegen/src/utils/fetch_metadata.rs b/codegen/src/utils/fetch_metadata.rs index 9d49e35ac4..3953d0971f 100644 --- a/codegen/src/utils/fetch_metadata.rs +++ b/codegen/src/utils/fetch_metadata.rs @@ -62,7 +62,7 @@ pub fn fetch_metadata_hex_blocking( // Block on some tokio runtime for sync contexts fn tokio_block_on>(fut: Fut) -> T { - tokio::runtime::Builder::new_multi_thread() + tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap() diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index d7d78127eb..f35de2906f 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -17,7 +17,7 @@ keywords = ["parity", "substrate", "blockchain"] [features] # For dev and documentation reasons we enable more features than are often desired. # it's recommended to use `--no-default-features` and then select what you need. -default = ["jsonrpsee", "native", "substrate-compat"] +default = ["jsonrpsee", "web", "substrate-compat", "unstable-light-client-wasm"] # Enable this for native (ie non web/wasm builds). # Exactly 1 of "web" and "native" is expected. @@ -56,11 +56,33 @@ unstable-metadata = [] # Activate this to expose the Light Client functionality. # Note that this feature is experimental and things may break or not work as expected. unstable-light-client = [ + "smoldot", "smoldot-light/std", "tokio-stream", "tokio/sync", "tokio/rt", "futures-util", + "tokio-util", +] + +unstable-light-client-wasm = [ + "smoldot", + "smoldot-light", + + "tokio-stream", + "tokio/sync", + "futures-util", + + # For the light-client platform. + "wasm-bindgen-futures", + "futures-timer/wasm-bindgen", + "instant/wasm-bindgen", + + # For websocket. + "js-sys", + "send_wrapper", + "web-sys", + "wasm-bindgen", ] [dependencies] @@ -101,10 +123,19 @@ subxt-macro = { workspace = true } subxt-metadata = { workspace = true } # Light client support: +smoldot = { workspace = true, optional = true } smoldot-light = { workspace = true, optional = true } tokio = { workspace = true, optional = true } tokio-stream = { workspace = true, optional = true } futures-util = { workspace = true, optional = true } +js-sys = { workspace = true, optional = true } +send_wrapper = { workspace = true, optional = true } +web-sys = { workspace = true, optional = true } +wasm-bindgen = { workspace = true, optional = true } +wasm-bindgen-futures = { workspace = true, optional = true } +futures-timer = { workspace = true, optional = true } +instant = { workspace = true, optional = true } +tokio-util = { workspace = true, optional = true } # Included if "web" feature is enabled, to enable its js feature. getrandom = { workspace = true, optional = true } diff --git a/subxt/src/client/lightclient/background.rs b/subxt/src/client/lightclient/background.rs index 6de5103be8..42094cd02e 100644 --- a/subxt/src/client/lightclient/background.rs +++ b/subxt/src/client/lightclient/background.rs @@ -6,11 +6,12 @@ use futures::stream::StreamExt; use futures_util::future::{self, Either}; use serde::Deserialize; use serde_json::value::RawValue; -use std::{collections::HashMap, str::FromStr, sync::Arc}; +use std::{collections::HashMap, str::FromStr}; use tokio::sync::{mpsc, oneshot}; +use super::platform::default::SubxtPlatform as Platform; use super::LightClientError; -use smoldot_light::{platform::default::DefaultPlatform as Platform, ChainId}; +use smoldot_light::ChainId; const LOG_TARGET: &str = "light-client-background"; @@ -50,7 +51,7 @@ pub enum FromSubxt { /// Background task data. pub struct BackgroundTask { /// Smoldot light client implementation that leverages the exposed platform. - client: smoldot_light::Client>, + client: smoldot_light::Client, /// The ID of the chain used to identify the chain protocol (ie. substrate). /// /// Note: A single chain is supported for a client. This aligns with the subxt's @@ -79,7 +80,7 @@ pub struct BackgroundTask { impl BackgroundTask { /// Constructs a new [`BackgroundTask`]. - pub fn new(client: smoldot_light::Client>, chain_id: ChainId) -> BackgroundTask { + pub fn new(client: smoldot_light::Client, chain_id: ChainId) -> BackgroundTask { BackgroundTask { client, chain_id, diff --git a/subxt/src/client/lightclient/builder.rs b/subxt/src/client/lightclient/builder.rs index f27542959e..c386100bc2 100644 --- a/subxt/src/client/lightclient/builder.rs +++ b/subxt/src/client/lightclient/builder.rs @@ -5,13 +5,6 @@ use super::{rpc::LightClientRpc, LightClient, LightClientError}; use crate::{config::Config, error::Error, OnlineClient}; -#[cfg(feature = "jsonrpsee")] -use jsonrpsee::{ - async_client::ClientBuilder, - client_transport::ws::{Uri, WsTransportClientBuilder}, - core::client::ClientT, - rpc_params, -}; use smoldot_light::ChainId; use std::num::NonZeroU32; use std::sync::Arc; @@ -165,27 +158,65 @@ impl LightClientBuilder { /// Fetch the chain spec from the URL. #[cfg(feature = "jsonrpsee")] async fn fetch_url(url: impl AsRef) -> Result { - let url = url - .as_ref() - .parse::() - .map_err(|_| Error::LightClient(LightClientError::InvalidUrl))?; - - if url.scheme_str() != Some("ws") && url.scheme_str() != Some("wss") { - return Err(Error::LightClient(LightClientError::InvalidScheme)); - } - - let (sender, receiver) = WsTransportClientBuilder::default() - .build(url) - .await - .map_err(|_| LightClientError::Handshake)?; + use jsonrpsee::core::client::ClientT; - let client = ClientBuilder::default() - .request_timeout(core::time::Duration::from_secs(180)) - .max_notifs_per_subscription(4096) - .build_with_tokio(sender, receiver); + let client = jsonrpsee_helpers::client(url.as_ref()).await?; client - .request("sync_state_genSyncSpec", rpc_params![true]) + .request("sync_state_genSyncSpec", jsonrpsee::rpc_params![true]) .await .map_err(|err| Error::Rpc(crate::error::RpcError::ClientError(Box::new(err)))) } + +#[cfg(all(feature = "jsonrpsee", feature = "native"))] +mod jsonrpsee_helpers { + use crate::error::{Error, LightClientError}; + pub use jsonrpsee::{ + client_transport::ws::{InvalidUri, Receiver, Sender, Uri, WsTransportClientBuilder}, + core::client::{Client, ClientBuilder}, + }; + + /// Build WS RPC client from URL + pub async fn client(url: &str) -> Result { + let url = url + .parse::() + .map_err(|_| Error::LightClient(LightClientError::InvalidUrl))?; + + if url.scheme_str() != Some("ws") && url.scheme_str() != Some("wss") { + return Err(Error::LightClient(LightClientError::InvalidScheme)); + } + + let (sender, receiver) = ws_transport(url).await?; + + Ok(ClientBuilder::default() + .max_notifs_per_subscription(4096) + .build_with_tokio(sender, receiver)) + } + + async fn ws_transport(url: Uri) -> Result<(Sender, Receiver), Error> { + WsTransportClientBuilder::default() + .build(url) + .await + .map_err(|_| Error::LightClient(LightClientError::Handshake)) + } +} + +#[cfg(all(feature = "jsonrpsee", feature = "web"))] +mod jsonrpsee_helpers { + use crate::error::{Error, LightClientError}; + pub use jsonrpsee::{ + client_transport::web, + core::client::{Client, ClientBuilder}, + }; + + /// Build web RPC client from URL + pub async fn client(url: &str) -> Result { + let (sender, receiver) = web::connect(url) + .await + .map_err(|_| Error::LightClient(LightClientError::Handshake))?; + + Ok(ClientBuilder::default() + .max_notifs_per_subscription(4096) + .build_with_wasm(sender, receiver)) + } +} diff --git a/subxt/src/client/lightclient/mod.rs b/subxt/src/client/lightclient/mod.rs index 5f07be3f9e..091b49d201 100644 --- a/subxt/src/client/lightclient/mod.rs +++ b/subxt/src/client/lightclient/mod.rs @@ -6,6 +6,7 @@ mod background; mod builder; +mod platform; mod rpc; use derivative::Derivative; diff --git a/subxt/src/client/lightclient/platform/mod.rs b/subxt/src/client/lightclient/platform/mod.rs new file mode 100644 index 0000000000..26868e37db --- /dev/null +++ b/subxt/src/client/lightclient/platform/mod.rs @@ -0,0 +1,13 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +pub mod default; + +#[cfg(not(feature = "unstable-light-client-wasm"))] +mod native; + +#[cfg(feature = "unstable-light-client-wasm")] +mod wasm; +#[cfg(feature = "unstable-light-client-wasm")] +mod wasm_socket; diff --git a/subxt/src/client/lightclient/rpc.rs b/subxt/src/client/lightclient/rpc.rs index bfa13c6370..1c3fdfa9ff 100644 --- a/subxt/src/client/lightclient/rpc.rs +++ b/subxt/src/client/lightclient/rpc.rs @@ -12,11 +12,14 @@ use crate::{ }; use futures::{stream::StreamExt, Stream}; use serde_json::value::RawValue; -use smoldot_light::{platform::default::DefaultPlatform as Platform, ChainId}; +// use smoldot_light::{platform::default::DefaultPlatform as Platform, ChainId}; +use smoldot_light::ChainId; use std::pin::Pin; use tokio::sync::{mpsc, mpsc::error::SendError, oneshot}; use tokio_stream::wrappers::UnboundedReceiverStream; +use super::platform::default::SubxtPlatform as Platform; + pub const LOG_TARGET: &str = "light-client"; /// The light-client RPC implementation that is used to connect with the chain. @@ -43,10 +46,7 @@ impl LightClientRpc { ) -> Result { tracing::trace!(target: LOG_TARGET, "Create light client"); - let mut client = smoldot_light::Client::new(Platform::new( - env!("CARGO_PKG_NAME").into(), - env!("CARGO_PKG_VERSION").into(), - )); + let mut client = smoldot_light::Client::new(Platform::new()); let smoldot_light::AddChainSuccess { chain_id, @@ -60,10 +60,15 @@ impl LightClientRpc { // `json_rpc_responses` can only be `None` if we had passed `json_rpc: Disabled`. let rpc_responses = json_rpc_responses.expect("Light client RPC configured; qed"); - tokio::spawn(async move { + let future = async move { let mut task = BackgroundTask::new(client, chain_id); task.start_task(backend, rpc_responses).await; - }); + }; + + #[cfg(not(feature = "unstable-light-client-wasm"))] + tokio::spawn(future); + #[cfg(feature = "unstable-light-client-wasm")] + wasm_bindgen_futures::spawn_local(future); Ok(LightClientRpc { to_backend }) } diff --git a/subxt/src/client/mod.rs b/subxt/src/client/mod.rs index b2cc087d34..62c265f9e8 100644 --- a/subxt/src/client/mod.rs +++ b/subxt/src/client/mod.rs @@ -11,7 +11,10 @@ mod offline_client; mod online_client; -#[cfg(feature = "unstable-light-client")] +#[cfg(any( + feature = "unstable-light-client", + feature = "unstable-light-client-wasm" +))] mod lightclient; pub use offline_client::{OfflineClient, OfflineClientT}; @@ -22,5 +25,8 @@ pub use online_client::{ #[cfg(feature = "jsonrpsee")] pub use online_client::default_rpc_client; -#[cfg(feature = "unstable-light-client")] +#[cfg(any( + feature = "unstable-light-client", + feature = "unstable-light-client-wasm" +))] pub use lightclient::{LightClient, LightClientBuilder, LightClientError}; diff --git a/subxt/src/error/mod.rs b/subxt/src/error/mod.rs index c47e27babc..e6b468d9a1 100644 --- a/subxt/src/error/mod.rs +++ b/subxt/src/error/mod.rs @@ -8,7 +8,10 @@ mod dispatch_error; use core::fmt::Debug; -#[cfg(feature = "unstable-light-client")] +#[cfg(any( + feature = "unstable-light-client", + feature = "unstable-light-client-wasm" +))] pub use crate::client::LightClientError; // Re-export dispatch error types: @@ -68,7 +71,10 @@ pub enum Error { #[error("An error occurred but it could not be decoded: {0:?}")] Unknown(Vec), /// Light client error. - #[cfg(feature = "unstable-light-client")] + #[cfg(any( + feature = "unstable-light-client", + feature = "unstable-light-client-wasm" + ))] #[error("An error occurred but it could not be decoded: {0:?}")] LightClient(#[from] LightClientError), /// Other error. diff --git a/testing/wasm-tests/Cargo.lock b/testing/wasm-tests/Cargo.lock index e60c7aad6b..3cf136f916 100644 --- a/testing/wasm-tests/Cargo.lock +++ b/testing/wasm-tests/Cargo.lock @@ -75,63 +75,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -[[package]] -name = "async-channel" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-executor" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" -dependencies = [ - "async-lock", - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" -dependencies = [ - "async-lock", - "autocfg", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite", - "log", - "parking", - "polling", - "rustix", - "slab", - "socket2", - "waker-fn", -] - [[package]] name = "async-lock" version = "2.7.0" @@ -141,42 +84,6 @@ dependencies = [ "event-listener", ] -[[package]] -name = "async-net" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f" -dependencies = [ - "async-io", - "autocfg", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-process" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" -dependencies = [ - "async-io", - "async-lock", - "autocfg", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix", - "signal-hook", - "windows-sys 0.48.0", -] - -[[package]] -name = "async-task" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" - [[package]] name = "async-trait" version = "0.1.68" @@ -194,12 +101,6 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" -[[package]] -name = "atomic-waker" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" - [[package]] name = "autocfg" version = "1.1.0" @@ -314,21 +215,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blocking" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" -dependencies = [ - "async-channel", - "async-lock", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "log", -] - [[package]] name = "bs58" version = "0.5.0" @@ -408,15 +294,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "concurrent-queue" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -704,42 +581,12 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "event-listener" version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fiat-crypto" version = "0.1.20" @@ -818,21 +665,6 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - [[package]] name = "futures-macro" version = "0.3.28" @@ -863,7 +695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" dependencies = [ "gloo-timers", - "send_wrapper", + "send_wrapper 0.4.0", ] [[package]] @@ -1005,21 +837,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - [[package]] name = "hex" version = "0.4.3" @@ -1188,6 +1005,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -1196,17 +1016,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f38a50a899dc47a6d0ed5508e7f601a2e34c3a85303514b5d137f3c10a0c75" -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "itertools" version = "0.10.5" @@ -1406,22 +1215,6 @@ dependencies = [ "libsecp256k1-core", ] -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "lock_api" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.19" @@ -1533,16 +1326,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - [[package]] name = "once_cell" version = "1.18.0" @@ -1597,35 +1380,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "parking" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - [[package]] name = "paste" version = "1.0.12" @@ -1679,22 +1433,6 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - [[package]] name = "poly1305" version = "0.7.2" @@ -1831,15 +1569,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags", -] - [[package]] name = "ring" version = "0.16.20" @@ -1876,20 +1605,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.37.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - [[package]] name = "rustls" version = "0.20.8" @@ -2084,12 +1799,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - [[package]] name = "sct" version = "0.7.0" @@ -2135,6 +1844,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "serde" version = "1.0.164" @@ -2222,25 +1937,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "signal-hook" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - [[package]] name = "siphasher" version = "0.3.10" @@ -2262,23 +1958,6 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" -[[package]] -name = "smol" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1" -dependencies = [ - "async-channel", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-net", - "async-process", - "blocking", - "futures-lite", -] - [[package]] name = "smoldot" version = "0.8.0" @@ -2312,7 +1991,6 @@ dependencies = [ "num-rational", "num-traits", "pbkdf2", - "pin-project", "rand", "rand_chacha", "ruzstd", @@ -2323,9 +2001,7 @@ dependencies = [ "siphasher", "slab", "smallvec", - "smol", "snow", - "soketto", "tiny-keccak", "twox-hash", "wasmi", @@ -2350,13 +2026,11 @@ dependencies = [ "itertools", "log", "lru", - "parking_lot", "rand", "serde", "serde_json", "siphasher", "slab", - "smol", "smoldot", ] @@ -2468,10 +2142,13 @@ dependencies = [ "either", "frame-metadata", "futures", + "futures-timer", "futures-util", "getrandom", "hex", "impl-serde", + "instant", + "js-sys", "jsonrpsee", "parity-scale-codec", "primitive-types", @@ -2480,8 +2157,10 @@ dependencies = [ "scale-encode", "scale-info", "scale-value", + "send_wrapper 0.6.0", "serde", "serde_json", + "smoldot", "smoldot-light", "sp-core-hashing", "subxt-macro", @@ -2490,6 +2169,9 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", ] [[package]] @@ -2643,7 +2325,6 @@ dependencies = [ "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", "tokio-macros", @@ -2839,12 +2520,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - [[package]] name = "want" version = "0.3.1" @@ -2955,8 +2630,10 @@ name = "wasm-tests" version = "0.1.0" dependencies = [ "console_error_panic_hook", + "futures-util", "serde_json", "subxt", + "tracing", "tracing-wasm", "wasm-bindgen-test", ] diff --git a/testing/wasm-tests/Cargo.toml b/testing/wasm-tests/Cargo.toml index 973972e7d1..fa44b9e1c0 100644 --- a/testing/wasm-tests/Cargo.toml +++ b/testing/wasm-tests/Cargo.toml @@ -7,10 +7,12 @@ publish = false [dev-dependencies] wasm-bindgen-test = "0.3.24" tracing-wasm = "0.2.1" +tracing = "0.1.34" console_error_panic_hook = "0.1.7" serde_json = "1" +futures-util = "0.3.28" # This crate is not a part of the workspace, because it # requires the "jsonrpsee web unstable-light-client" features to be enabled, which we don't # want enabled for workspace builds in general. -subxt = { path = "../../subxt", default-features = false, features = ["web", "jsonrpsee", "unstable-light-client"] } +subxt = { path = "../../subxt", default-features = false, features = ["web", "jsonrpsee", "unstable-light-client-wasm"] } From a8576acadbfa685128341639dc302a37c04883ec Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 13:14:32 +0300 Subject: [PATCH 08/36] Adjust feature flags Signed-off-by: Alexandru Vasile --- testing/test-runtime/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/test-runtime/Cargo.toml b/testing/test-runtime/Cargo.toml index 1638232bb5..07036e8c10 100644 --- a/testing/test-runtime/Cargo.toml +++ b/testing/test-runtime/Cargo.toml @@ -11,7 +11,7 @@ subxt = { workspace = true, features = ["native"] } substrate-runner = { workspace = true } impl-serde = { workspace = true } serde = { workspace = true } -tokio = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread"] } which = { workspace = true } jsonrpsee = { workspace = true, features = ["async-client", "client-ws-transport"] } hex = { workspace = true } From 4dec3b7ed233ae0de47424e1ca3f495aa892fd56 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 13:28:58 +0300 Subject: [PATCH 09/36] tests: Adjust wasm endpoint to accept ws for p2p Signed-off-by: Alexandru Vasile --- .github/workflows/rust.yml | 6 +++++- testing/wasm-tests/tests/wasm.rs | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8ecef7e212..80c0b61968 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -20,6 +20,8 @@ env: CARGO_TERM_COLOR: always # TODO: Currently pointing at latest substrate; is there a suitable binary we can pin to here? SUBSTRATE_URL: https://releases.parity.io/substrate/x86_64-debian:stretch/latest/substrate/substrate + # Increase wasm test timeout from 20 seconds (default) to 1 minute. + WASM_BINDGEN_TEST_TIMEOUT=60 jobs: build: @@ -259,7 +261,9 @@ jobs: - name: Run subxt WASM tests run: | - substrate --dev --tmp > /dev/null 2>&1 & + # `listen-addr` is used to configure p2p to accept websocket connections instead of TCP. + # `node-key` provides a deterministic p2p address. + substrate --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws > /dev/null 2>&1 & wasm-pack test --headless --firefox wasm-pack test --headless --chrome pkill substrate diff --git a/testing/wasm-tests/tests/wasm.rs b/testing/wasm-tests/tests/wasm.rs index 33f5891303..3847f676e5 100644 --- a/testing/wasm-tests/tests/wasm.rs +++ b/testing/wasm-tests/tests/wasm.rs @@ -41,12 +41,12 @@ async fn light_client_works() { let api: LightClient = LightClientBuilder::new() .bootnodes( - ["/ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp"] + ["/ip4/127.0.0.1/tcp/30333/ws/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp"] .into_iter(), ) .build_from_url("ws://127.0.0.1:9944") .await - .unwrap(); + .expect("Cannot construct light client"); tracing::info!("Subscribe to latest finalized blocks: "); From 2e660bb079dabe66f2a4eefc729cbdd7307ba97d Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 13:54:18 +0300 Subject: [PATCH 10/36] Adjust wasm socket Signed-off-by: Alexandru Vasile --- .../lightclient/platform/wasm_socket.rs | 93 ++++++++++--------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/subxt/src/client/lightclient/platform/wasm_socket.rs b/subxt/src/client/lightclient/platform/wasm_socket.rs index 0ac34d4e8b..661a377c13 100644 --- a/subxt/src/client/lightclient/platform/wasm_socket.rs +++ b/subxt/src/client/lightclient/platform/wasm_socket.rs @@ -5,7 +5,6 @@ use futures::{io, prelude::*}; use send_wrapper::SendWrapper; use wasm_bindgen::{prelude::*, JsCast}; -use web_sys::{MessageEvent, WebSocket}; use std::{ collections::VecDeque, @@ -21,14 +20,16 @@ pub enum Error { ConnectionError(String), } -/// Wasm websocket. +/// Websocket for WASM environments. +/// +/// This is a rust-based wrapper around browser's WebSocket API. pub struct WasmSocket { inner: Arc>, } /// The state of the [`WasmSocket`]. #[derive(PartialEq, Eq, Clone, Copy)] -pub enum ConnectionState { +enum ConnectionState { /// Initial state of the socket. Connecting, /// Socket is fully opened. @@ -40,29 +41,39 @@ pub enum ConnectionState { } struct InnerWasmSocket { + /// The state of the connection. state: ConnectionState, /// This implements `Send` and panics if the value is accessed /// or dropped from another thread. /// /// This is safe in wasm environments. - socket: SendWrapper, + socket: SendWrapper, + /// Data buffer for the socket. data: VecDeque, + /// Waker from `poll_read` / `poll_write`. waker: Option, + /// In memory callbacks to handle messages from the browser socket. callbacks: Option>, } /// Registered callbacks of the [`WasmSocket`]. -struct Callbacks { - open: Closure, - message: Closure, - error: Closure, - close: Closure, -} +/// +/// These need to be kept around until the socket is dropped. +type Callbacks = ( + Closure, + Closure, + Closure, + Closure, +); impl WasmSocket { - /// Constructs a new [`WasmSocket`]. + /// Establish a WebSocket connection. + /// + /// The error is a string representing the browser error. + /// Visit [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket#exceptions_thrown) + /// for more info. pub fn new(addr: &str) -> Result { - let socket = match WebSocket::new(addr) { + let socket = match web_sys::WebSocket::new(addr) { Ok(socket) => socket, Err(err) => return Err(Error::ConnectionError(format!("{:?}", err))), }; @@ -77,22 +88,22 @@ impl WasmSocket { callbacks: None, })); - let open = Closure::::new({ + let open_callback = Closure::::new({ let inner = inner.clone(); move || { let mut inner = inner.lock().expect("Mutex is poised; qed"); inner.state = ConnectionState::Opened; - if let Some(waker) = &inner.waker { - waker.wake_by_ref(); + if let Some(waker) = inner.waker.take() { + waker.wake(); } } }); - socket.set_onopen(Some(open.as_ref().unchecked_ref())); + socket.set_onopen(Some(open_callback.as_ref().unchecked_ref())); - let message = Closure::::new({ + let message_callback = Closure::::new({ let inner = inner.clone(); - move |event: MessageEvent| { + move |event: web_sys::MessageEvent| { let Ok(buffer) = event.data().dyn_into::() else { panic!("Unexpected data format {:?}", event.data()); }; @@ -101,56 +112,50 @@ impl WasmSocket { let bytes = js_sys::Uint8Array::new(&buffer).to_vec(); inner.data.extend(bytes.into_iter()); - if let Some(waker) = &inner.waker { - waker.wake_by_ref(); + if let Some(waker) = inner.waker.take() { + waker.wake(); } } }); - socket.set_onmessage(Some(message.as_ref().unchecked_ref())); + socket.set_onmessage(Some(message_callback.as_ref().unchecked_ref())); - let error = Closure::::new({ + let error_callback = Closure::::new({ let inner = inner.clone(); move |_| { // Callback does not provide useful information, signal it back to the stream. let mut inner = inner.lock().expect("Mutex is poised; qed"); inner.state = ConnectionState::Error; - if let Some(waker) = &inner.waker { - waker.wake_by_ref(); + if let Some(waker) = inner.waker.take() { + waker.wake(); } } }); - socket.set_onerror(Some(error.as_ref().unchecked_ref())); + socket.set_onerror(Some(error_callback.as_ref().unchecked_ref())); - let close = Closure::::new({ + let close_callback = Closure::::new({ let inner = inner.clone(); move |_| { let mut inner = inner.lock().expect("Mutex is poised; qed"); inner.state = ConnectionState::Closed; - if let Some(waker) = &inner.waker { - waker.wake_by_ref(); + if let Some(waker) = inner.waker.take() { + waker.wake(); } } }); - socket.set_onclose(Some(close.as_ref().unchecked_ref())); - - let callbacks = SendWrapper::new(Callbacks { - open, - message, - error, - close, - }); + socket.set_onclose(Some(close_callback.as_ref().unchecked_ref())); + + let callbacks = SendWrapper::new(( + open_callback, + message_callback, + error_callback, + close_callback, + )); inner.lock().expect("Mutex poised; qed").callbacks = Some(callbacks); Ok(Self { inner }) } - - /// The state of the [`WasmSocket`]. - pub fn state(&self) -> ConnectionState { - let inner = self.inner.lock().expect("Mutex is poised; qed"); - inner.state - } } impl AsyncRead for WasmSocket { @@ -175,7 +180,7 @@ impl AsyncRead for WasmSocket { let n = inner.data.len().min(buf.len()); for k in buf.iter_mut().take(n) { - *k = inner.data.pop_front().unwrap(); + *k = inner.data.pop_front().expect("Buffer non empty; qed"); } Poll::Ready(Ok(n)) } @@ -213,7 +218,7 @@ impl AsyncWrite for WasmSocket { } fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Pending + Poll::Ready(Ok(())) } } From f9b08344ee29c8a5a979fbdb62c0d2ed0fa0452c Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 14:05:19 +0300 Subject: [PATCH 11/36] Book mention of wasm Signed-off-by: Alexandru Vasile --- subxt/src/book/usage/light_client.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/subxt/src/book/usage/light_client.rs b/subxt/src/book/usage/light_client.rs index d5c642afbc..e5b51a0932 100644 --- a/subxt/src/book/usage/light_client.rs +++ b/subxt/src/book/usage/light_client.rs @@ -8,6 +8,7 @@ //! to the P2P network and behaving similarly to a full node. //! //! To enable this functionality, the unstable-light-client feature flag needs to be enabled. +//! To enable light client for WASM environments, also enable the web feature flag. //! //! To connect to a blockchain network, the Light Client requires a trusted sync state of the network, named "chain spec". //! This can be obtained by making a `sync_state_genSyncSpec` RPC call to a trusted node. From d23b398e9e986d8598105bccd5963adab7e31b9b Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 14:10:11 +0300 Subject: [PATCH 12/36] ci: Propagate env variable properly Signed-off-by: Alexandru Vasile --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 80c0b61968..9f7a0de611 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -21,7 +21,7 @@ env: # TODO: Currently pointing at latest substrate; is there a suitable binary we can pin to here? SUBSTRATE_URL: https://releases.parity.io/substrate/x86_64-debian:stretch/latest/substrate/substrate # Increase wasm test timeout from 20 seconds (default) to 1 minute. - WASM_BINDGEN_TEST_TIMEOUT=60 + WASM_BINDGEN_TEST_TIMEOUT: 60 jobs: build: From 03407cdb3c9667e91ce1b31d7beeda42c95b6efa Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 14:11:28 +0300 Subject: [PATCH 13/36] subxt: Revert to native feature flags Signed-off-by: Alexandru Vasile --- subxt/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index f35de2906f..c4a2be5f44 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -17,7 +17,7 @@ keywords = ["parity", "substrate", "blockchain"] [features] # For dev and documentation reasons we enable more features than are often desired. # it's recommended to use `--no-default-features` and then select what you need. -default = ["jsonrpsee", "web", "substrate-compat", "unstable-light-client-wasm"] +default = ["jsonrpsee", "native", "substrate-compat"] # Enable this for native (ie non web/wasm builds). # Exactly 1 of "web" and "native" is expected. From 540172f11dfed327fa0930a82af1033bb72d95c4 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 14:20:35 +0300 Subject: [PATCH 14/36] cli: Use tokio rt-multi-thread feature Signed-off-by: Alexandru Vasile --- cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/Cargo.toml b/cli/Cargo.toml index d3d54acc64..b27aa858f3 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -31,4 +31,4 @@ scale-info = { workspace = true } scale-value = { workspace = true } syn = { workspace = true } jsonrpsee = { workspace = true, features = ["async-client", "client-ws-transport", "http-client"] } -tokio = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread"] } From b25ce5ca83b566cd65783d36d284de3531b79ac0 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 14:24:02 +0300 Subject: [PATCH 15/36] subxt: Add tokio feature flags for native platform Signed-off-by: Alexandru Vasile --- subxt/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index c4a2be5f44..dd90009050 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -61,8 +61,9 @@ unstable-light-client = [ "tokio-stream", "tokio/sync", "tokio/rt", + "tokio/net", + "tokio-util/compat", "futures-util", - "tokio-util", ] unstable-light-client-wasm = [ From ad3362077fa2e91eed32119a24e4f60b675a7a7b Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 16:44:57 +0300 Subject: [PATCH 16/36] wasm: Use polkadot live for wasm testing Signed-off-by: Alexandru Vasile --- testing/wasm-tests/tests/wasm.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/wasm-tests/tests/wasm.rs b/testing/wasm-tests/tests/wasm.rs index 3847f676e5..e159c204f3 100644 --- a/testing/wasm-tests/tests/wasm.rs +++ b/testing/wasm-tests/tests/wasm.rs @@ -39,12 +39,12 @@ async fn light_client_works() { console_error_panic_hook::set_once(); tracing_wasm::set_as_global_default(); + // Use a polkadot trusted DNS. let api: LightClient = LightClientBuilder::new() .bootnodes( - ["/ip4/127.0.0.1/tcp/30333/ws/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp"] - .into_iter(), + ["/dns/polkadot-connect-0.parity.io/tcp/443/wss/p2p/12D3KooWEPmjoRpDSUuiTjvyNDd8fejZ9eNWH5bE965nyBMDrB4o"] ) - .build_from_url("ws://127.0.0.1:9944") + .build_from_url("wss://rpc.polkadot.io:443") .await .expect("Cannot construct light client"); From 8ba2e0fe6f6c4724be7c001e69327a6ac8fe0e87 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 16:46:02 +0300 Subject: [PATCH 17/36] wasm: Add support for DNS p2p addresses Signed-off-by: Alexandru Vasile --- subxt/src/client/lightclient/platform/wasm.rs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/subxt/src/client/lightclient/platform/wasm.rs b/subxt/src/client/lightclient/platform/wasm.rs index 0fd93ac910..0bef476249 100644 --- a/subxt/src/client/lightclient/platform/wasm.rs +++ b/subxt/src/client/lightclient/platform/wasm.rs @@ -71,10 +71,26 @@ pub async fn connect<'a>( // Ensure ahead of time that the multiaddress is supported. let addr = match (&proto1, &proto2, &proto3) { (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { - SocketAddr::new(IpAddr::V4((*ip).into()), *port) + let addr = SocketAddr::new(IpAddr::V4((*ip).into()), *port); + format!("ws://{}", addr.to_string()) } (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { - SocketAddr::new(IpAddr::V6((*ip).into()), *port) + let addr = SocketAddr::new(IpAddr::V6((*ip).into()), *port); + format!("ws://{}", addr.to_string()) + } + ( + ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), + ProtocolRef::Tcp(port), + Some(ProtocolRef::Ws), + ) => { + format!("ws://{}:{}", addr.to_string(), port) + } + ( + ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), + ProtocolRef::Tcp(port), + Some(ProtocolRef::Wss), + ) => { + format!("wss://{}:{}", addr.to_string(), port) } _ => { return Err(ConnectError { @@ -84,7 +100,6 @@ pub async fn connect<'a>( } }; - let addr = format!("ws://{}", addr.to_string()); tracing::debug!("Connecting to addr={addr}"); let socket = WasmSocket::new(addr.as_str()).map_err(|err| ConnectError { From 4452fc3ee92499413d3471d1f6cd7d3dd24a5b3f Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 18:50:27 +0300 Subject: [PATCH 18/36] wasm: Disable logs Signed-off-by: Alexandru Vasile --- testing/wasm-tests/tests/wasm.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/testing/wasm-tests/tests/wasm.rs b/testing/wasm-tests/tests/wasm.rs index e159c204f3..6a02efce54 100644 --- a/testing/wasm-tests/tests/wasm.rs +++ b/testing/wasm-tests/tests/wasm.rs @@ -23,6 +23,11 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); // ./polkadot --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws // ``` // +// Use the following to enable logs: +// ``` +// console_error_panic_hook::set_once(); +// tracing_wasm::set_as_global_default(); +// ``` #[wasm_bindgen_test] async fn wasm_ws_transport_works() { @@ -36,9 +41,6 @@ async fn wasm_ws_transport_works() { #[wasm_bindgen_test] async fn light_client_works() { - console_error_panic_hook::set_once(); - tracing_wasm::set_as_global_default(); - // Use a polkadot trusted DNS. let api: LightClient = LightClientBuilder::new() .bootnodes( From 1615313031954c854f54b968cb505ce14adaa363 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 18:50:54 +0300 Subject: [PATCH 19/36] wasm: Run wasm test for firefox driver Signed-off-by: Alexandru Vasile --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9f7a0de611..20823faf68 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -265,7 +265,7 @@ jobs: # `node-key` provides a deterministic p2p address. substrate --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws > /dev/null 2>&1 & wasm-pack test --headless --firefox - wasm-pack test --headless --chrome + # wasm-pack test --headless --chrome pkill substrate working-directory: testing/wasm-tests From 1e8c9493ca425e5a87dfcce4a01d3a0f11ced436 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 26 Jun 2023 19:08:41 +0300 Subject: [PATCH 20/36] wasm: Reenable chrome driver Signed-off-by: Alexandru Vasile --- .github/workflows/rust.yml | 2 +- testing/wasm-tests/Cargo.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 20823faf68..9f7a0de611 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -265,7 +265,7 @@ jobs: # `node-key` provides a deterministic p2p address. substrate --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws > /dev/null 2>&1 & wasm-pack test --headless --firefox - # wasm-pack test --headless --chrome + wasm-pack test --headless --chrome pkill substrate working-directory: testing/wasm-tests diff --git a/testing/wasm-tests/Cargo.lock b/testing/wasm-tests/Cargo.lock index 3cf136f916..666ca51daf 100644 --- a/testing/wasm-tests/Cargo.lock +++ b/testing/wasm-tests/Cargo.lock @@ -1872,9 +1872,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.97" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", From 3a6557395036398323d140be4f84ff7d65352a37 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 27 Jun 2023 13:49:11 +0300 Subject: [PATCH 21/36] Move lightclient RPC to dedicated crate for better feature flags and modularity Signed-off-by: Alexandru Vasile --- Cargo.lock | 26 ++ Cargo.toml | 1 + lightclient/Cargo.toml | 90 +++++ lightclient/src/background.rs | 437 ++++++++++++++++++++++++ lightclient/src/client.rs | 115 +++++++ lightclient/src/lib.rs | 46 +++ lightclient/src/platform/default.rs | 300 ++++++++++++++++ lightclient/src/platform/mod.rs | 13 + lightclient/src/platform/native.rs | 161 +++++++++ lightclient/src/platform/wasm.rs | 126 +++++++ lightclient/src/platform/wasm_socket.rs | 233 +++++++++++++ 11 files changed, 1548 insertions(+) create mode 100644 lightclient/Cargo.toml create mode 100644 lightclient/src/background.rs create mode 100644 lightclient/src/client.rs create mode 100644 lightclient/src/lib.rs create mode 100644 lightclient/src/platform/default.rs create mode 100644 lightclient/src/platform/mod.rs create mode 100644 lightclient/src/platform/native.rs create mode 100644 lightclient/src/platform/wasm.rs create mode 100644 lightclient/src/platform/wasm_socket.rs diff --git a/Cargo.lock b/Cargo.lock index 859c974860..cb618ef86d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4237,6 +4237,32 @@ dependencies = [ "tokio", ] +[[package]] +name = "subxt-lightclient" +version = "0.29.0" +dependencies = [ + "either", + "futures", + "futures-timer", + "futures-util", + "getrandom 0.2.10", + "instant", + "js-sys", + "send_wrapper 0.6.0", + "serde", + "serde_json", + "smoldot", + "smoldot-light", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "subxt-macro" version = "0.29.0" diff --git a/Cargo.toml b/Cargo.toml index d089c8b991..1f96c3bf9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "cli", "codegen", + "lightclient", "testing/substrate-runner", "testing/test-runtime", "testing/integration-tests", diff --git a/lightclient/Cargo.toml b/lightclient/Cargo.toml new file mode 100644 index 0000000000..53369a110c --- /dev/null +++ b/lightclient/Cargo.toml @@ -0,0 +1,90 @@ +[package] +name = "subxt-lightclient" +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +publish = true + +license.workspace = true +readme = "../README.md" +repository.workspace = true +documentation.workspace = true +homepage.workspace = true +description = "Light Client for chain interaction" +keywords = ["parity", "substrate", "blockchain"] + +[features] +# For dev and documentation reasons we enable more features than are often desired. +# it's recommended to use `--no-default-features` and then select what you need. +default = ["native"] + +# Enable this for native (ie non web/wasm builds). +# Exactly 1 of "web" and "native" is expected. +native = [ + "smoldot", + "smoldot-light/std", + "tokio-stream", + "tokio/sync", + "tokio/rt", + "tokio/net", + "tokio-util/compat", + "futures-util", + "either", +] + +# Enable this for web/wasm builds. +# Exactly 1 of "web" and "native" is expected. +web = [ + "getrandom/js", + + "smoldot", + "smoldot-light", + "tokio-stream", + "tokio/sync", + "futures-util", + # For the light-client platform. + "wasm-bindgen-futures", + "futures-timer/wasm-bindgen", + "instant/wasm-bindgen", + # For websocket. + "js-sys", + "send_wrapper", + "web-sys", + "wasm-bindgen", +] + +[dependencies] +futures = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true, features = ["raw_value"] } +thiserror = { workspace = true } +tracing = { workspace = true } + +# Light client support: +smoldot = { workspace = true, optional = true } +smoldot-light = { workspace = true, optional = true } +either = { workspace = true, optional = true } +tokio = { workspace = true, optional = true } +tokio-stream = { workspace = true, optional = true } +futures-util = { workspace = true, optional = true } +js-sys = { workspace = true, optional = true } +send_wrapper = { workspace = true, optional = true } +web-sys = { workspace = true, optional = true } +wasm-bindgen = { workspace = true, optional = true } +wasm-bindgen-futures = { workspace = true, optional = true } +futures-timer = { workspace = true, optional = true } +instant = { workspace = true, optional = true } +tokio-util = { workspace = true, optional = true } + +# Included if "web" feature is enabled, to enable its js feature. +getrandom = { workspace = true, optional = true } + +[profile.dev.package.smoldot-light] +opt-level = 2 +[profile.test.package.smoldot-light] +opt-level = 2 +[profile.dev.package.smoldot] +opt-level = 2 +[profile.test.package.smoldot] +opt-level = 2 diff --git a/lightclient/src/background.rs b/lightclient/src/background.rs new file mode 100644 index 0000000000..3f3d6351d7 --- /dev/null +++ b/lightclient/src/background.rs @@ -0,0 +1,437 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +use futures::stream::StreamExt; +use futures_util::future::{self, Either}; +use serde::Deserialize; +use serde_json::value::RawValue; +use std::{collections::HashMap, str::FromStr}; +use tokio::sync::{mpsc, oneshot}; + +use super::platform::default::SubxtPlatform as Platform; +use super::LightClientRpcError; +use smoldot_light::ChainId; + +const LOG_TARGET: &str = "light-client-background"; + +/// The response of an RPC method. +pub type MethodResponse = Result, LightClientRpcError>; + +/// Message protocol between the front-end client that submits the RPC requests +/// and the backend handler that produces responses from the chain. +/// +/// The light client uses a single object [`smoldot_light::JsonRpcResponses`] to +/// handle all requests and subscriptions from a chain. A background task is spawned +/// to multiplex the rpc responses and to provide them back to their rightful submitters. +#[derive(Debug)] +pub enum FromSubxt { + /// The RPC method request. + Request { + /// The method of the request. + method: String, + /// The parameters of the request. + params: String, + /// Channel used to send back the result. + sender: oneshot::Sender, + }, + /// The RPC subscription (pub/sub) request. + Subscription { + /// The method of the request. + method: String, + /// The parameters of the request. + params: String, + /// Channel used to send back the subscription ID if successful. + sub_id: oneshot::Sender, + /// Channel used to send back the notifcations. + sender: mpsc::UnboundedSender>, + }, +} + +/// Background task data. +pub struct BackgroundTask { + /// Smoldot light client implementation that leverages the exposed platform. + client: smoldot_light::Client, + /// The ID of the chain used to identify the chain protocol (ie. substrate). + /// + /// Note: A single chain is supported for a client. This aligns with the subxt's + /// vision of the Client. + chain_id: ChainId, + /// Unique ID for RPC calls. + request_id: usize, + /// Map the request ID of a RPC method to the frontend `Sender`. + requests: HashMap>, + /// Subscription calls first need to make a plain RPC method + /// request to obtain the subscription ID. + /// + /// The RPC method request is made in the background and the response should + /// not be sent back to the user. + /// Map the request ID of a RPC method to the frontend `Sender`. + id_to_subscription: HashMap< + usize, + ( + oneshot::Sender, + mpsc::UnboundedSender>, + ), + >, + /// Map the subscription ID to the frontend `Sender`. + subscriptions: HashMap>>, +} + +impl BackgroundTask { + /// Constructs a new [`BackgroundTask`]. + pub fn new(client: smoldot_light::Client, chain_id: ChainId) -> BackgroundTask { + BackgroundTask { + client, + chain_id, + request_id: 1, + requests: Default::default(), + id_to_subscription: Default::default(), + subscriptions: Default::default(), + } + } + + /// Fetch and increment the request ID. + fn next_id(&mut self) -> usize { + let next = self.request_id; + self.request_id = self.request_id.wrapping_add(1); + next + } + + /// Handle the registration messages received from the user. + async fn handle_requests(&mut self, message: FromSubxt) { + match message { + FromSubxt::Request { + method, + params, + sender, + } => { + let id = self.next_id(); + let request = format!( + r#"{{"jsonrpc":"2.0","id":"{}", "method":"{}","params":{}}}"#, + id, method, params + ); + + self.requests.insert(id, sender); + + let result = self.client.json_rpc_request(request, self.chain_id); + if let Err(err) = result { + tracing::warn!( + target: LOG_TARGET, + "Cannot send RPC request to lightclient {:?}", + err.to_string() + ); + let sender = self + .requests + .remove(&id) + .expect("Channel is inserted above; qed"); + + // Send the error back to frontend. + if sender + .send(Err(LightClientRpcError::Request(err.to_string()))) + .is_err() + { + tracing::warn!( + target: LOG_TARGET, + "Cannot send RPC request error to id={id}", + ); + } + } + } + FromSubxt::Subscription { + method, + params, + sub_id, + sender, + } => { + // For subscriptions we need to make a plain RPC request to the subscription method. + // The server will return as a result the subscription ID. + let id = self.next_id(); + let request = format!( + r#"{{"jsonrpc":"2.0","id":"{}", "method":"{}","params":{}}}"#, + id, method, params + ); + + self.id_to_subscription.insert(id, (sub_id, sender)); + + let result = self.client.json_rpc_request(request, self.chain_id); + if let Err(err) = result { + tracing::warn!( + target: LOG_TARGET, + "Cannot send RPC request to lightclient {:?}", + err.to_string() + ); + let (sub_id, _) = self + .id_to_subscription + .remove(&id) + .expect("Channels are inserted above; qed"); + + // Send the error back to frontend. + if sub_id + .send(Err(LightClientRpcError::Request(err.to_string()))) + .is_err() + { + tracing::warn!( + target: LOG_TARGET, + "Cannot send RPC request error to id={id}", + ); + } + } + } + }; + } + + /// Parse the response received from the light client and sent it to the appropriate user. + fn handle_rpc_response(&mut self, response: String) { + match RpcResponse::from_str(&response) { + Ok(RpcResponse::Error { id, error }) => { + let Ok(id) = id.parse::() else { + tracing::warn!(target: LOG_TARGET, "Cannot send error. Id={id} is not a valid number"); + return + }; + + if let Some(sender) = self.requests.remove(&id) { + if sender + .send(Err(LightClientRpcError::Request(error.to_string()))) + .is_err() + { + tracing::warn!( + target: LOG_TARGET, + "Cannot send method response to id={id}", + ); + } + } else if let Some((sub_id_sender, _)) = self.id_to_subscription.remove(&id) { + if sub_id_sender + .send(Err(LightClientRpcError::Request(error.to_string()))) + .is_err() + { + tracing::warn!( + target: LOG_TARGET, + "Cannot send method response to id {:?}", + id + ); + } + } + } + Ok(RpcResponse::Method { id, result }) => { + let Ok(id) = id.parse::() else { + tracing::warn!(target: LOG_TARGET, "Cannot send response. Id={id} is not a valid number"); + return + }; + + // Send the response back. + if let Some(sender) = self.requests.remove(&id) { + if sender.send(Ok(result)).is_err() { + tracing::warn!( + target: LOG_TARGET, + "Cannot send method response to id={id}", + ); + } + } else if let Some((sub_id_sender, sender)) = self.id_to_subscription.remove(&id) { + let Ok(sub_id) = result + .get() + .trim_start_matches('"') + .trim_end_matches('"') + .parse::() else { + tracing::warn!( + target: LOG_TARGET, + "Subscription id={result} is not a valid number", + ); + return; + }; + + tracing::trace!(target: LOG_TARGET, "Received subscription id={sub_id}"); + + if sub_id_sender.send(Ok(result)).is_err() { + tracing::warn!( + target: LOG_TARGET, + "Cannot send method response to id={id}", + ); + } else { + // Track this subscription ID if send is successful. + self.subscriptions.insert(sub_id, sender); + } + } + } + Ok(RpcResponse::Subscription { method, id, result }) => { + let Ok(id) = id.parse::() else { + tracing::warn!(target: LOG_TARGET, "Cannot send subscription. Id={id} is not a valid number"); + return + }; + + if let Some(sender) = self.subscriptions.get_mut(&id) { + // Send the current notification response. + if sender.send(result).is_err() { + tracing::warn!( + target: LOG_TARGET, + "Cannot send notification to subscription id={id} method={method}", + ); + + // Remove the sender if the subscription dropped the receiver. + self.subscriptions.remove(&id); + } + } + } + Err(err) => { + tracing::warn!(target: LOG_TARGET, "cannot decode RPC response {:?}", err); + } + } + } + + /// Perform the main background task: + /// - receiving requests from subxt RPC method / subscriptions + /// - provides the results from the light client back to users. + pub async fn start_task( + &mut self, + from_subxt: mpsc::UnboundedReceiver, + from_node: smoldot_light::JsonRpcResponses, + ) { + let from_subxt_event = tokio_stream::wrappers::UnboundedReceiverStream::new(from_subxt); + let from_node_event = futures_util::stream::unfold(from_node, |mut from_node| async { + from_node.next().await.map(|result| (result, from_node)) + }); + + tokio::pin!(from_subxt_event, from_node_event); + + let mut from_subxt_event_fut = from_subxt_event.next(); + let mut from_node_event_fut = from_node_event.next(); + + loop { + match future::select(from_subxt_event_fut, from_node_event_fut).await { + // Message received from subxt. + Either::Left((subxt_message, previous_fut)) => { + let Some(message) = subxt_message else { + tracing::trace!(target: LOG_TARGET, "Subxt channel closed"); + break; + }; + tracing::trace!( + target: LOG_TARGET, + "Received register message {:?}", + message + ); + + self.handle_requests(message).await; + + from_subxt_event_fut = from_subxt_event.next(); + from_node_event_fut = previous_fut; + } + // Message received from rpc handler: lightclient response. + Either::Right((node_message, previous_fut)) => { + // Smoldot returns `None` if the chain has been removed (which subxt does not remove). + let Some(response) = node_message else { + tracing::trace!(target: LOG_TARGET, "Smoldot RPC responses channel closed"); + break; + }; + tracing::trace!( + target: LOG_TARGET, + "Received smoldot RPC result {:?}", + response + ); + + self.handle_rpc_response(response); + + // Advance backend, save frontend. + from_subxt_event_fut = previous_fut; + from_node_event_fut = from_node_event.next(); + } + } + } + + tracing::trace!(target: LOG_TARGET, "Task closed"); + } +} + +/// The RPC response from the light-client. +/// This can either be a response of a method, or a notification from a subscription. +#[derive(Debug, Clone)] +enum RpcResponse { + Method { + /// Response ID. + id: String, + /// The result of the method call. + result: Box, + }, + Subscription { + /// RPC method that generated the notification. + method: String, + /// Subscription ID. + id: String, + /// Result. + result: Box, + }, + Error { + /// Response ID. + id: String, + /// Error. + error: Box, + }, +} + +impl std::str::FromStr for RpcResponse { + type Err = serde_json::Error; + + fn from_str(response: &str) -> Result { + // Helper structures to deserialize from raw RPC strings. + #[derive(Deserialize, Debug)] + struct Response { + /// JSON-RPC version. + #[allow(unused)] + jsonrpc: String, + /// Result. + result: Box, + /// Request ID + id: String, + } + #[derive(Deserialize)] + struct NotificationParams { + /// The ID of the subscription. + subscription: String, + /// Result. + result: Box, + } + #[derive(Deserialize)] + struct ResponseNotification { + /// JSON-RPC version. + #[allow(unused)] + jsonrpc: String, + /// RPC method that generated the notification. + method: String, + /// Result. + params: NotificationParams, + } + #[derive(Deserialize)] + struct ErrorResponse { + /// JSON-RPC version. + #[allow(unused)] + jsonrpc: String, + /// Request ID. + id: String, + /// Error. + error: Box, + } + + // Check if the response can be mapped as an RPC method response. + let result: Result = serde_json::from_str(response); + if let Ok(response) = result { + return Ok(RpcResponse::Method { + id: response.id, + result: response.result, + }); + } + + let result: Result = serde_json::from_str(response); + if let Ok(notification) = result { + return Ok(RpcResponse::Subscription { + id: notification.params.subscription, + method: notification.method, + result: notification.params.result, + }); + } + + let error: ErrorResponse = serde_json::from_str(response)?; + Ok(RpcResponse::Error { + id: error.id, + error: error.error, + }) + } +} diff --git a/lightclient/src/client.rs b/lightclient/src/client.rs new file mode 100644 index 0000000000..c25d475221 --- /dev/null +++ b/lightclient/src/client.rs @@ -0,0 +1,115 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +use super::{ + background::{BackgroundTask, FromSubxt, MethodResponse}, + LightClientRpcError, +}; +use serde_json::value::RawValue; +use smoldot_light::ChainId; +use tokio::sync::{mpsc, mpsc::error::SendError, oneshot}; + +use super::platform::default::SubxtPlatform as Platform; + +pub const LOG_TARGET: &str = "light-client"; + +/// The light-client RPC implementation that is used to connect with the chain. +#[derive(Clone)] +pub struct LightClientRpc { + /// Communicate with the backend task that multiplexes the responses + /// back to the frontend. + to_backend: mpsc::UnboundedSender, +} + +impl LightClientRpc { + /// Constructs a new [`LightClientRpc`], providing the chain specification. + /// + /// The chain specification can be downloaded from a trusted network via + /// the `sync_state_genSyncSpec` RPC method. This parameter expects the + /// chain spec in text format (ie not in hex-encoded scale-encoded as RPC methods + /// will provide). + /// + /// ## Panics + /// + /// Panics if being called outside of `tokio` runtime context. + pub fn new( + config: smoldot_light::AddChainConfig<'_, (), impl Iterator>, + ) -> Result { + tracing::trace!(target: LOG_TARGET, "Create light client"); + + let mut client = smoldot_light::Client::new(Platform::new()); + + let smoldot_light::AddChainSuccess { + chain_id, + json_rpc_responses, + } = client + .add_chain(config) + .map_err(|err| LightClientRpcError::AddChainError(err.to_string()))?; + + let (to_backend, backend) = mpsc::unbounded_channel(); + + // `json_rpc_responses` can only be `None` if we had passed `json_rpc: Disabled`. + let rpc_responses = json_rpc_responses.expect("Light client RPC configured; qed"); + + let future = async move { + let mut task = BackgroundTask::new(client, chain_id); + task.start_task(backend, rpc_responses).await; + }; + + #[cfg(feature = "native")] + tokio::spawn(future); + #[cfg(feature = "web")] + wasm_bindgen_futures::spawn_local(future); + + Ok(LightClientRpc { to_backend }) + } + + /// Submits an RPC method request to the light-client. + /// + /// This method sends a request to the light-client to execute an RPC method with the provided parameters. + /// The parameters are parsed into a valid JSON object in the background. + pub fn method_request( + &self, + method: String, + params: String, + ) -> Result, SendError> { + let (sender, receiver) = oneshot::channel(); + + self.to_backend.send(FromSubxt::Request { + method, + params, + sender, + })?; + + Ok(receiver) + } + + /// Makes an RPC subscription call to the light-client. + /// + /// This method sends a request to the light-client to establish an RPC subscription with the provided parameters. + /// The parameters are parsed into a valid JSON object in the background. + pub fn subscription_request( + &self, + method: String, + params: String, + ) -> Result< + ( + oneshot::Receiver, + mpsc::UnboundedReceiver>, + ), + SendError, + > { + let (sub_id, sub_id_rx) = oneshot::channel(); + let (sender, receiver) = mpsc::unbounded_channel(); + + self.to_backend.send(FromSubxt::Subscription { + method, + params, + sub_id, + sender, + })?; + + Ok((sub_id_rx, receiver)) + } +} diff --git a/lightclient/src/lib.rs b/lightclient/src/lib.rs new file mode 100644 index 0000000000..1d72ae1192 --- /dev/null +++ b/lightclient/src/lib.rs @@ -0,0 +1,46 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +//! Low level light client implementation for RPC method and +//! subscriptions requests. +//! +//! The client implementation supports both native and wasm +//! environments. +//! +//! This leverages the smoldot crate to connect to the chain. + +#![deny( + missing_docs, + unused_crate_dependencies, + unused_extern_crates, + clippy::all +)] + +#[cfg(any( + all(feature = "web", feature = "native"), + not(any(feature = "web", feature = "native")) +))] +compile_error!("subxt: exactly one of the 'web' and 'native' features should be used."); + +mod background; +mod platform; +mod client; + +// Used to enable the js feature for wasm. +#[cfg(feature = "web")] +#[allow(unused_imports)] +pub use getrandom as _; + +pub use client::LightClientRpc; + +/// Light client error. +#[derive(Debug, thiserror::Error)] +pub enum LightClientRpcError { + /// Error encountered while adding the chain to the light-client. + #[error("Failed to add the chain to the light client: {0}.")] + AddChainError(String), + /// Error originated while trying to submit a RPC request. + #[error("RPC request cannot be sent: {0}.")] + Request(String), +} diff --git a/lightclient/src/platform/default.rs b/lightclient/src/platform/default.rs new file mode 100644 index 0000000000..da9db50763 --- /dev/null +++ b/lightclient/src/platform/default.rs @@ -0,0 +1,300 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +use core::time::Duration; +use futures::{prelude::*, task::Poll}; + +use smoldot::libp2p::multiaddr::Multiaddr; +use smoldot_light::platform::{ + ConnectError, PlatformConnection, PlatformRef, PlatformSubstreamDirection, ReadBuffer, +}; +use std::{io::IoSlice, pin::Pin}; + +#[cfg(feature = "native")] +use super::native as platform_impl; +#[cfg(feature = "web")] +use super::wasm as platform_impl; + +use platform_impl::{StreamReadBuffer, StreamWriteBuffer}; + +/// Subxt plaform implementation for native and wasm. +/// +/// This implementation is a conversion of the implementation from the smoldot: +/// https://github.com/smol-dot/smoldot/blob/f49ce4ea6a325c444ab6ad37d3ab5558edf0d541/light-base/src/platform/default.rs#L52. +#[derive(Clone)] +pub struct SubxtPlatform {} + +impl SubxtPlatform { + pub fn new() -> Self { + SubxtPlatform {} + } +} + +impl PlatformRef for SubxtPlatform { + type Delay = platform_impl::Delay; + type Yield = future::Ready<()>; + type Instant = platform_impl::Instant; + type Connection = std::convert::Infallible; + type Stream = platform_impl::Stream; + type ConnectFuture = future::BoxFuture< + 'static, + Result, ConnectError>, + >; + type StreamUpdateFuture<'a> = future::BoxFuture<'a, ()>; + type NextSubstreamFuture<'a> = + future::Pending>; + + fn now_from_unix_epoch(&self) -> Duration { + platform_impl::now_from_unix_epoch() + } + + fn now(&self) -> Self::Instant { + platform_impl::now() + } + + fn sleep(&self, duration: Duration) -> Self::Delay { + platform_impl::sleep(duration) + } + + fn sleep_until(&self, when: Self::Instant) -> Self::Delay { + self.sleep(when.saturating_duration_since(self.now())) + } + + fn yield_after_cpu_intensive(&self) -> Self::Yield { + // No-op. + future::ready(()) + } + + fn connect(&self, multiaddr: &str) -> Self::ConnectFuture { + // We simply copy the address to own it. We could be more zero-cost here, but doing so + // would considerably complicate the implementation. + let multiaddr = multiaddr.to_owned(); + + tracing::debug!("Connecting to multiaddress={:?}", multiaddr); + + Box::pin(async move { + let addr = multiaddr.parse::().map_err(|_| ConnectError { + is_bad_addr: true, + message: "Failed to parse address".to_string(), + })?; + + let mut iter = addr.iter().fuse(); + let proto1 = iter.next().ok_or(ConnectError { + is_bad_addr: true, + message: "Unknown protocols combination".to_string(), + })?; + let proto2 = iter.next().ok_or(ConnectError { + is_bad_addr: true, + message: "Unknown protocols combination".to_string(), + })?; + let proto3 = iter.next(); + + if iter.next().is_some() { + return Err(ConnectError { + is_bad_addr: true, + message: "Unknown protocols combination".to_string(), + }); + } + + platform_impl::connect(proto1, proto2, proto3).await + }) + } + + fn open_out_substream(&self, c: &mut Self::Connection) { + // This function can only be called with so-called "multi-stream" connections. We never + // open such connection. + match *c {} + } + + fn next_substream<'a>(&self, c: &'a mut Self::Connection) -> Self::NextSubstreamFuture<'a> { + // This function can only be called with so-called "multi-stream" connections. We never + // open such connection. + match *c {} + } + + fn update_stream<'a>(&self, stream: &'a mut Self::Stream) -> Self::StreamUpdateFuture<'a> { + Box::pin(future::poll_fn(|cx| { + let Some((read_buffer, write_buffer)) = stream.buffers.as_mut() else { return Poll::Pending }; + + // Whether the future returned by `update_stream` should return `Ready` or `Pending`. + let mut update_stream_future_ready = false; + + if let StreamReadBuffer::Open { + buffer: ref mut buf, + ref mut cursor, + } = read_buffer + { + // When reading data from the socket, `poll_read` might return "EOF". In that + // situation, we transition to the `Closed` state, which would discard the data + // currently in the buffer. For this reason, we only try to read if there is no + // data left in the buffer. + if cursor.start == cursor.end { + if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_read(cx, buf) { + update_stream_future_ready = true; + match result { + Err(_) => { + // End the stream. + stream.buffers = None; + return Poll::Ready(()); + } + Ok(0) => { + // EOF. + *read_buffer = StreamReadBuffer::Closed; + } + Ok(bytes) => { + *cursor = 0..bytes; + } + } + } + } + } + + if let StreamWriteBuffer::Open { + buffer: ref mut buf, + must_flush, + must_close, + } = write_buffer + { + while !buf.is_empty() { + let write_queue_slices = buf.as_slices(); + if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_write_vectored( + cx, + &[ + IoSlice::new(write_queue_slices.0), + IoSlice::new(write_queue_slices.1), + ], + ) { + if !*must_close { + // In the situation where the API user wants to close the writing + // side, simply sending the buffered data isn't enough to justify + // making the future ready. + update_stream_future_ready = true; + } + + match result { + Err(_) => { + // End the stream. + stream.buffers = None; + return Poll::Ready(()); + } + Ok(bytes) => { + *must_flush = true; + for _ in 0..bytes { + buf.pop_front(); + } + } + } + } else { + break; + } + } + + if buf.is_empty() && *must_close { + if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_close(cx) { + update_stream_future_ready = true; + match result { + Err(_) => { + // End the stream. + stream.buffers = None; + return Poll::Ready(()); + } + Ok(()) => { + *write_buffer = StreamWriteBuffer::Closed; + } + } + } + } else if *must_flush { + if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_flush(cx) { + update_stream_future_ready = true; + match result { + Err(_) => { + // End the stream. + stream.buffers = None; + return Poll::Ready(()); + } + Ok(()) => { + *must_flush = false; + } + } + } + } + } + + if update_stream_future_ready { + Poll::Ready(()) + } else { + Poll::Pending + } + })) + } + + fn read_buffer<'a>(&self, stream: &'a mut Self::Stream) -> ReadBuffer<'a> { + match stream.buffers.as_ref().map(|(r, _)| r) { + None => ReadBuffer::Reset, + Some(StreamReadBuffer::Closed) => ReadBuffer::Closed, + Some(StreamReadBuffer::Open { buffer, cursor }) => { + ReadBuffer::Open(&buffer[cursor.clone()]) + } + } + } + + fn advance_read_cursor(&self, stream: &mut Self::Stream, extra_bytes: usize) { + let Some(StreamReadBuffer::Open { ref mut cursor, .. }) = + stream.buffers.as_mut().map(|(r, _)| r) + else { + assert_eq!(extra_bytes, 0); + return + }; + + assert!(cursor.start + extra_bytes <= cursor.end); + cursor.start += extra_bytes; + } + + fn writable_bytes(&self, stream: &mut Self::Stream) -> usize { + let Some(StreamWriteBuffer::Open { ref mut buffer, must_close: false, ..}) = + stream.buffers.as_mut().map(|(_, w)| w) else { return 0 }; + buffer.capacity() - buffer.len() + } + + fn send(&self, stream: &mut Self::Stream, data: &[u8]) { + debug_assert!(!data.is_empty()); + + // Because `writable_bytes` returns 0 if the writing side is closed, and because `data` + // must always have a size inferior or equal to `writable_bytes`, we know for sure that + // the writing side isn't closed. + let Some(StreamWriteBuffer::Open { ref mut buffer, .. } )= + stream.buffers.as_mut().map(|(_, w)| w) else { panic!() }; + buffer.reserve(data.len()); + buffer.extend(data.iter().copied()); + } + + fn close_send(&self, stream: &mut Self::Stream) { + // It is not illegal to call this on an already-reset stream. + let Some((_, write_buffer)) = stream.buffers.as_mut() else { return }; + + match write_buffer { + StreamWriteBuffer::Open { + must_close: must_close @ false, + .. + } => *must_close = true, + _ => { + // However, it is illegal to call this on a stream that was already close + // attempted. + panic!() + } + } + } + + fn spawn_task(&self, _: std::borrow::Cow, task: future::BoxFuture<'static, ()>) { + platform_impl::spawn(task); + } + + fn client_name(&self) -> std::borrow::Cow { + "subxt-light-client".into() + } + + fn client_version(&self) -> std::borrow::Cow { + env!("CARGO_PKG_VERSION").into() + } +} diff --git a/lightclient/src/platform/mod.rs b/lightclient/src/platform/mod.rs new file mode 100644 index 0000000000..133fc8e554 --- /dev/null +++ b/lightclient/src/platform/mod.rs @@ -0,0 +1,13 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +pub mod default; + +#[cfg(feature = "native")] +mod native; + +#[cfg(feature = "web")] +mod wasm; +#[cfg(feature = "web")] +mod wasm_socket; diff --git a/lightclient/src/platform/native.rs b/lightclient/src/platform/native.rs new file mode 100644 index 0000000000..64006f026e --- /dev/null +++ b/lightclient/src/platform/native.rs @@ -0,0 +1,161 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +//! Native implementation for the light client's platform using +//! `tokio::net::TcpStream` for connections. + +use core::time::Duration; +use futures_util::{future, FutureExt}; +use smoldot::libp2p::{multiaddr::ProtocolRef, websocket}; +use smoldot_light::platform::{ConnectError, PlatformConnection}; +use std::{ + collections::VecDeque, + net::{IpAddr, SocketAddr}, +}; +use tokio::net::TcpStream; +use tokio_util::compat::{Compat, TokioAsyncReadCompatExt}; + +pub fn spawn(task: future::BoxFuture<'static, ()>) { + tokio::spawn(task); +} + +pub fn now_from_unix_epoch() -> Duration { + // Intentionally panic if the time is configured earlier than the UNIX EPOCH. + std::time::UNIX_EPOCH.elapsed().unwrap_or_else(|_| { + panic!("Invalid systime cannot be configured earlier than `UNIX_EPOCH`") + }) +} + +pub type Instant = std::time::Instant; + +pub fn now() -> Instant { + Instant::now() +} + +pub type Delay = future::BoxFuture<'static, ()>; + +pub fn sleep(duration: Duration) -> Delay { + tokio::time::sleep(duration).boxed() +} + +pub type CompatTcpStream = Compat; +pub type Socket = future::Either>; + +pub struct Stream { + pub socket: Socket, + /// Read and write buffers of the connection, or `None` if the socket has been reset. + pub buffers: Option<(StreamReadBuffer, StreamWriteBuffer)>, +} + +pub enum StreamReadBuffer { + Open { + buffer: Vec, + cursor: std::ops::Range, + }, + Closed, +} + +pub enum StreamWriteBuffer { + Open { + buffer: VecDeque, + must_flush: bool, + must_close: bool, + }, + Closed, +} + +pub async fn connect<'a>( + proto1: ProtocolRef<'a>, + proto2: ProtocolRef<'a>, + proto3: Option>, +) -> Result, ConnectError> { + // Ensure ahead of time that the multiaddress is supported. + let (addr, host_if_websocket) = match (&proto1, &proto2, &proto3) { + (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), None) => ( + either::Left(SocketAddr::new(IpAddr::V4((*ip).into()), *port)), + None, + ), + (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), None) => ( + either::Left(SocketAddr::new(IpAddr::V6((*ip).into()), *port)), + None, + ), + (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { + let addr = SocketAddr::new(IpAddr::V4((*ip).into()), *port); + (either::Left(addr), Some(addr.to_string())) + } + (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { + let addr = SocketAddr::new(IpAddr::V6((*ip).into()), *port); + (either::Left(addr), Some(addr.to_string())) + } + ( + ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), + ProtocolRef::Tcp(port), + None, + ) => (either::Right((addr.to_string(), *port)), None), + ( + ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), + ProtocolRef::Tcp(port), + Some(ProtocolRef::Ws), + ) => ( + either::Right((addr.to_string(), *port)), + Some(format!("{}:{}", addr, *port)), + ), + _ => { + return Err(ConnectError { + is_bad_addr: true, + message: "Unknown protocols combination".to_string(), + }) + } + }; + + tracing::debug!("Connecting to addr={addr:?}"); + + let tcp_socket = match addr { + either::Left(socket_addr) => tokio::net::TcpStream::connect(socket_addr).await, + either::Right((dns, port)) => tokio::net::TcpStream::connect((&dns[..], port)).await, + }; + + if let Ok(tcp_socket) = &tcp_socket { + let _ = tcp_socket.set_nodelay(true); + } + + let socket: Socket = match (tcp_socket, host_if_websocket) { + (Ok(tcp_socket), Some(host)) => future::Either::Right( + websocket::websocket_client_handshake(websocket::Config { + tcp_socket: tcp_socket.compat(), + host: &host, + url: "/", + }) + .await + .map_err(|err| ConnectError { + message: format!("Failed to negotiate WebSocket: {err}"), + is_bad_addr: false, + })?, + ), + (Ok(tcp_socket), None) => future::Either::Left(tcp_socket.compat()), + (Err(err), _) => { + return Err(ConnectError { + is_bad_addr: false, + message: format!("Failed to reach peer: {err}"), + }) + } + }; + + Ok(PlatformConnection::SingleStreamMultistreamSelectNoiseYamux( + Stream { + socket, + buffers: Some(( + StreamReadBuffer::Open { + buffer: vec![0; 16384], + cursor: 0..0, + }, + StreamWriteBuffer::Open { + buffer: VecDeque::with_capacity(16384), + must_close: false, + must_flush: false, + }, + )), + }, + )) +} diff --git a/lightclient/src/platform/wasm.rs b/lightclient/src/platform/wasm.rs new file mode 100644 index 0000000000..0bef476249 --- /dev/null +++ b/lightclient/src/platform/wasm.rs @@ -0,0 +1,126 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +//! Wasm implementation for the light client's platform using +//! custom websockets. + +use core::time::Duration; +use futures_util::{future, FutureExt}; +use smoldot::libp2p::multiaddr::ProtocolRef; +use smoldot_light::platform::{ConnectError, PlatformConnection}; +use std::{ + collections::VecDeque, + net::{IpAddr, SocketAddr}, +}; + +use super::wasm_socket::WasmSocket; + +pub fn spawn(task: future::BoxFuture<'static, ()>) { + wasm_bindgen_futures::spawn_local(task); +} + +pub fn now_from_unix_epoch() -> Duration { + instant::SystemTime::now() + .duration_since(instant::SystemTime::UNIX_EPOCH) + .unwrap_or_else(|_| { + panic!("Invalid systime cannot be configured earlier than `UNIX_EPOCH`") + }) +} + +pub type Instant = instant::Instant; + +pub fn now() -> Instant { + instant::Instant::now() +} + +pub type Delay = future::BoxFuture<'static, ()>; + +pub fn sleep(duration: Duration) -> Delay { + futures_timer::Delay::new(duration).boxed() +} + +pub struct Stream { + pub socket: WasmSocket, + /// Read and write buffers of the connection, or `None` if the socket has been reset. + pub buffers: Option<(StreamReadBuffer, StreamWriteBuffer)>, +} + +pub enum StreamReadBuffer { + Open { + buffer: Vec, + cursor: std::ops::Range, + }, + Closed, +} + +pub enum StreamWriteBuffer { + Open { + buffer: VecDeque, + must_flush: bool, + must_close: bool, + }, + Closed, +} + +pub async fn connect<'a>( + proto1: ProtocolRef<'a>, + proto2: ProtocolRef<'a>, + proto3: Option>, +) -> Result, ConnectError> { + // Ensure ahead of time that the multiaddress is supported. + let addr = match (&proto1, &proto2, &proto3) { + (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { + let addr = SocketAddr::new(IpAddr::V4((*ip).into()), *port); + format!("ws://{}", addr.to_string()) + } + (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { + let addr = SocketAddr::new(IpAddr::V6((*ip).into()), *port); + format!("ws://{}", addr.to_string()) + } + ( + ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), + ProtocolRef::Tcp(port), + Some(ProtocolRef::Ws), + ) => { + format!("ws://{}:{}", addr.to_string(), port) + } + ( + ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), + ProtocolRef::Tcp(port), + Some(ProtocolRef::Wss), + ) => { + format!("wss://{}:{}", addr.to_string(), port) + } + _ => { + return Err(ConnectError { + is_bad_addr: true, + message: "Unknown protocols combination".to_string(), + }) + } + }; + + tracing::debug!("Connecting to addr={addr}"); + + let socket = WasmSocket::new(addr.as_str()).map_err(|err| ConnectError { + is_bad_addr: false, + message: format!("Failed to reach peer: {err}"), + })?; + + Ok(PlatformConnection::SingleStreamMultistreamSelectNoiseYamux( + Stream { + socket, + buffers: Some(( + StreamReadBuffer::Open { + buffer: vec![0; 16384], + cursor: 0..0, + }, + StreamWriteBuffer::Open { + buffer: VecDeque::with_capacity(16384), + must_close: false, + must_flush: false, + }, + )), + }, + )) +} diff --git a/lightclient/src/platform/wasm_socket.rs b/lightclient/src/platform/wasm_socket.rs new file mode 100644 index 0000000000..661a377c13 --- /dev/null +++ b/lightclient/src/platform/wasm_socket.rs @@ -0,0 +1,233 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +use futures::{io, prelude::*}; +use send_wrapper::SendWrapper; +use wasm_bindgen::{prelude::*, JsCast}; + +use std::{ + collections::VecDeque, + pin::Pin, + sync::{Arc, Mutex}, + task::Poll, + task::{Context, Waker}, +}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Failed to connect {0}")] + ConnectionError(String), +} + +/// Websocket for WASM environments. +/// +/// This is a rust-based wrapper around browser's WebSocket API. +pub struct WasmSocket { + inner: Arc>, +} + +/// The state of the [`WasmSocket`]. +#[derive(PartialEq, Eq, Clone, Copy)] +enum ConnectionState { + /// Initial state of the socket. + Connecting, + /// Socket is fully opened. + Opened, + /// Socket is closed. + Closed, + /// Error reported by callbacks. + Error, +} + +struct InnerWasmSocket { + /// The state of the connection. + state: ConnectionState, + /// This implements `Send` and panics if the value is accessed + /// or dropped from another thread. + /// + /// This is safe in wasm environments. + socket: SendWrapper, + /// Data buffer for the socket. + data: VecDeque, + /// Waker from `poll_read` / `poll_write`. + waker: Option, + /// In memory callbacks to handle messages from the browser socket. + callbacks: Option>, +} + +/// Registered callbacks of the [`WasmSocket`]. +/// +/// These need to be kept around until the socket is dropped. +type Callbacks = ( + Closure, + Closure, + Closure, + Closure, +); + +impl WasmSocket { + /// Establish a WebSocket connection. + /// + /// The error is a string representing the browser error. + /// Visit [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket#exceptions_thrown) + /// for more info. + pub fn new(addr: &str) -> Result { + let socket = match web_sys::WebSocket::new(addr) { + Ok(socket) => socket, + Err(err) => return Err(Error::ConnectionError(format!("{:?}", err))), + }; + + socket.set_binary_type(web_sys::BinaryType::Arraybuffer); + + let inner = Arc::new(Mutex::new(InnerWasmSocket { + state: ConnectionState::Connecting, + socket: SendWrapper::new(socket.clone()), + data: VecDeque::with_capacity(16384), + waker: None, + callbacks: None, + })); + + let open_callback = Closure::::new({ + let inner = inner.clone(); + move || { + let mut inner = inner.lock().expect("Mutex is poised; qed"); + inner.state = ConnectionState::Opened; + + if let Some(waker) = inner.waker.take() { + waker.wake(); + } + } + }); + socket.set_onopen(Some(open_callback.as_ref().unchecked_ref())); + + let message_callback = Closure::::new({ + let inner = inner.clone(); + move |event: web_sys::MessageEvent| { + let Ok(buffer) = event.data().dyn_into::() else { + panic!("Unexpected data format {:?}", event.data()); + }; + + let mut inner = inner.lock().expect("Mutex is poised; qed"); + let bytes = js_sys::Uint8Array::new(&buffer).to_vec(); + inner.data.extend(bytes.into_iter()); + + if let Some(waker) = inner.waker.take() { + waker.wake(); + } + } + }); + socket.set_onmessage(Some(message_callback.as_ref().unchecked_ref())); + + let error_callback = Closure::::new({ + let inner = inner.clone(); + move |_| { + // Callback does not provide useful information, signal it back to the stream. + let mut inner = inner.lock().expect("Mutex is poised; qed"); + inner.state = ConnectionState::Error; + + if let Some(waker) = inner.waker.take() { + waker.wake(); + } + } + }); + socket.set_onerror(Some(error_callback.as_ref().unchecked_ref())); + + let close_callback = Closure::::new({ + let inner = inner.clone(); + move |_| { + let mut inner = inner.lock().expect("Mutex is poised; qed"); + inner.state = ConnectionState::Closed; + + if let Some(waker) = inner.waker.take() { + waker.wake(); + } + } + }); + socket.set_onclose(Some(close_callback.as_ref().unchecked_ref())); + + let callbacks = SendWrapper::new(( + open_callback, + message_callback, + error_callback, + close_callback, + )); + inner.lock().expect("Mutex poised; qed").callbacks = Some(callbacks); + + Ok(Self { inner }) + } +} + +impl AsyncRead for WasmSocket { + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut [u8], + ) -> Poll> { + let mut inner = self.inner.lock().expect("Mutex is poised; qed"); + inner.waker = Some(cx.waker().clone()); + + match inner.state { + ConnectionState::Error => { + Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, "Socket error"))) + } + ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())), + ConnectionState::Connecting => Poll::Pending, + ConnectionState::Opened => { + if inner.data.is_empty() { + return Poll::Pending; + } + + let n = inner.data.len().min(buf.len()); + for k in buf.iter_mut().take(n) { + *k = inner.data.pop_front().expect("Buffer non empty; qed"); + } + Poll::Ready(Ok(n)) + } + } + } +} + +impl AsyncWrite for WasmSocket { + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + let mut inner = self.inner.lock().expect("Mutex is poised; qed"); + inner.waker = Some(cx.waker().clone()); + + match inner.state { + ConnectionState::Error => { + Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, "Socket error"))) + } + ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())), + ConnectionState::Connecting => Poll::Pending, + ConnectionState::Opened => match inner.socket.send_with_u8_array(buf) { + Ok(()) => Poll::Ready(Ok(buf.len())), + Err(err) => Poll::Ready(Err(io::Error::new( + io::ErrorKind::Other, + format!("Write error: {err:?}"), + ))), + }, + } + } + + fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } +} + +impl Drop for WasmSocket { + fn drop(&mut self) { + let inner = self.inner.lock().expect("Mutex is poised; qed"); + + if inner.state == ConnectionState::Opened { + let _ = inner.socket.close(); + } + } +} From 5e850aa651f88630e8b71b1d50594db007d97cb5 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 27 Jun 2023 14:16:04 +0300 Subject: [PATCH 22/36] Use subxt-lightclient low level RPC crate Signed-off-by: Alexandru Vasile --- Cargo.lock | 12 +- Cargo.toml | 1 + lightclient/Cargo.toml | 6 +- lightclient/src/client.rs | 3 +- lightclient/src/lib.rs | 4 +- subxt/Cargo.toml | 54 +-- subxt/src/client/lightclient/background.rs | 437 ------------------ subxt/src/client/lightclient/builder.rs | 7 +- subxt/src/client/lightclient/mod.rs | 14 +- .../client/lightclient/platform/default.rs | 300 ------------ subxt/src/client/lightclient/platform/mod.rs | 13 - .../src/client/lightclient/platform/native.rs | 161 ------- subxt/src/client/lightclient/platform/wasm.rs | 126 ----- .../lightclient/platform/wasm_socket.rs | 233 ---------- subxt/src/client/lightclient/rpc.rs | 104 +---- subxt/src/client/mod.rs | 10 +- subxt/src/error/mod.rs | 10 +- subxt/src/rpc/types.rs | 2 - testing/wasm-tests/Cargo.lock | 36 +- testing/wasm-tests/Cargo.toml | 2 +- 20 files changed, 67 insertions(+), 1468 deletions(-) delete mode 100644 subxt/src/client/lightclient/background.rs delete mode 100644 subxt/src/client/lightclient/platform/default.rs delete mode 100644 subxt/src/client/lightclient/platform/mod.rs delete mode 100644 subxt/src/client/lightclient/platform/native.rs delete mode 100644 subxt/src/client/lightclient/platform/wasm.rs delete mode 100644 subxt/src/client/lightclient/platform/wasm_socket.rs diff --git a/Cargo.lock b/Cargo.lock index cb618ef86d..fe96972a2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4157,13 +4157,9 @@ dependencies = [ "either", "frame-metadata", "futures", - "futures-timer", - "futures-util", "getrandom 0.2.10", "hex", "impl-serde", - "instant", - "js-sys", "jsonrpsee", "parity-scale-codec", "primitive-types", @@ -4172,28 +4168,22 @@ dependencies = [ "scale-encode", "scale-info", "scale-value", - "send_wrapper 0.6.0", "serde", "serde_json", - "smoldot", - "smoldot-light", "sp-core", "sp-core-hashing", "sp-keyring", "sp-runtime", "sp-version", + "subxt-lightclient", "subxt-macro", "subxt-metadata", "subxt-signer", "thiserror", "tokio", "tokio-stream", - "tokio-util", "tracing", "tracing-subscriber 0.3.17", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1f96c3bf9c..d2bf624998 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,6 +106,7 @@ subxt-macro = { version = "0.29.0", path = "macro" } subxt-metadata = { version = "0.29.0", path = "metadata" } subxt-codegen = { version = "0.29.0", path = "codegen" } subxt-signer = { version = "0.29.0", path = "signer" } +subxt-lightclient = { version = "0.29.0", path = "lightclient" } test-runtime = { path = "testing/test-runtime" } substrate-runner = { path = "testing/substrate-runner" } diff --git a/lightclient/Cargo.toml b/lightclient/Cargo.toml index 53369a110c..1c415fa59b 100644 --- a/lightclient/Cargo.toml +++ b/lightclient/Cargo.toml @@ -15,9 +15,7 @@ description = "Light Client for chain interaction" keywords = ["parity", "substrate", "blockchain"] [features] -# For dev and documentation reasons we enable more features than are often desired. -# it's recommended to use `--no-default-features` and then select what you need. -default = ["native"] +default = [] # Enable this for native (ie non web/wasm builds). # Exactly 1 of "web" and "native" is expected. @@ -43,10 +41,12 @@ web = [ "tokio-stream", "tokio/sync", "futures-util", + # For the light-client platform. "wasm-bindgen-futures", "futures-timer/wasm-bindgen", "instant/wasm-bindgen", + # For websocket. "js-sys", "send_wrapper", diff --git a/lightclient/src/client.rs b/lightclient/src/client.rs index c25d475221..09c84f924d 100644 --- a/lightclient/src/client.rs +++ b/lightclient/src/client.rs @@ -7,7 +7,6 @@ use super::{ LightClientRpcError, }; use serde_json::value::RawValue; -use smoldot_light::ChainId; use tokio::sync::{mpsc, mpsc::error::SendError, oneshot}; use super::platform::default::SubxtPlatform as Platform; @@ -34,7 +33,7 @@ impl LightClientRpc { /// /// Panics if being called outside of `tokio` runtime context. pub fn new( - config: smoldot_light::AddChainConfig<'_, (), impl Iterator>, + config: smoldot_light::AddChainConfig<'_, (), impl Iterator>, ) -> Result { tracing::trace!(target: LOG_TARGET, "Create light client"); diff --git a/lightclient/src/lib.rs b/lightclient/src/lib.rs index 1d72ae1192..43869bbc45 100644 --- a/lightclient/src/lib.rs +++ b/lightclient/src/lib.rs @@ -16,6 +16,7 @@ unused_extern_crates, clippy::all )] +#![allow(clippy::type_complexity)] #[cfg(any( all(feature = "web", feature = "native"), @@ -24,8 +25,8 @@ compile_error!("subxt: exactly one of the 'web' and 'native' features should be used."); mod background; -mod platform; mod client; +mod platform; // Used to enable the js feature for wasm. #[cfg(feature = "web")] @@ -33,6 +34,7 @@ mod client; pub use getrandom as _; pub use client::LightClientRpc; +pub use smoldot_light::{AddChainConfig, AddChainConfigJsonRpc, ChainId}; /// Light client error. #[derive(Debug, thiserror::Error)] diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index dd90009050..d4fa845d27 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -23,7 +23,8 @@ default = ["jsonrpsee", "native", "substrate-compat"] # Exactly 1 of "web" and "native" is expected. native = [ "jsonrpsee?/async-client", - "jsonrpsee?/client-ws-transport" + "jsonrpsee?/client-ws-transport", + "subxt-lightclient?/native" ] # Enable this for web/wasm builds. @@ -31,7 +32,8 @@ native = [ web = [ "jsonrpsee?/async-wasm-client", "jsonrpsee?/client-web-transport", - "getrandom/js" + "getrandom/js", + "subxt-lightclient?/web" ] # Enable this to use jsonrpsee (allowing for example `OnlineClient::from_url`). @@ -56,34 +58,8 @@ unstable-metadata = [] # Activate this to expose the Light Client functionality. # Note that this feature is experimental and things may break or not work as expected. unstable-light-client = [ - "smoldot", - "smoldot-light/std", - "tokio-stream", - "tokio/sync", - "tokio/rt", - "tokio/net", - "tokio-util/compat", - "futures-util", -] - -unstable-light-client-wasm = [ - "smoldot", - "smoldot-light", - - "tokio-stream", - "tokio/sync", - "futures-util", - - # For the light-client platform. - "wasm-bindgen-futures", - "futures-timer/wasm-bindgen", - "instant/wasm-bindgen", - - # For websocket. - "js-sys", - "send_wrapper", - "web-sys", - "wasm-bindgen", + "subxt-lightclient", + "tokio-stream" ] [dependencies] @@ -122,21 +98,10 @@ sp-runtime = { workspace = true, optional = true } # Other subxt crates we depend on. subxt-macro = { workspace = true } subxt-metadata = { workspace = true } +subxt-lightclient = { workspace = true, optional = true, default-features = false } # Light client support: -smoldot = { workspace = true, optional = true } -smoldot-light = { workspace = true, optional = true } -tokio = { workspace = true, optional = true } tokio-stream = { workspace = true, optional = true } -futures-util = { workspace = true, optional = true } -js-sys = { workspace = true, optional = true } -send_wrapper = { workspace = true, optional = true } -web-sys = { workspace = true, optional = true } -wasm-bindgen = { workspace = true, optional = true } -wasm-bindgen-futures = { workspace = true, optional = true } -futures-timer = { workspace = true, optional = true } -instant = { workspace = true, optional = true } -tokio-util = { workspace = true, optional = true } # Included if "web" feature is enabled, to enable its js feature. getrandom = { workspace = true, optional = true } @@ -162,8 +127,3 @@ tracing-subscriber = { workspace = true } name = "unstable_light_client_tx_basic" path = "examples/unstable_light_client_tx_basic.rs" required-features = ["unstable-light-client", "jsonrpsee"] - -[profile.dev.package.smoldot-light] -opt-level = 2 -[profile.test.package.smoldot-light] -opt-level = 2 diff --git a/subxt/src/client/lightclient/background.rs b/subxt/src/client/lightclient/background.rs deleted file mode 100644 index 42094cd02e..0000000000 --- a/subxt/src/client/lightclient/background.rs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. -// This file is dual-licensed as Apache-2.0 or GPL-3.0. -// see LICENSE for license details. - -use futures::stream::StreamExt; -use futures_util::future::{self, Either}; -use serde::Deserialize; -use serde_json::value::RawValue; -use std::{collections::HashMap, str::FromStr}; -use tokio::sync::{mpsc, oneshot}; - -use super::platform::default::SubxtPlatform as Platform; -use super::LightClientError; -use smoldot_light::ChainId; - -const LOG_TARGET: &str = "light-client-background"; - -/// The response of an RPC method. -pub type MethodResponse = Result, LightClientError>; - -/// Message protocol between the front-end client that submits the RPC requests -/// and the backend handler that produces responses from the chain. -/// -/// The light client uses a single object [`smoldot_light::JsonRpcResponses`] to -/// handle all requests and subscriptions from a chain. A background task is spawned -/// to multiplex the rpc responses and to provide them back to their rightful submitters. -#[derive(Debug)] -pub enum FromSubxt { - /// The RPC method request. - Request { - /// The method of the request. - method: String, - /// The parameters of the request. - params: String, - /// Channel used to send back the result. - sender: oneshot::Sender, - }, - /// The RPC subscription (pub/sub) request. - Subscription { - /// The method of the request. - method: String, - /// The parameters of the request. - params: String, - /// Channel used to send back the subscription ID if successful. - sub_id: oneshot::Sender, - /// Channel used to send back the notifcations. - sender: mpsc::UnboundedSender>, - }, -} - -/// Background task data. -pub struct BackgroundTask { - /// Smoldot light client implementation that leverages the exposed platform. - client: smoldot_light::Client, - /// The ID of the chain used to identify the chain protocol (ie. substrate). - /// - /// Note: A single chain is supported for a client. This aligns with the subxt's - /// vision of the Client. - chain_id: ChainId, - /// Unique ID for RPC calls. - request_id: usize, - /// Map the request ID of a RPC method to the frontend `Sender`. - requests: HashMap>, - /// Subscription calls first need to make a plain RPC method - /// request to obtain the subscription ID. - /// - /// The RPC method request is made in the background and the response should - /// not be sent back to the user. - /// Map the request ID of a RPC method to the frontend `Sender`. - id_to_subscription: HashMap< - usize, - ( - oneshot::Sender, - mpsc::UnboundedSender>, - ), - >, - /// Map the subscription ID to the frontend `Sender`. - subscriptions: HashMap>>, -} - -impl BackgroundTask { - /// Constructs a new [`BackgroundTask`]. - pub fn new(client: smoldot_light::Client, chain_id: ChainId) -> BackgroundTask { - BackgroundTask { - client, - chain_id, - request_id: 1, - requests: Default::default(), - id_to_subscription: Default::default(), - subscriptions: Default::default(), - } - } - - /// Fetch and increment the request ID. - fn next_id(&mut self) -> usize { - let next = self.request_id; - self.request_id = self.request_id.wrapping_add(1); - next - } - - /// Handle the registration messages received from the user. - async fn handle_requests(&mut self, message: FromSubxt) { - match message { - FromSubxt::Request { - method, - params, - sender, - } => { - let id = self.next_id(); - let request = format!( - r#"{{"jsonrpc":"2.0","id":"{}", "method":"{}","params":{}}}"#, - id, method, params - ); - - self.requests.insert(id, sender); - - let result = self.client.json_rpc_request(request, self.chain_id); - if let Err(err) = result { - tracing::warn!( - target: LOG_TARGET, - "Cannot send RPC request to lightclient {:?}", - err.to_string() - ); - let sender = self - .requests - .remove(&id) - .expect("Channel is inserted above; qed"); - - // Send the error back to frontend. - if sender - .send(Err(LightClientError::Request(err.to_string()))) - .is_err() - { - tracing::warn!( - target: LOG_TARGET, - "Cannot send RPC request error to id={id}", - ); - } - } - } - FromSubxt::Subscription { - method, - params, - sub_id, - sender, - } => { - // For subscriptions we need to make a plain RPC request to the subscription method. - // The server will return as a result the subscription ID. - let id = self.next_id(); - let request = format!( - r#"{{"jsonrpc":"2.0","id":"{}", "method":"{}","params":{}}}"#, - id, method, params - ); - - self.id_to_subscription.insert(id, (sub_id, sender)); - - let result = self.client.json_rpc_request(request, self.chain_id); - if let Err(err) = result { - tracing::warn!( - target: LOG_TARGET, - "Cannot send RPC request to lightclient {:?}", - err.to_string() - ); - let (sub_id, _) = self - .id_to_subscription - .remove(&id) - .expect("Channels are inserted above; qed"); - - // Send the error back to frontend. - if sub_id - .send(Err(LightClientError::Request(err.to_string()))) - .is_err() - { - tracing::warn!( - target: LOG_TARGET, - "Cannot send RPC request error to id={id}", - ); - } - } - } - }; - } - - /// Parse the response received from the light client and sent it to the appropriate user. - fn handle_rpc_response(&mut self, response: String) { - match RpcResponse::from_str(&response) { - Ok(RpcResponse::Error { id, error }) => { - let Ok(id) = id.parse::() else { - tracing::warn!(target: LOG_TARGET, "Cannot send error. Id={id} is not a valid number"); - return - }; - - if let Some(sender) = self.requests.remove(&id) { - if sender - .send(Err(LightClientError::Request(error.to_string()))) - .is_err() - { - tracing::warn!( - target: LOG_TARGET, - "Cannot send method response to id={id}", - ); - } - } else if let Some((sub_id_sender, _)) = self.id_to_subscription.remove(&id) { - if sub_id_sender - .send(Err(LightClientError::Request(error.to_string()))) - .is_err() - { - tracing::warn!( - target: LOG_TARGET, - "Cannot send method response to id {:?}", - id - ); - } - } - } - Ok(RpcResponse::Method { id, result }) => { - let Ok(id) = id.parse::() else { - tracing::warn!(target: LOG_TARGET, "Cannot send response. Id={id} is not a valid number"); - return - }; - - // Send the response back. - if let Some(sender) = self.requests.remove(&id) { - if sender.send(Ok(result)).is_err() { - tracing::warn!( - target: LOG_TARGET, - "Cannot send method response to id={id}", - ); - } - } else if let Some((sub_id_sender, sender)) = self.id_to_subscription.remove(&id) { - let Ok(sub_id) = result - .get() - .trim_start_matches('"') - .trim_end_matches('"') - .parse::() else { - tracing::warn!( - target: LOG_TARGET, - "Subscription id={result} is not a valid number", - ); - return; - }; - - tracing::trace!(target: LOG_TARGET, "Received subscription id={sub_id}"); - - if sub_id_sender.send(Ok(result)).is_err() { - tracing::warn!( - target: LOG_TARGET, - "Cannot send method response to id={id}", - ); - } else { - // Track this subscription ID if send is successful. - self.subscriptions.insert(sub_id, sender); - } - } - } - Ok(RpcResponse::Subscription { method, id, result }) => { - let Ok(id) = id.parse::() else { - tracing::warn!(target: LOG_TARGET, "Cannot send subscription. Id={id} is not a valid number"); - return - }; - - if let Some(sender) = self.subscriptions.get_mut(&id) { - // Send the current notification response. - if sender.send(result).is_err() { - tracing::warn!( - target: LOG_TARGET, - "Cannot send notification to subscription id={id} method={method}", - ); - - // Remove the sender if the subscription dropped the receiver. - self.subscriptions.remove(&id); - } - } - } - Err(err) => { - tracing::warn!(target: LOG_TARGET, "cannot decode RPC response {:?}", err); - } - } - } - - /// Perform the main background task: - /// - receiving requests from subxt RPC method / subscriptions - /// - provides the results from the light client back to users. - pub async fn start_task( - &mut self, - from_subxt: mpsc::UnboundedReceiver, - from_node: smoldot_light::JsonRpcResponses, - ) { - let from_subxt_event = tokio_stream::wrappers::UnboundedReceiverStream::new(from_subxt); - let from_node_event = futures_util::stream::unfold(from_node, |mut from_node| async { - from_node.next().await.map(|result| (result, from_node)) - }); - - tokio::pin!(from_subxt_event, from_node_event); - - let mut from_subxt_event_fut = from_subxt_event.next(); - let mut from_node_event_fut = from_node_event.next(); - - loop { - match future::select(from_subxt_event_fut, from_node_event_fut).await { - // Message received from subxt. - Either::Left((subxt_message, previous_fut)) => { - let Some(message) = subxt_message else { - tracing::trace!(target: LOG_TARGET, "Subxt channel closed"); - break; - }; - tracing::trace!( - target: LOG_TARGET, - "Received register message {:?}", - message - ); - - self.handle_requests(message).await; - - from_subxt_event_fut = from_subxt_event.next(); - from_node_event_fut = previous_fut; - } - // Message received from rpc handler: lightclient response. - Either::Right((node_message, previous_fut)) => { - // Smoldot returns `None` if the chain has been removed (which subxt does not remove). - let Some(response) = node_message else { - tracing::trace!(target: LOG_TARGET, "Smoldot RPC responses channel closed"); - break; - }; - tracing::trace!( - target: LOG_TARGET, - "Received smoldot RPC result {:?}", - response - ); - - self.handle_rpc_response(response); - - // Advance backend, save frontend. - from_subxt_event_fut = previous_fut; - from_node_event_fut = from_node_event.next(); - } - } - } - - tracing::trace!(target: LOG_TARGET, "Task closed"); - } -} - -/// The RPC response from the light-client. -/// This can either be a response of a method, or a notification from a subscription. -#[derive(Debug, Clone)] -enum RpcResponse { - Method { - /// Response ID. - id: String, - /// The result of the method call. - result: Box, - }, - Subscription { - /// RPC method that generated the notification. - method: String, - /// Subscription ID. - id: String, - /// Result. - result: Box, - }, - Error { - /// Response ID. - id: String, - /// Error. - error: Box, - }, -} - -impl std::str::FromStr for RpcResponse { - type Err = serde_json::Error; - - fn from_str(response: &str) -> Result { - // Helper structures to deserialize from raw RPC strings. - #[derive(Deserialize, Debug)] - struct Response { - /// JSON-RPC version. - #[allow(unused)] - jsonrpc: String, - /// Result. - result: Box, - /// Request ID - id: String, - } - #[derive(Deserialize)] - struct NotificationParams { - /// The ID of the subscription. - subscription: String, - /// Result. - result: Box, - } - #[derive(Deserialize)] - struct ResponseNotification { - /// JSON-RPC version. - #[allow(unused)] - jsonrpc: String, - /// RPC method that generated the notification. - method: String, - /// Result. - params: NotificationParams, - } - #[derive(Deserialize)] - struct ErrorResponse { - /// JSON-RPC version. - #[allow(unused)] - jsonrpc: String, - /// Request ID. - id: String, - /// Error. - error: Box, - } - - // Check if the response can be mapped as an RPC method response. - let result: Result = serde_json::from_str(response); - if let Ok(response) = result { - return Ok(RpcResponse::Method { - id: response.id, - result: response.result, - }); - } - - let result: Result = serde_json::from_str(response); - if let Ok(notification) = result { - return Ok(RpcResponse::Subscription { - id: notification.params.subscription, - method: notification.method, - result: notification.params.result, - }); - } - - let error: ErrorResponse = serde_json::from_str(response)?; - Ok(RpcResponse::Error { - id: error.id, - error: error.error, - }) - } -} diff --git a/subxt/src/client/lightclient/builder.rs b/subxt/src/client/lightclient/builder.rs index c386100bc2..56e3696ffa 100644 --- a/subxt/src/client/lightclient/builder.rs +++ b/subxt/src/client/lightclient/builder.rs @@ -5,7 +5,8 @@ use super::{rpc::LightClientRpc, LightClient, LightClientError}; use crate::{config::Config, error::Error, OnlineClient}; -use smoldot_light::ChainId; +use subxt_lightclient::{AddChainConfig, AddChainConfigJsonRpc, ChainId}; + use std::num::NonZeroU32; use std::sync::Arc; @@ -138,9 +139,9 @@ impl LightClientBuilder { } } - let config = smoldot_light::AddChainConfig { + let config = AddChainConfig { specification: &chain_spec.to_string(), - json_rpc: smoldot_light::AddChainConfigJsonRpc::Enabled { + json_rpc: AddChainConfigJsonRpc::Enabled { max_pending_requests: self.max_pending_requests, max_subscriptions: self.max_subscriptions, }, diff --git a/subxt/src/client/lightclient/mod.rs b/subxt/src/client/lightclient/mod.rs index 091b49d201..4d8f3130d2 100644 --- a/subxt/src/client/lightclient/mod.rs +++ b/subxt/src/client/lightclient/mod.rs @@ -4,36 +4,30 @@ //! This module provides support for light clients. -mod background; mod builder; -mod platform; mod rpc; use derivative::Derivative; - use crate::{ client::{OfflineClientT, OnlineClientT}, config::Config, OnlineClient, }; - pub use builder::LightClientBuilder; +use subxt_lightclient::LightClientRpcError; /// Light client error. #[derive(Debug, thiserror::Error)] pub enum LightClientError { - /// Error encountered while adding the chain to the light-client. - #[error("Failed to add the chain to the light client: {0}.")] - AddChainError(String), + /// Error originated from the low-level RPC layer. + #[error("Rpc error: {0}")] + Rpc(LightClientRpcError), /// The background task is closed. #[error("Failed to communicate with the background task.")] BackgroundClosed, /// Invalid RPC parameters cannot be serialized as JSON string. #[error("RPC parameters cannot be serialized as JSON string.")] InvalidParams, - /// Error originated while trying to submit a RPC request. - #[error("RPC request cannot be sent: {0}.")] - Request(String), /// The provided URL scheme is invalid. /// /// Supported versions: WS, WSS. diff --git a/subxt/src/client/lightclient/platform/default.rs b/subxt/src/client/lightclient/platform/default.rs deleted file mode 100644 index 6703dc8282..0000000000 --- a/subxt/src/client/lightclient/platform/default.rs +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. -// This file is dual-licensed as Apache-2.0 or GPL-3.0. -// see LICENSE for license details. - -use core::time::Duration; -use futures::{prelude::*, task::Poll}; - -use smoldot::libp2p::multiaddr::Multiaddr; -use smoldot_light::platform::{ - ConnectError, PlatformConnection, PlatformRef, PlatformSubstreamDirection, ReadBuffer, -}; -use std::{io::IoSlice, pin::Pin}; - -#[cfg(not(feature = "unstable-light-client-wasm"))] -use super::native as platform_impl; -#[cfg(feature = "unstable-light-client-wasm")] -use super::wasm as platform_impl; - -use platform_impl::{StreamReadBuffer, StreamWriteBuffer}; - -/// Subxt plaform implementation for native and wasm. -/// -/// This implementation is a conversion of the implementation from the smoldot: -/// https://github.com/smol-dot/smoldot/blob/f49ce4ea6a325c444ab6ad37d3ab5558edf0d541/light-base/src/platform/default.rs#L52. -#[derive(Clone)] -pub struct SubxtPlatform {} - -impl SubxtPlatform { - pub fn new() -> Self { - SubxtPlatform {} - } -} - -impl PlatformRef for SubxtPlatform { - type Delay = platform_impl::Delay; - type Yield = future::Ready<()>; - type Instant = platform_impl::Instant; - type Connection = std::convert::Infallible; - type Stream = platform_impl::Stream; - type ConnectFuture = future::BoxFuture< - 'static, - Result, ConnectError>, - >; - type StreamUpdateFuture<'a> = future::BoxFuture<'a, ()>; - type NextSubstreamFuture<'a> = - future::Pending>; - - fn now_from_unix_epoch(&self) -> Duration { - platform_impl::now_from_unix_epoch() - } - - fn now(&self) -> Self::Instant { - platform_impl::now() - } - - fn sleep(&self, duration: Duration) -> Self::Delay { - platform_impl::sleep(duration) - } - - fn sleep_until(&self, when: Self::Instant) -> Self::Delay { - self.sleep(when.saturating_duration_since(self.now())) - } - - fn yield_after_cpu_intensive(&self) -> Self::Yield { - // No-op. - future::ready(()) - } - - fn connect(&self, multiaddr: &str) -> Self::ConnectFuture { - // We simply copy the address to own it. We could be more zero-cost here, but doing so - // would considerably complicate the implementation. - let multiaddr = multiaddr.to_owned(); - - tracing::debug!("Connecting to multiaddress={:?}", multiaddr); - - Box::pin(async move { - let addr = multiaddr.parse::().map_err(|_| ConnectError { - is_bad_addr: true, - message: "Failed to parse address".to_string(), - })?; - - let mut iter = addr.iter().fuse(); - let proto1 = iter.next().ok_or(ConnectError { - is_bad_addr: true, - message: "Unknown protocols combination".to_string(), - })?; - let proto2 = iter.next().ok_or(ConnectError { - is_bad_addr: true, - message: "Unknown protocols combination".to_string(), - })?; - let proto3 = iter.next(); - - if iter.next().is_some() { - return Err(ConnectError { - is_bad_addr: true, - message: "Unknown protocols combination".to_string(), - }); - } - - platform_impl::connect(proto1, proto2, proto3).await - }) - } - - fn open_out_substream(&self, c: &mut Self::Connection) { - // This function can only be called with so-called "multi-stream" connections. We never - // open such connection. - match *c {} - } - - fn next_substream<'a>(&self, c: &'a mut Self::Connection) -> Self::NextSubstreamFuture<'a> { - // This function can only be called with so-called "multi-stream" connections. We never - // open such connection. - match *c {} - } - - fn update_stream<'a>(&self, stream: &'a mut Self::Stream) -> Self::StreamUpdateFuture<'a> { - Box::pin(future::poll_fn(|cx| { - let Some((read_buffer, write_buffer)) = stream.buffers.as_mut() else { return Poll::Pending }; - - // Whether the future returned by `update_stream` should return `Ready` or `Pending`. - let mut update_stream_future_ready = false; - - if let StreamReadBuffer::Open { - buffer: ref mut buf, - ref mut cursor, - } = read_buffer - { - // When reading data from the socket, `poll_read` might return "EOF". In that - // situation, we transition to the `Closed` state, which would discard the data - // currently in the buffer. For this reason, we only try to read if there is no - // data left in the buffer. - if cursor.start == cursor.end { - if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_read(cx, buf) { - update_stream_future_ready = true; - match result { - Err(_) => { - // End the stream. - stream.buffers = None; - return Poll::Ready(()); - } - Ok(0) => { - // EOF. - *read_buffer = StreamReadBuffer::Closed; - } - Ok(bytes) => { - *cursor = 0..bytes; - } - } - } - } - } - - if let StreamWriteBuffer::Open { - buffer: ref mut buf, - must_flush, - must_close, - } = write_buffer - { - while !buf.is_empty() { - let write_queue_slices = buf.as_slices(); - if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_write_vectored( - cx, - &[ - IoSlice::new(write_queue_slices.0), - IoSlice::new(write_queue_slices.1), - ], - ) { - if !*must_close { - // In the situation where the API user wants to close the writing - // side, simply sending the buffered data isn't enough to justify - // making the future ready. - update_stream_future_ready = true; - } - - match result { - Err(_) => { - // End the stream. - stream.buffers = None; - return Poll::Ready(()); - } - Ok(bytes) => { - *must_flush = true; - for _ in 0..bytes { - buf.pop_front(); - } - } - } - } else { - break; - } - } - - if buf.is_empty() && *must_close { - if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_close(cx) { - update_stream_future_ready = true; - match result { - Err(_) => { - // End the stream. - stream.buffers = None; - return Poll::Ready(()); - } - Ok(()) => { - *write_buffer = StreamWriteBuffer::Closed; - } - } - } - } else if *must_flush { - if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_flush(cx) { - update_stream_future_ready = true; - match result { - Err(_) => { - // End the stream. - stream.buffers = None; - return Poll::Ready(()); - } - Ok(()) => { - *must_flush = false; - } - } - } - } - } - - if update_stream_future_ready { - Poll::Ready(()) - } else { - Poll::Pending - } - })) - } - - fn read_buffer<'a>(&self, stream: &'a mut Self::Stream) -> ReadBuffer<'a> { - match stream.buffers.as_ref().map(|(r, _)| r) { - None => ReadBuffer::Reset, - Some(StreamReadBuffer::Closed) => ReadBuffer::Closed, - Some(StreamReadBuffer::Open { buffer, cursor }) => { - ReadBuffer::Open(&buffer[cursor.clone()]) - } - } - } - - fn advance_read_cursor(&self, stream: &mut Self::Stream, extra_bytes: usize) { - let Some(StreamReadBuffer::Open { ref mut cursor, .. }) = - stream.buffers.as_mut().map(|(r, _)| r) - else { - assert_eq!(extra_bytes, 0); - return - }; - - assert!(cursor.start + extra_bytes <= cursor.end); - cursor.start += extra_bytes; - } - - fn writable_bytes(&self, stream: &mut Self::Stream) -> usize { - let Some(StreamWriteBuffer::Open { ref mut buffer, must_close: false, ..}) = - stream.buffers.as_mut().map(|(_, w)| w) else { return 0 }; - buffer.capacity() - buffer.len() - } - - fn send(&self, stream: &mut Self::Stream, data: &[u8]) { - debug_assert!(!data.is_empty()); - - // Because `writable_bytes` returns 0 if the writing side is closed, and because `data` - // must always have a size inferior or equal to `writable_bytes`, we know for sure that - // the writing side isn't closed. - let Some(StreamWriteBuffer::Open { ref mut buffer, .. } )= - stream.buffers.as_mut().map(|(_, w)| w) else { panic!() }; - buffer.reserve(data.len()); - buffer.extend(data.iter().copied()); - } - - fn close_send(&self, stream: &mut Self::Stream) { - // It is not illegal to call this on an already-reset stream. - let Some((_, write_buffer)) = stream.buffers.as_mut() else { return }; - - match write_buffer { - StreamWriteBuffer::Open { - must_close: must_close @ false, - .. - } => *must_close = true, - _ => { - // However, it is illegal to call this on a stream that was already close - // attempted. - panic!() - } - } - } - - fn spawn_task(&self, _: std::borrow::Cow, task: future::BoxFuture<'static, ()>) { - platform_impl::spawn(task); - } - - fn client_name(&self) -> std::borrow::Cow { - "subxt-light-client".into() - } - - fn client_version(&self) -> std::borrow::Cow { - env!("CARGO_PKG_VERSION").into() - } -} diff --git a/subxt/src/client/lightclient/platform/mod.rs b/subxt/src/client/lightclient/platform/mod.rs deleted file mode 100644 index 26868e37db..0000000000 --- a/subxt/src/client/lightclient/platform/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. -// This file is dual-licensed as Apache-2.0 or GPL-3.0. -// see LICENSE for license details. - -pub mod default; - -#[cfg(not(feature = "unstable-light-client-wasm"))] -mod native; - -#[cfg(feature = "unstable-light-client-wasm")] -mod wasm; -#[cfg(feature = "unstable-light-client-wasm")] -mod wasm_socket; diff --git a/subxt/src/client/lightclient/platform/native.rs b/subxt/src/client/lightclient/platform/native.rs deleted file mode 100644 index 64006f026e..0000000000 --- a/subxt/src/client/lightclient/platform/native.rs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. -// This file is dual-licensed as Apache-2.0 or GPL-3.0. -// see LICENSE for license details. - -//! Native implementation for the light client's platform using -//! `tokio::net::TcpStream` for connections. - -use core::time::Duration; -use futures_util::{future, FutureExt}; -use smoldot::libp2p::{multiaddr::ProtocolRef, websocket}; -use smoldot_light::platform::{ConnectError, PlatformConnection}; -use std::{ - collections::VecDeque, - net::{IpAddr, SocketAddr}, -}; -use tokio::net::TcpStream; -use tokio_util::compat::{Compat, TokioAsyncReadCompatExt}; - -pub fn spawn(task: future::BoxFuture<'static, ()>) { - tokio::spawn(task); -} - -pub fn now_from_unix_epoch() -> Duration { - // Intentionally panic if the time is configured earlier than the UNIX EPOCH. - std::time::UNIX_EPOCH.elapsed().unwrap_or_else(|_| { - panic!("Invalid systime cannot be configured earlier than `UNIX_EPOCH`") - }) -} - -pub type Instant = std::time::Instant; - -pub fn now() -> Instant { - Instant::now() -} - -pub type Delay = future::BoxFuture<'static, ()>; - -pub fn sleep(duration: Duration) -> Delay { - tokio::time::sleep(duration).boxed() -} - -pub type CompatTcpStream = Compat; -pub type Socket = future::Either>; - -pub struct Stream { - pub socket: Socket, - /// Read and write buffers of the connection, or `None` if the socket has been reset. - pub buffers: Option<(StreamReadBuffer, StreamWriteBuffer)>, -} - -pub enum StreamReadBuffer { - Open { - buffer: Vec, - cursor: std::ops::Range, - }, - Closed, -} - -pub enum StreamWriteBuffer { - Open { - buffer: VecDeque, - must_flush: bool, - must_close: bool, - }, - Closed, -} - -pub async fn connect<'a>( - proto1: ProtocolRef<'a>, - proto2: ProtocolRef<'a>, - proto3: Option>, -) -> Result, ConnectError> { - // Ensure ahead of time that the multiaddress is supported. - let (addr, host_if_websocket) = match (&proto1, &proto2, &proto3) { - (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), None) => ( - either::Left(SocketAddr::new(IpAddr::V4((*ip).into()), *port)), - None, - ), - (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), None) => ( - either::Left(SocketAddr::new(IpAddr::V6((*ip).into()), *port)), - None, - ), - (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { - let addr = SocketAddr::new(IpAddr::V4((*ip).into()), *port); - (either::Left(addr), Some(addr.to_string())) - } - (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { - let addr = SocketAddr::new(IpAddr::V6((*ip).into()), *port); - (either::Left(addr), Some(addr.to_string())) - } - ( - ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), - ProtocolRef::Tcp(port), - None, - ) => (either::Right((addr.to_string(), *port)), None), - ( - ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), - ProtocolRef::Tcp(port), - Some(ProtocolRef::Ws), - ) => ( - either::Right((addr.to_string(), *port)), - Some(format!("{}:{}", addr, *port)), - ), - _ => { - return Err(ConnectError { - is_bad_addr: true, - message: "Unknown protocols combination".to_string(), - }) - } - }; - - tracing::debug!("Connecting to addr={addr:?}"); - - let tcp_socket = match addr { - either::Left(socket_addr) => tokio::net::TcpStream::connect(socket_addr).await, - either::Right((dns, port)) => tokio::net::TcpStream::connect((&dns[..], port)).await, - }; - - if let Ok(tcp_socket) = &tcp_socket { - let _ = tcp_socket.set_nodelay(true); - } - - let socket: Socket = match (tcp_socket, host_if_websocket) { - (Ok(tcp_socket), Some(host)) => future::Either::Right( - websocket::websocket_client_handshake(websocket::Config { - tcp_socket: tcp_socket.compat(), - host: &host, - url: "/", - }) - .await - .map_err(|err| ConnectError { - message: format!("Failed to negotiate WebSocket: {err}"), - is_bad_addr: false, - })?, - ), - (Ok(tcp_socket), None) => future::Either::Left(tcp_socket.compat()), - (Err(err), _) => { - return Err(ConnectError { - is_bad_addr: false, - message: format!("Failed to reach peer: {err}"), - }) - } - }; - - Ok(PlatformConnection::SingleStreamMultistreamSelectNoiseYamux( - Stream { - socket, - buffers: Some(( - StreamReadBuffer::Open { - buffer: vec![0; 16384], - cursor: 0..0, - }, - StreamWriteBuffer::Open { - buffer: VecDeque::with_capacity(16384), - must_close: false, - must_flush: false, - }, - )), - }, - )) -} diff --git a/subxt/src/client/lightclient/platform/wasm.rs b/subxt/src/client/lightclient/platform/wasm.rs deleted file mode 100644 index 0bef476249..0000000000 --- a/subxt/src/client/lightclient/platform/wasm.rs +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. -// This file is dual-licensed as Apache-2.0 or GPL-3.0. -// see LICENSE for license details. - -//! Wasm implementation for the light client's platform using -//! custom websockets. - -use core::time::Duration; -use futures_util::{future, FutureExt}; -use smoldot::libp2p::multiaddr::ProtocolRef; -use smoldot_light::platform::{ConnectError, PlatformConnection}; -use std::{ - collections::VecDeque, - net::{IpAddr, SocketAddr}, -}; - -use super::wasm_socket::WasmSocket; - -pub fn spawn(task: future::BoxFuture<'static, ()>) { - wasm_bindgen_futures::spawn_local(task); -} - -pub fn now_from_unix_epoch() -> Duration { - instant::SystemTime::now() - .duration_since(instant::SystemTime::UNIX_EPOCH) - .unwrap_or_else(|_| { - panic!("Invalid systime cannot be configured earlier than `UNIX_EPOCH`") - }) -} - -pub type Instant = instant::Instant; - -pub fn now() -> Instant { - instant::Instant::now() -} - -pub type Delay = future::BoxFuture<'static, ()>; - -pub fn sleep(duration: Duration) -> Delay { - futures_timer::Delay::new(duration).boxed() -} - -pub struct Stream { - pub socket: WasmSocket, - /// Read and write buffers of the connection, or `None` if the socket has been reset. - pub buffers: Option<(StreamReadBuffer, StreamWriteBuffer)>, -} - -pub enum StreamReadBuffer { - Open { - buffer: Vec, - cursor: std::ops::Range, - }, - Closed, -} - -pub enum StreamWriteBuffer { - Open { - buffer: VecDeque, - must_flush: bool, - must_close: bool, - }, - Closed, -} - -pub async fn connect<'a>( - proto1: ProtocolRef<'a>, - proto2: ProtocolRef<'a>, - proto3: Option>, -) -> Result, ConnectError> { - // Ensure ahead of time that the multiaddress is supported. - let addr = match (&proto1, &proto2, &proto3) { - (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { - let addr = SocketAddr::new(IpAddr::V4((*ip).into()), *port); - format!("ws://{}", addr.to_string()) - } - (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { - let addr = SocketAddr::new(IpAddr::V6((*ip).into()), *port); - format!("ws://{}", addr.to_string()) - } - ( - ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), - ProtocolRef::Tcp(port), - Some(ProtocolRef::Ws), - ) => { - format!("ws://{}:{}", addr.to_string(), port) - } - ( - ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), - ProtocolRef::Tcp(port), - Some(ProtocolRef::Wss), - ) => { - format!("wss://{}:{}", addr.to_string(), port) - } - _ => { - return Err(ConnectError { - is_bad_addr: true, - message: "Unknown protocols combination".to_string(), - }) - } - }; - - tracing::debug!("Connecting to addr={addr}"); - - let socket = WasmSocket::new(addr.as_str()).map_err(|err| ConnectError { - is_bad_addr: false, - message: format!("Failed to reach peer: {err}"), - })?; - - Ok(PlatformConnection::SingleStreamMultistreamSelectNoiseYamux( - Stream { - socket, - buffers: Some(( - StreamReadBuffer::Open { - buffer: vec![0; 16384], - cursor: 0..0, - }, - StreamWriteBuffer::Open { - buffer: VecDeque::with_capacity(16384), - must_close: false, - must_flush: false, - }, - )), - }, - )) -} diff --git a/subxt/src/client/lightclient/platform/wasm_socket.rs b/subxt/src/client/lightclient/platform/wasm_socket.rs deleted file mode 100644 index 661a377c13..0000000000 --- a/subxt/src/client/lightclient/platform/wasm_socket.rs +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. -// This file is dual-licensed as Apache-2.0 or GPL-3.0. -// see LICENSE for license details. - -use futures::{io, prelude::*}; -use send_wrapper::SendWrapper; -use wasm_bindgen::{prelude::*, JsCast}; - -use std::{ - collections::VecDeque, - pin::Pin, - sync::{Arc, Mutex}, - task::Poll, - task::{Context, Waker}, -}; - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("Failed to connect {0}")] - ConnectionError(String), -} - -/// Websocket for WASM environments. -/// -/// This is a rust-based wrapper around browser's WebSocket API. -pub struct WasmSocket { - inner: Arc>, -} - -/// The state of the [`WasmSocket`]. -#[derive(PartialEq, Eq, Clone, Copy)] -enum ConnectionState { - /// Initial state of the socket. - Connecting, - /// Socket is fully opened. - Opened, - /// Socket is closed. - Closed, - /// Error reported by callbacks. - Error, -} - -struct InnerWasmSocket { - /// The state of the connection. - state: ConnectionState, - /// This implements `Send` and panics if the value is accessed - /// or dropped from another thread. - /// - /// This is safe in wasm environments. - socket: SendWrapper, - /// Data buffer for the socket. - data: VecDeque, - /// Waker from `poll_read` / `poll_write`. - waker: Option, - /// In memory callbacks to handle messages from the browser socket. - callbacks: Option>, -} - -/// Registered callbacks of the [`WasmSocket`]. -/// -/// These need to be kept around until the socket is dropped. -type Callbacks = ( - Closure, - Closure, - Closure, - Closure, -); - -impl WasmSocket { - /// Establish a WebSocket connection. - /// - /// The error is a string representing the browser error. - /// Visit [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket#exceptions_thrown) - /// for more info. - pub fn new(addr: &str) -> Result { - let socket = match web_sys::WebSocket::new(addr) { - Ok(socket) => socket, - Err(err) => return Err(Error::ConnectionError(format!("{:?}", err))), - }; - - socket.set_binary_type(web_sys::BinaryType::Arraybuffer); - - let inner = Arc::new(Mutex::new(InnerWasmSocket { - state: ConnectionState::Connecting, - socket: SendWrapper::new(socket.clone()), - data: VecDeque::with_capacity(16384), - waker: None, - callbacks: None, - })); - - let open_callback = Closure::::new({ - let inner = inner.clone(); - move || { - let mut inner = inner.lock().expect("Mutex is poised; qed"); - inner.state = ConnectionState::Opened; - - if let Some(waker) = inner.waker.take() { - waker.wake(); - } - } - }); - socket.set_onopen(Some(open_callback.as_ref().unchecked_ref())); - - let message_callback = Closure::::new({ - let inner = inner.clone(); - move |event: web_sys::MessageEvent| { - let Ok(buffer) = event.data().dyn_into::() else { - panic!("Unexpected data format {:?}", event.data()); - }; - - let mut inner = inner.lock().expect("Mutex is poised; qed"); - let bytes = js_sys::Uint8Array::new(&buffer).to_vec(); - inner.data.extend(bytes.into_iter()); - - if let Some(waker) = inner.waker.take() { - waker.wake(); - } - } - }); - socket.set_onmessage(Some(message_callback.as_ref().unchecked_ref())); - - let error_callback = Closure::::new({ - let inner = inner.clone(); - move |_| { - // Callback does not provide useful information, signal it back to the stream. - let mut inner = inner.lock().expect("Mutex is poised; qed"); - inner.state = ConnectionState::Error; - - if let Some(waker) = inner.waker.take() { - waker.wake(); - } - } - }); - socket.set_onerror(Some(error_callback.as_ref().unchecked_ref())); - - let close_callback = Closure::::new({ - let inner = inner.clone(); - move |_| { - let mut inner = inner.lock().expect("Mutex is poised; qed"); - inner.state = ConnectionState::Closed; - - if let Some(waker) = inner.waker.take() { - waker.wake(); - } - } - }); - socket.set_onclose(Some(close_callback.as_ref().unchecked_ref())); - - let callbacks = SendWrapper::new(( - open_callback, - message_callback, - error_callback, - close_callback, - )); - inner.lock().expect("Mutex poised; qed").callbacks = Some(callbacks); - - Ok(Self { inner }) - } -} - -impl AsyncRead for WasmSocket { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - let mut inner = self.inner.lock().expect("Mutex is poised; qed"); - inner.waker = Some(cx.waker().clone()); - - match inner.state { - ConnectionState::Error => { - Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, "Socket error"))) - } - ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())), - ConnectionState::Connecting => Poll::Pending, - ConnectionState::Opened => { - if inner.data.is_empty() { - return Poll::Pending; - } - - let n = inner.data.len().min(buf.len()); - for k in buf.iter_mut().take(n) { - *k = inner.data.pop_front().expect("Buffer non empty; qed"); - } - Poll::Ready(Ok(n)) - } - } - } -} - -impl AsyncWrite for WasmSocket { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let mut inner = self.inner.lock().expect("Mutex is poised; qed"); - inner.waker = Some(cx.waker().clone()); - - match inner.state { - ConnectionState::Error => { - Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, "Socket error"))) - } - ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())), - ConnectionState::Connecting => Poll::Pending, - ConnectionState::Opened => match inner.socket.send_with_u8_array(buf) { - Ok(()) => Poll::Ready(Ok(buf.len())), - Err(err) => Poll::Ready(Err(io::Error::new( - io::ErrorKind::Other, - format!("Write error: {err:?}"), - ))), - }, - } - } - - fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } -} - -impl Drop for WasmSocket { - fn drop(&mut self) { - let inner = self.inner.lock().expect("Mutex is poised; qed"); - - if inner.state == ConnectionState::Opened { - let _ = inner.socket.close(); - } - } -} diff --git a/subxt/src/client/lightclient/rpc.rs b/subxt/src/client/lightclient/rpc.rs index 1c3fdfa9ff..4d675db6b9 100644 --- a/subxt/src/client/lightclient/rpc.rs +++ b/subxt/src/client/lightclient/rpc.rs @@ -2,33 +2,22 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use super::{ - background::{BackgroundTask, FromSubxt, MethodResponse}, - LightClientError, -}; +use super::LightClientError; use crate::{ error::{Error, RpcError}, rpc::{RpcClientT, RpcFuture, RpcSubscription}, }; -use futures::{stream::StreamExt, Stream}; +use futures::{Stream, StreamExt}; use serde_json::value::RawValue; -// use smoldot_light::{platform::default::DefaultPlatform as Platform, ChainId}; -use smoldot_light::ChainId; use std::pin::Pin; -use tokio::sync::{mpsc, mpsc::error::SendError, oneshot}; +use subxt_lightclient::{AddChainConfig, ChainId, LightClientRpcError}; use tokio_stream::wrappers::UnboundedReceiverStream; -use super::platform::default::SubxtPlatform as Platform; - pub const LOG_TARGET: &str = "light-client"; /// The light-client RPC implementation that is used to connect with the chain. #[derive(Clone)] -pub struct LightClientRpc { - /// Communicate with the backend task that multiplexes the responses - /// back to the frontend. - to_backend: mpsc::UnboundedSender, -} +pub struct LightClientRpc(subxt_lightclient::LightClientRpc); impl LightClientRpc { /// Constructs a new [`LightClientRpc`], providing the chain specification. @@ -42,83 +31,12 @@ impl LightClientRpc { /// /// Panics if being called outside of `tokio` runtime context. pub fn new( - config: smoldot_light::AddChainConfig<'_, (), impl Iterator>, + config: AddChainConfig<'_, (), impl Iterator>, ) -> Result { - tracing::trace!(target: LOG_TARGET, "Create light client"); - - let mut client = smoldot_light::Client::new(Platform::new()); - - let smoldot_light::AddChainSuccess { - chain_id, - json_rpc_responses, - } = client - .add_chain(config) - .map_err(|err| LightClientError::AddChainError(err.to_string()))?; - - let (to_backend, backend) = mpsc::unbounded_channel(); - - // `json_rpc_responses` can only be `None` if we had passed `json_rpc: Disabled`. - let rpc_responses = json_rpc_responses.expect("Light client RPC configured; qed"); - - let future = async move { - let mut task = BackgroundTask::new(client, chain_id); - task.start_task(backend, rpc_responses).await; - }; + let rpc = subxt_lightclient::LightClientRpc::new(config) + .map_err(|err| LightClientError::Rpc(err))?; - #[cfg(not(feature = "unstable-light-client-wasm"))] - tokio::spawn(future); - #[cfg(feature = "unstable-light-client-wasm")] - wasm_bindgen_futures::spawn_local(future); - - Ok(LightClientRpc { to_backend }) - } - - /// Submits an RPC method request to the light-client. - /// - /// This method sends a request to the light-client to execute an RPC method with the provided parameters. - /// The parameters are parsed into a valid JSON object in the background. - fn method_request( - &self, - method: String, - params: String, - ) -> Result, SendError> { - let (sender, receiver) = oneshot::channel(); - - self.to_backend.send(FromSubxt::Request { - method, - params, - sender, - })?; - - Ok(receiver) - } - - /// Makes an RPC subscription call to the light-client. - /// - /// This method sends a request to the light-client to establish an RPC subscription with the provided parameters. - /// The parameters are parsed into a valid JSON object in the background. - fn subscription_request( - &self, - method: String, - params: String, - ) -> Result< - ( - oneshot::Receiver, - mpsc::UnboundedReceiver>, - ), - SendError, - > { - let (sub_id, sub_id_rx) = oneshot::channel(); - let (sender, receiver) = mpsc::unbounded_channel(); - - self.to_backend.send(FromSubxt::Subscription { - method, - params, - sub_id, - sender, - })?; - - Ok((sub_id_rx, receiver)) + Ok(LightClientRpc(rpc)) } } @@ -140,6 +58,7 @@ impl RpcClientT for LightClientRpc { // Fails if the background is closed. let rx = client + .0 .method_request(method.to_string(), params) .map_err(|_| RpcError::ClientError(Box::new(LightClientError::BackgroundClosed)))?; @@ -179,6 +98,7 @@ impl RpcClientT for LightClientRpc { // Fails if the background is closed. let (sub_id, notif) = client + .0 .subscription_request(sub.to_string(), params) .map_err(|_| RpcError::ClientError(Box::new(LightClientError::BackgroundClosed)))?; @@ -187,7 +107,9 @@ impl RpcClientT for LightClientRpc { .await .map_err(|_| RpcError::ClientError(Box::new(LightClientError::BackgroundClosed)))? .map_err(|err| { - RpcError::ClientError(Box::new(LightClientError::Request(err.to_string()))) + RpcError::ClientError(Box::new(LightClientError::Rpc( + LightClientRpcError::Request(err.to_string()), + ))) })?; let sub_id = result diff --git a/subxt/src/client/mod.rs b/subxt/src/client/mod.rs index 62c265f9e8..b2cc087d34 100644 --- a/subxt/src/client/mod.rs +++ b/subxt/src/client/mod.rs @@ -11,10 +11,7 @@ mod offline_client; mod online_client; -#[cfg(any( - feature = "unstable-light-client", - feature = "unstable-light-client-wasm" -))] +#[cfg(feature = "unstable-light-client")] mod lightclient; pub use offline_client::{OfflineClient, OfflineClientT}; @@ -25,8 +22,5 @@ pub use online_client::{ #[cfg(feature = "jsonrpsee")] pub use online_client::default_rpc_client; -#[cfg(any( - feature = "unstable-light-client", - feature = "unstable-light-client-wasm" -))] +#[cfg(feature = "unstable-light-client")] pub use lightclient::{LightClient, LightClientBuilder, LightClientError}; diff --git a/subxt/src/error/mod.rs b/subxt/src/error/mod.rs index e6b468d9a1..c47e27babc 100644 --- a/subxt/src/error/mod.rs +++ b/subxt/src/error/mod.rs @@ -8,10 +8,7 @@ mod dispatch_error; use core::fmt::Debug; -#[cfg(any( - feature = "unstable-light-client", - feature = "unstable-light-client-wasm" -))] +#[cfg(feature = "unstable-light-client")] pub use crate::client::LightClientError; // Re-export dispatch error types: @@ -71,10 +68,7 @@ pub enum Error { #[error("An error occurred but it could not be decoded: {0:?}")] Unknown(Vec), /// Light client error. - #[cfg(any( - feature = "unstable-light-client", - feature = "unstable-light-client-wasm" - ))] + #[cfg(feature = "unstable-light-client")] #[error("An error occurred but it could not be decoded: {0:?}")] LightClient(#[from] LightClientError), /// Other error. diff --git a/subxt/src/rpc/types.rs b/subxt/src/rpc/types.rs index c12c8d34df..2500507da0 100644 --- a/subxt/src/rpc/types.rs +++ b/subxt/src/rpc/types.rs @@ -239,8 +239,6 @@ pub type SystemProperties = serde_json::Map; /// /// This is copied from `sp-transaction-pool` to avoid a dependency on that crate. Therefore it /// must be kept compatible with that type from the target substrate version. -/// -/// Substrate produces `camelCase` events, while smoldot produces `CamelCase` events. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum SubstrateTxStatus { diff --git a/testing/wasm-tests/Cargo.lock b/testing/wasm-tests/Cargo.lock index 666ca51daf..362b0ff5ab 100644 --- a/testing/wasm-tests/Cargo.lock +++ b/testing/wasm-tests/Cargo.lock @@ -2142,13 +2142,9 @@ dependencies = [ "either", "frame-metadata", "futures", - "futures-timer", - "futures-util", "getrandom", "hex", "impl-serde", - "instant", - "js-sys", "jsonrpsee", "parity-scale-codec", "primitive-types", @@ -2157,21 +2153,15 @@ dependencies = [ "scale-encode", "scale-info", "scale-value", - "send_wrapper 0.6.0", "serde", "serde_json", - "smoldot", - "smoldot-light", "sp-core-hashing", + "subxt-lightclient", "subxt-macro", "subxt-metadata", "thiserror", - "tokio", "tokio-stream", "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", ] [[package]] @@ -2192,6 +2182,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "subxt-lightclient" +version = "0.29.0" +dependencies = [ + "futures", + "futures-timer", + "futures-util", + "getrandom", + "instant", + "js-sys", + "send_wrapper 0.6.0", + "serde", + "serde_json", + "smoldot", + "smoldot-light", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "subxt-macro" version = "0.29.0" diff --git a/testing/wasm-tests/Cargo.toml b/testing/wasm-tests/Cargo.toml index fa44b9e1c0..af62c500f3 100644 --- a/testing/wasm-tests/Cargo.toml +++ b/testing/wasm-tests/Cargo.toml @@ -15,4 +15,4 @@ futures-util = "0.3.28" # This crate is not a part of the workspace, because it # requires the "jsonrpsee web unstable-light-client" features to be enabled, which we don't # want enabled for workspace builds in general. -subxt = { path = "../../subxt", default-features = false, features = ["web", "jsonrpsee", "unstable-light-client-wasm"] } +subxt = { path = "../../subxt", default-features = false, features = ["web", "jsonrpsee", "unstable-light-client"] } From 2b99fd474c64f571ea0563d1a3918ad40e0c9bf8 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 27 Jun 2023 14:33:53 +0300 Subject: [PATCH 23/36] Apply cargo fmt Signed-off-by: Alexandru Vasile --- subxt/src/client/lightclient/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subxt/src/client/lightclient/mod.rs b/subxt/src/client/lightclient/mod.rs index 4d8f3130d2..c77ffa4fc2 100644 --- a/subxt/src/client/lightclient/mod.rs +++ b/subxt/src/client/lightclient/mod.rs @@ -7,13 +7,13 @@ mod builder; mod rpc; -use derivative::Derivative; use crate::{ client::{OfflineClientT, OnlineClientT}, config::Config, OnlineClient, }; pub use builder::LightClientBuilder; +use derivative::Derivative; use subxt_lightclient::LightClientRpcError; /// Light client error. From a3eedc6651f7702f93e80dd10dc5769dc4331b49 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 27 Jun 2023 14:58:06 +0300 Subject: [PATCH 24/36] Enable default:native feature for cargo check Signed-off-by: Alexandru Vasile --- Cargo.toml | 2 +- lightclient/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d2bf624998..f8e6cfdd1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,7 +106,7 @@ subxt-macro = { version = "0.29.0", path = "macro" } subxt-metadata = { version = "0.29.0", path = "metadata" } subxt-codegen = { version = "0.29.0", path = "codegen" } subxt-signer = { version = "0.29.0", path = "signer" } -subxt-lightclient = { version = "0.29.0", path = "lightclient" } +subxt-lightclient = { version = "0.29.0", path = "lightclient", default-features = false } test-runtime = { path = "testing/test-runtime" } substrate-runner = { path = "testing/substrate-runner" } diff --git a/lightclient/Cargo.toml b/lightclient/Cargo.toml index 1c415fa59b..1c70740062 100644 --- a/lightclient/Cargo.toml +++ b/lightclient/Cargo.toml @@ -15,7 +15,7 @@ description = "Light Client for chain interaction" keywords = ["parity", "substrate", "blockchain"] [features] -default = [] +default = ["native"] # Enable this for native (ie non web/wasm builds). # Exactly 1 of "web" and "native" is expected. From 2dc13846ddfed8a1a1f2103b4350e52c6a4ebe0f Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 27 Jun 2023 15:08:14 +0300 Subject: [PATCH 25/36] ci: Extra step for subxt-lightclient similar to signer crate Signed-off-by: Alexandru Vasile --- .github/workflows/rust.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9f7a0de611..8f0aaa9507 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -72,9 +72,13 @@ jobs: - name: Cargo check subxt-signer run: cargo check -p subxt-signer + # We can't enable web features here, so no cargo hack. + - name: Cargo check subxt-lightclient + run: cargo check -p subxt-lightclient + # Next, check each other package in isolation. - name: Cargo hack; check each feature/crate on its own - run: cargo hack --exclude subxt --exclude subxt-signer --exclude-all-features --each-feature check --workspace + run: cargo hack --exclude subxt --exclude subxt-signer --exclude subxt-lightclient --exclude-all-features --each-feature check --workspace fmt: name: Cargo fmt From 6223e05dc098d2777e907e14dd36ae9d8f4f46c2 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 28 Jun 2023 19:25:21 +0300 Subject: [PATCH 26/36] Remove native platform code and use smoldot instead Signed-off-by: Alexandru Vasile --- lightclient/Cargo.toml | 4 - lightclient/src/background.rs | 6 +- lightclient/src/client.rs | 4 +- lightclient/src/platform/default.rs | 5 +- lightclient/src/platform/mod.rs | 35 +++++- lightclient/src/platform/native.rs | 161 ---------------------------- 6 files changed, 38 insertions(+), 177 deletions(-) delete mode 100644 lightclient/src/platform/native.rs diff --git a/lightclient/Cargo.toml b/lightclient/Cargo.toml index 1c70740062..f27832048a 100644 --- a/lightclient/Cargo.toml +++ b/lightclient/Cargo.toml @@ -20,15 +20,11 @@ default = ["native"] # Enable this for native (ie non web/wasm builds). # Exactly 1 of "web" and "native" is expected. native = [ - "smoldot", "smoldot-light/std", "tokio-stream", "tokio/sync", "tokio/rt", - "tokio/net", - "tokio-util/compat", "futures-util", - "either", ] # Enable this for web/wasm builds. diff --git a/lightclient/src/background.rs b/lightclient/src/background.rs index 3f3d6351d7..f9169cc244 100644 --- a/lightclient/src/background.rs +++ b/lightclient/src/background.rs @@ -9,7 +9,7 @@ use serde_json::value::RawValue; use std::{collections::HashMap, str::FromStr}; use tokio::sync::{mpsc, oneshot}; -use super::platform::default::SubxtPlatform as Platform; +use super::platform::PlatformType; use super::LightClientRpcError; use smoldot_light::ChainId; @@ -51,7 +51,7 @@ pub enum FromSubxt { /// Background task data. pub struct BackgroundTask { /// Smoldot light client implementation that leverages the exposed platform. - client: smoldot_light::Client, + client: smoldot_light::Client, /// The ID of the chain used to identify the chain protocol (ie. substrate). /// /// Note: A single chain is supported for a client. This aligns with the subxt's @@ -80,7 +80,7 @@ pub struct BackgroundTask { impl BackgroundTask { /// Constructs a new [`BackgroundTask`]. - pub fn new(client: smoldot_light::Client, chain_id: ChainId) -> BackgroundTask { + pub fn new(client: smoldot_light::Client, chain_id: ChainId) -> BackgroundTask { BackgroundTask { client, chain_id, diff --git a/lightclient/src/client.rs b/lightclient/src/client.rs index 09c84f924d..62bd65172b 100644 --- a/lightclient/src/client.rs +++ b/lightclient/src/client.rs @@ -9,7 +9,7 @@ use super::{ use serde_json::value::RawValue; use tokio::sync::{mpsc, mpsc::error::SendError, oneshot}; -use super::platform::default::SubxtPlatform as Platform; +use super::platform::build_platform; pub const LOG_TARGET: &str = "light-client"; @@ -37,7 +37,7 @@ impl LightClientRpc { ) -> Result { tracing::trace!(target: LOG_TARGET, "Create light client"); - let mut client = smoldot_light::Client::new(Platform::new()); + let mut client = smoldot_light::Client::new(build_platform()); let smoldot_light::AddChainSuccess { chain_id, diff --git a/lightclient/src/platform/default.rs b/lightclient/src/platform/default.rs index da9db50763..cf84a314e3 100644 --- a/lightclient/src/platform/default.rs +++ b/lightclient/src/platform/default.rs @@ -11,9 +11,6 @@ use smoldot_light::platform::{ }; use std::{io::IoSlice, pin::Pin}; -#[cfg(feature = "native")] -use super::native as platform_impl; -#[cfg(feature = "web")] use super::wasm as platform_impl; use platform_impl::{StreamReadBuffer, StreamWriteBuffer}; @@ -22,6 +19,8 @@ use platform_impl::{StreamReadBuffer, StreamWriteBuffer}; /// /// This implementation is a conversion of the implementation from the smoldot: /// https://github.com/smol-dot/smoldot/blob/f49ce4ea6a325c444ab6ad37d3ab5558edf0d541/light-base/src/platform/default.rs#L52. +/// +/// This platform will evolve over time and we'll need to keep this code in sync. #[derive(Clone)] pub struct SubxtPlatform {} diff --git a/lightclient/src/platform/mod.rs b/lightclient/src/platform/mod.rs index 133fc8e554..6f52a34a52 100644 --- a/lightclient/src/platform/mod.rs +++ b/lightclient/src/platform/mod.rs @@ -2,12 +2,39 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -pub mod default; - -#[cfg(feature = "native")] -mod native; +//! Default platform for WASM environments. +#[cfg(feature = "web")] +mod default; #[cfg(feature = "web")] mod wasm; #[cfg(feature = "web")] mod wasm_socket; + +pub use helpers::{build_platform, PlatformType}; + +#[cfg(feature = "native")] +mod helpers { + use smoldot_light::platform::default::DefaultPlatform as Platform; + use std::sync::Arc; + + pub type PlatformType = Arc; + + pub fn build_platform() -> PlatformType { + Platform::new( + "subxt-light-client".into(), + env!("CARGO_PKG_VERSION").into(), + ) + } +} + +#[cfg(feature = "web")] +mod helpers { + use super::default::SubxtPlatform as Platform; + + pub type PlatformType = Platform; + + pub fn build_platform() -> PlatformType { + Platform::new() + } +} diff --git a/lightclient/src/platform/native.rs b/lightclient/src/platform/native.rs deleted file mode 100644 index 64006f026e..0000000000 --- a/lightclient/src/platform/native.rs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019-2023 Parity Technologies (UK) Ltd. -// This file is dual-licensed as Apache-2.0 or GPL-3.0. -// see LICENSE for license details. - -//! Native implementation for the light client's platform using -//! `tokio::net::TcpStream` for connections. - -use core::time::Duration; -use futures_util::{future, FutureExt}; -use smoldot::libp2p::{multiaddr::ProtocolRef, websocket}; -use smoldot_light::platform::{ConnectError, PlatformConnection}; -use std::{ - collections::VecDeque, - net::{IpAddr, SocketAddr}, -}; -use tokio::net::TcpStream; -use tokio_util::compat::{Compat, TokioAsyncReadCompatExt}; - -pub fn spawn(task: future::BoxFuture<'static, ()>) { - tokio::spawn(task); -} - -pub fn now_from_unix_epoch() -> Duration { - // Intentionally panic if the time is configured earlier than the UNIX EPOCH. - std::time::UNIX_EPOCH.elapsed().unwrap_or_else(|_| { - panic!("Invalid systime cannot be configured earlier than `UNIX_EPOCH`") - }) -} - -pub type Instant = std::time::Instant; - -pub fn now() -> Instant { - Instant::now() -} - -pub type Delay = future::BoxFuture<'static, ()>; - -pub fn sleep(duration: Duration) -> Delay { - tokio::time::sleep(duration).boxed() -} - -pub type CompatTcpStream = Compat; -pub type Socket = future::Either>; - -pub struct Stream { - pub socket: Socket, - /// Read and write buffers of the connection, or `None` if the socket has been reset. - pub buffers: Option<(StreamReadBuffer, StreamWriteBuffer)>, -} - -pub enum StreamReadBuffer { - Open { - buffer: Vec, - cursor: std::ops::Range, - }, - Closed, -} - -pub enum StreamWriteBuffer { - Open { - buffer: VecDeque, - must_flush: bool, - must_close: bool, - }, - Closed, -} - -pub async fn connect<'a>( - proto1: ProtocolRef<'a>, - proto2: ProtocolRef<'a>, - proto3: Option>, -) -> Result, ConnectError> { - // Ensure ahead of time that the multiaddress is supported. - let (addr, host_if_websocket) = match (&proto1, &proto2, &proto3) { - (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), None) => ( - either::Left(SocketAddr::new(IpAddr::V4((*ip).into()), *port)), - None, - ), - (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), None) => ( - either::Left(SocketAddr::new(IpAddr::V6((*ip).into()), *port)), - None, - ), - (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { - let addr = SocketAddr::new(IpAddr::V4((*ip).into()), *port); - (either::Left(addr), Some(addr.to_string())) - } - (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { - let addr = SocketAddr::new(IpAddr::V6((*ip).into()), *port); - (either::Left(addr), Some(addr.to_string())) - } - ( - ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), - ProtocolRef::Tcp(port), - None, - ) => (either::Right((addr.to_string(), *port)), None), - ( - ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), - ProtocolRef::Tcp(port), - Some(ProtocolRef::Ws), - ) => ( - either::Right((addr.to_string(), *port)), - Some(format!("{}:{}", addr, *port)), - ), - _ => { - return Err(ConnectError { - is_bad_addr: true, - message: "Unknown protocols combination".to_string(), - }) - } - }; - - tracing::debug!("Connecting to addr={addr:?}"); - - let tcp_socket = match addr { - either::Left(socket_addr) => tokio::net::TcpStream::connect(socket_addr).await, - either::Right((dns, port)) => tokio::net::TcpStream::connect((&dns[..], port)).await, - }; - - if let Ok(tcp_socket) = &tcp_socket { - let _ = tcp_socket.set_nodelay(true); - } - - let socket: Socket = match (tcp_socket, host_if_websocket) { - (Ok(tcp_socket), Some(host)) => future::Either::Right( - websocket::websocket_client_handshake(websocket::Config { - tcp_socket: tcp_socket.compat(), - host: &host, - url: "/", - }) - .await - .map_err(|err| ConnectError { - message: format!("Failed to negotiate WebSocket: {err}"), - is_bad_addr: false, - })?, - ), - (Ok(tcp_socket), None) => future::Either::Left(tcp_socket.compat()), - (Err(err), _) => { - return Err(ConnectError { - is_bad_addr: false, - message: format!("Failed to reach peer: {err}"), - }) - } - }; - - Ok(PlatformConnection::SingleStreamMultistreamSelectNoiseYamux( - Stream { - socket, - buffers: Some(( - StreamReadBuffer::Open { - buffer: vec![0; 16384], - cursor: 0..0, - }, - StreamWriteBuffer::Open { - buffer: VecDeque::with_capacity(16384), - must_close: false, - must_flush: false, - }, - )), - }, - )) -} From 33880ccc737f9de59461c28da45ec348166fd2cf Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 29 Jun 2023 11:29:05 +0300 Subject: [PATCH 27/36] codegen: Enable tokio/multi-threads Signed-off-by: Alexandru Vasile --- Cargo.toml | 2 +- codegen/Cargo.toml | 2 +- codegen/src/utils/fetch_metadata.rs | 2 +- testing/wasm-tests/Cargo.lock | 20 ++++++++++++++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f8e6cfdd1f..9dd9c3df7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,7 @@ tokio-stream = "0.1.14" futures-util = "0.3.28" # Light client wasm: -web-sys = { version = "0.3.61", features = [ "BinaryType", "CloseEvent", "MessageEvent", "WebSocket"] } +web-sys = { version = "0.3.61", features = ["BinaryType", "CloseEvent", "MessageEvent", "WebSocket"] } wasm-bindgen = "0.2.84" send_wrapper = "0.6.0" js-sys = "0.3.61" diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 3db79d4829..0b8a810d4b 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -23,7 +23,7 @@ scale-info = { workspace = true } subxt-metadata = { workspace = true } jsonrpsee = { workspace = true, features = ["async-client", "client-ws-transport", "http-client"] } hex = { workspace = true } -tokio = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread"] } thiserror = { workspace = true } [dev-dependencies] diff --git a/codegen/src/utils/fetch_metadata.rs b/codegen/src/utils/fetch_metadata.rs index 3953d0971f..9d49e35ac4 100644 --- a/codegen/src/utils/fetch_metadata.rs +++ b/codegen/src/utils/fetch_metadata.rs @@ -62,7 +62,7 @@ pub fn fetch_metadata_hex_blocking( // Block on some tokio runtime for sync contexts fn tokio_block_on>(fut: Fut) -> T { - tokio::runtime::Builder::new_current_thread() + tokio::runtime::Builder::new_multi_thread() .enable_all() .build() .unwrap() diff --git a/testing/wasm-tests/Cargo.lock b/testing/wasm-tests/Cargo.lock index 362b0ff5ab..089d6f4951 100644 --- a/testing/wasm-tests/Cargo.lock +++ b/testing/wasm-tests/Cargo.lock @@ -837,6 +837,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.3" @@ -1326,6 +1335,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -2339,6 +2358,7 @@ dependencies = [ "bytes", "libc", "mio", + "num_cpus", "pin-project-lite", "socket2", "tokio-macros", From 290651d7792366fda6df4ade5575568a50a6a19f Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 17 Jul 2023 14:50:10 +0300 Subject: [PATCH 28/36] lightclient: Refactor modules Signed-off-by: Alexandru Vasile --- lightclient/src/platform/mod.rs | 6 ++--- .../src/platform/{wasm.rs => wasm_helpers.rs} | 0 .../platform/{default.rs => wasm_platform.rs} | 22 +++++++++---------- 3 files changed, 13 insertions(+), 15 deletions(-) rename lightclient/src/platform/{wasm.rs => wasm_helpers.rs} (100%) rename lightclient/src/platform/{default.rs => wasm_platform.rs} (95%) diff --git a/lightclient/src/platform/mod.rs b/lightclient/src/platform/mod.rs index 6f52a34a52..bfba17c029 100644 --- a/lightclient/src/platform/mod.rs +++ b/lightclient/src/platform/mod.rs @@ -5,9 +5,9 @@ //! Default platform for WASM environments. #[cfg(feature = "web")] -mod default; +mod wasm_helpers; #[cfg(feature = "web")] -mod wasm; +mod wasm_platform; #[cfg(feature = "web")] mod wasm_socket; @@ -30,7 +30,7 @@ mod helpers { #[cfg(feature = "web")] mod helpers { - use super::default::SubxtPlatform as Platform; + use super::wasm_platform::SubxtPlatform as Platform; pub type PlatformType = Platform; diff --git a/lightclient/src/platform/wasm.rs b/lightclient/src/platform/wasm_helpers.rs similarity index 100% rename from lightclient/src/platform/wasm.rs rename to lightclient/src/platform/wasm_helpers.rs diff --git a/lightclient/src/platform/default.rs b/lightclient/src/platform/wasm_platform.rs similarity index 95% rename from lightclient/src/platform/default.rs rename to lightclient/src/platform/wasm_platform.rs index cf84a314e3..79e90882c8 100644 --- a/lightclient/src/platform/default.rs +++ b/lightclient/src/platform/wasm_platform.rs @@ -11,11 +11,9 @@ use smoldot_light::platform::{ }; use std::{io::IoSlice, pin::Pin}; -use super::wasm as platform_impl; +use super::wasm_helpers::{StreamReadBuffer, StreamWriteBuffer}; -use platform_impl::{StreamReadBuffer, StreamWriteBuffer}; - -/// Subxt plaform implementation for native and wasm. +/// Subxt plaform implementation for wasm. /// /// This implementation is a conversion of the implementation from the smoldot: /// https://github.com/smol-dot/smoldot/blob/f49ce4ea6a325c444ab6ad37d3ab5558edf0d541/light-base/src/platform/default.rs#L52. @@ -31,11 +29,11 @@ impl SubxtPlatform { } impl PlatformRef for SubxtPlatform { - type Delay = platform_impl::Delay; + type Delay = super::wasm_helpers::Delay; type Yield = future::Ready<()>; - type Instant = platform_impl::Instant; + type Instant = super::wasm_helpers::Instant; type Connection = std::convert::Infallible; - type Stream = platform_impl::Stream; + type Stream = super::wasm_helpers::Stream; type ConnectFuture = future::BoxFuture< 'static, Result, ConnectError>, @@ -45,15 +43,15 @@ impl PlatformRef for SubxtPlatform { future::Pending>; fn now_from_unix_epoch(&self) -> Duration { - platform_impl::now_from_unix_epoch() + super::wasm_helpers::now_from_unix_epoch() } fn now(&self) -> Self::Instant { - platform_impl::now() + super::wasm_helpers::now() } fn sleep(&self, duration: Duration) -> Self::Delay { - platform_impl::sleep(duration) + super::wasm_helpers::sleep(duration) } fn sleep_until(&self, when: Self::Instant) -> Self::Delay { @@ -96,7 +94,7 @@ impl PlatformRef for SubxtPlatform { }); } - platform_impl::connect(proto1, proto2, proto3).await + super::wasm_helpers::connect(proto1, proto2, proto3).await }) } @@ -286,7 +284,7 @@ impl PlatformRef for SubxtPlatform { } fn spawn_task(&self, _: std::borrow::Cow, task: future::BoxFuture<'static, ()>) { - platform_impl::spawn(task); + super::wasm_helpers::spawn(task); } fn client_name(&self) -> std::borrow::Cow { From a58f04faf718664cc2e868e630ae1989538b74cc Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 17 Jul 2023 16:38:26 +0300 Subject: [PATCH 29/36] Adjust testing crates Signed-off-by: Alexandru Vasile --- Cargo.toml | 3 +- .../.gitignore | 0 testing/wasm-lightclient-tests/Cargo.lock | 2932 +++++++++++++++++ .../Cargo.toml | 2 +- .../tests/wasm.rs | 10 - testing/wasm-rpc-tests/.gitignore | 1 + .../{wasm-tests => wasm-rpc-tests}/Cargo.lock | 0 testing/wasm-rpc-tests/Cargo.toml | 18 + testing/wasm-rpc-tests/tests/wasm.rs | 40 + 9 files changed, 2994 insertions(+), 12 deletions(-) rename testing/{wasm-tests => wasm-lightclient-tests}/.gitignore (100%) create mode 100644 testing/wasm-lightclient-tests/Cargo.lock rename testing/{wasm-tests => wasm-lightclient-tests}/Cargo.toml (94%) rename testing/{wasm-tests => wasm-lightclient-tests}/tests/wasm.rs (86%) create mode 100644 testing/wasm-rpc-tests/.gitignore rename testing/{wasm-tests => wasm-rpc-tests}/Cargo.lock (100%) create mode 100644 testing/wasm-rpc-tests/Cargo.toml create mode 100644 testing/wasm-rpc-tests/tests/wasm.rs diff --git a/Cargo.toml b/Cargo.toml index 9dd9c3df7e..87f8433114 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,8 @@ members = [ # exclusive feature flags and thus can't compile with the # workspace: exclude = [ - "testing/wasm-tests", + "testing/wasm-rpc-tests", + "testing/wasm-lightclient-tests", "signer/wasm-tests", "examples/wasm-example" ] diff --git a/testing/wasm-tests/.gitignore b/testing/wasm-lightclient-tests/.gitignore similarity index 100% rename from testing/wasm-tests/.gitignore rename to testing/wasm-lightclient-tests/.gitignore diff --git a/testing/wasm-lightclient-tests/Cargo.lock b/testing/wasm-lightclient-tests/Cargo.lock new file mode 100644 index 0000000000..0eb8009dca --- /dev/null +++ b/testing/wasm-lightclient-tests/Cargo.lock @@ -0,0 +1,2932 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes-gcm" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc3be92e19a7ef47457b8e6f90707e12b6ac5d20c6f3866584fa3be0787d839f" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +dependencies = [ + "nodrop", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-lock" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-trait" +version = "0.1.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +dependencies = [ + "serde", +] + +[[package]] +name = "bip39" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +dependencies = [ + "bitcoin_hashes", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake2-rfc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" +dependencies = [ + "arrayvec 0.4.12", + "constant_time_eq 0.1.5", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.2.6", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chacha20" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "chacha20poly1305" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +dependencies = [ + "cfg-if", + "fiat-crypto", + "packed_simd_2", + "platforms", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-ng" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.6.4", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" +dependencies = [ + "darling_core 0.20.1", + "darling_macro 0.20.1", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.18", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" +dependencies = [ + "darling_core 0.20.1", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "frame-metadata" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gloo-net" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-utils" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "h2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "serde", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +dependencies = [ + "http", + "hyper", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "webpki-roots", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap-nostd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "intx" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f38a50a899dc47a6d0ed5508e7f601a2e34c3a85303514b5d137f3c10a0c75" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonrpsee" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" +dependencies = [ + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-http-client", + "jsonrpsee-types", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965de52763f2004bc91ac5bcec504192440f0b568a5d621c59d9dbd6f886c3fb" +dependencies = [ + "anyhow", + "futures-channel", + "futures-timer", + "futures-util", + "gloo-net", + "http", + "jsonrpsee-core", + "jsonrpsee-types", + "pin-project", + "rustls-native-certs", + "soketto", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "webpki-roots", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e70b4439a751a5de7dd5ed55eacff78ebf4ffe0fc009cb1ebb11417f5b536b" +dependencies = [ + "anyhow", + "async-lock", + "async-trait", + "beef", + "futures-channel", + "futures-timer", + "futures-util", + "hyper", + "jsonrpsee-types", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen-futures", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls", + "jsonrpsee-core", + "jsonrpsee-types", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd522fe1ce3702fd94812965d7bb7a3364b1c9aba743944c5a00529aae80f8c" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.146" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" + +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" + +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "lru" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if", + "libm 0.1.4", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2287753623c76f953acd29d15d8100bcab84d29db78fb6f352adb3c53e83b967" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b6937b5e67bfba3351b87b040d48352a2fcb6ad72f81855412ce97b45c8f110" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "pbkdf2" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pin-project" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + +[[package]] +name = "poly1305" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64 0.21.2", +] + +[[package]] +name = "ruzstd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc" +dependencies = [ + "byteorder", + "thiserror-core", + "twox-hash", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "scale-bits" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd7aca73785181cc41f0bbe017263e682b585ca660540ba569133901d013ecf" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "scale-decode" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0459d00b0dbd2e765009924a78ef36b2ff7ba116292d732f00eb0ed8e465d15" +dependencies = [ + "parity-scale-codec", + "primitive-types", + "scale-bits", + "scale-decode-derive", + "scale-info", + "smallvec", + "thiserror", +] + +[[package]] +name = "scale-decode-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4391f0dfbb6690f035f6d2a15d6a12f88cc5395c36bcc056db07ffa2a90870ec" +dependencies = [ + "darling 0.14.4", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scale-encode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0401b7cdae8b8aa33725f3611a051358d5b32887ecaa0fda5953a775b2d4d76" +dependencies = [ + "parity-scale-codec", + "primitive-types", + "scale-bits", + "scale-encode-derive", + "scale-info", + "smallvec", + "thiserror", +] + +[[package]] +name = "scale-encode-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "316e0fb10ec0fee266822bd641bab5e332a4ab80ef8c5b5ff35e5401a394f5a6" +dependencies = [ + "darling 0.14.4", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scale-info" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad560913365790f17cbf12479491169f01b9d46d29cfc7422bf8c64bdc61b731" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", + "serde", +] + +[[package]] +name = "scale-info-derive" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19df9bd9ace6cc2fe19387c96ce677e823e07d017ceed253e7bb3d1d1bd9c73b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scale-value" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2096d36e94ce9bf87d8addb752423b6b19730dc88edd7cc452bb2b90573f7a7" +dependencies = [ + "base58", + "blake2", + "either", + "frame-metadata", + "parity-scale-codec", + "scale-bits", + "scale-decode", + "scale-encode", + "scale-info", + "serde", + "thiserror", + "yap", +] + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "schnorrkel" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "844b7645371e6ecdf61ff246ba1958c29e802881a749ae3fb1993675d210d28d" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "curve25519-dalek-ng", + "merlin", + "rand_core 0.6.4", + "sha2 0.9.9", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "serde_json" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "smoldot" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cce5e2881b30bad7ef89f383a816ad0b22c45915911f28499026de4a76d20ee" +dependencies = [ + "arrayvec 0.7.4", + "async-lock", + "atomic", + "base64 0.21.2", + "bip39", + "blake2-rfc", + "bs58", + "crossbeam-queue", + "derive_more", + "ed25519-zebra", + "either", + "event-listener", + "fnv", + "futures-channel", + "futures-util", + "hashbrown 0.14.0", + "hex", + "hmac 0.12.1", + "itertools", + "libsecp256k1", + "merlin", + "no-std-net", + "nom", + "num-bigint", + "num-rational", + "num-traits", + "pbkdf2", + "rand", + "rand_chacha", + "ruzstd", + "schnorrkel", + "serde", + "serde_json", + "sha2 0.10.7", + "siphasher", + "slab", + "smallvec", + "snow", + "tiny-keccak", + "twox-hash", + "wasmi", +] + +[[package]] +name = "smoldot-light" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2f7b4687b83ff244ef6137735ed5716ad37dcdf3ee16c4eb1a32fb9808fa47" +dependencies = [ + "async-lock", + "blake2-rfc", + "derive_more", + "either", + "event-listener", + "fnv", + "futures-channel", + "futures-util", + "hashbrown 0.14.0", + "hex", + "itertools", + "log", + "lru", + "rand", + "serde", + "serde_json", + "siphasher", + "slab", + "smoldot", +] + +[[package]] +name = "snow" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" +dependencies = [ + "aes-gcm", + "blake2", + "chacha20poly1305", + "curve25519-dalek 4.0.0-rc.1", + "rand_core 0.6.4", + "rustc_version", + "sha2 0.10.7", + "subtle", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "soketto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +dependencies = [ + "base64 0.13.1", + "bytes", + "futures", + "httparse", + "log", + "rand", + "sha-1", +] + +[[package]] +name = "sp-core-hashing" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee599a8399448e65197f9a6cee338ad192e9023e35e31f22382964c3c174c68" +dependencies = [ + "blake2b_simd", + "byteorder", + "digest 0.10.7", + "sha2 0.10.7", + "sha3", + "sp-std", + "twox-hash", +] + +[[package]] +name = "sp-std" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53458e3c57df53698b3401ec0934bea8e8cfce034816873c0b0abbd83d7bac0d" + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + +[[package]] +name = "subxt" +version = "0.29.0" +dependencies = [ + "base58", + "blake2", + "derivative", + "either", + "frame-metadata", + "futures", + "getrandom", + "hex", + "impl-serde", + "jsonrpsee", + "parity-scale-codec", + "primitive-types", + "scale-bits", + "scale-decode", + "scale-encode", + "scale-info", + "scale-value", + "serde", + "serde_json", + "sp-core-hashing", + "subxt-lightclient", + "subxt-macro", + "subxt-metadata", + "thiserror", + "tokio-stream", + "tracing", +] + +[[package]] +name = "subxt-codegen" +version = "0.29.0" +dependencies = [ + "frame-metadata", + "heck", + "hex", + "jsonrpsee", + "parity-scale-codec", + "proc-macro2", + "quote", + "scale-info", + "subxt-metadata", + "syn 2.0.18", + "thiserror", + "tokio", +] + +[[package]] +name = "subxt-lightclient" +version = "0.29.0" +dependencies = [ + "futures", + "futures-timer", + "futures-util", + "getrandom", + "instant", + "js-sys", + "send_wrapper 0.6.0", + "serde", + "serde_json", + "smoldot", + "smoldot-light", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "subxt-macro" +version = "0.29.0" +dependencies = [ + "darling 0.20.1", + "proc-macro-error", + "subxt-codegen", + "syn 2.0.18", +] + +[[package]] +name = "subxt-metadata" +version = "0.29.0" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", + "sp-core-hashing", + "thiserror", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-core" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" +dependencies = [ + "thiserror-core-impl", +] + +[[package]] +name = "thiserror-core-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +dependencies = [ + "autocfg", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml_datetime" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" + +[[package]] +name = "toml_edit" +version = "0.19.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + +[[package]] +name = "tracing-wasm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" +dependencies = [ + "tracing", + "tracing-subscriber", + "wasm-bindgen", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "digest 0.10.7", + "rand", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "universal-hash" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.18", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wasm-lightclient-tests" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "futures-util", + "serde_json", + "subxt", + "tracing", + "tracing-wasm", + "wasm-bindgen-test", +] + +[[package]] +name = "wasmi" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51fb5c61993e71158abf5bb863df2674ca3ec39ed6471c64f07aeaf751d67b4" +dependencies = [ + "intx", + "smallvec", + "spin 0.9.8", + "wasmi_arena", + "wasmi_core", + "wasmparser-nostd", +] + +[[package]] +name = "wasmi_arena" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "401c1f35e413fac1846d4843745589d9ec678977ab35a384db8ae7830525d468" + +[[package]] +name = "wasmi_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624e6333e861ef49095d2d678b76ebf30b06bf37effca845be7e5b87c90071b7" +dependencies = [ + "downcast-rs", + "libm 0.2.7", + "num-traits", + "paste", +] + +[[package]] +name = "wasmparser-nostd" +version = "0.100.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9157cab83003221bfd385833ab587a039f5d6fa7304854042ba358a3b09e0724" +dependencies = [ + "indexmap-nostd", +] + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[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.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2a7eb6d82a11e4d0b8e6bda8347169aff4ccd8235d039bba7c47482d977dcf7" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] diff --git a/testing/wasm-tests/Cargo.toml b/testing/wasm-lightclient-tests/Cargo.toml similarity index 94% rename from testing/wasm-tests/Cargo.toml rename to testing/wasm-lightclient-tests/Cargo.toml index af62c500f3..27a9522318 100644 --- a/testing/wasm-tests/Cargo.toml +++ b/testing/wasm-lightclient-tests/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "wasm-tests" +name = "wasm-lightclient-tests" version = "0.1.0" edition = "2021" publish = false diff --git a/testing/wasm-tests/tests/wasm.rs b/testing/wasm-lightclient-tests/tests/wasm.rs similarity index 86% rename from testing/wasm-tests/tests/wasm.rs rename to testing/wasm-lightclient-tests/tests/wasm.rs index 6a02efce54..4cd52e83a8 100644 --- a/testing/wasm-tests/tests/wasm.rs +++ b/testing/wasm-lightclient-tests/tests/wasm.rs @@ -29,16 +29,6 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); // tracing_wasm::set_as_global_default(); // ``` -#[wasm_bindgen_test] -async fn wasm_ws_transport_works() { - let client = subxt::client::OnlineClient::::from_url("ws://127.0.0.1:9944") - .await - .unwrap(); - - let chain = client.rpc().system_chain().await.unwrap(); - assert_eq!(&chain, "Development"); -} - #[wasm_bindgen_test] async fn light_client_works() { // Use a polkadot trusted DNS. diff --git a/testing/wasm-rpc-tests/.gitignore b/testing/wasm-rpc-tests/.gitignore new file mode 100644 index 0000000000..c41cc9e35e --- /dev/null +++ b/testing/wasm-rpc-tests/.gitignore @@ -0,0 +1 @@ +/target \ No newline at end of file diff --git a/testing/wasm-tests/Cargo.lock b/testing/wasm-rpc-tests/Cargo.lock similarity index 100% rename from testing/wasm-tests/Cargo.lock rename to testing/wasm-rpc-tests/Cargo.lock diff --git a/testing/wasm-rpc-tests/Cargo.toml b/testing/wasm-rpc-tests/Cargo.toml new file mode 100644 index 0000000000..47b1758a04 --- /dev/null +++ b/testing/wasm-rpc-tests/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "wasm-rpc-tests" +version = "0.1.0" +edition = "2021" +publish = false + +[dev-dependencies] +wasm-bindgen-test = "0.3.24" +tracing-wasm = "0.2.1" +tracing = "0.1.34" +console_error_panic_hook = "0.1.7" +serde_json = "1" +futures-util = "0.3.28" + +# This crate is not a part of the workspace, because it +# requires the "jsonrpsee web" features to be enabled, which we don't +# want enabled for workspace builds in general. +subxt = { path = "../../subxt", default-features = false, features = ["web", "jsonrpsee"] } diff --git a/testing/wasm-rpc-tests/tests/wasm.rs b/testing/wasm-rpc-tests/tests/wasm.rs new file mode 100644 index 0000000000..2ab59d2b17 --- /dev/null +++ b/testing/wasm-rpc-tests/tests/wasm.rs @@ -0,0 +1,40 @@ +#![cfg(target_arch = "wasm32")] + +use subxt::{config::PolkadotConfig, + client::{LightClient, OfflineClientT, LightClientBuilder}, +}; +use futures_util::StreamExt; +use wasm_bindgen_test::*; + +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + +// Run the tests by calling: +// +// ```text +// wasm-pack test --firefox --headless` +// ``` +// +// You'll need to have a substrate/polkadot node running: +// +// ```bash +// # Polkadot does not accept by default WebSocket connections to the P2P network. +// # Ensure `--listen-addr` is provided with valid ws adddress endpoint. +// # The `--node-key` provides a deterministic p2p address for the node. +// ./polkadot --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws +// ``` +// +// Use the following to enable logs: +// ``` +// console_error_panic_hook::set_once(); +// tracing_wasm::set_as_global_default(); +// ``` + +#[wasm_bindgen_test] +async fn wasm_ws_transport_works() { + let client = subxt::client::OnlineClient::::from_url("ws://127.0.0.1:9944") + .await + .unwrap(); + + let chain = client.rpc().system_chain().await.unwrap(); + assert_eq!(&chain, "Development"); +} From d119ae6b45c71b4e09f16f4646a4c3637fe42223 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 17 Jul 2023 16:39:02 +0300 Subject: [PATCH 30/36] ci: Run light-client WASM tests Signed-off-by: Alexandru Vasile --- .github/workflows/rust.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8f0aaa9507..ffe78991a5 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -264,6 +264,14 @@ jobs: mv substrate ~/.local/bin - name: Run subxt WASM tests + run: | + substrate --dev /dev/null 2>&1 & + wasm-pack test --headless --firefox + wasm-pack test --headless --chrome + pkill substrate + working-directory: testing/wasm-rpc-tests + + - name: Run subxt-lightclient WASM tests run: | # `listen-addr` is used to configure p2p to accept websocket connections instead of TCP. # `node-key` provides a deterministic p2p address. @@ -271,7 +279,7 @@ jobs: wasm-pack test --headless --firefox wasm-pack test --headless --chrome pkill substrate - working-directory: testing/wasm-tests + working-directory: testing/wasm-lightclient-tests - name: Run subxt-signer WASM tests run: | From 95a9c8fb22001aecf9a691b7b8e8d36433aee52a Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 17 Jul 2023 16:42:58 +0300 Subject: [PATCH 31/36] wasm-rpc: Remove light-client imports Signed-off-by: Alexandru Vasile --- testing/wasm-rpc-tests/Cargo.lock | 3 +-- testing/wasm-rpc-tests/tests/wasm.rs | 10 ++-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/testing/wasm-rpc-tests/Cargo.lock b/testing/wasm-rpc-tests/Cargo.lock index 089d6f4951..268f9fa754 100644 --- a/testing/wasm-rpc-tests/Cargo.lock +++ b/testing/wasm-rpc-tests/Cargo.lock @@ -2179,7 +2179,6 @@ dependencies = [ "subxt-macro", "subxt-metadata", "thiserror", - "tokio-stream", "tracing", ] @@ -2660,7 +2659,7 @@ dependencies = [ ] [[package]] -name = "wasm-tests" +name = "wasm-rpc-tests" version = "0.1.0" dependencies = [ "console_error_panic_hook", diff --git a/testing/wasm-rpc-tests/tests/wasm.rs b/testing/wasm-rpc-tests/tests/wasm.rs index 2ab59d2b17..4875e8ab24 100644 --- a/testing/wasm-rpc-tests/tests/wasm.rs +++ b/testing/wasm-rpc-tests/tests/wasm.rs @@ -1,9 +1,6 @@ #![cfg(target_arch = "wasm32")] -use subxt::{config::PolkadotConfig, - client::{LightClient, OfflineClientT, LightClientBuilder}, -}; -use futures_util::StreamExt; +use subxt::{config::PolkadotConfig}; use wasm_bindgen_test::*; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); @@ -17,10 +14,7 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); // You'll need to have a substrate/polkadot node running: // // ```bash -// # Polkadot does not accept by default WebSocket connections to the P2P network. -// # Ensure `--listen-addr` is provided with valid ws adddress endpoint. -// # The `--node-key` provides a deterministic p2p address for the node. -// ./polkadot --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws +// ./polkadot --dev // ``` // // Use the following to enable logs: From 4d4f0856cc47881b524f5823569636f689ff0180 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 17 Jul 2023 16:51:41 +0300 Subject: [PATCH 32/36] testing: Update wasm cargo.lock files Signed-off-by: Alexandru Vasile --- testing/wasm-lightclient-tests/Cargo.lock | 144 ++++++++++++++++------ testing/wasm-rpc-tests/Cargo.lock | 144 ++++++++++++++++------ 2 files changed, 216 insertions(+), 72 deletions(-) diff --git a/testing/wasm-lightclient-tests/Cargo.lock b/testing/wasm-lightclient-tests/Cargo.lock index 0eb8009dca..43753b916c 100644 --- a/testing/wasm-lightclient-tests/Cargo.lock +++ b/testing/wasm-lightclient-tests/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.4.3" @@ -92,7 +107,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -107,6 +122,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", + "object", + "rustc-demangle", +] + [[package]] name = "base58" version = "0.2.0" @@ -486,7 +516,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -508,7 +538,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" dependencies = [ "darling_core 0.20.1", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -616,6 +646,17 @@ name = "frame-metadata" version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "frame-metadata" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cf1549fba25a6fcac22785b61698317d958e96cac72a59102ea45b9ae64692" dependencies = [ "cfg-if", "parity-scale-codec", @@ -673,7 +714,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -749,6 +790,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "gloo-net" version = "0.2.6" @@ -1260,6 +1307,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.8" @@ -1345,6 +1401,15 @@ dependencies = [ "libc", ] +[[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" version = "1.18.0" @@ -1431,7 +1496,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -1530,18 +1595,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -1603,6 +1668,12 @@ dependencies = [ "winapi", ] +[[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" @@ -1743,9 +1814,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad560913365790f17cbf12479491169f01b9d46d29cfc7422bf8c64bdc61b731" +checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" dependencies = [ "bitvec", "cfg-if", @@ -1757,9 +1828,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19df9bd9ace6cc2fe19387c96ce677e823e07d017ceed253e7bb3d1d1bd9c73b" +checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1776,7 +1847,7 @@ dependencies = [ "base58", "blake2", "either", - "frame-metadata", + "frame-metadata 15.1.0", "parity-scale-codec", "scale-bits", "scale-decode", @@ -1871,29 +1942,29 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", @@ -2159,7 +2230,7 @@ dependencies = [ "blake2", "derivative", "either", - "frame-metadata", + "frame-metadata 16.0.0", "futures", "getrandom", "hex", @@ -2187,7 +2258,7 @@ dependencies = [ name = "subxt-codegen" version = "0.29.0" dependencies = [ - "frame-metadata", + "frame-metadata 16.0.0", "heck", "hex", "jsonrpsee", @@ -2196,7 +2267,7 @@ dependencies = [ "quote", "scale-info", "subxt-metadata", - "syn 2.0.18", + "syn 2.0.26", "thiserror", "tokio", ] @@ -2232,14 +2303,14 @@ dependencies = [ "darling 0.20.1", "proc-macro-error", "subxt-codegen", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] name = "subxt-metadata" version = "0.29.0" dependencies = [ - "frame-metadata", + "frame-metadata 16.0.0", "parity-scale-codec", "scale-info", "sp-core-hashing", @@ -2259,9 +2330,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -2311,7 +2382,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -2350,11 +2421,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -2373,7 +2445,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -2456,7 +2528,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -2590,7 +2662,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", "wasm-bindgen-shared", ] @@ -2624,7 +2696,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2928,5 +3000,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] diff --git a/testing/wasm-rpc-tests/Cargo.lock b/testing/wasm-rpc-tests/Cargo.lock index 268f9fa754..1a13c21959 100644 --- a/testing/wasm-rpc-tests/Cargo.lock +++ b/testing/wasm-rpc-tests/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.4.3" @@ -92,7 +107,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -107,6 +122,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", + "object", + "rustc-demangle", +] + [[package]] name = "base58" version = "0.2.0" @@ -486,7 +516,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -508,7 +538,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" dependencies = [ "darling_core 0.20.1", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -616,6 +646,17 @@ name = "frame-metadata" version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "frame-metadata" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cf1549fba25a6fcac22785b61698317d958e96cac72a59102ea45b9ae64692" dependencies = [ "cfg-if", "parity-scale-codec", @@ -673,7 +714,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -749,6 +790,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "gloo-net" version = "0.2.6" @@ -1260,6 +1307,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.8" @@ -1345,6 +1401,15 @@ dependencies = [ "libc", ] +[[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" version = "1.18.0" @@ -1431,7 +1496,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -1530,18 +1595,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -1603,6 +1668,12 @@ dependencies = [ "winapi", ] +[[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" @@ -1743,9 +1814,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad560913365790f17cbf12479491169f01b9d46d29cfc7422bf8c64bdc61b731" +checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" dependencies = [ "bitvec", "cfg-if", @@ -1757,9 +1828,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19df9bd9ace6cc2fe19387c96ce677e823e07d017ceed253e7bb3d1d1bd9c73b" +checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1776,7 +1847,7 @@ dependencies = [ "base58", "blake2", "either", - "frame-metadata", + "frame-metadata 15.1.0", "parity-scale-codec", "scale-bits", "scale-decode", @@ -1871,29 +1942,29 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", @@ -2159,7 +2230,7 @@ dependencies = [ "blake2", "derivative", "either", - "frame-metadata", + "frame-metadata 16.0.0", "futures", "getrandom", "hex", @@ -2186,7 +2257,7 @@ dependencies = [ name = "subxt-codegen" version = "0.29.0" dependencies = [ - "frame-metadata", + "frame-metadata 16.0.0", "heck", "hex", "jsonrpsee", @@ -2195,7 +2266,7 @@ dependencies = [ "quote", "scale-info", "subxt-metadata", - "syn 2.0.18", + "syn 2.0.26", "thiserror", "tokio", ] @@ -2231,14 +2302,14 @@ dependencies = [ "darling 0.20.1", "proc-macro-error", "subxt-codegen", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] name = "subxt-metadata" version = "0.29.0" dependencies = [ - "frame-metadata", + "frame-metadata 16.0.0", "parity-scale-codec", "scale-info", "sp-core-hashing", @@ -2258,9 +2329,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -2310,7 +2381,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -2349,11 +2420,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -2372,7 +2444,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -2455,7 +2527,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] [[package]] @@ -2589,7 +2661,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", "wasm-bindgen-shared", ] @@ -2623,7 +2695,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2927,5 +2999,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.26", ] From 1293210aec15fc051fb36ef4d2a2b1819120911b Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 17 Jul 2023 16:51:52 +0300 Subject: [PATCH 33/36] ci: Spawn substrate node with deterministic p2p address for WASM tests Signed-off-by: Alexandru Vasile --- .github/workflows/rust.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7135a3ef7f..0a7670598b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -265,7 +265,9 @@ jobs: - name: Run subxt WASM tests run: | - substrate --dev /dev/null 2>&1 & + # `listen-addr` is used to configure p2p to accept websocket connections instead of TCP. + # `node-key` provides a deterministic p2p address. + substrate --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws > /dev/null 2>&1 & wasm-pack test --headless --firefox wasm-pack test --headless --chrome pkill substrate From a781435282eafa3cb0ea9426969979e770f8574e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 17 Jul 2023 19:34:06 +0300 Subject: [PATCH 34/36] wasm_socket: Use rc and refcell Signed-off-by: Alexandru Vasile --- lightclient/src/platform/wasm_socket.rs | 63 +++++++++++++------------ 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/lightclient/src/platform/wasm_socket.rs b/lightclient/src/platform/wasm_socket.rs index 661a377c13..bdf3d43a9e 100644 --- a/lightclient/src/platform/wasm_socket.rs +++ b/lightclient/src/platform/wasm_socket.rs @@ -7,9 +7,10 @@ use send_wrapper::SendWrapper; use wasm_bindgen::{prelude::*, JsCast}; use std::{ + cell::RefCell, collections::VecDeque, pin::Pin, - sync::{Arc, Mutex}, + rc::Rc, task::Poll, task::{Context, Waker}, }; @@ -24,7 +25,17 @@ pub enum Error { /// /// This is a rust-based wrapper around browser's WebSocket API. pub struct WasmSocket { - inner: Arc>, + /// Inner data shared between `poll` and web_sys callbacks. + /// + /// This is safe in wasm environments. + inner: SendWrapper>>, + /// This implements `Send` and panics if the value is accessed + /// or dropped from another thread. + /// + /// This is safe in wasm environments. + socket: SendWrapper, + /// In memory callbacks to handle messages from the browser socket. + _callbacks: SendWrapper, } /// The state of the [`WasmSocket`]. @@ -43,17 +54,10 @@ enum ConnectionState { struct InnerWasmSocket { /// The state of the connection. state: ConnectionState, - /// This implements `Send` and panics if the value is accessed - /// or dropped from another thread. - /// - /// This is safe in wasm environments. - socket: SendWrapper, /// Data buffer for the socket. data: VecDeque, /// Waker from `poll_read` / `poll_write`. waker: Option, - /// In memory callbacks to handle messages from the browser socket. - callbacks: Option>, } /// Registered callbacks of the [`WasmSocket`]. @@ -80,18 +84,16 @@ impl WasmSocket { socket.set_binary_type(web_sys::BinaryType::Arraybuffer); - let inner = Arc::new(Mutex::new(InnerWasmSocket { + let inner = Rc::new(RefCell::new(InnerWasmSocket { state: ConnectionState::Connecting, - socket: SendWrapper::new(socket.clone()), data: VecDeque::with_capacity(16384), waker: None, - callbacks: None, })); let open_callback = Closure::::new({ - let inner = inner.clone(); + let inner = Rc::clone(&inner); move || { - let mut inner = inner.lock().expect("Mutex is poised; qed"); + let mut inner = inner.borrow_mut(); inner.state = ConnectionState::Opened; if let Some(waker) = inner.waker.take() { @@ -102,13 +104,13 @@ impl WasmSocket { socket.set_onopen(Some(open_callback.as_ref().unchecked_ref())); let message_callback = Closure::::new({ - let inner = inner.clone(); + let inner = Rc::clone(&inner); move |event: web_sys::MessageEvent| { let Ok(buffer) = event.data().dyn_into::() else { panic!("Unexpected data format {:?}", event.data()); }; - let mut inner = inner.lock().expect("Mutex is poised; qed"); + let mut inner = inner.borrow_mut(); let bytes = js_sys::Uint8Array::new(&buffer).to_vec(); inner.data.extend(bytes.into_iter()); @@ -120,10 +122,10 @@ impl WasmSocket { socket.set_onmessage(Some(message_callback.as_ref().unchecked_ref())); let error_callback = Closure::::new({ - let inner = inner.clone(); + let inner = Rc::clone(&inner); move |_| { // Callback does not provide useful information, signal it back to the stream. - let mut inner = inner.lock().expect("Mutex is poised; qed"); + let mut inner = inner.borrow_mut(); inner.state = ConnectionState::Error; if let Some(waker) = inner.waker.take() { @@ -134,9 +136,9 @@ impl WasmSocket { socket.set_onerror(Some(error_callback.as_ref().unchecked_ref())); let close_callback = Closure::::new({ - let inner = inner.clone(); + let inner = Rc::clone(&inner); move |_| { - let mut inner = inner.lock().expect("Mutex is poised; qed"); + let mut inner = inner.borrow_mut(); inner.state = ConnectionState::Closed; if let Some(waker) = inner.waker.take() { @@ -146,15 +148,18 @@ impl WasmSocket { }); socket.set_onclose(Some(close_callback.as_ref().unchecked_ref())); - let callbacks = SendWrapper::new(( + let callbacks = ( open_callback, message_callback, error_callback, close_callback, - )); - inner.lock().expect("Mutex poised; qed").callbacks = Some(callbacks); + ); - Ok(Self { inner }) + Ok(Self { + inner: SendWrapper::new(inner), + socket: SendWrapper::new(socket), + _callbacks: SendWrapper::new(callbacks), + }) } } @@ -164,7 +169,7 @@ impl AsyncRead for WasmSocket { cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { - let mut inner = self.inner.lock().expect("Mutex is poised; qed"); + let mut inner = self.inner.borrow_mut(); inner.waker = Some(cx.waker().clone()); match inner.state { @@ -194,7 +199,7 @@ impl AsyncWrite for WasmSocket { cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - let mut inner = self.inner.lock().expect("Mutex is poised; qed"); + let mut inner = self.inner.borrow_mut(); inner.waker = Some(cx.waker().clone()); match inner.state { @@ -203,7 +208,7 @@ impl AsyncWrite for WasmSocket { } ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())), ConnectionState::Connecting => Poll::Pending, - ConnectionState::Opened => match inner.socket.send_with_u8_array(buf) { + ConnectionState::Opened => match self.socket.send_with_u8_array(buf) { Ok(()) => Poll::Ready(Ok(buf.len())), Err(err) => Poll::Ready(Err(io::Error::new( io::ErrorKind::Other, @@ -224,10 +229,10 @@ impl AsyncWrite for WasmSocket { impl Drop for WasmSocket { fn drop(&mut self) { - let inner = self.inner.lock().expect("Mutex is poised; qed"); + let inner = self.inner.borrow_mut(); if inner.state == ConnectionState::Opened { - let _ = inner.socket.close(); + let _ = self.socket.close(); } } } From 6c46995e5eb5b0dd7bd43aa685af76972e380fd9 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 18 Jul 2023 13:37:15 +0300 Subject: [PATCH 35/36] wasm_socket: Switch back to Arc> Signed-off-by: Alexandru Vasile --- lightclient/src/platform/wasm_socket.rs | 35 ++++++++++++------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/lightclient/src/platform/wasm_socket.rs b/lightclient/src/platform/wasm_socket.rs index bdf3d43a9e..3d212a3506 100644 --- a/lightclient/src/platform/wasm_socket.rs +++ b/lightclient/src/platform/wasm_socket.rs @@ -7,10 +7,9 @@ use send_wrapper::SendWrapper; use wasm_bindgen::{prelude::*, JsCast}; use std::{ - cell::RefCell, collections::VecDeque, pin::Pin, - rc::Rc, + sync::{Arc, Mutex}, task::Poll, task::{Context, Waker}, }; @@ -24,11 +23,11 @@ pub enum Error { /// Websocket for WASM environments. /// /// This is a rust-based wrapper around browser's WebSocket API. +/// +// Warning: It is not safe to have `Clone` on this structure. pub struct WasmSocket { /// Inner data shared between `poll` and web_sys callbacks. - /// - /// This is safe in wasm environments. - inner: SendWrapper>>, + inner: Arc>, /// This implements `Send` and panics if the value is accessed /// or dropped from another thread. /// @@ -84,16 +83,16 @@ impl WasmSocket { socket.set_binary_type(web_sys::BinaryType::Arraybuffer); - let inner = Rc::new(RefCell::new(InnerWasmSocket { + let inner = Arc::new(Mutex::new(InnerWasmSocket { state: ConnectionState::Connecting, data: VecDeque::with_capacity(16384), waker: None, })); let open_callback = Closure::::new({ - let inner = Rc::clone(&inner); + let inner = inner.clone(); move || { - let mut inner = inner.borrow_mut(); + let mut inner = inner.lock().expect("Mutex is poised; qed"); inner.state = ConnectionState::Opened; if let Some(waker) = inner.waker.take() { @@ -104,13 +103,13 @@ impl WasmSocket { socket.set_onopen(Some(open_callback.as_ref().unchecked_ref())); let message_callback = Closure::::new({ - let inner = Rc::clone(&inner); + let inner = inner.clone(); move |event: web_sys::MessageEvent| { let Ok(buffer) = event.data().dyn_into::() else { panic!("Unexpected data format {:?}", event.data()); }; - let mut inner = inner.borrow_mut(); + let mut inner = inner.lock().expect("Mutex is poised; qed"); let bytes = js_sys::Uint8Array::new(&buffer).to_vec(); inner.data.extend(bytes.into_iter()); @@ -122,10 +121,10 @@ impl WasmSocket { socket.set_onmessage(Some(message_callback.as_ref().unchecked_ref())); let error_callback = Closure::::new({ - let inner = Rc::clone(&inner); + let inner = inner.clone(); move |_| { // Callback does not provide useful information, signal it back to the stream. - let mut inner = inner.borrow_mut(); + let mut inner = inner.lock().expect("Mutex is poised; qed"); inner.state = ConnectionState::Error; if let Some(waker) = inner.waker.take() { @@ -136,9 +135,9 @@ impl WasmSocket { socket.set_onerror(Some(error_callback.as_ref().unchecked_ref())); let close_callback = Closure::::new({ - let inner = Rc::clone(&inner); + let inner = inner.clone(); move |_| { - let mut inner = inner.borrow_mut(); + let mut inner = inner.lock().expect("Mutex is poised; qed"); inner.state = ConnectionState::Closed; if let Some(waker) = inner.waker.take() { @@ -156,7 +155,7 @@ impl WasmSocket { ); Ok(Self { - inner: SendWrapper::new(inner), + inner, socket: SendWrapper::new(socket), _callbacks: SendWrapper::new(callbacks), }) @@ -169,7 +168,7 @@ impl AsyncRead for WasmSocket { cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { - let mut inner = self.inner.borrow_mut(); + let mut inner = self.inner.lock().expect("Mutex is poised; qed"); inner.waker = Some(cx.waker().clone()); match inner.state { @@ -199,7 +198,7 @@ impl AsyncWrite for WasmSocket { cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - let mut inner = self.inner.borrow_mut(); + let mut inner = self.inner.lock().expect("Mutex is poised; qed"); inner.waker = Some(cx.waker().clone()); match inner.state { @@ -229,7 +228,7 @@ impl AsyncWrite for WasmSocket { impl Drop for WasmSocket { fn drop(&mut self) { - let inner = self.inner.borrow_mut(); + let inner = self.inner.lock().expect("Mutex is poised; qed"); if inner.state == ConnectionState::Opened { let _ = self.socket.close(); From e172bbb20c79d413b2e4fb7aaf0d01e140fb02db Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 18 Jul 2023 13:57:12 +0300 Subject: [PATCH 36/36] Add comments Signed-off-by: Alexandru Vasile --- lightclient/src/platform/wasm_platform.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lightclient/src/platform/wasm_platform.rs b/lightclient/src/platform/wasm_platform.rs index 79e90882c8..d3ca05101e 100644 --- a/lightclient/src/platform/wasm_platform.rs +++ b/lightclient/src/platform/wasm_platform.rs @@ -112,6 +112,8 @@ impl PlatformRef for SubxtPlatform { fn update_stream<'a>(&self, stream: &'a mut Self::Stream) -> Self::StreamUpdateFuture<'a> { Box::pin(future::poll_fn(|cx| { + // The `connect` is expected to be called before this method and would populate + // the buffers properly. When the buffers are empty, this future is shortly dropped. let Some((read_buffer, write_buffer)) = stream.buffers.as_mut() else { return Poll::Pending }; // Whether the future returned by `update_stream` should return `Ready` or `Pending`. @@ -221,6 +223,9 @@ impl PlatformRef for SubxtPlatform { if update_stream_future_ready { Poll::Ready(()) } else { + // Progress cannot be made since poll_read, poll_write, poll_close, poll_flush + // are not ready yet. Smoldot drops this future and calls it again with the + // next processing iteration. Poll::Pending } }))