diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9283dbf342..468fa0b1a4 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -47,7 +47,7 @@ jobs: args: --all -- --check - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 machete: name: "Check unused dependencies" @@ -78,7 +78,7 @@ jobs: command: machete - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 clippy: name: Cargo clippy @@ -110,7 +110,7 @@ jobs: cargo clippy -p subxt --no-default-features --features web,unstable-light-client -- -D warnings - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 wasm_clippy: name: Cargo clippy (WASM) @@ -141,7 +141,7 @@ jobs: args: -p subxt --no-default-features --features web,unstable-light-client,jsonrpsee --target wasm32-unknown-unknown -- -D warnings - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 check: name: Cargo check @@ -165,7 +165,7 @@ jobs: uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - name: Install cargo-hack - uses: baptiste0928/cargo-install@v2 + uses: baptiste0928/cargo-install@v3 with: crate: cargo-hack version: 0.5 @@ -203,7 +203,7 @@ jobs: run: cargo check --manifest-path examples/parachain-example/Cargo.toml - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 wasm_check: name: Cargo check (WASM) @@ -230,7 +230,7 @@ jobs: cargo check --manifest-path examples/wasm-example/Cargo.toml --target wasm32-unknown-unknown - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 docs: name: Check documentation and run doc tests @@ -263,7 +263,7 @@ jobs: args: --doc - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 tests: name: "Test (Native)" @@ -297,7 +297,7 @@ jobs: args: run --workspace - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 unstable_backend_tests: name: "Test (Unstable Backend)" @@ -331,7 +331,7 @@ jobs: args: run --workspace --features unstable-backend-client - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 light_client_tests: name: "Test (Light Client)" @@ -362,7 +362,7 @@ jobs: args: --release --package integration-tests --features unstable-light-client - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 wasm_tests: name: Test (WASM) @@ -418,7 +418,7 @@ jobs: working-directory: signer/wasm-tests - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 no-std-tests: name: "Test (no_std)" @@ -453,4 +453,4 @@ jobs: working-directory: testing/no-std-tests - if: "failure()" - uses: "andymckay/cancel-action@b9280e3f8986d7a8e91c7462efc0fa318010c8b1" # v0.3 + uses: "andymckay/cancel-action@271cfbfa11ca9222f7be99a47e8f929574549e0a" # v0.4 diff --git a/.github/workflows/update-artifacts.yml b/.github/workflows/update-artifacts.yml index a8f4d03812..03a9e53806 100644 --- a/.github/workflows/update-artifacts.yml +++ b/.github/workflows/update-artifacts.yml @@ -46,7 +46,7 @@ jobs: run: rm ./substrate-node - name: Create Pull Request - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: base: master branch: update-artifacts diff --git a/Cargo.lock b/Cargo.lock index 4fd98a19cd..dd3b4c93d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -854,9 +854,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" dependencies = [ "clap_builder", "clap_derive", @@ -864,21 +864,21 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" dependencies = [ "anstream", "anstyle", - "clap_lex 0.6.0", - "strsim", + "clap_lex 0.7.0", + "strsim 0.11.0", ] [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck", "proc-macro2", @@ -897,9 +897,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "cmake" @@ -1213,12 +1213,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.3" +version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8" dependencies = [ - "darling_core 0.20.3", - "darling_macro 0.20.3", + "darling_core 0.20.5", + "darling_macro 0.20.5", ] [[package]] @@ -1231,21 +1231,21 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 1.0.109", ] [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 2.0.48", ] @@ -1262,11 +1262,11 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77" dependencies = [ - "darling_core 0.20.3", + "darling_core 0.20.5", "quote", "syn 2.0.48", ] @@ -1466,9 +1466,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "environmental" @@ -2293,30 +2293,31 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] [[package]] name = "jsonrpsee" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9579d0ca9fb30da026bac2f0f7d9576ec93489aeb7cd4971dd5b4617d82c79b2" +checksum = "4a95f7cc23d5fab0cdeeaf6bad8c8f5e7a3aa7f0d211957ea78232b327ab27b0" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-http-client", "jsonrpsee-types", + "jsonrpsee-ws-client", ] [[package]] name = "jsonrpsee-client-transport" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9f9ed46590a8d5681975f126e22531698211b926129a40a2db47cbca429220" +checksum = "6b1736cfa3845fd9f8f43751f2b8e0e83f7b6081e754502f7d63b6587692cc83" dependencies = [ "futures-channel", "futures-util", @@ -2337,9 +2338,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "776d009e2f591b78c038e0d053a796f94575d66ca4e77dd84bfc5e81419e436c" +checksum = "82030d038658974732103e623ba2e0abec03bbbe175b39c0a2fafbada60c5868" dependencies = [ "anyhow", "async-lock 3.3.0", @@ -2362,9 +2363,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b7de9f3219d95985eb77fd03194d7c1b56c19bce1abfcc9d07462574b15572" +checksum = "36a06ef0de060005fddf772d54597bb6a8b0413da47dcffd304b0306147b9678" dependencies = [ "async-trait", "hyper", @@ -2382,9 +2383,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3266dfb045c9174b24c77c2dfe0084914bb23a6b2597d70c9dc6018392e1cd1b" +checksum = "9a48fdc1202eafc51c63e00406575e59493284ace8b8b61aa16f3a6db5d64f1a" dependencies = [ "anyhow", "beef", @@ -2393,6 +2394,19 @@ dependencies = [ "thiserror", ] +[[package]] +name = "jsonrpsee-ws-client" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5ce25d70a8e4d3cc574bbc3cad0137c326ad64b194793d5e7bbdd3fa4504181" +dependencies = [ + "http", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", + "url", +] + [[package]] name = "keccak" version = "0.1.5" @@ -3149,6 +3163,22 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "reconnecting-jsonrpsee-ws-client" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea5cf7b021db88f1af45a9b2ecdbe5bc1c5cbebc146632269d572cdd435f5cf" +dependencies = [ + "futures", + "jsonrpsee", + "serde_json", + "thiserror", + "tokio", + "tokio-retry", + "tokio-stream", + "tracing", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -3636,9 +3666,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f622567e3b4b38154fb8190bcf6b160d7a4301d70595a49195b48c116007a27" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ "secp256k1-sys", ] @@ -4395,6 +4425,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "strum" version = "0.24.1" @@ -4460,6 +4496,7 @@ dependencies = [ "jsonrpsee", "parity-scale-codec", "primitive-types", + "reconnecting-jsonrpsee-ws-client", "scale-bits", "scale-decode", "scale-encode", @@ -4488,7 +4525,7 @@ dependencies = [ name = "subxt-cli" version = "0.34.0" dependencies = [ - "clap 4.4.18", + "clap 4.5.0", "color-eyre", "frame-metadata 16.0.0", "heck", @@ -4563,7 +4600,7 @@ dependencies = [ name = "subxt-macro" version = "0.34.0" dependencies = [ - "darling 0.20.3", + "darling 0.20.5", "parity-scale-codec", "proc-macro-error", "quote", @@ -4677,18 +4714,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", @@ -4732,9 +4769,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", @@ -4758,6 +4795,17 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "tokio-retry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" +dependencies = [ + "pin-project", + "rand", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -5252,9 +5300,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -5262,9 +5310,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", @@ -5289,9 +5337,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5299,9 +5347,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", @@ -5312,9 +5360,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "wasmi" diff --git a/Cargo.toml b/Cargo.toml index 41241ebe0c..c1de7a20d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,16 +56,16 @@ assert_matches = "1.5.0" base58 = { version = "0.2.0" } bitvec = { version = "1", default-features = false } blake2 = { version = "0.10.6", default-features = false } -clap = { version = "4.4.18", features = ["derive", "cargo"] } cfg-if = "1.0.0" +clap = { version = "4.5.0", features = ["derive", "cargo"] } criterion = "0.4" codec = { package = "parity-scale-codec", version = "3.6.9", default-features = false } color-eyre = "0.6.1" console_error_panic_hook = "0.1.7" -darling = "0.20.3" +darling = "0.20.5" derivative = "2.2.0" derive_more = "0.99.17" -either = "1.9.0" +either = "1.10.0" frame-metadata = { version = "16.0.0", default-features = false } futures = { version = "0.3.30", default-features = false, features = ["std"] } getrandom = { version = "0.2", default-features = false } @@ -74,7 +74,7 @@ hex = "0.4.3" heck = "0.4.1" impl-serde = { version = "0.4.0" } indoc = "2" -jsonrpsee = { version = "0.21" } +jsonrpsee = { version = "0.22" } pretty_assertions = "1.4.0" primitive-types = { version = "0.12.2", default-features = false, features = ["codec", "scale-info", "serde"] } proc-macro-error = "1.0.4" @@ -89,8 +89,8 @@ scale-encode = "0.5.0" serde = { version = "1.0.196" } serde_json = { version = "1.0.113" } syn = { version = "2.0.15", features = ["full", "extra-traits"] } -thiserror = "1.0.53" -tokio = { version = "1.35", default-features = false } +thiserror = "1.0.57" +tokio = { version = "1.36", default-features = false } tracing = "0.1.40" tracing-wasm = "0.2.1" tracing-subscriber = "0.3.18" @@ -115,7 +115,7 @@ pin-project = "1.1.4" web-sys = { version = "0.3.67", features = ["BinaryType", "CloseEvent", "MessageEvent", "WebSocket"] } wasm-bindgen = "0.2.90" send_wrapper = "0.6.0" -js-sys = "0.3.67" +js-sys = "0.3.68" wasm-bindgen-futures = "0.4.38" futures-timer = "3" instant = { version = "0.1.12", default-features = false } @@ -142,7 +142,7 @@ bip39 = "2.0.0" hmac = "0.12.1" pbkdf2 = { version = "0.12.2", default-features = false } schnorrkel = "0.11.4" -secp256k1 = "0.28.1" +secp256k1 = "0.28.2" secrecy = "0.8.0" sha2 = "0.10.8" zeroize = { version = "1", default-features = false } diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index 7655a0c5f4..4a18bb2b41 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -42,6 +42,9 @@ web = [ "instant/wasm-bindgen" ] +# Enable this to use the reconnecting rpc client +unstable-reconnecting-rpc-client = ["dep:reconnecting-jsonrpsee-ws-client"] + # Enable this to use jsonrpsee (allowing for example `OnlineClient::from_url`). jsonrpsee = ["dep:jsonrpsee"] @@ -103,6 +106,9 @@ subxt-lightclient = { workspace = true, optional = true, default-features = fals # Light client support: tokio-stream = { workspace = true, optional = true } +# Reconnecting jsonrpc ws client +reconnecting-jsonrpsee-ws-client = { version = "0.3", optional = true } + # For parsing urls to disallow insecure schemes url = { workspace = true } @@ -138,6 +144,11 @@ name = "light_client_parachains" path = "examples/light_client_parachains.rs" required-features = ["unstable-light-client", "jsonrpsee", "native"] +[[example]] +name = "reconnecting_rpc_client" +path = "examples/reconnecting_rpc_client.rs" +required-features = ["unstable-reconnecting-rpc-client"] + [package.metadata.docs.rs] features = ["default", "substrate-compat", "unstable-light-client"] rustdoc-args = ["--cfg", "docsrs"] diff --git a/subxt/examples/reconnecting_rpc_client.rs b/subxt/examples/reconnecting_rpc_client.rs new file mode 100644 index 0000000000..b21be899f6 --- /dev/null +++ b/subxt/examples/reconnecting_rpc_client.rs @@ -0,0 +1,73 @@ +//! Example to utilize the `reconnecting rpc client` in subxt +//! which hidden behind behind `--feature unstable-reconnecting-rpc-client` +//! +//! To utilize full logs from the RPC client use: +//! `RUST_LOG="jsonrpsee=trace,reconnecting_jsonrpsee_ws_client=trace"` + +#![allow(missing_docs)] + +use std::time::Duration; + +use subxt::backend::rpc::reconnecting_rpc_client::{Client, ExponentialBackoff, PingConfig}; +use subxt::backend::rpc::RpcClient; +use subxt::error::{Error, RpcError}; +use subxt::{OnlineClient, PolkadotConfig}; + +// Generate an interface that we can use from the node's metadata. +#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")] +pub mod polkadot {} + +#[tokio::main] +async fn main() -> Result<(), Box> { + tracing_subscriber::fmt::init(); + + // Create a new client with with a reconnecting RPC client. + let rpc = Client::builder() + // Reconnect with exponential backoff + // + // This API is "iterator-like" so one could limit it to only + // reconnect x times and then quit. + .retry_policy(ExponentialBackoff::from_millis(100).max_delay(Duration::from_secs(10))) + // Send period WebSocket pings/pongs every 6th second and if it's not ACK:ed in 30 seconds + // then disconnect. + // + // This is just a way to ensure that the connection isn't idle if no message is sent that often + .enable_ws_ping( + PingConfig::new() + .ping_interval(Duration::from_secs(6)) + .inactive_limit(Duration::from_secs(30)), + ) + // There are other configurations as well that can be found here: + // + .build("ws://localhost:9944".to_string()) + .await?; + + let api: OnlineClient = + OnlineClient::from_rpc_client(RpcClient::new(rpc.clone())).await?; + + // Subscribe to all finalized blocks: + let mut blocks_sub = api.blocks().subscribe_finalized().await?; + + // For each block, print a bunch of information about it: + while let Some(block) = blocks_sub.next().await { + let block = match block { + Ok(b) => b, + Err(Error::Rpc(RpcError::DisconnectedWillReconnect(err))) => { + println!("{err}"); + continue; + } + Err(e) => { + return Err(e.into()); + } + }; + + let block_number = block.header().number; + let block_hash = block.hash(); + + println!("Block #{block_number} ({block_hash})"); + } + + println!("RPC client reconnected `{}` times", rpc.reconnect_count()); + + Ok(()) +} diff --git a/subxt/src/backend/mod.rs b/subxt/src/backend/mod.rs index 3db06818b3..e816bc904c 100644 --- a/subxt/src/backend/mod.rs +++ b/subxt/src/backend/mod.rs @@ -184,6 +184,7 @@ impl PartialEq for BlockRef { } impl Eq for BlockRef {} +// Manual implementation to work around https://github.com/mcarton/rust-derivative/issues/115. impl PartialOrd for BlockRef { fn partial_cmp(&self, other: &Self) -> Option { self.hash.partial_cmp(&other.hash) diff --git a/subxt/src/backend/rpc/mod.rs b/subxt/src/backend/rpc/mod.rs index 12910939e7..19101dd5df 100644 --- a/subxt/src/backend/rpc/mod.rs +++ b/subxt/src/backend/rpc/mod.rs @@ -60,9 +60,13 @@ crate::macros::cfg_jsonrpsee! { mod jsonrpsee_impl; } +crate::macros::cfg_reconnecting_rpc_client! { + mod reconnecting_jsonrpsee_impl; + pub use reconnecting_jsonrpsee_ws_client as reconnecting_rpc_client; +} + mod rpc_client; mod rpc_client_t; -pub use rpc_client_t::{RawRpcFuture, RawRpcSubscription, RawValue, RpcClientT}; - pub use rpc_client::{rpc_params, RpcClient, RpcParams, RpcSubscription}; +pub use rpc_client_t::{RawRpcFuture, RawRpcSubscription, RawValue, RpcClientT}; diff --git a/subxt/src/backend/rpc/reconnecting_jsonrpsee_impl.rs b/subxt/src/backend/rpc/reconnecting_jsonrpsee_impl.rs new file mode 100644 index 0000000000..da37b267e0 --- /dev/null +++ b/subxt/src/backend/rpc/reconnecting_jsonrpsee_impl.rs @@ -0,0 +1,52 @@ +// 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::{RawRpcFuture, RawRpcSubscription, RpcClientT}; +use crate::error::RpcError; +use futures::{FutureExt, StreamExt, TryStreamExt}; +use reconnecting_jsonrpsee_ws_client::SubscriptionId; +use serde_json::value::RawValue; + +impl RpcClientT for reconnecting_jsonrpsee_ws_client::Client { + fn request_raw<'a>( + &'a self, + method: &'a str, + params: Option>, + ) -> RawRpcFuture<'a, Box> { + async { + self.request_raw(method.to_string(), params) + .await + .map_err(|e| RpcError::ClientError(Box::new(e))) + } + .boxed() + } + + fn subscribe_raw<'a>( + &'a self, + sub: &'a str, + params: Option>, + unsub: &'a str, + ) -> RawRpcFuture<'a, RawRpcSubscription> { + async { + let sub = self + .subscribe_raw(sub.to_string(), params, unsub.to_string()) + .await + .map_err(|e| RpcError::ClientError(Box::new(e)))?; + + let id = match sub.id() { + SubscriptionId::Num(n) => n.to_string(), + SubscriptionId::Str(s) => s.to_string(), + }; + let stream = sub + .map_err(|e| RpcError::DisconnectedWillReconnect(e.to_string())) + .boxed(); + + Ok(RawRpcSubscription { + stream, + id: Some(id), + }) + } + .boxed() + } +} diff --git a/subxt/src/constants/constant_address.rs b/subxt/src/constants/constant_address.rs index e9a0eb37b0..3765d4c84b 100644 --- a/subxt/src/constants/constant_address.rs +++ b/subxt/src/constants/constant_address.rs @@ -28,7 +28,13 @@ pub trait ConstantAddress { /// This represents the address of a constant. #[derive(Derivative)] -#[derivative(Clone(bound = ""), Debug(bound = ""))] +#[derivative( + Clone(bound = ""), + Debug(bound = ""), + Eq(bound = ""), + Ord(bound = ""), + PartialEq(bound = "") +)] pub struct Address { pallet_name: Cow<'static, str>, constant_name: Cow<'static, str>, @@ -36,6 +42,13 @@ pub struct Address { _marker: std::marker::PhantomData, } +// Manual implementation to work around https://github.com/mcarton/rust-derivative/issues/115. +impl PartialOrd for Address { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + /// The type of address typically used to return dynamic constant values. pub type DynamicAddress = Address; diff --git a/subxt/src/custom_values/custom_value_address.rs b/subxt/src/custom_values/custom_value_address.rs index f8034a161b..6e2f7f77ea 100644 --- a/subxt/src/custom_values/custom_value_address.rs +++ b/subxt/src/custom_values/custom_value_address.rs @@ -38,13 +38,25 @@ pub struct Yes; /// A static address to a custom value. #[derive(Derivative)] -#[derivative(Clone(bound = ""), Debug(bound = ""))] +#[derivative( + Clone(bound = ""), + Debug(bound = ""), + Eq(bound = ""), + Ord(bound = ""), + PartialEq(bound = "") +)] pub struct StaticAddress { name: &'static str, hash: Option<[u8; 32]>, phantom: PhantomData<(ReturnTy, IsDecodable)>, } +impl PartialOrd for StaticAddress { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl StaticAddress { #[doc(hidden)] /// Creates a new StaticAddress. diff --git a/subxt/src/error/mod.rs b/subxt/src/error/mod.rs index 78c5528012..41dbc11d31 100644 --- a/subxt/src/error/mod.rs +++ b/subxt/src/error/mod.rs @@ -6,8 +6,6 @@ mod dispatch_error; -use core::fmt::Debug; - crate::macros::cfg_unstable_light_client! { pub use crate::client::LightClientError; } @@ -100,6 +98,13 @@ impl From for Error { } } +impl Error { + /// Checks whether the error was caused by a RPC re-connection. + pub fn is_disconnected_will_reconnect(&self) -> bool { + matches!(self, Error::Rpc(RpcError::DisconnectedWillReconnect(_))) + } +} + /// An RPC error. Since we are generic over the RPC client that is used, /// the error is boxed and could be casted. #[derive(Debug, thiserror::Error)] @@ -120,6 +125,9 @@ pub enum RpcError { /// The requested URL is insecure. #[error("RPC error: insecure URL: {0}")] InsecureUrl(String), + /// The connection was lost and automatically reconnected. + #[error("RPC error: the connection was lost `{0}`; reconnect automatically initiated")] + DisconnectedWillReconnect(String), } impl RpcError { diff --git a/subxt/src/macros.rs b/subxt/src/macros.rs index a8d86ada69..47362f18ca 100644 --- a/subxt/src/macros.rs +++ b/subxt/src/macros.rs @@ -52,7 +52,21 @@ macro_rules! cfg_jsonrpsee_web { } } -pub(crate) use {cfg_feature, cfg_jsonrpsee, cfg_substrate_compat, cfg_unstable_light_client}; +#[allow(unused)] +macro_rules! cfg_reconnecting_rpc_client { + ($($item:item)*) => { + $( + #[cfg(all(feature = "unstable-reconnecting-rpc-client"))] + #[cfg_attr(docsrs, doc(cfg(feature = "unstable-reconnecting-rpc-client")))] + $item + )* + } +} + +pub(crate) use { + cfg_feature, cfg_jsonrpsee, cfg_reconnecting_rpc_client, cfg_substrate_compat, + cfg_unstable_light_client, +}; // Only used by light-client. #[allow(unused)] diff --git a/subxt/src/runtime_api/runtime_payload.rs b/subxt/src/runtime_api/runtime_payload.rs index cd5a3355b8..ff776eb14f 100644 --- a/subxt/src/runtime_api/runtime_payload.rs +++ b/subxt/src/runtime_api/runtime_payload.rs @@ -69,7 +69,11 @@ pub trait RuntimeApiPayload { #[derive(Derivative)] #[derivative( Clone(bound = "ArgsData: Clone"), - Debug(bound = "ArgsData: std::fmt::Debug") + Debug(bound = "ArgsData: std::fmt::Debug"), + Eq(bound = "ArgsData: std::cmp::Eq"), + Ord(bound = "ArgsData: std::cmp::Ord"), + PartialEq(bound = "ArgsData: std::cmp::PartialEq"), + PartialOrd(bound = "ArgsData: std::cmp::PartialOrd") )] pub struct Payload { trait_name: Cow<'static, str>, diff --git a/subxt/src/storage/storage_address.rs b/subxt/src/storage/storage_address.rs index 893474b518..2211b20def 100644 --- a/subxt/src/storage/storage_address.rs +++ b/subxt/src/storage/storage_address.rs @@ -55,7 +55,11 @@ pub struct Yes; #[derive(Derivative)] #[derivative( Clone(bound = "StorageKey: Clone"), - Debug(bound = "StorageKey: std::fmt::Debug") + Debug(bound = "StorageKey: std::fmt::Debug"), + Eq(bound = "StorageKey: std::cmp::Eq"), + Ord(bound = "StorageKey: std::cmp::Ord"), + PartialEq(bound = "StorageKey: std::cmp::PartialEq"), + PartialOrd(bound = "StorageKey: std::cmp::PartialOrd") )] pub struct Address { pallet_name: Cow<'static, str>, diff --git a/subxt/src/tx/tx_payload.rs b/subxt/src/tx/tx_payload.rs index 508a6a99e6..ff9c71fd21 100644 --- a/subxt/src/tx/tx_payload.rs +++ b/subxt/src/tx/tx_payload.rs @@ -11,6 +11,7 @@ use crate::{ metadata::Metadata, }; use codec::Encode; +use derivative::Derivative; use scale_encode::EncodeAsFields; use scale_value::{Composite, ValueDef, Variant}; use std::{borrow::Cow, sync::Arc}; @@ -48,7 +49,15 @@ pub struct ValidationDetails<'a> { } /// A transaction payload containing some generic `CallData`. -#[derive(Clone, Debug)] +#[derive(Derivative)] +#[derivative( + Clone(bound = "CallData: Clone"), + Debug(bound = "CallData: std::fmt::Debug"), + Eq(bound = "CallData: std::cmp::Eq"), + Ord(bound = "CallData: std::cmp::Ord"), + PartialEq(bound = "CallData: std::cmp::PartialEq"), + PartialOrd(bound = "CallData: std::cmp::PartialOrd") +)] pub struct Payload { pallet_name: Cow<'static, str>, call_name: Cow<'static, str>,