From 568493f573f8010e9782c608c9964e7300f336a0 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Tue, 8 Oct 2024 17:05:39 +0200 Subject: [PATCH 01/10] add omni-executor offchain service --- tee-worker/omni-executor/.gitignore | 7 + tee-worker/omni-executor/Cargo.lock | 5315 +++++++++++++++++ tee-worker/omni-executor/Cargo.toml | 22 + tee-worker/omni-executor/Dockerfile | 8 + tee-worker/omni-executor/Makefile | 78 + tee-worker/omni-executor/README.md | 3 + tee-worker/omni-executor/docker-compose.yml | 19 + .../ethereum/intention-executor/Cargo.toml | 10 + .../ethereum/intention-executor/src/lib.rs | 75 + .../omni-executor/executor-core/Cargo.toml | 11 + .../omni-executor/executor-core/README.md | 0 .../executor-core/src/fetcher.rs | 30 + .../executor-core/src/intention_executor.rs | 44 + .../omni-executor/executor-core/src/lib.rs | 21 + .../executor-core/src/listener.rs | 194 + .../executor-core/src/primitives.rs | 21 + .../src/sync_checkpoint_repository.rs | 107 + .../omni-executor/executor-worker/Cargo.lock | 7 + .../omni-executor/executor-worker/Cargo.toml | 15 + .../omni-executor/executor-worker/src/main.rs | 69 + .../omni-executor/omni-executor.manifest | 44 + .../omni-executor.manifest.template | 45 + .../artifacts/rococo-omni-execution.scale | Bin 0 -> 234767 bytes .../parentchain/listener/Cargo.toml | 16 + .../parentchain/listener/src/fetcher.rs | 88 + .../parentchain/listener/src/lib.rs | 98 + .../parentchain/listener/src/listener.rs | 29 + .../parentchain/listener/src/primitives.rs | 95 + .../parentchain/listener/src/rpc_client.rs | 142 + tee-worker/omni-executor/rust-toolchain.toml | 3 + 30 files changed, 6616 insertions(+) create mode 100644 tee-worker/omni-executor/.gitignore create mode 100644 tee-worker/omni-executor/Cargo.lock create mode 100644 tee-worker/omni-executor/Cargo.toml create mode 100644 tee-worker/omni-executor/Dockerfile create mode 100644 tee-worker/omni-executor/Makefile create mode 100644 tee-worker/omni-executor/README.md create mode 100644 tee-worker/omni-executor/docker-compose.yml create mode 100644 tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml create mode 100644 tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs create mode 100644 tee-worker/omni-executor/executor-core/Cargo.toml create mode 100644 tee-worker/omni-executor/executor-core/README.md create mode 100644 tee-worker/omni-executor/executor-core/src/fetcher.rs create mode 100644 tee-worker/omni-executor/executor-core/src/intention_executor.rs create mode 100644 tee-worker/omni-executor/executor-core/src/lib.rs create mode 100644 tee-worker/omni-executor/executor-core/src/listener.rs create mode 100644 tee-worker/omni-executor/executor-core/src/primitives.rs create mode 100644 tee-worker/omni-executor/executor-core/src/sync_checkpoint_repository.rs create mode 100644 tee-worker/omni-executor/executor-worker/Cargo.lock create mode 100644 tee-worker/omni-executor/executor-worker/Cargo.toml create mode 100644 tee-worker/omni-executor/executor-worker/src/main.rs create mode 100644 tee-worker/omni-executor/omni-executor.manifest create mode 100644 tee-worker/omni-executor/omni-executor.manifest.template create mode 100644 tee-worker/omni-executor/parentchain/artifacts/rococo-omni-execution.scale create mode 100644 tee-worker/omni-executor/parentchain/listener/Cargo.toml create mode 100644 tee-worker/omni-executor/parentchain/listener/src/fetcher.rs create mode 100644 tee-worker/omni-executor/parentchain/listener/src/lib.rs create mode 100644 tee-worker/omni-executor/parentchain/listener/src/listener.rs create mode 100644 tee-worker/omni-executor/parentchain/listener/src/primitives.rs create mode 100644 tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs create mode 100644 tee-worker/omni-executor/rust-toolchain.toml diff --git a/tee-worker/omni-executor/.gitignore b/tee-worker/omni-executor/.gitignore new file mode 100644 index 0000000000..7ea756c65e --- /dev/null +++ b/tee-worker/omni-executor/.gitignore @@ -0,0 +1,7 @@ +debug/ +target/ +.idea/ +**/*.bin + +cache + diff --git a/tee-worker/omni-executor/Cargo.lock b/tee-worker/omni-executor/Cargo.lock new file mode 100644 index 0000000000..b83c7799dd --- /dev/null +++ b/tee-worker/omni-executor/Cargo.lock @@ -0,0 +1,5315 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "alloy" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8367891bf380210abb0d6aa30c5f85a9080cb4a066c4d5c5acadad630823751b" +dependencies = [ + "alloy-consensus", + "alloy-contract", + "alloy-core", + "alloy-eips", + "alloy-genesis", + "alloy-network", + "alloy-provider", + "alloy-rpc-client", + "alloy-rpc-types", + "alloy-serde", + "alloy-signer", + "alloy-signer-local", + "alloy-transport", + "alloy-transport-http", +] + +[[package]] +name = "alloy-chains" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8158b4878c67837e5413721cc44298e6a2d88d39203175ea025e51892a16ba4c" +dependencies = [ + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "629b62e38d471cc15fea534eb7283d2f8a4e8bdb1811bcc5d66dda6cfce6fae1" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "serde", +] + +[[package]] +name = "alloy-contract" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eefe64fd344cffa9cf9e3435ec4e93e6e9c3481bc37269af988bf497faf4a6a" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-eth", + "alloy-sol-types", + "alloy-transport", + "futures", + "futures-util", + "thiserror", +] + +[[package]] +name = "alloy-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce854562e7cafd5049189d0268d6e5cba05fe6c9cb7c6f8126a79b94800629c" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives", + "alloy-rlp", + "alloy-sol-types", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b499852e1d0e9b8c6db0f24c48998e647c0d5762a01090f955106a7700e4611" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow 0.6.20", +] + +[[package]] +name = "alloy-eip2930" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-eips" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f923dd5fca5f67a43d81ed3ebad0880bd41f6dd0ada930030353ac356c54cd0f" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "derive_more 1.0.0", + "once_cell", + "serde", + "sha2 0.10.8", +] + +[[package]] +name = "alloy-genesis" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a7a18afb0b318616b6b2b0e2e7ac5529d32a966c673b48091c9919e284e6aca" +dependencies = [ + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-json-abi" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a438d4486b5d525df3b3004188f9d5cd1d65cd30ecc41e5a3ccef6f6342e8af9" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3c717b5298fad078cd3a418335b266eba91b511383ca9bd497f742d5975d5ab" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb3705ce7d8602132bcf5ac7a1dd293a42adc2f183abf5907c30ac535ceca049" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror", +] + +[[package]] +name = "alloy-network-primitives" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94ad40869867ed2d9cd3842b1e800889e5b49e6b92da346e93862b4a741bedf3" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-primitives" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260d3ff3bff0bb84599f032a2f2c6828180b0ea0cd41fdaf44f39cef3ba41861" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more 1.0.0", + "hashbrown 0.14.5", + "hex-literal", + "indexmap", + "itoa", + "k256", + "keccak-asm", + "paste", + "proptest", + "rand", + "ruint", + "rustc-hash 2.0.0", + "serde", + "sha3", + "tiny-keccak", +] + +[[package]] +name = "alloy-provider" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927f708dd457ed63420400ee5f06945df9632d5d101851952056840426a10dc5" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-transport", + "alloy-transport-http", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures", + "futures-utils-wasm", + "lru", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +dependencies = [ + "alloy-rlp-derive", + "arrayvec 0.7.6", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d82952dca71173813d4e5733e2c986d8b04aea9e0f3b0a576664c232ad050a5" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "alloy-transport-http", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower 0.5.1", + "tracing", + "url", +] + +[[package]] +name = "alloy-rpc-types" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64333d639f2a0cf73491813c629a405744e16343a4bc5640931be707c345ecc5" +dependencies = [ + "alloy-rpc-types-eth", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83aa984386deda02482660aa31cb8ca1e63d533f1c31a52d7d181ac5ec68e9b8" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "cfg-if", + "derive_more 1.0.0", + "hashbrown 0.14.5", + "itertools 0.13.0", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-serde" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "731f75ec5d383107fd745d781619bd9cedf145836c51ecb991623d41278e71fa" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307324cca94354cd654d6713629f0383ec037e1ff9e3e3d547212471209860c0" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-signer-local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fabe917ab1778e760b4701628d1cae8e028ee9d52ac6307de4e1e9286ab6b5f" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-signer", + "async-trait", + "k256", + "rand", + "thiserror", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68e7f6e8fe5b443f82b3f1e15abfa191128f71569148428e49449d01f6f49e8b" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b96ce28d2fde09abb6135f410c41fad670a3a770b6776869bd852f1df102e6f" +dependencies = [ + "alloy-json-abi", + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.79", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "906746396a8296537745711630d9185746c0b50c033d5e9d18b0a6eba3d53f90" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.79", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc85178909a49c8827ffccfc9103a7ce1767ae66a801b69bdc326913870bf8e6" +dependencies = [ + "serde", + "winnow 0.6.20", +] + +[[package]] +name = "alloy-sol-types" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86a533ce22525969661b25dfe296c112d35eb6861f188fd284f8bd4bb3842ae" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33616b2edf7454302a1d48084db185e52c309f73f6c10be99b0fe39354b3f1e9" +dependencies = [ + "alloy-json-rpc", + "base64 0.22.1", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower 0.5.1", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport-http" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a944f5310c690b62bbb3e7e5ce34527cbd36b2d18532a797af123271ce595a49" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "reqwest", + "serde_json", + "tower 0.5.1", + "tracing", + "url", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener 5.3.1", + "futures-lite", + "rustix", + "tracing", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "atomic-take" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8ab6b55fe97976e46f91ddbed8d147d966475dc29b2032757ba47e02376fbc3" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[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 = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec 0.7.6", + "constant_time_eq 0.3.1", +] + +[[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 = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "blst" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[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.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + +[[package]] +name = "cc" +version = "1.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" +dependencies = [ + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-hex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[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.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "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 = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version 0.4.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core 0.20.10", + "darling_macro 0.20.10", +] + +[[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 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.79", +] + +[[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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core 0.20.10", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[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-where" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.79", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", + "unicode-xid", +] + +[[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", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-zebra" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "hashbrown 0.14.5", + "hex", + "rand_core", + "sha2 0.10.8", + "zeroize", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + +[[package]] +name = "executor-core" +version = "0.1.0" +dependencies = [ + "async-trait", + "log", + "parity-scale-codec", + "tokio", +] + +[[package]] +name = "executor-worker" +version = "0.1.0" +dependencies = [ + "env_logger", + "executor-core", + "hex", + "intention-executor", + "log", + "parentchain-listener", + "scale-encode", + "serde_json", + "tokio", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec 0.7.6", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "finito" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2384245d85162258a14b43567a9ee3598f5ae746a1581fb5d3d2cb780f0dbf95" +dependencies = [ + "futures-timer", + "pin-project", +] + +[[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 = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[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", +] + +[[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", + "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.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom_or_panic" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea1015b5a70616b688dc230cfe50c8af89d972cb132d5a622814d29773b10b9" +dependencies = [ + "rand_core", +] + +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[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.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.30", + "log", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[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 = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.0", + "serde", +] + +[[package]] +name = "indexmap-nostd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "intention-executor" +version = "0.1.0" +dependencies = [ + "alloy", + "async-trait", + "executor-core", + "log", +] + +[[package]] +name = "ipnet" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonrpsee" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdb12a2381ea5b2e68c3469ec604a007b367778cdb14d09612c8069ebd616ad" +dependencies = [ + "jsonrpsee-client-transport 0.22.5", + "jsonrpsee-core 0.22.5", + "jsonrpsee-http-client", + "jsonrpsee-types 0.22.5", +] + +[[package]] +name = "jsonrpsee" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b089779ad7f80768693755a031cc14a7766aba707cbe886674e3f79e9b7e47" +dependencies = [ + "jsonrpsee-core 0.23.2", + "jsonrpsee-types 0.23.2", + "jsonrpsee-ws-client", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4978087a58c3ab02efc5b07c5e5e2803024536106fd5506f558db172c889b3aa" +dependencies = [ + "futures-util", + "http 0.2.12", + "jsonrpsee-core 0.22.5", + "pin-project", + "rustls-native-certs 0.7.3", + "rustls-pki-types", + "soketto 0.7.1", + "thiserror", + "tokio", + "tokio-rustls 0.25.0", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08163edd8bcc466c33d79e10f695cdc98c00d1e6ddfb95cec41b6b0279dd5432" +dependencies = [ + "base64 0.22.1", + "futures-util", + "http 1.1.0", + "jsonrpsee-core 0.23.2", + "pin-project", + "rustls 0.23.13", + "rustls-pki-types", + "rustls-platform-verifier", + "soketto 0.8.0", + "thiserror", + "tokio", + "tokio-rustls 0.26.0", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "futures-timer", + "futures-util", + "hyper 0.14.30", + "jsonrpsee-types 0.22.5", + "pin-project", + "rustc-hash 1.1.0", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79712302e737d23ca0daa178e752c9334846b08321d439fd89af9a384f8c830b" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "futures-timer", + "futures-util", + "jsonrpsee-types 0.23.2", + "pin-project", + "rustc-hash 1.1.0", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" +dependencies = [ + "async-trait", + "hyper 0.14.30", + "hyper-rustls", + "jsonrpsee-core 0.22.5", + "jsonrpsee-types 0.22.5", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower 0.4.13", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c465fbe385238e861fdc4d1c85e04ada6c1fd246161d26385c1b311724d2af" +dependencies = [ + "beef", + "http 1.1.0", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c28759775f5cb2f1ea9667672d3fe2b0e701d1f4b7b67954e60afe7fd058b5e" +dependencies = [ + "http 1.1.0", + "jsonrpsee-client-transport 0.23.2", + "jsonrpsee-core 0.23.2", + "jsonrpsee-types 0.23.2", + "url", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.8", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[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 = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lru" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core", + "zeroize", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parentchain-listener" +version = "0.1.0" +dependencies = [ + "async-trait", + "env_logger", + "executor-core", + "log", + "parity-scale-codec", + "scale-encode", + "subxt", + "tokio", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec 0.7.6", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "polling" +version = "3.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +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 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit 0.22.22", +] + +[[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-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +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", + "serde", +] + +[[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", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "reconnecting-jsonrpsee-ws-client" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06fa4f17e09edfc3131636082faaec633c7baa269396b4004040bc6c52f49f65" +dependencies = [ + "cfg_aliases", + "finito", + "futures", + "jsonrpsee 0.23.2", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[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.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[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 1.0.4", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" + +[[package]] +name = "rustls-platform-verifier" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.13", + "rustls-native-certs 0.7.3", + "rustls-platform-verifier-android", + "rustls-webpki 0.102.8", + "security-framework", + "security-framework-sys", + "webpki-roots", + "winapi", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ruzstd" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" +dependencies = [ + "byteorder", + "derive_more 0.99.18", + "twox-hash", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-bits" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57b1e7f6b65ed1f04e79a85a57d755ad56d76fdf1e9bddcc9ae14f71fcdcf54" +dependencies = [ + "parity-scale-codec", + "scale-info", + "scale-type-resolver", + "serde", +] + +[[package]] +name = "scale-decode" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e98f3262c250d90e700bb802eb704e1f841e03331c2eb815e46516c4edbf5b27" +dependencies = [ + "derive_more 0.99.18", + "parity-scale-codec", + "primitive-types", + "scale-bits", + "scale-decode-derive", + "scale-type-resolver", + "smallvec", +] + +[[package]] +name = "scale-decode-derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb22f574168103cdd3133b19281639ca65ad985e24612728f727339dcaf4021" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scale-encode" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba0b9c48dc0eb20c60b083c29447c0c4617cb7c4a4c9fef72aa5c5bc539e15e" +dependencies = [ + "derive_more 0.99.18", + "parity-scale-codec", + "primitive-types", + "scale-bits", + "scale-encode-derive", + "scale-type-resolver", + "smallvec", +] + +[[package]] +name = "scale-encode-derive" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ab7e60e2d9c8d47105f44527b26f04418e5e624ffc034f6b4a86c0ba19c5bf" +dependencies = [ + "darling 0.14.4", + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more 0.99.18", + "parity-scale-codec", + "scale-info-derive", + "serde", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scale-type-resolver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0cded6518aa0bd6c1be2b88ac81bf7044992f0f154bfbabd5ad34f43512abcb" +dependencies = [ + "scale-info", + "smallvec", +] + +[[package]] +name = "scale-typegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498d1aecf2ea61325d4511787c115791639c0fd21ef4f8e11e49dd09eff2bbac" +dependencies = [ + "proc-macro2", + "quote", + "scale-info", + "syn 2.0.79", + "thiserror", +] + +[[package]] +name = "scale-value" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6ab090d823e75cfdb258aad5fe92e13f2af7d04b43a55d607d25fcc38c811" +dependencies = [ + "base58", + "blake2", + "derive_more 0.99.18", + "either", + "frame-metadata 15.1.0", + "parity-scale-codec", + "scale-bits", + "scale-decode", + "scale-encode", + "scale-info", + "scale-type-resolver", + "serde", + "yap", +] + +[[package]] +name = "schannel" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "schnorrkel" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0" +dependencies = [ + "aead", + "arrayref", + "arrayvec 0.7.6", + "curve25519-dalek", + "getrandom_or_panic", + "merlin", + "rand_core", + "serde_bytes", + "sha2 0.10.8", + "subtle", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "num-bigint", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "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 = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +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 = "sha3-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "smol" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" +dependencies = [ + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", +] + +[[package]] +name = "smoldot" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d1eaa97d77be4d026a1e7ffad1bb3b78448763b357ea6f8188d3e6f736a9b9" +dependencies = [ + "arrayvec 0.7.6", + "async-lock", + "atomic-take", + "base64 0.21.7", + "bip39", + "blake2-rfc", + "bs58", + "chacha20", + "crossbeam-queue", + "derive_more 0.99.18", + "ed25519-zebra", + "either", + "event-listener 4.0.3", + "fnv", + "futures-lite", + "futures-util", + "hashbrown 0.14.5", + "hex", + "hmac 0.12.1", + "itertools 0.12.1", + "libm", + "libsecp256k1", + "merlin", + "no-std-net", + "nom", + "num-bigint", + "num-rational", + "num-traits", + "pbkdf2", + "pin-project", + "poly1305", + "rand", + "rand_chacha", + "ruzstd", + "schnorrkel", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3", + "siphasher", + "slab", + "smallvec", + "soketto 0.7.1", + "twox-hash", + "wasmi", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "smoldot-light" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5496f2d116b7019a526b1039ec2247dd172b8670633b1a64a614c9ea12c9d8c7" +dependencies = [ + "async-channel", + "async-lock", + "base64 0.21.7", + "blake2-rfc", + "derive_more 0.99.18", + "either", + "event-listener 4.0.3", + "fnv", + "futures-channel", + "futures-lite", + "futures-util", + "hashbrown 0.14.5", + "hex", + "itertools 0.12.1", + "log", + "lru", + "no-std-net", + "parking_lot", + "pin-project", + "rand", + "rand_chacha", + "serde", + "serde_json", + "siphasher", + "slab", + "smol", + "smoldot", + "zeroize", +] + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[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 = "soketto" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures", + "httparse", + "log", + "rand", + "sha1", +] + +[[package]] +name = "sp-crypto-hashing" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9927a7f81334ed5b8a98a4a978c81324d12bd9713ec76b5c68fd410174c5eb" +dependencies = [ + "blake2b_simd", + "byteorder", + "digest 0.10.7", + "sha2 0.10.8", + "sha3", + "twox-hash", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[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 = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.79", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "subxt" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a160cba1edbf3ec4fbbeaea3f1a185f70448116a6bccc8276bb39adb3b3053bd" +dependencies = [ + "async-trait", + "derive-where", + "either", + "frame-metadata 16.0.0", + "futures", + "hex", + "impl-serde", + "instant", + "jsonrpsee 0.22.5", + "parity-scale-codec", + "primitive-types", + "reconnecting-jsonrpsee-ws-client", + "scale-bits", + "scale-decode", + "scale-encode", + "scale-info", + "scale-value", + "serde", + "serde_json", + "sp-crypto-hashing", + "subxt-core", + "subxt-lightclient", + "subxt-macro", + "subxt-metadata", + "thiserror", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "subxt-codegen" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d703dca0905cc5272d7cc27a4ac5f37dcaae7671acc7fef0200057cc8c317786" +dependencies = [ + "frame-metadata 16.0.0", + "heck", + "hex", + "jsonrpsee 0.22.5", + "parity-scale-codec", + "proc-macro2", + "quote", + "scale-info", + "scale-typegen", + "subxt-metadata", + "syn 2.0.79", + "thiserror", + "tokio", +] + +[[package]] +name = "subxt-core" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59f41eb2e2eea6ed45649508cc735f92c27f1fcfb15229e75f8270ea73177345" +dependencies = [ + "base58", + "blake2", + "derive-where", + "frame-metadata 16.0.0", + "hashbrown 0.14.5", + "hex", + "impl-serde", + "parity-scale-codec", + "primitive-types", + "scale-bits", + "scale-decode", + "scale-encode", + "scale-info", + "scale-value", + "serde", + "serde_json", + "sp-crypto-hashing", + "subxt-metadata", + "tracing", +] + +[[package]] +name = "subxt-lightclient" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d9406fbdb9548c110803cb8afa750f8b911d51eefdf95474b11319591d225d9" +dependencies = [ + "futures", + "futures-util", + "serde", + "serde_json", + "smoldot-light", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "subxt-macro" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c195f803d70687e409aba9be6c87115b5da8952cd83c4d13f2e043239818fcd" +dependencies = [ + "darling 0.20.10", + "parity-scale-codec", + "proc-macro-error", + "quote", + "scale-typegen", + "subxt-codegen", + "syn 2.0.79", +] + +[[package]] +name = "subxt-metadata" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738be5890fdeff899bbffff4d9c0f244fe2a952fb861301b937e3aa40ebb55da" +dependencies = [ + "frame-metadata 16.0.0", + "hashbrown 0.14.5", + "parity-scale-codec", + "scale-info", + "sp-crypto-hashing", +] + +[[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.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab661c8148c2261222a4d641ad5477fd4bea79406a99056096a0b41b35617a5" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[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.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +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.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.13", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.6.20", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[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", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[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 = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[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.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.79", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "wasmi" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8281d1d660cdf54c76a3efa9ddd0c270cada1383a995db3ccb43d166456c7" +dependencies = [ + "smallvec", + "spin", + "wasmi_arena", + "wasmi_core", + "wasmparser-nostd", +] + +[[package]] +name = "wasmi_arena" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "104a7f73be44570cac297b3035d76b169d6599637631cf37a1703326a0727073" + +[[package]] +name = "wasmi_core" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf1a7db34bff95b85c261002720c00c3a6168256dcb93041d3fa2054d19856a" +dependencies = [ + "downcast-rs", + "libm", + "num-traits", + "paste", +] + +[[package]] +name = "wasmparser-nostd" +version = "0.100.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a015fe95f3504a94bb1462c717aae75253e39b9dd6c3fb1062c934535c64aa" +dependencies = [ + "indexmap-nostd", +] + +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +dependencies = [ + "rustls-pki-types", +] + +[[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-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[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-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +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 = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + +[[package]] +name = "yap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4524214bc4629eba08d78ceb1d6507070cc0bcbbed23af74e19e6e924a24cf" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +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.79", +] diff --git a/tee-worker/omni-executor/Cargo.toml b/tee-worker/omni-executor/Cargo.toml new file mode 100644 index 0000000000..3ad1c90515 --- /dev/null +++ b/tee-worker/omni-executor/Cargo.toml @@ -0,0 +1,22 @@ +[workspace] +members = [ + "executor-core", + "executor-worker", + "parentchain/listener", + "ethereum/intention-executor" +] + +resolver = "2" + +[workspace.package] +edition = "2021" + +[workspace.dependencies] +log = "0.4.22" +tokio = "1.40.0" +async-trait = "0.1.82" +env_logger = "0.11.5" +scale-encode = "0.7.1" +parity-scale-codec = "3.6.12" +alloy = "0.3.6" +clap = "4.5.17" \ No newline at end of file diff --git a/tee-worker/omni-executor/Dockerfile b/tee-worker/omni-executor/Dockerfile new file mode 100644 index 0000000000..06f4d3881b --- /dev/null +++ b/tee-worker/omni-executor/Dockerfile @@ -0,0 +1,8 @@ +FROM rust:1.79 AS builder +WORKDIR /usr/src/omni-executor +COPY . . +RUN cargo build --release + +FROM ubuntu:22.04 +COPY --from=builder /usr/src/omni-executor/target/release/executor-worker /usr/local/bin/executor-worker +CMD ["executor-worker"] \ No newline at end of file diff --git a/tee-worker/omni-executor/Makefile b/tee-worker/omni-executor/Makefile new file mode 100644 index 0000000000..92b0c87557 --- /dev/null +++ b/tee-worker/omni-executor/Makefile @@ -0,0 +1,78 @@ +# Copyright (C) 2023 Gramine contributors +# SPDX-License-Identifier: BSD-3-Clause + +ARCH_LIBDIR ?= /lib/$(shell $(CC) -dumpmachine) + +SELF_EXE = target/release/omni-executor + +.PHONY: all +all: $(SELF_EXE) omni-executor.manifest +ifeq ($(SGX),1) +all: omni-executor.manifest.sgx omni-executor.sig +endif + +ifeq ($(DEBUG),1) +GRAMINE_LOG_LEVEL = debug +else +GRAMINE_LOG_LEVEL = error +endif + +# Note that we're compiling in release mode regardless of the DEBUG setting passed +# to Make, as compiling in debug mode results in an order of magnitude's difference in +# performance that makes testing by running a benchmark with ab painful. The primary goal +# of the DEBUG setting is to control Gramine's loglevel. +-include $(SELF_EXE).d # See also: .cargo/config.toml +$(SELF_EXE): Cargo.toml + cargo build --release + +omni-executor.manifest: omni-executor.manifest.template + gramine-manifest \ + -Dlog_level=$(GRAMINE_LOG_LEVEL) \ + -Darch_libdir=$(ARCH_LIBDIR) \ + -Dself_exe=$(SELF_EXE) \ + $< $@ + +# Make on Ubuntu <= 20.04 doesn't support "Rules with Grouped Targets" (`&:`), +# see the helloworld example for details on this workaround. +omni-executor.manifest.sgx tee-bridge.sig: sgx_sign + @: + +.INTERMEDIATE: sgx_sign +sgx_sign: omni-executor.manifest $(SELF_EXE) + gramine-sgx-sign \ + --manifest $< \ + --output $<.sgx + +ifeq ($(SGX),) +GRAMINE = gramine-direct +else +GRAMINE = gramine-sgx +endif + +.PHONY: start-gramine-server +start-gramine-server: all + $(GRAMINE) tee-bridge + +.PHONY: clean +clean: + $(RM) -rf *.token *.sig *.manifest.sgx *.manifest result-* OUTPUT + +.PHONY: distclean +distclean: clean + $(RM) -rf target/ Cargo.lock + +.PHONY: build-docker +build-docker: + docker build . --tag omni-executor:latest + +.PHONY: start-local +start-local: + docker-compose up + +.PHONY: stop-local +stop-local: + docker-compose down + +.PHONY: get-omni-pallet-metadata +get-omni-pallet-metadata: + subxt metadata --url http://localhost:9944 --allow-insecure --pallets OmniExecution > substrate/artifacts/rococo-omni-execution.scale diff --git a/tee-worker/omni-executor/README.md b/tee-worker/omni-executor/README.md new file mode 100644 index 0000000000..314d1e163a --- /dev/null +++ b/tee-worker/omni-executor/README.md @@ -0,0 +1,3 @@ +# Omni-executor worker + +! Connect to trusted RPC endpoints ! \ No newline at end of file diff --git a/tee-worker/omni-executor/docker-compose.yml b/tee-worker/omni-executor/docker-compose.yml new file mode 100644 index 0000000000..ba55c94acd --- /dev/null +++ b/tee-worker/omni-executor/docker-compose.yml @@ -0,0 +1,19 @@ +services: + omni-executor: + image: omni-executor:latest + environment: + - RUST_LOG=debug + depends_on: + - ethereum-node + - litentry-node + ethereum-node: + image: ghcr.io/foundry-rs/foundry + command: + - "anvil --host 0.0.0.0 --block-time 1" + ports: + - "8545:8545" + litentry-node: + image: litentry/litentry-parachain + ports: + - "9944:9944" + command: ["--dev", "--rpc-external"] \ No newline at end of file diff --git a/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml b/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml new file mode 100644 index 0000000000..aadb6d4c16 --- /dev/null +++ b/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "intention-executor" +version = "0.1.0" +edition.workspace = true + +[dependencies] +executor-core = { path = "../../executor-core" } +async-trait = { workspace = true } +alloy = { workspace = true, features = ["contract", "signer-local", "rpc", "rpc-types"]} +log = { workspace = true } \ No newline at end of file diff --git a/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs b/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs new file mode 100644 index 0000000000..ba3fee692f --- /dev/null +++ b/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs @@ -0,0 +1,75 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use std::str::FromStr; + +use alloy::network::{EthereumWallet, NetworkWallet}; +use alloy::primitives::{Address, U256}; +use alloy::providers::{Provider, ProviderBuilder, WalletProvider}; +use alloy::rpc::types::TransactionRequest; +use alloy::signers::local::PrivateKeySigner; +use async_trait::async_trait; +use executor_core::intention_executor::IntentionExecutor; +use executor_core::primitives::Intention; +use log::{error, info}; + +/// Executes intentions on Ethereum network. +pub struct EthereumIntentionExecutor { + rpc_url: String, +} + +impl EthereumIntentionExecutor { + pub fn new(rpc_url: &str) -> Result { + Ok(Self { rpc_url: rpc_url.to_string() }) + } +} + +#[async_trait] +impl IntentionExecutor for EthereumIntentionExecutor { + async fn execute(&self, intention: Intention) -> Result<(), ()> { + info!("Relaying intention: {:?}", intention); + // todo: this should be retrieved from key_store + let signer = PrivateKeySigner::from_str( + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", + ) + .unwrap(); + let wallet = EthereumWallet::from(signer); + let provider = ProviderBuilder::new() + .with_recommended_fillers() + .wallet(wallet) + .on_http(self.rpc_url.parse().map_err(|e| error!("Could not parse rpc url: {:?}", e))?); + let account = + provider.get_account(provider.signer_addresses().next().unwrap()).await.unwrap(); + match intention { + Intention::Transfer {} => { + // todo: read transfer details from intention + let tx = TransactionRequest::default() + .to(Address::from_str("0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65").unwrap()) + .nonce(account.nonce) + .value(U256::from(1)); + let pending_tx = provider.send_transaction(tx).await.map_err(|e| { + error!("Could not send transaction: {:?}", e); + })?; + // wait for transaction to be included + pending_tx.get_receipt().await.map_err(|e| { + error!("Could not get transaction receipt: {:?}", e); + })?; + }, + Intention::Call {} => todo!(), + } + Ok(()) + } +} diff --git a/tee-worker/omni-executor/executor-core/Cargo.toml b/tee-worker/omni-executor/executor-core/Cargo.toml new file mode 100644 index 0000000000..45c1cb7a91 --- /dev/null +++ b/tee-worker/omni-executor/executor-core/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "executor-core" +version = "0.1.0" +edition.workspace = true + +[dependencies] +tokio = { workspace = true } +async-trait = { workspace = true } +log = { workspace = true } +parity-scale-codec = { workspace = true, features = ["derive"] } + diff --git a/tee-worker/omni-executor/executor-core/README.md b/tee-worker/omni-executor/executor-core/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tee-worker/omni-executor/executor-core/src/fetcher.rs b/tee-worker/omni-executor/executor-core/src/fetcher.rs new file mode 100644 index 0000000000..0b068448ff --- /dev/null +++ b/tee-worker/omni-executor/executor-core/src/fetcher.rs @@ -0,0 +1,30 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::listener::IntentionEvent; +use async_trait::async_trait; + +/// Returns the last finalized block number +#[async_trait] +pub trait LastFinalizedBlockNumFetcher { + async fn get_last_finalized_block_num(&mut self) -> Result, ()>; +} + +/// Returns all events emitted on given chain +#[async_trait] +pub trait IntentionEventsFetcher { + async fn get_block_events(&mut self, block_num: u64) -> Result>, ()>; +} diff --git a/tee-worker/omni-executor/executor-core/src/intention_executor.rs b/tee-worker/omni-executor/executor-core/src/intention_executor.rs new file mode 100644 index 0000000000..fd46337883 --- /dev/null +++ b/tee-worker/omni-executor/executor-core/src/intention_executor.rs @@ -0,0 +1,44 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use async_trait::async_trait; +use tokio::sync::mpsc; + +use crate::primitives::Intention; + +/// Used to perform intention on destination chain +#[async_trait] +pub trait IntentionExecutor: Send { + async fn execute(&self, intention: Intention) -> Result<(), ()>; +} + +pub struct MockedIntentionExecutor { + sender: mpsc::UnboundedSender<()>, +} + +impl MockedIntentionExecutor { + pub fn new() -> (Self, mpsc::UnboundedReceiver<()>) { + let (sender, receiver) = mpsc::unbounded_channel(); + (Self { sender }, receiver) + } +} + +#[async_trait] +impl IntentionExecutor for MockedIntentionExecutor { + async fn execute(&self, _intention: Intention) -> Result<(), ()> { + self.sender.send(()).map_err(|_| ()) + } +} diff --git a/tee-worker/omni-executor/executor-core/src/lib.rs b/tee-worker/omni-executor/executor-core/src/lib.rs new file mode 100644 index 0000000000..474dfb6a57 --- /dev/null +++ b/tee-worker/omni-executor/executor-core/src/lib.rs @@ -0,0 +1,21 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +pub mod fetcher; +pub mod intention_executor; +pub mod listener; +pub mod primitives; +pub mod sync_checkpoint_repository; diff --git a/tee-worker/omni-executor/executor-core/src/listener.rs b/tee-worker/omni-executor/executor-core/src/listener.rs new file mode 100644 index 0000000000..6edf573492 --- /dev/null +++ b/tee-worker/omni-executor/executor-core/src/listener.rs @@ -0,0 +1,194 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use std::{marker::PhantomData, thread::sleep, time::Duration}; + +use tokio::{runtime::Handle, sync::oneshot::Receiver}; + +use crate::fetcher::{IntentionEventsFetcher, LastFinalizedBlockNumFetcher}; +use crate::{ + intention_executor::IntentionExecutor, + sync_checkpoint_repository::{Checkpoint, CheckpointRepository}, +}; + +/// Represents event emitted on listened chain. +#[derive(Clone, Debug, PartialEq)] +pub struct IntentionEvent { + id: Id, + //todo: fill +} + +impl IntentionEvent { + pub fn new(id: Id) -> Self { + Self { id } + } +} + +/// Component, used to listen to chain and execute requested intentions +/// Requires specific implementations of: +/// `Fetcher` - used to fetch data from source chain +/// `IntentionExecutor` - used to execute intentions on destination chain +/// `CheckpointRepository` - used to store listener's progress +pub struct Listener { + id: String, + handle: Handle, + fetcher: Fetcher, + intention_executor: Box, + stop_signal: Receiver<()>, + checkpoint_repository: CheckpointRepository, + _phantom: PhantomData<(Checkpoint, IntentionEvent)>, +} + +impl< + EventId: Into + Clone, + Fetcher: LastFinalizedBlockNumFetcher + IntentionEventsFetcher, + CheckpointT: PartialOrd + Checkpoint + From, + CheckpointRepositoryT: CheckpointRepository, + > Listener +{ + pub fn new( + id: &str, + handle: Handle, + fetcher: Fetcher, + intention_executor: Box, + stop_signal: Receiver<()>, + last_processed_log_repository: CheckpointRepositoryT, + ) -> Result { + Ok(Self { + id: id.to_string(), + handle, + fetcher, + intention_executor, + stop_signal, + checkpoint_repository: last_processed_log_repository, + _phantom: PhantomData, + }) + } + + /// Start syncing. It's a long-running blocking operation - should be started in dedicated thread. + pub fn sync(&mut self, start_block: u64) { + log::info!("Starting {} network sync, start block: {}", self.id, start_block); + let mut block_number_to_sync = if let Some(ref checkpoint) = + self.checkpoint_repository.get().expect("Could not read checkpoint") + { + if checkpoint.just_block_num() { + // let's start syncing from next block as we processed previous fully + checkpoint.get_block_num() + 1 + } else { + // block processing was interrupted, so we have to process last block again + // but currently processed logs will be skipped + checkpoint.get_block_num() + } + } else { + start_block + }; + log::debug!("Starting sync from {:?}", block_number_to_sync); + + 'main: loop { + log::info!("Syncing block: {}", block_number_to_sync); + if self.stop_signal.try_recv().is_ok() { + break; + } + + let maybe_last_finalized_block = + match self.handle.block_on(self.fetcher.get_last_finalized_block_num()) { + Ok(maybe_block) => maybe_block, + Err(_) => { + log::info!("Could not get last finalized block number"); + sleep(Duration::from_secs(1)); + continue; + }, + }; + + let last_finalized_block = match maybe_last_finalized_block { + Some(v) => v, + None => { + log::info!( + "Waiting for finalized block, block to sync {}", + block_number_to_sync + ); + sleep(Duration::from_secs(1)); + continue; + }, + }; + + log::trace!( + "Last finalized block: {}, block to sync {}", + last_finalized_block, + block_number_to_sync + ); + + //we know there are more block waiting for sync so let's skip sleep + let fast = match last_finalized_block.checked_sub(block_number_to_sync) { + Some(v) => v > 1, + None => false, + }; + + if last_finalized_block >= block_number_to_sync { + if let Ok(events) = + self.handle.block_on(self.fetcher.get_block_events(block_number_to_sync)) + { + for event in events { + if let Some(ref checkpoint) = + self.checkpoint_repository.get().expect("Could not read checkpoint") + { + if checkpoint.lt(&event.id.clone().into()) { + log::info!("Executing intention"); + if let Err(e) = self.handle.block_on( + self.intention_executor + .execute(crate::primitives::Intention::Transfer {}), + ) { + log::error!("Could not execute intention: {:?}", e); + sleep(Duration::from_secs(1)); + // it will try again in next loop + continue 'main; + } + } else { + log::debug!("Skipping event"); + } + } else { + log::info!("Executing intention"); + if let Err(e) = self.handle.block_on( + self.intention_executor + .execute(crate::primitives::Intention::Call {}), + ) { + log::error!("Could not execute intention: {:?}", e); + sleep(Duration::from_secs(1)); + // it will try again in next loop + continue 'main; + } + } + self.checkpoint_repository + .save(event.id.into()) + .expect("Could not save checkpoint"); + } + // we processed block completely so store new checkpoint + self.checkpoint_repository + .save(CheckpointT::from(block_number_to_sync)) + .expect("Could not save checkpoint"); + log::info!("Finished syncing block: {}", block_number_to_sync); + block_number_to_sync += 1; + } + } + + if !fast { + sleep(Duration::from_secs(1)) + } else { + log::trace!("Fast sync skipping 1s wait"); + } + } + } +} diff --git a/tee-worker/omni-executor/executor-core/src/primitives.rs b/tee-worker/omni-executor/executor-core/src/primitives.rs new file mode 100644 index 0000000000..989274c603 --- /dev/null +++ b/tee-worker/omni-executor/executor-core/src/primitives.rs @@ -0,0 +1,21 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +#[derive(Debug)] +pub enum Intention { + Transfer {}, + Call {}, +} diff --git a/tee-worker/omni-executor/executor-core/src/sync_checkpoint_repository.rs b/tee-worker/omni-executor/executor-core/src/sync_checkpoint_repository.rs new file mode 100644 index 0000000000..2fdf008404 --- /dev/null +++ b/tee-worker/omni-executor/executor-core/src/sync_checkpoint_repository.rs @@ -0,0 +1,107 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use parity_scale_codec::{Decode, Encode}; +use std::fmt::Debug; +use std::fs; +use std::fs::File; +use std::io::{ErrorKind, Write}; + +/// Represents the point in chain. It can be a whole block or a more precise unit, for example +/// in case of substrate chain it is BLOCK_NUM::EVENT_NUM +pub trait Checkpoint { + // determines whether checkpoint is a whole block or not + fn just_block_num(&self) -> bool; + fn get_block_num(&self) -> u64; +} + +/// Used for saving and reading `Checkpoint` +pub trait CheckpointRepository { + fn get(&self) -> Result, ()>; + fn save(&mut self, checkpoint: Checkpoint) -> Result<(), ()>; +} + +/// Simple `CheckpointRepository`. Checkpoints are not persisted across restarts. +pub struct InMemoryCheckpointRepository { + last: Option, +} + +impl InMemoryCheckpointRepository { + pub fn new(last: Option) -> Self { + Self { last } + } +} + +impl CheckpointRepository for InMemoryCheckpointRepository +where + Checkpoint: Clone, +{ + fn get(&self) -> Result, ()> { + Ok(self.last.clone()) + } + + fn save(&mut self, checkpoint: Checkpoint) -> Result<(), ()> { + self.last = Some(checkpoint); + Ok(()) + } +} + +/// File based `CheckpointRepository`. Used to persist checkpoints across restarts. +pub struct FileCheckpointRepository { + file_name: String, +} + +impl FileCheckpointRepository { + pub fn new(file_name: &str) -> Self { + // todo add regex check here + Self { file_name: file_name.to_owned() } + } +} + +impl CheckpointRepository for FileCheckpointRepository +where + Checkpoint: Encode + Decode + Debug, +{ + fn get(&self) -> Result, ()> { + match fs::read(&self.file_name) { + Ok(content) => { + let checkpoint: Checkpoint = + Checkpoint::decode(&mut content.as_slice()).map_err(|e| { + log::error!("Could not decode last processed log: {:?}", e); + })?; + Ok(Some(checkpoint)) + }, + Err(e) => match e.kind() { + ErrorKind::NotFound => Ok(None), + _ => { + log::error!("Could not open file {:?}", e); + Err(()) + }, + }, + } + } + + fn save(&mut self, checkpoint: Checkpoint) -> Result<(), ()> { + log::trace!("Saving checkpoint: {:?}", checkpoint); + let content = checkpoint.encode(); + if let Ok(mut file) = File::create(&self.file_name) { + file.write(content.as_slice()).map_err(|_| ())?; + Ok(()) + } else { + Err(()) + } + } +} diff --git a/tee-worker/omni-executor/executor-worker/Cargo.lock b/tee-worker/omni-executor/executor-worker/Cargo.lock new file mode 100644 index 0000000000..31c1e7fcd0 --- /dev/null +++ b/tee-worker/omni-executor/executor-worker/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "executor-worker" +version = "0.1.0" diff --git a/tee-worker/omni-executor/executor-worker/Cargo.toml b/tee-worker/omni-executor/executor-worker/Cargo.toml new file mode 100644 index 0000000000..220852623e --- /dev/null +++ b/tee-worker/omni-executor/executor-worker/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "executor-worker" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +serde_json = "1.0.127" +scale-encode = { workspace = true } +env_logger = { workspace = true } +log = { workspace = true } +intention-executor = { path = "../ethereum/intention-executor" } +executor-core = { path = "../executor-core" } +parentchain-listener = { path = "../parentchain/listener" } +hex = "0.4.3" \ No newline at end of file diff --git a/tee-worker/omni-executor/executor-worker/src/main.rs b/tee-worker/omni-executor/executor-worker/src/main.rs new file mode 100644 index 0000000000..8d378d8d3d --- /dev/null +++ b/tee-worker/omni-executor/executor-worker/src/main.rs @@ -0,0 +1,69 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use intention_executor::EthereumIntentionExecutor; +use log::error; +use parentchain_listener::CustomConfig; +use std::io::Write; +use std::thread::JoinHandle; +use std::{fs, thread}; +use tokio::runtime::Handle; +use tokio::sync::oneshot; + +#[tokio::main] +async fn main() -> Result<(), ()> { + env_logger::builder() + .format(|buf, record| { + let ts = buf.timestamp_micros(); + writeln!( + buf, + "{} [{}][{}]: {}", + ts, + record.level(), + std::thread::current().name().unwrap_or("none"), + record.args(), + ) + }) + .init(); + + fs::create_dir_all("data/").map_err(|e| { + error!("Could not create data dir: {:?}", e); + })?; + + listen_to_parentchain().await.unwrap().join().unwrap(); + Ok(()) +} + +async fn listen_to_parentchain() -> Result, ()> { + let (_sub_stop_sender, sub_stop_receiver) = oneshot::channel(); + + let relayer = EthereumIntentionExecutor::new("http://ethereum-node:8545") + .map_err(|e| log::error!("{:?}", e))?; + + let mut parentchain_listener = parentchain_listener::create_listener::( + "litentry_rococo", + Handle::current(), + "ws://litentry-node:9944", + Box::new(relayer), + sub_stop_receiver, + ) + .await?; + + Ok(thread::Builder::new() + .name("litentry_rococo_sync".to_string()) + .spawn(move || parentchain_listener.sync(0)) + .unwrap()) +} diff --git a/tee-worker/omni-executor/omni-executor.manifest b/tee-worker/omni-executor/omni-executor.manifest new file mode 100644 index 0000000000..fddc897506 --- /dev/null +++ b/tee-worker/omni-executor/omni-executor.manifest @@ -0,0 +1,44 @@ +[loader] +entrypoint = "file:/usr/lib/x86_64-linux-gnu/gramine/libsysdb.so" +log_level = "error" + +[loader.env] +LD_LIBRARY_PATH = "/lib:/lib/x86_64-linux-gnu" +MALLOC_ARENA_MAX = "1" +RUST_BACKTRACE = "full" + +[libos] +entrypoint = "target/release/omni-executor" + +[fs] +mounts = [ + { path = "/lib", uri = "file:/usr/lib/x86_64-linux-gnu/gramine/runtime/glibc" }, + { path = "/lib/x86_64-linux-gnu", uri = "file:/lib/x86_64-linux-gnu" }, +] + +[sgx] +debug = true +edmm_enable = false +trusted_files = [ + { uri = "file:/usr/lib/x86_64-linux-gnu/gramine/libsysdb.so" }, + { uri = "file:target/release/omni-executor" }, + { uri = "file:/usr/lib/x86_64-linux-gnu/gramine/runtime/glibc/" }, + { uri = "file:/lib/x86_64-linux-gnu/" }, +] +max_threads = 8 +isvprodid = 0 +isvsvn = 0 +remote_attestation = "none" +enable_stats = false +enclave_size = "256M" +use_exinfo = false + +[sgx.cpu_features] +avx = "unspecified" +avx512 = "unspecified" +amx = "unspecified" +mpx = "disabled" +pkru = "disabled" + +[sys] +enable_extra_runtime_domain_names_conf = true diff --git a/tee-worker/omni-executor/omni-executor.manifest.template b/tee-worker/omni-executor/omni-executor.manifest.template new file mode 100644 index 0000000000..b846149bff --- /dev/null +++ b/tee-worker/omni-executor/omni-executor.manifest.template @@ -0,0 +1,45 @@ +# Copyright (C) 2023 Gramine contributors +# SPDX-License-Identifier: BSD-3-Clause + +# Rust manifest example + +loader.entrypoint = "file:{{ gramine.libos }}" +libos.entrypoint = "{{ self_exe }}" +loader.log_level = "{{ log_level }}" + +loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}" + +# See https://gramine.readthedocs.io/en/stable/performance.html#glibc-malloc-tuning +loader.env.MALLOC_ARENA_MAX = "1" + +# For easier debugging — not strictly required to run this workload +loader.env.RUST_BACKTRACE = "full" + +fs.mounts = [ + { path = "/lib", uri = "file:{{ gramine.runtimedir() }}" }, + { path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" }, + { path = "/data", uri = "file:data", type="encrypted", key_name="_sgx_mrsigner" }, +] + +sgx.debug = true +sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} + + +# dns +sys.enable_extra_runtime_domain_names_conf = true + +sgx.trusted_files = [ + "file:{{ gramine.libos }}", + "file:{{ self_exe }}", + "file:{{ gramine.runtimedir() }}/", + "file:{{ arch_libdir }}/", +] + +# The maximum number of threads in a single process needs to be declared in advance. +# You need to account for: +# - one main thread +# - the tokio worker threads +# - any threads and threadpools you might be starting +# - helper threads internal to Gramine — see: +# https://gramine.readthedocs.io/en/stable/manifest-syntax.html#number-of-threads +sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '64' }} diff --git a/tee-worker/omni-executor/parentchain/artifacts/rococo-omni-execution.scale b/tee-worker/omni-executor/parentchain/artifacts/rococo-omni-execution.scale new file mode 100644 index 0000000000000000000000000000000000000000..5bf4344459694931a0ece87e84b852eb28f92aea GIT binary patch literal 234767 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 f)33Sy. + +use crate::rpc_client::SubstrateRpcClientFactory; +use crate::{listener::IntentionEventId, rpc_client::SubstrateRpcClient}; +use async_trait::async_trait; +use executor_core::fetcher::{IntentionEventsFetcher, LastFinalizedBlockNumFetcher}; +use executor_core::listener::IntentionEvent; +use log::error; + +/// Used for fetching data from parentchain +pub struct Fetcher< + RpcClient: SubstrateRpcClient, + RpcClientFactory: SubstrateRpcClientFactory, +> { + client_factory: RpcClientFactory, + client: Option, +} + +impl> + Fetcher +{ + pub fn new(client_factory: RpcClientFactory) -> Self { + Self { client: None, client_factory } + } + + async fn connect_if_needed(&mut self) { + if self.client.is_none() { + match self.client_factory.new_client().await { + Ok(client) => self.client = Some(client), + Err(e) => error!("Could not create client: {:?}", e), + } + } + } +} + +#[async_trait] +impl< + RpcClient: SubstrateRpcClient + Sync + Send, + RpcClientFactory: SubstrateRpcClientFactory + Sync + Send, + > LastFinalizedBlockNumFetcher for Fetcher +{ + async fn get_last_finalized_block_num(&mut self) -> Result, ()> { + self.connect_if_needed().await; + + if let Some(ref mut client) = self.client { + let block_num = client.get_last_finalized_block_num().await?; + Ok(Some(block_num)) + } else { + Err(()) + } + } +} + +#[async_trait] +impl< + RpcClient: SubstrateRpcClient + Sync + Send, + RpcClientFactory: SubstrateRpcClientFactory + Sync + Send, + > IntentionEventsFetcher for Fetcher +{ + async fn get_block_events( + &mut self, + block_num: u64, + ) -> Result>, ()> { + self.connect_if_needed().await; + + if let Some(ref mut client) = self.client { + client.get_block_events(block_num).await.map(|events| { + events.into_iter().map(|event| IntentionEvent::new(event.id)).collect() + }) + } else { + Ok(vec![]) + } + } +} diff --git a/tee-worker/omni-executor/parentchain/listener/src/lib.rs b/tee-worker/omni-executor/parentchain/listener/src/lib.rs new file mode 100644 index 0000000000..a9b6f35650 --- /dev/null +++ b/tee-worker/omni-executor/parentchain/listener/src/lib.rs @@ -0,0 +1,98 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +mod fetcher; +mod listener; +mod primitives; +mod rpc_client; + +use crate::fetcher::Fetcher; +use crate::listener::ParentchainListener; +use crate::rpc_client::{SubxtClient, SubxtClientFactory}; +use executor_core::intention_executor::IntentionExecutor; +use executor_core::listener::Listener; +use executor_core::sync_checkpoint_repository::FileCheckpointRepository; +use scale_encode::EncodeAsType; +use subxt::config::signed_extensions; +use subxt::Config; +use tokio::runtime::Handle; +use tokio::sync::oneshot::Receiver; + +// Generate an interface that we can use from the node's metadata. +#[subxt::subxt(runtime_metadata_path = "../artifacts/rococo-omni-execution.scale")] +pub mod litentry_rococo {} + +// We don't need to construct this at runtime, +// so an empty enum is appropriate: +#[derive(EncodeAsType)] +pub enum CustomConfig {} + +//todo: adjust if needed +impl Config for CustomConfig { + type Hash = subxt::utils::H256; + type AccountId = subxt::utils::AccountId32; + type Address = subxt::utils::MultiAddress; + type Signature = subxt::utils::MultiSignature; + type Hasher = subxt::config::substrate::BlakeTwo256; + type Header = subxt::config::substrate::SubstrateHeader; + type ExtrinsicParams = signed_extensions::AnyOf< + Self, + ( + // Load in the existing signed extensions we're interested in + // (if the extension isn't actually needed it'll just be ignored): + signed_extensions::CheckSpecVersion, + signed_extensions::CheckTxVersion, + signed_extensions::CheckNonce, + signed_extensions::CheckGenesis, + signed_extensions::CheckMortality, + signed_extensions::ChargeAssetTxPayment, + signed_extensions::ChargeTransactionPayment, + signed_extensions::CheckMetadataHash, + ), + >; + type AssetId = u32; +} + +/// Creates parentchain listener +pub async fn create_listener( + id: &str, + handle: Handle, + ws_rpc_endpoint: &str, + intention_executor: Box, + stop_signal: Receiver<()>, +) -> Result< + ParentchainListener< + SubxtClient, + SubxtClientFactory, + FileCheckpointRepository, + >, + (), +> { + let client_factory: SubxtClientFactory = SubxtClientFactory::new(ws_rpc_endpoint); + + let fetcher = Fetcher::new(client_factory); + let last_processed_log_repository = + FileCheckpointRepository::new("data/parentchain_last_log.bin"); + + Listener::new( + id, + handle, + fetcher, + intention_executor, + stop_signal, + last_processed_log_repository, + ) +} diff --git a/tee-worker/omni-executor/parentchain/listener/src/listener.rs b/tee-worker/omni-executor/parentchain/listener/src/listener.rs new file mode 100644 index 0000000000..19b1034c12 --- /dev/null +++ b/tee-worker/omni-executor/parentchain/listener/src/listener.rs @@ -0,0 +1,29 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::fetcher::Fetcher; +use crate::primitives::EventId; +use crate::primitives::SyncCheckpoint; +use executor_core::listener::Listener; + +pub type IntentionEventId = EventId; + +pub type ParentchainListener = Listener< + Fetcher, + SyncCheckpoint, + CheckpointRepository, + IntentionEventId, +>; diff --git a/tee-worker/omni-executor/parentchain/listener/src/primitives.rs b/tee-worker/omni-executor/parentchain/listener/src/primitives.rs new file mode 100644 index 0000000000..e66edc7a91 --- /dev/null +++ b/tee-worker/omni-executor/parentchain/listener/src/primitives.rs @@ -0,0 +1,95 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::listener::IntentionEventId; +use executor_core::sync_checkpoint_repository::Checkpoint; +use parity_scale_codec::{Decode, Encode}; + +/// Used to uniquely identify intention event on parentchain. +#[derive(Clone)] +pub struct EventId { + block_num: u64, + event_idx: u64, +} + +impl EventId { + pub fn new(block_num: u64, event_idx: u64) -> Self { + Self { block_num, event_idx } + } +} + +/// Represents parentchain sync checkpoint. +#[derive(Clone, Debug, PartialEq, Encode, Decode)] +pub struct SyncCheckpoint { + pub block_num: u64, + pub event_idx: Option, +} + +impl SyncCheckpoint { + pub fn new(block_num: u64, event_idx: Option) -> Self { + Self { block_num, event_idx } + } + + pub fn from_event_id(event_id: &EventId) -> Self { + Self::new(event_id.block_num, Some(event_id.event_idx)) + } + + pub fn from_block_num(block_num: u64) -> Self { + Self::new(block_num, None) + } + + pub fn just_block_num(&self) -> bool { + self.event_idx.is_none() + } +} + +impl Checkpoint for SyncCheckpoint { + fn just_block_num(&self) -> bool { + self.event_idx.is_none() + } + + fn get_block_num(&self) -> u64 { + self.block_num + } +} + +impl From for SyncCheckpoint { + fn from(block_num: u64) -> Self { + Self::from_block_num(block_num) + } +} + +impl From for SyncCheckpoint { + fn from(event_id: IntentionEventId) -> Self { + Self::from_event_id(&event_id) + } +} + +impl PartialOrd for SyncCheckpoint { + fn partial_cmp(&self, other: &Self) -> Option { + if self.block_num > other.block_num { + Some(std::cmp::Ordering::Greater) + } else if self.block_num < other.block_num { + Some(std::cmp::Ordering::Less) + } else if self.event_idx > other.event_idx { + Some(std::cmp::Ordering::Greater) + } else if self.event_idx < other.event_idx { + Some(std::cmp::Ordering::Less) + } else { + Some(std::cmp::Ordering::Equal) + } + } +} diff --git a/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs b/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs new file mode 100644 index 0000000000..1748b1edbf --- /dev/null +++ b/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs @@ -0,0 +1,142 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::primitives::EventId; +use async_trait::async_trait; +use std::marker::PhantomData; +use subxt::backend::legacy::LegacyRpcMethods; +use subxt::backend::BlockRef; +use subxt::config::Header; +use subxt::events::EventsClient; +use subxt::{Config, OnlineClient}; + +pub struct BlockEvent { + pub id: EventId, + pub pallet_name: String, + pub variant_name: String, + pub field_bytes: Vec, +} + +impl BlockEvent { + pub fn new( + id: EventId, + pallet_name: String, + variant_name: String, + field_bytes: Vec, + ) -> Self { + Self { id, pallet_name, variant_name, field_bytes } + } +} + +/// For fetching data from Substrate RPC node +#[async_trait] +pub trait SubstrateRpcClient { + async fn get_last_finalized_block_num(&mut self) -> Result; + async fn get_block_events(&mut self, block_num: u64) -> Result, ()>; +} + +pub struct SubxtClient { + legacy: LegacyRpcMethods, + events: EventsClient>, +} + +impl SubxtClient {} + +#[async_trait] +impl SubstrateRpcClient for SubxtClient { + async fn get_last_finalized_block_num(&mut self) -> Result { + let finalized_header = self.legacy.chain_get_finalized_head().await.map_err(|_| ())?; + match self.legacy.chain_get_header(Some(finalized_header)).await.map_err(|_| ())? { + Some(header) => Ok(header.number().into()), + None => Err(()), + } + } + async fn get_block_events(&mut self, block_num: u64) -> Result, ()> { + match self.legacy.chain_get_block_hash(Some(block_num.into())).await.map_err(|_| ())? { + Some(hash) => { + let events = self.events.at(BlockRef::from_hash(hash)).await.map_err(|_| ())?; + + Ok(events + .iter() + .enumerate() + .map(|(i, event)| { + let event = event.unwrap(); + BlockEvent::new( + EventId::new(block_num, i as u64), + event.pallet_name().to_string(), + event.variant_name().to_string(), + event.field_bytes().to_vec(), + ) + }) + .collect()) + }, + None => Err(()), + } + } +} + +pub struct MockedRpcClient { + block_num: u64, +} + +#[async_trait] +impl SubstrateRpcClient for MockedRpcClient { + async fn get_last_finalized_block_num(&mut self) -> Result { + Ok(self.block_num) + } + + async fn get_block_events(&mut self, _block_num: u64) -> Result, ()> { + Ok(vec![]) + } +} + +#[async_trait] +pub trait SubstrateRpcClientFactory { + async fn new_client(&self) -> Result; +} + +pub struct SubxtClientFactory { + url: String, + _phantom: PhantomData, +} + +impl SubxtClientFactory { + pub fn new(url: &str) -> Self { + Self { url: url.to_string(), _phantom: PhantomData } + } +} + +#[async_trait] +impl SubstrateRpcClientFactory> + for SubxtClientFactory +{ + async fn new_client(&self) -> Result, ()> { + let rpc_client = subxt::backend::rpc::RpcClient::from_insecure_url(self.url.clone()) + .await + .map_err(|e| { + log::error!("Could not create RpcClient: {:?}", e); + })?; + let legacy = LegacyRpcMethods::new(rpc_client); + + let online_client = + OnlineClient::from_insecure_url(self.url.clone()).await.map_err(|e| { + log::error!("Could not create OnlineClient: {:?}", e); + })?; + let events = online_client.events(); + + Ok(SubxtClient { legacy, events }) + } +} diff --git a/tee-worker/omni-executor/rust-toolchain.toml b/tee-worker/omni-executor/rust-toolchain.toml new file mode 100644 index 0000000000..c72b613e98 --- /dev/null +++ b/tee-worker/omni-executor/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.79" +profile = "default" # include rustfmt, clippy From 3adbc13e908fac099b250764786704bcc4a05c12 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Wed, 9 Oct 2024 09:15:41 +0200 Subject: [PATCH 02/10] taplo fmt --- tee-worker/omni-executor/Cargo.toml | 4 ++-- .../ethereum/intention-executor/Cargo.toml | 6 +++--- tee-worker/omni-executor/executor-core/Cargo.toml | 3 +-- tee-worker/omni-executor/executor-worker/Cargo.toml | 12 ++++++------ .../omni-executor/parentchain/listener/Cargo.toml | 8 ++++---- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/tee-worker/omni-executor/Cargo.toml b/tee-worker/omni-executor/Cargo.toml index 3ad1c90515..1672f89225 100644 --- a/tee-worker/omni-executor/Cargo.toml +++ b/tee-worker/omni-executor/Cargo.toml @@ -3,7 +3,7 @@ members = [ "executor-core", "executor-worker", "parentchain/listener", - "ethereum/intention-executor" + "ethereum/intention-executor", ] resolver = "2" @@ -19,4 +19,4 @@ env_logger = "0.11.5" scale-encode = "0.7.1" parity-scale-codec = "3.6.12" alloy = "0.3.6" -clap = "4.5.17" \ No newline at end of file +clap = "4.5.17" diff --git a/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml b/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml index aadb6d4c16..763052599c 100644 --- a/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml +++ b/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition.workspace = true [dependencies] -executor-core = { path = "../../executor-core" } +alloy = { workspace = true, features = ["contract", "signer-local", "rpc", "rpc-types"] } async-trait = { workspace = true } -alloy = { workspace = true, features = ["contract", "signer-local", "rpc", "rpc-types"]} -log = { workspace = true } \ No newline at end of file +executor-core = { path = "../../executor-core" } +log = { workspace = true } diff --git a/tee-worker/omni-executor/executor-core/Cargo.toml b/tee-worker/omni-executor/executor-core/Cargo.toml index 45c1cb7a91..59c748b914 100644 --- a/tee-worker/omni-executor/executor-core/Cargo.toml +++ b/tee-worker/omni-executor/executor-core/Cargo.toml @@ -4,8 +4,7 @@ version = "0.1.0" edition.workspace = true [dependencies] -tokio = { workspace = true } async-trait = { workspace = true } log = { workspace = true } parity-scale-codec = { workspace = true, features = ["derive"] } - +tokio = { workspace = true } diff --git a/tee-worker/omni-executor/executor-worker/Cargo.toml b/tee-worker/omni-executor/executor-worker/Cargo.toml index 220852623e..41a254634a 100644 --- a/tee-worker/omni-executor/executor-worker/Cargo.toml +++ b/tee-worker/omni-executor/executor-worker/Cargo.toml @@ -4,12 +4,12 @@ version = "0.1.0" edition = "2021" [dependencies] -tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } -serde_json = "1.0.127" -scale-encode = { workspace = true } env_logger = { workspace = true } -log = { workspace = true } -intention-executor = { path = "../ethereum/intention-executor" } executor-core = { path = "../executor-core" } +hex = "0.4.3" +intention-executor = { path = "../ethereum/intention-executor" } +log = { workspace = true } parentchain-listener = { path = "../parentchain/listener" } -hex = "0.4.3" \ No newline at end of file +scale-encode = { workspace = true } +serde_json = "1.0.127" +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/tee-worker/omni-executor/parentchain/listener/Cargo.toml b/tee-worker/omni-executor/parentchain/listener/Cargo.toml index 4a340fc848..50a6b54cc8 100644 --- a/tee-worker/omni-executor/parentchain/listener/Cargo.toml +++ b/tee-worker/omni-executor/parentchain/listener/Cargo.toml @@ -4,13 +4,13 @@ version = "0.1.0" edition = "2021" [dependencies] -log = { workspace = true } -executor-core = { path = "../../executor-core" } async-trait = { workspace = true } +executor-core = { path = "../../executor-core" } +log = { workspace = true } parity-scale-codec = { workspace = true, features = ["derive"] } -subxt = "0.37.0" scale-encode = "0.7.1" -tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +subxt = "0.37.0" +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } [dev-dependencies] env_logger = { workspace = true } From 824b51feea0a71aeaa75bbbee5588322e2b730d4 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Wed, 9 Oct 2024 14:44:35 +0200 Subject: [PATCH 03/10] add authors --- .../omni-executor/ethereum/intention-executor/Cargo.toml | 1 + tee-worker/omni-executor/executor-core/Cargo.toml | 1 + tee-worker/omni-executor/executor-worker/Cargo.toml | 3 ++- tee-worker/omni-executor/parentchain/listener/Cargo.toml | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml b/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml index 763052599c..2c62fda636 100644 --- a/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml +++ b/tee-worker/omni-executor/ethereum/intention-executor/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "intention-executor" version = "0.1.0" +authors = ['Trust Computing GmbH '] edition.workspace = true [dependencies] diff --git a/tee-worker/omni-executor/executor-core/Cargo.toml b/tee-worker/omni-executor/executor-core/Cargo.toml index 59c748b914..2139accc31 100644 --- a/tee-worker/omni-executor/executor-core/Cargo.toml +++ b/tee-worker/omni-executor/executor-core/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "executor-core" version = "0.1.0" +authors = ['Trust Computing GmbH '] edition.workspace = true [dependencies] diff --git a/tee-worker/omni-executor/executor-worker/Cargo.toml b/tee-worker/omni-executor/executor-worker/Cargo.toml index 41a254634a..fb174d0914 100644 --- a/tee-worker/omni-executor/executor-worker/Cargo.toml +++ b/tee-worker/omni-executor/executor-worker/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "executor-worker" version = "0.1.0" -edition = "2021" +authors = ['Trust Computing GmbH '] +edition.workspace = true [dependencies] env_logger = { workspace = true } diff --git a/tee-worker/omni-executor/parentchain/listener/Cargo.toml b/tee-worker/omni-executor/parentchain/listener/Cargo.toml index 50a6b54cc8..7c1fc8ce71 100644 --- a/tee-worker/omni-executor/parentchain/listener/Cargo.toml +++ b/tee-worker/omni-executor/parentchain/listener/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "parentchain-listener" version = "0.1.0" -edition = "2021" +authors = ['Trust Computing GmbH '] +edition.workspace = true [dependencies] async-trait = { workspace = true } From 7feab3dfb5f31c12f3a6a185f718e2db335c222c Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Fri, 11 Oct 2024 09:16:15 +0200 Subject: [PATCH 04/10] intention events handling --- tee-worker/omni-executor/Makefile | 2 +- .../ethereum/intention-executor/src/lib.rs | 10 +- .../omni-executor/executor-core/Cargo.toml | 2 +- .../executor-core/src/event_handler.rs | 22 ++++ .../executor-core/src/fetcher.rs | 6 +- .../omni-executor/executor-core/src/lib.rs | 1 + .../executor-core/src/listener.rs | 80 +++++++------ .../executor-core/src/primitives.rs | 8 +- .../omni-executor/executor-worker/src/main.rs | 19 ++-- .../artifacts/rococo-omni-account.scale | Bin 0 -> 23189 bytes .../artifacts/rococo-omni-execution.scale | Bin 234767 -> 0 bytes .../parentchain/listener/src/event_handler.rs | 107 ++++++++++++++++++ .../parentchain/listener/src/fetcher.rs | 22 ++-- .../parentchain/listener/src/lib.rs | 21 +++- .../parentchain/listener/src/listener.rs | 15 ++- .../parentchain/listener/src/metadata.rs | 45 ++++++++ .../parentchain/listener/src/primitives.rs | 33 +++++- .../parentchain/listener/src/rpc_client.rs | 35 +++--- 18 files changed, 332 insertions(+), 96 deletions(-) create mode 100644 tee-worker/omni-executor/executor-core/src/event_handler.rs create mode 100644 tee-worker/omni-executor/parentchain/artifacts/rococo-omni-account.scale delete mode 100644 tee-worker/omni-executor/parentchain/artifacts/rococo-omni-execution.scale create mode 100644 tee-worker/omni-executor/parentchain/listener/src/event_handler.rs create mode 100644 tee-worker/omni-executor/parentchain/listener/src/metadata.rs diff --git a/tee-worker/omni-executor/Makefile b/tee-worker/omni-executor/Makefile index 92b0c87557..375c12114e 100644 --- a/tee-worker/omni-executor/Makefile +++ b/tee-worker/omni-executor/Makefile @@ -75,4 +75,4 @@ stop-local: .PHONY: get-omni-pallet-metadata get-omni-pallet-metadata: - subxt metadata --url http://localhost:9944 --allow-insecure --pallets OmniExecution > substrate/artifacts/rococo-omni-execution.scale + subxt metadata --url http://localhost:9944 --allow-insecure --pallets OmniAccount > parentchain/artifacts/rococo-omni-account.scale diff --git a/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs b/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs index ba3fee692f..2d472938b0 100644 --- a/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs +++ b/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs @@ -16,7 +16,7 @@ use std::str::FromStr; -use alloy::network::{EthereumWallet, NetworkWallet}; +use alloy::network::EthereumWallet; use alloy::primitives::{Address, U256}; use alloy::providers::{Provider, ProviderBuilder, WalletProvider}; use alloy::rpc::types::TransactionRequest; @@ -54,12 +54,12 @@ impl IntentionExecutor for EthereumIntentionExecutor { let account = provider.get_account(provider.signer_addresses().next().unwrap()).await.unwrap(); match intention { - Intention::Transfer {} => { + Intention::TransferEthereum(to, value) => { // todo: read transfer details from intention let tx = TransactionRequest::default() - .to(Address::from_str("0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65").unwrap()) + .to(Address::from(to)) .nonce(account.nonce) - .value(U256::from(1)); + .value(U256::from_be_bytes(value)); let pending_tx = provider.send_transaction(tx).await.map_err(|e| { error!("Could not send transaction: {:?}", e); })?; @@ -68,7 +68,7 @@ impl IntentionExecutor for EthereumIntentionExecutor { error!("Could not get transaction receipt: {:?}", e); })?; }, - Intention::Call {} => todo!(), + Intention::CallEthereum(address, input) => todo!(), } Ok(()) } diff --git a/tee-worker/omni-executor/executor-core/Cargo.toml b/tee-worker/omni-executor/executor-core/Cargo.toml index 2139accc31..c4ced78d0f 100644 --- a/tee-worker/omni-executor/executor-core/Cargo.toml +++ b/tee-worker/omni-executor/executor-core/Cargo.toml @@ -8,4 +8,4 @@ edition.workspace = true async-trait = { workspace = true } log = { workspace = true } parity-scale-codec = { workspace = true, features = ["derive"] } -tokio = { workspace = true } +tokio = { workspace = true } \ No newline at end of file diff --git a/tee-worker/omni-executor/executor-core/src/event_handler.rs b/tee-worker/omni-executor/executor-core/src/event_handler.rs new file mode 100644 index 0000000000..977358b4d0 --- /dev/null +++ b/tee-worker/omni-executor/executor-core/src/event_handler.rs @@ -0,0 +1,22 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use async_trait::async_trait; + +#[async_trait] +pub trait EventHandler { + async fn handle(&self, event: BlockEvent) -> Result<(), ()>; +} diff --git a/tee-worker/omni-executor/executor-core/src/fetcher.rs b/tee-worker/omni-executor/executor-core/src/fetcher.rs index 0b068448ff..3efafbe779 100644 --- a/tee-worker/omni-executor/executor-core/src/fetcher.rs +++ b/tee-worker/omni-executor/executor-core/src/fetcher.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . -use crate::listener::IntentionEvent; +use crate::primitives::GetEventId; use async_trait::async_trait; /// Returns the last finalized block number @@ -25,6 +25,6 @@ pub trait LastFinalizedBlockNumFetcher { /// Returns all events emitted on given chain #[async_trait] -pub trait IntentionEventsFetcher { - async fn get_block_events(&mut self, block_num: u64) -> Result>, ()>; +pub trait EventsFetcher> { + async fn get_block_events(&mut self, block_num: u64) -> Result, ()>; } diff --git a/tee-worker/omni-executor/executor-core/src/lib.rs b/tee-worker/omni-executor/executor-core/src/lib.rs index 474dfb6a57..f12f2f081f 100644 --- a/tee-worker/omni-executor/executor-core/src/lib.rs +++ b/tee-worker/omni-executor/executor-core/src/lib.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . +pub mod event_handler; pub mod fetcher; pub mod intention_executor; pub mod listener; diff --git a/tee-worker/omni-executor/executor-core/src/listener.rs b/tee-worker/omni-executor/executor-core/src/listener.rs index 6edf573492..8558c2cfb3 100644 --- a/tee-worker/omni-executor/executor-core/src/listener.rs +++ b/tee-worker/omni-executor/executor-core/src/listener.rs @@ -14,15 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . +use std::fmt::Debug; use std::{marker::PhantomData, thread::sleep, time::Duration}; - use tokio::{runtime::Handle, sync::oneshot::Receiver}; -use crate::fetcher::{IntentionEventsFetcher, LastFinalizedBlockNumFetcher}; -use crate::{ - intention_executor::IntentionExecutor, - sync_checkpoint_repository::{Checkpoint, CheckpointRepository}, -}; +use crate::event_handler::EventHandler; +use crate::fetcher::{EventsFetcher, LastFinalizedBlockNumFetcher}; +use crate::primitives::GetEventId; +use crate::sync_checkpoint_repository::{Checkpoint, CheckpointRepository}; /// Represents event emitted on listened chain. #[derive(Clone, Debug, PartialEq)] @@ -39,31 +38,43 @@ impl IntentionEvent { /// Component, used to listen to chain and execute requested intentions /// Requires specific implementations of: -/// `Fetcher` - used to fetch data from source chain -/// `IntentionExecutor` - used to execute intentions on destination chain +/// `Fetcher` - used to fetch data from chain +/// `IntentionExecutor` - used to execute intentions on target chain /// `CheckpointRepository` - used to store listener's progress -pub struct Listener { +/// `EventId` - represents chain event id +/// `BlockEvent` - represents chain event +pub struct Listener< + Fetcher, + Checkpoint, + CheckpointRepository, + BlockEventId, + BlockEvent, + IntentionEventHandler, +> { id: String, handle: Handle, fetcher: Fetcher, - intention_executor: Box, + intention_event_handler: IntentionEventHandler, stop_signal: Receiver<()>, checkpoint_repository: CheckpointRepository, - _phantom: PhantomData<(Checkpoint, IntentionEvent)>, + _phantom: PhantomData<(Checkpoint, BlockEventId, BlockEvent)>, } impl< - EventId: Into + Clone, - Fetcher: LastFinalizedBlockNumFetcher + IntentionEventsFetcher, + EventId: Into + Clone + Debug, + BlockEventT: GetEventId, + Fetcher: LastFinalizedBlockNumFetcher + EventsFetcher, CheckpointT: PartialOrd + Checkpoint + From, CheckpointRepositoryT: CheckpointRepository, - > Listener + IntentionEventHandler: EventHandler, + > + Listener { pub fn new( id: &str, handle: Handle, fetcher: Fetcher, - intention_executor: Box, + intention_event_handler: IntentionEventHandler, stop_signal: Receiver<()>, last_processed_log_repository: CheckpointRepositoryT, ) -> Result { @@ -71,7 +82,7 @@ impl< id: id.to_string(), handle, fetcher, - intention_executor, + intention_event_handler, stop_signal, checkpoint_repository: last_processed_log_repository, _phantom: PhantomData, @@ -97,7 +108,7 @@ impl< }; log::debug!("Starting sync from {:?}", block_number_to_sync); - 'main: loop { + loop { log::info!("Syncing block: {}", block_number_to_sync); if self.stop_signal.try_recv().is_ok() { break; @@ -142,37 +153,38 @@ impl< self.handle.block_on(self.fetcher.get_block_events(block_number_to_sync)) { for event in events { + let event_id = event.get_event_id().clone(); if let Some(ref checkpoint) = self.checkpoint_repository.get().expect("Could not read checkpoint") { - if checkpoint.lt(&event.id.clone().into()) { + if checkpoint.lt(&event.get_event_id().clone().into()) { log::info!("Executing intention"); - if let Err(e) = self.handle.block_on( - self.intention_executor - .execute(crate::primitives::Intention::Transfer {}), - ) { + if let Err(e) = + self.handle.block_on(self.intention_event_handler.handle(event)) + { log::error!("Could not execute intention: {:?}", e); - sleep(Duration::from_secs(1)); - // it will try again in next loop - continue 'main; + // sleep(Duration::from_secs(1)); + // // it will try again in next loop + // continue 'main; } + log::info!("Intention executed"); } else { log::debug!("Skipping event"); } } else { - log::info!("Executing intention"); - if let Err(e) = self.handle.block_on( - self.intention_executor - .execute(crate::primitives::Intention::Call {}), - ) { + log::info!("Handling event: {:?}", event_id); + if let Err(e) = + self.handle.block_on(self.intention_event_handler.handle(event)) + { log::error!("Could not execute intention: {:?}", e); - sleep(Duration::from_secs(1)); - // it will try again in next loop - continue 'main; + // sleep(Duration::from_secs(1)); + // // it will try again in next loop + // continue 'main; } + log::info!("Intention executed"); } self.checkpoint_repository - .save(event.id.into()) + .save(event_id.into()) .expect("Could not save checkpoint"); } // we processed block completely so store new checkpoint diff --git a/tee-worker/omni-executor/executor-core/src/primitives.rs b/tee-worker/omni-executor/executor-core/src/primitives.rs index 989274c603..4dd12f93dc 100644 --- a/tee-worker/omni-executor/executor-core/src/primitives.rs +++ b/tee-worker/omni-executor/executor-core/src/primitives.rs @@ -16,6 +16,10 @@ #[derive(Debug)] pub enum Intention { - Transfer {}, - Call {}, + TransferEthereum([u8; 20], [u8; 32]), + CallEthereum([u8; 20], Vec), +} + +pub trait GetEventId { + fn get_event_id(&self) -> Id; } diff --git a/tee-worker/omni-executor/executor-worker/src/main.rs b/tee-worker/omni-executor/executor-worker/src/main.rs index 8d378d8d3d..140cfdcece 100644 --- a/tee-worker/omni-executor/executor-worker/src/main.rs +++ b/tee-worker/omni-executor/executor-worker/src/main.rs @@ -50,17 +50,18 @@ async fn main() -> Result<(), ()> { async fn listen_to_parentchain() -> Result, ()> { let (_sub_stop_sender, sub_stop_receiver) = oneshot::channel(); - let relayer = EthereumIntentionExecutor::new("http://ethereum-node:8545") + let ethereum_intention_executor = EthereumIntentionExecutor::new("http://ethereum-node:8545") .map_err(|e| log::error!("{:?}", e))?; - let mut parentchain_listener = parentchain_listener::create_listener::( - "litentry_rococo", - Handle::current(), - "ws://litentry-node:9944", - Box::new(relayer), - sub_stop_receiver, - ) - .await?; + let mut parentchain_listener = + parentchain_listener::create_listener::( + "litentry_rococo", + Handle::current(), + "ws://litentry-node:9944", + ethereum_intention_executor, + sub_stop_receiver, + ) + .await?; Ok(thread::Builder::new() .name("litentry_rococo_sync".to_string()) diff --git a/tee-worker/omni-executor/parentchain/artifacts/rococo-omni-account.scale b/tee-worker/omni-executor/parentchain/artifacts/rococo-omni-account.scale new file mode 100644 index 0000000000000000000000000000000000000000..0287a9e670fa496bc5136d18bedf326a8ee9c06f GIT binary patch literal 23189 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 literal 0 HcmV?d00001 diff --git a/tee-worker/omni-executor/parentchain/artifacts/rococo-omni-execution.scale b/tee-worker/omni-executor/parentchain/artifacts/rococo-omni-execution.scale deleted file mode 100644 index 5bf4344459694931a0ece87e84b852eb28f92aea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 234767 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 f)33Sy. + +use crate::metadata::{MetadataProvider, SubxtMetadataProvider}; +use crate::primitives::BlockEvent; +use async_trait::async_trait; +use executor_core::event_handler::EventHandler; +use executor_core::intention_executor::IntentionExecutor; +use executor_core::primitives::Intention; +use std::marker::PhantomData; +use subxt::ext::scale_decode; +use subxt::ext::scale_decode::DecodeAsFields; +use subxt::{Config, Metadata}; + +pub struct IntentionEventHandler< + MetadataT, + MetadataProviderT: MetadataProvider, + EthereumIntentionExecutorT: IntentionExecutor, +> { + metadata_provider: MetadataProviderT, + ethereum_intention_executor: EthereumIntentionExecutorT, + phantom_data: PhantomData, +} + +impl< + MetadataT, + MetadataProviderT: MetadataProvider, + EthereumIntentionExecutorT: IntentionExecutor, + > IntentionEventHandler +{ + pub fn new( + metadata_provider: MetadataProviderT, + ethereum_intention_executor: EthereumIntentionExecutorT, + ) -> Self { + Self { metadata_provider, ethereum_intention_executor, phantom_data: Default::default() } + } +} + +#[async_trait] +impl + EventHandler + for IntentionEventHandler, EthereumIntentionExecutorT> +{ + async fn handle(&self, event: BlockEvent) -> Result<(), ()> { + log::debug!("Handling block event: {:?}", event.id); + let metadata = self.metadata_provider.get(event.id.block_num).await; + + let pallet = metadata.pallet_by_name(&event.pallet_name).ok_or_else(move || { + log::error!("No metadata found for {}", event.id.block_num); + })?; + let variant = pallet.event_variant_by_index(event.variant_index).ok_or_else(move || { + log::error!("No metadata found for {}", event.id.block_num); + })?; + + let mut fields = variant + .fields + .iter() + .map(|f| scale_decode::Field::new(f.ty.id, f.name.as_deref())); + + let decoded = + crate::litentry_rococo::omni_account::events::IntentionRequested::decode_as_fields( + &mut event.field_bytes.as_slice(), + &mut fields, + metadata.types(), + ) + .map_err(|_| ())?; + + let intention = match decoded.intention { + crate::litentry_rococo::runtime_types::core_primitives::intention::Intention::CallEthereum(call_ethereum) => { + Intention::CallEthereum(call_ethereum.address.to_fixed_bytes(), call_ethereum.input.0) + }, + crate::litentry_rococo::runtime_types::core_primitives::intention::Intention::TransferEthereum(transfer) => { + Intention::TransferEthereum(transfer.to.to_fixed_bytes(), [0; 32]) + } + }; + + //to explicitly handle all intention variants + match intention { + Intention::CallEthereum(_, _) => { + self.ethereum_intention_executor + .execute(intention) + .await + .map_err(|e| log::error!("Error executing intention"))?; + }, + Intention::TransferEthereum(_, _) => { + self.ethereum_intention_executor + .execute(intention) + .await + .map_err(|e| log::error!("Error executing intention"))?; + }, + } + Ok(()) + } +} diff --git a/tee-worker/omni-executor/parentchain/listener/src/fetcher.rs b/tee-worker/omni-executor/parentchain/listener/src/fetcher.rs index 87a309b874..c8f9264d5a 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/fetcher.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/fetcher.rs @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . +use crate::primitives::{BlockEvent, EventId}; +use crate::rpc_client::SubstrateRpcClient; use crate::rpc_client::SubstrateRpcClientFactory; -use crate::{listener::IntentionEventId, rpc_client::SubstrateRpcClient}; use async_trait::async_trait; -use executor_core::fetcher::{IntentionEventsFetcher, LastFinalizedBlockNumFetcher}; -use executor_core::listener::IntentionEvent; +use executor_core::fetcher::{EventsFetcher, LastFinalizedBlockNumFetcher}; use log::error; /// Used for fetching data from parentchain @@ -69,20 +69,18 @@ impl< impl< RpcClient: SubstrateRpcClient + Sync + Send, RpcClientFactory: SubstrateRpcClientFactory + Sync + Send, - > IntentionEventsFetcher for Fetcher + > EventsFetcher for Fetcher { - async fn get_block_events( - &mut self, - block_num: u64, - ) -> Result>, ()> { + async fn get_block_events(&mut self, block_num: u64) -> Result, ()> { self.connect_if_needed().await; if let Some(ref mut client) = self.client { - client.get_block_events(block_num).await.map(|events| { - events.into_iter().map(|event| IntentionEvent::new(event.id)).collect() - }) + client.get_block_events(block_num).await + // client.get_block_events(block_num).await.map(|events| { + // events.into_iter().map(|event| IntentionEvent::new(event.id)).collect() + // }) } else { - Ok(vec![]) + Err(()) } } } diff --git a/tee-worker/omni-executor/parentchain/listener/src/lib.rs b/tee-worker/omni-executor/parentchain/listener/src/lib.rs index a9b6f35650..7ef8f940d2 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/lib.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/lib.rs @@ -14,13 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . +mod event_handler; mod fetcher; mod listener; +mod metadata; mod primitives; mod rpc_client; +use crate::event_handler::IntentionEventHandler; use crate::fetcher::Fetcher; use crate::listener::ParentchainListener; +use crate::metadata::SubxtMetadataProvider; use crate::rpc_client::{SubxtClient, SubxtClientFactory}; use executor_core::intention_executor::IntentionExecutor; use executor_core::listener::Listener; @@ -32,7 +36,7 @@ use tokio::runtime::Handle; use tokio::sync::oneshot::Receiver; // Generate an interface that we can use from the node's metadata. -#[subxt::subxt(runtime_metadata_path = "../artifacts/rococo-omni-execution.scale")] +#[subxt::subxt(runtime_metadata_path = "../artifacts/rococo-omni-account.scale")] pub mod litentry_rococo {} // We don't need to construct this at runtime, @@ -67,17 +71,22 @@ impl Config for CustomConfig { } /// Creates parentchain listener -pub async fn create_listener( +pub async fn create_listener< + ChainConfig: Config, + EthereumIntentionExecutorT: IntentionExecutor + Send + Sync, +>( id: &str, handle: Handle, ws_rpc_endpoint: &str, - intention_executor: Box, + ethereum_intention_executor: EthereumIntentionExecutorT, stop_signal: Receiver<()>, ) -> Result< ParentchainListener< SubxtClient, SubxtClientFactory, FileCheckpointRepository, + ChainConfig, + EthereumIntentionExecutorT, >, (), > { @@ -87,11 +96,15 @@ pub async fn create_listener( let last_processed_log_repository = FileCheckpointRepository::new("data/parentchain_last_log.bin"); + let metadata_provider = SubxtMetadataProvider::new(SubxtClientFactory::new(ws_rpc_endpoint)); + let intention_event_handler = + IntentionEventHandler::new(metadata_provider, ethereum_intention_executor); + Listener::new( id, handle, fetcher, - intention_executor, + intention_event_handler, stop_signal, last_processed_log_repository, ) diff --git a/tee-worker/omni-executor/parentchain/listener/src/listener.rs b/tee-worker/omni-executor/parentchain/listener/src/listener.rs index 19b1034c12..b32d65a93d 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/listener.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/listener.rs @@ -14,16 +14,27 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . +use crate::event_handler::IntentionEventHandler; use crate::fetcher::Fetcher; -use crate::primitives::EventId; +use crate::metadata::SubxtMetadataProvider; use crate::primitives::SyncCheckpoint; +use crate::primitives::{BlockEvent, EventId}; use executor_core::listener::Listener; +use subxt::Metadata; pub type IntentionEventId = EventId; -pub type ParentchainListener = Listener< +pub type ParentchainListener< + RpcClient, + RpcClientFactory, + CheckpointRepository, + ChainConfig, + EthereumIntentionExecutor, +> = Listener< Fetcher, SyncCheckpoint, CheckpointRepository, IntentionEventId, + BlockEvent, + IntentionEventHandler, EthereumIntentionExecutor>, >; diff --git a/tee-worker/omni-executor/parentchain/listener/src/metadata.rs b/tee-worker/omni-executor/parentchain/listener/src/metadata.rs new file mode 100644 index 0000000000..fbd0c9838f --- /dev/null +++ b/tee-worker/omni-executor/parentchain/listener/src/metadata.rs @@ -0,0 +1,45 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::rpc_client::{SubstrateRpcClient, SubstrateRpcClientFactory, SubxtClientFactory}; +use async_trait::async_trait; +use parity_scale_codec::Decode; +use subxt::{Config, Metadata}; + +#[async_trait] +pub trait MetadataProvider { + async fn get(&self, block_num: u64) -> M; +} + +pub struct SubxtMetadataProvider { + client_factory: SubxtClientFactory, +} + +impl SubxtMetadataProvider { + pub fn new(client_factory: SubxtClientFactory) -> Self { + Self { client_factory } + } +} + +#[async_trait] +impl MetadataProvider for SubxtMetadataProvider { + async fn get(&self, block_num: u64) -> Metadata { + let mut client = self.client_factory.new_client().await.unwrap(); + let raw_metadata = client.get_raw_metadata(block_num).await.unwrap(); + + Metadata::decode(&mut raw_metadata.as_slice()).unwrap() + } +} diff --git a/tee-worker/omni-executor/parentchain/listener/src/primitives.rs b/tee-worker/omni-executor/parentchain/listener/src/primitives.rs index e66edc7a91..08e161e198 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/primitives.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/primitives.rs @@ -15,14 +15,15 @@ // along with Litentry. If not, see . use crate::listener::IntentionEventId; +use executor_core::primitives::GetEventId; use executor_core::sync_checkpoint_repository::Checkpoint; use parity_scale_codec::{Decode, Encode}; /// Used to uniquely identify intention event on parentchain. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct EventId { - block_num: u64, - event_idx: u64, + pub block_num: u64, + pub event_idx: u64, } impl EventId { @@ -93,3 +94,29 @@ impl PartialOrd for SyncCheckpoint { } } } + +pub struct BlockEvent { + pub id: EventId, + pub pallet_name: String, + pub variant_name: String, + pub variant_index: u8, + pub field_bytes: Vec, +} + +impl BlockEvent { + pub fn new( + id: EventId, + pallet_name: String, + variant_name: String, + variant_index: u8, + field_bytes: Vec, + ) -> Self { + Self { id, pallet_name, variant_name, variant_index, field_bytes } + } +} + +impl GetEventId for BlockEvent { + fn get_event_id(&self) -> EventId { + self.id.clone() + } +} diff --git a/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs b/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs index 1748b1edbf..a42f6b34f3 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs @@ -14,38 +14,23 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . -use crate::primitives::EventId; +use crate::primitives::{BlockEvent, EventId}; use async_trait::async_trait; +use parity_scale_codec::Encode; use std::marker::PhantomData; +use std::ops::Deref; use subxt::backend::legacy::LegacyRpcMethods; use subxt::backend::BlockRef; use subxt::config::Header; use subxt::events::EventsClient; use subxt::{Config, OnlineClient}; -pub struct BlockEvent { - pub id: EventId, - pub pallet_name: String, - pub variant_name: String, - pub field_bytes: Vec, -} - -impl BlockEvent { - pub fn new( - id: EventId, - pallet_name: String, - variant_name: String, - field_bytes: Vec, - ) -> Self { - Self { id, pallet_name, variant_name, field_bytes } - } -} - /// For fetching data from Substrate RPC node #[async_trait] pub trait SubstrateRpcClient { async fn get_last_finalized_block_num(&mut self) -> Result; async fn get_block_events(&mut self, block_num: u64) -> Result, ()>; + async fn get_raw_metadata(&mut self, block_num: u64) -> Result, ()>; } pub struct SubxtClient { @@ -68,7 +53,6 @@ impl SubstrateRpcClient for SubxtClient { match self.legacy.chain_get_block_hash(Some(block_num.into())).await.map_err(|_| ())? { Some(hash) => { let events = self.events.at(BlockRef::from_hash(hash)).await.map_err(|_| ())?; - Ok(events .iter() .enumerate() @@ -78,6 +62,7 @@ impl SubstrateRpcClient for SubxtClient { EventId::new(block_num, i as u64), event.pallet_name().to_string(), event.variant_name().to_string(), + event.variant_index(), event.field_bytes().to_vec(), ) }) @@ -86,6 +71,12 @@ impl SubstrateRpcClient for SubxtClient { None => Err(()), } } + + async fn get_raw_metadata(&mut self, block_num: u64) -> Result, ()> { + let maybe_hash = + self.legacy.chain_get_block_hash(Some(block_num.into())).await.map_err(|_| ())?; + Ok(self.legacy.state_get_metadata(maybe_hash).await.unwrap().deref().encode()) + } } pub struct MockedRpcClient { @@ -101,6 +92,10 @@ impl SubstrateRpcClient for MockedRpcClient { async fn get_block_events(&mut self, _block_num: u64) -> Result, ()> { Ok(vec![]) } + + async fn get_raw_metadata(&mut self, _block_num: u64) -> Result, ()> { + Ok(vec![]) + } } #[async_trait] From 70e0184112e7ba763d6c0a238de34f1ac2a9ef94 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Wed, 9 Oct 2024 11:07:51 +0200 Subject: [PATCH 05/10] add omni-account request intention call --- common/primitives/core/src/intention.rs | 29 ++++++++++++ common/primitives/core/src/lib.rs | 3 ++ parachain/pallets/omni-account/src/lib.rs | 12 ++++- parachain/pallets/omni-account/src/tests.rs | 43 ++++++++++++++++++ .../ethereum/intention-executor/src/lib.rs | 17 +++++-- .../executor-core/src/event_handler.rs | 8 +++- .../executor-core/src/listener.rs | 21 +++++++-- .../artifacts/rococo-omni-account.scale | Bin 23189 -> 23193 bytes .../parentchain/listener/src/event_handler.rs | 43 ++++++++++++------ 9 files changed, 152 insertions(+), 24 deletions(-) create mode 100644 common/primitives/core/src/intention.rs diff --git a/common/primitives/core/src/intention.rs b/common/primitives/core/src/intention.rs new file mode 100644 index 0000000000..f49f77270b --- /dev/null +++ b/common/primitives/core/src/intention.rs @@ -0,0 +1,29 @@ +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::{H160}; +use sp_runtime::{traits::ConstU32, BoundedVec}; + +pub const CALL_ETHEREUM_INPUT_LEN: u32 = 10 * 1024; + +//todo: this should be versioned ? +#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, MaxEncodedLen, TypeInfo)] +pub enum Intention { + #[codec(index = 0)] + TransferEthereum(TransferEthereum), + #[codec(index = 1)] + CallEthereum(CallEthereum), +} + +#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, MaxEncodedLen, TypeInfo)] +pub struct TransferEthereum { + pub to: H160, + pub value: [u8; 32], +} + +pub type CallEthereumInputLen = ConstU32; + +#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, MaxEncodedLen, TypeInfo)] +pub struct CallEthereum { + pub address: H160, + pub input: BoundedVec, +} diff --git a/common/primitives/core/src/lib.rs b/common/primitives/core/src/lib.rs index acea7e721f..0151bc4a66 100644 --- a/common/primitives/core/src/lib.rs +++ b/common/primitives/core/src/lib.rs @@ -29,6 +29,9 @@ pub use assertion::Assertion; pub mod identity; pub use identity::*; +pub mod intention; +pub use intention::*; + extern crate alloc; extern crate core; use alloc::{format, str, str::FromStr, string::String, vec, vec::Vec}; diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index f2676ec01d..639b0fc571 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -21,7 +21,7 @@ mod mock; #[cfg(test)] mod tests; -pub use core_primitives::{Identity, MemberIdentity}; +pub use core_primitives::{Identity, Intention, MemberIdentity}; pub use frame_system::pallet_prelude::BlockNumberFor; pub use pallet::*; @@ -157,6 +157,8 @@ pub mod pallet { DispatchedAsOmniAccount { who: T::AccountId, result: DispatchResult }, /// Some call is dispatched as signed origin DispatchedAsSigned { who: T::AccountId, result: DispatchResult }, + /// Intention is requested + IntentionRequested { who: T::AccountId, intention: Intention }, } #[pallet::error] @@ -311,6 +313,14 @@ pub mod pallet { Ok(()) } + + #[pallet::call_index(5)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn request_intention(origin: OriginFor, intention: Intention) -> DispatchResult { + let who = T::OmniAccountOrigin::ensure_origin(origin)?; + Self::deposit_event(Event::IntentionRequested { who, intention }); + Ok(()) + } } impl Pallet { diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index 0e3855195a..e582870300 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -15,8 +15,10 @@ // along with Litentry. If not, see . use crate::{mock::*, AccountStore, MemberAccountHash, *}; +use core_primitives::CallEthereum; use core_primitives::Identity; use frame_support::{assert_noop, assert_ok}; +use sp_core::H160; use sp_runtime::{traits::BadOrigin, ModuleError}; use sp_std::vec; @@ -34,6 +36,10 @@ fn publicize_account_call(hash: H256, id: MemberIdentity) -> Box { Box::new(call) } +fn request_intention_call(intention: Intention) -> Box { + RuntimeCall::OmniAccount(crate::Call::request_intention { intention }).into() +} + fn make_balance_transfer_call(dest: AccountId, value: Balance) -> Box { let call = RuntimeCall::Balances(pallet_balances::Call::transfer { dest, value }); Box::new(call) @@ -614,6 +620,43 @@ fn publicize_account_identity_is_private_check_works() { }); } +#[test] +fn request_intention_works() { + new_test_ext().execute_with(|| { + let tee_signer = get_tee_signer(); + let who = alice(); + let who_identity = Identity::from(who.clone()); + let who_identity_hash = who_identity.hash(); + assert_ok!(OmniAccount::add_account( + RuntimeOrigin::signed(tee_signer.clone()), + who_identity, + MemberAccount { + id: MemberIdentity::Private(vec![1, 2, 3]), + hash: H256::from(blake2_256(&[1, 2, 3])), + }, + None + )); + let intention = Intention::CallEthereum(CallEthereum { + address: H160::zero(), + input: BoundedVec::new(), + }); + + let call = request_intention_call(intention.clone()); + assert_ok!(OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + who_identity_hash, + call + )); + + System::assert_has_event( + Event::DispatchedAsOmniAccount { who: who.clone(), result: DispatchResult::Ok(()) } + .into(), + ); + + System::assert_has_event(Event::IntentionRequested { who: who.clone(), intention }.into()); + }); +} + #[test] fn dispatch_as_signed_works() { new_test_ext().execute_with(|| { diff --git a/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs b/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs index 2d472938b0..9ae22727c4 100644 --- a/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs +++ b/tee-worker/omni-executor/ethereum/intention-executor/src/lib.rs @@ -19,7 +19,7 @@ use std::str::FromStr; use alloy::network::EthereumWallet; use alloy::primitives::{Address, U256}; use alloy::providers::{Provider, ProviderBuilder, WalletProvider}; -use alloy::rpc::types::TransactionRequest; +use alloy::rpc::types::{TransactionInput, TransactionRequest}; use alloy::signers::local::PrivateKeySigner; use async_trait::async_trait; use executor_core::intention_executor::IntentionExecutor; @@ -55,7 +55,6 @@ impl IntentionExecutor for EthereumIntentionExecutor { provider.get_account(provider.signer_addresses().next().unwrap()).await.unwrap(); match intention { Intention::TransferEthereum(to, value) => { - // todo: read transfer details from intention let tx = TransactionRequest::default() .to(Address::from(to)) .nonce(account.nonce) @@ -68,7 +67,19 @@ impl IntentionExecutor for EthereumIntentionExecutor { error!("Could not get transaction receipt: {:?}", e); })?; }, - Intention::CallEthereum(address, input) => todo!(), + Intention::CallEthereum(address, input) => { + let tx = TransactionRequest::default() + .to(Address::from(address)) + .nonce(account.nonce) + .input(TransactionInput::from(input)); + let pending_tx = provider.send_transaction(tx).await.map_err(|e| { + error!("Could not send transaction: {:?}", e); + })?; + // wait for transaction to be included + pending_tx.get_receipt().await.map_err(|e| { + error!("Could not get transaction receipt: {:?}", e); + })?; + }, } Ok(()) } diff --git a/tee-worker/omni-executor/executor-core/src/event_handler.rs b/tee-worker/omni-executor/executor-core/src/event_handler.rs index 977358b4d0..6671937fd9 100644 --- a/tee-worker/omni-executor/executor-core/src/event_handler.rs +++ b/tee-worker/omni-executor/executor-core/src/event_handler.rs @@ -16,7 +16,13 @@ use async_trait::async_trait; +#[derive(Debug)] +pub enum Error { + NonRecoverableError, + RecoverableError, +} + #[async_trait] pub trait EventHandler { - async fn handle(&self, event: BlockEvent) -> Result<(), ()>; + async fn handle(&self, event: BlockEvent) -> Result<(), Error>; } diff --git a/tee-worker/omni-executor/executor-core/src/listener.rs b/tee-worker/omni-executor/executor-core/src/listener.rs index 8558c2cfb3..f3293f8096 100644 --- a/tee-worker/omni-executor/executor-core/src/listener.rs +++ b/tee-worker/omni-executor/executor-core/src/listener.rs @@ -14,11 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . +use log::error; use std::fmt::Debug; use std::{marker::PhantomData, thread::sleep, time::Duration}; use tokio::{runtime::Handle, sync::oneshot::Receiver}; -use crate::event_handler::EventHandler; +use crate::event_handler::{Error, EventHandler}; use crate::fetcher::{EventsFetcher, LastFinalizedBlockNumFetcher}; use crate::primitives::GetEventId; use crate::sync_checkpoint_repository::{Checkpoint, CheckpointRepository}; @@ -108,7 +109,7 @@ impl< }; log::debug!("Starting sync from {:?}", block_number_to_sync); - loop { + 'main: loop { log::info!("Syncing block: {}", block_number_to_sync); if self.stop_signal.try_recv().is_ok() { break; @@ -163,9 +164,19 @@ impl< self.handle.block_on(self.intention_event_handler.handle(event)) { log::error!("Could not execute intention: {:?}", e); - // sleep(Duration::from_secs(1)); - // // it will try again in next loop - // continue 'main; + match e { + Error::NonRecoverableError => { + error!("Non-recoverable intention handling error, event: {:?}", event_id); + break 'main; + }, + Error::RecoverableError => { + error!( + "Recoverable intention handling error, event: {:?}", + event_id + ); + continue 'main; + }, + } } log::info!("Intention executed"); } else { diff --git a/tee-worker/omni-executor/parentchain/artifacts/rococo-omni-account.scale b/tee-worker/omni-executor/parentchain/artifacts/rococo-omni-account.scale index 0287a9e670fa496bc5136d18bedf326a8ee9c06f..cc85f5c8e5e5ab0ed294454d1534063df372374a 100644 GIT binary patch delta 1112 zcmb7DPfQbO6o0Rs+9?z|VpqF3Xf-vWt_#~D)KHC3kr+2(L@=l10Ud(1MzOrE=(aTO|-uKOW-}}Ay ze(!yM&Ed^CEU8}1&>!BuY5~J13-R`FEILR}yt`z_*@d!FK{L)1oi&%Q$; zt&By|Yd2n+#z;pdlT-5fSQOmg?;6nsn01uVX3k&kRIRkB8UoyP46zuq6Y4d!l#vo( z1uH^|o{Nr2TbPCcDT4EKQTiPp(ranJ`w(DN9Ln^sx4vzm z0@&Kp9&Ta41qKu9kGGal>Wl7b1&o|Y z<%hC4HLa{vX{xSTnrn#R+1 zq3K6@_45r!VP9x^>5?aeevB~6ZT4Iet{DV=D^pBnw3$<$js{V)=c0M!Wn0TxkK|++ zG)#k;vS)Vhb$iAcW}Mz8UIra|L>V4d(v~{HXBPLIa<@8`kWr|Nx%2;3t;?+lS6WfX zE15E#?zn>!wy(1ev24r91vlTMcLy@AdA>^B#X2i4C3)2R@`#elbEjd<{-^u17qj-q po-Pmb-PZSxWkbK_FMkz?#N+K;-;4eo-%;E9kN@iSOg7HA;0r6jMW_G( delta 1140 zcmb7DUuaWj6h9}qX>MxL+@@KY)>NZJ{8P0x{j*3rw;H=BiXC%pQCDJ`dt>jo$?a}# zY6qe|^uY%=WT#?;3Od|S5UE@X6=cdN*bTuwDER1$pbtLkU@-I~>P4q7!o5HE&iT$c zzjJ=)J2Qu;=5SVZqekDk2i-DCgYm9z`pex#_4Uo+F^ujnb$9keJ4XP<0Gt8dM0#DLobZ~;uxoEXEys6^(v^+SU24W0l2PVjyH9Vg)=fFMqLVVY};Y!#u*nLouDO4S}>yjeSf zWolV+q>3x)_a%vza~RzrD_q$80WgtQ@}r88&SbMXlbNRm?>f9iTfDdN2G#iP;5oYM zZ>FcdQ11myyouXm8fxJn*NbdZi&@=}1$f_!5KgJ)SZS1<^m*O#wu>0+lVw9G7CYkL z1aJRDUVzKCG2YItMYgJDR#yuG%+il_jho(ysexdBKBHGH0csL(M+gs$o2p)@C?lgN?bZtwHKjdzUJ*bBK!CsLKtqU* z)L&ZtdVK(62Q$U=xS?j1cTJj_S529A2U=04_F&lhIj|EyI_wKH>HFXx9y>R+3^#4C zPrdofWICrP>2cPbiP(-RtN&4Wm1`OKLRWE~ZiX6#dGI0cRm6H8`m<47kdhfqvI`1qoozY&<)eN z9xo!A)`re8mt^w`7W4v7%=&fn7N={9vrf_D-UmV3A5(HUC2Oh^eCOV0-#WW(PqdpL567(kQvbMd(t0+~?_%M41|Ko57}C7*TZPCw+{41$A8P%8+1ft5%jqhwIq!g% Db?Zl% diff --git a/tee-worker/omni-executor/parentchain/listener/src/event_handler.rs b/tee-worker/omni-executor/parentchain/listener/src/event_handler.rs index ea4ad0f733..6ac81c4e60 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/event_handler.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/event_handler.rs @@ -17,7 +17,7 @@ use crate::metadata::{MetadataProvider, SubxtMetadataProvider}; use crate::primitives::BlockEvent; use async_trait::async_trait; -use executor_core::event_handler::EventHandler; +use executor_core::event_handler::{Error, EventHandler}; use executor_core::intention_executor::IntentionExecutor; use executor_core::primitives::Intention; use std::marker::PhantomData; @@ -54,15 +54,25 @@ impl for IntentionEventHandler, EthereumIntentionExecutorT> { - async fn handle(&self, event: BlockEvent) -> Result<(), ()> { + async fn handle(&self, event: BlockEvent) -> Result<(), Error> { log::debug!("Handling block event: {:?}", event.id); let metadata = self.metadata_provider.get(event.id.block_num).await; let pallet = metadata.pallet_by_name(&event.pallet_name).ok_or_else(move || { - log::error!("No metadata found for {}", event.id.block_num); + log::error!( + "No pallet metadata found for event {} and pallet {} ", + event.id.block_num, + event.pallet_name + ); + Error::NonRecoverableError })?; let variant = pallet.event_variant_by_index(event.variant_index).ok_or_else(move || { - log::error!("No metadata found for {}", event.id.block_num); + log::error!( + "No event variant metadata found for event {} and variant {}", + event.id.block_num, + event.variant_index + ); + Error::NonRecoverableError })?; let mut fields = variant @@ -76,30 +86,35 @@ impl { Intention::CallEthereum(call_ethereum.address.to_fixed_bytes(), call_ethereum.input.0) }, crate::litentry_rococo::runtime_types::core_primitives::intention::Intention::TransferEthereum(transfer) => { - Intention::TransferEthereum(transfer.to.to_fixed_bytes(), [0; 32]) + Intention::TransferEthereum(transfer.to.to_fixed_bytes(), transfer.value) } }; //to explicitly handle all intention variants match intention { Intention::CallEthereum(_, _) => { - self.ethereum_intention_executor - .execute(intention) - .await - .map_err(|e| log::error!("Error executing intention"))?; + self.ethereum_intention_executor.execute(intention).await.map_err(|e| { + // assume for now we can easily recover + log::error!("Error executing intention"); + Error::RecoverableError + })?; }, Intention::TransferEthereum(_, _) => { - self.ethereum_intention_executor - .execute(intention) - .await - .map_err(|e| log::error!("Error executing intention"))?; + self.ethereum_intention_executor.execute(intention).await.map_err(|e| { + // assume for now we can easily recover + log::error!("Error executing intention"); + Error::RecoverableError + })?; }, } Ok(()) From fef629fb56ca3946ed2b15a52d7b94197484dba4 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Fri, 11 Oct 2024 14:32:44 +0200 Subject: [PATCH 06/10] cli --- tee-worker/omni-executor/Cargo.lock | 41 +++++++++++++++++++ tee-worker/omni-executor/docker-compose.yml | 1 + .../omni-executor/executor-worker/Cargo.toml | 1 + .../omni-executor/executor-worker/src/cli.rs | 8 ++++ .../omni-executor/executor-worker/src/main.rs | 16 +++++--- 5 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tee-worker/omni-executor/executor-worker/src/cli.rs diff --git a/tee-worker/omni-executor/Cargo.lock b/tee-worker/omni-executor/Cargo.lock index b83c7799dd..96aca827b5 100644 --- a/tee-worker/omni-executor/Cargo.lock +++ b/tee-worker/omni-executor/Cargo.lock @@ -1206,6 +1206,46 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.1", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + [[package]] name = "colorchoice" version = "1.0.2" @@ -1704,6 +1744,7 @@ dependencies = [ name = "executor-worker" version = "0.1.0" dependencies = [ + "clap", "env_logger", "executor-core", "hex", diff --git a/tee-worker/omni-executor/docker-compose.yml b/tee-worker/omni-executor/docker-compose.yml index ba55c94acd..b926adbbf4 100644 --- a/tee-worker/omni-executor/docker-compose.yml +++ b/tee-worker/omni-executor/docker-compose.yml @@ -6,6 +6,7 @@ services: depends_on: - ethereum-node - litentry-node + command: ["ws://litentry-node:9944", "http://ethereum-node:8545"] ethereum-node: image: ghcr.io/foundry-rs/foundry command: diff --git a/tee-worker/omni-executor/executor-worker/Cargo.toml b/tee-worker/omni-executor/executor-worker/Cargo.toml index fb174d0914..f34d291011 100644 --- a/tee-worker/omni-executor/executor-worker/Cargo.toml +++ b/tee-worker/omni-executor/executor-worker/Cargo.toml @@ -14,3 +14,4 @@ parentchain-listener = { path = "../parentchain/listener" } scale-encode = { workspace = true } serde_json = "1.0.127" tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +clap = { workspace = true, features = ["derive"] } diff --git a/tee-worker/omni-executor/executor-worker/src/cli.rs b/tee-worker/omni-executor/executor-worker/src/cli.rs new file mode 100644 index 0000000000..1bb4112442 --- /dev/null +++ b/tee-worker/omni-executor/executor-worker/src/cli.rs @@ -0,0 +1,8 @@ +use clap::Parser; + +#[derive(Parser)] +#[command(version, about, long_about = None)] +pub struct Cli { + pub parentchain_url: String, + pub ethereum_url: String, +} \ No newline at end of file diff --git a/tee-worker/omni-executor/executor-worker/src/main.rs b/tee-worker/omni-executor/executor-worker/src/main.rs index 140cfdcece..19b1b64df3 100644 --- a/tee-worker/omni-executor/executor-worker/src/main.rs +++ b/tee-worker/omni-executor/executor-worker/src/main.rs @@ -20,8 +20,12 @@ use parentchain_listener::CustomConfig; use std::io::Write; use std::thread::JoinHandle; use std::{fs, thread}; +use clap::Parser; use tokio::runtime::Handle; use tokio::sync::oneshot; +use crate::cli::Cli; + +mod cli; #[tokio::main] async fn main() -> Result<(), ()> { @@ -39,25 +43,27 @@ async fn main() -> Result<(), ()> { }) .init(); + + let cli = Cli::parse(); + fs::create_dir_all("data/").map_err(|e| { error!("Could not create data dir: {:?}", e); })?; - listen_to_parentchain().await.unwrap().join().unwrap(); + listen_to_parentchain(cli.parentchain_url, cli.ethereum_url).await.unwrap().join().unwrap(); Ok(()) } -async fn listen_to_parentchain() -> Result, ()> { +async fn listen_to_parentchain(parentchain_url: String, ethereum_url: String) -> Result, ()> { let (_sub_stop_sender, sub_stop_receiver) = oneshot::channel(); - - let ethereum_intention_executor = EthereumIntentionExecutor::new("http://ethereum-node:8545") + let ethereum_intention_executor = EthereumIntentionExecutor::new(ðereum_url) .map_err(|e| log::error!("{:?}", e))?; let mut parentchain_listener = parentchain_listener::create_listener::( "litentry_rococo", Handle::current(), - "ws://litentry-node:9944", + &parentchain_url, ethereum_intention_executor, sub_stop_receiver, ) From 15a54f7107ba3ecfbca3cdebd91432a440f8ecd4 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Mon, 14 Oct 2024 10:28:21 +0200 Subject: [PATCH 07/10] taplo fmt --- tee-worker/omni-executor/executor-core/Cargo.toml | 2 +- tee-worker/omni-executor/executor-worker/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tee-worker/omni-executor/executor-core/Cargo.toml b/tee-worker/omni-executor/executor-core/Cargo.toml index c4ced78d0f..2139accc31 100644 --- a/tee-worker/omni-executor/executor-core/Cargo.toml +++ b/tee-worker/omni-executor/executor-core/Cargo.toml @@ -8,4 +8,4 @@ edition.workspace = true async-trait = { workspace = true } log = { workspace = true } parity-scale-codec = { workspace = true, features = ["derive"] } -tokio = { workspace = true } \ No newline at end of file +tokio = { workspace = true } diff --git a/tee-worker/omni-executor/executor-worker/Cargo.toml b/tee-worker/omni-executor/executor-worker/Cargo.toml index f34d291011..f0b8afd215 100644 --- a/tee-worker/omni-executor/executor-worker/Cargo.toml +++ b/tee-worker/omni-executor/executor-worker/Cargo.toml @@ -5,6 +5,7 @@ authors = ['Trust Computing GmbH '] edition.workspace = true [dependencies] +clap = { workspace = true, features = ["derive"] } env_logger = { workspace = true } executor-core = { path = "../executor-core" } hex = "0.4.3" @@ -14,4 +15,3 @@ parentchain-listener = { path = "../parentchain/listener" } scale-encode = { workspace = true } serde_json = "1.0.127" tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } -clap = { workspace = true, features = ["derive"] } From ea939381f63414982d3c96f96d9da593f1eeb447 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Mon, 14 Oct 2024 10:29:08 +0200 Subject: [PATCH 08/10] remove todo --- common/primitives/core/src/intention.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/common/primitives/core/src/intention.rs b/common/primitives/core/src/intention.rs index 25aed60b10..2255c1eabd 100644 --- a/common/primitives/core/src/intention.rs +++ b/common/primitives/core/src/intention.rs @@ -5,7 +5,6 @@ use sp_runtime::{traits::ConstU32, BoundedVec}; pub const CALL_ETHEREUM_INPUT_LEN: u32 = 10 * 1024; -//todo: this should be versioned ? #[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, MaxEncodedLen, TypeInfo)] pub enum Intention { #[codec(index = 0)] From b7b455f6012164ea336f66c2469d35f65cedbdfe Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Mon, 14 Oct 2024 14:36:31 +0200 Subject: [PATCH 09/10] update docker-compose --- tee-worker/omni-executor/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tee-worker/omni-executor/docker-compose.yml b/tee-worker/omni-executor/docker-compose.yml index b926adbbf4..b3798d98ed 100644 --- a/tee-worker/omni-executor/docker-compose.yml +++ b/tee-worker/omni-executor/docker-compose.yml @@ -6,7 +6,7 @@ services: depends_on: - ethereum-node - litentry-node - command: ["ws://litentry-node:9944", "http://ethereum-node:8545"] + command: ["executor-worker", "ws://litentry-node:9944", "http://ethereum-node:8545"] ethereum-node: image: ghcr.io/foundry-rs/foundry command: From 8476093bc8dd9fc76c294cf2c926961d54235728 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Wed, 16 Oct 2024 21:53:37 +0200 Subject: [PATCH 10/10] fix test --- parachain/pallets/omni-account/src/lib.rs | 2 +- parachain/pallets/omni-account/src/tests.rs | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 9686c235e9..9c46581c51 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -311,7 +311,7 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(5)] + #[pallet::call_index(6)] #[pallet::weight((195_000_000, DispatchClass::Normal))] pub fn request_intention(origin: OriginFor, intention: Intention) -> DispatchResult { let who = T::OmniAccountOrigin::ensure_origin(origin)?; diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index 343097e48e..c4306d83d5 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -603,11 +603,21 @@ fn request_intention_works() { let who_identity_hash = who_identity.hash(); let who_omni_account = who_identity.to_omni_account(); - assert_ok!(OmniAccount::add_account( + let private_account = + MemberAccount::Private(vec![1, 2, 3], H256::from(blake2_256(&[1, 2, 3]))); + + assert_ok!(OmniAccount::create_account_store( RuntimeOrigin::signed(tee_signer.clone()), - who_identity, - MemberAccount::Private(vec![1, 2, 3], H256::from(blake2_256(&[1, 2, 3]))), + who_identity.clone(), )); + + let call = add_account_call(private_account); + assert_ok!(OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + who_identity.hash(), + call + )); + let intention = Intention::CallEthereum(CallEthereum { address: H160::zero(), input: BoundedVec::new(),